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