Attribute VB_Name = "basMain" Option Explicit ' $Id: basMain.bas $ '**************************************************************************** ' Copyright (C) 2009 DI Management Services Pty Limited, All Rights Reserved. '**************************************************************************** ' Distribution: You can freely use this code in your own applications, but ' you may not reproduce or publish this code on any web site, online service, ' or distribute as source on any media without express permission. ' Terms: Use at your own risk. Provided "as is" with no warranties. ' Contact: <www.di-mgt.com.au> <www.cryptosys.net> '**************************************************************************** ' This file last updated: ' $Date: 2009-06-21 01:46Z $ '**************************************************************************** ' A VB6 conversion of the core functions the VB.NET project CrSysAPIDemo ' Requires the module ``basCryptoSys.bas'' to be included in the project. ' Points to note: ' * Integer variables in VB.NET need to be changed to Long in VB6 ' * Functions that output to a string need to have the output string pre-dimensioned first; else GPF! ' * There are some convenient functions in basCryptoSys that return strings directly. Sub Main() ' NOTE: We use the words salt, nonce and IV interchangeably Dim strSaltHex As String Dim strPassword As String Dim nCount As Long Dim strPlain As String Dim strCipherHex As String ' USER INPUT: strPassword = "password" strPlain = "Hello world" nCount = 2048 Debug.Print "ENCRYPTION USER INPUT:" Debug.Print "PWD='" & strPassword & "'" Debug.Print "CNT=" & nCount Debug.Print "PT ='" & strPlain & "'" ' ENCRYPT... Debug.Print "DEBUGGING..." strSaltHex = SetNonceHex Debug.Print "IV =" & strSaltHex strCipherHex = EncryptWithPassword(strPassword, strSaltHex, nCount, strPlain) Debug.Print "OUTPUT:" Debug.Print "CT =" & strCipherHex Debug.Print ' DECRYPT... Debug.Print "DECRYPTION USER INPUT:" Debug.Print "PWD='" & strPassword & "'" Debug.Print "CNT=" & nCount Debug.Print "IV =" & strSaltHex Debug.Print "CT =" & strCipherHex Debug.Print "DEBUGGING..." strPlain = DecryptWithPassword(strPassword, strSaltHex, nCount, strCipherHex) Debug.Print "OUTPUT:" If strPlain = strCipherHex Then MsgBox ("Decryption error") Debug.Print "PT =" & "<Decryption error>" Else Debug.Print "PT ='" & strPlain & "'" End If End Sub Public Function SetNonceHex() As String ' Generate a random nonce the same size as the AES-128 block (128 bits) '''Return Rng.NonceHex(Aes128.BlockSize) SetNonceHex = rngNonceHex(API_BLK_AES_BYTES) End Function Public Function EncryptWithPassword(ByVal strPassword As String, ByVal strSaltHex As String, ByVal nCount As Long, ByVal strPlain As String) As String ' Encrypts `ordinary' text given password, etc. and returns hex-encoded ciphertext Dim strKeyHex As String Dim strInputHex As String Dim strCipherHex As String Dim nRet As Long Dim nOutChars As Long Dim strPaddedHex As String ' 1. Form a 128-bit key from the password + salt + count '''strKeyHex = Pbe.Kdf2(Aes128.BlockSize, strPassword, strSaltHex, nCount) ' We know that a hex string is exactly 2 times the length in bytes strKeyHex = String(API_BLK_AES_BYTES * 2, " ") nRet = PBE_Kdf2Hex(strKeyHex, Len(strKeyHex), API_BLK_AES_BYTES, strPassword, strSaltHex, CLng(nCount), 0) If nRet <> 0 Then Debug.Print "ERROR: PBE_Kdf2Hex returns " & nRet Exit Function End If Debug.Print "KEY=" & strKeyHex ' 2. Encode the plaintext input in hex format '''strInputHex = Cnv.ToHex(strPlain) strInputHex = cnvHexStrFromString(strPlain) Debug.Print "PT =" & strInputHex ' 3. Pad the plaintext to an exact multiple of the encryption block size '''strInputHex = Aes128.Pad(strInputHex) nOutChars = PAD_HexBlock("", 0, strInputHex, API_BLK_AES_BYTES, 0) strPaddedHex = String(nOutChars, " ") nRet = PAD_HexBlock(strPaddedHex, Len(strPaddedHex), strInputHex, API_BLK_AES_BYTES, 0) Debug.Print "PAD=" & strPaddedHex ' 4. Encrypt this padded input using the key and the IV ' (we use the same value for the IV as we used for the salt above) '''strCipherHex = Aes128.ENCRYPT(strInputHex, strKeyHex, Mode.CBC, strSaltHex) strCipherHex = String(Len(strPaddedHex), " ") nRet = AES128_HexMode(strCipherHex, strPaddedHex, strKeyHex, ENCRYPT, "CBC", strSaltHex) Debug.Print "CT =" & strCipherHex ' Return the ciphertext in hex format '''Return strCipherHex EncryptWithPassword = strCipherHex End Function Public Function DecryptWithPassword(ByVal strPassword As String, ByVal strSaltHex As String, ByVal nCount As Long, ByVal strCipherHex As String) As String ' Decrypts strCipherHex. Returns plaintext as an `ordinary' text string. ' If fails, returns original hex-encoded ciphertext to indicate an error ' (this is because an empty string is a valid result). Dim strKeyHex As String Dim strPaddedHex As String Dim strPlainHex As String Dim strPlain As String Dim nOutChars As Long Dim nRet As Long ' 1. Form a 128-bit key from the password + salt + count '''strKeyHex = Pbe.Kdf2(Aes128.BlockSize, strPassword, strSaltHex, nCount) ' We know that a hex string is exactly 2 times the length in bytes strKeyHex = String(API_BLK_AES_BYTES * 2, " ") nRet = PBE_Kdf2Hex(strKeyHex, Len(strKeyHex), API_BLK_AES_BYTES, strPassword, strSaltHex, CLng(nCount), 0) If nRet <> 0 Then Debug.Print "ERROR: PBE_Kdf2Hex returns " & nRet Exit Function End If Debug.Print "KEY=" & strKeyHex ' 2. Decrypt the ciphertext to get padded plaintext (IV = salt) '''strPaddedHex = Aes128.DECRYPT(strCipherHex, strKeyHex, Mode.CBC, strSaltHex) strPaddedHex = String(Len(strCipherHex), " ") nRet = AES128_HexMode(strPaddedHex, strCipherHex, strKeyHex, DECRYPT, "CBC", strSaltHex) Debug.Print "PAD=" & strPaddedHex ' No need to query for length because we know the output will be shorter than input ' so make sure output is as long as the input strPlainHex = String(Len(strPaddedHex), " ") nOutChars = PAD_UnpadHex(strPlainHex, Len(strPaddedHex), strPaddedHex, API_BLK_AES_BYTES, 0) Debug.Print "Unpadded length is " & nOutChars & " characters" ' 3. Check for error (i.e. an empty string) '''If strPaddedHex.Length = 0 Then '''Return strCipherHex '''End If ' Check for error If (nOutChars < 0) Then ' Return unchanged input to indicate error DecryptWithPassword = strCipherHex Exit Function End If ' 4. Unpad to retrieve the plaintext '''strPlainHex = Aes128.Unpad(strPaddedHex) strPlainHex = Left$(strPlainHex, nOutChars) Debug.Print "PT =" & strPlainHex ' 5. Check for error (this time strPlain *equal* to strPaddedHex) '''If strPlainHex.Length = strPaddedHex.Length Then '''Return strCipherHex '''End If ' (Not applicable in VB6) ' 6. Encode the hex-encoded text into normal text '''strPlain = Cnv.StringFromHex(strPlainHex) strPlain = cnvStringFromHexStr(strPlainHex) ' Return the plaintext '''Return strPlain DecryptWithPassword = strPlain End Function