java 无法验证加密的私钥

yftpprvb  于 9个月前  发布在  Java
关注(0)|答案(2)|浏览(235)

我有以下的上下文:
我使用openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes来生成密钥和证书文件。
然后我使用openssl pkcs8 -in key.pem -out key-encrypted.pem -topk8加密我的私钥。
该代码适用于key.pemcert.pem,但在key-encrypted.pemcert.pem上存在问题。
当它转到此行以生成私钥时,它显示一个错误java.security.InvalidKeyException: IOException : DerValue.getBigIntegerInternal, not expected 48
我加载了我的证书文件,并创建了X509Certificate对象,如下所示:

byte[] certData = Files.readAllBytes(certPath);
InputStream st = new ByteArrayInputStream(certData)
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
certificate = (X509Certificate) certFactory.generateCertificate(st);

字符串
然后,我加载我的私钥文件如下:

List<String> keys = Files.readAllLines(keyPath);
//I have removed the first and last line of the key content:
//-----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- lines
String key = String.join("", keys);

//Parse it into PKCS8
byte[] decoded = Base64.decodeBase64(key);
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(decoded);

//Now I use kf to generate private key
PrivateKey pk = kf.generatePrivate(ks);

//Then I use the following code to verify
Signature s = Signature.getInstance("SHA256withRSA");
s.initSign(pk);

byte[] sign = s.sign();
s.initVerify(certificate.getPublicKey());
s.verify(sign);

qnakjoqk

qnakjoqk1#

较新的openssl-pkcs8版本默认使用PKCS#5 v2.0/PBES 2,更具体地说,使用PBKDF 2的 * aes 256 * 和 * hmacWithSHA 256 *(截至2016年的v1.1.0,s. comment)。
而另一个答案中建议的EncryptedPrivateKeyInfo在Java版本中支持PBES 2算法,截至19(针对19-21进行了测试)对于较旧的Java版本(如Java 8甚至Java 18),情况并非如此,并且会导致异常(这取决于Java版本,例如 IOException:ObjectIdentifier()--数据不是对象ID(tag = 48) 对于Java 8或 * NoSuch异常:PBES 2 SecretKeyFactory不可用 * 对于Java 18)。
对于EncryptedPrivateKeyInfo不支持PBES 2算法的Java版本,org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo是一个选项,它也支持PBES 2算法:

import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
...
Security.addProvider(new BouncyCastleProvider());
// Load DER encoded encrypted key
byte[] encryptedPkcs8Der = Base64.decodeBase64(key);
PKCS8EncryptedPrivateKeyInfo pkcs8EncryptedPrivateKeyInfo = new PKCS8EncryptedPrivateKeyInfo(encryptedPkcs8Der);
// Decrypt encrypted key
JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter();
InputDecryptorProvider inputDecryptorProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder().build("<your password>".toCharArray());
PrivateKeyInfo privateKeyInfo = pkcs8EncryptedPrivateKeyInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
// Import decrypted key
PrivateKey privateKey = jcaPEMKeyConverter.getPrivateKey(privateKeyInfo);
...
Signature s = Signature.getInstance("SHA256withRSA");
s.initSign(privateKey);
...

字符串

nc1teljy

nc1teljy2#

PKCS8EncodedKeySpec只支持 inner PKCS#8结构。该类不直接支持加密的PKCS#8。但是,有EncryptedPrivateKeyInfo支持。
你可以找到更多关于如何使用这个类的信息here。注意,现在它应该使用PBES2(即PBKDF2 +加密)来进行密钥推导,所以这应该是可以的。

相关问题