views:

61

answers:

3

I'm looking for a way to encrypt data on its way into a MySQL database, and decrypt it on the way out. Additionally, I would like to be able to perform normal SQL queries on those fields, such as searching and comparison, which prevents me from using a pure PHP solution.

This leads me to AES_ENCRYPT() and AES_DECRYPT(), which can be duplicated in PHP using MCRYPT.

I'm having a hard time with AES_DECRYPT and have tried all suggestions I can find through searches online.

Here's my table:

CREATE TABLE IF NOT EXISTS `test_table` (
  `id` int(6) NOT NULL,
  `secure_info` text NOT NULL,
  `encrypted_blob` blob NOT NULL,
  `encrypted` text NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

I perform these queries:

INSERT INTO test_table (id, secure_info) VALUES (1,'Testing');
UPDATE test_table SET encrypted = AES_ENCRYPT(secure_info,'key') WHERE id=1 LIMIT 1;
UPDATE test_table SET encrypted_blob = AES_ENCRYPT(secure_info,'key') WHERE id=1 LIMIT 1;

SELECT *, AES_DECRYPT(encrypted,'key') as decrypted, AES_DECRYPT(encrypted_blob,'key') as decrypted_blob FROM test_table WHERE id=1;

I cannot get the original value. 'decrypted' returns NULL, and 'decrypted_blob' returns 54657374696e67

Any ideas, or perhaps a better solution?

A: 

AES_ENCRYPT returns a binary string so don't use a text column type.

Tip: Start primary key numbering at 1, not 0

Tip 2: Try not to name your fields after MySQL keywords. This can lead to confusion and will usually require escaping with backticks (text is an exception).

http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html

webbiedave
Doesn't AES_ENCRYPT just return the value? I have two fields, 'encrypted', and 'encrypted_blob' for testing, because I am aware of the need for a binary field. I've updated my code with your tips and it's the same result. Very interesting tips; I'll be sure to look into them further. Thanks!
Travis
`AES_ENCRYPT` returns binary so don't store its result in a text column. Your first `UPDATE` is storing it in a text column. That can lead to encryption/decryption errors.
webbiedave
Thanks - My goal with the text column was to see what was going on. I now understand that a binary column is necessary, and the text column is entirely useless.
Travis
+1  A: 

Blob decryption works just fine, "54657374696e67" is "Testing", only hex-encoded. You're probably executing this with a tool that displays blobs to hex. Text decryption doesn't work (and shouldn't).

stereofrog
Thanks - this is what I was having the most trouble with. My DB is also setup to UNHEX() on the way out - I get the original text when I select!
Travis
@stereofrog: Nice catch. You don't even see the hexcode. All you see is blond, brunette, redhead, Testing...
webbiedave
+1  A: 

TEXT fields in MySQL are subject to character set conversion. If you're connecting with iso-8859 and the table's stored in CP1252, say, then MySQL will auto-convert the text between the two character sets. This will trash the encrypted data, as some bytes of the original 8859 data will get converted to 1252's equivalents, which have different values.

BLOB fields, on the other hand, are passed through verbatim with no conversion, so there's no errors decrypting.

Marc B
Thanks - this is very helpful!
Travis