java 无法验证加密的私钥

yftpprvb  于 2024-01-05  发布在  Java
关注(0)|答案(2)|浏览(403)

我有以下的上下文:
我使用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对象,如下所示:

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

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

  1. List<String> keys = Files.readAllLines(keyPath);
  2. //I have removed the first and last line of the key content:
  3. //-----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- lines
  4. String key = String.join("", keys);
  5. //Parse it into PKCS8
  6. byte[] decoded = Base64.decodeBase64(key);
  7. KeyFactory kf = KeyFactory.getInstance("RSA");
  8. PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(decoded);
  9. //Now I use kf to generate private key
  10. PrivateKey pk = kf.generatePrivate(ks);
  11. //Then I use the following code to verify
  12. Signature s = Signature.getInstance("SHA256withRSA");
  13. s.initSign(pk);
  14. byte[] sign = s.sign();
  15. s.initVerify(certificate.getPublicKey());
  16. 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算法:

  1. import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
  2. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  3. import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
  4. import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
  5. import org.bouncycastle.operator.InputDecryptorProvider;
  6. import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
  7. ...
  8. Security.addProvider(new BouncyCastleProvider());
  9. // Load DER encoded encrypted key
  10. byte[] encryptedPkcs8Der = Base64.decodeBase64(key);
  11. PKCS8EncryptedPrivateKeyInfo pkcs8EncryptedPrivateKeyInfo = new PKCS8EncryptedPrivateKeyInfo(encryptedPkcs8Der);
  12. // Decrypt encrypted key
  13. JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter();
  14. InputDecryptorProvider inputDecryptorProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder().build("<your password>".toCharArray());
  15. PrivateKeyInfo privateKeyInfo = pkcs8EncryptedPrivateKeyInfo.decryptPrivateKeyInfo(inputDecryptorProvider);
  16. // Import decrypted key
  17. PrivateKey privateKey = jcaPEMKeyConverter.getPrivateKey(privateKeyInfo);
  18. ...
  19. Signature s = Signature.getInstance("SHA256withRSA");
  20. s.initSign(privateKey);
  21. ...

字符串

展开查看全部
nc1teljy

nc1teljy2#

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

相关问题