MATLAB实现PRESENT密码时密钥更新错误导致加解密异常
我帮你梳理下PRESENT密码密钥更新模块的常见问题,结合你给出的测试密钥和预期轮密钥来一步步排查:
你使用的测试密钥是'00000 00000 00000 00000'(去掉空格后是20个十六进制0,对应80位全0密钥),先对齐PRESENT-80的官方密钥更新步骤:
给定当前80位密钥 ( K = k_{79}k_{78}...k_0 )(( k_{79} )是最高位,( k_0 )是最低位),每轮密钥更新需执行:
- 循环左移64位:将密钥变为 ( k_{15}k_{14}...k_0 k_{79}k_{78}...k_{16} )(把原密钥的低16位移到最高位,高64位移到低位)
- S盒替换:取新密钥的最高4位(( k_{15}k_{14}k_{13}k_{12} )),用PRESENT标准S盒替换。S盒映射为:
( S = [0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2] )(输入0-15对应输出S[x+1],MATLAB是1索引)- 轮计数器异或:将轮计数器( i )(1≤i≤31,5位二进制)与新密钥的第19-15位(( k_{19}k_{18}k_{17}k_{16}k_{15} ))异或
- 本轮轮密钥是更新后密钥的最高64位(( k_{79}...k_{16} ))
结合你的测试用例,初始全0密钥的预期结果完全符合这个流程:
- Round1轮密钥:初始密钥的最高64位,即全0
- Round2轮密钥:第一次更新后,最高4位被S盒替换为0xc,其余高位仍为0,即
c000000000000000
1. 密钥存储与位序错误
- 如果你用字符串存储密钥,务必先去掉空格,转换为统一的十六进制或二进制格式,比如把
'00000 00000 00000 00000'转为'00000000000000000000' - 核心错误点:位序是否和标准一致?比如你是否把最高位存在数组的第一个元素,还是最后一个?如果位序搞反,循环左移、S盒替换的位置全错。
2. 循环左移64位实现错误
对于80位二进制数组K(K(1)是最高位(k_{79}),K(80)是最低位(k_0)),正确的循环左移64位代码是:
K = [K(65:80), K(1:64)]; % 把原低16位移到高位,原高64位移到低位
如果你写成[K(1:64), K(65:80)],相当于循环右移,完全不符合要求。
3. S盒替换的索引错误
MATLAB数组是1索引,而S盒输入是0-15的十进制数,所以正确的替换逻辑是:
S = [0xc, 0x5, 0x6, 0xb, 0x9, 0x0, 0xa, 0xd, 0x3, 0xe, 0xf, 0x8, 0x4, 0x7, 0x1, 0x2]; top4_dec = bi2de(K(1:4), 'left-msb'); % 把最高4位二进制转十进制 top4_new_dec = S(top4_dec + 1); % 加1适配1索引 K(1:4) = de2bi(top4_new_dec, 4, 'left-msb'); % 转回二进制替换
如果直接用S(top4_dec),会导致索引越界或映射错误。
4. 轮计数器异或的位置错误
轮计数器是5位二进制,要异或到密钥的第19-15位(对应数组的K(16:20),因为K(1)是(k_{79})),正确代码示例:
i = 1; % 对应生成Round2的轮密钥 counter_bin = de2bi(i, 5, 'left-msb'); K(16:20) = xor(K(16:20), counter_bin);
如果异或位置错了,后续轮密钥的低位部分会不符合预期(比如Round3的0000000000000001部分)。
5. 整数操作的符号问题
如果你用uint64或uint128存储密钥,务必用无符号整数类型,避免有符号整数的符号位扩展导致循环左移错误。推荐用二进制数组处理每一位,更直观不易出错。
把密钥更新每一步的中间结果打印出来,比如循环左移后的密钥、S盒替换后的密钥、轮计数器异或后的密钥,和手动计算的结果对比,就能快速定位哪一步偏离了预期。
内容的提问来源于stack exchange,提问作者Zeeshan Haider

