# Saturday, September 03, 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



Steve Tootill reported that the DecryptFile() function was not working for dbf's. On closer inspection, I found there was a problem with the original Visual C++ code that was written by George Anescu from which the encryption and decryption features of the vfpencryption.fll is derived.

The problem is that basically George just returned entire decrypted blocks and didn't take into consideration the original file size. To fix this I have added a single byte to the end of the file before it is encrypted that tells the decryption functions how long the original file is. This byte is read into memory and the decrypted file is sized appropriately... thus eliminating the extraneous padding characters from the end of the file. For more detailed information regarding this FLL please refer to my earlier post:

Visual FoxPro - Encrypt and Decrypt Files

Here is the latest download for the VFP Encryption FLL (NOTE: all downloads on this weblog for the VFP Encryption FLL point to the latest version)

Download VFP Encryption FLL (58 KB approx.)

Saturday, September 03, 2005 7:01:54 AM (GMT Daylight Time, UTC+01:00)  #    Comments [9]
Sunday, September 11, 2005 5:39:47 AM (GMT Daylight Time, UTC+01:00)
Hi Craig,

You have helped me twice at the Tek-Tips (THANKS AGAIN!) Forum and I downloaded your Encrypt/Decrypt FLL...

The execution speed of your .fll is fantastic; I really want to be able to use it..

I have tried various things with the TAE version but have encountered some things for you to review?

(a) --- Using it on a SELECT-SQL

VFP returns a FieldSize bigger than the original with padded characters (CHR(0) and spaces)... The latter is easily fixed : ALLTRIM(STRTRAN(deCRYPT(KeyWord,m.A128BitKey,8),CHR(0),"")) AS DecrKeyWord

But perhaps the size of the selection could be made to match the original field/expression from the get-go.

(b) --- ENCRYPT is a reserved VFP word

Since ENCRYPT is a reserved VFP word, I wonder if your function should alter that function name to avoid unknown conflicts. Also might as well pair any change of function name of ENCRYPT to its counterpart DECRYPT.

(c) --- API Exception Error

This last one is the one that will need your attention... I am only using the TAE version, perhaps the others are OK. But, in my case/appl, is more about performance than security.

If I do a REPLACE ALL.... ENCRYPT(...) on a field and then run the reverse DECRYPT(... I always end up with an API Exception Error starting with the first record. I have looked to see if perhaps the parameters where wrong or the seed, but they are alright.

----------------

I am sure you will be able to work this out, and it is going to be bullet-proof soon!

Regards,

Kenneth Tamayo
San Juan, PR - USA


Sunday, September 11, 2005 5:41:55 AM (GMT Daylight Time, UTC+01:00)
Please remove my email from the display... Don't need any more spammers!!!!
Monday, September 12, 2005 10:17:39 PM (GMT Daylight Time, UTC+01:00)
Hi Kenneth,

I've removed your email address. Also, you make some pretty good points. Here are my responses and some sample code:

a) Definitely. I have toyed with some ideas of how to remove the chr(0) padding that comes back from a decrypted string. Since these are block ciphers, the return is padded. One way to do this would be to add a byte to the encrypted text that would tell the decryption algorithm how many bytes are padded, then it could remove them before returning. For now, you are using the correct way to remove them, though concatenating a chr(0) flag when it is encrypted would also be a good idea (see my code below)

b)Encrypt is only a reserved word because there is a little known SET statement... SET ENCRYPTION ON/OFF - this has no effect on the VFP environment however. Perhaps the MS Fox Team was thinking about giving us native encryption at one time? There are no compatibility errors with using Encrypt, even though it is tagged as a keyword.

c)The API exception is caused because the encryption string you are sending into the decrypt function is invalid. Below is some working example code for you to try. I've commented to code so you can see what I am doing. Even with the additional machinations, I think you will find that the code is extremely fast when used with a much larger data set.

*!* Example of use
#DEFINE PRIVATEKEY "ISTOTALSECRETKEY"
CREATE CURSOR crsPeople (firstname c(25))
INSERT INTO crsPeople (firstname) VALUES ("Craig")
INSERT INTO crsPeople (firstname) VALUES ("Kenneth")
INSERT INTO crsPeople (firstname) VALUES ("Sue")
INSERT INTO crsPeople (firstname) VALUES ("Claire")
INSERT INTO crsPeople (firstname) VALUES ("Bill")

SET LIBRARY TO LOCFILE("vfpencryption.fll")
*!* For encryption we don't want the field padding to be included
*!* We also set a flag that shows where the encryption ends by using Chr(0)
replace ALL firstname WITH Encrypt(ALLTRIM(firstname), PRIVATEKEY, 8, 0) + CHR(0) IN "crsPeople"
BROWSE && All field values are encrypted
*!* For decryption we want to check for the flag chr(0) and grab everything before it using Left() and RAT()
*!* Then we want to strip any Chr(0) padding from the decrypted block
replace ALL firstname WITH CHRTRAN(Decrypt(LEFT(firstname, RAT(CHR(0), firstname) - 1), PRIVATEKEY, 8, 0), CHR(0), "") IN "crsPeople" && key is 16 bytes
BROWSE && All field values are decrypted
Tuesday, September 13, 2005 1:17:40 AM (GMT Daylight Time, UTC+01:00)
Craig,

Thanks for the input and for investing the time...!!


Still API exceptions to report, try Decrypting after Encrypting...:

INSERT INTO crsPeople (firstname) VALUES ("MIRADOR DE BORINQUEN GDNS")
INSERT INTO crsPeople (firstname) VALUES (" ")


One could place a FOR EMPTY(...) condition and that would prevent the 2nd entry from generating the error but ideally, it would be great to even fill out empty records with the encrypted equivalent of spaces. It looks odd to have some records encrypted and others simply blank IMHO.

I don't know what's the problem with entries like the first one... I tried changing the field's precision/length to say 30 characters --- thinking, perhaps the function NEEDED to find a CHR(0) --- but that also triggered the API exception. Eventually, with some field length definitions the Decrypt function did not result in API exceptions... 33+ characters wide fields generally worked but considering the expression is only 25 characters long, it's all hit and miss.

Another concern; if a user is able to open a table with an encrypted expression/field and he where to alter its content removing the CHR(0) marker, would any attempts to later decrypt that expression also possibly trigger an API exception?

Many many thanks!!

Kenneth
Tuesday, September 13, 2005 3:54:34 AM (GMT Daylight Time, UTC+01:00)
The problem with encrypting all the spaces or even encrypting the contents of a field that is filled in completely is that the original space is not large enough to handle the encrypted text. Case in point... let's say you have a 25 character field as I've shown above. Using TEA for instance the ciphertext for that 25 character field will be 32 characters long. This is because in block ciphers it deals with blocks of data, unlike a stream cipher. So, when you go to replace the field with the 32 bytes of ciphertext, it will be truncated at 25 bytes and result in the decrypt routine throwing an error. There's no easy answer to this, I'm afraid. I could pad the encrypted string with the total length of padding, and then truncate that during decryption, but then it would be difficult for a developer to tell how long they must make the field to accomodate it. Maybe a bigger problem than what we have now?

In the following example, I've modified the code I posted above that should clearly show that it is the size of the fields (and subsequent padding done by a block cipher) that is causing the problem. Try this:

*!* Example of use
#DEFINE PRIVATEKEY "ISTOTALSECRETKEY"
CREATE CURSOR crsPeople (firstname c(32)) && note I have changed fieldsize from 25 to 32 (any multiple of 8 will work for TEA: 16, 24, 40, 48, etc.)
INSERT INTO crsPeople (firstname) VALUES ("Craig")
INSERT INTO crsPeople (firstname) VALUES (" ")
INSERT INTO crsPeople (firstname) VALUES ("Kenneth")
INSERT INTO crsPeople (firstname) VALUES (" ")
INSERT INTO crsPeople (firstname) VALUES ("Sue")
INSERT INTO crsPeople (firstname) VALUES (" ")
INSERT INTO crsPeople (firstname) VALUES ("Claire")
INSERT INTO crsPeople (firstname) VALUES (" ")
INSERT INTO crsPeople (firstname) VALUES ("Bill")

SET LIBRARY TO LOCFILE("vfpencryption.fll")
replace ALL firstname WITH Encrypt(firstname, PRIVATEKEY, 8, 0) IN "crsPeople"
BROWSE && All field values are encrypted
replace ALL firstname WITH Decrypt(firstname, PRIVATEKEY, 8, 0) IN "crsPeople" && key is 16 bytes
BROWSE && All field values are decrypted
Tuesday, September 13, 2005 1:06:49 PM (GMT Daylight Time, UTC+01:00)
I understand the nature of the beast at this point and realize why a block cipher may not be the most suitable option in some specific cases. Perhaps this type of encryption would work perfectly with MEMO-type fields but one would need to devise decoy encryption string for EMPTY entries.

I can see why block ciphering would be perfect for encrypting a complete file rather than fixed-field-length instances. In such cases disk-size does not make much difference.

Do you know of any stream-based ciphers out there? Does the contributed FLL contain one?

-------

Thanks again for putting in all this effort in helping me (and the rest of the VFP community that no doubt are beginning to tune in into this valuable blog on a regular basis!).

Given the quality of your output and the interest in Visual FoxPro, I can foresee increasingly high-bandwith demands placed on your web-server in the future.
Saturday, October 01, 2005 9:37:39 AM (GMT Daylight Time, UTC+01:00)
Hi Kenneth,

I'm working on adding RC4, PIKE, SEAL, and PC1 stream ciphers to the library, however for right now it only provides block ciphers and hash functions. If you can wait until just after I present at Southwest Fox then I think I will be able to get you what you need in this FLL. For a more immediate solution you may want to try using CAPICOM from MS which provides access to RC4.
Friday, October 07, 2005 1:41:41 AM (GMT Daylight Time, UTC+01:00)
Hi Craig,

Thanks again for keeping this in mind!!!!! I will definitely keep stopping by for this and any other fantastic contribution you may extend to the VFP community.

I am still hoping for a small miracle down here in order to get in the plane to Arizona/SouthWest Fox Conference. Would really like to attend your presentation and perhaps be able to show you the application I've been working on. If not possible this year, I sure hope to do so in next year's FoxPro Advisor DevCon. I already bought my VFP polo-shirt from FoxToolBox.com for the occassion!!

The stream cipher options will be godsend for those field-bound replacements/encryption/decryption procedures...
Monday, September 29, 2008 4:00:33 PM (GMT Daylight Time, UTC+01:00)
You look nice in that color.
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