Java非对称加密:存储公钥/私钥的首选方法
此代码生成一对公钥/私钥:Java非对称加密:存储公钥/私钥的首选方法,java,encryption,encryption-asymmetric,Java,Encryption,Encryption Asymmetric,此代码生成一对公钥/私钥: KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); keyGen.initialize(1024); KeyPair keypair = keyGen.genKeyPair(); PrivateKey privateKey = keypair.getPrivate(); PublicKey publicKey = keypair.getPublic(); 我想知道的是,您通常如何存储公钥: 选
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);
第二个选项更容易实现,但我不知道它是否性能较差
有什么建议吗?如果您想定义一种存储密钥的格式,那么我会选择一种可替换的格式,这样当您想要更改加密时(例如,当旧的加密变弱时),它就不会中断
因此,我将存储编码为base64的字节,以及一个描述格式的字符串,可能是“rsa”。在我们的应用程序中,我们以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;
}
许多人存储密钥库。出于我们的目的,我们需要用几种不同的语言在多个应用程序之间共享相同的密钥,并且不希望复制磁盘上的文件
在任何一种情况下,性能都不应该是一个大问题,因为您可能会将这些密钥存储在某种单例或缓存中,而不是每次重新生成它们。无论您是否意识到,您实际上都在存储这两种情况下的字节。我想@Brian M.Carr answer中暗示了正确的答案,即以最自然的形式存储高级对象。对于公钥,最明显的选择是PKCS#1 RSAPublicKey ASN.1结构,DER编码,或X509 SubjectPublicKeyInfo ASN.1结构,DER编码。后者是Sun提供程序提供给您的,Sun类X509EncodedKeySpec支持后者。类似地,PKCS8EncodedKeySpec支持私钥格式。这两种格式都是标准格式,例如openssl支持。Sun倾向于——倾向于:(-支持现有标准,而不是定义自己的标准。DER本身并不是一种真正的格式,只是编码ASN.1对象的方式。对于那些希望直接从
id\u rsa.pub
(公钥)而不是id\u rsa
(私钥)获取public.DER
)的人来说。谢谢。非常有帮助。由于代码示例,我将@Brian M.Carr的答案标记为已接受。