使用BouncyCastle从文件中读取椭圆曲线私钥

BouncyCastle加密API允许使用常规java.security包对象创建和validation数字签名,例如java.security.PublicKeyjava.security.PrivateKey及其容器java.security.KeyPair

假设我使用OpenSSL创建一个.pem(或者,如果更简单,一个.der文件),它包含我想在我的应用程序中使用的椭圆曲线私钥。 例如,它看起来像这样:

 -----BEGIN EC PARAMETERS----- BgUrgQQACg== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHQCAQEEIDzESrZFmTaOozu2NyiS8LMZGqkHfpSOoI/qA9Lw+d4NoAcGBSuBBAAK oUQDQgAE7kIqoSQzC/UUXdFdQ9Xvu1Lri7pFfd7xDbQWhSqHaDtj+XY36Z1Cznun GDxlA0AavdVDuoGXxNQPIed3FxPE3Q== -----END EC PRIVATE KEY----- 

如何使用BouncyCastle API获取包含此私钥和相应公钥的java.security.KeyPair

请注意我想使用BouncyCastle 1.50中提供的API(在撰写本文时是最新的)并且没有弃用的API。 遗憾的是,这不包括其他SO答案中使用的PEMReader类。 此外,这个问题特定于椭圆曲线的格式; 在比较RSA或DSA密钥文件时,它们包含其他参数。

在Java中,这将是几乎相同的代码。 剥离保护字符串并解码Base64数据后,将其提供给此实用程序方法:

 public static PrivateKey keyToValue(byte[] pkcs8key) throw GeneralSecurityException { PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(pkcs8key); KeyFactory factory = KeyFactory.getInstance("ECDSA"); PrivateKey privateKey = factory.generatePrivate(spec); return privateKey; } 

除了divanov显示的标准JCE方法,只要你给它正确的输入(参见我的评论),或者只是像你的selfanswer一样使用JCE, BouncyCastle 1.48 up DOES仍然包含刚刚组织的旧PEMReaderfunction有点不同,在这种情况下你可以使用类似的东西:

 static void SO22963581BCPEMPrivateEC () throws Exception { Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); Reader rdr = new StringReader ("-----BEGIN EC PRIVATE KEY-----\n" +"MHQCAQEEIDzESrZFmTaOozu2NyiS8LMZGqkHfpSOoI/qA9Lw+d4NoAcGBSuBBAAK\n" +"oUQDQgAE7kIqoSQzC/UUXdFdQ9Xvu1Lri7pFfd7xDbQWhSqHaDtj+XY36Z1Cznun\n" +"GDxlA0AavdVDuoGXxNQPIed3FxPE3Q==\n"+"-----END EC PRIVATE KEY-----\n"); Object parsed = new org.bouncycastle.openssl.PEMParser(rdr).readObject(); KeyPair pair = new org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter().getKeyPair((org.bouncycastle.openssl.PEMKeyPair)parsed); System.out.println (pair.getPrivate().getAlgorithm()); } 

由于我只需要这个快速而肮脏的演示,我通过以下方式解决了它(在Scala中)。 首先,我在REPL中生成一个公共私钥对并打印出其数据:

 Security.addProvider(new BouncyCastleProvider) val SignatureScheme = "some signature scheme, eg ECDSA" val RandomAlgorithm = "some random algorithm, eg SHA1PRNG" val keygen = KeyPairGenerator.getInstance(SignatureScheme) val rng = SecureRandom.getInstance(RandomAlgorithm) rng.setSeed(seed) keygen.initialize(KeySize, rng) val kp = keygen.generateKeyPair() println(kp.getPublic.getEncoded.toSeq) // toSeq so that Scala actually prints it println(kp.getPrivate.getEncoded.toSeq) 

然后使用生成的数据,

 val hardcodedPublic = Array[Byte]( /* data */ ) val hardcodedPrivate = Array[Byte]( /* data */ ) val factory = KeyFactory.getInstance(SignatureScheme) val publicSpec = new X509EncodedKeySpec(hardcodedPublic) val publicKey = factory.generatePublic(publicSpec) val privateSpec = new PKCS8EncodedKeySpec(hardcodedPrivate) val privateKey = factory.generatePrivate(privateSpec) 

您需要知道的关键是默认情况下公钥数据使用X509编码,私钥数据使用PKCS8编码。 应该可以让OpenSSL输出这些格式并手动解析它们,但我没有检查如何。

我使用这个博客文章中有关SpongyCastle(这是Android的BouncyCastle别名)的信息非常有帮助。 遗憾的是,文档像这样碎片化,并且BouncyCastle的wiki在这个问题时已经失效了。

更新 :BouncyCastle wiki已启动,您可以在此处找到文档。