I'm currently a student and I'm studying PHP, I'm trying to make a simple encrypt/decrypt of data in PHP. I made some online research and some of them were quite confusing(at least for me).
Here's what I'm trying to do:
I have a table consisting of these fields (UserID,Fname,Lname,Email,Password)
What I want to have is have the all fields encrypted and then be decrypted(Is it possible to use sha256
for encryption/decryption, if not any encryption algorithm)
Another thing I want to learn is how to create a one way hash(sha256)
combined with a good "salt".
(Basically I just want to have a simple implementation of encryption/decryption, hash(sha256)+salt)
Sir/Ma'am, your answers would be of great help and be very much appreciated. Thank you++
I'm think this has been answered before...but anyway, if you want to encrypt/decrypt data, you can't use SHA256
Answer Background and Explanation
To understand this question, you must first understand what SHA256 is. SHA256 is a Cryptographic Hash Function. A Cryptographic Hash Function is a one-way function, whose output is cryptographically secure. This means it is easy to compute a hash (equivalent to encrypting data), but hard to get the original input using the hash (equivalent to decrypting the data). Since using a Cryptographic hash function means decrypting is computationally infeasible, so therefore you cannot perform decryption with SHA256.
What you want to use is a two-way function, but more specifically, a Block Cipher. A function that allows for both encryption and decryption of data. The functions
mcrypt_encrypt
andmcrypt_decrypt
by default use the Blowfish algorithm. PHP's use of mcrypt can be found in this manual. A list of cipher definitions to select the cipher mcrypt uses also exists. A wiki on Blowfish can be found at Wikipedia. A block cipher encrypts the input in blocks of known size and position with a known key, so that the data can later be decrypted using the key. This is what SHA256 cannot provide you.Code
It took me quite a while to figure out, how to not get a
false
when usingopenssl_decrypt()
and get encrypt and decrypt working.If you want to pass the encrypted string via a URL, you need to urlencode the string:
To better understand what is going on, read:
To generate 16 bytes long keys you can use:
To see error messages of openssl you can use:
echo openssl_error_string();
Hope that helps.
Here is an example using openssl_encrypt
Foreword
Starting with your table definition:
Here are the changes:
Fname
,Lname
andEmail
will be encrypted using a symmetric cipher, provided by OpenSSL,IV
field will store the initialisation vector used for encryption. The storage requirements depend on the cipher and mode used; more about this later.Password
field will be hashed using a one-way password hash,Encryption
Cipher and mode
Choosing the best encryption cipher and mode is beyond the scope of this answer, but the final choice affects the size of both the encryption key and initialisation vector; for this post we will be using AES-256-CBC which has a fixed block size of 16 bytes and a key size of either 16, 24 or 32 bytes.
Encryption key
A good encryption key is a binary blob that's generated from a reliable random number generator. The following example would be recommended (>= 5.3):
This can be done once or multiple times (if you wish to create a chain of encryption keys). Keep these as private as possible.
IV
The initialisation vector adds randomness to the encryption and required for CBC mode. These values should be ideally be used only once (technically once per encryption key), so an update to any part of a row should regenerate it.
A function is provided to help you generate the IV:
Example
Let's encrypt the name field, using the earlier
$encryption_key
and$iv
; to do this, we have to pad our data to the block size:Storage requirements
The encrypted output, like the IV, is binary; storing these values in a database can be accomplished by using designated column types such as
BINARY
orVARBINARY
.The output value, like the IV, is binary; to store those values in MySQL, consider using
BINARY
orVARBINARY
columns. If this is not an option, you can also convert the binary data into a textual representation usingbase64_encode()
orbin2hex()
, doing so requires between 33% to 100% more storage space.Decryption
Decryption of the stored values is similar:
Authenticated encryption
You can further improve the integrity of the generated cipher text by appending a signature that's generated from a secret key (different from the encryption key) and the cipher text. Before the cipher text is decrypted, the signature is first verified (preferably with a constant-time comparison method).
Example
See also:
hash_equals()
Hashing
Storing a reversible password in your database must be avoided as much as possible; you only wish to verify the password rather than knowing its contents. If a user loses their password, it's better to allow them to reset it rather than sending them their original one (make sure that password reset can only be done for a limited time).
Applying a hash function is a one-way operation; afterwards it can be safely used for verification without revealing the original data; for passwords, a brute force method is a feasible approach to uncover it due to its relatively short length and poor password choices of many people.
Hashing algorithms such as MD5 or SHA1 were made to verify file contents against a known hash value. They're greatly optimized to make this verification as fast as possible while still being accurate. Given their relatively limited output space it was easy to build a database with known passwords and their respective hash outputs, the rainbow tables.
Adding a salt to the password before hashing it would render a rainbow table useless, but recent hardware advancements made brute force lookups a viable approach. That's why you need a hashing algorithm that's deliberately slow and simply impossible to optimize. It should also be able to increase the load for faster hardware without affecting the ability to verify existing password hashes to make it future proof.
Currently there are two popular choices available:
This answer will use an example with bcrypt.
Generation
A password hash can be generated like this:
The salt is generated with
openssl_random_pseudo_bytes()
to form a random blob of data which is then run throughbase64_encode()
andstrtr()
to match the required alphabet of[A-Za-z0-9/.]
.The
crypt()
function performs the hashing based on the algorithm ($2y$
for Blowfish), the cost factor (a factor of 13 takes roughly 0.40s on a 3GHz machine) and the salt of 22 characters.Validation
Once you have fetched the row containing the user information, you validate the password in this manner:
To verify a password, you call
crypt()
again but you pass the previously calculated hash as the salt value. The return value yields the same hash if the given password matches the hash. To verify the hash, it's often recommended to use a constant-time comparison function to avoid timing attacks.Password hashing with PHP 5.5
PHP 5.5 introduced the password hashing functions that you can use to simplify the above method of hashing:
And verifying:
See also:
password_hash()
,password_verify()