我正在研究使用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);
答案 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
的值也是正确的。
您的十六进制编码器肯定存在问题,您的结果甚至没有达到该值的正确大小(十六进制编码的前导零会发生什么?)。根据结果和代码,我一定会看一下您的编码/解码功能。