7

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.
EbraHim
  • 2,279
  • 2
  • 16
  • 28

2 Answers2

4

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.

vojta
  • 5,591
  • 2
  • 24
  • 64
  • Good erfforts opn the exact timings vojta! Still if you are using IV=0 you can benefit with persistent key data. I think thats a valid case... – Paul Bastian May 04 '16 at 11:18
  • I wonder if thats just a typo in you code lines that there is always only one `cipher` and not `cipher1`; `cipher2`? – Paul Bastian May 04 '16 at 11:20
  • @PaulBastian Yes, but you can gain round 20ms only... Is that enough for 34 bytes of RAM? I don't think so... – vojta May 04 '16 at 11:20
  • @PaulBastian No, that is not a typo... I measured "option 2" - how much time I need to perform `init(...)` – vojta May 04 '16 at 11:21
  • Depends how often you use it and what your preferences are :P – Paul Bastian May 04 '16 at 11:33
  • Due to RAM limitation, It is more rational (logical?) to use a single Cipher object instead of 3 or 6 different Cipher objects for asymmetric cryptography operations using 3 different RSA 2048 key pairs, . Am I right? – EbraHim May 05 '16 at 13:50
  • 1
    @EbraHim As Paul said, it depends on your preferences... However, RSA requires much more RAM than AES, so just one Cipher instance seems to be reasonable. – vojta May 05 '16 at 14:30
  • Your information is very useful but the conculusion is not. Surely it depends very much on the use case. I'd imagine for all high volume web servers that spending 34 bytes per thread on a Cipher is significantly worth the massive 20ms per call. – mjaggard Jul 03 '20 at 23:40
  • 1
    @mjaggard This is a Java Card question. The situation is quite different on less limited platforms, of course. – vojta Jul 05 '20 at 08:37
3

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
Paul Bastian
  • 2,597
  • 11
  • 26