使用单个密码对象或两个不同的对象进行解密和加密操作?

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

如您所知,当我们要使用Java个卡片进行密码运算时,我们必须使用Cipher个对象。我的问题实际上与效率有关。假设我想使用 AES 密钥执行一些 EncryptionDecryption 操作。

以下哪种策略更好?

  1. 定义两个不同的 Cipher 对象并用一个键初始化它们,但模式不同(MODE_ENCRYPTMODE_DECRYPT)。然后对于每个操作,我只需要在适当的对象上调用 doFinal() 方法。
  2. 定义单个 Cipher 对象,每次在调用 doFinal() 方法之前,以适当的模式对该对象执行 init() 方法调用。

这取决于您处理的是永久密钥还是临时密钥material。
如果你有持久键 material:

  • 选项 1 需要更多的 EEPROM,但你有显着的时间提升,因为你只在生成或导入密钥 material 时调用 init() 一次。
  • 因此选项 2 不可取

如果您有临时密钥 material:

  • 选项 1 需要更多的 EEPROM,并且时间提升几乎不存在,因为无论如何您都需要调用 init()。我在 2 年前做了一些主要测试,如果我没记错的话,这两个选项之间存在 none 或非常小的性能差异
  • 选项 2 需要较少的 EEPROM 并降低了代码的复杂性,因此是可取的

首先,根据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.

这意味着如果你使用非零IV的AES-CBC,你必须在每个doFinal之后调用init,所以没有选择,真的。


现在让我们来看看我在 NXP 的 J2E145 卡上进行的一些实际测量。

每个对象 ALG_AES_BLOCK_128_CBC_NOPADALG_AES_BLOCK_128_ECB_NOPAD 都需要 34 字节的 RAM32 字节的持久内存实例。

关于时间消耗,有4种可能的情况:

情况一:同一个瞬态键:

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);

结果:每个 11 毫秒 init(...)

情况 2: 不同的临时键:

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);

结果:每个 18 毫秒 init(...)

情况三:同一个持久键:

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

结果:每个 12 毫秒 init(...)

情况4:不同的持久键:

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);

结果:每个 19 毫秒 init(...)

结论: init 与存储器类型无关,确实非常快,因为 EEPROM 仅被读取并复制到 [=25 的内部(瞬态)存储器中=] 实例。虽然我可以想象一些对时间消耗要求很高的情况,但 34 个 RAM 字节似乎太多了,无法支付 20ms。当然,在您的平台上,确切的结果可能会有所不同,但权衡效率或多或少会保持不变。