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

时间:2014-04-09 13:09:55

标签: java openssl bouncycastle

BouncyCastle加密API允许使用常规java.security包对象创建和验证数字签名,例如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密钥文件时包含其他参数。

3 个答案:

答案 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