require_relative '../data_conversion' require_relative '../keystore/keystore' module Ccrypto module Java class ECCPublicKey < Ccrypto::ECCPublicKey include DataConversion 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)) #p pubKey curve = pubKey.params.name ECCPublicKey.new(pubKey, curve) 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 def initialize(kp, conf) @nativeKeypair = kp @config = conf end def curve @config.provider_config[:curve] end # standardize external API def key_param @config end # standardize external API def public_key if @pubKey.nil? @pubKey = ECCPublicKey.new(@nativeKeypair.public, @config.curve) end @pubKey end # standardize external API def private_key ECCPrivateKey.new(@nativeKeypair.private) end # standardize external API def derive_enc_shared_secret(*args, &block) derive_dh_shared_secret(*args, &block) end # standardize external API def derive_dec_shared_secret(*args, &block) derive_dh_shared_secret(*args, &block) end def is_public_key_equal?(pubKey) public_key.equals?(pubKey) end def equal?(kp) case kp when Ccrypto::ECCKeyBundle private_key.encoded == kp.private_key.encoded else false end end 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 @nativeKeypair else block.call(key) if block end end when :jks Keystore::JKSKeystore.to_jks do |key, *val| case key when :keypair @nativeKeypair else block.call(key) if block end end else raise Ccrypto::Keystore::KeystoreException, "Unsupported keystore type '#{type}' for engine '#{self.class.name}'" end end private def derive_dh_shared_secret(pubKey, &block) JCEProvider.instance.add_bc_provider ka = javax.crypto.KeyAgreement.getInstance("ECDH", JCEProvider::DEFProv) ka.init(@nativeKeypair.private) 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 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}" @nativeKeypair.send(mtd, *args, &block) end def respond_to_missing?(mtd, incPriv = false) teLogger.debug "Respond to missing #{mtd}" @nativeKeypair.respond_to?(mtd) end def teLogger Ccrypto::Java.logger(:ecc_keybundle) end end # class ECCKeyBundle class ECCEngine include TR::CondUtils include DataConversion def self.supported_curves if @curves.nil? @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 <