Search code examples
javacryptographymifare

Change Cipher encryption/decryption mode while retaining IV


When interacting with a DESfire EV1 tag, AES-CBC is used for securing communication. After encrypting and sending a message, the response needs to be decrypted using the IV that resulted from the encryption:

Cipher c = Cipher.getInstance("AES/CBC/NoPadding");
c.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(zeroBytes));

byte[] encrypted_response = transceive(c.doFinal(message));

// TODO: cipher needs to be re-set to DECRYPT_MODE while retaining the IV
c.init(Cipher.DECRYPT_MODE, ...?);

byte[] response = c.doFinal(encrypted_response);

Unfortunately, Cipher.getIV() returns the initial IV (all zeroes), and there seems to be no way to get the IV short of implementing the whole CBC part manually. In Get updated IV from Cipher after encrypting bytes a similar question is asked, however only CTR-specific solutions are presented, which do not apply in CBC mode.


Solution

  • You set the encrypt IV to all zeros here:

    new IvParameterSpec(zeroBytes)
    

    So instead if you use random bytes, and then you will have those random bytes as your iv, keep track of them yourself.

    Update

    From you comments it looks like you may be trying to restart decryption midstream or mid chunk, with CBC mode you can use the previous block of ciphertext as your IV, as long as you are block aligned in your stream or chunk.