Twofish已知答案测试

时间:2019-04-09 20:47:27

标签: cryptography block-cipher twofish

我正在研究使用twofish来加密数据字符串。在将我的宝贵数据信任到一个未知的库之前,我想验证一下它是否与在Bruce Schneier网站上发布的known answer tests一致。

令我沮丧的是,我尝试了三种twofish实现,但发现没有一个与KAT相符。这使我相信我做错了事,我想知道是否有人可以告诉我这是什么。

我确保模式相同(CBC),密钥长度相同(128bits),并且iv / key / pt值相同。双向鱼加密是否还有其他参数?

以下是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。

我在这里做错什么了吗?任何帮助表示赞赏。

在线工具易于使用,只需确保选择十六进制作为键并输入文本即可。这是我用来生成这些值的红宝石代码(必须检查每个库才能起作用):

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

1 个答案:

答案 0 :(得分:2)

CBC_E_M.txt文件的标题为:

  

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

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

  

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

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


要测试您的CBC代码是否正确,只需使用任何其他测试矢量(不是蒙特卡洛矢量),并假设全零IV。在这种情况下,单个块(ECB)加密的结果与CBC模式相同。这也适用于越来越流行的点击率模式。

您发现的初始9f589f5cf6122c32b6bfec2f2ae8c35a值对于128位全零键,IV和纯文本是正确的。 f84268f0293adf4d24e27194911a24c的值也是正确的。

您的十六进制编码器肯定存在问题,您的结果甚至没有达到该值的正确大小(十六进制编码的前导零会发生什么?)。根据结果​​和代码,我一定会看一下您的编码/解码功能。