Skip to content

Instantly share code, notes, and snippets.

@yaauie
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yaauie/7fccc752df3c673ba44b to your computer and use it in GitHub Desktop.
Save yaauie/7fccc752df3c673ba44b to your computer and use it in GitHub Desktop.
# encoding: utf-8
require 'openssl'
class EasyKrypt
class Error < RuntimeError
def initialize(*args)
@cause = $!
end
attr_reader :cause
end
LoadError = Class.new(Error)
DumpError = Class.new(Error)
# @param key [String] a 32-byte string (secure random key)
def initialize(key = nil)
fail('invalid key length') if key && key.bytes.count != 32
@key = key
end
# @return [String] a 32-byte string (generated if not pre-configured)
def key
@key || (cipher && @key)
end
# @param encrypted_payload [String]
# @return decrypted_payload [String]
# @raise EasyKrypt::LoadError
def load(encrypted_payload)
@key || fail(ArgumentError, 'key not provided!')
# shift the 16-byte initialisation vector from the front
iv, encrypted = encrypted_payload.unpack('a16a*')
decipher = cipher(:decrypt)
decipher.iv = iv
decipher.update(encrypted) + decipher.final
rescue => e
raise LoadError, e.message
end
alias_method(:decrypt, :load)
# @param decrypted_payload [String]
# @param iv [String] (default: secure random iv)
# up to 16 bytes, used as an initialisation vector
# @return encrypted_payload [String] binary string
# @raise EasyKrypt::DumpError
def dump(plain, iv = nil)
encipher = cipher(:encrypt)
# ensure a 16-byte initialisation vector
iv ||= encipher.random_iv
encipher.iv = (iv.bytes.cycle.first(16).pack('C*'))
encrypted = encipher.update(plain) + encipher.final
(iv + encrypted)
rescue => e
raise DumpError, e.message
end
alias_method(:encrypt, :dump)
private
# Returns an AES-256-CBC OpenSSL::Cipher object pre-configured with the
# requested mode and our key; if no key is present, it is set here.
# @param mode [:encode, :decode]
# @return [OpenSSL::Cipher]
def cipher(mode = nil)
OpenSSL::Cipher.new('AES-256-CBC').tap do |cipher|
mode && cipher.public_send(mode)
if @key
cipher.key = @key
else
@key = cipher.random_key
end
end
end
end
# USAGE:
key = EasyKrypt.new.key # generate a new secure random key
krypt = EasyKrypt.new(key) # initialize with a given key
secret = krypt.dump('super secret text string') # => binary string
krypt.load(secret) # => "super secret text string"
EasyKrypt.new(key).load(secret)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment