FileFlex' core encryption technology is "office quality", meaning its good enough for casual protection in an office environment, but far from "spook-proof". FileFlex encryption will prevent casual users from gaining access to data, but won't stop determined hackers from cracking the code.
We originally intended to implement DES but determined that DES wouldn't encrypt in-place and was quite slow. In-place encryption is critical; when you've got a 30-character field, you want to make sure the encrypted data will fit back into it. The FileFlex encryption routines do on-the-fly, dynamic encryption and are exceptionally fast.
While there's no technical reason you can't encrypt everything, FileFlex doesn't support encryption of non-alphanumeric fields. This is because the encrypted data is totally random and you couldn't put the data back into the fields. If you want to encrypt numbers (i.e., salary data), store them in alphanumeric fields. For speed reasons, FileFlex doesn't check to see if you're attempting to encrypt or decrypt from a non-text field. FileFlex will attempt to encrypt or decrypt the data. However, the results are likely to be invalid or unreliable.
In practice, you also shouldn't encrypt any field you intend to search or index. In theory, you could do an indexed or relational search on encrypted data by doing a search for the encrypted string. But this doesn't seem really viable in practice.
Encryption keys should be printable characters. Encryption using keys and strings that aren't standard characters may be unreliable. In other words, you can use the following characters:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890 ~!@#$%^&*()_+true|<>?,./:";'`
Also, the DBGetMatchList function will not work with encrypted data, nor will DBFillColumn or DBColumnMash. In short, no table or column functions work with encryption because all rely on the newline character.
Standalone Encryption (DBEncrypt and DBDecrypt)
The easiest commands to use are DBEncrypt and DBDecrypt. Both take as arguments a string and a key and return either an error code or an encrypted or decrypted string, as appropriate. In the following sample line, "ardvark" is the key:
put DBDecrypt(field "src","aardvark") into plainText put DBEncrypt(field "src","aardvark") into scrambleText
Dynamic, On-the-Fly Encryption Functions
The idea behind dynamic encryption is that the data is plain-text in your project but enroute to or from a FileFlex data file the data is encrypted. Dynamic encryption options are extensions to existing FileFlex functions. The extended functions include:
FileFlex Function Encryption Mode ----------------- --------------- DBGetCurrRecVal dynamic decrypt DBWriteRec dynamic encrypt DBGetFieldByName dynamic decrypt DBGetMemo dynamic decrypt DBWriteMemo dynamic encrypt
Syntax of DBWriteMemo is DBWriteMemo(memoField, memoVal). An optional "E" or "Encrypt" parameter and a key parameter has been added to the DBWriteMemo call so that the encryption syntax is:
DBWriteMemo(memoField, memoVal [, encryptFlag, key])
Note: Everything inside the brackets "" are optional.
put DBWriteMemo("MYMEMO",fld "memo","E","aardvark") ¬ into theResult
Same idea as DBWriteMemo. Encryption syntax is:
DBGetMemo(memoField [, decryptFlag, key])Example:
put DBGetMemo("MYMEMO","D","aardvark") into fld "memo"
In both cases, decryption requires additional parameters:
DBGetFieldByName(fieldName [, decryptFlag,key])Example:
put DBGetFieldByName("SALARY","D","aardvark") into fld "salary"
Some Background on Implementation Choices
When you look at DBGetCurrRecVal, this is where things start to get interesting. Encryption/decryption couldn't be implemented with just an "E" or "D" parameter since that would require you to encrypt or decrypt ALL the fields at once. This is not practical. The easiest "out" would have been to require you to get encrypted fields one field at a time using DBGetMemo and DBGetFieldByName. This isn't wasn't slick as we wanted and user feedback indicated it would be overly onerous in your development cycle.
The next choice was to specify the whether a field is to be encrypted by prepending some special character in front of a field name, and this way the program would be able to check the first character. If the first character was the special character, the field would be decrypted. The problem with this approach is that you'd have to redefine the whole bloody database schema each time you switched from an encrypted field to an unencrypted field (and vice versa). But it's pretty easy to understand and is marginally elegant.
How Field-List Decryption Works
The third choice was to pass a list of field names to the DBGetCurrRecVal function when decrypting. This is the method that's been implemented in FileFlex. Here's how it works:
Assume the variable "decryptList" contains a comma-delimited list of fields to be decrypted. Here's an example:
To turn on decryption, you'd pass a "D" parameter. (You want to be able to specifically turn on decryption because checking field names will be slower than normal operations--and therefore you don't want it on when not necessary).
Here's an example to bring data back into a global:
put DBGetCurrRecVal("GD",decryptList,"aarvark") into theResult"G" for global variables, "D" is the decryptFlag. Here's the syntax:
DBGetCurrRecVal("G[D]" [,decryptFieldList, key])Note: Decryption is not supported for options that return the entire record in a single container.
DBWriteRec (with "G")
DBWriteRec can be used to write either from a set of matching named global variables or from a complex container. This segment talks about doing the "G" magic.
Again, you'd build a field list. For the purpose of this example, we'll assume the variable encryptList contains the field list:
put DBWriteRec("GE",12,encryptList,"aarvark") into theResult put DBWriteRec("E",12,newData,encryptList,"aardvark") into theResult"G" for global variables, "E" to encrypt. 12 is the record to write. EncryptList is the field list and "aarvark" is the key. Syntax is:
DBWriteRec("G[E]",recNum [,encryptList,key])Note: Encryption is not supported for options that save the entire record from a single complex container.
Discuss this chapter on the FileFlex Boards.