[英]Java - asymmetric encryption of traffic with pre-shared public keys and without trust store hassles
[英]Java asymmetric encryption: preferred way to store public/private keys
此代碼生成一對公鑰/私鑰:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keypair = keyGen.genKeyPair();
PrivateKey privateKey = keypair.getPrivate();
PublicKey publicKey = keypair.getPublic();
我想知道的是你通常如何存儲公鑰:
選項1:存儲字節
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();
// ... write to file
// convert bytes back to public/private keys
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
我不喜歡的是將代碼綁定到具體的實現,如PKCS8EncodedKeySpec
和X509EncodedKeySpec
。
選項2:存儲模數和指數
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey, RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,RSAPrivateKeySpec.class);
// store modulus and exponent as BigIntegers
BigInteger modulus = pub.getModulus());
BigInteger exponent = pub.getPublicExponent());
// ... write to file
// recreate public key (the same applies to the private key)
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
第二種選擇更容易實現,但我不知道它是否會降低性能。
有什么建議嗎?
在我們的應用程序中,我們以DER格式存儲公鑰和私鑰,因此可以更容易地在java之外使用和操作它們。 在我們的例子中,私鑰沒有密碼。
要將私鑰轉換為更容易在java中使用的東西:
openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER
然后,您可以通過以下方式直接獲取RSA私鑰:
public static RSAPrivateKey getPrivateKey(File privateKeyFile) throws IOException, GeneralSecurityException {
byte[] keyBytes = new byte[(int)privateKeyFile.length()];
FileInputStream fis = new FileInputStream(privateKeyFile);
fis.read(keyBytes);
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(spec);
return privKey;
}
公鑰類似:
openssl rsa -in private.pem -pubout -outform DER -out public.der
並閱讀它:
public static RSAPublicKey getPublicKey(File publicKeyFile) throws IOException, GeneralSecurityException {
byte[] keyBytes = new byte[(int)publicKeyFile.length()];
FileInputStream fis = new FileInputStream(publicKeyFile);
fis.read(keyBytes);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey)factory.generatePublic(publicKeySpec);
return pubKey;
}
許多人存儲密鑰庫。 出於我們的目的,我們需要在多種不同語言的多個應用程序之間共享相同的密鑰,並且不希望在磁盤上復制文件。
在任何一種情況下,性能都不應該是一個巨大的問題,因為您可能會將這些鍵存儲在某種Singleton或緩存中,而不是每次都重新生成它們。
無論你是否意識到,你實際上都存儲了兩種情況下的字節。 我想在@Brian M. Carr的回答中暗示了正確的答案,即以最自然的形式存儲更高級別的對象。 在公鑰的情況下,明顯的選擇是作為PKCS#1 RSAPublicKey ASN.1結構,DER編碼,或作為X509 SubjectPublicKeyInfo ASN.1結構,DER編碼。 后者是Sun提供商提供的,sun class X509EncodedKeySpec支持的。 同樣,PKCS8EncodedKeySpec支持私鑰格式。 這兩種格式都是標准,例如openssl支持。 太陽傾向於:( - 支持現有標准,而不是定義自己的標准。
如果你想定義一個用於存儲密鑰的格式,那么我會選擇一種可消耗的格式,這樣當你想要改變加密時它就不會中斷(例如當舊的加密變弱時)。
所以我將存儲編碼為base64的字節,以及描述格式的字符串,“rsa”也許。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.