require 'gcrypto' require_relative 'secretkey' require_relative 'error' require_relative 'io_utils' require_relative 'provider' require_relative 'global' require_relative 'converter' module GcryptoJce module KDF module PBKDF2 def derive(pass, opts = { }) if pass.nil? or pass.empty? raise GcryptoJce::Error, "Password to derive is empty" else if pass.is_a?(String) pa = pass.to_java.toCharArray elsif pass.java_kind_of?(Java::byte[]) pa = String.from_java_bytes(pass).to_java.toCharArray elsif pass.java_kind_of?(Java::char[]) pa = pass else raise GcryptoJce::Error, "Unknown password type '#{pass.class}'" end end iter = opts[:iteration] iter_lb = opts[:iter_lb] || 10000 iter_hb = opts[:iter_hb] || 30000 if iter.nil? or iter.to_i == 0 iter = rand(iter_lb...iter_hb) end hashSpec = opts[:hash_eng] if not (hashSpec.nil? or hashSpec.empty?) case hashSpec.downcase.to_sym when :sha1 engSpec = "PBKDF2WithHMACSHA1" when :sha2, :sha256 engSpec = "PBKDF2WithHMACSHA256" when :sha512 engSpec = "PBKDF2WithHMACSHA512" else engSpec = "PBKDF2WithHMACSHA256" GcryptoJce::Gconf.instance.glog.warn "User asking for hash engine '#{hashSpec}' but not in supported list. Using default PBKDF2WithHMACSHA256 instead." end end keyLen = opts[:outKeyLen] case keyLen when 128 outKeyLen = 128 when 256, 192 outKeyLen = 256 when 512 outKeyLen = 512 else outKeyLen = 256 end prov = GcryptoJce::Provider.handle_options(opts, nil) salt = opts[:salt] if salt.nil? salt = Java::byte[outKeyLen/8].new java.security.SecureRandom.new.nextBytes(salt) end GcryptoJce::GConf.instance.glog.debug "PBKDF2 using config salt : #{Gcrypto::Converter.to_hex(salt)} / iteration : #{iter} / output hash length : #{outKeyLen} / Eng : #{engSpec}" spec = javax.crypto.spec.PBEKeySpec.new(pa, salt, iter, outKeyLen) if prov.nil? fact = javax.crypto.SecretKeyFactory.getInstance(engSpec) else fact = javax.crypto.SecretKeyFactory.getInstance(engSpec, prov) end secKey = fact.generateSecret(spec) key = javax.crypto.spec.SecretKeySpec.new(secKey.encoded,"AES") res = { } res[:key] = key res[:hash] = secKey.getEncoded res[:salt] = salt res[:iteration] = iter res[:hashLen] = outKeyLen res[:eng] = :pbkdf2 res end end # end PBKDF2 # class PBKDF2Engine extend PBKDF2 end end # end KDF # end # end GcryptoJce #