How to get AES secret key from DH secret key

2019-02-28 06:30发布

I have the following code that converts a DH secret key to AES secret key. This used to work until Oracle JRE 8u161 when they started restricting creation of DH keys < 1024 in java.security file. Now, I will get NoSuchAlgorithmException: Unsupported secret key algorithm AES at the last line.

PrivateKey privKey = null;
PublicKey pubKey = null;
PublicKey agreement = null;

KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
keyAgreement.init(privKey);
keyAgreement.doPhase(pubKey, false);
keyAgreement.doPhase(agreement, true);
SecretKey key = keyAgreement.generateSecret("AES");

I tried changing the last line to this. I can encrypt and decrypt using the new keys but this does not work with the old keys generated before.

byte[] encodedKey = keyAgreement.generateSecret();
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");

I found a similar SO question What metod KeyAgreement.generateSecret(String algorithm) does? but I am still clueless on how I can fix this without breaking the existing keys.

2条回答
Anthone
2楼-- · 2019-02-28 07:12

Generally key size requirements are checked in the Cipher and KeyAgreement class itself rather than the service implementation by the provider. It is of course try to test another provider such as the Bouncy Castle provider regardless [EDIT: this seems to work in this case, so the key size restraints are in the default provider delivered with the Java runtime, using the "BC" provider seems to work fine, see the comment below the answer].

If using another provider doesn't work then use the Bouncy Castle lightweight API (org.bouncycastle.** classes) to use another software implementation of DH, bypassing the KeyAgreement class altogether. Stepping outside the JCA / KeyAgreement should however be avoided.

Needless to say, the requirements of not using < 1024 bits keys are there for a reason, they are not considered secure anymore. Upgrade your security ASAP!

查看更多
Deceive 欺骗
3楼-- · 2019-02-28 07:13

The problem with Oracle/Sun-providers is not the DH keysize limitation in java.security, which only applies to TLS/SSL (i.e. JSSE), but this item slightly further down in the release notes you linked:

  • Stricter key generation

The generateSecret(String) method has been mostly disabled in the javax.crypto.KeyAgreement services of the SunJCE and SunPKCS11 providers. Invoking this method for these providers will result in a NoSuchAlgorithmException for most algorithm string arguments. The previous behavior of this method can be re-enabled by setting the value of the jdk.crypto.KeyAgreement.legacyKDF system property to true (case insensitive). Re-enabling this method by setting this system property is not recommended.

The next paragraphs basically say, not very clearly, that using DH correctly requires a suitable KDF, but this operation doesn't provide/define the KDF, so it can't ensure suitability, and instead you should use the no-argument generateSecretKey() method to get the raw DH value and apply a suitable KDF yourself; they give SP800-56Ar2 and plain hash as examples.

BouncyCastle went the other way; in 1.60 it has several KeyAgreement algorithms with the KDF encoded like DHwithSHA256CKDF.

查看更多
登录 后发表回答