Encrypting & signing stuff in Ruby

Securing your communications between parts of your infrastructure has never been more important. For encryption, in most cases, you can rely on normal SSL on HTTP connections (HTTPS) however what happens when you're not using HTTP or you need don't have the option of using HTTPS?

What is encryption & data signing?

Encryption is the process of converting data into a format which means it can only be read by someone who possesses a private key. This is particularly useful if you want to send sensitive data over an insecure network connection to a known consumer.

Signing is the process of generating a "signature" which links some data to a given "producer". For exampe, if I wanted to send some data to Charlie and he needed to be sure it came from me, I could sign the data with my private key and he could verify it was signed by me and that it was authentic.

These two techniques are very useful and, at aTech, we use them both extensively in many of our apps. They are used heavily in our single-sign on system in order to ensure that authentication requests are only submitted by our applications and responses are always received from our SSO app.

What can I do?

Many years ago we created a very simple wrapper around OpenSSL which allows you to easily encrypt/decrypt/sign/verify data. We re-released this today under a new name and with much improved documentation.

 Generating some keys

Before you can start using EncryptoSigno, you will need a keypair. A keypair is a set of two keys, one public and one private. You should always keep your private key secure however your public key can be distributed as you see fit without compromising security. The two commands below will create a private & public key for you.

$ openssl genrsa -out path/to/private.key 2048
$ openssl rsa -pubout -in path/to/private.key -out path/to/public.key

In order to use these keys in your application, you will need to load them into your Ruby application as and when required. You can just read them from the file and store them in a variable, as shown below:

private_key = File.read("path/to/private.key")  
public_key  = File.read("path/to/public.key")  

Encrypting & Decrypting

In this encryption example, we are going to send some data to a colleague who has provided us with their public key. They will then be able to read this data by decrypting it using their private key.

string = "I love bananas but I don't want anyone other than you to know this!"  
encrypted_string = EncryptoSigno.encrypt(public_key, string)  

Decrypting data is just as easy as encrypting it. You just need to pass your private key and some encrypted data to the decrypt method as shown below:

decrypted_string = EncryptoSigno.decrypt(private_key, encrypted_string)  

Signing & Verifying

We want to send some data to someone and they need to be sure that the data originated from us. To do this, we will sign our data and send a signature along with the data which they can use (along with our public key, which would be distributed separately) to verify it was signed by us.

string = "Your access code is 123456."  
signature = EncryptoSigno.sign(private_key, string)  

The signature variable will contain a Base64 signature which you can transmit along with the string. Remember, this is not like encryption and the signature does not include your original data so this must be sent too.

If you receive a signature, you can use the verify method to determine whether it was signed using a provided public key or not.

EncryptoSigno.verify(public_key, signature, string) #=> true or false  

Conclusion

I hope this post highlights some of the benefits of encrypting & signing data and also provides a simple way to achieve this in Ruby. For more information, check out the docs.