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?
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.Cipher
object and each time before calling doFinal()
method do an init()
method call on the object with proper mode. Encryption is the process of translating plain text data (plaintext) into something that appears to be random and meaningless (ciphertext). Decryption is the process of converting ciphertext back to plaintext. To encrypt more than a small amount of data, symmetric encryption is used.
After initializing the Cipher object, we call the doFinal() method to perform the encryption or decryption operation. This method returns a byte array containing the encrypted or decrypted message.
Ciphers can be distinguished into two types by the type of input data: block ciphers, which encrypt block of data of fixed size, and. stream ciphers, which encrypt continuous streams of data.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With