Java 非对称加密:存储公钥/私钥的首选方式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3441501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java asymmetric encryption: preferred way to store public/private keys
提问by Guido
This code generates a pair of public/private keys:
此代码生成一对公钥/私钥:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(1024);
KeyPair keypair = keyGen.genKeyPair();
PrivateKey privateKey = keypair.getPrivate();
PublicKey publicKey = keypair.getPublic();
What I'd like to know is how do you usually store the public key:
我想知道的是你通常如何存储公钥:
Option 1: store the bytes
选项 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);
What I don't like is to tie the code to concrete implementations such as PKCS8EncodedKeySpecand X509EncodedKeySpec.
我不喜欢将代码与具体实现相关联,例如PKCS8EncodedKeySpec和X509EncodedKeySpec。
Option 2: store the modulus and exponent
选项 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);
The second option is easier to implement, but I don't know if it could be less performant.
第二个选项更容易实现,但我不知道它是否会降低性能。
Any advise ?
有什么建议吗?
回答by Brian M. Carr
In our applications, we store public and private keys in DER format so they can be used and manipulated outside java more easily. In our case, the private keys do not have passwords on them.
在我们的应用程序中,我们以 DER 格式存储公钥和私钥,以便可以更轻松地在 Java 之外使用和操作它们。在我们的例子中,私钥没有密码。
To convert the private key to something more easily usable in java:
要将私钥转换为在 Java 中更容易使用的东西:
openssl pkcs8 -topk8 -nocrypt -in key.pem -inform PEM -out key.der -outform DER
Then you can obtain an RSA private key directly by:
然后您可以通过以下方式直接获取 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;
}
The public key is similar:
公钥类似:
openssl rsa -in private.pem -pubout -outform DER -out public.der
and to read it:
并阅读它:
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;
}
Many people store then keystores. For our purposes, we needed the same key to be shared across multiple applications in several different languages, and didn't want to duplicate the files on disk.
许多人存储然后密钥库。出于我们的目的,我们需要在多种不同语言的多个应用程序之间共享相同的密钥,并且不想复制磁盘上的文件。
In either case, the performance shouldn't be a huge concern, because you're likely to store those keys in some sort of Singleton or cache instead of regenerating them each time.
在任何一种情况下,性能都不应该是一个大问题,因为您可能会将这些键存储在某种单例或缓存中,而不是每次都重新生成它们。
回答by President James K. Polk
You're actually storing the bytes in both cases whether you realize it or not. I suppose the correct answer is hinted at in @Brian M. Carr answer, which is to store the higher-level object in its most natural form. In the case of public keys, the obvious choices are as a PKCS#1 RSAPublicKey ASN.1 structure, DER-encoded, or as an X509 SubjectPublicKeyInfo ASN.1 structure, DER-encoded. The latter is what the Sun providers give you, which the sun class X509EncodedKeySpec supports. Similarly, the PKCS8EncodedKeySpec supports a private key format. Both these formats are standards, and are supported by openssl for example. Sun tends -- tended :( -- to support existing standards rather then define their own.
无论您是否意识到,您实际上都在两种情况下存储字节。我想@Brian M. Carr 的答案暗示了正确的答案,即以最自然的形式存储更高级别的对象。在公钥的情况下,明显的选择是作为 PKCS#1 RSAPublicKey ASN.1 结构,DER 编码,或作为 X509 SubjectPublicKeyInfo ASN.1 结构,DER 编码。后者是 Sun 提供者为您提供的,sun 类 X509EncodedKeySpec 支持。同样,PKCS8EncodedKeySpec 支持私钥格式。这两种格式都是标准格式,例如受 openssl 支持。Sun 倾向于 - 倾向于 :( - 支持现有标准而不是定义自己的标准。
回答by Alexander Kj?ll
If you want to define a format for storing the keys, then I would choose a format that is expendable so that it doesn't break when you want to change encryption (when the old one gets to weak for example).
如果您想定义用于存储密钥的格式,那么我会选择一种可消耗的格式,以便在您想要更改加密时(例如,当旧的加密变弱时)不会破坏它。
So i would store the bytes encoded as base64, together with a string that describes the format, "rsa" maybe.
因此,我会将编码为 base64 的字节与描述格式的字符串一起存储,可能是“rsa”。

