Blowfish in Classic Visual Basic VB6
This page comments on the changes in (our) version 6 of our code for Blowfish in Classic Visual Basic (VB6/VBA). Our original Blowfish in VB was first published in October 2000. Version 6 of the code was released in November 2003. To download the source code, go to Blowfish: a Visual Basic version.
Strings vs Bytes
In previous versions of our Blowfish Visual Basic code, we used the VB 'String' types to store the data before and after encryption. We developed this on a W98 computer set up for the ordinary US-ASCII character set and it all worked OK, well for us anyway. To carry out encryption we had theblf_StringEnc()
and blf_StringDec()
functions which worked as follows
strCipher = blf_StringEnc(strPlain)
We now acknowledge that this is not the correct way to store binary data and may lead to problems on systems set up for full 32-bit Unicode or oriental CJK character sets. The input to and output from any encryption algorithm is a bit string and the safest way to ensure that all the bits stay exactly as you want them is to use arrays of the VB 'Byte' type.
Sure, you can use a 'String' type to store binary values and you can treat each individual character as an 8-bit byte if your system is set up in ANSI. After all, Strings are easier to create and manage in VB. But it doesn't necessarily work across all system setups.
What we should do
All operations on 'binary' data should carried out using the Visual Basic Byte
type, and all textual data (original text input, password and base64-encoded data) should be stored in
the VB String
type. It is important to make sure you differentiate between these two types of
data - broadly speaking 'text' and 'binary' - when doing cryptographic operations in Visual Basic.
'Text' consists of readable, printable characters we expect to see on our computer screen or in a book. It might consist of simple US-ASCII/ANSI characters or it could be Unicode or DBCS oriental character strings. 'Binary' data is a string of bits that we conventionally store as bytes or octets.
Binary data must be exactly the same literally bit-for-bit in all systems. Change one bit and the results of
any cryptographic operation on it will be completely different. The way to ensure our binary data is always the same is
to use the Byte
type to store binary data, not the String
type.
Text data may be stored differently depending on the particular system we are using. On a ANSI system, each character is stored in one byte. On a Unicode system each character is stored in two bytes; and on a DBCS system, a character may be stored in one or two bytes. It is important to make sure we always convert our 'text' data into exactly the same 'binary' form before we do any encryption.
The input to an encryption process must be 'binary' data. We need to convert the text we want to encrypt into
'binary' format first and then encrypt it. The results of encryption are always binary. Do not attempt
to treat raw ciphertext as 'text' or put it directly into a String
type.
Store ciphertext either as a raw binary file or convert it to base64 or
hexadecimal format. You can safely put data in base64 or hexadecimal format in a String
.
When you decrypt, always start with binary data, decrypt to binary data, and then and only then, convert back to text, if that is what you are expecting. You can devise your own checks to make sure the decrypted ciphertext is what you expect before you do the final conversion, perhaps by checking that the first few bytes are valid printable ASCII characters in the range 0x20 to 0x7e (plus the control characters TAB (0x09), CR (0x13) and LF (0x10)).
On a US-English system set up for ANSI characters, you can probably get away with using a String
type to carry out 'binary' operations. However you will encounter problems on a system set up for
Chinese/Japanese/Korean/Hebrew/Arabic characters.
Changes in Version 6
We have replaced the twoblf_StringEnc()
and blf_StringDec()
functions with
new blf_BytesEnc()
and blf_BytesDec()
functions
that work with arrays of Bytes.
The onus is now on the user to convert their textual plaintext data into an unambiguous array of bytes before carrying out encryption and back again after decryption.
The first example shows how to encrypt some simple ASCII plaintext using the Visual Basic StrConv
function to convert the String into an array of Bytes before encryption.
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 strResultThis should produce the following output in the Immediate Window:
KY=FEDCBA9876543210 PT=48656C6C6F2C20776F726C6421 CT=AD57555135819EEC189034F3D753258D P'=48656C6C6F2C20776F726C6421 Hello, world!This second example shows how to encrypt the same string but this time it converts the VB 'String' directly without Unicode conversion. Remember that VB always stores all its strings internally as 16-bit (two-byte) Unicode characters. It then goes to great lengths to hide this fact from us, until, of course, we want to do bit-string manipulation on them.
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 strResultThe results of this will be:
KY=FEDCBA9876543210 PT=480065006C006C006F002C00200077006F0072006C0064002100 CT=6BDCB304F8CFEFB462891E00115773D304C4F06AFF91401EB7BD5598E2B2885E P'=480065006C006C006F002C00200077006F0072006C0064002100 Hello, world!
ANSI vs Unicode
Note how changing just two lines in the code produced two completely different results for the ciphertext:CT=AD57555135819EEC189034F3D753258D CT=6BDCB304F8CFEFB462891E00115773D304C4F06AFF91401EB7BD5598E2B2885Eand that was for an identical string of plain text "Hello, world!".
In the first example the string "Hello, world!"
of 13 characters was converted into
exactly 13 bytes where "H"=0x48, "e"=0x65, "l"=0x6C, ..., "!"=0x21. The encryption function padded
this to 16 bytes (the next highest multiple of the Blowfish block size of 8 bytes) and then encrypted it.
This sort of ANSI-to-byte conversion was implicit in our now
deprecated use of blf_StringEnc()
functions.
In the second example, the string of 13 characters is converted into its Unicode equivalent where each character is a 2-byte value "H"=0x0048, "e"=0x0065, ..., "!"=0x0021 (stored, you will note, in little-endian order 0x48006500...). This gives us 26 bytes of plaintext to encrypt. The Blowfish encryption function doesn't care what the bytes represent; it just sees a string of bits that we have stored conveniently in 8-bit containers. Provided we convert back to a 'String' in the reverse manner after decryption, we end up where we started.
More Information
For more information on dealing with Unicode and ANSI characters sets see Cryptography with International Character Sets.
See also
Back to the Cryptography Page.
Contact us
To comment on this page or to contact us, please send us a message.
This page first published November 2003. Last updated 9 September 2025.