Search code examples
javaencryption3des

Java's 3DES encryption generates trash at the end of encrypted data


I have a 3des Cipher object that is initialized like this:

KeySpec keySpec= new DESedeKeySpec(bytesKey);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
SecretKey secretKey= secretKeyFactory.generateSecret(keySpec);
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(modo, secretKey);

When this object is used to encrypt data, no exception is thrown and the algorithm ends succesfully:

String unencryptedText = "192 character length text in clear....        ";
byte[] bytesUnencryptedText = unencryptedText.getBytes("UTF8");
byte[] bytesEncryptedData = cipher.doFinal(bytesUnencryptedText);

When we took a look at the encrypted data generated by the doFinal, we noticed 200 bytes are being returned, as opposed to 192 as we expected. These additional 8 bytes took the following hexa value: 08.

The first 192 bytes are correct and we already have been able to decrypt them and obtain our original data. But the additional 8 bytes are generating an error at our HSM.

How can we prevent the Cipher to inject these additional bytes?


Solution

  • The block size of DES is 64-bit or 8 bytes. When the plaintext size is a multiple of the plaintext the padding used will add another block of data to the plaintext filled with 0x08. This is how PKCS#5/PKCS#7 padding works.

    It seems that your HSM expects that no padding is used. Also, from the comments it is apparent that "DESede" defaults to ECB mode, so the fully qualified Cipher would be:

    Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
    

    Note that ECB mode is not semantically secure. If possible, use a different mode like CBC with an HMAC over the ciphertext, or simply an authenticated mode like GCM.

    When you use NoPadding, the plaintext is filled up with 0x00 bytes and you will have to trim the decrypted plaintext yourself by removing all 0x00 bytes at the end. To do this, make sure that the plaintext doesn't actually contain 0x00 bytes at the end, otherwise you will remove actual plaintext bytes.