Attribute VB_Name = "basTDEABytesAndHex" Option Explicit Option Base 0 ' $Id: basTDEABytesAndHex.bas $ ' Examples showing how to encrypt a arbitrary-length 'text' string ' with CryptoSys API using both 'Bytes' and `Hex' modes. ' TDEA_Bytes_Example uses data in `Byte' format ' TDEA_Hex_Example uses data in `Hex' format 'Algorithm: Triple DES (TDEA, 3DES, des-ede3) 'Mode: Cipher Block Chaining (CBC) 'Padding: PKCS-7 Padding (same as PKCS-5) 'Key: F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677 'IV: FEDCBA9876543210 'Plaintext = "Hello world!" ' Copyright (C) 2006 DI Management Services Pty Limited. ' All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net> ' Last updated: ' $Date: 2006-08-18 06:39:00 $ ' Use at your own risk. Public Function TDEA_Bytes_Example() ' We are going to use the TDEA_BytesMode function in CBC mode ' which requires its data in Byte array form ' and requires the user to have provided the padding Dim strPlain As String Dim abKey() As Byte Dim abInitV() As Byte Dim abPlain() As Byte Dim abBlock() As Byte Dim abCipher() As Byte Dim strCheck As String Dim nPlainLen As Long Dim nBlockLen As Long Dim nRet As Long ' Key is required at 24 bytes long. ' Assume we are given the key, in hex format ' F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677 ' We could set this the `long' way ' ReDim abKey(23) ' (0..23) = 24 bytes ' abKey(0) = &HF0 ' abKey(1) = &HE1 ' ' ... ' abKey(23) = &H77 ' But we do a simple conversion using the cnvBytesFromHexStr function abKey = cnvBytesFromHexStr("F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677") ' As this is CBC mode we need an Initialization Vector (IV) ' of 8 bytes long selected randomly, e.g. FEDCBA9876543210 in hex. ' (NOTE: The IV should be different for each message and may be passed in the clear) abInitV = cnvBytesFromHexStr("FEDCBA9876543210") Debug.Print "KY=" & cnvHexStrFromBytes(abKey) Debug.Print "IV=" & cnvHexStrFromBytes(abInitV) ' E.1. Convert the plaintext string into Byte format ' We can use the built-in StrConv function to convert from 'text' to 'bytes' strPlain = "Hello world!" abPlain = StrConv(strPlain, vbFromUnicode) Debug.Print "SZ='" & strPlain & "'" Debug.Print "PT=" & cnvHexStrFromBytes(abPlain) ' E.2. Pad the message according to PKCS5/7 rules, namely: ' For a 64-bit block size: ' Append a padding string of between 1 and 8 bytes to make the total length an exact multiple of 8 bytes. ' The value of each byte of the padding string is set to the number of bytes added; namely, ' 8 bytes of value 0x08, 7 bytes of value 0x07, ..., 2 bytes of 0x02, or one byte of value 0x01. ' The length of the plaintext to be encrypted thus will be a multiple of 8 bytes and it will be ' possible to recover the message unambiguously from the decoded ciphertext. ' Version 3.2 of CryptoSys API introduced the PAD_BytesBlock and PAD_UnpadBytes functions nPlainLen = UBound(abPlain) - LBound(abPlain) + 1 ' How long should our input block be? nBlockLen = PAD_BytesBlock(0, 0, abPlain(0), nPlainLen, API_BLK_TDEA_BYTES, 0) If nBlockLen <= 0 Then MsgBox "Unable to pad the plaintext. Error = " & nRet, vbCritical Exit Function End If ReDim abBlock(nBlockLen - 1) nBlockLen = PAD_BytesBlock(abBlock(0), nBlockLen, abPlain(0), nPlainLen, API_BLK_TDEA_BYTES, 0) If nBlockLen <= 0 Then MsgBox "Unable to pad the plaintext. Error = " & nRet, vbCritical Exit Function End If Debug.Print "IB=" & cnvHexStrFromBytes(abBlock) ' E.3. Call the encryption function in CBC mode nRet = TDEA_BytesMode(abBlock(0), abBlock(0), nBlockLen, abKey(0), ENCRYPT, "CBC", abInitV(0)) ' It should return 0 to indicate success If nRet <> 0 Then MsgBox "Encryption failed. Error = " & nRet, vbCritical Exit Function End If Debug.Print "CT=" & cnvHexStrFromBytes(abBlock) ' OUTPUT the ciphertext ' The resulting ciphertext contains non-printable characters ' but we can look at it in hexadecimal form MsgBox "Ciphertext = " & cnvHexStrFromBytes(abBlock), vbOKOnly, "Encryption Output" ' TO DECRYPT, WE DO THE REVERSE PROCESS. ' D.1. First decrypt the ciphertext nRet = TDEA_BytesMode(abBlock(0), abBlock(0), nBlockLen, abKey(0), DECRYPT, "CBC", abInitV(0)) If nRet <> 0 Then MsgBox "Decryption failed. Error = " & nRet Exit Function End If Debug.Print "OB=" & cnvHexStrFromBytes(abBlock) ' D.2. Remove the padding bytes ' We know that the unpadded data will be shorter than the output block ' so we can use our existing buffer and then shorten it nPlainLen = PAD_UnpadBytes(abBlock(0), nBlockLen, abBlock(0), nBlockLen, API_BLK_TDEA_BYTES, 0) ' This function checks for invalid padding bytes. If it fails, our decryption has failed. If nPlainLen < 0 Then MsgBox "Decryption failed. Error = " & nRet Exit Function End If ' Otherwise, it was successful, so re-dimension the buffer ReDim Preserve abBlock(nPlainLen - 1) Debug.Print "PT=" & cnvHexStrFromBytes(abBlock) ' D.3. Now we should have our plaintext, so convert back to a string strCheck = StrConv(abBlock, vbUnicode) Debug.Print "SZ='" & strCheck & "'" ' OUTPUT the plaintext string MsgBox "[" & strCheck & "]", vbOKOnly, "Decryption Output" End Function Public Function TDEA_Hex_Example() ' We are going to use the TDEA_HexMode function ' which requires its data as a hexadecimal-encoded string ' and requires the user to have provided the padding Dim nRet As Long Dim strKeyHex As String Dim strIVHex As String Dim strPlain As String Dim strPlainHex As String Dim strInputHex As String Dim strCipherHex As String Dim strOutputHex As String Dim strCheckHex As String Dim strCheck As String ' Set the key strKeyHex = "F0E1D2C3B4A5968778695A4B3C2D1E0F0011223344556677" ' As this is CBC mode we need an Initialization Vector (IV) ' of 8 bytes long selected randomly, e.g. ' FEDCBA9876543210 in hex. ' (NOTE: The IV should be different for each message) strIVHex = "FEDCBA9876543210" Debug.Print "KY=" & strKeyHex Debug.Print "IV=" & strIVHex ' The plaintext to be encrypted strPlain = "Hello world!" ' E.1. Convert plaintext string to hexadecimal-encoded format strPlainHex = cnvHexStrFromString(strPlain) Debug.Print "SZ='" & strPlain & "'" Debug.Print "PT=" & strPlainHex ' E.2. Add padding bytes. ' CryptoSys API Version 3.2 introduces the PAD_HexBlock function ' and the VB wrapper function padHexString strInputHex = padHexString(strPlainHex, API_BLK_TDEA_BYTES) Debug.Print "IB=" & strInputHex ' E.3. Call the encryption function in CBC mode ' IMPORTANT: pre-dimension the output string first strCipherHex = String(Len(strInputHex), " ") nRet = TDEA_HexMode(strCipherHex, strInputHex, strKeyHex, ENCRYPT, "CBC", strIVHex) ' It should return 0 to indicate success If nRet <> 0 Then MsgBox "Encryption failed. Error = " & nRet Exit Function End If Debug.Print "CT=" & strCipherHex ' OUTPUT the ciphertext ' The hex-encoded ciphertext is printable (unlike the Byte version) MsgBox "Ciphertext = " & strCipherHex, vbOKOnly, "Encryption Output" ' TO DECRYPT, WE DO THE REVERSE PROCESS. ' D.1 Decrypt the ciphertext ' IMPORTANT: pre-dimension the output string first strOutputHex = String(Len(strCipherHex), " ") nRet = TDEA_HexMode(strOutputHex, strCipherHex, strKeyHex, DECRYPT, "CBC", strIVHex) If nRet <> 0 Then MsgBox "Decryption failed. Error = " & nRet Exit Function End If Debug.Print "OB=" & strOutputHex ' D.2. Remove the padding using wrapper function strCheckHex = unpadHexString(strOutputHex, API_BLK_TDEA_BYTES) ' If the result is the same length, the decryption has failed If Len(strCheckHex) = Len(strOutputHex) Then MsgBox "Decryption failed" Exit Function End If Debug.Print "PT=" & strCheckHex ' D.3. Convert to String format strCheck = cnvStringFromHexStr(strCheckHex) Debug.Print "SZ='" & strCheck & "'" ' OUTPUT the plaintext string MsgBox "[" & strCheck & "]", vbOKOnly, "Decryption Output" End Function