diff --git a/JenkinsfilePerformance b/JenkinsfilePerformance
index 2c7d40f2a..65963634c 100644
--- a/JenkinsfilePerformance
+++ b/JenkinsfilePerformance
@@ -353,6 +353,7 @@ pipeline {
'ibm.jceplus.jmh.MessageDigestInstanceBenchmark', \
'ibm.jceplus.jmh.MLDSABenchmark', \
'ibm.jceplus.jmh.MLKEMBenchmark', \
+ 'ibm.jceplus.jmh.PBEBenchmark', \
'ibm.jceplus.jmh.PBKDF2Benchmark', \
'ibm.jceplus.jmh.RandomBenchmark', \
'ibm.jceplus.jmh.RSAKeyGeneratorBenchmark', \
diff --git a/README.md b/README.md
index 9d707a673..f84eec894 100644
--- a/README.md
+++ b/README.md
@@ -268,170 +268,212 @@ take effect.
The following algorithms are registered by the OpenJCEPlus and OpenJCEPlusFIPS providers.
-| Algorithm Type | Algorithm Name | OpenJCEPlusFIPS | OpenJCEPlus | Notes |
-| --------------------------|----------------------------|-----------------|--------------|--------------|
-AlgorithmParameterGenerator | CCM |X |X | |
-AlgorithmParameterGenerator | DSA | |X | |
-AlgorithmParameterGenerator | DiffieHellman |X |X | |
-AlgorithmParameterGenerator | EC |X |X | |
-AlgorithmParameterGenerator | GCM |X |X | |
-AlgorithmParameters | AES |X |X | |
-AlgorithmParameters | CCM |X |X | |
-AlgorithmParameters | ChaCha20-Poly1305 | |X | |
-AlgorithmParameters | DESede | |X | |
-AlgorithmParameters | DSA |X |X | |
-AlgorithmParameters | DiffieHellman |X |X | |
-AlgorithmParameters | EC |X |X | |
-AlgorithmParameters | GCM |X |X | |
-AlgorithmParameters | OAEP |X |X | |
-AlgorithmParameters | RSAPSS |X |X | |
-Cipher | AES |X |X | |
-Cipher | AES/CCM/NoPadding |X |X | |
-Cipher | AES/GCM/NoPadding |X |X | |
-Cipher | ChaCha20 | |X | |
-Cipher | ChaCha20-Poly1305 | |X | |
-Cipher | DESede | |X | |
-Cipher | RSA |X |X | |
-KeyAgreement | DiffieHellman |X |X | |
-KeyAgreement | ECDH |X |X | |
-KeyAgreement | X25519 | |X | |
-KeyAgreement | X448 | |X | |
-KeyAgreement | XDH | |X | |
-KeyEncapsulationMechanism | ML-KEM-512 | |X |[ML-KEM](#ml-kem)|
-KeyEncapsulationMechanism | ML-KEM-768 | |X |[ML-KEM](#ml-kem)|
-KeyEncapsulationMechanism | ML-KEM-1024 | |X |[ML-KEM](#ml-kem)|
-KeyFactory | DSA |X |X | |
-KeyFactory | DiffieHellman |X |X | |
-KeyFactory | EC |X |X | |
-KeyFactory | Ed25519 | |X | |
-KeyFactory | Ed448 | |X | |
-KeyFactory | EdDSA | |X | |
-KeyFactory | ML-DSA-44 | |X |[ML-DSA](#ml-dsa)|
-KeyFactory | ML-DSA-65 | |X |[ML-DSA](#ml-dsa)|
-KeyFactory | ML-DSA-87 | |X |[ML-DSA](#ml-dsa)|
-KeyFactory | ML-KEM-512 | |X |[ML-KEM](#ml-kem)|
-KeyFactory | ML-KEM-768 | |X |[ML-KEM](#ml-kem)|
-KeyFactory | ML-KEM-1024 | |X |[ML-KEM](#ml-kem)|
-KeyFactory | RSA |X |X | |
-KeyFactory | RSAPSS |X |X | |
-KeyFactory | X25519 | |X | |
-KeyFactory | X448 | |X | |
-KeyFactory | XDH | |X | |
-KeyGenerator | AES |X |X | |
-KeyGenerator | ChaCha20 | |X | |
-KeyGenerator | DESede | |X | |
-KeyGenerator | HmacMD5 | |X | |
-KeyGenerator | HmacSHA1 | |X | |
-KeyGenerator | HmacSHA224 |X |X | |
-KeyGenerator | HmacSHA256 |X |X | |
-KeyGenerator | HmacSHA3-224 |X |X | |
-KeyGenerator | HmacSHA3-256 |X |X | |
-KeyGenerator | HmacSHA3-384 |X |X | |
-KeyGenerator | HmacSHA3-512 |X |X | |
-KeyGenerator | HmacSHA384 |X |X | |
-KeyGenerator | HmacSHA512 |X |X | |
-KeyGenerator | SunTls12KeyMaterial |X |X | |
-KeyGenerator | SunTls12MasterSecret |X |X | |
-KeyGenerator | SunTls12Prf |X |X | |
-KeyGenerator | SunTls12RsaPremasterSecret |X |X | |
-KeyGenerator | SunTlsKeyMaterial |X |X | |
-KeyGenerator | SunTlsMasterSecret |X |X | |
-KeyGenerator | SunTlsPrf |X |X | |
-KeyGenerator | SunTlsRsaPremasterSecret |X |X | |
-KeyGenerator | kda-hkdf-with-sha1 | |X | |
-KeyGenerator | kda-hkdf-with-sha224 |X |X | |
-KeyGenerator | kda-hkdf-with-sha256 |X |X | |
-KeyGenerator | kda-hkdf-with-sha384 |X |X | |
-KeyGenerator | kda-hkdf-with-sha512 |X |X | |
-KeyPairGenerator | DSA | |X | |
-KeyPairGenerator | DiffieHellman |X |X | |
-KeyPairGenerator | EC |X |X |[ECKeyPairGenerator incorrect keysize](#eckeypairgenerator-incorrect-keysize)|
-KeyPairGenerator | Ed25519 | |X | |
-KeyPairGenerator | Ed448 | |X | |
-KeyPairGenerator | EdDSA | |X | |
-KeyPairGenerator | ML-DSA-44 | |X | |
-KeyPairGenerator | ML-DSA-65 | |X | |
-KeyPairGenerator | ML-DSA-87 | |X | |
-KeyPairGenerator | ML-KEM-512 | |X |[ML-KEM](#ml-kem)|
-KeyPairGenerator | ML-KEM-768 | |X |[ML-KEM](#ml-kem)|
-KeyPairGenerator | ML-KEM-1024 | |X |[ML-KEM](#ml-kem)|
-KeyPairGenerator | RSA |X |X | |
-KeyPairGenerator | RSAPSS |X |X | |
-KeyPairGenerator | X25519 | |X | |
-KeyPairGenerator | X448 | |X | |
-KeyPairGenerator | XDH | |X | |
-KeyWrap | AES/KW/NoPadding |X |X |[AESKW](#AESKW)|
-KeyWrap | AES/KWP/NoPadding |X |X |[AESKW](#AESKW)|
-Mac | HmacMD5 | |X | |
-Mac | HmacSHA1 | |X | |
-Mac | HmacSHA224 |X |X | |
-Mac | HmacSHA256 |X |X | |
-Mac | HmacSHA3-224 |X |X | |
-Mac | HmacSHA3-256 |X |X | |
-Mac | HmacSHA3-384 |X |X | |
-Mac | HmacSHA3-512 |X |X | |
-Mac | HmacSHA384 |X |X | |
-Mac | HmacSHA512 |X |X | |
-MessageDigest | MD5 |X |X | |
-MessageDigest | SHA-1 |X |X | |
-MessageDigest | SHA-224 |X |X | |
-MessageDigest | SHA-256 |X |X | |
-MessageDigest | SHA-384 |X |X | |
-MessageDigest | SHA-512 |X |X | |
-MessageDigest | SHA-512/224 |X |X | |
-MessageDigest | SHA-512/256 |X |X | |
-MessageDigest | SHA3-224 |X |X | |
-MessageDigest | SHA3-256 |X |X | |
-MessageDigest | SHA3-384 |X |X | |
-MessageDigest | SHA3-512 |X |X | |
-SecretKeyFactory | AES |X |X | |
-SecretKeyFactory | ChaCha20 | |X | |
-SecretKeyFactory | DESede | |X | |
-SecretKeyFactory | PBKDF2WithHmacSHA1 | |X | |
-SecretKeyFactory | PBKDF2WithHmacSHA224 |X |X | |
-SecretKeyFactory | PBKDF2WithHmacSHA256 |X |X | |
-SecretKeyFactory | PBKDF2WithHmacSHA384 |X |X | |
-SecretKeyFactory | PBKDF2WithHmacSHA512 |X |X | |
-SecretKeyFactory | PBKDF2WithHmacSHA512/224 | |X | |
-SecretKeyFactory | PBKDF2WithHmacSHA512/256 | |X | |
-SecureRandom | SHA256DRBG |X |X | |
-SecureRandom | SHA512DRBG |X |X | |
-Signature | Ed25519 | |X | |
-Signature | Ed448 | |X | |
-Signature | EdDSA |X |X | |
-Signature | ML-DSA-44 | |X |[ML-DSA](#ml-dsa)|
-Signature | ML-DSA-65 | |X |[ML-DSA](#ml-dsa)|
-Signature | ML-DSA-87 | |X |[ML-DSA](#ml-dsa)|
-Signature | NONEwithDSA |X |X | |
-Signature | NONEwithECDSA |X |X | |
-Signature | NONEwithRSA |X |X | |
-Signature | RSAPSS |X |X | |
-Signature | RSAforSSL |X |X | |
-Signature | SHA1withDSA | |X | |
-Signature | SHA1withECDSA | |X | |
-Signature | SHA1withRSA |X |X | |
-Signature | SHA224withDSA |X |X | |
-Signature | SHA224withECDSA |X |X | |
-Signature | SHA224withRSA |X |X | |
-Signature | SHA256withDSA |X |X | |
-Signature | SHA256withECDSA |X |X | |
-Signature | SHA256withRSA |X |X | |
-Signature | SHA3-224withDSA | |X | |
-Signature | SHA3-224withECDSA | |X | |
-Signature | SHA3-224withRSA | |X | |
-Signature | SHA3-256withDSA | |X | |
-Signature | SHA3-256withECDSA | |X | |
-Signature | SHA3-256withRSA | |X | |
-Signature | SHA3-384withDSA | |X | |
-Signature | SHA3-384withECDSA | |X | |
-Signature | SHA3-384withRSA | |X | |
-Signature | SHA3-512withDSA | |X | |
-Signature | SHA3-512withECDSA | |X | |
-Signature | SHA3-512withRSA | |X | |
-Signature | SHA384withECDSA |X |X | |
-Signature | SHA384withRSA |X |X | |
-Signature | SHA512withECDSA |X |X | |
-Signature | SHA512withRSA |X |X | |
+| Algorithm Type | Algorithm Name | OpenJCEPlusFIPS | OpenJCEPlus | Notes |
+| --------------------------|---------------------------------|-----------------|--------------|--------------|
+AlgorithmParameterGenerator | CCM |X |X | |
+AlgorithmParameterGenerator | DSA | |X | |
+AlgorithmParameterGenerator | DiffieHellman |X |X | |
+AlgorithmParameterGenerator | EC |X |X | |
+AlgorithmParameterGenerator | GCM |X |X | |
+AlgorithmParameters | AES |X |X | |
+AlgorithmParameters | CCM |X |X | |
+AlgorithmParameters | ChaCha20-Poly1305 | |X | |
+AlgorithmParameters | DESede | |X | |
+AlgorithmParameters | DSA |X |X | |
+AlgorithmParameters | DiffieHellman |X |X | |
+AlgorithmParameters | EC |X |X | |
+AlgorithmParameters | GCM |X |X | |
+AlgorithmParameters | OAEP |X |X | |
+AlgorithmParameters | RSAPSS |X |X | |
+AlgorithmParameters | PBEWithHmacSHA1AndAES_128 | |X | |
+AlgorithmParameters | PBEWithHmacSHA1AndAES_256 | |X | |
+AlgorithmParameters | PBEWithHmacSHA224AndAES_128 | |X | |
+AlgorithmParameters | PBEWithHmacSHA224AndAES_256 | |X | |
+AlgorithmParameters | PBEWithHmacSHA256AndAES_128 | |X | |
+AlgorithmParameters | PBEWithHmacSHA256AndAES_256 | |X | |
+AlgorithmParameters | PBEWithHmacSHA384AndAES_128 | |X | |
+AlgorithmParameters | PBEWithHmacSHA384AndAES_256 | |X | |
+AlgorithmParameters | PBEWithHmacSHA512AndAES_128 | |X | |
+AlgorithmParameters | PBEWithHmacSHA512AndAES_256 | |X | |
+AlgorithmParameters | PBEWithHmacSHA512/224AndAES_128 | |X | |
+AlgorithmParameters | PBEWithHmacSHA512/224AndAES_256 | |X | |
+AlgorithmParameters | PBEWithHmacSHA512/256AndAES_128 | |X | |
+AlgorithmParameters | PBEWithHmacSHA512/256AndAES_256 | |X | |
+Cipher | AES |X |X | |
+Cipher | AES/CCM/NoPadding |X |X | |
+Cipher | AES/GCM/NoPadding |X |X | |
+Cipher | ChaCha20 | |X | |
+Cipher | ChaCha20-Poly1305 | |X | |
+Cipher | DESede | |X | |
+Cipher | RSA |X |X | |
+Cipher | PBEWithHmacSHA1AndAES_128 | |X | |
+Cipher | PBEWithHmacSHA1AndAES_256 | |X | |
+Cipher | PBEWithHmacSHA224AndAES_128 | |X | |
+Cipher | PBEWithHmacSHA224AndAES_256 | |X | |
+Cipher | PBEWithHmacSHA256AndAES_128 | |X | |
+Cipher | PBEWithHmacSHA256AndAES_256 | |X | |
+Cipher | PBEWithHmacSHA384AndAES_128 | |X | |
+Cipher | PBEWithHmacSHA384AndAES_256 | |X | |
+Cipher | PBEWithHmacSHA512AndAES_128 | |X | |
+Cipher | PBEWithHmacSHA512AndAES_256 | |X | |
+Cipher | PBEWithHmacSHA512/224AndAES_128 | |X | |
+Cipher | PBEWithHmacSHA512/224AndAES_256 | |X | |
+Cipher | PBEWithHmacSHA512/256AndAES_128 | |X | |
+Cipher | PBEWithHmacSHA512/256AndAES_256 | |X | |
+KeyAgreement | DiffieHellman |X |X | |
+KeyAgreement | ECDH |X |X | |
+KeyAgreement | X25519 | |X | |
+KeyAgreement | X448 | |X | |
+KeyAgreement | XDH | |X | |
+KeyEncapsulationMechanism | ML-KEM-512 | |X |[ML-KEM](#ml-kem)|
+KeyEncapsulationMechanism | ML-KEM-768 | |X |[ML-KEM](#ml-kem)|
+KeyEncapsulationMechanism | ML-KEM-1024 | |X |[ML-KEM](#ml-kem)|
+KeyFactory | DSA |X |X | |
+KeyFactory | DiffieHellman |X |X | |
+KeyFactory | EC |X |X | |
+KeyFactory | Ed25519 | |X | |
+KeyFactory | Ed448 | |X | |
+KeyFactory | EdDSA | |X | |
+KeyFactory | ML-DSA-44 | |X |[ML-DSA](#ml-dsa)|
+KeyFactory | ML-DSA-65 | |X |[ML-DSA](#ml-dsa)|
+KeyFactory | ML-DSA-87 | |X |[ML-DSA](#ml-dsa)|
+KeyFactory | ML-KEM-512 | |X |[ML-KEM](#ml-kem)|
+KeyFactory | ML-KEM-768 | |X |[ML-KEM](#ml-kem)|
+KeyFactory | ML-KEM-1024 | |X |[ML-KEM](#ml-kem)|
+KeyFactory | RSA |X |X | |
+KeyFactory | RSAPSS |X |X | |
+KeyFactory | X25519 | |X | |
+KeyFactory | X448 | |X | |
+KeyFactory | XDH | |X | |
+KeyGenerator | AES |X |X | |
+KeyGenerator | ChaCha20 | |X | |
+KeyGenerator | DESede | |X | |
+KeyGenerator | HmacMD5 | |X | |
+KeyGenerator | HmacSHA1 | |X | |
+KeyGenerator | HmacSHA224 |X |X | |
+KeyGenerator | HmacSHA256 |X |X | |
+KeyGenerator | HmacSHA3-224 |X |X | |
+KeyGenerator | HmacSHA3-256 |X |X | |
+KeyGenerator | HmacSHA3-384 |X |X | |
+KeyGenerator | HmacSHA3-512 |X |X | |
+KeyGenerator | HmacSHA384 |X |X | |
+KeyGenerator | HmacSHA512 |X |X | |
+KeyGenerator | SunTls12KeyMaterial |X |X | |
+KeyGenerator | SunTls12MasterSecret |X |X | |
+KeyGenerator | SunTls12Prf |X |X | |
+KeyGenerator | SunTls12RsaPremasterSecret |X |X | |
+KeyGenerator | SunTlsKeyMaterial |X |X | |
+KeyGenerator | SunTlsMasterSecret |X |X | |
+KeyGenerator | SunTlsPrf |X |X | |
+KeyGenerator | SunTlsRsaPremasterSecret |X |X | |
+KeyGenerator | kda-hkdf-with-sha1 | |X | |
+KeyGenerator | kda-hkdf-with-sha224 |X |X | |
+KeyGenerator | kda-hkdf-with-sha256 |X |X | |
+KeyGenerator | kda-hkdf-with-sha384 |X |X | |
+KeyGenerator | kda-hkdf-with-sha512 |X |X | |
+KeyPairGenerator | DSA | |X | |
+KeyPairGenerator | DiffieHellman |X |X | |
+KeyPairGenerator | EC |X |X |[ECKeyPairGenerator incorrect keysize](#eckeypairgenerator-incorrect-keysize)|
+KeyPairGenerator | Ed25519 | |X | |
+KeyPairGenerator | Ed448 | |X | |
+KeyPairGenerator | EdDSA | |X | |
+KeyPairGenerator | ML-DSA-44 | |X | |
+KeyPairGenerator | ML-DSA-65 | |X | |
+KeyPairGenerator | ML-DSA-87 | |X | |
+KeyPairGenerator | ML-KEM-512 | |X |[ML-KEM](#ml-kem)|
+KeyPairGenerator | ML-KEM-768 | |X |[ML-KEM](#ml-kem)|
+KeyPairGenerator | ML-KEM-1024 | |X |[ML-KEM](#ml-kem)|
+KeyPairGenerator | RSA |X |X | |
+KeyPairGenerator | RSAPSS |X |X | |
+KeyPairGenerator | X25519 | |X | |
+KeyPairGenerator | X448 | |X | |
+KeyPairGenerator | XDH | |X | |
+KeyWrap | AES/KW/NoPadding |X |X |[AESKW](#AESKW)|
+KeyWrap | AES/KWP/NoPadding |X |X |[AESKW](#AESKW)|
+Mac | HmacMD5 | |X | |
+Mac | HmacSHA1 | |X | |
+Mac | HmacSHA224 |X |X | |
+Mac | HmacSHA256 |X |X | |
+Mac | HmacSHA3-224 |X |X | |
+Mac | HmacSHA3-256 |X |X | |
+Mac | HmacSHA3-384 |X |X | |
+Mac | HmacSHA3-512 |X |X | |
+Mac | HmacSHA384 |X |X | |
+Mac | HmacSHA512 |X |X | |
+MessageDigest | MD5 |X |X | |
+MessageDigest | SHA-1 |X |X | |
+MessageDigest | SHA-224 |X |X | |
+MessageDigest | SHA-256 |X |X | |
+MessageDigest | SHA-384 |X |X | |
+MessageDigest | SHA-512 |X |X | |
+MessageDigest | SHA-512/224 |X |X | |
+MessageDigest | SHA-512/256 |X |X | |
+MessageDigest | SHA3-224 |X |X | |
+MessageDigest | SHA3-256 |X |X | |
+MessageDigest | SHA3-384 |X |X | |
+MessageDigest | SHA3-512 |X |X | |
+SecretKeyFactory | AES |X |X | |
+SecretKeyFactory | ChaCha20 | |X | |
+SecretKeyFactory | DESede | |X | |
+SecretKeyFactory | PBKDF2WithHmacSHA1 | |X | |
+SecretKeyFactory | PBKDF2WithHmacSHA224 |X |X | |
+SecretKeyFactory | PBKDF2WithHmacSHA256 |X |X | |
+SecretKeyFactory | PBKDF2WithHmacSHA384 |X |X | |
+SecretKeyFactory | PBKDF2WithHmacSHA512 |X |X | |
+SecretKeyFactory | PBKDF2WithHmacSHA512/224 | |X | |
+SecretKeyFactory | PBKDF2WithHmacSHA512/256 | |X | |
+SecretKeyFactory | PBEWithHmacSHA1AndAES_128 | |X | |
+SecretKeyFactory | PBEWithHmacSHA1AndAES_256 | |X | |
+SecretKeyFactory | PBEWithHmacSHA224AndAES_128 | |X | |
+SecretKeyFactory | PBEWithHmacSHA224AndAES_256 | |X | |
+SecretKeyFactory | PBEWithHmacSHA256AndAES_128 | |X | |
+SecretKeyFactory | PBEWithHmacSHA256AndAES_256 | |X | |
+SecretKeyFactory | PBEWithHmacSHA384AndAES_128 | |X | |
+SecretKeyFactory | PBEWithHmacSHA384AndAES_256 | |X | |
+SecretKeyFactory | PBEWithHmacSHA512AndAES_128 | |X | |
+SecretKeyFactory | PBEWithHmacSHA512AndAES_256 | |X | |
+SecretKeyFactory | PBEWithHmacSHA512/224AndAES_128 | |X | |
+SecretKeyFactory | PBEWithHmacSHA512/224AndAES_256 | |X | |
+SecretKeyFactory | PBEWithHmacSHA512/256AndAES_128 | |X | |
+SecretKeyFactory | PBEWithHmacSHA512/256AndAES_256 | |X | |
+SecureRandom | SHA256DRBG |X |X | |
+SecureRandom | SHA512DRBG |X |X | |
+Signature | Ed25519 | |X | |
+Signature | Ed448 | |X | |
+Signature | EdDSA |X |X | |
+Signature | ML-DSA-44 | |X |[ML-DSA](#ml-dsa)|
+Signature | ML-DSA-65 | |X |[ML-DSA](#ml-dsa)|
+Signature | ML-DSA-87 | |X |[ML-DSA](#ml-dsa)|
+Signature | NONEwithDSA |X |X | |
+Signature | NONEwithECDSA |X |X | |
+Signature | NONEwithRSA |X |X | |
+Signature | RSAPSS |X |X | |
+Signature | RSAforSSL |X |X | |
+Signature | SHA1withDSA | |X | |
+Signature | SHA1withECDSA | |X | |
+Signature | SHA1withRSA |X |X | |
+Signature | SHA224withDSA |X |X | |
+Signature | SHA224withECDSA |X |X | |
+Signature | SHA224withRSA |X |X | |
+Signature | SHA256withDSA |X |X | |
+Signature | SHA256withECDSA |X |X | |
+Signature | SHA256withRSA |X |X | |
+Signature | SHA3-224withDSA | |X | |
+Signature | SHA3-224withECDSA | |X | |
+Signature | SHA3-224withRSA | |X | |
+Signature | SHA3-256withDSA | |X | |
+Signature | SHA3-256withECDSA | |X | |
+Signature | SHA3-256withRSA | |X | |
+Signature | SHA3-384withDSA | |X | |
+Signature | SHA3-384withECDSA | |X | |
+Signature | SHA3-384withRSA | |X | |
+Signature | SHA3-512withDSA | |X | |
+Signature | SHA3-512withECDSA | |X | |
+Signature | SHA3-512withRSA | |X | |
+Signature | SHA384withECDSA |X |X | |
+Signature | SHA384withRSA |X |X | |
+Signature | SHA512withECDSA |X |X | |
+Signature | SHA512withRSA |X |X | |
## Algorithm Notes
diff --git a/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java b/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java
index 150c569e6..780b374a7 100644
--- a/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java
+++ b/src/main/java/com/ibm/crypto/plus/provider/OpenJCEPlus.java
@@ -31,8 +31,16 @@ public final class OpenJCEPlus extends OpenJCEPlusProvider {
private static final String info = "OpenJCEPlus Provider implements the following:\n"
+ "Algorithm parameter : AES, ChaCha20, ChaCha20-Poly1305, DESede, DiffieHellman, DSA, EC, XEC, GCM, CCM, OAEP, RSAPSS\n"
+ + " PBEWithHmacSHA1AndAES_128, PBEWithHmacSHA1AndAES_256, PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA224AndAES_256\n"
+ + " PBEWithHmacSHA256AndAES_128, PBEWithHmacSHA256AndAES_256, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA384AndAES_256\n"
+ + " PBEWithHmacSHA512AndAES_128, PBEWithHmacSHA512AndAES_256, PBEWithHmacSHA512/224AndAES_128, PBEWithHmacSHA512/224AndAES_256\n"
+ + " PBEWithHmacSHA512/256AndAES_128, PBEWithHmacSHA512/256AndAES_256\n"
+ "Algorithm parameter generator : DiffieHellman, DSA, EC, XEC, GCM, CCM\n"
+ "Cipher algorithms : AES, ChaCha20, ChaCha20-Poly1305, DESede, RSA\n"
+ + " PBEWithHmacSHA1AndAES_128, PBEWithHmacSHA1AndAES_256, PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA224AndAES_256\n"
+ + " PBEWithHmacSHA256AndAES_128, PBEWithHmacSHA256AndAES_256, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA384AndAES_256\n"
+ + " PBEWithHmacSHA512AndAES_128, PBEWithHmacSHA512AndAES_256, PBEWithHmacSHA512/224AndAES_128, PBEWithHmacSHA512/224AndAES_256\n"
+ + " PBEWithHmacSHA512/256AndAES_128, PBEWithHmacSHA512/256AndAES_256\n"
+ "Key agreement algorithms : DiffieHellman, ECDH, XDH\n"
+ "Key Encapsulation Mechanisms : ML-KEM-512, ML-KEM-768, ML-KEM-1024\n"
+ "Key factory : DiffieHellman, DSA, EC, XEC, RSA, RSAPSS, ML-KEM-512, ML-KEM-768, ML-KEM-1024\n"
@@ -49,6 +57,10 @@ public final class OpenJCEPlus extends OpenJCEPlusProvider {
+ "Message digest : MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256, SHA3-224, SHA3-256, SHA3-384, SHA3-512\n"
+ "Secret key factory : AES, ChaCha20, DESede, PBKDF2WithHmacSHA1, PBKDF2WithHmacSHA224, PBKDF2WithHmacSHA256, PBKDF2WithHmacSHA384, PBKDF2WithHmacSHA512\n"
+ " PBKDF2WithHmacSHA512/224, PBKDF2WithHmacSHA512/256\n"
+ + " PBEWithHmacSHA1AndAES_128, PBEWithHmacSHA1AndAES_256, PBEWithHmacSHA224AndAES_128, PBEWithHmacSHA224AndAES_256\n"
+ + " PBEWithHmacSHA256AndAES_128, PBEWithHmacSHA256AndAES_256, PBEWithHmacSHA384AndAES_128, PBEWithHmacSHA384AndAES_256\n"
+ + " PBEWithHmacSHA512AndAES_128, PBEWithHmacSHA512AndAES_256, PBEWithHmacSHA512/224AndAES_128, PBEWithHmacSHA512/224AndAES_256\n"
+ + " PBEWithHmacSHA512/256AndAES_128, PBEWithHmacSHA512/256AndAES_256\n"
+ "Secure random : HASHDRBG, SHA256DRBG, SHA512DRBG\n"
+ "Signature algorithms : NONEwithDSA, SHA1withDSA, SHA224withDSA, SHA256withDSA,\n"
+ " SHA3-224withDSA, SHA3-256withDSA, SHA3-384withDSA, SHA3-512withDSA,\n"
@@ -147,7 +159,63 @@ private void registerAlgorithms(Provider jce) {
aliases = null;
putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "OAEP",
"com.ibm.crypto.plus.provider.OAEPParameters", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA1AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA1AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA1AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA1AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA224AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA224AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA224AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA224AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA256AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA256AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA256AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA256AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA384AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA384AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA384AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA384AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA512AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA512AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA512AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA512AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA512/224AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA512_224AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA512/224AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA512_224AndAES_256", aliases));
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA512/256AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA512_256AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "AlgorithmParameters", "PBEWithHmacSHA512/256AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Parameters$HmacSHA512_256AndAES_256", aliases));
+
/*aliases = null;
putService(new OpenJCEPlusService(jce,
"AlgorithmParameters",
@@ -262,6 +330,62 @@ private void registerAlgorithms(Provider jce) {
putService(new OpenJCEPlusService(jce, "Cipher", "ChaCha20-Poly1305",
"com.ibm.crypto.plus.provider.ChaCha20Poly1305Cipher", aliases));
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA1AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA1AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA1AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA1AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA224AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA224AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA224AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA224AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA256AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA256AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA256AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA256AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA384AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA384AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA384AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA384AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA512AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA512AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA512AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA512AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA512/224AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA512_224AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA512/224AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA512_224AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA512/256AndAES_128",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA512_256AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "Cipher", "PBEWithHmacSHA512/256AndAES_256",
+ "com.ibm.crypto.plus.provider.PBES2Core$HmacSHA512_256AndAES_256", aliases));
+
/* =======================================================================
* Key agreement
* =======================================================================
@@ -790,6 +914,62 @@ private void registerAlgorithms(Provider jce) {
putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "ChaCha20",
"com.ibm.crypto.plus.provider.ChaCha20KeyFactory", aliases));
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA1AndAES_128",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA1AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA1AndAES_256",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA1AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA224AndAES_128",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA224AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA224AndAES_256",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA224AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA256AndAES_128",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA256AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA256AndAES_256",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA256AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA384AndAES_128",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA384AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA384AndAES_256",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA384AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA512AndAES_128",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA512AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA512AndAES_256",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA512AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA512/224AndAES_128",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA512_224AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA512/224AndAES_256",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA512_224AndAES_256", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA512/256AndAES_128",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA512_256AndAES_128", aliases));
+
+ aliases = null;
+ putService(new OpenJCEPlusService(jce, "SecretKeyFactory", "PBEWithHmacSHA512/256AndAES_256",
+ "com.ibm.crypto.plus.provider.PBEKeyFactory$PBEWithHmacSHA512_256AndAES_256", aliases));
+
/* =======================================================================
* SecureRandom
* =======================================================================
diff --git a/src/main/java/com/ibm/crypto/plus/provider/PBEKey.java b/src/main/java/com/ibm/crypto/plus/provider/PBEKey.java
new file mode 100644
index 000000000..6c54c14e9
--- /dev/null
+++ b/src/main/java/com/ibm/crypto/plus/provider/PBEKey.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright IBM Corp. 2025
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms provided by IBM in the LICENSE file that accompanied
+ * this code, including the "Classpath" Exception described therein.
+ */
+
+package com.ibm.crypto.plus.provider;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.lang.ref.Reference;
+import java.security.MessageDigest;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+import java.util.Locale;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+import sun.security.util.PBEUtil;
+
+final class PBEKey implements SecretKey {
+
+ @java.io.Serial
+ private static final long serialVersionUID = 9223372036854775807L;
+
+ private byte[] key;
+
+ private final String type;
+
+ private boolean destroyed = false;
+
+ private OpenJCEPlusProvider provider = null;
+
+ /**
+ * Creates a PBE key from a given PBE key specification.
+ *
+ * @param keytype the given PBE key specification
+ */
+ PBEKey(OpenJCEPlusProvider provider, PBEKeySpec keySpec, String keytype) throws InvalidKeySpecException {
+ char[] passwd = keySpec.getPassword();
+
+ if (passwd == null || passwd.length == 0) {
+ // Should allow an empty password.
+ passwd = new char[0];
+ }
+
+ for (char c : passwd) {
+ if (Character.isISOControl(c))
+ throw new InvalidKeySpecException("Invalid Password.");
+ }
+
+ this.key = PBEUtil.encodePassword(passwd);
+ Arrays.fill(passwd, '\0');
+ type = keytype;
+ this.provider = provider;
+ }
+
+ public byte[] getEncoded() {
+ try {
+ return key.clone();
+ } finally {
+ // prevent this from being cleaned for the above block
+ Reference.reachabilityFence(this);
+ }
+ }
+
+ public String getAlgorithm() {
+ return type;
+ }
+
+ public String getFormat() {
+ return "RAW";
+ }
+
+ @Override
+ public int hashCode() {
+ try {
+ return Arrays.hashCode(this.key)
+ ^ getAlgorithm().toLowerCase(Locale.ENGLISH).hashCode();
+ } finally {
+ // prevent this from being cleaned for the above block
+ Reference.reachabilityFence(this);
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ try {
+ if (obj == this)
+ return true;
+
+ if (!(obj instanceof SecretKey that))
+ return false;
+
+ if (isDestroyed() || that.isDestroyed()) {
+ return false;
+ }
+
+ if (!(that.getAlgorithm().equalsIgnoreCase(type)))
+ return false;
+
+ byte[] thatEncoded = that.getEncoded();
+ boolean ret = MessageDigest.isEqual(this.key, thatEncoded);
+ Arrays.fill(thatEncoded, (byte) 0x00);
+ return ret;
+ } finally {
+ // prevent this from being cleaned for the above block
+ Reference.reachabilityFence(this);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ if (this.key != null) {
+ Arrays.fill(this.key, (byte) 0x00);
+ destroyed = true;
+ }
+ }
+
+ @Override
+ public boolean isDestroyed() {
+ return destroyed;
+ }
+
+ /**
+ * Restores the state of this object from the stream.
+ *
+ * @param s the {@code ObjectInputStream} from which data is read
+ * @throws IOException if an I/O error occurs
+ * @throws ClassNotFoundException if a serialized class cannot be loaded
+ */
+ @java.io.Serial
+ private void readObject(java.io.ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ if (key == null) {
+ throw new InvalidObjectException(
+ "PBEKey couldn't be deserialized");
+ }
+ byte[] temp = key;
+ key = temp.clone();
+ Arrays.fill(temp, (byte) 0x00);
+
+ // Accept "\0" to signify "zero-length password with no terminator".
+ if (!(key.length == 1 && key[0] == 0)) {
+ for (int i = 0; i < key.length; i++) {
+ if ((key[i] < '\u0020') || (key[i] > '\u007E')) {
+ throw new InvalidObjectException(
+ "PBEKey had non-ASCII chars");
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Replace the PBE key to be serialized.
+ *
+ * @return the standard KeyRep object to be serialized
+ *
+ * @throws java.io.ObjectStreamException if a new object representing
+ * this PBE key could not be created
+ */
+ @java.io.Serial
+ private Object writeReplace() throws java.io.ObjectStreamException {
+ try {
+ return new JCEPlusKeyRep(JCEPlusKeyRep.Type.SECRET,
+ getAlgorithm(), getFormat(), getEncoded(), provider.getName());
+ } finally {
+ // prevent this from being cleaned for the above block
+ Reference.reachabilityFence(this);
+ }
+ }
+
+ protected void finalize() throws Throwable {
+ try {
+ destroy();
+ } finally {
+ super.finalize();
+ }
+ }
+}
diff --git a/src/main/java/com/ibm/crypto/plus/provider/PBEKeyFactory.java b/src/main/java/com/ibm/crypto/plus/provider/PBEKeyFactory.java
new file mode 100644
index 000000000..6f05fe720
--- /dev/null
+++ b/src/main/java/com/ibm/crypto/plus/provider/PBEKeyFactory.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright IBM Corp. 2025
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms provided by IBM in the LICENSE file that accompanied
+ * this code, including the "Classpath" Exception described therein.
+ */
+
+package com.ibm.crypto.plus.provider;
+
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.PBEKeySpec;
+
+abstract class PBEKeyFactory extends SecretKeyFactorySpi {
+
+ private final String type;
+ private OpenJCEPlusProvider provider = null;
+
+ private PBEKeyFactory(String keytype, OpenJCEPlusProvider provider) {
+ type = keytype;
+ this.provider = provider;
+ }
+
+ public static final class PBEWithHmacSHA1AndAES_128 extends PBEKeyFactory {
+ public PBEWithHmacSHA1AndAES_128(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA1AndAES_128", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA224AndAES_128
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA224AndAES_128(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA224AndAES_128", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA256AndAES_128
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA256AndAES_128(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA256AndAES_128", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA384AndAES_128
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA384AndAES_128(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA384AndAES_128", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA512AndAES_128
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA512AndAES_128(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA512AndAES_128", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA512_224AndAES_128
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA512_224AndAES_128(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA512/224AndAES_128", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA512_256AndAES_128
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA512_256AndAES_128(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA512/256AndAES_128", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA1AndAES_256 extends PBEKeyFactory {
+ public PBEWithHmacSHA1AndAES_256(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA1AndAES_256", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA224AndAES_256
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA224AndAES_256(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA224AndAES_256", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA256AndAES_256
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA256AndAES_256(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA256AndAES_256", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA384AndAES_256
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA384AndAES_256(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA384AndAES_256", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA512AndAES_256
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA512AndAES_256(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA512AndAES_256", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA512_224AndAES_256
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA512_224AndAES_256(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA512/224AndAES_256", provider);
+ }
+ }
+
+ public static final class PBEWithHmacSHA512_256AndAES_256
+ extends PBEKeyFactory {
+ public PBEWithHmacSHA512_256AndAES_256(OpenJCEPlusProvider provider) {
+ super("PBEWithHmacSHA512/256AndAES_256", provider);
+ }
+ }
+
+ /**
+ * Generates a SecretKey
object from the provided key
+ * specification (key material).
+ *
+ * @param keySpec the specification (key material) of the secret key
+ *
+ * @return the secret key
+ *
+ * @exception InvalidKeySpecException if the given key specification
+ * is inappropriate for this key factory to produce a public key.
+ */
+ protected SecretKey engineGenerateSecret(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (!(keySpec instanceof PBEKeySpec)) {
+ throw new InvalidKeySpecException("Invalid key spec");
+ }
+ return new PBEKey(provider, (PBEKeySpec) keySpec, type);
+ }
+
+ /**
+ * Returns a specification (key material) of the given key
+ * in the requested format.
+ *
+ * @param key the key
+ *
+ * @param keySpecCl the requested format in which the key material shall be
+ * returned
+ *
+ * @return the underlying key specification (key material) in the
+ * requested format
+ *
+ * @exception InvalidKeySpecException if the requested key specification is
+ * inappropriate for the given key, or the given key cannot be processed
+ * (e.g., the given key has an unrecognized algorithm or format).
+ */
+ protected KeySpec engineGetKeySpec(SecretKey key, Class> keySpecCl)
+ throws InvalidKeySpecException {
+ if ((key != null) && (key.getFormat() != null) && (key.getFormat().equalsIgnoreCase("RAW")) && (key.getEncoded() != null)) {
+ // Check if requested key spec is amongst the valid ones
+ if ((keySpecCl != null) && keySpecCl.isAssignableFrom(PBEKeySpec.class)) {
+ byte[] passwdBytes = key.getEncoded();
+ char[] passwdChars = new char[passwdBytes.length];
+ for (int i=0; i < passwdChars.length; i++)
+ passwdChars[i] = (char) (passwdBytes[i] & 0x7f);
+ PBEKeySpec ret = new PBEKeySpec(passwdChars);
+ // password char[] was cloned in PBEKeySpec constructor,
+ // so we can zero it out here
+ java.util.Arrays.fill(passwdChars, '\0');
+ java.util.Arrays.fill(passwdBytes, (byte) 0x00);
+ return ret;
+ } else {
+ throw new InvalidKeySpecException("Invalid key spec");
+ }
+ } else {
+ throw new InvalidKeySpecException("Invalid key "
+ + "format/algorithm");
+ }
+ }
+
+ /**
+ * Translates a SecretKey
object, whose provider may be
+ * unknown or potentially untrusted, into a corresponding
+ * SecretKey
object of this key factory.
+ *
+ * @param key the key whose provider is unknown or untrusted
+ *
+ * @return the translated key
+ *
+ * @exception InvalidKeyException if the given key cannot be processed by
+ * this key factory.
+ */
+ protected SecretKey engineTranslateKey(SecretKey key)
+ throws InvalidKeyException
+ {
+ try {
+ if ((key != null) && (key.getFormat() != null) && (key.getFormat().equalsIgnoreCase("RAW"))) {
+
+ if (key instanceof com.ibm.crypto.plus.provider.PBEKey) {
+ return key;
+ }
+
+ // Convert key to spec
+ PBEKeySpec pbeKeySpec = (PBEKeySpec) engineGetKeySpec
+ (key, PBEKeySpec.class);
+
+ try {
+ return engineGenerateSecret(pbeKeySpec);
+ } finally {
+ pbeKeySpec.clearPassword();
+ }
+ } else {
+ throw new InvalidKeyException("Invalid key format/algorithm");
+ }
+
+ } catch (InvalidKeySpecException ikse) {
+ throw new InvalidKeyException("Cannot translate key: "
+ + ikse.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/com/ibm/crypto/plus/provider/PBES2Core.java b/src/main/java/com/ibm/crypto/plus/provider/PBES2Core.java
new file mode 100644
index 000000000..88dafdde3
--- /dev/null
+++ b/src/main/java/com/ibm/crypto/plus/provider/PBES2Core.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright IBM Corp. 2025
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms provided by IBM in the LICENSE file that accompanied
+ * this code, including the "Classpath" Exception described therein.
+ */
+
+package com.ibm.crypto.plus.provider;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
+import javax.crypto.BadPaddingException;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+import sun.security.util.PBEUtil;
+
+abstract class PBES2Core extends CipherSpi {
+ private final AESCipher cipher;
+ private final int keyLength; // in bits
+ private final int blkSize; // in bits
+ private final PBKDF2Core kdf;
+ private final String pbeAlgo;
+ private final String cipherAlgo;
+ private final PBEUtil.PBES2Params pbes2Params = new PBEUtil.PBES2Params();
+ private OpenJCEPlusProvider provider = null;
+
+ /**
+ * Creates an instance of PBE Scheme 2 according to the selected
+ * password-based key derivation function and encryption scheme.
+ */
+ PBES2Core(String kdfAlgo, String cipherAlgo, int keySize, OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+
+ blkSize = AESCipher.AES_BLOCK_SIZE;
+ this.cipherAlgo = cipherAlgo;
+ keyLength = keySize * 8;
+ pbeAlgo = "PBEWith" + kdfAlgo + "And" + cipherAlgo + "_" + keyLength;
+ this.provider = provider;
+
+ if (cipherAlgo.equalsIgnoreCase("AES")) {
+ cipher = new AESCipher(provider);
+
+ switch(kdfAlgo.toLowerCase()) {
+ case "hmacsha1":
+ kdf = new PBKDF2Core.HmacSHA1(provider);
+ break;
+ case "hmacsha224":
+ kdf = new PBKDF2Core.HmacSHA224(provider);
+ break;
+ case "hmacsha256":
+ kdf = new PBKDF2Core.HmacSHA256(provider);
+ break;
+ case "hmacsha384":
+ kdf = new PBKDF2Core.HmacSHA384(provider);
+ break;
+ case "hmacsha512":
+ kdf = new PBKDF2Core.HmacSHA512(provider);
+ break;
+ case "hmacsha512/224":
+ kdf = new PBKDF2Core.HmacSHA512_224(provider);
+ break;
+ case "hmacsha512/256":
+ kdf = new PBKDF2Core.HmacSHA512_256(provider);
+ break;
+ default:
+ throw new NoSuchAlgorithmException(
+ "No Cipher implementation for " + kdfAlgo);
+ }
+ } else {
+ throw new NoSuchAlgorithmException("No Cipher implementation for " +
+ pbeAlgo);
+ }
+ cipher.engineSetMode("CBC");
+ cipher.engineSetPadding("PKCS5Padding");
+ }
+
+ protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+ if ((mode != null) && (!mode.equalsIgnoreCase("CBC"))) {
+ throw new NoSuchAlgorithmException("Invalid cipher mode: " + mode);
+ }
+ }
+
+ protected void engineSetPadding(String paddingScheme)
+ throws NoSuchPaddingException {
+ if ((paddingScheme != null) &&
+ (!paddingScheme.equalsIgnoreCase("PKCS5Padding"))) {
+ throw new NoSuchPaddingException("Invalid padding scheme: " +
+ paddingScheme);
+ }
+ }
+
+ protected int engineGetBlockSize() {
+ return blkSize;
+ }
+
+ protected int engineGetOutputSize(int inputLen) {
+ return cipher.engineGetOutputSize(inputLen);
+ }
+
+ protected byte[] engineGetIV() {
+ return cipher.engineGetIV();
+ }
+
+ protected AlgorithmParameters engineGetParameters() {
+ return pbes2Params.getAlgorithmParameters(
+ blkSize, pbeAlgo, provider, provider.getSecureRandom(null));
+ }
+
+ protected void engineInit(int opmode, Key key, SecureRandom random)
+ throws InvalidKeyException {
+ try {
+ engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
+ } catch (InvalidAlgorithmParameterException ie) {
+ throw new InvalidKeyException("requires PBE parameters", ie);
+ }
+ }
+
+ protected void engineInit(int opmode, Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ PBEKeySpec pbeSpec = pbes2Params.getPBEKeySpec(blkSize, keyLength,
+ opmode, key, params, random);
+ PBKDF2KeyImpl s = null;
+ byte[] derivedKey;
+ try {
+ s = (PBKDF2KeyImpl) kdf.engineGenerateSecret(pbeSpec);
+ derivedKey = s.getEncoded();
+ } catch (InvalidKeySpecException ikse) {
+ throw new InvalidKeyException("Cannot construct PBE key", ikse);
+ } finally {
+ if (s != null) {
+ try {
+ s.finalize();
+ } catch (Throwable e) {
+ //some error happened
+ }
+ }
+ pbeSpec.clearPassword();
+ }
+
+ SecretKeySpec cipherKey = null;
+ try {
+ cipherKey = new SecretKeySpec(derivedKey, cipherAlgo);
+ // initialize the underlying cipher
+ cipher.engineInit(opmode, cipherKey, pbes2Params.getIvSpec(), random);
+ } finally {
+ if (cipherKey != null) {
+ byte[] clean = cipherKey.getEncoded();
+ Arrays.fill(clean, (byte) 0x00);
+ }
+ Arrays.fill(derivedKey, (byte) 0x00);
+ }
+ }
+
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ engineInit(opmode, key, PBEUtil.PBES2Params.getParameterSpec(params),
+ random);
+ }
+
+ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+ return cipher.engineUpdate(input, inputOffset, inputLen);
+ }
+
+ protected int engineUpdate(byte[] input, int inputOffset, int inputLen,
+ byte[] output, int outputOffset)
+ throws ShortBufferException {
+ return cipher.engineUpdate(input, inputOffset, inputLen,
+ output, outputOffset);
+ }
+
+ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException {
+ return cipher.engineDoFinal(input, inputOffset, inputLen);
+ }
+
+ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen,
+ byte[] output, int outputOffset)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ return cipher.engineDoFinal(input, inputOffset, inputLen,
+ output, outputOffset);
+ }
+
+ protected int engineGetKeySize(Key key) throws InvalidKeyException {
+ return keyLength;
+ }
+
+ protected byte[] engineWrap(Key key)
+ throws IllegalBlockSizeException, InvalidKeyException {
+ return cipher.engineWrap(key);
+ }
+
+ protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ throws InvalidKeyException, NoSuchAlgorithmException {
+ return cipher.engineUnwrap(wrappedKey, wrappedKeyAlgorithm,
+ wrappedKeyType);
+ }
+
+ public static final class HmacSHA1AndAES_128 extends PBES2Core {
+ public HmacSHA1AndAES_128(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA1", "AES", 16, provider);
+ }
+ }
+
+ public static final class HmacSHA224AndAES_128 extends PBES2Core {
+ public HmacSHA224AndAES_128(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA224", "AES", 16, provider);
+ }
+ }
+
+ public static final class HmacSHA256AndAES_128 extends PBES2Core {
+ public HmacSHA256AndAES_128(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA256", "AES", 16, provider);
+ }
+ }
+
+ public static final class HmacSHA384AndAES_128 extends PBES2Core {
+ public HmacSHA384AndAES_128(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA384", "AES", 16, provider);
+ }
+ }
+
+ public static final class HmacSHA512AndAES_128 extends PBES2Core {
+ public HmacSHA512AndAES_128(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA512", "AES", 16, provider);
+ }
+ }
+
+ public static final class HmacSHA512_224AndAES_128 extends PBES2Core {
+ public HmacSHA512_224AndAES_128(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA512/224", "AES", 16, provider);
+ }
+ }
+
+ public static final class HmacSHA512_256AndAES_128 extends PBES2Core {
+ public HmacSHA512_256AndAES_128(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA512/256", "AES", 16, provider);
+ }
+ }
+
+ public static final class HmacSHA1AndAES_256 extends PBES2Core {
+ public HmacSHA1AndAES_256(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA1", "AES", 32, provider);
+ }
+ }
+
+ public static final class HmacSHA224AndAES_256 extends PBES2Core {
+ public HmacSHA224AndAES_256(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA224", "AES", 32, provider);
+ }
+ }
+
+ public static final class HmacSHA256AndAES_256 extends PBES2Core {
+ public HmacSHA256AndAES_256(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA256", "AES", 32, provider);
+ }
+ }
+
+ public static final class HmacSHA384AndAES_256 extends PBES2Core {
+ public HmacSHA384AndAES_256(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA384", "AES", 32, provider);
+ }
+ }
+
+ public static final class HmacSHA512AndAES_256 extends PBES2Core {
+ public HmacSHA512AndAES_256(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA512", "AES", 32, provider);
+ }
+ }
+
+ public static final class HmacSHA512_224AndAES_256 extends PBES2Core {
+ public HmacSHA512_224AndAES_256(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA512/224", "AES", 32, provider);
+ }
+ }
+ public static final class HmacSHA512_256AndAES_256 extends PBES2Core {
+ public HmacSHA512_256AndAES_256(OpenJCEPlusProvider provider)
+ throws NoSuchAlgorithmException, NoSuchPaddingException {
+ super("HmacSHA512/256", "AES", 32, provider);
+ }
+ }
+}
diff --git a/src/main/java/com/ibm/crypto/plus/provider/PBES2Parameters.java b/src/main/java/com/ibm/crypto/plus/provider/PBES2Parameters.java
new file mode 100644
index 000000000..1dd6ebb3c
--- /dev/null
+++ b/src/main/java/com/ibm/crypto/plus/provider/PBES2Parameters.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright IBM Corp. 2025
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms provided by IBM in the LICENSE file that accompanied
+ * this code, including the "Classpath" Exception described therein.
+ */
+
+package com.ibm.crypto.plus.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+import sun.security.util.KnownOIDs;
+import sun.security.util.ObjectIdentifier;
+
+/**
+ * This class implements the parameter set used with password-based
+ * encryption scheme 2 (PBES2), which is defined in PKCS#5 as follows:
+ *
+ *
+ * -- PBES2 + * + * PBES2Algorithms ALGORITHM-IDENTIFIER ::= + * { {PBES2-params IDENTIFIED BY id-PBES2}, ...} + * + * id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} + * + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} } + * + * PBES2-KDFs ALGORITHM-IDENTIFIER ::= + * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... } + * + * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } + * + * -- PBKDF2 + * + * PBKDF2Algorithms ALGORITHM-IDENTIFIER ::= + * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...} + * + * id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} + * + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} + * }, + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX) OPTIONAL, + * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 + * } + * + * PBKDF2-SaltSources ALGORITHM-IDENTIFIER ::= { ... } + * + * PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= { + * {NULL IDENTIFIED BY id-hmacWithSHA1} | + * {NULL IDENTIFIED BY id-hmacWithSHA224} | + * {NULL IDENTIFIED BY id-hmacWithSHA256} | + * {NULL IDENTIFIED BY id-hmacWithSHA384} | + * {NULL IDENTIFIED BY id-hmacWithSHA512}, ... } + * + * algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::= + * {algorithm id-hmacWithSHA1, parameters NULL : NULL} + * + * id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7} + * + * PBES2-Encs ALGORITHM-IDENTIFIER ::= { ... } + * + *+ */ +abstract class PBES2Parameters extends AlgorithmParametersSpi { + + private static final ObjectIdentifier pkcs5PBKDF2_OID = + ObjectIdentifier.of(KnownOIDs.PBKDF2WithHmacSHA1); + private static final ObjectIdentifier pkcs5PBES2_OID = + ObjectIdentifier.of(KnownOIDs.PBES2); + private static final ObjectIdentifier aes128CBC_OID = + ObjectIdentifier.of(KnownOIDs.AES_128$CBC$NoPadding); + private static final ObjectIdentifier aes192CBC_OID = + ObjectIdentifier.of(KnownOIDs.AES_192$CBC$NoPadding); + private static final ObjectIdentifier aes256CBC_OID = + ObjectIdentifier.of(KnownOIDs.AES_256$CBC$NoPadding); + + // the PBES2 algorithm name + private String pbes2AlgorithmName = null; + + // the salt + private byte[] salt = null; + + // the iteration count + private int iCount = 0; + + // the cipher parameter + private AlgorithmParameterSpec cipherParam = null; + + // the key derivation function (default is HmacSHA1) + private ObjectIdentifier kdfAlgo_OID = + ObjectIdentifier.of(KnownOIDs.HmacSHA1); + + // the encryption function + private ObjectIdentifier cipherAlgo_OID = null; + + // the cipher keysize (in bits) + private int keysize = -1; + + PBES2Parameters() { + // KDF, encryption & keysize values are set later, in engineInit(byte[]) + } + + PBES2Parameters(String pbes2AlgorithmName) throws NoSuchAlgorithmException { + int and; + String kdfAlgo; + String cipherAlgo; + + // Extract the KDF and encryption algorithm names + this.pbes2AlgorithmName = pbes2AlgorithmName; + if (pbes2AlgorithmName.startsWith("PBEWith") && + (and = pbes2AlgorithmName.indexOf("And", 7 + 1)) > 0) { + kdfAlgo = pbes2AlgorithmName.substring(7, and); + cipherAlgo = pbes2AlgorithmName.substring(and + 3); + + // Check for keysize + int underscore; + if ((underscore = cipherAlgo.indexOf('_')) > 0) { + int slash; + if ((slash = cipherAlgo.indexOf('/', underscore + 1)) > 0) { + keysize = + Integer.parseInt(cipherAlgo.substring(underscore + 1, + slash)); + } else { + keysize = + Integer.parseInt(cipherAlgo.substring(underscore + 1)); + } + cipherAlgo = cipherAlgo.substring(0, underscore); + } + } else { + throw new NoSuchAlgorithmException("No crypto implementation for " + + pbes2AlgorithmName); + } + + switch (kdfAlgo) { + case "HmacSHA1": + case "HmacSHA224": + case "HmacSHA256": + case "HmacSHA384": + case "HmacSHA512": + case "HmacSHA512/224": + case "HmacSHA512/256": + kdfAlgo_OID = ObjectIdentifier.of(KnownOIDs.findMatch(kdfAlgo)); + break; + default: + throw new NoSuchAlgorithmException( + "No crypto implementation for " + kdfAlgo); + } + + if (cipherAlgo.equals("AES")) { + switch (keysize) { + case 128: + cipherAlgo_OID = aes128CBC_OID; + break; + case 256: + cipherAlgo_OID = aes256CBC_OID; + break; + default: + throw new NoSuchAlgorithmException( + "No Cipher implementation for " + keysize + "-bit " + + cipherAlgo); + } + } else { + throw new NoSuchAlgorithmException("No Cipher implementation for " + + cipherAlgo); + } + } + + protected void engineInit(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException + { + if (!(paramSpec instanceof PBEParameterSpec)) { + throw new InvalidParameterSpecException ("Inappropriate parameter specification"); + } + this.salt = ((PBEParameterSpec) paramSpec).getSalt().clone(); + this.iCount = ((PBEParameterSpec) paramSpec).getIterationCount(); + this.cipherParam = ((PBEParameterSpec) paramSpec).getParameterSpec(); + } + + protected void engineInit(byte[] encoded) + throws IOException + { + DerValue pBES2_params = new DerValue(encoded); + if (pBES2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBE parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue kdf = pBES2_params.data.getDerValue(); + + // Before JDK-8202837, PBES2-params was mistakenly encoded like + // an AlgorithmId which is a sequence of its own OID and the real + // PBES2-params. If the first DerValue is an OID instead of a + // PBES2-KDFs (which should be a SEQUENCE), we are likely to be + // dealing with this buggy encoding. Skip the OID and treat the + // next DerValue as the real PBES2-params. + if (kdf.getTag() == DerValue.tag_ObjectId) { + pBES2_params = pBES2_params.data.getDerValue(); + kdf = pBES2_params.data.getDerValue(); + } + + String kdfAlgo = parseKDF(kdf); + + if (pBES2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBE parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + String cipherAlgo = parseES(pBES2_params.data.getDerValue()); + + this.pbes2AlgorithmName = "PBEWith" + kdfAlgo + "And" + cipherAlgo; + } + + private String parseKDF(DerValue keyDerivationFunc) throws IOException { + + if (keyDerivationFunc.tag != DerValue.tag_Sequence) { + throw new IOException("PBE parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + if (!pkcs5PBKDF2_OID.equals(keyDerivationFunc.data.getOID())) { + throw new IOException("PBE parameter parsing error: " + + "expecting the object identifier for PBKDF2"); + } + DerValue pBKDF2_params = keyDerivationFunc.data.getDerValue(); + if (pBKDF2_params.tag != DerValue.tag_Sequence) { + throw new IOException("PBE parameter parsing error: " + + "not an ASN.1 SEQUENCE tag"); + } + DerValue specified = pBKDF2_params.data.getDerValue(); + // the 'specified' ASN.1 CHOICE for 'salt' is supported + if (specified.tag == DerValue.tag_OctetString) { + salt = specified.getOctetString(); + } else { + // the 'otherSource' ASN.1 CHOICE for 'salt' is not supported + throw new IOException("PBE parameter parsing error: " + + "not an ASN.1 OCTET STRING tag"); + } + iCount = pBKDF2_params.data.getInteger(); + + // keyLength INTEGER (1..MAX) OPTIONAL, + var ksDer = pBKDF2_params.data.getOptional(DerValue.tag_Integer); + if (ksDer.isPresent()) { + keysize = ksDer.get().getInteger() * 8; // keysize (in bits) + } + + // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 + String kdfAlgo; + var prfDer = pBKDF2_params.data.getOptional(DerValue.tag_Sequence); + if (prfDer.isPresent()) { + DerValue prf = prfDer.get(); + kdfAlgo_OID = prf.data.getOID(); + KnownOIDs o = KnownOIDs.findMatch(kdfAlgo_OID.toString()); + if (o == null || (!o.stdName().equals("HmacSHA1") && + !o.stdName().equals("HmacSHA224") && + !o.stdName().equals("HmacSHA256") && + !o.stdName().equals("HmacSHA384") && + !o.stdName().equals("HmacSHA512") && + !o.stdName().equals("HmacSHA512/224") && + !o.stdName().equals("HmacSHA512/256"))) { + throw new IOException("PBE parameter parsing error: " + + "expecting the object identifier for a HmacSHA key " + + "derivation function"); + } + kdfAlgo = o.stdName(); + prf.data.getOptional(DerValue.tag_Null); + prf.data.atEnd(); + } else { + kdfAlgo = "HmacSHA1"; + } + return kdfAlgo; + } + + private String parseES(DerValue encryptionScheme) throws IOException { + String cipherAlgo; + + cipherAlgo_OID = encryptionScheme.data.getOID(); + if (aes128CBC_OID.equals(cipherAlgo_OID)) { + cipherAlgo = "AES_128"; + // parameter is AES-IV 'OCTET STRING (SIZE(16))' + cipherParam = + new IvParameterSpec(encryptionScheme.data.getOctetString()); + keysize = 128; + } else if (aes256CBC_OID.equals(cipherAlgo_OID)) { + cipherAlgo = "AES_256"; + // parameter is AES-IV 'OCTET STRING (SIZE(16))' + cipherParam = + new IvParameterSpec(encryptionScheme.data.getOctetString()); + keysize = 256; + } else { + throw new IOException("PBE parameter parsing error: " + + "expecting the object identifier for AES cipher"); + } + + return cipherAlgo; + } + + protected void engineInit(byte[] encoded, String decodingMethod) + throws IOException + { + engineInit(encoded); + } + + protected