require 'openssl' require 'digest/sha2' require 'digest/sha1' require 'base64' module EzCrypto =begin rdoc The Key is the only class you need to understand for simple use. === Algorithms The crypto algorithms default to aes-128-cbc however on any of the class methods you can change it to one of the standard openssl cipher names using the optional :algorithm=>alg name parameter. Eg. Key.new @raw, :algorithm=>"des" Key.generate :algorithm=>"blowfish" Key.with_password @pwd,@salt,:algorithm=>"aes256" == License Action Web Service is released under the MIT license. == Support To contact the author, send mail to pelleb@gmail.com Also see my blogs at: http://stakeventures.com and http://neubia.com This project was based on code used in my project StakeItOut, where you can securely share web services with your partners. https://stakeitout.com (C) 2005 Pelle Braendgaard =end class Key attr_reader :raw,:algorithm =begin rdoc Initialize the key with raw unencoded binary key data. This needs to be at least 16 bytes long for the default aes-128 algorithm. =end def initialize(raw,options = {}) @raw=raw @algorithm=options[:algorithm]||"aes-128-cbc" end =begin rdoc Generate random key. =end def self.generate(options = {}) Key.new(EzCrypto::Digester.generate_key(calculate_key_size(options[:algorithm])),options) end =begin rdoc Create key generated from the given password and salt =end def self.with_password(password,salt,options = {}) Key.new(EzCrypto::Digester.get_key(password,salt,calculate_key_size(options[:algorithm])),options) end =begin rdoc Initialize the key with Base64 encoded key data. =end def self.decode(encoded,options = {}) Key.new(Base64.decode64(encoded),options) end =begin rdoc Encrypts the data with the given password and a salt. Short hand for: key=Key.with_password(password,salt,options) key.encrypt(data) =end def self.encrypt_with_password(password,salt,data,options = {}) key=Key.with_password(password,salt,options) key.encrypt(data) end =begin rdoc Decrypts the data with the given password and a salt. Short hand for: key=Key.with_password(password,salt,options) key.decrypt(data) =end def self.decrypt_with_password(password,salt,data,options = {}) key=Key.with_password(password,salt,options) key.decrypt(data) end =begin rdoc Given an algorithm this calculates the keysize. This is used by both the generate and with_password methods. This is not yet 100% complete. =end def self.calculate_key_size(algorithm) if !algorithm.nil? algorithm=~/^([[:alnum:]]+)(-(\d+))?/ if $3 size=($3.to_i)/8 else case $1 when "bf" size = 16 when "blowfish" size = 16 when "des" size = 8 when "des3" size = 24 when "aes128" size = 16 when "aes192" size = 24 when "aes256" size = 32 when "rc2" size = 16 when "rc4" size = 16 else size = 16 end end end if size.nil? size = 16 end size end =begin rdoc returns the Base64 encoded key. =end def encode Base64.encode64 @raw end =begin rdoc returns the Base64 encoded key. Synonym for encode. =end def to_s encode end =begin rdoc Encrypts the data and returns it in encrypted binary form. =end def encrypt(data) @cipher=EzCrypto::Encrypter.new(self,"",@algorithm) @cipher.encrypt(data) end =begin rdoc Encrypts the data and returns it in encrypted Base64 encoded form. =end def encrypt64(data) Base64.encode64(encrypt(data)) end =begin rdoc Decrypts the data passed to it in binary format. =end def decrypt(data) @cipher=EzCrypto::Decrypter.new(self,"",@algorithm) @cipher.gulp(data) rescue puts @algorithm throw $! end =begin rdoc Decrypts a Base64 formatted string =end def decrypt64(data) decrypt(Base64.decode64(data)) end end =begin rdoc Abstract Wrapper around OpenSSL's Cipher object. Extended by Encrypter and Decrypter. You probably should be using the Key class instead. Warning! The interface may change. =end class CipherWrapper =begin rdoc =end def initialize(key,target,mode,algorithm) @cipher = OpenSSL::Cipher::Cipher.new(algorithm) if mode @cipher.encrypt else @cipher.decrypt end @cipher.key=key.raw @cipher.padding=1 @target=target @finished=false end =begin rdoc Process the givend data with the cipher. =end def update(data) reset if @finished @target<< @cipher.update(data) end =begin rdoc =end def <<(data) update(data) end =begin rdoc Finishes up any last bits of data in the cipher and returns the final result. =end def final @target<< @cipher.final @finished=true @target end =begin rdoc Processes the entire data string using update and performs a final on it returning the data. =end def gulp(data) update(data) final end =begin rdoc =end def reset(target="") @target=target @finished=false end end =begin rdoc Wrapper around OpenSSL Cipher for Encryption use. You probably should be using Key instead. Warning! The interface may change. =end class Encrypter