2015-04-02 102 views
2

我知道在AES計數器模式下,我需要使用128位隨機數。最簡單的方法是使用隨機的128位隨機數,但我不確定如果算法作爲所有隨機位傳遞,算法將無法正確增加計數器。我認爲正確的方式做它是使用一個96位的隨機數也從0開始,32位計數器,例如:爲AES-CTR模式正確使用隨機數和計數器

var key = CryptoJS.enc.Hex.parse('01ab23cd45ef67089a1b2c3d4e5f6a7b'); // 128 bits/16 bytes 
var nonce = '2301cd4ef785690a1b2c3dab'; // 96 bits/12 bytes 
var counter = '00000000'; // 32 bits/4 bytes 
var nonceAndCounter = nonce + counter; 
    nonceAndCounter = CryptoJS.enc.Hex.parse(nonceAndCounter); 
var plaintext = 'The quick brown fox jumps over the lazy dog.'; 

var encryption = CryptoJS.AES.encrypt(plaintext, key, { iv: nonceAndCounter, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding }); 
var ciphertext = encryption.ciphertext.toString(CryptoJS.enc.Hex); 

這與CryptoJS library做正確的方法是什麼?或者什麼是正確的方法?

回答

3

當我去挖掘庫代碼以查看它的真實含義時,我將回答我自己的問題。

摘要:

答案是你可以使用兩種方法,它將按預期工作:

1)通行證在96位長的隨機數和庫本身會自動添加32位計數器,並在生成每個密鑰流塊時增加它。例如。

var nonce = CryptoJS.enc.Hex.parse('2301cd4ef785690a1b2c3dab'); // 12 Bytes 
var encryption = CryptoJS.AES.encrypt(plaintext, key, { iv: nonce, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding }); 

2)通在長度爲96位,並明確一個隨機數指定的32位計數器,以及如果你想。如果您想從第9個塊開始加密/解密,您甚至可以指定一個像00000009這樣的計數器。

var nonce = '2301cd4ef785690a1b2c3dab'; // 12 Bytes 
var counter = '00000000';    // 4 Bytes, start at counter 0 
var nonceAndCounter = CryptoJS.enc.Hex.parse(nonce + counter); // 16 Bytes 
var encryption = CryptoJS.AES.encrypt(plaintext, key, { iv: nonceAndCounter, mode: CryptoJS.mode.CTR, padding: CryptoJS.pad.NoPadding }); 

說明::下面是一個例子,從計數器0開始

在與00000000 32位計數器的問題使用代碼,相關的代碼是在該文件中mode-ctr.js

/** 
* Counter block mode. 
*/ 
CryptoJS.mode.CTR = (function() { 
    var CTR = CryptoJS.lib.BlockCipherMode.extend(); 

    var Encryptor = CTR.Encryptor = CTR.extend({ 
     processBlock: function (words, offset) { 
      // Shortcuts 
      var cipher = this._cipher 
      var blockSize = cipher.blockSize; 
      var iv = this._iv; 
      var counter = this._counter; 

      // Generate keystream 
      if (iv) { 
       counter = this._counter = iv.slice(0); 

       // Remove IV for subsequent blocks 
       this._iv = undefined; 
      } 
      var keystream = counter.slice(0); 
      cipher.encryptBlock(keystream, 0); 

      // Increment counter 
      counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0 

      // Encrypt 
      for (var i = 0; i < blockSize; i++) { 
       words[offset + i] ^= keystream[i]; 
      } 
     } 
    }); 

    CTR.Decryptor = Encryptor; 

    return CTR; 
}()); 

當使用斷點在瀏覽器JS調試器中運行此代碼時,它將nonceAndCounter轉換爲WordArray缺點32種元素的isting:

[587320654, -142251766, 455884203, 0]

這被用來加密一個塊。要加密的下一個塊運行這一行:

counter[blockSize - 1] = (counter[blockSize - 1] + 1) | 0

其評估採取counter[3]元件即整數0和它遞增到:

[587320654, -142251766, 455884203, 1]

隨着後續塊和隨機數我可以看到...

[587320654, -142251766, 455884203, 2]

[587320654, -142251766, 455884203, 3]

[587320654, -142251766, 455884203, 4]

等。所以它似乎以這種方式正確工作。

如果你傳遞一個128位的隨機隨機數,例如:

var nonceAndCounter = CryptoJS.enc.Hex.parse('2301cd4ef785690a1b2c3dabdf99a9b3');

這產生的隨機數:

[587320654, -142251766, 455884203, -543577677, 0]

所以它產生5的數組元素!?然後,該函數將第四個元素從​​-543577677增加到-543577676,然後-543577675,然後-543577674等等。所以它仍然以某種方式工作,但是從0開始的增量並不會很好,並且可能更容易出錯。

當我傳入一個96位隨機數時,庫自動將計數器數組0加到計數器數組的末尾,併爲後續數組正確地加1。例如

[587320654, -142251766, 455884203, 0] 
[587320654, -142251766, 455884203, 1] 
[587320654, -142251766, 455884203, 2] 
+0

因此,看起來你不需要明確設置計數器,因爲CryptoJS會自動爲你添加它。它可能檢查最後一個單詞是否已經是0.另外,CTR模式沒有IV,它被稱爲隨機數。 – 2015-04-03 11:10:34

+0

「另外,CTR模式沒有IV,它被稱爲隨機數。」注意,謝謝。 「所以,你似乎不需要明確地設置計數器,因爲CryptoJS會自動爲你添加它。」是的,我測試了這一點,只是傳入一個96位隨機數,它自動將起始計數器加爲0到'counter'數組的末尾,例如'[587320654,-142251766,455884203,0]'並正確遞增。非常感謝Artjom的迴應。對不起,我標記了你的名字,因爲我看到你的名字附加到了其他一些CryptoJS答案中,並且我認爲你對這個圖書館非常瞭解。 – seatosum 2015-04-04 05:11:29

+0

添加了一個總結,謝謝Artjom! – seatosum 2015-04-05 21:10:55