Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Crypt - Comparing Values

Given that Laravel's Crypt always adds salt, and so therefore no two instances of the same encryption are the same.

Normally, this is fine because I can compare the decrypted version of the two. However, what if I want to search for a value that is encrypted in the database?

Say that I have a table of users and I would like to encrypt the email address. Now I want to find somebody by the email [email protected].

How do I go about to write the query for this? I cannot just Crypt::encrypt($email) and search since this iteration of the encrypt will be different than the one in the DB.

Edit

Currently, the ONLY thing I can think of is to get all, and filter through them:

$match = User::all()->filter(function($record) use($email) {
            $field = $record->email['email'];

            if(Crypt::decrypt($field) == $email) return $record;
         });

but this is awful. I don't want to search through everything.

like image 921
Kousha Avatar asked Jul 22 '14 08:07

Kousha


1 Answers

As described, you cannot. The answer you have given is the way you would achieve it if you don't need to optimize it.

If you do need to optimize it without completely compromising the encrypted value, and have profiled to find the amount of data returned and processed by your filter is a major cause of delay, you can do the following.

Add a new field to the table that will store a a subset of a hash. Depending on the number of unique email addresses, you can tune how large this subset is. Note: Smaller the better, as you are leaking some information on the encrypted value using this approach. For example, if you store a 1 byte hash of the email address, you are reducing the entropy of the encryption by ~8 bits.

When you query, first create the email hash's subset and place a where clause to return only those rows.

All this assumes the hash function is cheaper than the decrypt step. This approach would require you to re-calculate all hash subsets if you wanted to increase it's size, so picking a size that meaningfully increases performance, doesn't unduly compromise the encryption and most likely won't need to change as you grow is important.

Note: You shouldn't use a straight hash like MD5 in this situation. Not because of it's susceptibility to collisions, but because the key space will be so small. If performance is important and you store large amounts of data, you open yourself DOS attacks whereby the attacker creates large amounts of email addresses that all hash to the same subset. To hardern against this issue, use an HMAC function with a secret key.

Remember, unless you have true performance reasons for needing to add complexity - don't

like image 144
Dan McGrath Avatar answered Sep 26 '22 07:09

Dan McGrath