Question

Is it possible to Encrypt data with PHP mcrypt and decrypt it in the database with MySQL AES_DECRYPT? At the moment, I'm using RIJNDAEL_128 for mcrypt on PHP. I've also made sure that the encrypted fields in the database have data type blob. Yet, AES_DECRYPT with the correct key still returns NULL. Any suggestions on how to get this to work?

Was it helpful?

Solution

I found some good help here

Note this works for encrypted text up to 65519 characters in the plain text. (maybe a bit more if no UTF-8 encoding)

PHP code to encrypt:

// MySQL uses 16 bytes key for 128 encryption/decryption
$key = "ABCDEF0123456789";

$plaintext = "This string was AES-128 / EBC / ZeroBytePadding encrypted.";
// Optionally UTF-8 encode
$plaintext_utf8 = utf8_encode($plaintext);
// Find out what's your padding
$pad_len = 16 - (strlen($plaintext_utf8) % 16);
// Padd your text
$plaintext_utf8 = str_pad($plaintext_utf8, (16 * (floor(strlen($plaintext_utf8) / 16) + 1)), chr($pad_len));

// Encryption
mt_srand();
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
mcrypt_generic_init($td, $key, false);
// Generates a warning about empty IV but it's Ok
$ciphertext = mcrypt_generic($td, $plaintext_utf8);
mcrypt_generic_deinit($td);
$ciphertext = mysql_real_escape_string($ciphertext);

// Store in MySQL
$mysqli = new mysqli("localhost", "test", "test", "test");
$mysqli->set_charset("utf8");
$mysqli->query("insert into test(content) value ('$ciphertext')");
$mysqli->close();

SQL query to search for string was:

SELECT CAST(AES_DECRYPT(content,'ABCDEF0123456789') AS CHAR) AS content
FROM test
WHERE CAST(AES_DECRYPT(content,'ABCDEF0123456789') AS CHAR) like '%string was%';

Output is:

This string was AES-128 / EBC / ZeroBytePadding encrypted.

Note: MySQL table was created by:

create table test (
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
content blob ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

OTHER TIPS

If you are encrypting with say mcrypt RIJNDAEL_128 on PHP's side then I would recommend to leave decryption on PHP side. I was under the same issue not a long time ago when it came to student ID numbers for one of my applications. I chose against having the database do any sort of encryption / decryption. I highly recommend leaving that to just one system (in this case mcrypt). Reason being now you have less "moving" parts that could possibly go wrong allowing for easier maintenance and allows for easier documentation of audit trails. Your database should be used to store data (no surprise) so just make sure the length in the database is suitable for what ever you are storing.

Hopefully this answers your question / helps you out in some sort of way as this is how I would do it / actually am doing it.

Now if you need to see some code on how this would work then just ask. From my understanding though I think you know how to do the encrypt / decrypt but you were just asking if the database should decrypt the information or not.

Decrypting data in the dabatase during search seems like it could be a problem if you want your solution to be scalable to many users.

I would suggest that you look up the old gem the "bloom filter". It is commonly used for spellcheckers but can be used for speeding up search in databases as well. https://en.wikipedia.org/wiki/Bloom_filter

A bloom filter is a bitmask. You need to create a series of different hashing functions which generate hashes the same size as the bloom filter but where only one random bit is set by each hashing function.

Then you run a word (string) through these hashing functions and add these bits to your filter. Now the filter "knows" your word is in it.

The filter is compact because words can overlap each other in the filter.

To check if a word is in the filter you just run your hashing functions on it and check if all bits are set in the filter with a binary AND operation. MySQL supports binary operations.

You can never remove a word from the filter since the bits can be part of multiple words.

The text can never be recovered from a bloom filter.

A bloom filter can never give a false negative but it can give a false positive. If you get false positives then your filter is too small compared to your data set (words stored in filter) or your hashing functions are not good enough. How many hashing functions you need depends on the size of the data, try 5-20.

Tip! You can also add pairs of words or triplets of words to your bloom filter.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top