0

I am using SODIUM to encrypt personal data stored in a database. I can encrypt and decrypt happily the data stored. I am encrypting first and last names, telephone numbers, email addresses etc. when storing in the database.

However I don't know how to search the encrypted data. Can anyone give pointers for encrypting data and then being able to search for it?

For example I need to search by first name, last name etc. but this is encrypted.

I'm using this code to search and thought 'stupidly' of encrypting the name but of course that re-encrypts it and its then different to the actual record.

public function searchStaff($string) {
  $this->db->query('SELECT * FROM staff WHERE lastName IN (:unEncrypted, :encrypted)');
  $this->db->bind(':unEncrypted', $string);
  $this->db->bind(':encrypted', $string);
  $results = $this->db->resultSet();
  return $results;
}

I'm not sure how to even go about this, my only thought so far is to decrypt each row, check, and return but this is such a obviously flawed way of looking at it, especially when the table gets bigger!

I am using the code below to create the encrypted entry in the column. My only thought currently is to store the $nonce in the database row and use that to decrypt each row in turn? But this is going to creat massive overhead??

How do people ensure the security of personal data?

//create random number
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);

//encrypt the input
//to encrypt the value we pass it to sodium_crypto_secretbox() with our key
//and a $nonce. The nonce is generated using random_bytes(), because the 
//same nonce should never be reused.

$cipher = sodium_crypto_secretbox($data, $nonce, CRYPTOKEY);

//This presents a problem because we need the nonce to decrypt the value 
//later.
//Luckily, nonces don’t have to be kept secret so we can prepend it to our 
//$ciphertext then base64_encode() the value before saving it to the 
//database.

$encoded = base64_encode($nonce . $cipher);

sodium_memzero($data);

return $encoded;
Matthew Barraud
  • 467
  • 1
  • 5
  • 17
  • Where are you storing the nonce now? Isn't the nonce different for each row? – JNevill Feb 10 '20 at 21:13
  • I'm appending the nonce onto the encrypted string and storing it in the database. My only thought currently is to store a range of nonces and when searching encrypt using each nonce in turn, do the search and if a match retrun if not try the next nonce and so on. – Matthew Barraud Feb 10 '20 at 21:20
  • So the process would be... ~ Encrypt the name using a random nonce (from a list) and key ~ Store in database ~ On search, encrypt the search term using one of the nonces from the list check for a match ~ If no match move onto the next nonce etc. I wonder how much overhead this would produce and how secure it is – Matthew Barraud Feb 10 '20 at 21:23
  • That sounds just as bad as your other bad option. I think the biggest issue here is that you can't decrypt in your database on the fly since libsodium doesn't live in Mysql. I don't think there is an elegant way around your issue using libsodium, unfortunately. [This question was seeking something similar (ordering)](https://stackoverflow.com/questions/52000755/libsodium-decrypt-data-inside-mysql-query-like-did-with-aes-decrypt) and the suggestion there was to switch to `CipherSweet`. – JNevill Feb 10 '20 at 21:24
  • Yea, have been digging and came accross that one. – Matthew Barraud Feb 10 '20 at 21:25
  • I suppose my next question is do I really need to encrypt user data? As in names/emails what does everyone else do? – Matthew Barraud Feb 10 '20 at 21:29
  • I think encrypting data at rest is a step in the right direction, but if it can't be encrypted and decrypted by the database itself, it presents some really big obstacles like the one you are facing. In this case I would consider losing that extra layer of protection so you can gain functionality that your application requires. Parameterizing your SQL and doing routine audits of usernames and grants on your database would be recommended. Any safeguards you can put in place are extra layers that will allow you to sleep at night. – JNevill Feb 11 '20 at 13:57

1 Answers1

-1

Fundamentally ... if the data is encrypted, you can't search it. Decrypting every record to see if it contains a particular value is quite unmanageable.

In this case I would argue that encryption is unnecessary. Truly-secret information such as credit card numbers might need to be encrypted e.g. to meet "PCI Compliance" standards, but these data are never "searched." I see no value in encrypting things like names and addresses. Simply ensure that the access control rules are appropriate for your database.

Mike Robinson
  • 8,490
  • 5
  • 28
  • 41
  • I am beginning to think I have made a rod for my own back. Do you know how we stand with regard GDPR? I am using the recommended ways of connecting to the database, PDO prepared statements etc. is this enough? – Matthew Barraud Feb 10 '20 at 21:37