【问题标题】:Using a single Cipher object or two different objects for decrypt and encrypt operations?使用单个 Cipher 对象或两个不同的对象进行解密和加密操作?
【发布时间】:2016-05-04 02:57:11
【问题描述】:

如您所知,当我们想使用 Java Card 进行加密操作时,我们必须使用 Cipher 对象。我的问题实际上与效率有关。假设我想使用 AES 密钥进行一些 加密解密 操作。

以下哪种策略更好?

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

【问题讨论】:

    标签: java cryptography javacard


    【解决方案1】:

    首先,根据Cipher.doFinal(...)的文档:

    CBC 模式下的 AES、DES、三重 DES 和韩语 SEED 算法重置 初始向量(IV)为0。初始向量(IV)可以重新初始化 使用init(Key, byte, byte[], short, short) 方法。

    这意味着如果你使用非零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);
    

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

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

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

    情况3:相同的持久键:

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

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

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

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

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

    【讨论】:

    • 好 erfforts 选择确切的时间 vojta!尽管如此,如果您使用 IV=0,您仍然可以从持久密钥数据中受益。我认为这是一个有效的案例......
    • 我想知道这是否只是你代码行中的一个错字,总是只有一个cipher 而不是cipher1cipher2?
    • @PaulBastian 是的,但是你只能获得大约 20 毫秒的时间......这对于 34 字节的 RAM 来说足够了吗?我不这么认为......
    • @EbraHim 正如 Paul 所说,这取决于您的偏好......但是,RSA 需要比 AES 更多的 RAM,因此只需一个 Cipher 实例似乎是合理的。
    • @mjaggard 这是一个 Java Card 问题。当然,在限制较少的平台上情况就完全不同了。
    【解决方案2】:

    这取决于您是在处理持久密钥材料还是临时密钥材料。
    如果您有永久密钥材料:

    • 选项 1 需要更多 EEPROM,但您可以显着延长时间,因为在生成或导入密钥材料时只调用一次 init()
    • 因此选项 2 不可取

    如果您有临时密钥材料:

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

    【讨论】:

      猜你喜欢
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多