【问题标题】:Blowfish encryption sub-key generation河豚加密子密钥生成
【发布时间】:2009-08-31 21:27:14
【问题描述】:

好的,所以我正在 PHP 中做一个小河豚实现,作为我自己的编程练习,并更好地了解加密方法。我得到了一组有效的功能,我可以加密数据并再次解密,但我发现test vectors 不同意我的加密值......因为编码/解码似乎工作,我'我猜测错误是在我的函数设置中,将密钥应用于 P 数组和 S-box,得到一组不同的 P 值和 S-box 值,因此编码值是不同的。有人能找出我的逻辑哪里出错了吗?

对于键为 0x0000000000000000 和文本输入为 0x0000000000000000 的测试用例,第一步是将键与 P 数组进行异或,但键全为零,这将导致 P 数组保持不变,所以仍然会有它开始的 pi 的十六进制值。然后使用当前的 P 数组和 S-box 对 64 字节的文本字符串 (0x0000000000000000) 进行编码,并将结果拆分以替换 P1 和 P2。然后再次对相同的输出进行编码(使用新的 P1 和 P2 值)以获得另一个输出,用于替换 P3 和 P4。这种情况一直持续到所有 P 值和 S-box 都改变为止。执行该过程,我得到以下信息(左侧为原始值,右侧为通过密钥过程传播后的值):

P1: 243f6a88 ⇒ 99f2ff37
P2: 85a308d3 ⇒ 9ce5cb96
P3: 13198a2e ⇒ d8bf7d9a
P4: 03707344 ⇒ eba1db37
P5: a4093822 ⇒ 5954010a
P6: 299f31d0 ⇒ 2b121658
P7: 082efa98 ⇒ e7a5b7ed
P8: ec4e6c89 ⇒ 21a6717f
P9: 452821e6 ⇒ b2bb1bf8
P10: 38d01377 ⇒ 937f0244
P11: be5466cf ⇒ e111a3da
P12: 34e90c6c ⇒ 67170ab6
P13: c0ac29b7 ⇒ 5d1db61b
P14: c97c50dd ⇒ cdf63d96
P15: 3f84d5b5 ⇒ c4935141
P16: b5470917 ⇒ ad859868
P17: 9216d5d9 ⇒ 0ca32381
P18: 8979fb1b ⇒ 50964a67
S1,0: d1310ba6 ⇒ a96eceb6
S1,1: 98dfb5ac ⇒ 3480051c
S1,2: 2ffd72db ⇒ 8d315fa7
S1,3: d01adfb7 ⇒ 936c585a
S1,4: b8e1afed ⇒ cd9cd593
...
S4,251: c208e69f ⇒ cc091e06
S4,252: b74e6132 ⇒ 2e7b8ad3
S4,253: ce77e25b ⇒ dc3d8ec5
S4,254: 578fdfe3 ⇒ c52e90ab
S4,255: 3ac372e6 ⇒ e1866c06

当我使用该数据集编码 0x0000000000000000 时,我得到 0x3b8a9fa06e840430,但测试用例说我应该得到 0x4ef997456198dd78。

你能看出我哪里出错了吗?

编辑;详细加密,修复 32 位整数问题后 这是我如何解释(我认为我的程序正在解释)河豚加密发生的方式。给定一个使用 pi 的十六进制值初始化的 P 数组和 S-box 集,以及使用空键异或的 P 数组(所以它仍然相同),我执行以下操作:

0x0000000000000000输入被一分为二,左半边变成L0,右半边变成R0:

L0 = 0x00000000
R0 = 0x00000000

R1 = L0 ^ P1 = 0x00000000 ^ 0x243f6a88 = 0x243f6a88
L1 = F(R1) ^ R0 = F(0x243f6a88) ^ 0x00000000 = 0xdb2f9c4e ^ 0x00000000 = 0xdb2f9c4e

R2 = L1 ^ P2 = 0xdb2f9c4e ^ 0x85a308d3 = 0x5e8c949d
L2 = F(R2) ^ R1 = F(0x5e8c949d) ^ 0x243f6a88 = 0x33002cc0 ^ 0x243f6a88 = 0x173f4648

R3 = L2 ^ P3 = 0x173f4648 ^ 0x13198a2e = 0x426cc66
L3 = F(R3) ^ R2 = F(0x426cc66) ^ 0x5e8c949d = 0xd8a68913 ^ 0x5e8c949d = 0x862a1d8e
....

R16 = L15 ^ P16 = 0xf5e1fd40 ^ 0xb5470917 = 0x40a6f457
L16 = F(R16) ^ R15 = F(0x40a6f457) ^ 0xea27e3cc = 0x66509b85 ^ 0xea27e3cc = 0x8c777849

Now untwist and apply final P values
R_final = L16 ^ P17 = 0x8c777849 ^ 0x9216d5d9 = 0x1e61ad90
L_final = R16 ^ P18 = 0x40a6f457 ^ 0x8979fb1b = 0xc9df0f4c

Final ciphered output: 0xc9df0f4c1e61ad90, should be 0x706d9fcc1792d23a...

【问题讨论】:

  • 你会考虑位的顺序吗? (即英特尔架构的小端)
  • 如果您不知道,可以在schneier.com/blowfish-download.html 获得可能会有所启发的参考实现
  • 我已根据您的更新编辑了我的答案。
  • 非常感谢您的帮助,咖啡馆!
  • 好的,我又做了一个补充。顺便说一句,一旦问题解决,您应该尽量不要删除部分问题 - SO 的部分价值在于,遇到相同问题的其他人可以在这里找到解决方案,而无需再次询问,并删除部分问题一旦他们得到回答,问题就会有点失败。

标签: encryption blowfish


【解决方案1】:

您的加密功能有问题。这些应该是带有全零键的初始化 P 数组结果(我的 P 数组是从零开始的,但这不应该有所作为):

P0: 243f6a88 => 706d9fcc
P1: 85a308d3 => 1792d23a
P2: 13198a2e => 2db9d714
P3: 03707344 => 966e1439
P4: a4093822 => ac21a76d
P5: 299f31d0 => 8324e988
P6: 082efa98 => ac0dc9dd
P7: ec4e6c89 => 2c38f6b3
P8: 452821e6 => 70619520
P9: 38d01377 => fa23ecbe
P10: be5466cf => 17b2f676
P11: 34e90c6c => eba13a04
P12: c0ac29b7 => 8b949e61
P13: c97c50dd => 7a147caf
P14: 3f84d5b5 => 56ccc6b6
P15: b5470917 => 4461b24d
P16: 9216d5d9 => 7361e6a1
P17: 8979fb1b => 196a7c43

如果您需要一些帮助来跟踪错误,您必须发布算法在初始化的第一个加密步骤中的进展情况,其中零块使用初始 P 和 S 进行加密盒子。

附录 1:

F(0x5e8c949d) 的计算出错了 - 这应该是 0x33002cc0。不过,您的第一个 F() 是正确的 - 所以我想当您在 F() 函数中的添加溢出而不是正确包装时,就会出现问题。 This question 是关于 PHP 整数溢出的,并且在接受的答案中有一个对你有用的解决方案(事实上,他所做的计算与 Blowfish F() 函数完全相同,我认为这不是巧合;)

这是前两个F() 的计算方式:

F(0x243f6a88) =
        byte0 = 0x24, S0(byte0) = 0xe65525f3
        byte1 = 0x3f, S1(byte1) = 0x183eb331
        byte2 = 0x6a, S2(byte2) = 0x647d0862
        byte3 = 0x88, S3(byte3) = 0x4040cb08
((0xe65525f3 + 0x183eb331) ^ 0x647d0862) + 0x4040cb08
 = 0xdb2f9c4e
F(0x5e8c949d) =
        byte0 = 0x5e, S0(byte0) = 0x7d84a5c3
        byte1 = 0x8c, S1(byte1) = 0xeecea50f
        byte2 = 0x94, S2(byte2) = 0x1a6b1018
        byte3 = 0x9d, S3(byte3) = 0xbcc7d1f6
((0x7d84a5c3 + 0xeecea50f) ^ 0x1a6b1018) + 0xbcc7d1f6
 = 0x33002cc0

附录 2:

您对 F() 的实现仍然存在问题 - 这是第三次调用的运行方式:

F(0x0426cc66) =
        byte0 = 0x04, S0(byte0) = 0xb8e1afed
        byte1 = 0x26, S1(byte1) = 0x8e7d44ec
        byte2 = 0xcc, S2(byte2) = 0x1ab93d1d
        byte3 = 0x66, S3(byte3) = 0x5121ce64
((0xb8e1afed + 0x8e7d44ec) ^ 0x1ab93d1d) + 0x5121ce64
 = 0xaf099828

【讨论】:

  • 谢谢,这对于查看我应该为初始化加密达到什么目标值很有用。我编辑了我的问题以显示我目前对加密过程的了解。
  • 是的,我正在使用 dechex 函数将加法的结果转换回十六进制,这对于大数字来说是失败的。我现在得到了 F(0x5e8c949d) 的正确结果,但我得到了一个不同的、错误的整体加密结果……所以我怀疑我的 F 函数仍然有问题,或者我循环了错误的数量多次通过块循环,但我仍然找不到错误。你能再看看我更新的加密吗?
  • 成功!我的最后一个错误是我的 F 函数处理函数正在从输入的十六进制字符串中删除前导零。我很高兴第三个周期揭示了零填充问题,而不是在 16 轮之后的某个地方。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-27
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
  • 1970-01-01
  • 2011-03-25
相关资源
最近更新 更多