首页
社区
课程
招聘
[原创]在CRC签名中的初值出值碰撞问题
发表于: 2009-11-4 19:17 4407

[原创]在CRC签名中的初值出值碰撞问题

2009-11-4 19:17
4407
在像MD5等散列函数中,任意长度的信息都会散列为一定固定长度的散列值。
由于碰撞概率很小,且很难求逆即单向,故认为签名是合法的。

CRC当然也有如此特性,虽然很少有人重视并小瞧CRC"难登大雅",但事实确是如此。
CRC算法中的重要参数由明文密文和密钥组成,MD5中实际就是ABCD这四个数和4个非线性函数。

CRC密钥主要包括:权值、方向、初值和出值这4个。
当CRC做密码即签名时,为了不产生碰撞,必须满足明文、密文和权值等长。
故其不满足散列函数任意信息长度的要求,但绝对不会发生CRC碰撞。故签名是100%的准确。

在CRC密码中,由于明文与权值等长,故任意初值和出值非零的都可简化为初值非零出值为零的情况。

这样就完全符合CRC编解码矩阵的要求(它没出值,每个权值对应一个唯一的CRC编解码矩阵)
在其权值、方向及初值不公开时,一组明文对应于一组唯一的密文,即合法可信的签名。

假若加出值会发生些什么呢?以CRC16_ccitt为例:

多项式=左移CRC16=X16+X12+X5+1
权值=0x1021
初值=0xFFFF
出值=0x0000
简写为:CRCL16_1021_FFFF_0000

对其进行“三点攻击”:取0x0000,0x0001,0x0080
HotWC3工具自动攻击(选择CRC算法逆向功能):

输出采样值:000000010080
即0x0000,0x0001,0x0080这三个采样点

输出校验值:1D0F0D2E8C87
即:
CRCL16_1021_FFFF_0000[0x0000] = 0x1D0F
CRCL16_1021_FFFF_0000[0x0001] = 0x0D2E
CRCL16_1021_FFFF_0000[0x0080] = 0x8C87

再点击“还原”即可得到“左移CRC16逆向成功”的结果。

下面“手动”攻击:(参见CRC权值方向初值出值测试方法(破解CRC之法))

CRCL16_1021_0000_0000[0x0001] = CRCL16_1021_FFFF_0000[0x0001] ^ CRCL16_1021_FFFF_0000[0x0000] = 0x0D2E ^ 0x1D0F = 0x1021

CRCL16_1021_0000_0000[0x0080] = CRCL16_1021_FFFF_0000[0x0080] ^ CRCL16_1021_FFFF_0000[0x0000] = 0x8C87 ^ 0x1D0F = 0x9188
演算它是否为真权值:
CRCL16_1021_0000_0000[0x0080] = 0x9188 == 0x9188 故左移权值为真
CRCR16_9188_0000_0000[0x0001] = 0x1312 != 0x1021 故右移权值为假

再开始攻击初值和出值:
CRCL16_1021_FFFF_0000[0x0000] = 0x1D0F !=0 或 != 0xFFFF
故肯定其初值非零
CRCL16_1021_FFFF_0000[0xFFFF] = CRCL16_1021_0000_0000[0xFFFF] ^ CRCL16_1021_FFFF_0000[0x0000] = 0x1D0F ^ 0x1D0F = 0x0000
故其初值=0xFFFF,出值=0x0000

本来做为CRC运算攻击即可结束,但作为CRC密码或CRC签名,就必须继续攻击,以去掉出值,即令出值为零。
(本例出值已为零,下面主要演示逆向方法)

做CRC逆运算:
disCRCL16_1021_0000_0000[CRCL16_1021_FFFF_0000[0x0000]] = disCRCL16_1021_0000_0000[0x1D0F] = 0xFFFF

用CRC逆运算的结果做初值,则明文和密文的配对就是所需的初值和出值配对。
CRCL16_1021_FFFF_0000[0xFFFF] = 0x0000 初值 = 0xFFFF, 出值 = 0x0000
CRCL16_1021_FFFF_0000[0x1234] = 0x0EC9 初值 = 0x1234, 出值 = 0x0EC9
CRCL16_1021_FFFF_0000[0x3718] = 0x1234 初值 = 0x3718, 出值 = 0x1234
CRCL16_1021_FFFF_0000[0x0000] = 0x1D0F 初值 = 0x0000, 出值 = 0x1D0F

此时就会发生“CRC初值出值碰撞”,即用这些组合中任意一组做初值和出值,相同的明文必对应同样的密文,例如:

CRCL16_1021_FFFF_0000[0xABCD] = 0xD46A 初值 = 0xFFFF, 出值 = 0x0000
CRCL16_1021_1234_0EC9[0xABCD] = 0xD46A 初值 = 0x1234, 出值 = 0x0EC9
CRCL16_1021_3718_1234[0xABCD] = 0xD46A 初值 = 0x3718, 出值 = 0x1234
CRCL16_1021_0000_1D0F[0xABCD] = 0xD46A 初值 = 0x0000, 出值 = 0x1D0F

总结:
当应用于CRC密码或签名认证时,出值是没必要的,它实际不是CRC密钥的一部分。
HotWC3密码中为何出值有用,因为密钥流是滚动的,不能简化。

同时也看到了“三点攻击”的厉害之处,故多人的签名及认证码组合在一起即可攻陷
整个签名体系,故CRC做签名也是不可靠的,虽然它的签名真伪是最可信的。

为了杜绝此类现象的发生,让CRC做真的签名之用途,可再根据CRC的性质去掉初值,即初值为零。
也就是将CRC编解码矩阵简化为CRC编解码表,通常我们用到的CRC表格就是CRC编码表它没解码功能。

在权值确定时:
CRC编码矩阵[初值, 明文]=CRC编码表[初值 ^ 明文] = 密文
CRC解码矩阵[初值, 密文]=CRC解码表[密文] ^ 初值 = 明文

当初值为0时:
CRC编码矩阵[0, 明文]=CRC编码表[明文] = 密文
CRC解码矩阵[0, 密文]=CRC解码表[密文] = 明文

此时,明文和密文是成对出现且无CRC碰撞的发生,但CRC密钥(权值和方向)的长度等于明文和密文的长度。
这种认证体系无法复制签名,缺点是长度固定不能改变。而且CRCN中的N要足够大。

采用菜农的CRC四位域算法(每表16个元素)构造CRC1024也不过建表占用1024*16=16K个字节。
假若用CRC4096也不过64K个字节,对于64位的计算机不过是8K个数组单元。

我想即使是MD5也无法抗衡CRC4096的签名认证体系~~~

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//