Home > Engineering > Functional OpenSSL encrypt and decrypt in Ruby

Functional OpenSSL encrypt and decrypt in Ruby

As part of a project I am working on, I wanted to have a method for unsubscribing users from a mailing list without having to log in — just click and unsubscribe. I wanted to keep the URLs opaque and unguessable while not requiring a database hit to guarantee authenticity or a full table scan before going about the main work of unsubscribing the user. Encrypting a unique key, in my case the email address, for the user will accomplish these goals.

I like this Blowfish module built on top of the ruby OpenSSL wrapper, though I wanted a more flexible module which would allow choosing the cipher at time of use rather than having to make the exact same module for AES, idea or whatever. This can be implemented as a simple class which takes the engine during construction and a private cipher method so that people know to only call encrypt() and decypt()  adding a fair chunk of boilerplate code. Instead, I chose to implement this as a module function which returns an appropriate encrypt and decrypt Proc based on the engine you want to use for encryption.

[sourcecode language=”ruby”]
require ‘openssl’

module CipherSuite
def self.make(engine)
def self.cipher_fn(engine)
lambda do |mode, key, data|
cipher = OpenSSL::Cipher::Cipher.new(engine).send(mode)
cipher.key = Digest::SHA256.digest(key)
cipher.update(data) << cipher.final

cipher = self.cipher_fn(engine)
encrypt = lambda { |key, data| cipher.call(:encrypt, key, data) }
decrypt = lambda { |key, data| cipher.call(:decrypt, key, data) }
return encrypt, decrypt

Usage is straightforward:

[sourcecode language=”ruby”]
encrypt, decrypt = CipherSuite::make(‘aes-128-cbc’)
encypt.call(key, plain_text) # => encrypted_text
decrypt.call(key, encrypted_text) # => plain_text

I am a bit of a r00b, so if this could be simplified further please let me know.

Categories: Engineering Tags:
  1. No comments yet.
  1. No trackbacks yet.