9

I am trying to replace PBEWithMD5AndDES with PBEWithMD5AndTripleDES in existing code. So far, I am using the same passphrase that I was using before, and receiving this Exception:

java.security.InvalidKeyException: Illegal key size

I looked online and saw that DES uses a 64 bit key and TripleDES uses a 128 bit key. I am not clear on the details of how my passphrase is used to generate a key, and not sure where to look to understand this fully. My passphrase is 260 characters long. I tried doubling the length, but I get the same Exception.

I am generating a PBEKeySpec from my passphrase, with an 8 byte salt and an iteration count of 12. I see that there's another constructor that takes a keyLength argument, but the documentation describes it as "to be derived," and I don't understand that. I have the idea that I need to modify the iteration count and/or supply a keyLength argument, but I don't want to just do this blindly without fully understanding what I am doing.

Here is the basic outline of the code I'm currently using:

String passphrase = ...
byte[] salt = ...
int iterationCount = 12;
String algorithm = "PBEWithMD5AndTripleDES";
KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance(algorithm).generateSecret(keySpec);
Cipher cipher = Cipher.getInstance(key.getAlgorithm());
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
byte[] encoded = cipher.doFinal(data);
skiphoppy
  • 97,646
  • 72
  • 174
  • 218
  • TripleDES, or more specifically DESede uses either a DES ABA key or a DES ABC key. In the 16 byte / 128 bit version, which has an entropy of 112 bit and an effective length of about 80 bit, the first 8 bytes are the first key (A), and the next 8 bytes are the second key (B), then DESede is C = E(Sa, D(Sb, E(Sa, data block))). It's more likely that Oracle uses ABC keys (24 byte, 192 bits, 168 bit entropy, 128 bit effective) because that was the only one they supported for quite some time. 16 byte keys would give an InvalidKeySize, or a InvalidKeySpec exception, if I'm not mistaken. – Maarten Bodewes Feb 25 '12 at 21:36
  • Just a note: Consider to use AES instead of (Triple)DES - it is both faster and considered more secure. – Paŭlo Ebermann Mar 03 '12 at 18:37

2 Answers2

15

PBEWith<Hash>AndTripleDES Requires "Unlimited Strength" Policy

This algorithm uses a 168-bit key (although due to vulnerabilities, it has an effective strength of 112 bits). To use a symmetric key of that length, you need the "unlimited strength jurisdiction policy" installed in your Java runtime.

An "Illegal key size" message indicates the key length is not permitted by policy; if the key length is incorrect for the algorithm, the SunJCE provider uses the message, "Wrong key size".

Don't Use PBEWith<Hash>AndTripleDES

Note that "PBEWithMD5AndTripleDES" is a bad algorithm to use.

Password-based encryption generally follows PKCS #5. It defines an encryption scheme for DES (or RC2) called PBES1. Because PBES1 was designed to generate 64-bit (or less) keys, Oracle has created a proprietary extension to generate longer keys. It hasn't been exposed to the same scrutiny that PKCS #5 has, and if you need to inter-operate with any other platform, you'll have to dig into the source code to find out how the key and initialization vector are derived.

It's also strange that the initialization vector is derived from the password. The purpose of an IV is to create different cipher texts each time a given plain text is encrypted with the same key. If the IV is generated from the key, this purpose is defeated. The key-derivation algorithm used by PBES1 avoids this by incorporating a "salt" that is supposed to be different each time the password is used. But, it could be easy to screw this up; providing an IV directly to the cipher initialization is more conventional, and makes it more obvious what is happening.

Use PBKDF2 Instead

PKCS #5 also defines an key-derivation algorithm called PBKDF2 that is now supported by Java. It provides superior security to PBES1 because the initialization vector and any other parameters required by the cipher are not derived from the password, but are selected independently.

Here's an example with PBKDF2, using AES. If you can't follow the recommendation to update to AES, the example can be applied to DESede by using a key length of 192, and changing occurrences "AES" to "DESede".

TDEA Keying Options

There are three keying options that can be used with TDEA ("Triple DES" or "DESede"). They take 64-, 128-, or 192-bit keys (including parity bits), depending on the option.

The key sizes accepted by the TDEA implementation depend on the provider; a few require you to form a 192-bit key, even if you are using the 56-bit key option which is effectively DES instead of TDEA. Most implementations will take 16 or 24 bytes as a key.

Only the three-key option (168 bits, or 192 bits with parity) can be considered "strong encryption". It has 112 bits of effective strength.

Community
  • 1
  • 1
erickson
  • 265,237
  • 58
  • 395
  • 493
  • Does this mean I need to explicitly set keyLength of 128? That sounds like the obvious thing to try, but I couldn't find any confirmation or examples online, and with cryptography I'm loathe to just "try it and see if it works." – skiphoppy Feb 24 '12 at 14:52
  • There are several ways to do PBE in Java. Are you passing a `KeySpec` to a `SecretKeyFactory`, then using the resulting `SecretKey` with a "DESede" `Cipher` object, or are you trying to use a "PBEWithMD5AndTripleDES" `Cipher` in one step? Also, what security provider are you using? While [this example](http://stackoverflow.com/a/992413/3474) is for AES-256, the same approach is what I recommend for TDEA, because you can use PBKDF2, which is a better key derivation algorithm. – erickson Feb 24 '12 at 15:16
  • I'm trying to use PBEWithMD5AndTripleDES in one step. I'll add sample code. I am using no security provider other than what is present in the JDK. At this point I'd like to make minimal changes to what we've already got in operation, but not so minimal that it is not secure or does not work. – skiphoppy Feb 24 '12 at 15:46
  • @skiphoppy With the Java 6 SunJCE provider, generating the `SecretKey` the way you have doesn't do anything. If you actually print out `new String(key.getEncoded())`, you should see your password. The actual key derivation happens (when using the SunJCE provider) when you `init()` the `Cipher` (that's why you need the redundant `PBEParameterSpec` information). However, maybe your `Cipher` provider is *not* SunJCE. Please specify your Java runtime version, and add some debugging to find for certain the provider of the `SecretKeyFactory` *and* the `Cipher`: `x.getProvider().getName()` – erickson Feb 24 '12 at 16:52
  • You're right, all I'm getting is my passphrase right back at me! The provider is SunJCE version 1.6. – skiphoppy Feb 24 '12 at 17:21
  • 1
    @skiphoppy You don't have the "unlimited strength jurisdiction policy" files installed correctly in your Java runtime. You can get them [here.](http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html) – erickson Feb 24 '12 at 18:20
  • 1
    @skiphoppy Even though this will fix your problem, I still urge you to follow the pattern in the AES example I linked to. With this approach, you don't know what you are getting. What length key is actually used? What is the cipher mode? Java's approach to password-based encryption is somewhat unsafe and hard to inter-operate with because of its obscurity. – erickson Feb 24 '12 at 18:28
  • erickson, thanks for all of your help. It was immensely valuable. – skiphoppy Feb 29 '12 at 15:27
2

As erickson says, the "right" answer to this question is to install the unlimited strength jurisdiction policy files in the JRE.

That will make encryption with PBEWithMD5AndTripleDES "work," but the resulting data cannot be decrypted as far as I can tell. You will get a padding error exception. There may be some way to fix it, but this was proof enough to me that pursuing this route was not worth it as it seems to be a road that is not traveled enough to get the bugs worked out or to popularize working examples.

I also discovered a PBEWithSHA1AndTripleDES and tried it, but got the same padding error upon decryption.

I was able to get our requirements changed from PBEWithMD5AndTripleDES to just TripleDES (DESede), and that eliminated the whole issue for me!

skiphoppy
  • 97,646
  • 72
  • 174
  • 218