# Sunday, November 27, 2005


IMPORTANT: The functions within this FLL have changed. Please refer to the latest documention for the VFP Encryption FLL that can be found at the following link:

Major VFP Encryption Update



The free vfpencryption.fll has been updated. Changes include:

  • Converted the vfpencryption project to Visual Studio 2005 (VC++ 8.0)
  • Added an RC4 Stream Cipher
  • Fixed a bug in the Hash() function that would truncate hashes if NULLs were returned anywhere in the message digest

The RC4 stream cipher that has been added is very useful in encrypting/decrypting fields in a table. Because it is a stream cipher, the resulting ciphertext (encrypted data) is the same length as the plaintext. Unlike a block cipher (which comprises all of the other ciphers that vfpencryption.fll provides), a stream cipher does not pad the results with extra characters. This means that RC4 can be used to encrypt and decrypt a field with a simple Replace command. No additional machinations are required. In any event, give it a try and see what you think.

Special thanks to Tomás Cané out of Santiago, Chile for the heads up regarding the bug in the Hash() function that was causing certain message digests (hash codes) to be truncated. This bug has been fixed.

Here is the link for the latest version of the vfpencryption.fll

Download the Latest Version of the VFP Encryption FLL (57 KB approx.)

I've also decided to offer a download of Microsoft's redistributable installer for the VC++ 8.0 runtimes to ease the problems some were encountering during deployment of the FLL. If you "SET LIBRARY TO vfpencryption.fll" in Visual FoxPro and get an error saying that the FLL is invalid, then you (or your client) don't have the required C runtimes installed. The installer available at the link below will solve this problem.

Download the Microsoft's installer for the VC++ 8.0 runtimes (2.5 MB approx.)

I hope that the documentation I am providing below is clear to everyone. If there is something further that I could do in order to make this FLL more useful or understandable, please let me know. I will be putting together some Visual FoxPro samples of use for this FLL in the near future to be included as a separate download.


 vfpencryption.fll Documentation...

Function ENCRYPT()

Signature: Encrypt(cStringtoEncrypt, cSecretKey[, nEncryptionType[, nEncryptionMode]])

Parameters:

cStringtoEncrypt - A plain text string that you want to have encrypted, such as "Hello World!"

cSecretKey - A plain text string that is the Key you want used during encryption, such as "My_SeCrEt_KeY".
Please note that keys may need to be of a particular length for certain types of encryption. Refer below for more information.

nEncryptionType - There are currently 5 types of encryption available. The value of this parameter determines that type of encryption used and how long your Secret Key should be. A single character in Visual FoxPro is  equal to 1 byte or 8 bits. So an encryption algorithm requiring a 128-bit key would need a Secret Key of 16 characters (16 x 8 = 128).

   0 = AES128 (requires a 16 character Key)
   1 = AES192 (requires a 24 character Key)
   2 = AES256 (requires a 32 character Key) *Default
   4 = Blowfish (requires a 56 character Key)
   8 = TEA (requires a 16 character Key)
   1024 = RC4 (Key can be any length)

nEncryptionMode - There are three different modes available for the each of the encryption types listed above. They include: Electronic Code Book (ECB), Cipher Block Chaining (CBC) and Cipher Feedback Block (CFB). The nEncryptionMode parameter does not apply to RC4 encryption (nEncryptionType = 1024).

   0 = ECB *Default
   1 = CBC
   2 = CFB

Return Value:

Character data type - the encrypted form of cStringtoEncrypt.

Remarks:

When saving the return value of Encrypt() function to a field in a table, remember that Visual FoxPro will append blanks to the end of the string in order to fill the character field to its designated length. This can cause problems when decrypting the data as the spaces will be considered part of the encrypted string. To work around this, I suggest placing a single CHR(0) at the end of the encrypted string when saving it to the table. Then when decrypting the data just the portion prior to the CHR(0) can be sent into the Decrypt() function. This does not apply when using RC4 encryption (nEncryptionType = 1024).


Function DECRYPT()

Signature: Decrypt(cEncryptString, cSecretKey[, nDecryptionType[, nDecryptionMode]])

Parameters:

cEncryptedString - A string that has been encrypted using the Encrypt() function.

cSecretKey - A plain text string that is the same Key that you used when you encrypted the data using the Encrypt function, such as "My_SeCrEt_KeY".
Please note that keys may need to be of a particular length for certain types of decryption. Refer below for more information.

nDecryptionType - There are currently 5 types of decryption available and they correspond to the same ones available in Encrypt(). A single character in Visual FoxPro is  equal to 1 byte or 8 bits. So an decryption algorithm requiring a 128-bit key would need a Secret Key of 16 characters (16 x 8 = 128).

   0 = AES128 (requires a 16 character Key)
   1 = AES192 (requires a 24 character Key)
   2 = AES256 (requires a 32 character Key) *Default
   4 = Blowfish (requires a 56 character Key)
   8 = TEA (requires a 16 character Key)
   1024 = RC4 (Key can be any length)

nDecryptionMode - There are three different modes available for the each of the encryption types listed above. They include: Electronic Code Book (ECB), Cipher Block Chaining (CBC) and Cipher Feedback Block (CFB). The nDecryptionMode parameter does not apply to RC4 decryption (nDecryptionType = 1024).

   0 = ECB *Default
   1 = CBC
   2 = CFB

Return Value:

Character data type - the decrypted form of cEncryptedString followed by a variable number of CHR(0)s. See Remarks below for further clarification

Remarks:

IMPORTANT: Decryption is done on blocks of memory, so when the decrypt function returns the encrypted string it will be followed by a variable number of CHR(0)s unless the decrypted string just happens to end at exactly the same location as the last block decrypted. These extraneous CHR(0)'s can be removed using a number of Visual FoxPro functions, such as STRTRAN(), CHRTRAN(), or a combination of LEFT() and AT(). This does not apply when using RC4 decryption (nDecryptionType = 1024).



Function ENCRYPTFILE()

Signature: EncryptFile(cFiletoEncrypt, cDestinationFile, cSecretKey[, nEncryptionType[, nEncryptionMode]])

Parameters:

cFiletoEncrypt - A plain text string that is the fullpath to the file you wish to be encrypted, such as "C:\SensitiveInfo.doc"

cDestinationFile - A plain text string that is the fullpath to an encrypted file you wish to have created on disk, such as "C:\EncryptedInfo.doc". If this file doesn't exist then it will be created for you.

cSecretKey - A plain text string that is the Key you want used during encryption, such as "My_SeCrEt_KeY".
Please note that keys may need to be of a particular length for certain types of encryption. Refer below for more information.

nEncryptionType - There are currently 5 types of encryption available. The value of this parameter determines that type of encryption used and how long your Secret Key should be. A single character in Visual FoxPro is  equal to 1 byte or 8 bits. So an encryption algorithm requiring a 128-bit key would need a Secret Key of 16 characters (16 x 8 = 128).

   0 = AES128 (requires a 16 character Key)
   1 = AES192 (requires a 24 character Key)
   2 = AES256 (requires a 32 character Key) *Default
   4 = Blowfish (requires a 56 character Key)
   8 = TEA (requires a 16 character Key)
   1024 = RC4 (Key can be any length)

nEncryptionMode - There are three different modes available for the each of the encryption types listed above. They include: Electronic Code Book (ECB), Cipher Block Chaining (CBC) and Cipher Feedback Block (CFB). This does not apply when using RC4 encryption (nEncryptionType = 1024).

   0 = ECB *Default
   1 = CBC
   2 = CFB

Return Value:

None

Remarks:

Currently the cFiletoEncrypt and cDestinationFile parameters cannot point to the same file. This may be revised in a future version. But for safety sake, this function requires that the original file be left untouched.



Function DECRYPTFILE()

Signature: DecryptFile(cEncryptedFile, cDestinationFile, cSecretKey[, nDecryptionType[, nDecryptionMode]])

Parameters:

cEncyptedFile - A plain text string that is the fullpath to the file you wish to be decrypted, such as "C:\EncryptedInfo.doc"

cDestinationFile - A plain text string that is the fullpath to a decrypted file you wish to have created on disk, such as "C:\SensitiveInfo.doc". If this file doesn't exist then it will be created for you.

cSecretKey - A plain text string that is the same Key that you used when you encrypted the data using the Encrypt function, such as "My_SeCrEt_KeY".
Please note that keys may need to be of a particular length for certain types of decryption. Refer below for more information.

nDecryptionType - There are currently 5 types of decryption available and they correspond to the same ones available in Encrypt(). A single character in Visual FoxPro is  equal to 1 byte or 8 bits. So an decryption algorithm requiring a 128-bit key would need a Secret Key of 16 characters (16 x 8 = 128).

   0 = AES128 (requires a 16 character Key)
   1 = AES192 (requires a 24 character Key)
   2 = AES256 (requires a 32 character Key) *Default
   4 = Blowfish (requires a 56 character Key)
   8 = TEA (requires a 16 character Key)
   1024 = RC4 (Key can be any length)

nDecryptionMode - There are three different modes available for the each of the encryption types listed above. They include: Electronic Code Book (ECB), Cipher Block Chaining (CBC) and Cipher Feedback Block (CFB). This does not apply when using RC4 decryption (nDecryptionType = 1024).

   0 = ECB *Default
   1 = CBC
   2 = CFB

Return Value:

None

Remarks:

As with EncryptFile(), the cFiletoEncrypt and cDestinationFile parameters cannot point to the same file.


Function HASH()

Signature: Hash(cStringtoHash[, nHashType])

Parameters:

cStringtoHash - A plain text string you wish to have hashed

nHashType - The type of hash function to generate. There are currently 7 different hash functions supported

1 = SHA1 (a.k.a SHA160)
2 = SHA256
3 = SHA384
4 = SHA512 *Default
5 = MD5
6 = RIPEMD128
7 = RIPEMD256

Return Value:

Binary Character Data - the hash for cStringtoHash.

Remarks:

The hash is returned as a series of binary characters. However, it is more common to see hashes in a hexBinary format. This can be accomplished in Visual FoxPro by taking the return of the Hash() function and sending it in as a parameter to the STRCONV() function. For example:

?STRCONV(Hash("Some String"), 15) && hexBinary Hash


Function HASHFILE()

Signature: HashFile(cFileName[, nHashType])

Parameters:

cFileName - The fullpath and name of an existing file you wish to generate a message digest for

nHashType - The type of hash function to generate. There are currently 7 different hash functions supported

1 = SHA1 (a.k.a SHA160)
2 = SHA256
3 = SHA384
4 = SHA512 *Default
5 = MD5
6 = RIPEMD128
7 = RIPEMD256

Return Value:

Binary Character Data - the hash for cFileName.

Remarks:

The hash is returned as a series of binary characters. However, it is more common to see hashes in a hexBinary format. This can be accomplished in Visual FoxPro by taking the return of the HashFile() function and sending it in as a parameter to the STRCONV() function. For example:

?STRCONV(HashFile("C:\MyFile.txt"), 15) && hexBinary Hash

Sunday, November 27, 2005 3:17:42 AM (GMT Standard Time, UTC+00:00)  #    Comments [19]
Monday, November 28, 2005 4:14:14 AM (GMT Standard Time, UTC+00:00)
Hi Craig,

This is all really exciting... For some reason, the RC4 Stream Cipher returns unanticipated characters under certain combinations of Field/Expression Lengths and Password Combinations. Could you take a look?

Again, these behavior is not consistent; only certain combinations trigger it.

** Sample of Problem **

SET LIBRARY TO VFPEncryption.FLL

CREATE TABLE myTable (myField C(28))
INSERT INTO myTable (myField) VALUES ("QTAS DE CANOVANAS")

REPLACE MyField WITH ENCRYPT(MyField,"RUSHLIFE",1024)

BROWSE

REPLACE MyField WITH ENCRYPT(MyField,"RUSHLIFE",1024)

BROWSE
Monday, November 28, 2005 4:17:20 AM (GMT Standard Time, UTC+00:00)
PD: You will want to issue a:

? MyField

or simply APPEND BLANK, Then BROWSE.

The highlight will conceal the unintended characters
Monday, November 28, 2005 3:17:22 PM (GMT Standard Time, UTC+00:00)
Will there be a version of VFPENCRYPTION that uses the Visual C runtime that ships with VFP 9? Your recompile under VC 8 means that your 60K FLL now requires 2.6M of additional files to distribute. This almost doubles the size of a typical VFP setup. BTW: Great website - I gotta lot of reading to do to catch up on all your content!
Monday, November 28, 2005 3:19:40 PM (GMT Standard Time, UTC+00:00)
Craig: Is there anyway you can remove my email address from my previous post. I mistakenly assumed that email adddresses would be kept private. Thanks! Bill Gunn
Bill Gunn
Tuesday, November 29, 2005 1:38:17 AM (GMT Standard Time, UTC+00:00)
Kenneth,

Thanks for the repo code. That is very strange behavior you have found. I will see what I can do to fix it. Thanks for the heads up.

Bill,

I have removed your email addy. I have been thinking about providing a Visual Studio 6.0 version of the FLL to lessen the bloat. Creating a C++ 7.1 version of the FLL (which is what VFP 9.0 uses would lessen the bloat somewhat but the msvcr71.dll (488 KB) and msvcp71.dll (340 KB) would both still be required runtimes. C++ 6.0 provides the best way for us to reduce the size - I think only the FLL would be needed on Win98 and above.

Eventually users will need to get the latest version of .NET in order for their windows apps to function properly on windows. We shouldn't have to include any of this stuff, just the FLL and then require users to have the latest .NET framework installed. But, those days aren't here yet.

I provided the MS installer to just make stuff easier even though it is large and provides runtimes and stuff that aren't needed. For this version of the FLL (built with VC++ 8.0). The runtimes that it actually uses are mscvr80.dll, msvcp80.dll, and msvcm80.dll. Total size 1616 KB. However, the pain is that on older systems (pre-WinXP) the files need to go into the System32 directory and the WinSxS directory (if WinSxS isn't there then you create it). On Windows XP or newer systems the files just get installed into the WinSxs directory, unless you want to place them in a "Microsoft.VC80.CRT" directory that is in the same directory as the vfpencryption.fll. See how convoluted all of this is at the moment while Microsoft tries to make the transition? In any event, I felt it much easier to just provide the installer that is about 1 MB larger than try to explain all of these different ways of providing just the runtimes needed.

I do however think that a VC++ 6.0 version would be useful for those needing something much smaller for their VFP application, so I appreciate your suggestion Bill.

Thanks for the kind words regarding my site. I hope you find the information out here useful.
Tuesday, November 29, 2005 2:11:50 PM (GMT Standard Time, UTC+00:00)
Craig: Thanks(!) for fixing my email address and for the details behind various VC runtimes.

1. Comment regarding the VC 7.1 runtimes:

On my XP SP2 system, the MS VC 7.1 runtime files are:

msvcr71.dll = 348,160 Feb 21 2003 (as shipped with VFP 9)
msvcp71.dll = 499,712 Mar 18 2003 (zips to 132K)

IMO, I'm don't think we should consider the size of msvcr71.dll when comparing different VC runtime sizes because this DLL needs to ship as part of all VFP 9 setups so its already a "given".

2. I like your idea of a standalone VC 6 compile, but fear that this adds additional effort to your plate and may remove the extra functionality/bugfixes present in the VC 7.1 runtimes.

3. I totally agree with your conclusion that it is not reasonable to depend on our users having an up-to-date version of the .NET CLR (VC 8 runtimes) installed.

To wrap up: Unless you have plans to take advantage of VC 8 specific functionality in the future, I believe a VC 7.1 strategy makes the most sense for your FLL's ... this is a strategy that balances distribution overhead/complexity against bug fixes/enhancements.

PS: Is it possible to RSS subscribe to your blog's comments?
Bill Gunn
Wednesday, December 21, 2005 5:45:15 PM (GMT Standard Time, UTC+00:00)
Hi Craig,

Great FLL.

I haven't got the latest version but I wondered why I cannot get the FLL to work on Win98. I used dependancy walker to look at which DLL's it uses and I've made sure the 98 machine has the MSVCP70.dll and MSVCR70.dll. Am I missing something? Is the FLL using calls in different versions of the kernel32?

Cheers

Rich.
Richard Norris
Tuesday, January 24, 2006 9:14:05 PM (GMT Standard Time, UTC+00:00)
Hi Craig, great work!

Is it possible to handle Blob Fields with this encryption engine?

Thansk
Sam
Thursday, January 26, 2006 1:09:49 PM (GMT Standard Time, UTC+00:00)
Hello Craig,

In some cases hash('string',5) returns a short string in foxpro because of a chr(0) value in the returned hash value. Can you tell me how to handle this?

Thanks,

Thursday, February 02, 2006 10:42:08 PM (GMT Standard Time, UTC+00:00)
Hi Craig,

I'm thinking of using your encryption fll (terific project BTW), but I'm a bit wary given the "QTAS DE CANOVANAS" problem illustrated by Kenneth.
Have you had a look at this yet?

Thanks.
Paul Elliott
Paul Elliott
Sunday, February 19, 2006 7:26:40 PM (GMT Standard Time, UTC+00:00)
Hi, I am not a programmer but I need the mscvr80.dll and mscvp80.dll files to fix a couple of errors. I cannot locate them anywhere. Can one of you guys send them to me at the address above? Thanks!
Jeff
Friday, February 24, 2006 7:17:18 AM (GMT Standard Time, UTC+00:00)
Kenneth,

Great catch and it has been fixed now in the latest release. See my blog post on 02-24-2006.

Richard,

You're not using the correct runtimes. There are two versions of this FLL now. One that uses the C++ 7.1 runtimes (Visual Studio 2003) and one that uses the C++ 8.0 runtimes (Visual Studio 2005). There isn't a version of this that runs with the 7.0 libraries (Visual Studio 2002).

Sam,

The library is set up to handle files and strings. I guess you could export a blob to file and do it there then bring it back into the database. Allowing for binary fields is an interesting thought though. Maybe a future enhancement.

Gé,

Yeah, null terminators are a pain when it comes to VFP. One way around this would be to use the STRCONV(Hash("string",5), 5) to return the hex equivalent of the message digest.

Paul,

See my reply to Kenneth. Its fixed now.

Jeff,

I'm not in the business of distributing Microsoft runtimes without a product, but you might want to look at the link in my blog entry above -- "Download the Microsoft's installer for the VC++ 8.0 runtimes"
Friday, March 10, 2006 6:20:59 PM (GMT Standard Time, UTC+00:00)
i'm not sure what HTML is, so i'm not sure if i am using it or not.
am running xp home edition and in running my norton system check i keep getting told i have 10 problems where the files cannot find mscvr80.dll.
can somebody please help me? i'm a retired heavy equipment operator, and don't know squat about these computers.
steve walker
Friday, March 10, 2006 6:37:13 PM (GMT Standard Time, UTC+00:00)
Hi Steve,

In this blog entry (above) you will find a link to "Download the Microsoft's installer for the VC++ 8.0 runtimes"... download that and install it. It might fix the problem you are experiencing... if not then you'll probably need to download and reinstall the entire .NET framework. As for HTML, it's a markup language and no, you didn't type any of it. Good luck.
Wednesday, April 05, 2006 3:00:38 PM (GMT Daylight Time, UTC+01:00)
Hi Craig, This library is excellent! Unfortunately, I'm having trouble with the hashFile() function. I get intermittent but persistent "API call caused an exception" errors when attempting to hash any single file (tested with three different files). Are there any limitations (size, spaces-in-filename, etc.) that may be causing the error? -JC
John Clarke
Saturday, August 26, 2006 10:32:38 PM (GMT Daylight Time, UTC+01:00)
Hi
Please if it's possible name the vc++ 7.1 runtime files and vc++ 8.0 files
i need these files names because in some win98 the vc runtimes installer does not work and i have to setup them manually
Thanks
Monday, March 19, 2007 2:30:40 PM (GMT Standard Time, UTC+00:00)
Hello,
Thanks for an excellent module. I am having an issue decrypting from C# however (the decrypt in Fox works beautifully).
I am using AES 128 encryption with CBC blocking and can't seem to get the decryption working in C#.
Below is the code I am trying to use (just for reference if it helps). Any help you can provide would be much appreciated.
<pre>
RijndaelManaged myRijndael = new RijndaelManaged();
myRijndael.BlockSize = 128;
myRijndael.KeySize = 128;
myRijndael.Key = ASCIIEncoding.ASCII.GetBytes(theKey);
myRijndael.IV = ASCIIEncoding.ASCII.GetBytes(theKey);
FileStream fsread = new FileStream(bulletPath,
FileMode.Open,
FileAccess.Read);
ICryptoTransform aesDecrypt = myRijndael.CreateDecryptor();
CryptoStream cryptostreamDecr = new CryptoStream(fsread,
aesDecrypt,
CryptoStreamMode.Read);
StreamWriter fsDecrypted = new StreamWriter(outputFile);
fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
fsDecrypted.Flush();
fsDecrypted.Close();
</pre>
Wednesday, December 17, 2008 6:00:10 PM (GMT Standard Time, UTC+00:00)
I'm having an issue that I can't figure out.

When using decrypt in runtime(v9 sp1) I get a "data type missmatch error"

When running the same code from the development environment (v9 sp1) it works fine.

Any Suggestions??
*************************************
Code
lcDecrypt = ALLTRIM(LEFT(tcString, AT(CHR(0), tcString) - 1))

lcPassKey=[<key goes here>]
lcDecrypt = Decrypt(lcDecrypt,lcPassKey , 1, 0)
Alan
Wednesday, January 28, 2009 3:25:38 AM (GMT Standard Time, UTC+00:00)
I would like to know where I can download the mscvp80.dll so I can fix some errors on my computer. If you could email me and let me know if I could do that and where I would appreciate it. Thank you.
Karen
All comments require the approval of the site owner before being displayed.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, sup, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview

 

Archive

<February 2012>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910