class Gibberish::AES::SJCL

Constants

ALLOWED_KS
ALLOWED_MODES
ALLOWED_TS
DEFAULTS
MAX_ITER

Public Class Methods

new(password, opts={}) click to toggle source
# File lib/gibberish/aes.rb, line 131
def initialize(password, opts={})
  @password = password
  @opts = DEFAULTS.merge(opts)
  check_cipher_options(@opts)
end

Public Instance Methods

check_cipher_options(c_opts) click to toggle source

Assume the worst

# File lib/gibberish/aes.rb, line 190
def check_cipher_options(c_opts)
  if @opts[:max_iter] < c_opts[:iter]
    # Prevent DOS attacks from high PBKDF iterations
    # You an increase this by passing in opts[:max_iter]
    raise CipherOptionsError.new("Iteration count of #{c_opts[:iter]} exceeds the maximum of #{@opts[:max_iter]}")
  elsif !ALLOWED_MODES.include?(c_opts[:mode])
    raise CipherOptionsError.new("Mode '#{c_opts[:mode]}' not supported")
  elsif !ALLOWED_KS.include?(c_opts[:ks])
    raise CipherOptionsError.new("Keystrength of #{c_opts[:ks]} not supported")
  elsif !ALLOWED_TS.include?(c_opts[:ts])
    raise CipherOptionsError.new("Tag length of #{c_opts[:ts]} not supported")
  elsif c_opts[:iv] && Base64.decode64(c_opts[:iv]).length > 12
    raise CipherOptionsError.new("Initialization vector's greater than 12 bytes are not supported in Ruby.")
  end
end
decrypt(h) click to toggle source
# File lib/gibberish/aes.rb, line 158
def decrypt(h)
  begin
    h = JSON.parse(h, {:symbolize_names => true})
  rescue => e
    raise "Unable to parse JSON of crypted text. #{e.inspect}"
  end
  check_cipher_options(h)
  key = OpenSSL::PKCS5.pbkdf2_hmac(@password, Base64.decode64(h[:salt]), h[:iter], h[:ks]/8, 'SHA256')
  iv = Base64.decode64(h[:iv])
  ct = Base64.decode64(h[:ct])
  tag = ct[ct.length-h[:ts]/8,ct.length]
  ct = ct[0,ct.length-h[:ts]/8]
  cipherMode = "#{h[:cipher]}-#{h[:ks]}-#{h[:mode]}"
  begin
    c = OpenSSL::Cipher.new(cipherMode)
  rescue RuntimeError => e
    raise "OpenSSL error when initializing: #{e.inspect}"
  end
  c.decrypt
  c.key = key
  c.iv = iv
  c.auth_tag = tag;
  c.auth_data = h[:adata] || ""
  begin
    out = c.update(ct) + c.final();
  rescue OpenSSL::Cipher::CipherError => e
    raise DecryptionError.new(e.inspect);
  end
  return Plaintext.new(out.force_encoding('utf-8'), h[:adata])
end
encrypt(plaintext, adata='') click to toggle source
# File lib/gibberish/aes.rb, line 137
def encrypt(plaintext, adata='')
  salt = SecureRandom.random_bytes(8)
  iv = SecureRandom.random_bytes(12)
  key = OpenSSL::PKCS5.pbkdf2_hmac(@password, salt, @opts[:iter], @opts[:ks]/8, 'SHA256')
  cipherMode = "#{@opts[:cipher]}-#{@opts[:ks]}-#{@opts[:mode]}"
  c = OpenSSL::Cipher.new(cipherMode)
  c.encrypt
  c.key = key
  c.iv = iv
  c.auth_data = adata
  ct = c.update(plaintext) + c.final
  tag = c.auth_tag(@opts[:ts]/8);
  ct = ct + tag
  out = {
    v: @opts[:v], adata: adata, ks: @opts[:ks], ct: Base64.strict_encode64(ct).encode('utf-8'), ts: tag.length * 8,
    mode: @opts[:mode], cipher: 'aes', iter: @opts[:iter], iv:  Base64.strict_encode64(iv),
    salt: Base64.strict_encode64(salt)
  }
  out.to_json
end