Using a single Cipher object or two different objects for decryption and encryption?

As you know, when we want to perform cryptographic operations using Java maps, we must use Cipher objects. The question I have is actually related to efficiency. Suppose I want to perform some encryption and decryption operations using the AES key.

Which of the following strategies is better?

  • Definition of two different Cipher objects and their initialization with one key, but with different modes ( MODE_ENCRYPT and MODE_DECRYPT ). Then for each operation I only need to call the doFinal() method on the corresponding object.
  • Defining a single Cipher object and each time before calling the doFinal() method, it calls the init() method on the object with the appropriate mode.
+5
source share
2 answers

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 reinitialized using the init(Key, byte, byte[], short, short) method init(Key, byte, byte[], short, short) .

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


Now let's look at some real-world measurements that I made on my NXP J2E145 cards.

Both ALG_AES_BLOCK_128_CBC_NOPAD and ALG_AES_BLOCK_128_ECB_NOPAD require 34 bytes of RAM and 32 bytes of read-only memory for each instance of the object.

As for the consumption of time, 4 situations are possible:

Situation 1: the same transition 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 for each init(...)

Situation 2: different transition 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 for each init(...)

Case 3: The same permanent 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 for each init(...)

Case 4: different constant 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 for each init(...)

Conclusion: init really fast regardless of the type of memory, since the EEPROM is only read and copied to the internal (temporary) memory of the Cipher instance. Although I can imagine some cases with high demand for time, 34 bytes of RAM seem too large to pay for 20 ms. Of course, the exact results may be different on your platform, but the effectiveness of the compromise will remain more or less the same.

+4
source

It depends on whether you work with permanent or temporary key material.
If you have constant key material:

  • Option 1 requires more EEPROM, but you have a significant increase in time because you only call init() once when key material is generated or imported.
  • therefore option 2 is undesirable

If you have temporary key material:

  • Option 1 requires more EEPROM, and the increase in time almost does not exist, since in any case you need to call init() . I did some serious tests 2 years ago, and if I remember correctly, either not, or a very tiny performance delta between two parameters.
  • Option 2 requires less EEPROM and reduces code complexity, so its desirable
+3
source

All Articles