我需要将未加密的 RSA 私钥替换为加密的私钥。 我用过
openssl -newKey rsa:2048 -new sha256 ...
生成pem。我看到生成的 pem 以“----BEGIN ENCRYPTED PRIVATE KEY-----”开头。 (过去只是说 -----BEGIN PRIVATE KEY-----")
当我尝试在现有 Java 代码中使用该 pem 文件时,它会抛出 InvalidKeySpecException
PrivateKey getPrivateKey(String path) throws Exception{
String algorithm = "RSA";
try{
String rsaPrivateKey = String.join("", Files.readAllLines(Paths.get(path)));
Files.readAllLines(Paths.get(path)));
// tried with and without the following replaceAll()
rsaPrivateKey = rsaPrivateKey.replaceAll("-----.*?.....");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.getDecoder(rsaPrivateKey)).decode(rsaPrivateKey);
KeyFactory kf = KeyFactor.getInstance(algorithm);
// next line throws the exception
PrivateKey privKey = kf.generatePrivate(keySpec);
return privKey;
}catch(InvalidKeySpecException e){
// this is getting thrown
}
}
我尝试添加新的EncryptedPrivateKeyInfo(rsaPrivateKey.getBytes())在decode()调用之前对其进行解密,但这引发了自己的异常。
初步来说你的问题有很多错误。
没有命令
openssl -newKey rsa:2048 -new sha256 ...
。您的意思是 openssl req -newkey rsa:2048 -new -sha256 ...
(req
必须存在,-newkey
必须小写,摘要必须以 -
开头)。
rsaPrivateKey.replaceAll("-----.*?.....")
无法编译。如果您将所需的第二个参数添加为 ""
,它会编译,但会做完全错误的事情并破坏您的数据。
Base64.getDecoder(rsaPrivateKey)
无法编译(假设 java.util.Base64
),如果编译了,则不是 new PKCS8EncodedKeySpec
的正确参数,而是可以通过对来自 未加密密钥文件的数据调用
.decode(body)
的结果来代替.
对您的文件类型进行 PEM 解码的正确方法是
String body = string_without_linebreaks.repaceAll ("-----(BEGIN|END) ENCRYPTED PRIVATE KEY-----","");
// or if you have some fetish about generality
// = string_without_linebreaks.replaceAll ("-----(BEGIN|END)[A-Z ]*-----","");
// followed by
Base64.getDecoder().decode(body)
但是您不能直接将其用作
PKCS8EncodedKeySpec
,因为它必须未加密。
javax.crypto.EncryptedPrivateKeyInfo
确实是读取加密 PKCS8 的纯 Java 方式 - 但对于使用 PBES2 的 PKCS8(如 OpenSSL 现在所做的那样),它仅在密码为 AES-128 或 AES-256 时才有效,而 openssl req
创建一个文件使用 PBES2 和三重 DES(又名 TDEA、DES3、3DES、DESede)加密。如果您使用例如重新加密您的文件
openssl pkey -in from_req.key -aes-128-cbc -out fixed.key
然后对于上面的 de-PEM 之后的 that 文件,您可以使用
解析结果EncryptedPrivateKeyInfo epki = new EncryptedPrivateKeyInfo( base64_decoded );
和在Java 19以上你可以简单地解密它
SecretKey kek = SecretKeyFactory.getInstance( epki.getAlgName() )
.generateSecret( new PBEKeySpec (your_password_as_chararray) );
PrivateKey pkey = KeyFactory.getInstance("RSA") .generatePrivate (epki.getKeySpec(kek));
但低于 19 你必须使用我在这里展示的hack或硬编码,例如
PBEwithHmacSHA256andAES_128
对于 SKF -- 或 SHA1,如果您使用 (d) OpenSSL 低于 1.1.0,现在已经有 8 年多了并且很少见。
或者,在所有版本的 Java 中以及对于所有(通常使用的)PKCS8 加密,您可以使用 BouncyCastle 直接读取 PEM,正如我在那里提到的,并且许多其他问题已经解决。