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] if iter.nil? or iter.to_i == 0 iter = rand(10000...20000) end keyLen = opts[:outKeyLen] case keyLen when 128 outKeyLen = 128 engSpec = "PBKDF2WithHMACSHA1" when 256, 192 outKeyLen = 256 engSpec = "PBKDF2WithHMACSHA256" when 512 outKeyLen = 512 engSpec = "PBKDF2WithHMACSHA512" else outKeyLen = 256 engSpec = "PBKDF2WithHMACSHA256" 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 #