Home

Awesome

Encryptor

Build Status Code Climate Coverage Gem Version security

A simple wrapper for the standard Ruby OpenSSL library

Upgrading from v2.0.0 to v3.0.0

A bug was discovered in Encryptor 2.0.0 wherein the IV was not being used when using an AES-*-GCM algorithm. Unfornately fixing this major security issue results in the inability to decrypt records encrypted using an AES-*-GCM algorithm from Encryptor v2.0.0. While the behavior change is minimal between v2.0.0 and v3.0.0, the change has a significant impact on users that used v2.0.0 and encrypted data using an AES-*-GCM algorithm, which is the default algorithm for v2.0.0. Consequently, we decided to increment the version with a major bump to help people avoid a confusing situation where some of their data will not decrypt. A new option is available in Encryptor 3.0.0 that allows decryption of data encrypted using an AES-*-GCM algorithm from Encryptor v2.0.0.

Installation

gem install encryptor

Usage

Basic

Encryptor uses the AES-256-GCM algorithm by default to encrypt strings securely.

The best example is:

cipher = OpenSSL::Cipher.new('aes-256-gcm')
cipher.encrypt # Required before '#random_key' or '#random_iv' can be called. http://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-encrypt
secret_key = cipher.random_key # Insures that the key is the correct length respective to the algorithm used.
iv = cipher.random_iv # Insures that the IV is the correct length respective to the algorithm used.
salt = SecureRandom.random_bytes(16)
encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: secret_key, iv: iv, salt: salt)
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: secret_key, iv: iv, salt: salt)

A slightly easier example is:

require 'securerandom'
secret_key = SecureRandom.random_bytes(32) # The length in bytes must be equal to or greater than the algorithm bit length.
iv = SecureRandom.random_bytes(12) # Recomended length for AES-###-GCM algorithm. https://tools.ietf.org/html/rfc5084#section-3.2
encrypted_value = Encryptor.encrypt(value: 'some string to encrypt', key: secret_key, iv: iv)
decrypted_value = Encryptor.decrypt(value: encrypted_value, key: secret_key, iv: iv)

NOTE: It is imperative that you use a unique IV per each string and encryption key combo; a nonce as the IV. See RFC 5084 for more details.

The value to encrypt or decrypt may also be passed as the first option if you'd prefer.

encrypted_value = Encryptor.encrypt('some string to encrypt', key: secret_key, iv: iv)
decrypted_value = Encryptor.decrypt(encrypted_value, key: secret_key, iv: iv)

Options

Defaults:

    { algorithm: 'aes-256-gcm',
      auth_data: '',
      insecure_mode: false,
      hmac_iterations: 2000,
      v2_gcm_iv: false }

Older versions of Encryptor allowed you to use it in a less secure way. Namely, you were allowed to run Encryptor without an IV, or with a key of insufficient length. Encryptor now requires a key and IV of the correct length respective to the algorithm that you use. However, to maintain backwards compatibility you can run Encryptor with the :insecure_mode option. Additionally, when using AES-*-GCM algorithms in Encryptor v2.0.0, the IV was set incorrectly and was not used. The :v2_gcm_iv option is available to allow Encryptor to set the IV as it was set in Encryptor v2.0.0. This is provided to assist with migrating data that unsafely encrypted using an AES-*-GCM algorithm from Encryptor v2.0.0.

You may also pass an :algorithm,:salt, and hmac_iterations option, however none of these options are required. If you pass the :salt option, a new unique key will be derived from the key that you passed in using PKCS5 with a default of 2000 iterations. You can change the number of PKCS5 iterations with the hmac_iterations option. As PKCS5 is slow, it is optional behavior, but it does provide more security to use a unique IV and key for every encryption operation.

Encryptor.default_options.merge!(algorithm: 'aes-256-cbc', key: 'some default secret key', iv: iv, salt: salt)

Strings

Older versions of Encryptor added encrypt and decrypt methods to String objects for your convenience. However, this behavior has been removed to avoid polluting Ruby's core String class. The Encryptor::String module remains within this gem to allow users of this feature to implement it themselves. These encrypt and decrypt methods accept the same arguments as the associated ones in the Encryptor module. They're nice when you set the default options in the Encryptor.default_options attribute. For example:

require 'encryptor/string'
String.include Encryptor::String
Encryptor.default_options.merge!(key: 'some default secret key', iv: iv)
credit_card = 'xxxx xxxx xxxx 1234'
encrypted_credit_card = credit_card.encrypt

There's also encrypt! and decrypt! methods that replace the contents of a string with the encrypted or decrypted version of itself.

Algorithms

To view a list of all cipher algorithms that are supported on your platform, run the following code in your favorite Ruby REPL:

require 'openssl'
puts OpenSSL::Cipher.ciphers

The supported ciphers will vary depending on the version of OpenSSL that was used to compile your version of Ruby. However, the following ciphers are typically supported:

Cipher NameKey size in bytesIV size in bytes
aes-128-cbc1616
aes-128-cbc-hmac-sha11616
aes-128-cbc-hmac-sha2561616
aes-128-ccm1612
aes-128-cfb1616
aes-128-cfb11616
aes-128-cfb81616
aes-128-ctr1616
aes-128-ecb160
aes-128-gcm1612
aes-128-ofb1616
aes-128-xts3216
aes-192-cbc2416
aes-192-ccm2412
aes-192-cfb2416
aes-192-cfb12416
aes-192-cfb82416
aes-192-ctr2416
aes-192-ecb240
aes-192-gcm2412
aes-192-ofb2416
aes-256-cbc3216
aes-256-cbc-hmac-sha13216
aes-256-cbc-hmac-sha2563216
aes-256-ccm3212
aes-256-cfb3216
aes-256-cfb13216
aes-256-cfb83216
aes-256-ctr3216
aes-256-ecb320
aes-256-gcm3212
aes-256-ofb3216
aes-256-xts6416
aes1281616
aes1922416
aes2563216
bf168
bf-cbc168
bf-cfb168
bf-ecb160
bf-ofb168
blowfish168
camellia-128-cbc1616
camellia-128-cfb1616
camellia-128-cfb11616
camellia-128-cfb81616
camellia-128-ecb160
camellia-128-ofb1616
camellia-192-cbc2416
camellia-192-cfb2416
camellia-192-cfb12416
camellia-192-cfb82416
camellia-192-ecb240
camellia-192-ofb2416
camellia-256-cbc3216
camellia-256-cfb3216
camellia-256-cfb13216
camellia-256-cfb83216
camellia-256-ecb320
camellia-256-ofb3216
camellia1281616
camellia1922416
camellia2563216
cast168
cast-cbc168
cast5-cbc168
cast5-cfb168
cast5-ecb160
cast5-ofb168
des88
des-cbc88
des-cfb88
des-cfb188
des-cfb888
des-ecb80
des-ede160
des-ede-cbc168
des-ede-cfb168
des-ede-ofb168
des-ede3240
des-ede3-cbc248
des-ede3-cfb248
des-ede3-cfb1248
des-ede3-cfb8248
des-ede3-ofb248
des-ofb88
des3248
desx248
desx-cbc248
idea168
idea-cbc168
idea-cfb168
idea-ecb160
idea-ofb168
rc2168
rc2-40-cbc58
rc2-64-cbc88
rc2-cbc168
rc2-cfb168
rc2-ecb160
rc2-ofb168
rc4160
rc4-4050
rc4-hmac-md5160
seed1616
seed-cbc1616
seed-cfb1616
seed-ecb160
seed-ofb1616

NOTE: Some ciphers may not be supported by Ruby. Additionally, Ruby compiled with OpenSSL >= v1.0.1 will include AEAD ciphers, ie., aes-256-gcm.

Notes on patches/pull requests