module Ccrypto module Java module Keystore class PEMKeystore include TR::CondUtils include DataConversion def self.to_pem(&block) raise KeystoreException, "Block is required" if not block pass = block.call(:store_pass) raise KeystoreException, "Password is required" if is_empty?(pass) keypair = block.call(:keypair) raise KeystoreException, "Keypair is required" if is_empty?(keypair) output = block.call(:output) if not_empty?(output) ext = File.extname(output) bname = File.basename(output, ext) privPath = File.join("#{bname}_priv#{ext}") pubPath = File.join("#{bname}_pub#{ext}") privHead, privFoot, pubHead, pubFoot = marker(keypair) File.open(privPath,"wb") do |f| f.write privHead f.write to_b64(keypair.private.to_bin) f.write privFoot end File.open(pubPath,"wb") do |f| f.write pubHead f.write to_b64(keypair.public.to_bin) f.write pubFoot end else [to_b64(keypair.private.to_bin),to_b64(keypair.public.to_bin)] end end # def to_pem def self.from_pem(str) raise KeystoreException, "block is required" if not block case check_keytype(str) when :ecc cont = str.lines[1..-2].join Ccrypto::Java::ECCPrivateKey.to_key(from_b64(cont)) when :rsa when :ed25519 when :x25519 when :crystal_dilithium when :crystal_kyber else raise KeystoreException, "Unable to derive keytype from input : '#{str}'" end case key when java.security.interfaces.ECPrivateKey param = java.security.AlgorithmParameters.getInstance("EC") param.init(key.params) oid = param.getParameterSpec(java.security.spec.ECGenParameterSpec.java_class).name curve = org.bouncycastle.asn1.x9.ECNamedCurveTable.getName(org.bouncycastle.asn1.ASN1ObjectIdentifier.new(oid)) logger.debug "Recover curve info : #{curve}" conf = Ccrypto::Java::ECCEngine.find_curve(curve) logger.debug "Found config : #{conf}" [Ccrypto::Java::ECCKeyBundle.new(kp, conf), userCert, chain] when org.bouncycastle.jcajce.provider.asymmetric.ec::BCECPrivateKey curve = key.params.name logger.debug "Recover curve info : #{curve}" conf = Ccrypto::Java::ECCEngine.find_curve(curve) logger.debug "Found config : #{conf}" [Ccrypto::Java::ECCKeyBundle.new(kp, conf), userCert, chain] when java.security.interfaces.RSAPrivateKey [Ccrypto::Java::RSAKeyBundle.new(kp), userCert, chain] else raise KeystoreException, "Unknown key type #{key}" end end private def self.logger Ccrypto::Java.logger(:pem_ks) end def self.marker(keypair) case keypair when ECCKeybundle keytype = "ECC" when RSAKeybundle keytype = "RSA" when ED25519KeyBundle keytype = "ED25519" when X25519KeyBundle keytype = "X25519" when CrystalDilithiumKeyBundle keytype = "CRYSTAL DILITHIUM" when CrystalKyberKeyBundle keytype = "CRYSTAL KYBER" else raise Error, "Unsupported keypair type '#{keypair.class.name}'" end [ "-----BEGIN #{keytype} PRIVATE KEY-----\n", "\n-----END #{keytype} PRIVATE KEY-----\n", "-----BEGIN #{keytype} PUBLIC KEY-----\n", "\n-----END #{keytype} PUBLIC KEY-----\n", ] end def self.check_keytype(cont) case cont when /ECC/ :ecc when /RSA/ :rsa when /ED25519/ :ed25519 when /X25519/ :x25519 when /DILITHIUM/ :crystal_dilithium when /KYBER/ :crystal_kyber else nil end end # def check_keytype end end end end