EbraHim
EbraHim

Reputation: 2349

Using a single Cipher object or two different objects for decrypt and encrypt operations?

As you know, when we want to do cryptography operations using Java Cards, we must use Cipher objects. The question that I have is actually efficiency related. Let assume that I want to do some Encryption and Decryption operations using an AES key.

Which one of the following strategies is better?

  1. Defining two different Cipher objects and initial them with a single key, but different modes (MODE_ENCRYPT and MODE_DECRYPT). Then for each operation I only need to call doFinal() method on the proper object.
  2. Defining a single Cipher object and each time before calling doFinal() method do an init() method call on the object with proper mode.

Upvotes: 7

Views: 1299

Answers (2)

vojta
vojta

Reputation: 5651

Firstly, according to the documentation of Cipher.doFinal(...):

AES, DES, triple DES and Korean SEED algorithms in CBC mode reset the initial vector(IV) to 0. The initial vector(IV) can be re-initialized using the init(Key, byte, byte[], short, short) method.

It means that if you use AES-CBC with non-zero IV, you have to call init after each doFinal, so there is no choice, really.


Let's have a look now at some real-world measurements I did on my J2E145 cards by NXP.

Both ALG_AES_BLOCK_128_CBC_NOPAD and ALG_AES_BLOCK_128_ECB_NOPAD require 34 bytes of RAM and 32 bytes of persistent memory per object instance.

Concerning time consumption, there are 4 possible situations:

Situation 1: the same transient key:

key1 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
 KeyBuilder.LENGTH_AES_128, false);
...
cipher.init(key1, Cipher.MODE_DECRYPT);
cipher.init(key1, Cipher.MODE_ENCRYPT);

Result: 11 ms per each init(...)

Situation 2: different transient keys:

key1 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
     KeyBuilder.LENGTH_AES_128, false);
key2 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT,
     KeyBuilder.LENGTH_AES_128, false);
...
cipher.init(key1, Cipher.MODE_DECRYPT);
cipher.init(key2, Cipher.MODE_ENCRYPT);

Result: 18 ms per each init(...)

Situation 3: the same persistent key:

key1 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES,
 KeyBuilder.LENGTH_AES_128, false);
...
cipher.init(key1, Cipher.MODE_DECRYPT);
cipher.init(key1, Cipher.MODE_ENCRYPT);

Result: 12 ms per each init(...)

Situation 4: different persistent keys:

key1 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES,
     KeyBuilder.LENGTH_AES_128, false);
key2 = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES,
     KeyBuilder.LENGTH_AES_128, false);
...
cipher.init(key1, Cipher.MODE_DECRYPT);
cipher.init(key2, Cipher.MODE_ENCRYPT);

Result: 19 ms per each init(...)

Conclusion: init is really fast independently of the memory type, because EEPROM is only read and copied into the internal (transient) memory of the Cipher instance. Although I can imagine some cases with high time consumption requirements, 34 RAM bytes seem to be too many to pay for 20ms. Exact results can be different on your platform, of course, but the trade-off efficiency will remain more or less the same.

Upvotes: 4

Paul Bastian
Paul Bastian

Reputation: 2647

It depends whether you are handling with persistent or transient key material.
If you have persistent key material:

  • Option 1 needs more EEPROM but you have a significant time boost because you call init() only once when key material is generated or imported.
  • therefore Option 2 is not desirable

If you have transient key material:

  • Option 1 needs more EEPROM and time boost is almost non-existent because you need to call init() anyway. I did some major testing 2years ago and if I remember correctly there is either none or a very tiny performance delta between the two options
  • Option 2 needs less EEPROM and reduces complexity of the code, therefore its desirable

Upvotes: 3

Related Questions