Java非对称加密:存储公钥/私钥的首选方式
此代码生成一对公钥/私钥:
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);
第二个选项更容易实现,但我不知道它是否会降低性能。
有什么建议吗?
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
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 PKCS8EncodedKeySpec
and X509EncodedKeySpec
.
Option 2: store the modulus and exponent
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 ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在我们的应用程序中,我们以 DER 格式存储公钥和私钥,以便可以更轻松地在 java 外部使用和操作它们。在我们的例子中,私钥上没有密码。
要将私钥转换为在 java 中更容易使用的东西:
然后您可以直接通过以下方式获取 RSA 私钥:
公钥类似:
并读取它:
许多人存储然后密钥库。出于我们的目的,我们需要在多种不同语言的多个应用程序之间共享相同的密钥,并且不想在磁盘上复制文件。
无论哪种情况,性能都不应该成为一个大问题,因为您可能会将这些键存储在某种单例或缓存中,而不是每次都重新生成它们。
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.
To convert the private key to something more easily usable in java:
Then you can obtain an RSA private key directly by:
The public key is similar:
and to read it:
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.
无论您是否意识到,在这两种情况下您实际上都在存储字节。我想 @Brian M. Carr 的答案暗示了正确的答案,即以最自然的形式存储更高级别的对象。对于公钥,明显的选择是 PKCS#1 RSAPublicKey ASN.1 结构(DER 编码)或 X509 SubjectPublicKeyInfo ASN.1 结构(DER 编码)。后者是 Sun 提供商为您提供的,sun 类 X509EncodedKeySpec 支持。同样,PKCS8EncodedKeySpec 支持私钥格式。这两种格式都是标准,并且受到 openssl 等支持。 Sun 倾向于——倾向于:(——支持现有标准而不是定义自己的标准。
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.
如果您想定义一种存储密钥的格式,那么我会选择一种可消耗的格式,这样当您想要更改加密时(例如,当旧的加密变得很弱时),它就不会被破坏。
因此,我将存储编码为 base64 的字节以及描述格式的字符串(可能是“rsa”)。
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.