Class: Gibberish::AES

Inherits:
Object
  • Object
show all
Defined in:
lib/gibberish/aes.rb

Overview

Handles AES encryption and decryption with some sensible defaults

  • 256 bit AES encryption
  • GCM mode with Authentication
  • 100,000 iterations of PBKDF2_HMAC for key strengthening

Compatibility with SJCL

It outputs into a format that is compatible with SJCL and easy to consume in browsers/Node.js

Basic Usage

Encrypting

cipher = Gibberish::AES.new('p4ssw0rd')
cipher.encrypt("some secret text")
#=> Outputs a JSON string containing all the necessary information

Decrypting

cipher = Gibberish::AES.new('p4ssw0rd')
cipher.decrypt('{"iv":"I4XKgNfMNkYhvzXc","v":1,"iter":1000,"ks":128,"ts":64,"mode":"gcm","adata":"123abc","cipher":"aes","salt":"PJsit8L16Ug=","ct":"5sEBsHXQqLXLOjxuVQK7fGZVdrMyRGDJ"}')
#=> "some secret text"

Including Authenticated data.

GCM mode allows you to include "Authenticated Data" with the ciphertext, if you wish. For an overview of Authenticated Data, see this post: http://crypto.stackexchange.com/a/15701

Using AD is easy with Gibberish

cipher = Gibberish::AES.new('p4ssw0rd')
ciphertext = cipher.encrypt("Some secret data", "my authenticated data")
plaintext = cipher.decrypt(ciphertext)
#=> "some secret text"
plaintext.adata
# => "my authenticated data"

Interoperability with SJCL's GCM mode AES

Decrypting

// In the browser
var cleartext = sjcl.decrypt('key', '[output from Gibberish AES]');

Encrypting

Ruby OpenSSL cannot handle an IV longer than 12 bytes, therefore we need to tell SJCL to only use a 3 word IV value. See: https://github.com/bitwiseshiftleft/sjcl/issues/180

// In the browser
var ciphertext = sjcl.encrypt('key', 'plain text', {mode: 'gcm', iv: sjcl.random.randomWords(3, 0)});

Backward compatibility with older pre 2.0 Gibberish

Gibberish was previously designed to be compatible with OpenSSL on the command line with CBC mode AES. This has been deprecated in favor of GCM mode. However, you may still decrypt and encrypt using legacy convenience methods below:

(Note: OpenSSL "enc" uses a non-standard file format which lacks key stretching, this means less secure passwords are more susceptible to brute forcing.)

AES-256-CBC mode

cipher = Gibberish::AES::CBC.new('p4ssw0rd')
cipher_text = cipher.encrypt("some secret text")
# => U2FsdGVkX1/D7z2azGmmQELbMNJV/n9T/9j2iBPy2AM=

cipher.decrypt(cipher_text)

# From the command line
echo "U2FsdGVkX1/D7z2azGmmQELbMNJV/n9T/9j2iBPy2AM=\n" | openssl enc -d -aes-256-cbc -a -k p4ssw0rd

Defined Under Namespace

Classes: CBC, SJCL

Instance Method Summary collapse

Constructor Details

#initialize(password, opts = {}) ⇒ AES

Returns the AES object

Parameters:

  • password (String)
  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :mode (Symbol) — default: 'gcm'

    the AES mode to use

  • :ks (Symbol) — default: 256

    keystrength

  • :iter (Symbol) — default: 100_000

    number of PBKDF2 iterations to run on the password

  • :max_iter (Symbol) — default: 100_000

    maximum allow iterations, set to prevent DOS attack of someone setting a large 'iter' value in the ciphertext JSON

  • :ts (Symbol) — default: 64

    length of the authentication data hash



91
92
93
# File 'lib/gibberish/aes.rb', line 91

def initialize(password, opts={})
  @cipher = SJCL.new(password, opts)
end

Instance Method Details

#decrypt(ciphertext) ⇒ Object

Returns a Plaintext object (essentially a String with an additional 'adata' attribute)

Parameters:

  • ciphertext (String)


106
107
108
# File 'lib/gibberish/aes.rb', line 106

def decrypt(ciphertext)
  @cipher.decrypt(ciphertext)
end

#encrypt(data, authenticated_data = '') ⇒ Object

Returns the ciphertext in the form of a JSON string

Parameters:

  • data (String)
  • authenticated_data (String) (defaults to: '')

    (Won't be encrypted)



99
100
101
# File 'lib/gibberish/aes.rb', line 99

def encrypt(data, authenticated_data='')
  @cipher.encrypt(data, authenticated_data)
end