JDK-8266293 : Key protection using PBEWithMD5AndDES fails with "java.security.InvalidAlgorithmParameterException: Salt must be 8 bytes long"
  • Type: Bug
  • Component: security-libs
  • Affected Version: 7u311,8u301,11.0.12-oracle,17
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2021-04-29
  • Updated: 2021-06-24
  • Resolved: 2021-05-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 17 JDK 7 JDK 8
11.0.12-oracleFixed 17 b22Fixed 7u311Fixed 8u301Fixed
Related Reports
Relates :  
Description
Attached is a test that reads the in-memory key and certificate bytes, constructs a key and certificate chain, and attempts to import those onto a PKCS12 keystore. The default execution works well. However, if we run:

java -Dkeystore.pkcs12.keyProtectionAlgorithm=PBEWithMD5AndDES PKCS12Tester

---------------------------------------------

Exception in thread "main" java.security.KeyStoreException: Key protection algorithm not found: java.security.UnrecoverableKeyException: Encrypt Private Key failed: Salt must be 8 bytes long
	at java.base/sun.security.pkcs12.PKCS12KeyStore.setKeyEntry(PKCS12KeyStore.java:709)
	at java.base/sun.security.pkcs12.PKCS12KeyStore.engineSetKeyEntry(PKCS12KeyStore.java:589)
	at java.base/sun.security.util.KeyStoreDelegator.engineSetKeyEntry(KeyStoreDelegator.java:111)
	at java.base/java.security.KeyStore.setKeyEntry(KeyStore.java:1167)
	at PKCS12Tester.main(PKCS12Tester.java:81)
Caused by: java.security.UnrecoverableKeyException: Encrypt Private Key failed: Salt must be 8 bytes long
	at java.base/sun.security.pkcs12.PKCS12KeyStore.encryptPrivateKey(PKCS12KeyStore.java:951)
	at java.base/sun.security.pkcs12.PKCS12KeyStore.setKeyEntry(PKCS12KeyStore.java:631)
	... 4 more
Caused by: java.security.InvalidAlgorithmParameterException: Salt must be 8 bytes long
	at java.base/com.sun.crypto.provider.PBES1Core.init(PBES1Core.java:241)
	at java.base/com.sun.crypto.provider.PBES1Core.init(PBES1Core.java:347)
	at java.base/com.sun.crypto.provider.PBEWithMD5AndDESCipher.engineInit(PBEWithMD5AndDESCipher.java:227)
	at java.base/javax.crypto.Cipher.implInit(Cipher.java:875)
	at java.base/javax.crypto.Cipher.chooseProvider(Cipher.java:929)
	at java.base/javax.crypto.Cipher.init(Cipher.java:1585)
	at java.base/javax.crypto.Cipher.init(Cipher.java:1516)
	at java.base/sun.security.pkcs12.PKCS12KeyStore.encryptPrivateKey(PKCS12KeyStore.java:931)
	... 5 more

-----------------------------------------------

In comparison, openssl seems to have no issues with the same algorithm:

$ openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017

$ openssl pkcs12 -export -in rsa.cert.pem -inkey rsa.pkey.pem -name a -passout pass:hello -keypbe PBE-MD5-DES >/dev/null && echo $?
0

I went through the PKCS12KeyStore implementation, and have included at the end of the same attached program, what I think is taking place in the implementation, reaching at the exception.
Comments
Fix Request (11u) Should get backported for parity with 11.0.12-oracle. Included test shows that it's needed. It applies almost cleanly, but requires an adaptation. Review thread: http://mail.openjdk.java.net/pipermail/jdk-updates-dev/2021-May/006240.html
18-05-2021

Changeset: 04f71126 Author: Weijun Wang <weijun@openjdk.org> Date: 2021-05-06 18:00:11 +0000 URL: https://git.openjdk.java.net/jdk/commit/04f71126479f9c39aa71e8aebe7196d72fc16796
06-05-2021

Ah, I must be reading RFC 8018, where it is "at least eight octets (64 bits) long". Wait, RFC 2898 Page 7 also says "It should be at least eight octets" but then in the algorithms description uses 8-byte salt again.
06-05-2021

RFC 2898 has salt length to be "exact" 8 bytes for PBKDF1 and PBES1 which is what PBEwithMD5AndDES is based upon. So, it's correct for PBES1Core to enforce 8-byte salt length. However, for the newer PBE algorithms, e.g. PBKDF2, PBES2, PBMAC1, the salt does not have a fixed length.
06-05-2021

The fix in JDK 17 uses `KnownOIDs.findMatch(algorithm) == KnownOIDs.PBEWithMD5AndDES` to detect whether PBEWithMD5AndDES is used. Backporters might need to check case-insensitive equality to both "PBEWithMD5AndDES" and "1.2.840.113549.1.5.3" because both the algorithm name and OID can be specified through the system property.
30-04-2021

PKCS12KeyStore always uses a 20-byte salt in encryption but PBEWithMD5AndDES only accepts 8-byte salt. With this code change, the salt used for this algorithm will be 8 bytes. RFC 2898 only requires the salt to be at least 8 bytes, but I don't intend to modify the PBES1Core.java to accept a long salt. Otherwise, a newly generated PKCS #12 file using a long salt will not be recognized by an old JDK. Also, although PBES1Core.java also take cares of another algorithm named PBEWithMD5AndDESede but it's not usable in a PKCS #12 keystore as we have not defined its Object Identifier anywhere.
30-04-2021