双鱼已知答案测试

Twofish known answer test

我正在研究使用 twofish 来加密数据字符串。在将我宝贵的数据托付给一个未知的图书馆之前,我希望验证它是否与 Bruce Schneier 网站上发布的 known answer tests 一致。

令我沮丧的是,我尝试了三个 twofish 实现并发现 none 与 KAT 一致。这让我相信我做错了什么,我想知道是否有人可以告诉我它是什么。

我已确定模式相同 (CBC),密钥长度相同(128 位)并且 iv/key/pt 值相同。 twofish 加密是否有额外的参数?

这是来自 KAT 档案 CBC_E_M.txt 的前两个测试条目:

I=0
KEY=00000000000000000000000000000000
IV=00000000000000000000000000000000
PT=00000000000000000000000000000000
CT=3CC3B181E1495D0495D652B66921DA0F

I=1
KEY=3CC3B181E1495D0495D652B66921DA0F
IV=3CC3B181E1495D0495D652B66921DA0F
PT=BE938D30FAB43B71F2E114E9C0529299
CT=695250B109C6F71D410AC38B0BBDA3D2

我将这些解释为十六进制,因此 16 字节 = 128 位长。

我尝试使用以下双鱼实现:

第一次测试三个都给出相同的CT,即(十六进制编码)

9f589f5cf6122c32b6bfec2f2ae8c35a

到目前为止一切顺利,除了它与 KAT 中的 CT0 不一致...

对于第二次测试,ruby 库和在线工具给出:

f84268f0293adf4d24e27194911a24c

而 js 库给出:

fd803b310bb5388ddb76d5faf9e23dbe

而且这些都不符合 KAT 中的 CT1。

我是不是做错了什么?非常感谢任何帮助。

在线工具很容易使用,只需确保 select HEX 键和输入文本即可。这是我用来生成这些值的 ruby 代码(必须检查每个库才能正常工作):

def twofish_encrypt(iv_hex, key_hex, data_hex)
  iv = iv_hex.gsub(/ /, "").scan(/../).map { |x| x.hex.chr }.join
  key = key_hex.gsub(/ /, "").scan(/../).map { |x| x.hex.chr }.join
  data = data_hex.gsub(/ /, "").scan(/../).map { |x| x.hex.chr }.join

  tf = Twofish.new(key, :mode => :cbc, :padding => :none)
  tf.iv = iv
  enc_data = tf.encrypt(data)
  enc_data.each_byte.map { |b| b.to_s(16) }.join
end

ct0 = twofish_encrypt("00000000000000000000000000000000",
                      "00000000000000000000000000000000",
                      "00000000000000000000000000000000")
puts "ct0: #{ct0}"
ct1 = twofish_encrypt("3CC3B181E1495D0495D652B66921DA0F",
                      "3CC3B181E1495D0495D652B66921DA0F",
                      "BE938D30FAB43B71F2E114E9C0529299")
puts "ct1: #{ct1}"
function twofish_encrypt(iv_hex, key_hex, data_hex) {
    var iv = new BinData()                             
    iv.setHexNibbles(iv_hex)
    iv.setlength(16*8)
    binkey = new BinData()
    binkey.setHexNibbles(key_hex)
    binkey.setlength(16*8)
    key = new TwoFish.Key(binkey);

    data = new BinData()
    data.setHexNibbles(data_hex)
    data.setlength(16*8)

    cipher = new TwoFish.Cipher(TwoFish.MODE_CBC, iv);
    enc_data = TwoFish.Encrypt(cipher, key, data);

    return enc_data.getHexNibbles(32);
}

var ct0 = twofish_encrypt("00000000000000000000000000000000",
                          "00000000000000000000000000000000",
                          "00000000000000000000000000000000");
console.log("ct0: " + ct0);

var ct1 = twofish_encrypt("3CC3B181E1495D0495D652B66921DA0F",
                          "3CC3B181E1495D0495D652B66921DA0F",
                          "BE938D30FAB43B71F2E114E9C0529299");
console.log("ct1: " + ct1);

CBC_E_M.txt 文件的 header 内容为:

Cipher Block Chaining (CBC) Mode - ENCRYPTION
Monte Carlo Test

这个描述可以解释混乱;来自 NIST description of the Monte Carlo Tests:

Each Monte Carlo Test consists of four million cycles through the candidate algorithm implementation. These cycles are divided into four hundred groups of 10,000 iterations each. Each iteration consists of processing an input block through the candidate algorithm, resulting in an output block. At the 10,000th cycle in an iteration, new values are assigned to the variables needed for the next iteration. The results of each 10,000th encryption or decryption cycle are recorded and included by the submitter in the appropriate file.

所以您在文本文件中得到的是 400 个结果,每个结果代表 10,000 次迭代,其中迭代的每个输入都取决于先前迭代的输出。这显然和单次加密不一样。 Monte Carlo 测试基本上是使用随机输入执行许多测试;在这种情况下,大量的块密码加密用于执行随机化。


要测试您的 CBC 代码是否正确,只需使用任何其他测试向量(不是 Monte Carlo 向量)并假设一个全零 IV。在这种情况下,单个块 (ECB) 加密具有与 CBC 模式相同的结果。这也适用于越来越流行的 CTR 模式。

您找到的初始 9f589f5cf6122c32b6bfec2f2ae8c35a 值对于 128 位全零密钥、IV 和明文是正确的。 f84268f0293adf4d24e27194911a24c 值也是正确的。

您的十六进制编码器肯定有问题,您的结果甚至不是该值的正确大小(十六进制编码的前导零会发生什么情况?)。鉴于结果和代码,我一定会看看你的编码/解码函数。