【问题标题】:How to use CryptoJS CTR mode with variable message size (nonce counter & offset)如何使用具有可变消息大小的 CryptoJS CTR 模式(随机数计数器和偏移量)
【发布时间】:2020-04-29 15:29:38
【问题描述】:

在 AES(CTR 模式)下使用 cryptoJS 加密和解密消息时,AES 算法依赖一个随机数(Number Once)值来混淆您的流块并防止重放攻击。在cryptoJS中,设置你的nonce:

  const cli_verify = CryptoJS.AES.encrypt(CryptoJS.enc.Latin1.parse(originalString), key, {
    mode: CryptoJS.mode.CTR,
    iv: iv,
    padding: CryptoJS.pad.NoPadding
  });

同样,您可以在解密消息时使用相同的方法:

  const decryptedString = CryptoJS.AES.decrypt(encryptedStringB64, key, {
  mode: CryptoJS.mode.CTR,
    iv: iv,
    padding: CryptoJS.pad.NoPadding
  }).toString(CryptoJS.enc.Latin1); 

但是:如果您这样做,您需要自己跟踪 nonce。如果您开始处理可变大小的消息(即不是 16 字节的倍数),这 a) 很痛苦,b) 真的很困难。

我已经分解了我在另一边与之交谈的 AES 库,并弄清楚了 nonce 计数器和偏移量是如何工作的。基本上,如果您开始发送非常小的消息,例如 4 个字节,则 4 个字节将使用流的前 4 个字节进行解密,并且偏移量将增加到 4 以跟踪这一点。如果随后加密了 6 个字节,则使用流的下 6 个字节(不增加 nonce),并将偏移量更新为 10... 如果下一次传输是 143 个字节,您可以看到这开始变得复杂自己实施。使用当前流的最后 6 个字节,增加随机数等等。

我的问题是:如何让 CryptoJS 在会话期间为您处理这个问题。我尝试在第一次调用中设置 IV、填充和模式,然后在下一次将其留空,但它不起作用。它是一个很棒的图书馆,我相信它就在那里。只是不清楚如何使用它。

【问题讨论】:

    标签: javascript cryptography aes cryptojs nonce


    【解决方案1】:

    您可以改用渐进式密码 API,这确实会正确更新随机数/计数器。

    var key = CryptoJS.enc.Hex.parse("000102030405060708090a0b0c0d0e0f");
    var iv = CryptoJS.enc.Hex.parse("101112131415161718191a1b1c1d1e1f");
        
    // encrypt
    var aesEncryptor = CryptoJS.algo.AES.createEncryptor(key, {
        mode: CryptoJS.mode.CTR,
        iv: iv,
        padding: CryptoJS.pad.NoPadding
    });
    var ciphertextPart1 = aesEncryptor.process("Message Part 1");
    var ciphertextPart2 = aesEncryptor.process("Message Part 2");
    var ciphertextPart3 = aesEncryptor.process("Message Part 3");
    var ciphertextPart4 = aesEncryptor.finalize();
        ​
    // decrypt
    var aesDecryptor = CryptoJS.algo.AES.createDecryptor(key, {
        mode: CryptoJS.mode.CTR,
        iv: iv,
        padding: CryptoJS.pad.NoPadding
    });    ​
    
    var plaintextPart1 = aesDecryptor.process(ciphertextPart1);
    var plaintextPart2 = aesDecryptor.process(ciphertextPart2);
    var plaintextPart3 = aesDecryptor.process(ciphertextPart3);
    var plaintextPart4 = aesDecryptor.process(ciphertextPart4);
    var plaintextPart5 = aesDecryptor.finalize();
    

    根据https://cryptojs.gitbook.io/docs/,上面的 sn-p 最初来自哪里。

    如果您处理与块大小不匹配的输入(如您的情况),您将无法获得所有输出,直到您调用 finalize。

    您可能会发现您需要调用 finalize 以从与块大小不匹配但仍希望继续使用加密器/解密器的输入中获取输出。这个用例是需要在客户端和服务器之间同步随机数的地方。如果在输入和块大小不匹配时在 finalize 之后调用 process,则 api 不起作用。克隆 api 在块大小和输入不匹配的情况下也无法正常工作(在这种情况下,这实际上是您想要做的)。

    但是,如果您跟踪会话期间发送和接收的所有输入,则可以在调用 finalize 后重新构建会话。这可以通过在调用 finalize 以获得最终输出之前调用 process 将先前的输入重播到新的加密器/解密器中来完成。在这种情况下,在您调用 finalize 之后,您需要从输出中获取与输入中相同数量的字节,因为加密器/解密器可能包含一些先前的输出,就像输入块大小不匹配的情况一样。

    【讨论】:

      猜你喜欢
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      • 1970-01-01
      相关资源
      最近更新 更多