BouncyCastle加密API允许使用常规java.security
包对象创建和验证数字签名,例如java.security.PublicKey
,java.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密钥文件时包含其他参数。
答案 0 :(得分:10)
除了标准的JCE方法shown by divanov之外,只要你给它正确的输入(参见我的评论),或者首先使用JCE就像你的selfanswer一样, BouncyCastle 1.48 up DOES仍然包含旧的PEMReader功能,只是组织有点不同,在这种情况下你可以使用类似的东西:
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());
}
答案 1 :(得分:6)
在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;
}
答案 2 :(得分:3)
由于我只需要这个快速而肮脏的演示,我通过以下方式解决了它(在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输出这些格式并手动解析它们,但我没有检查如何。
我使用来自this blog post的关于SpongyCastle(这是Android的BouncyCastle别名)的信息非常有帮助。遗憾的是,文档像这样碎片化,并且BouncyCastle的wiki在这个问题发生时就已经失效了。
更新:BouncyCastle wiki已启动,您可以找到文档here。