Attribute VB_Name = "basTestBlowfish"
Option Explicit
Option Base 0

' basTestBlowfish: Tests of Blowfish function

' New version: published November 20032

'************************* COPYRIGHT NOTICE*************************
' This code was originally written in Visual Basic by David Ireland
' and is copyright (c) 2000-3 D.I. Management Services Pty Limited,
' all rights reserved.

' You are free to use this code as part of your own applications
' provided you keep this copyright notice intact and acknowledge
' its authorship with the words:

'   "Contains cryptography software by David Ireland of
'   DI Management Services Pty Ltd <www.di-mgt.com.au>."

' If you use it as part of a web site, please include a link
' to our site in the form
' <A HREF="http://www.di-mgt.com.au/crypto.html">Cryptography
' Software Code</a>

' This code may only be used as part of an application. It may
' not be reproduced or distributed separately by any means without
' the express written permission of the author.

' David Ireland and DI Management Services Pty Limited make no
' representations concerning either the merchantability of this
' software or the suitability of this software for any particular
' purpose. It is provided "as is" without express or implied
' warranty of any kind.

' Please forward comments or bug reports to <code@di-mgt.com.au>.
' The latest version of this source code can be downloaded from
' www.di-mgt.com.au/crypto.html.
'****************** END OF COPYRIGHT NOTICE*************************

' Public Functions in this module are:
' TestStrEnc(): Encrypts and decrypts a standard hex block in ECB mode
' TestStrEncCBC(): ditto using CBC mode
' BlowfishTestSuite(): carries out Eric Young's Blowfish test suite
' TestFileEnc(): Encrypts a file using blf_FileEnc()
' TestFileDec(): Decrypts a file using blf_FileDec()
' TestFileEncViaString(): Encrypts a file via a string
' TestFileEncCBC(): Encrypts a file using CBC mode
' TestFileDecCBC(): Decrypts a file using CBC mode
' ReadFileIntoString(sFilePath): Returns string of file contents
' WriteFileFromString(sFilePath): Creates a file from a string

Private Type SuiteSet
' Used to store test suite
    Key As String * 16
    Plain As String * 16
    Cipher As String * 16
End Type

Public Function TestByteEnc() As Boolean
' Example showing encryption and decryption of standard hex block
' This should produce the output:
'   KY=FEDCBA9876543210
'   PT=0123456789ABCDEF
'   CT=0ACEAB0FC6A0A28D
'   OK=0ACEAB0FC6A0A28D
'   P '=0123456789ABCDEF

    Dim abData() As Byte
    Dim abCipher() As Byte
    Dim abPlain() As Byte
    Dim aKey() As Byte

    ' Load test key and initialise
    aKey() = cv_BytesFromHex("FEDCBA9876543210")
    Call blf_KeyInit(aKey)
    
    ' Convert data in hex format to bytes
    abData = cv_BytesFromHex("0123456789ABCDEF")
    
    ' Encipher the bytes
    abCipher = blf_BytesRaw(abData, True)
    ' Then decipher it
    abPlain = blf_BytesRaw(abCipher, False)
    
    ' Output results
    Debug.Print "KY=" & cv_HexFromBytes(aKey)
    Debug.Print "PT=" & cv_HexFromBytes(abData)
    Debug.Print "CT=" & cv_HexFromBytes(abCipher)
    Debug.Print "OK=" & "0ACEAB0FC6A0A28D"  ' Correct answer
    Debug.Print "P'=" & cv_HexFromBytes(abPlain)
End Function

Public Function TestEncString()
    Dim strData As String
    Dim strResult As String
    Dim abBytes() As Byte
    Dim abKey() As Byte
    
    ' Load test key and initialise
    abKey() = cv_BytesFromHex("FEDCBA9876543210")
    Call blf_KeyInit(abKey)
    Debug.Print "KY=" & cv_HexFromBytes(abKey)
    
    strData = "Hello, world!"
    ' Convert to byte array
    abBytes = StrConv(strData, vbFromUnicode)
    Debug.Print "PT=" & cv_HexFromBytes(abBytes)
    
    ' Encrypt
    abBytes = blf_BytesEnc(abBytes)
    Debug.Print "CT=" & cv_HexFromBytes(abBytes)
    
    ' Decrypt
    abBytes = blf_BytesDec(abBytes)
    Debug.Print "P'=" & cv_HexFromBytes(abBytes)
    
    ' Convert back to a string
    strResult = StrConv(abBytes, vbUnicode)
    Debug.Print strResult
    
End Function

Public Function TestEncUnicode()
    Dim strData As String
    Dim strResult As String
    Dim abBytes() As Byte
    Dim abKey() As Byte
    
    ' Load test key and initialise
    abKey() = cv_BytesFromHex("FEDCBA9876543210")
    Call blf_KeyInit(abKey)
    Debug.Print "KY=" & cv_HexFromBytes(abKey)
    
    strData = "Hello, world!"
    ' Convert to byte array without Unicode conversion
    abBytes = strData
    Debug.Print "PT=" & cv_HexFromBytes(abBytes)
    
    ' Encrypt
    abBytes = blf_BytesEnc(abBytes)
    Debug.Print "CT=" & cv_HexFromBytes(abBytes)
    
    ' Decrypt
    abBytes = blf_BytesDec(abBytes)
    Debug.Print "P'=" & cv_HexFromBytes(abBytes)
    
    ' Convert back to a string
    strResult = abBytes
    Debug.Print strResult
    
End Function


Public Function TestBytesEncRawCBC() As Boolean
' Example showing encryption and decryption in Cipher Block Chaining mode
' without padding
' This is a standard test vector by Eric Young
    Dim sData As String
    Dim abData() As Byte
    Dim abCipher() As Byte
    Dim abPlain() As Byte
    Dim abKey() As Byte
    Dim abInitV() As Byte

    ' Get data and convert to byte array
    sData = "7654321 Now is the time for " & Chr$(0) & Chr$(0) & Chr$(0) & Chr$(0)
    abData = StrConv(sData, vbFromUnicode)
    
    ' Load test key and initialise
    abKey() = cv_BytesFromHex("0123456789ABCDEFF0E1D2C3B4A59687")
    Call blf_KeyInit(abKey)
    
    ' Set IV as byte array
    abInitV = cv_BytesFromHex("FEDCBA9876543210")
    
    ' Encipher the data
    abCipher = blf_BytesEncRawCBC(abData, abInitV)
    ' Then decipher it
    abPlain = blf_BytesDecRawCBC(abCipher, abInitV)
    
    ' Output results
    Debug.Print "KY="; cv_HexFromBytes(abKey)
    Debug.Print "IV="; cv_HexFromBytes(abInitV)
    Debug.Print "PT="; sData
    Debug.Print "PT="; cv_HexFromBytes(abData)
    Debug.Print "CT="; cv_HexFromBytes(abCipher)
    Debug.Print "OK="; "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"
    Debug.Print "P'="; cv_HexFromBytes(abPlain)
    Debug.Print "P'="; StrConv(abPlain, vbUnicode)
End Function

Public Function TestBytesCBC() As Boolean
' Example showing encryption and decryption in Cipher Block Chaining mode
' with PKCS#5 padding
    Dim sData As String
    Dim abData() As Byte
    Dim abCipher() As Byte
    Dim abPlain() As Byte
    Dim abKey() As Byte
    Dim abInitV() As Byte

    ' Get data and convert to byte array
    sData = "7654321 Now is the time for "
    abData = StrConv(sData, vbFromUnicode)
    
    ' Load test key and initialise
    abKey() = cv_BytesFromHex("0123456789ABCDEFF0E1D2C3B4A59687")
    Call blf_KeyInit(abKey)
    
    ' Set IV as byte array
    abInitV = cv_BytesFromHex("FEDCBA9876543210")
    
    ' Encipher the data
    abCipher = blf_BytesEncCBC(abData, abInitV)
    ' Then decipher it
    abPlain = blf_BytesDecCBC(abCipher, abInitV)
    
    ' Output results
    Debug.Print "KY="; cv_HexFromBytes(abKey)
    Debug.Print "IV="; cv_HexFromBytes(abInitV)
    Debug.Print "PT="; sData
    Debug.Print "PT="; cv_HexFromBytes(abData)
    Debug.Print "CT="; cv_HexFromBytes(abCipher)
    Debug.Print "OK="; "6B77B4D63006DEE605B156E27403979358DEB9E7154616D9DBACBD4E28928430"
    Debug.Print "P'="; cv_HexFromBytes(abPlain)
    Debug.Print "P'="; StrConv(abPlain, vbUnicode)
End Function


Public Function BlowfishTestSuiteBytes()
    ' Data from test suite by Eric Young
    Const NTESTS As Integer = 34    ' # of sets in suite
    Dim aSuite(NTESTS - 1) As SuiteSet
    Dim vntA As Variant
    Dim i As Integer, j As Integer
    Dim aKey() As Byte
    Dim abPlain() As Byte
    Dim abCipher() As Byte
    Dim abBack() As Byte
    
    ' Read in test suite as array of strings using array of variants
    ' These values are taken directly from the C code by Eric Young.
'       key bytes               clear bytes             cipher bytes
    vntA = Array( _
        "0000000000000000", "0000000000000000", "4EF997456198DD78", _
        "FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A", _
        "3000000000000000", "1000000000000001", "7D856F9A613063F2", _
        "1111111111111111", "1111111111111111", "2466DD878B963C9D", _
        "0123456789ABCDEF", "1111111111111111", "61F9C3802281B096", _
        "1111111111111111", "0123456789ABCDEF", "7D0CC630AFDA1EC7", _
        "0000000000000000", "0000000000000000", "4EF997456198DD78", _
        "FEDCBA9876543210", "0123456789ABCDEF", "0ACEAB0FC6A0A28D", _
        "7CA110454A1A6E57", "01A1D6D039776742", "59C68245EB05282B", _
        "0131D9619DC1376E", "5CD54CA83DEF57DA", "B1B8CC0B250F09A0", _
        "07A1133E4A0B2686", "0248D43806F67172", "1730E5778BEA1DA4", _
        "3849674C2602319E", "51454B582DDF440A", "A25E7856CF2651EB", _
        "04B915BA43FEB5B6", "42FD443059577FA2", "353882B109CE8F1A", _
        "0113B970FD34F2CE", "059B5E0851CF143A", "48F4D0884C379918", _
        "0170F175468FB5E6", "0756D8E0774761D2", "432193B78951FC98", _
        "43297FAD38E373FE", "762514B829BF486A", "13F04154D69D1AE5", _
        "07A7137045DA2A16", "3BDD119049372802", "2EEDDA93FFD39C79")
        
    For i = 0 To 16
        aSuite(i).Key = vntA(i * 3)
        aSuite(i).Plain = vntA(i * 3 + 1)
        aSuite(i).Cipher = vntA(i * 3 + 2)
    Next
    
    vntA = Array( _
        "04689104C2FD3B2F", "26955F6835AF609A", "D887E0393C2DA6E3", _
        "37D06BB516CB7546", "164D5E404F275232", "5F99D04F5B163969", _
        "1F08260D1AC2465E", "6B056E18759F5CCA", "4A057A3B24D3977B", _
        "584023641ABA6176", "004BD6EF09176062", "452031C1E4FADA8E", _
        "025816164629B007", "480D39006EE762F2", "7555AE39F59B87BD", _
        "49793EBC79B3258F", "437540C8698F3CFA", "53C55F9CB49FC019", _
        "4FB05E1515AB73A7", "072D43A077075292", "7A8E7BFA937E89A3", _
        "49E95D6D4CA229BF", "02FE55778117F12A", "CF9C5D7A4986ADB5", _
        "018310DC409B26D6", "1D9D5C5018F728C2", "D1ABB290658BC778", _
        "1C587F1C13924FEF", "305532286D6F295A", "55CB3774D13EF201", _
        "0101010101010101", "0123456789ABCDEF", "FA34EC4847B268B2", _
        "1F1F1F1F0E0E0E0E", "0123456789ABCDEF", "A790795108EA3CAE", _
        "E0FEE0FEF1FEF1FE", "0123456789ABCDEF", "C39E072D9FAC631D", _
        "0000000000000000", "FFFFFFFFFFFFFFFF", "014933E0CDAFF6E4", _
        "FFFFFFFFFFFFFFFF", "0000000000000000", "F21E9A77B71C49BC", _
        "0123456789ABCDEF", "0000000000000000", "245946885754369A", _
        "FEDCBA9876543210", "FFFFFFFFFFFFFFFF", "6B5C5A9C5D9E0A5A")
        
    For i = 0 To 16
        aSuite(i + 17).Key = vntA(i * 3)
        aSuite(i + 17).Plain = vntA(i * 3 + 1)
        aSuite(i + 17).Cipher = vntA(i * 3 + 2)
    Next
  
    For i = 0 To NTESTS - 1
        Debug.Print "Test " & i + 1
        Debug.Print "Key=" & aSuite(i).Key & " Plain Data=" & aSuite(i).Plain
        
        ' Convert key and plaintext to arrays of 8 bytes
        aKey() = cv_BytesFromHex(aSuite(i).Key)
        abPlain = cv_BytesFromHex(aSuite(i).Plain)
        Debug.Print "Correct Cipher=" & aSuite(i).Cipher
        
        ' Encrypt just the raw block with new key
        Call blf_KeyInit(aKey)
        abCipher = blf_BytesRaw(abPlain, bEncrypt:=True)
    
        Debug.Print "Calc'd Cipher =" & cv_HexFromBytes(abCipher)
        ' Check we did it
        If aSuite(i).Cipher <> cv_HexFromBytes(abCipher) Then
            MsgBox "Failed to get correct cipher on round " & i
        End If
    
        ' Now decipher back to plaintext, again just the raw block
        abBack = blf_BytesRaw(abCipher, bEncrypt:=False)
        Debug.Print "Converted Back to Plain=        " & cv_HexFromBytes(abBack)
        
        If aSuite(i).Plain <> cv_HexFromBytes(abBack) Then
            MsgBox "Failed to get correct plain on round " & i
        End If
    Next
    
End Function

Private Function EncString(ByVal strData As String)
    Dim strResult As String
    Dim abBytes() As Byte
    
    ' Convert to byte array
    abBytes = StrConv(strData, vbFromUnicode)
    Debug.Print "PT=" & cv_HexFromBytes(abBytes)
    
    ' Encrypt
    abBytes = blf_BytesEnc(abBytes)
    Debug.Print "CT=" & cv_HexFromBytes(abBytes)
    
    ' Decrypt
    abBytes = blf_BytesDec(abBytes)
    Debug.Print "P'=" & cv_HexFromBytes(abBytes)
    
    ' Convert back to a string
    strResult = StrConv(abBytes, vbUnicode)
    Debug.Print strResult
    If strResult <> strData Then
        MsgBox strResult & " not equal to " & strData
    End If
    
End Function

Private Function EncBytes(abData() As Byte)
    Dim abBytes() As Byte
    Dim j As Integer
    
    Debug.Print "PT=" & cv_HexFromBytes(abData)
    
    ' Encrypt
    abBytes = blf_BytesEnc(abData)
    Debug.Print "CT=" & cv_HexFromBytes(abBytes)
    
    ' Decrypt
    abBytes = blf_BytesDec(abBytes)
    Debug.Print "P'=" & cv_HexFromBytes(abBytes)
    
    For j = LBound(abBytes) To UBound(abBytes)
        If abBytes(j) <> abData(j) Then
            MsgBox abBytes(j) & " not equal to " & abData(j) & " at offset " & j
        End If
    Next
    
End Function

Public Function TestEncs()
' Encrypt and decrypt random text strings and random byte arrays
' using a random key of random length
    Dim abKey() As Byte
    Dim strData As String
    Dim abData() As Byte
    Dim nLen As Long
    Dim i As Long
    Dim n As Long
    
    Randomize
    ' Create a random test key and initialise
    nLen = Int(Rnd() * 56) Mod 56 + 1
    ReDim abKey(nLen - 1)
    For i = 0 To nLen - 1
        abKey(i) = Int(Rnd() * 256) And &HFF
    Next
    Call blf_KeyInit(abKey)
    Debug.Print "KY=" & cv_HexFromBytes(abKey)
    
    ' Generate a random string of printable chars (0x20 SP to 0x7e '~')
    For n = 1 To 10
        nLen = Int(Rnd() * 100) + 1
        strData = ""
        For i = 1 To nLen
            strData = strData & Chr(Int(Rnd() * 95) + Asc(" "))
        Next
        Debug.Print "SN=" & n
        Call EncString(strData)
    Next
    
    ' Now do with random bytes instead (0 - 255)
    For n = 1 To 10
        nLen = Int(Rnd() * 100) + 1
        ReDim abData(nLen - 1)
        For i = 0 To nLen - 1
            abData(i) = CByte(Int(Rnd() * 256) And &HFF)
        Next
        Debug.Print "BN=" & n
        Call EncBytes(abData)
    Next

End Function

Public Function TestEncryptAsciiAndUnicode()
    Dim strData As String
    Dim strOutput As String
    Dim abData() As Byte
    Dim abKey() As Byte
    Dim i As Long
    
    ' Setup a 8-byte/64-bit key to use for Blowfish encryption
    ' Key = 0xfedcba9876543210
    ReDim abKey(7)
    abKey(0) = &HFE
    abKey(1) = &HDC
    abKey(2) = &HBA
    abKey(3) = &H98
    abKey(4) = &H76
    abKey(5) = &H54
    abKey(6) = &H32
    abKey(7) = &H10
    Call blf_KeyInit(abKey)
    
    ' Set plaintext in a String type
    strData = "Hello, world!"
    
    ' ----------------------------------------------
    ' Alternative 1. Convert string to byte array of ANSI/ASCII characters
    abData = StrConv(strData, vbFromUnicode)
    
    ' Display plaintext as a set of hex values
    ' This should print 13 bytes as follows:
    ' 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21
    ' H  e  l  l  o  ,     w  o  r  l  d  !
    For i = LBound(abData) To UBound(abData)
        Debug.Print Hex(abData(i)) & " ";
    Next
    Debug.Print
    
    ' Encrypt the byte array (with padding, overwriting plaintext)
    abData = blf_BytesEnc(abData)
    
    ' Display result
    ' Should be 16 bytes:
    ' AD 57 55 51 35 81 9E EC 18 90 34 F3 D7 53 25 8D
    For i = LBound(abData) To UBound(abData)
        Debug.Print Hex(abData(i)) & " ";
    Next
    Debug.Print
    
    ' Decrypt and display
    abData = blf_BytesDec(abData)
    For i = LBound(abData) To UBound(abData)
        Debug.Print Hex(abData(i)) & " ";
    Next
    Debug.Print
    
    ' Convert decrypted plaintext back to a VB String type
    strOutput = StrConv(abData, vbUnicode)
    Debug.Print strOutput
    
    ' ----------------------------------------------
    ' Alternative 2. Convert String to a Unicode byte array
    ' Ref: MS KB article Q187675
    ' HOWTO: Copy a String to a Byte Array Without Unicode Conversion
    abData = strData
    
    ' Display as a set of hex values
    ' This should print 26 bytes (NB two bytes for each character):
    ' 48 0 65 0 6C 0 6C 0 6F 0 2C 0 20 0 77 0 6F 0 72 0 6C 0 64 0 21 0
    For i = LBound(abData) To UBound(abData)
        Debug.Print Hex(abData(i)) & " ";
    Next
    Debug.Print
    
    ' Encrypt the byte array (with padding, overwriting plaintext)
    abData = blf_BytesEnc(abData)
    
    ' Display result
    ' Should be 32 bytes:
    ' 6B DC B3 4 F8 CF EF B4 62 89 1E 0 11 57 73 D3
    ' 4 C4 F0 6A FF 91 40 1E B7 BD 55 98 E2 B2 88 5E
    For i = LBound(abData) To UBound(abData)
        Debug.Print Hex(abData(i)) & " ";
    Next
    Debug.Print
    
    ' Decrypt and display
    abData = blf_BytesDec(abData)
    For i = LBound(abData) To UBound(abData)
        Debug.Print Hex(abData(i)) & " ";
    Next
    Debug.Print
    
    ' Convert decrypted plaintext back to a VB String type
    strOutput = abData
    Debug.Print strOutput
    
End Function

Public Function TestFileEnc() As Boolean
' Example encrypting file using blf_FileEnc()
' Input file is the 13 bytes:-
' 000000  68 65 6c 6c 6f 20 77 6f 72 6c 64 0d 0a           hello world..
' Output file should be the 16 bytes:-
' 000000  1a a1 51 b7 7a 5a 33 5c 4e 7e dc 84 a3 86 dc 96  .QzZ3\N~...

    Dim sFileIn As String
    Dim sFileOut As String
    Dim aKey() As Byte

    sFileIn = "C:\test\hello.txt"
    sFileOut = "C:\test\hello.enc"
    
    Debug.Print "Processing..."
    ' Load test key and initialise
    aKey() = cv_BytesFromHex("FEDCBA9876543210")
    Call ap_StartTimer
    Call blf_KeyInit(aKey)
    
    ' Encipher the file
    Call blf_FileEnc(sFileIn, sFileOut)
    Debug.Print "By blf_FileEnc: " & ap_EndTimer & " millisecs"
End Function

Public Function TestFileDec() As Boolean
' Decrypting an encrypted file
' This should produce an identical file to "hello.txt"
    Dim sFileIn As String
    Dim sFileOut As String
    Dim aKey() As Byte

    sFileIn = "C:\test\hello.enc"
    sFileOut = "C:\test\hello.dec"
    
    Debug.Print "Processing..."
    ' Load test key and initialise
    aKey() = cv_BytesFromHex("FEDCBA9876543210")
    Call ap_StartTimer
    Call blf_KeyInit(aKey)
    
    ' Encipher the file
    Call blf_FileDec(sFileIn, sFileOut)
    Debug.Print "By blf_FileDec: " & ap_EndTimer & " millisecs"
End Function


Public Function TestFileEncViaBytes()
' Shows how a file could be read into a byte array and then encrypted
' Try timing tests on your computer to see which is faster
' blf_FileEnc or blf_BytesEnc
    Dim sFilePath As String
    Dim sFileOut As String
    Dim sFileDec As String
    Dim abIn() As Byte
    Dim abOut() As Byte
    Dim aKey() As Byte
    Dim i As Long
    Dim lTime As Long
    
    sFilePath = "C:\test\sonnets.txt"
    sFileOut = "C:\test\sonnets.enc"
    sFileDec = "C:\test\sonnets.dec"
    
    ' Start the timer
    Call ap_StartTimer
    
    ' Read the file into a string ready to process
    abIn = ReadFileIntoBytes(sFilePath)
    Debug.Print "File is " & (UBound(abIn) - LBound(abIn) + 1) & " bytes long"
    
    ' Now set up key (=0x3132333435)
    aKey() = StrConv("12345", vbFromUnicode)
        
    ' And initialise Blowfish
    Call blf_KeyInit(aKey())
    
    ' Encrypt it
    abOut = blf_BytesEnc(abIn)
    ' Save as a file
    Call WriteFileFromBytes(sFileOut, abOut)
    
    ' Decrypt it
    abOut = blf_BytesDec(abOut)
    
    ' Now write to a file
    Call WriteFileFromBytes(sFileDec, abOut)
    
    ' This decrypted file should be identical to the original
    ' Use the DOS file compare command (fc) to check:-
    '   C:\Test>fc sonnets.txt sonnets.dec
    '   Comparing files sonnets.txt and sonnets.dec
    '   FC: no differences encountered
    
    ' Get the time
    lTime = ap_EndTimer()
    Debug.Print "Using blf_BytesEnc: ", lTime & " ms"
    
    ' Make sure we did it correctly
    If StrConv(abIn, vbUnicode) <> StrConv(abOut, vbUnicode) Then
        MsgBox "Encrypt error"
    End If
    
    ' Now do the same test but using the direct file encryption fns
    Call ap_StartTimer
    aKey() = StrConv("12345", vbFromUnicode)
    Call blf_KeyInit(aKey())
    ' Encrypt it
    Call blf_FileEnc(sFilePath, sFileOut)
    ' Decrypt it
    Call blf_FileDec(sFileOut, sFileDec)
    lTime = ap_EndTimer()
    Debug.Print "Using blf_FileEnc: ", lTime & " ms"
    
    
End Function

Public Function TestFileEncCBC() As Boolean
' Encrypts a file using CBC mode
' Input file is the 32 bytes:-
' 000000  37 36 35 34 33 32 31 20 4e 6f 77 20 69 73 20 74  7654321 Now is t
' 000010  68 65 20 74 69 6d 65 20 66 6f 72 20 00 00 00 00  he time for ....

' This should produce a file containing the 40 bytes
' 000000  6b 77 b4 d6 30 06 de e6 05 b1 56 e2 74 03 97 93  ................
' 000010  58 de b9 e7 15 46 16 d9 59 f1 65 2b d5 ff 92 cc  ................
' 000020  ec 04 44 13 2b c4 6e 49                          ........

' (there are 8 extra bytes because of padding)

    Dim sFileIn  As String
    Dim sFileOut As String
    Dim sCipher As String
    Dim sPlain As String
    Dim aKey() As Byte

    sFileIn = "C:\test\Nowis.txt"
    sFileOut = "C:\test\Nowis.enc"
    
    ' Load test key and initialise
    aKey() = cv_BytesFromHex("0123456789ABCDEFF0E1D2C3B4A59687")
    Call blf_KeyInit(aKey)
    
    ' Encipher the file in CBC mode
    Call blf_FileEncCBC(sFileIn, sFileOut, "FEDCBA9876543210")
    
    MsgBox "done"
End Function

Public Function TestFileDecCBC() As Boolean
' This should produce a file identical to what we started with
    Dim sFileIn As String
    Dim sFileOut As String
    Dim aKey() As Byte

    sFileIn = "C:\test\Nowis.enc"
    sFileOut = "C:\test\NowisDec.txt"
    
    ' Load test key and initialise
    aKey() = cv_BytesFromHex("0123456789ABCDEFF0E1D2C3B4A59687")
    Call blf_KeyInit(aKey)
    
    ' Decipher the file in CBC mode
    Call blf_FileDecCBC(sFileIn, sFileOut, "FEDCBA9876543210")
    MsgBox "done"
End Function

' ---- File read and write functions

Public Function ReadFileIntoString(sFilePath As String) As String
' Reads file (if it exists) into a string.
    Dim strIn As String
    Dim hFile As Integer
    
    ' Check if file exists
    If Len(Dir(sFilePath)) = 0 Then
        Exit Function
    End If
    hFile = FreeFile
    Open sFilePath For Binary Access Read As #hFile
    strIn = Input(LOF(hFile), #hFile)
    Close #hFile
    ReadFileIntoString = strIn
    
End Function

Public Function WriteFileFromString(sFilePath As String, strIn As String) As Boolean
' Creates a file from a string. Clobbers any existing file.
On Error GoTo OnError
    Dim hFile As Integer
    
    If Len(Dir(sFilePath)) > 0 Then
        Kill sFilePath
    End If
    hFile = FreeFile
    Open sFilePath For Binary Access Write As #hFile
    Put #hFile, , strIn
    Close #hFile
    WriteFileFromString = True
Done:
    Exit Function
OnError:
    Resume Done
    
End Function

Public Function ReadFileIntoBytes(sFilePath As String) As Variant
' Reads file (if it exists) into an array of bytes; returns as variant.
    Dim abIn() As Byte
    Dim hFile As Integer
    
    ' Check if file exists
    If Len(Dir(sFilePath)) = 0 Then
        Exit Function
    End If
    hFile = FreeFile
    Open sFilePath For Binary Access Read As #hFile
    abIn = InputB(LOF(hFile), #hFile)
    Close #hFile
    ReadFileIntoBytes = abIn
    
End Function

Public Function WriteFileFromBytes(sFilePath As String, abData() As Byte) As Boolean
' Creates a file from byte array. Clobbers any existing file.
On Error GoTo OnError
    Dim hFile As Integer
    
    If Len(Dir(sFilePath)) > 0 Then
        Kill sFilePath
    End If
    hFile = FreeFile
    Open sFilePath For Binary Access Write As #hFile
    Put #hFile, , abData
    Close #hFile
    WriteFileFromBytes = True
Done:
    Exit Function
OnError:
    Resume Done
    
End Function

Public Function TestFileBytes()
    Dim abData() As Byte
    Dim sFilePath As String
    
    sFilePath = "C:\Test\hello.txt"
    abData = ReadFileIntoBytes(sFilePath)
    Stop
    WriteFileFromBytes "C:\Test\helloout.txt", abData
End Function