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