簡體   English   中英

Java非對稱加密:存儲公鑰/私鑰的首選方式

[英]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);

我不喜歡的是將代碼綁定到具體的實現,如PKCS8EncodedKeySpecX509EncodedKeySpec

選項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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM