# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  Simple Get File

## couttsj

Attached is a simplified encrypted file download Client/Server similar to:
https://www.vbforums.com/showthread....13-VB6-GetFile

Whereas the original used full TLS 1.3 to establish the network connection, this one uses an abbreviated version. It is NOT compatible with full TLS 1.3. TLS 1.3 is very complex for the novice to follow, and this one is not burdened with all the logic required to be backwards compatible with previous versions of SSL/TLS. It only supports Elliptic-Curve Cryptography (ECC), which does not require Key storage. Like the full version, it negotiates the session parameters using Client Hello and Server Hello, followed by a Finished record.


```
************ New Client Hello Sample *************
01 01 00 00 4C - Header (len=76)
00 06 - Supported Elliptic Curves (len=6)
   00 17 - secp256r1
   00 18 - secp384r1
   00 19 - secp521r1
00 17 - Curve Used
   00 40 - Len=64 (Public Key)
      DA D0 B6 53 94 22 1C F9 B0 51 E1 FE CA 57 87 D0 
      98 DF E6 37 FC 90 B9 EF 94 5D 0C 37 72 58 11 80 
      52 71 A0 46 1C DB 82 52 D6 1F 1C 45 6F A3 E5 9A 
      B1 F4 5B 33 AC CF 5F 58 38 9E 05 77 B8 99 0B B3

************ New Server Hello Sample *************
02 01 00 00 44 - Header (len=68)
00 17 - Curve Used
   00 40 - Len=64 (Public Key)
      5C A5 0F AD 85 5C 6D 0F 9B CE DB 75 B1 29 8B F0 
      F5 D2 51 66 DD 47 47 75 20 AA 2B C9 AF 28 AE 19 
      CC 48 93 F5 B2 4A 9E 52 29 A7 D8 0A 02 41 AC 02 
      C8 12 69 52 FC 16 78 BC 83 AF F4 A5 00 C0 BD 09
```

The Public ECC Key from the other end is combined with the Internal Private ECC Key to form the Agreed Secret. The other end does the same thing, and the two connected ends should have identical Agreed Secrets. The Hello records are considerably smaller than the originals. 

This Version utilizes a MAC. For further information, see post #6.

The full version manipulates the Agreed Secret to create Handshake Read & Write keys, as well as Application Read & Write keys. Our simplified version utilizes the Agreed Secret itself as the starting data encryption/decryption key. The simplified routine uses the same routine for both encryption and decryption. The result is determined by the Key Stream used. "bStream" is updated every time the routine is called.

I have used a DLL (Dynamic Linked Library) prepared by using MakeDLL from DanSoft Australia to create jCrypt.dll. It provides the following functions:
Encrypt
GetECCKey
GenRandom
HashData
as outlined in the declarations section of the form. If you don't have access to this facility, you can comment out the declarations provided and add the mEncrypt.bas module provided to each project.

The encryption/decryption call deserves further explanation.
bStream = Encrypt(bBuffer, bStream)
"bStream" is the Key Stream applied to the Buffer (bBuffer) to form the encrypted or decrypted value, which is returned in "bBuffer". The updated Key Stream is returned in "bStream". If you are encrypting and decrypting within the same program, replace "bStream =" with "Call" on the encryption part of it. This allows you to use the same "bStream" to decrypt.

J.A. Coutts

Updated: 12/12/2022 - See post #6 for details

----------


## yokesee

how to get jCrypt.dll
http://www.yellowhead.com/documents/jCrypt.dll
not found

----------


## couttsj

> how to get jCrypt.dll
> http://www.yellowhead.com/documents/jCrypt.dll
> not found


It is considered an executable file and cannot be posted. I no longer have access to that domain, so it is up to you to activate the addon if you want to compile it.
https://github.com/Planet-Source-Cod...ke-yo__1-54190

As stated in the original post, you can always comment out the declarations and add the "mEncrypt.bas" module to the program.

J.A. Coutts

----------


## yokesee

yes but I wanted to see the DLL.
It works very well I will try it more times

----------


## couttsj

> yes but I wanted to see the DLL.
> It works very well I will try it more times


Send me a PM with your email address and I will try and send it to you.

J.A. Coutts

----------


## couttsj

Version 2 has added message authentication. In cryptography, message authentication comes in different forms.

Message Authentication Code (MAC)
Hash-based Message Authentication Code (HMAC)
Additional Associated Data (AAD)
Authenticated Encryption with Associated Data (AEAD)

Its purpose is to determine if the contents of the message have been altered in transit. The difficulty with hash based authentication code is that it is relatively slow when implemented with larger volumes of data, so what I have chosen to use is 32 bit Cyclic Redundancy Check (CRC). This is the same basic check used in network packets, and although it has been proven insecure when used with fixed keys, we are not using fixed keys.

Initially, I had added the MAC to the header. But then I realized that if a hacker can intercept and replace a complete record, what is to stop the hacker from calculating the MAC and adding it to the header. It took a bit of work, but I calculated the MAC on the unencrypted record and added it to the end of the record before encryption.

Feedback is welcome.

J.A. Coutts

----------


## wqweto

> Feedback is welcome.


CRC32 is not a MAC.

MAC is like a Hash but with a key i.e. without the key you cannot calculate the MAC of a sending packet, neither check if MAC of receiving packet matches.

In TLS client and server in the beginning if you remember they derive both encryption key and MAC *key* from the common master secret so no man-in-the-middle can calculate packets MACs because the initial MAC key is never transmitted and is impossible to guess.

You need real MAC (not hash/checksum like CRC32, SHA-1, etc.) which accepts initial key, otherwise it's not MAC but ordinaly hash/checksum which is less secure. For instance BLAKE2/BLAKE3 family of hashes implement MAC mode i.e. accept a key but the key is optional -- when missing they act as ordinary hash functions.

You can construct MAC from almost any hash function by using HMAC construct which is a couple of lines of code. This is from [VB6/VBA] Pure VB6 implementation of SHA-1 hash. 



```
Public Function CryptoHmacSha1ByteArray(baKey() As Byte, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1) As Byte()
    Const INNER_PAD     As Long = &H36
    Const OUTER_PAD     As Long = &H5C
    Dim lPadSize        As Long
    Dim lIdx            As Long
    Dim baPass()        As Byte
    Dim baPad()         As Byte
    Dim baHash()        As Byte
    
    lPadSize = LNG_BLOCKSZ
    If UBound(baKey) < lPadSize Then
        baPass = baKey
    Else
        baPass = CryptoSha1ByteArray(baKey)
    End If
    If Size < 0 Then
        Size = UBound(baInput) + 1 - Pos
    End If
    ReDim baPad(0 To lPadSize + Size - 1) As Byte
    For lIdx = 0 To UBound(baPass)
        baPad(lIdx) = baPass(lIdx) Xor INNER_PAD
    Next
    For lIdx = lIdx To lPadSize - 1
        baPad(lIdx) = INNER_PAD
    Next
    If Size > 0 Then
        Call CopyMemory(baPad(lPadSize), baInput(Pos), Size)
    End If
    baHash = CryptoSha1ByteArray(baPad)
    Size = UBound(baHash) + 1
    ReDim baPad(0 To lPadSize + Size - 1) As Byte
    For lIdx = 0 To UBound(baPass)
        baPad(lIdx) = baPass(lIdx) Xor OUTER_PAD
    Next
    For lIdx = lIdx To lPadSize - 1
        baPad(lIdx) = OUTER_PAD
    Next
    Call CopyMemory(baPad(lPadSize), baHash(0), Size)
    CryptoHmacSha1ByteArray = CryptoSha1ByteArray(baPad)
End Function
```

Unfortunately CRC32 is too short being 4 bytes total so not very suitable for HMAC-ing but still possible.

cheers,
</wqw>

----------


## couttsj

CRC was initially designed to detect bit loss in network transmission packets. If the process was reversed it should produce a zero result. It was very fast and if non-zero, the sender could be instructed to retransmit the packet. Some WiFi systems then used CRC in conjunction with a fixed key and password to control access. This was quickly shown to be very insecure because of the small size and fixed key/password. When used for its intended purpose to detect changes in transmitted packets, it was quite adequate.

We are not using CRC in the reverse manner because the record size can be too large in comparison to the packet size. Instead we are recalculating the CRC from the decrypted record and comparing it to the decrypted CRC transmitted. Without knowing the decryption key used, it is virtually impossible to anticipate what the CRC will be, and on the next record the key will be different.

J.A. Coutts

----------


## wqweto

> We are not using CRC in the reverse manner because the record size can be too large in comparison to the packet size. Instead we are recalculating the CRC from the decrypted record and comparing it to the decrypted CRC transmitted. Without knowing the decryption key used, it is virtually impossible to anticipate what the CRC will be, and on the next record the key will be different.


This is worse than using checksum algorithm like CRC instead of a real cryptographic hash of any kind, unkeyed MD5 would be better.

You are implementing MAC-then-Encrypt scheme which is flawed as discussed here. This has been tried in SSH (and SSL) and proved insecure i.e. performed successful real-life attacks.

The way to go is to Encrypt-then-MAC i.e. you calculate MAC on the *encrypted* packet, not on the plaintext. When you receive a packet you first check MAC and after it's ok then you decrypt. The idea is to not trust decrypted data contains valid data (i.e. the part which is storing the MAC) before verifying it by some means (like using a MAC).

Imagine you have to transmit a zero-sized packet. Your CRC would be 0 because it's not a real cryptographic hash. Using unkeyed cryptographic hash would result in each zero-sized packet having the same hash (which would be non-0). You need a keyed crypto hash to produce different MAC for each zero-sized packets.

cheers,
</wqw>

----------


## couttsj

> Imagine you have to transmit a zero-sized packet. Your CRC would be 0 because it's not a real cryptographic hash. Using unkeyed cryptographic hash would result in each zero-sized packet having the same hash (which would be non-0). You need a keyed crypto hash to produce different MAC for each zero-sized packets.
> 
> cheers,
> </wqw>


If you examine the code more closely, you will see that the MAC is performed on the record, not the packet. Also, zero length records are ignored.

J.A. Coutts

----------


## wqweto

Btw, SipHash is a keyed hash function which is cryptographically secure (at least the SipHash-2-4 variant iterates enough rounds) and can be used for MAC instead of other slower regular keyed crypto hashes.

Edit: You can use *CryptoHalfSiphash24Long* (110MB/s) and *CryptoHalfSiphash13Long* (240MB/s) from the *mdHalfSiphash.bas* module above as a direct replacement for CRC32 as these return a simple 32-bit Long as a result.

The only difference is that they allow for an 8 byte key/seed to be used for the hash to become keyed on it i.e. the hash will thus differ for differend keys/seeds.

cheers,
</wqw>

----------

