sirjay sirjay - 9 days ago 5
MySQL Question

Can I store hashed phone number and send it unhashed to email?

I have a task for my new PHP job, but I don't understand if it is possible to solve. Task:

You need to create PHP web page that implements functional on picture below. Data must be stored in SQL. Hacker can not see user phone numbers and emails even if he got access to database or files. The solutions must contain standart PHP libs.


So, what algorithm should I use to solve problem? I can store emails with
password_hash()
function and when I need to retrieve phone number from email, I will use
password_verify()
to find out if email exists. But how to be with phone number, if I need to send it pure and unhashed?

enter image description here

Answer

PHP provides built-in solutions for encrypting and decrypting data. Use e.g. MCrypt, supports a good buffet of common algorithms. What exact cipher you choose is up to you, depending on the level of security required. Read up at Wikipedia on block ciphers for the general picture.

If the phone numbers must be inaccessible even if a hacker gains complete access to your system, then the decrypt key must obviously be off-server, ie. you can't store it in DB or the filesystem.

In the spec you have, this key would then be the e-mail address that's matched with the phone number. Then, at input time you'd one-way hash the e-mail, and use the unhashed e-mail as a key for encrypting the phone number. At request time, you'd find the matching phone number by using the e-mail hash, and decrypt it using the unhashed email as the key. Should get you sorted.


Update: When fetching a record that matches the phone/email pair in the database, if you've used password_hash() (which generates a new salt and a unique string each time), then your only option is to fetch all records and iterate them through password_verify(). That's not particularly scalable.

Unless this is an exercise in security, I'm not sure I'd bother with more than a simple sha1() hash for the e-mails. Or use crypt($email, '$2y$08$Some22CharsOfFixedSalt$'); -- see crypt() -- and generate e.g. a blowfish-based hash that uses a fixed salt string, resulting in an invariant hash. I'd also truncate the leading salt-part of the resulting string from the database entry.

If you're feeling crafty, why not cook up an algorithm that derives a unique string from each email, and then use that for salt in your hashing function, instead of using the same salt for hashing all e-mails.

You could also delegate the e-mail hashing for the database and use MySQL's encryption functions. Then you'd use e.g. SHA2('email', 256) in your INSERT and SELECT queries, like so: INSERT INTO records values (SHA2('email@what', 256)); and SELECT * FROM records WHERE email = SHA2('email@what', 256);. Plenty of ways to accomplish this.