Hashing and Public Key Encryption

All code examples available at: https://github.com/glynrob/encryption

Hashing

Hashing is an important part of the storing the passwords of your users in your database.
You do not need to know or be able to look up the password a user used. Instead you want to be able to validate that the password is correct then let them continue on your website/app.
So how do you do this?
In all programming languages there are hashing functions available to you that do this.
This is not encryption, as hashing is only be made one way, it can not be reversed to get the original password.
If your database was ever hacked and copied by a third party (it has happened to very big companies so could easily happen to you too) then the hash password you stored will not show the passwords of your users.
Many users use the same password on all websites which means that attacker can now try other websites with the same credentials to gain access.

Salt

Salt is a term used when hashing data which simply means adding some data.
So if your password was monkey123, when you hash this password you actually hash monkey123SALTVAL
The salt value should be unqiue to the user also so you DO NOT USE THE SAME SALT value for all users.
If the same salt was used then it would be easier for the attacker to create its own rainbow table (try all password variations) to find the original unhashed password.
Therefore you need to now save 2 items of data for this user.

  • Hashed password
  • Salt value

This salt value should be random and not just the unix time stamp of the server when it was created. My examples use methods like openssl_random_pseudo_bytes but other options like mcrypt_create_iv are just as suitable.
The more random and longer the string is, the better.

Hashing functions

There are many different hashing functions available so I choose 3 to sample.

  • MD5 – Now very weak so do not use
  • SHA1 – Stronger but still not suitable
  • SHA512 – Strong and recommended

What you aim to do is choose a function that takes awhile to generate the output.
You want to do this to avoid possible rainbow tables, the longer it takes to get 1 result the longer it will take an attacker for each possible password.
You could hash the value 100 times to make the generation time longer but keep an eye on your server if many people are logging in at the same time.

PHP Example:

Python Example:

You save the salt value for that user and the hashed value when they create their account.
Next time they try to login you generate a hash using the same method but with the saved salt value and if the hash matches, then the password was correct.

Public Key Encryption

Public Key Encryption is used to encrypt data from one point and allow it to be decrypted in another using different keys.
This is used for saving sensitive users data in a database, or passing information from one server to another.
This means a provider can have his own private key which he never shares with anyone, but provides multiple public keys to other which allows them to encrypt the data to be sent to him. Only the provider with the private key can decrypt this data.

There are other encryption methods available, but my examples use openSSL
https://github.com/glynrob/encryption

DO NOT USE MY PUBLIC KEY except for testing. This private key is public so anyone can decrypt any data you send using this.
To generate your own private and public keys you can use:

Linux/MAC:
# private key
openssl genrsa -out mykey.pem 2048
# public key
openssl rsa -in mykey.pem -pubout -out mykey.pub

Windows:
Puttygen or one of the other software providers
https://www.racf.bnl.gov/docs/authentication/ssh/sshkeygenwin

If you run the examples I provided for PHP and Python you should see the following output.

hashing_screenshot

From this example you see a string encrypted which can then be sent anywhere, then it is decrypted back with the private key.

Example function PHP:

Example function Python:

It really is as easy as that to encrypt and decrypt data.

Just ensure that the private key is only available at the locations where it is required.

7 comments for “Hashing and Public Key Encryption

  1. PB
    May 10, 2014 at 1:57 pm

    So I have two questions:

    1. How do I get the private & public keys into a plain text format (maybe base64) and then send it to the different parties (via email) and then turn those plain text back into keys so they can encrypt / decrypt? So like in your examples, instead of loading key from file, they would enter the plain text (copy&paste) version & let the program (php) convert to keys for the en/decrypt.

    2. Because of converting to plain text, is it possible to have a small private key bit size? Say something like 40bits? Php complains & doesn’t allow me to have anything below 300 some odd bits. I am not so much worried about the strength of the cypher… more worried about the manageability of they keys.

    For example , I would like to have a web from end where a user can enter their private key to decrypt a message from either the system or another user. Or have all the messages encrypted with one public key & the private key would be split up between 2 or 3 people. The messages can’t be decrypted until all the holders of the chunks of the private have entered their chunk into the web page. Therefore the chunks should be small… 9-12 bytes or so.

    the site is running php & on shared hosting plan so no access to cmdline.

    any thoughts?

  2. GlynRob
    May 10, 2014 at 8:53 pm

    Hi PB,

    For what you are trying to do I would use something like Crypto.js.
    I have covered this http://glynrob.com/javascript/client-side-hashing-and-encryption/

    You can view the contents of server side public and private keys in the command line, but you should never email a private key as this is not a secure way to share information.

    Hope this helps

  3. Navinder
    August 7, 2014 at 8:41 pm

    Hi, I tried copying and pasting your code to my encrpt.php file and called the function as
    public_encrypt(“plain text here”);
    But it is always showing a blank page. I tried copying and pasting the entire public key from file but still a blank output.
    I am using a MAC.

    Can you please suggest what I may be doing wrong? Thank you.

  4. MIke
    September 29, 2014 at 8:05 pm

    Hello, I have learn a lot from your articles.
    But have question using a public and private keys.
    on the server this is great, encrypting on the client side with a public key is also straight forward. What happens if you need to decrypt on the clients side with the private key like in your example? Is there a technique for this? Or do you just need to make sure the private key is secured.

  5. GlynRob
    October 6, 2014 at 6:57 pm

    Mike: To encrypt and decrypt on the client side read this other blog post I did.
    http://glynrob.com/javascript/client-side-hashing-and-encryption/

  6. November 11, 2014 at 1:56 am

    Hello Glyn
    This is a very helpful article however it does not cover how to go about encrypting long strings.

    Taken from php.net discussion about openssl_public_encrypt().

    “When you encrypt something using an RSA key (whether public or private), the encrypted value must be smaller than the key (due to the maths used to do the actual encryption). So if you have a 1024-bit key, in theory you could encrypt any 1023-bit value (or a 1024-bit value smaller than the key) with that key.”

    Is there is best practise work around to this?

  7. GlynRob
    November 14, 2014 at 1:46 pm

    One way would be to break your content into chunks and encrypt them separately.
    http://phpseclib.sourceforge.net/ does this but you could easily implement a similar solution yourself.

    Another option is to use openssl_seal() and openssl_open(). openssl_seal generates a random string, encrypts it with RSA and then encrypts the data you’re actually trying to encrypt with RC4 using the random string as the key.

Leave a Reply

Your email address will not be published. Required fields are marked *