lib/ccrypto/java/engines/pbkdf2_engine.rb in ccrypto-java-0.1.0 vs lib/ccrypto/java/engines/pbkdf2_engine.rb in ccrypto-java-0.2.0

- old
+ new

@@ -1,47 +1,108 @@ require_relative '../data_conversion' module Ccrypto module Java - + class PBKDF2Engine include TR::CondUtils include DataConversion + class PBKDF2EngineException < KDFEngineException; end + + class SupportedPBKDF2HMAC + include Ccrypto::InMemoryRecord + end + + def self.supported_pbkdf2_digests + + if @supportedHmac.nil? + @supportedHmac = SupportedPBKDF2HMAC.load("cj_pbkdf2") + logger.debug "supported hmac : #{@supportedHmac.empty?}" + if @supportedHmac.empty? + HMACEngine.supported_hmac_configs.each do |hm| + begin + algo = "PBKDF2With#{hm.provider_config[:hmac_algo]}" + prov = hm.provider_config[:jce_provider] + javax.crypto.SecretKeyFactory.getInstance(algo, prov) + + logger.debug "PBKDF2 algo #{algo} is good" + hm.provider_config[:hmac_algo] = algo + logger.debug "Registering PBKDF2 config #{hm.inspect}" + @supportedHmac.register(hm, { tag_under: :algo, tag_value: hm.digest_config.algo }) + #@supportedHmac[algo] = hm + rescue Exception => ex + logger.debug "HMAC algo #{algo} failed with PBKDF2 with error #{ex}" + end + end + @supportedHmac.save("cj_pbkdf2") + end + end + @supportedHmac + + end + + def self.find_supported_hmac_by_digest(algo) + supported_pbkdf2_digests.find( algo: algo ) + end + + private + def self.logger + Ccrypto::Java.logger(:pbkdf2_eng_c) + end + + public def initialize(*args, &block) @config = args.first - raise KDFEngineException, "KDF config is expected. Given #{@config}" if not @config.is_a?(Ccrypto::PBKDF2Config) - raise KDFEngineException, "Output bit length (outBitLength) value is not given or not a positive value (#{@config.outBitLength})" if is_empty?(@config.outBitLength) or @config.outBitLength <= 0 + raise PBKDF2EngineException, "KDF config is expected. Given #{@config}" if not @config.is_a?(Ccrypto::PBKDF2Config) + raise PBKDF2EngineException, "Output bit length (outBitLength) value is not given or not a positive value (#{@config.outBitLength})" if is_empty?(@config.outBitLength) or @config.outBitLength <= 0 - raise KDFEngineException, "Digest algo is not supported. Given #{@config.digest}, supported: #{supported_digest.join(", ")}" if not @config.digest.nil? and not is_digest_supported?(@config.digest) + if is_empty?(@config.digest) + @config.digest = default_digest + else - @config.digest = default_digest if is_empty?(@config.digest) + case @config.digest + when String, Symbol + dig = self.class.find_supported_hmac_by_digest(@config.digest) + raise PBKDF2EngineException, "Cannot find digest '#{@config.digest}'" if is_empty?(dig) + logger.warn "More than 1 result for supported hmac by digest found. Found #{dig.length}" if dig.length > 1 + @config.digest = dig.first - @config.salt = SecureRandom.random_bytes(16) if is_empty?(@config.salt) + when Ccrypto::HMACConfig + + else + raise PBKDF2EngineException, "HMACConfig is expected instead got '#{@config.digest.class}'" + + end + + raise PBKDF2EngineException, "HMACConfig is required to be provider initialized HMACConfig. Please get the HMACConfig via the supported_hmac from PBKDF2" if is_empty?(@config.digest.provider_config[:hmac_algo]) + end + + #@config.salt = SecureRandom.random_bytes(16) if is_empty?(@config.salt) + end def derive(input, output = :binary) - + + cinput = java.lang.String.new(to_java_bytes(input)) + + #raise KDFEngineException, "Given input is not a String" if not input.is_a?(String) + begin - case input - when String - if input.ascii_only? - pass = input.to_java.toCharArray - else - pass = to_hex(to_java_bytes(input)).to_java.toCharArray - end - when ::Java::byte[] - pass = to_hex(to_java_bytes(input)).to_java.toCharArray + algo = @config.digest.provider_config[:hmac_algo] + prov = @config.digest.provider_config[:jce_provider] + if not_empty?(prov) + skf = javax.crypto.SecretKeyFactory.getInstance(algo, prov) else - raise KDFEngineException, "Input type '#{input.class}' cannot convert to char array" + skf = javax.crypto.SecretKeyFactory.getInstance(algo) end - skf = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHMAC#{@config.digest.upcase}",JCEProvider::DEFProv) - keySpec = javax.crypto.spec.PBEKeySpec.new(pass.to_java, to_java_bytes(@config.salt), @config.iter, @config.outBitLength) + # Java API 1st parameter is char[] + keySpec = javax.crypto.spec.PBEKeySpec.new(cinput.to_java.toCharArray, to_java_bytes(@config.salt), @config.iter, @config.outBitLength) sk = skf.generateSecret(keySpec) out = sk.encoded case output @@ -58,27 +119,15 @@ end end def default_digest - :sha256 + self.class.find_supported_hmac_by_digest("sha256").first end private def logger - if @logger.nil? - @logger = TeLogger::Tlogger.new - @logger.tag = :j_pbkdf2 - end - @logger - end - - def is_digest_supported?(dig) - supported_digest.include?(dig) - end - - def supported_digest - [:sha1, :sha256, :sha224, :sha384, :sha512] + Ccrypto::Java.logger(:pbkdf2_eng) end end