3

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

令我沮丧的是,我尝试了三个 twofish 实现,但没有一个与 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

我将这些解释为十六进制,因此 16bytes=128bits 长。

我尝试使用以下 twofish 实现:

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

9f589f5cf6122c32b6bfec2f2ae8c35a

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

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

f84268f0293adf4d24e27194911a24c

虽然 js 库提供:

fd803b310bb5388ddb76d5faf9e23dbe

这些都不与 KAT 中的 CT1 一致。

我在这里做错了吗?非常感谢任何帮助。

在线工具易于使用,只需确保选择 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);
4

1 回答 1

3

文件头CBC_E_M.txt内容如下:

密码块链接 (CBC) 模式 - 加密
蒙特卡洛测试

混乱可以通过这个描述来解释;来自NIST 对蒙特卡洛测试的描述:

每个蒙特卡洛测试都包含通过候选算法实现的四百万个循环。这些循环分为四百组,每组 10,000 次迭代。每次迭代都包括通过候选算法处理一个输入块,从而产生一个输出块。在迭代的第 10,000 个循环中,将新值分配给下一次迭代所需的变量。每 10,000 个加密或解密周期的结果由提交者记录并包含在适当的文件中。

因此,您在文本文件中得到 400 个结果,每个结果代表 10,000 次迭代,其中迭代的每个输入取决于先前迭代的输出。这显然与单一加密不同。蒙特卡洛测试基本上是使用随机输入执行许多测试;在这种情况下,大量的分组密码加密用于执行随机化。


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

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

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

于 2019-04-10T14:03:53.200 回答