One of the more stupid things about the Oracle implementation is that the SecretKeyFactory
does not support DES ABA keys, also known as "two-key" DES keys.
These keys for triple-DES operation consists of a single DES key A, followed by single DES key B. Key A is used both for the first and last iteration of DES within DES EDE (Encrypt-Decrypt-Encrypt).
If you stay within software you can create a method to create such keys. The problem is that the resulting keys actually have 192 bits, which is simply not correct - it makes it impossible to distinguish between the key sizes.
Anyway, the following code can be used to generate DES ABA keys:
private static final int DES_KEY_SIZE_BYTES = 64 / Byte.SIZE;
private static final int DES_ABA_KEY_SIZE_BYTES = 2 * DES_KEY_SIZE_BYTES;
private static final int DES_ABC_KEY_SIZE_BYTES = 3 * DES_KEY_SIZE_BYTES;
public static SecretKey createDES_ABAKey(byte[] key) {
if (key.length != DES_ABA_KEY_SIZE_BYTES) {
throw new IllegalArgumentException("128 bit key argument with size expected (including parity bits.)");
}
try {
byte[] desABCKey = new byte[DES_ABC_KEY_SIZE_BYTES];
System.arraycopy(key, 0, desABCKey, 0, DES_ABA_KEY_SIZE_BYTES);
System.arraycopy(key, 0, desABCKey, DES_ABA_KEY_SIZE_BYTES, DES_KEY_SIZE_BYTES);
SecretKeySpec spec = new SecretKeySpec(desABCKey, "DESede");
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey desKey = factory.generateSecret(spec);
return desKey;
} catch (GeneralSecurityException e) {
throw new RuntimeException("DES-EDE ABC key factory not functioning correctly", e);
}
}
OK, so that leaves us with the CBC encryption (no padding, and zero IV):
private static final byte[] ENCRYPTION_KEY = Hex.decode("448D3F076D8304036A55A3D7E0055A78");
private static final byte[] PLAINTEXT = Hex.decode("1234567890ABCDEFFEDCBA0987654321");
public static void main(String[] args) throws Exception {
SecretKey desABAKey = createDES_ABAKey(ENCRYPTION_KEY);
Cipher desEDE = Cipher.getInstance("DESede/CBC/NoPadding");
IvParameterSpec zeroIV = new IvParameterSpec(new byte[desEDE.getBlockSize()]);
desEDE.init(Cipher.ENCRYPT_MODE, desABAKey, zeroIV);
byte[] ciphertext = desEDE.doFinal(PLAINTEXT);
System.out.println(Hex.toHexString(ciphertext));
}
I've used the Bouncy Castle hexadecimal codec, but other hexadecimal codecs can also be used.