2014-04-09 93 views
3

的BouncyCastle的加密API允許創建和使用的常規java.security包對象,如java.security.PublicKeyjava.security.PrivateKey及其容器java.security.KeyPair驗證數字簽名。閱讀橢圓曲線從私有密鑰文件與BouncyCastle的

假設我使用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

的'EC PARAMETERS'塊在你的_file_我這是'openssl ecparam -genkey'默認工作的一種意外;它不需要或用作實際鍵的一部分,你可以通過指定'-noout'來忽略它,這肯定有點不明顯。 EC(DSA/DH)_does_的實際密鑰結構(base64/DER數據中的「隱藏」)包含一些RSA不參與的信息,但是DSA_does_。 –

回答

3

在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; 
} 
+0

我已將此答案標記爲正確,因爲它以最初詢問的形式呈現答案。對於普通觀衆來說,它也應該更清楚。 – DCKing

+2

查看[JCA文檔](http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyFactory)讓我相信'KeyFactory.getInstance()'的參數應該是「EC」而不是「ECDSA」。我錯了嗎? –

+1

這取決於使用的提供商。對於BouncyCastle它可能是EC和ECDSA。對於Sun提供商來說,它可能只是EC,我沒有太多用處。 – divanov

2

由於我只需要這個快速和骯髒的演示,我以下面的方式(在斯卡拉)解決它。首先,我產生了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

7

除了標準JCE方法shown by divanov只要你給它正確的輸入(見我的評論此),或者只是使用JCE在喜歡你selfanswer,BouncyCastle的首位 1.48多達確實還包含舊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()); 
}