0

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.

Community
  • 1
  • 1
ge0rg
  • 1,816
  • 1
  • 26
  • 38

2 Answers2

2

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.

jbtule
  • 31,383
  • 12
  • 95
  • 128
  • For the first encryption, the IV is zero indeed. However, after the first doFinal() pass, the internal IV in the Cipher changes, and I need to obtain its value to pass to the next Cipher.init(). If I call Cipher.init() without the IvParameterSpec parameter, the IV will be reset to zero as well. – ge0rg Mar 25 '13 at 15:07
  • It's an initialization vector, all you need to worry about it is at initialization, there is no resulting iv it's not calculated, with cbc each block uses the previous block's ciphertext as the initialization vector except for the first one you have to provide, the IV at init for encryption and decryption needs to be the same. BTW for security at encryption, it also needs to be non repeating and non predictable, which all zeros is not. – jbtule Mar 25 '13 at 15:23
  • Ok, now you made it obvious. The IV is the input/output of the last decryption/encryption operation, respectively, so it is not too hard to obtain it. If you make that into an answer instead of a comment, I'll accept it :) – ge0rg Mar 25 '13 at 23:13
  • no, that is not what an IV is, and that's not what jbtule says that it is. The IV can be communicated over an open channel. It should be randomized, but doesn't need to be secret. The IV does not change with the state of the cipher, because it is an **initial** value, hence the name Initialization Vector. – Peter Elliott Mar 26 '13 at 00:55
0

you can get the IV out of the Cipher object by calling c.getIV(), which will return a byte array with the IV data. You can then plug that into an IVParametersSpec on the decrypt side

That said, you are using the init method of Cipher incorrectly. It will not generate an internal IV (as you say in your comment on the other answer) if you supply an IVParameterSpec in the init call. It will instead use an IV of all zeros, because that's what that version of init tells it to do. Instead, use a call to init like c.init(Cipher.ENCRYPT_MODE, secretKey) then use the above c.getIV() to get the IV out. Check out the javadocs for Cipher here to see what I mean.

Peter Elliott
  • 3,273
  • 16
  • 30
  • 1
    As I wrote in the question, c.getIV() returns not the IV state after the last encryption, but the IV that was supplied to init(), making that function call useless for re-initing the Cipher. :( – ge0rg Mar 25 '13 at 23:07
  • @ge0rg that's because those IV's are the same. The IV doesn't change when you encrypt something. you would use `c.getIV()` if you properly generated a random IV using the `c.init(mode, key)` function. Did you read the second half of my answer? – Peter Elliott Mar 26 '13 at 00:53
  • 1
    I need to clarify: If you consider the CBC encryption of each block as a separate process, the IV for the second block is the ciphertext of the first block - this is what I meant by saying that the IV changes. Regarding the IV being all zeroes, I am aware that it is insecure, but it is required by the DESfire specification and I am not in the position to change it. – ge0rg Mar 26 '13 at 08:14
  • You are considering IV incorrectly, then, and using that terminology will not get you a correct answer. The value XORed with the second block of plaintext, that is literally just the first block of ciphertext -- 16 bytes in the `encrypted_response` array. See the [wikipedia article](http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation) for a diagram. – Peter Elliott Mar 26 '13 at 13:17