lib/ccrypto/java/engines/ecc_engine.rb in ccrypto-java-0.1.0 vs lib/ccrypto/java/engines/ecc_engine.rb in ccrypto-java-0.2.0
- old
+ new
@@ -1,191 +1,319 @@
require_relative '../data_conversion'
-require_relative '../keybundle_store/pkcs12'
+require_relative '../keystore/keystore'
module Ccrypto
module Java
class ECCPublicKey < Ccrypto::ECCPublicKey
include DataConversion
- def to_bin
- @native_pubKey.encoded
+ def initialize(kp, curve)
+ super(kp)
+ @curve = curve
end
+ def curve
+ @curve
+ end
+
+ def to_bin(enc = :bin)
+ res = @native_pubKey.encoded
+ case enc
+ when :b64, :base64
+ to_b64(res)
+ when :hex
+ to_hex(res)
+ else
+ res
+ end
+ end
+
def encoded
to_bin
end
+ def to_pem
+ cont = ["-----BEGIN ECC PUBLIC KEY-----\n"]
+ cont << to_b64(to_bin)
+ cont << "\n-----END ECC PUBLIC KEY-----"
+ cont.join
+ end
+
+ def self.from_pem(str)
+ if str =~ /ECC PUBLIC/
+ cont = str.lines[1..-2].join.strip
+ to_key(from_b64(cont))
+ else
+ raise KeypairEngineException, "Not an ECC public key"
+ end
+ end
+
+ # from binary to public key object
def self.to_key(bin)
bin = to_java_bytes(bin) if not bin.is_a?(::Java::byte[])
pubKey = java.security.KeyFactory.getInstance("ECDSA", "BC").generatePublic(java.security.spec.X509EncodedKeySpec.new(bin))
- ECCPublicKey.new(pubKey)
+ #p pubKey
+ curve = pubKey.params.name
+ ECCPublicKey.new(pubKey, curve)
end
- end
+ def equals?(pubKey)
+ if not @native_pubKey.nil?
+ case pubKey
+ when ECCPublicKey
+ @native_pubKey.encoded == pubKey.to_bin
+ else
+ logger.warn "Unmatched public key : (native) #{@native_pubKey} vs. (subject) #{pubKey}"
+ false
+ end
+ else
+ logger.warn "ECCPublicKey equals? returned false because native_pubKey is nil"
+ false
+ end
+ end
+ alias_method :key_equals?, :equals?
+ private
+ def logger
+ Ccrypto::Java.logger(:ecc_pubKey)
+ end
+
+ end # class ECCPublicKey
+
+ class ECCPrivateKey < Ccrypto::ECCPrivateKey
+ include DataConversion
+
+ def self.to_key(bin, &block)
+ if block
+ prov = block.call(:jce_provider)
+ else
+ prov = JCEProvider::BCProv
+ end
+
+ kf = java.security.KeyFactory.getInstance("ECDSA",prov)
+ priv = kf.generate_private(java.security.spec.PKCS8EncodedKeySpec.new(bin))
+ curve = priv.params.name
+ ECCPrivateKey.new(priv, curve)
+
+ end
+
+ attr_reader :curve
+ def initialize(privKey, curve = nil)
+ super(privKey)
+ @curve = curve
+ end
+
+ def to_pem
+ cont = ["-----BEGIN ECC PRIVATE KEY-----\n"]
+ cont << to_b64(@native_privKey.encoded)
+ cont << "\n-----END ECC PRIVATE KEY-----"
+ cont.join
+ end
+
+ def self.from_pem(str)
+ if str =~ /ECC PRIVATE/
+ cont = str.lines[1..-2].join.strip
+ to_key(from_b64(cont))
+ else
+ raise KeypairEngineException, "Not an ECC private key"
+ end
+ end
+
+ def to_bin
+ @native_privKey.encoded
+ end
+
+ def equals?(privKey)
+ if not @native_privKey.nil?
+ case privKey
+ when ECCPrivateKey
+ @native_privKey.encoded == privKey.to_bin
+ else
+ logger.warn "Unmatched private key : (native) #{@native_privKey} vs. (subject) #{privKey}"
+ false
+ end
+ else
+ logger.warn "ECCPrivateKey equals? returned false because native_privKey is nil"
+ false
+ end
+ end
+ alias_method :key_equals?, :equals?
+
+ end # class ECCPrivateKey
+
class ECCKeyBundle
include Ccrypto::ECCKeyBundle
include TR::CondUtils
include DataConversion
- include PKCS12
+ def initialize(kp, conf)
+ @nativeKeypair = kp
+ @config = conf
+ end
- include TeLogger::TeLogHelper
-
- teLogger_tag :j_ecc_keybundle
-
- def initialize(kp)
- @keypair = kp
+ def curve
+ @config.provider_config[:curve]
end
- def native_keypair
- @keypair
+ # standardize external API
+ def key_param
+ @config
end
+ # standardize external API
def public_key
if @pubKey.nil?
- @pubKey = ECCPublicKey.new(@keypair.public)
+ @pubKey = ECCPublicKey.new(@nativeKeypair.public, @config.curve)
end
@pubKey
end
+ # standardize external API
def private_key
- ECCPrivateKey.new(@keypair.private)
+ ECCPrivateKey.new(@nativeKeypair.private)
end
- def derive_dh_shared_secret(pubKey, &block)
+ # standardize external API
+ def derive_enc_shared_secret(*args, &block)
+ derive_dh_shared_secret(*args, &block)
+ end
- JCEProvider.instance.add_bc_provider
+ # standardize external API
+ def derive_dec_shared_secret(*args, &block)
+ derive_dh_shared_secret(*args, &block)
+ end
- ka = javax.crypto.KeyAgreement.getInstance("ECDH", JCEProvider::DEFProv)
- ka.init(@keypair.private)
+ def is_public_key_equal?(pubKey)
+ public_key.equals?(pubKey)
+ end
- case pubKey
- when ECCPublicKey
- pub = pubKey.native_pubKey
- when java.security.PublicKey
- pub = pubKey
+ def equal?(kp)
+ case kp
+ when Ccrypto::ECCKeyBundle
+ private_key.encoded == kp.private_key.encoded
else
- raise KeypairEngineException, "Unsupported public key type #{pubKey.class}"
+ false
end
- ka.doPhase(pub, true)
- #ka.doPhase(pubKey.native_pubKey, true)
- if block
- keyType = block.call(:keytype)
- else
- keyType = "AES"
- end
- keyType = "AES" if is_empty?(keyType)
- teLogger.debug "Generate secret key type #{keyType}"
- ka.generateSecret(keyType).encoded
end
- def is_public_key_equal?(pubKey)
- @keypair.public.encoded == pubKey.encoded
- end
-
- def to_storage(type, &block)
-
- case type
- when :p12, :pkcs12
- to_pkcs12 do |key|
+ def write_keystore(type, &block)
+ ksType = Keystore.map_keystore_type(type)
+ case ksType
+ when :pkcs12
+ Keystore::PKCS12Keystore.to_p12 do |key, *val|
case key
when :keypair
- @keypair
+ @nativeKeypair
else
block.call(key) if block
end
end
-
when :jks
- to_pkcs12 do |key|
+ Keystore::JKSKeystore.to_jks do |key, *val|
case key
- when :storeType
- "JKS"
when :keypair
- @keypair
+ @nativeKeypair
else
- block.call(key) if key
+ block.call(key) if block
end
end
-
- when :pem
- header = "-----BEGIN EC PRIVATE KEY-----\n"
- footer = "\n-----END EC PRIVATE KEY-----"
-
- out = StringIO.new
- out.write header
- out.write to_b64_mime(@keypair.private.encoded)
- out.write footer
-
- out.string
-
else
- raise KeypairEngineException, "Unknown storage type #{type}"
+ raise Ccrypto::Keystore::KeystoreException, "Unsupported keystore type '#{type}' for engine '#{self.class.name}'"
end
-
end
- def self.from_storage(bin, &block)
-
- if is_pem?(bin)
- else
- from_pkcs12(bin, &block)
- end
+ private
+ def derive_dh_shared_secret(pubKey, &block)
- end
+ JCEProvider.instance.add_bc_provider
- def self.is_pem?(bin)
- begin
- (bin =~ /BEGIN/) != nil
- rescue ArgumentError => ex
- false
- end
- end
+ ka = javax.crypto.KeyAgreement.getInstance("ECDH", JCEProvider::DEFProv)
+ ka.init(@nativeKeypair.private)
- def equal?(kp)
- case kp
- when Ccrypto::ECCKeyBundle
- @keypair.encoded == kp.private.encoded
+ case pubKey
+ when ECCPublicKey
+ #teLogger.debug "pubKey instanceof ECCPublicKey"
+ pub = pubKey.native_pubKey
+ when java.security.PublicKey
+ #teLogger.debug "pubKey instanceof java.security.PublicKey"
+ pub = pubKey
else
- false
+ raise KeypairEngineException, "Unsupported public key type #{pubKey.class}"
end
+ ka.doPhase(pub, true)
+
+ ka.generateSecret
+
+ #if block
+ # keyType = block.call(:keytype)
+ #else
+ # keyType = "AES"
+ #end
+ #keyType = "AES" if is_empty?(keyType)
+ #teLogger.debug "Generate secret key type #{keyType}"
+ #ka.generateSecret(keyType).encoded
+
end
def method_missing(mtd, *args, &block)
teLogger.debug "Sending to native #{mtd}"
- @keypair.send(mtd, *args, &block)
+ @nativeKeypair.send(mtd, *args, &block)
end
def respond_to_missing?(mtd, incPriv = false)
teLogger.debug "Respond to missing #{mtd}"
- @keypair.respond_to?(mtd)
+ @nativeKeypair.respond_to?(mtd)
end
- end
+ def teLogger
+ Ccrypto::Java.logger(:ecc_keybundle)
+ end
+ end # class ECCKeyBundle
+
class ECCEngine
include TR::CondUtils
include DataConversion
- include TeLogger::TeLogHelper
- teLogger_tag :j_ecc
-
def self.supported_curves
if @curves.nil?
- @curves = org.bouncycastle.asn1.x9.ECNamedCurveTable.getNames.sort.to_a.map { |c| Ccrypto::ECCConfig.new(c) }
+ @curves = org.bouncycastle.asn1.x9.ECNamedCurveTable.getNames.sort.to_a.map { |c|
+ conf = Ccrypto::ECCConfig.new(c.downcase.to_sym)
+ conf.provider_config = { curve: c }
+ conf
+ }
end
@curves
end
+ def self.find_curve(name)
+ case name
+ when String, Symbol
+ supported_curves.select { |c| c.provider_config[:curve] == name or c.curve == name.downcase.to_sym }.first
+ when Ccrypto::ECCKeyBundle
+ fname = name.key_param
+ supported_curves.select { |c| c.provider_config[:curve] == fname.provider_config[:curve] or c.curve == fname.algo }.first
+ when Ccrypto::ECCPublicKey
+ fname = name.curve
+ supported_curves.select { |c| c.provider_config[:curve] == fname or c.curve == fname.to_sym }.first
+ else
+ raise KeypairEngineException, "Not supported curve finder with '#{name.class}'"
+ end
+ end
+ class <<self
+ alias_method :supported_params, :supported_curves
+ alias_method :find_by_param, :find_curve
+ end
+
def initialize(*args,&block)
@config = args.first
raise KeypairEngineException, "1st parameter must be a #{Ccrypto::KeypairConfig.class} object" if not @config.is_a?(Ccrypto::KeypairConfig)
+ raise KeypairEngineException, "Keypair config must be an initialized config. Please get the initialized config from the list of supported_curves()" if is_empty?(@config.provider_config)
end
def generate_keypair(&block)
algoName = "ECDSA"
@@ -205,14 +333,14 @@
randomEngine = uRandEng if not uRandEng.nil?
end
kpg = java.security.KeyPairGenerator.getInstance(algoName, prov)
#kpg.java_send :initialize, [java.security.spec.AlgorithmParameterSpec, java.security.SecureRandom], java.security.spec.ECGenParameterSpec.new(curve), java.security.SecureRandom.new
- kpg.java_send :initialize, [java.security.spec.AlgorithmParameterSpec, randomEngine.class], java.security.spec.ECGenParameterSpec.new(@config.curve), randomEngine
+ kpg.java_send :initialize, [java.security.spec.AlgorithmParameterSpec, randomEngine.class], java.security.spec.ECGenParameterSpec.new(@config.provider_config[:curve]), randomEngine
kp = kpg.generate_key_pair
- kb = ECCKeyBundle.new(kp)
+ kb = ECCKeyBundle.new(kp, @config)
kb
end
def regenerate_keypair(pubKey, privKey, &block)
@@ -225,11 +353,11 @@
raise KeypairEngineException, "ECC keypair is required. Given #{@config.keypair}" if not @config.keypair.is_a?(ECCKeyBundle)
kp = @config.keypair
sign = java.security.Signature.getInstance("SHA256WithECDSA")
sign.initSign(kp.private_key)
- teLogger.debug "Signing data : #{val}"
+ #teLogger.debug "Signing data : #{val}"
case val
when java.io.InputStream
buf = Java::byte[102400].new
while((read = val.read(buf, 0, buf.length)) != nil)
sign.update(buf,0,read)
@@ -242,11 +370,11 @@
end
def self.verify(pubKey, val, sign)
ver = java.security.Signature.getInstance("SHA256WithECDSA")
ver.initVerify(pubKey)
- teLogger.debug "Verifing data : #{val}"
+ #teLogger.debug "Verifing data : #{val}"
case val
when java.io.InputStream
buf = Java::byte[102400].new
while((read = val.read(buf, 0 ,buf.length)) != nil)
ver.update(buf,0, read)
@@ -255,9 +383,34 @@
ver.update(to_java_bytes(val))
end
ver.verify(to_java_bytes(sign))
end
+
+ #
+ # KeyFactory keyFactory = KeyFactory.getInstance(EC.getAlgorithmName(), BouncyCastleProviderHolder.getInstance());
+ # BCECPrivateKey ecPrivateKey = (BCECPrivateKey) privateKey;
+ # ECParameterSpec ecParameterSpec = ecPrivateKey.getParameters();
+ # ECPoint ecPoint = new FixedPointCombMultiplier().multiply(ecParameterSpec.getG(), ecPrivateKey.getD());
+ # ECPublicKeySpec keySpec = new ECPublicKeySpec(ecPoint, ecParameterSpec);
+ # return keyFactory.generatePublic(keySpec);
+ #
+ def self.ecc_public_key_from_private_key(privKey)
+ kf = java.security.KeyFactory.getInstance("ECDSA", JCEProvider::BCProv)
+ param = privKey.parameters
+ ecPoint = org.bouncycastle.math.ec.FixedPointCombMultiplier.new.multiply(param.g, privKey.d)
+ keySpec = org.bouncycastle.jce.spec.ECPublicKeySpec.new(ecPoint, param)
+ kf.generatePublic(keySpec)
+ end
+
+ private
+ def self.teLogger
+ Ccrypto::Java.logger(:ecc_eng)
+ end
+ def teLogger
+ self.class.teLogger
+ end
+
end
end
end