首页
社区
课程
招聘
[求助][结贴]算法问题,大数算法,RSA
2008-10-22 18:35 7235

[求助][结贴]算法问题,大数算法,RSA

2008-10-22 18:35
7235
我这两天分析一个程序,最终找到了它验证的算法,描述如下

一个无符号常量 S = 0x2225CB63
一个大数常量    M = 0x95D9F4F67E40AD36482F82610093DDB1D1A98A65CB79AA26D5977A471917A9BAFB6C2E5C8127AEE103EA31D94C677BAA72638838A7339750683E4548CB51C1EB8F744D5E90173A56E0E85ED403FAC93FD2F13B0808076E26F3A01D24E6F04600AAF8F1EF4754B83DB35899B5DD1B92DECCCF732E6B86CB55FC2E01F2E722EFB27891F12E810A0C259C489121D63AB3903FCB71BD51C56A9DB0F57BD1E9512899CC3988796E5BAE816DA8871FE98A0175B23957CF5B2894B5A3D7D1A0B3A6A772A5F3CB1E8ECD0E1D99A0A7BA8EDC54740641D00D9EE18B657E19963B564B5DDCF25328AA5BA34A11B9B8D83F4DD882B97EB3ADD7A09F2EF19C2EE39B744A5D69

注册码也是一个大数,记为X
计算中使用一个大数变量,记为A

对 S 次高有效位开始,逐位扫描,进行循环。

S 的最高有效位为BIT29(最低位从BIT0算起),所以有以下循环,从BIT28开始扫描

for  ( A = X, int i = 27 ; i >= 0; --i )     // A初始赋值为X
{
        A = ( A * A ) % M;

        if ( ( S & ( 1 << i ) ) != 0 )           // 如果当前S当前被扫描的位为1
        {
                   A = ( A * X ) % M;
         }

}

最后得到的 A 的值,恰好为机器码的值。

以上算法已经编程验证过了,我参考了 afanty@vip.sina.com 的大数库,写了一个简单的大数算法进行验证,整个过程与调试器中原来软件的中间结果完全一致
并且用一组正确的 机器码/注册码 进行了验证,确认算法分析没有错误。

可是当我试图寻找从机器码到注册码的逆推过程时,遇到了麻烦。

外层循环,对S的逐位扫描,像是一个求指数的算法,可是我手中没有大数的指数算法,不能确认。

并且对于其中的取模运算,我不知道如何逆推。

请数学基础好,算法好的朋友指点一二。

如果不写出算法注册机,总觉得没有完成工作。

如果还需要什么信息,我可以再补充。

请务必帮忙。

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞0
打赏
分享
最新回复 (14)
雪    币: 993
活跃值: (437)
能力值: ( LV12,RANK:403 )
在线值:
发帖
回帖
粉丝
Loka 2 2008-10-22 19:12
2
0
看一下RSA实现中有一种叫反复平方乘的算法可能会有所帮助。
雪    币: 6073
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
forgot 26 2008-10-22 19:14
3
0
装一个python当计算器用吧
雪    币:
能力值: (RANK: )
在线值:
发帖
回帖
粉丝
游客 2008-10-22 20:18
4
0
按你的描述, 这个算法实际上就是计算 X^S = A(mod M), 即标准的RSA算法.
这就是计算乘方的一种算法, 好象叫加法链还是什么二元法.
雪    币: 2108
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
书呆彭 6 2008-10-22 21:51
5
0
对对对,我现在也推导到这个公式了。

原来这就是RSA算法。

另外感谢楼上几位的回答。

我现在去看RSA的资料去。

等有时间了,我把分析过程整理一下。

PS:上面的计算流程是我从IDA反汇编中,结合OD,一行一行地分析后用c++重现的,就是为了验证一下分析的正确与否。

可惜我对密码学没有了解,要不可以省多少时间啊。

还有,如果各位有好的RSA的资料,希望共享一下。

再次感谢。
雪    币: 58
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jeffcjh 2008-10-22 22:10
6
0
如果无符号常量 S = 0x1225CB63(而不是0x2225CB63),那么所提供的算法过程的确就是在计算X^S (mod M)  (即计算X的S次幂)。这是数学计算中经常采用的一种求方幂技巧,为什么可以这样进行呢?我们可以这样理解,将常量S按二进制展开:
S = b28 b27 b26 ...... b2 b1 b0
  =  ((((b28*2+b27)*2+b26)*2+ ... )*2+b2)*2+b1)*2+b0

如此一来,计算X^S的过程即转化为 (b28=1)
  X ^ (b28 b27 b26 ...... b2 b1 b0)
= X ^ (((((b28*2+b27)*2+b26)*2+ ... )*2+b2)*2+b1)*2+b0)

按照模幂运算的分配率展开,具体计算方式:
从S最高比特位开始,这里其实不用考虑对应比特是否为1。
1、首先计算 (X^2) * (X^b27) --> A;
2、再计算 (A^2) * (X^b26);
3、依此计算下去,直到b0。

所以可以认为LZ提供的计算过程是
进行模幂运算:X ^ (S-0x10000000)  mod M。
雪    币: 58
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jeffcjh 2008-10-22 22:23
7
0
LZ提出的由机器码反推注册码的问题, 可以形式化描述为:
已知次幂S、同余值A和模数M,解高次同余方程  X^S = A mod M  求出底X。

这个问题应该很容易解决:
1、解一次同余方程 S*d = 1 mod M 求出d(具体需要使用欧几里德辗转相除法);
2、在原方程 X^S = A mod M 两边同时取d次幂,即得
   X^(S*d) = X^1 = X = A^d mod M
3、按照LZ提供的方法求出A^d mod M,即为X。
雪    币: 2108
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
书呆彭 6 2008-10-22 22:27
8
0
多谢提醒,确实如你所述,我也正纳闷它为啥不从最高位开始扫描,原来是这里有一点小陷阱。

还有,因为 零次幂 是1,所以判断该位为0就不做求幂运算,我想这可能是出于效率的一种优化。
因为我发的计算过程是完全从软件中原样”扒“下来的,原来汇编代码中有这个判断,我就写了。

你所说的不用判断该位是否为1,直接用这做幂指数,虽然在数学上完全等价,但从程序来说,一个分支指令应该比求一次幂(即使幂指数是0)要更有效率吧。

谢谢你的数学解释,让我豁然开朗。

之前我感觉是在求幂,但没有数学证明,所以只有用个小点的数自己用C++验证了一下。

现在经过你的指点,已经明白了。谢谢
雪    币: 2108
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
书呆彭 6 2008-10-22 22:30
9
0
回贴的功夫,你把解法又贴上了。

太谢谢了。

我马上去试试。
雪    币: 2108
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
书呆彭 6 2008-10-23 12:55
10
0
jeffcjh兄,在你的指点下,我昨天把同余的一些知识又复习了一下,发现你给的解法有一些错误,所以这个问题又卡住了。

错误之处在于,由 S * d = 1 mod M,
推不出 X ^( S * d ) = X ^1 mod M,

应该是这样的
若 X ^ k = 1 mod M,   而 S * d = 1 mod k, 才能推出 X ^ ( S * d ) = X ^ 1 mod M

但目前X是待求的值,那么k值更无法求得了。

另外,还有之前那个求幂的算法描述,我仔细推导了一下,不是 X ^ (S-0x10000000)  mod M,而就是 X ^ S mod M
这只是个细节问题,小问题而已,不过我还是指出来一下,不是有意挑刺。推导如下(为了看得更清楚,我用了数学里的圆括号,方括号和花括号,而不是程序中的只有圆括号):

以 S = B3 B2 B1 B0 = [ ( B3 * 2 + B2 ) * 2 + B1 ] * 2 + B0 为例,
X ^ B
= X ^ { [ ( B3 * 2 + B2 ) * 2 + B1 ] * 2 + B0 }
= X ^ B0 * { X ^ [ ( B3 * 2 + B2 ) * 2 + B1 ] } ^ 2
= X ^ B0 * { X ^ B1 * [ X ^ ( B3 * 2 + B2 ) ] ^ 2 } ^ 2
= X ^ B0 * { X ^ B1 * [ X ^ B2 * ( X ^ B3 ) ^ 2 ] ^ 2 } ^ 2

可以看到,幂指数有4位,但平方运算有3次,因为最低位B0没有平方。而算法中的迭代过程,之所以从次高位开始扫描,因为最高有效位必为1,即 上式中的 B3 必为1,而第一次循环中要判断的是 B2是否为0。

见笑了。我数学很差的,以上过程完全是受 jeffcjh 大哥的指点才有所了解。

现在还没有想出解法,所以还需要各位朋友的帮助。
雪    币: 58
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jeffcjh 2008-10-23 21:03
11
0
关于由机器码反推注册码的问题,我觉得LZ可能理解错了,我重新表述一遍吧:
问题可以形式化描述为:
已知次幂S、同余值A和模数M,解高次同余方程  X^S = A mod M  即可求出底X。
具体解法如下:

1、解同余方程 S*d = 1 mod M,即可求出d。这可以直接利用afanty提供的小程序做到;
2、按照LZ提供的算法求出A^d mod M;
3、在原方程 X^S = A mod M 两边同时取d次幂,可以作如下推导:
         (X^S)^d = A^d  mod M
    即     X^(S*d) = A^d  mod M
    因为   S*d = 1 mod M,故有
          X = A^d mod M

    而在第2步中已求出 A^d mod M,故X即得。

   (X^S)^d = X^(S*d) = X^1 = X = A^d  mod M
   此时即得X。
雪    币: 2108
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
书呆彭 6 2008-10-24 01:44
12
0
你确实错了。

S * d = 1 mod M,不能得到 X ^ ( S * d ) = X ^ 1 mod M

所以用你的方法计算不到X,只是 X ^ ( S * d )

我如果没说明白你自己算算,用你的算法得到的 X 再算回 A 是错的。
或者我举个小一点数字的反例吧。数字小是为了好计算,说明问题

反例:

比如假定 M = 15, S = 7,A = 8,方程是 X ^ 7 = 8 mod 15

在你描述的方法中,解得最小正整数d = 13,这一步理解对你的算法没有错误吧。

那么d * S = 91 = 1 mod 15,

所以 X ^ 91 =  A ^ 13 = 8 * 64 ^ 6 = 8 * 4 ^ 6 = 8  mod 15
方程化成这样了

根据你的描述,可以得到 X = 8 mod 15,

但实际上,满足这X = 8 mod 15的X 并不就是 X ^ 91 = 8 mod 15,或者原方程 X ^ 7 = 8 mod 15 的解

比如就取 X = 8 ,
有 8 ^ 91= 8 * 64 ^ 45 = 8 * 4 ^ 45 = 8 * 4 * 16 ^ 22 = 32 = 2 mod 15
而并不满足 X ^ 91 = 8 mod 15

同样也不满足原来的方程 X ^ S = A mod M,即 X ^ 7 = 8 mod 15

因为这个例子我是从正向构造的,所以我知道这个期望的解是 X = 2, 可以验证 2 ^ 7 = 128 = 8 mod 15

所以你的算法中,条件 d * S = 1 mod M是不对的。

我上面已经说过了,如果X是已知的,并且 X ^ k = 1 mod M,那么从
d * S = 1 mod k
可以得到 X ^ ( d * S ) = X ^ 1 mod M

而你错在了上面红字的k换成了M,因为 d * S 是在 X 的指数上,而 X ^ M 根本就没有意义。因此结论也是错的。

虽然你帮了我很大的忙,不过错了就是错了,我需要说清楚。

好了,又是一整个晚上,我看了许多RSA的算法的资料,明白了RSA算法的解密依赖于大数的因数分解。

当 M 很小时,比如例子中 M =15,可以直接分解为 3 * 5,那么解密的 私钥应该由 S * d = 1 mod ( 2 * 4 )来算,正确的d应该是7
而不是你的描述中的 由 S * d = 1 ( 15 ) 得到的 d =13.

可以验证用d=7对我举的例子进行解密是正确的。

可能jeffcjh兄对RSA算法也没完全搞清楚,完全从数学方面得出的这个解法,所以有些错误。

明天继续学习数学,呵呵。

再次感谢jeffcjh对这个问题的关注。我会继续学习的。
雪    币: 58
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jeffcjh 2008-10-24 20:03
13
0
我原来的说法有点问题,谢谢LZ的指出。

现在进行修正后给出正确答案:
问题描述:
已知次幂S、同余值A和模数M,
解同余方程  X^S = A mod M  即求底X。

具体解法:

1、解同余方程 S*d = 1 mod Ф(M),即可求出d。这里Ф表示欧拉函数;
2、按照LZ提供的算法求出A^d mod M;
3、在原方程 X^S = A mod M 两边同时取d次幂,可以作如下推导:
         (X^S)^d = A^d  mod M
    即     X^(S*d) = A^d  mod M
    因为   S*d = 1 mod Ф(M),
   根据欧拉定理,可得
          X = X^(S*d) = A^d  mod M
    而在第2步中已求出 A^d mod M,故X即得。

我原来的解法错在第1步,修改为
   解同余方程 S*d = 1 mod Ф(M)
即可成立。

再次谢谢LZ的指正。
雪    币: 2108
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
书呆彭 6 2008-10-24 21:21
14
0
不用客气,我还要感谢你帮我把问题用数学语言描述出来。

我也是在你的帮助之后,复习了一下同余的相关知识,之前仅在高中数学竞赛时略学过一点点,现在早已忘光了。

这个问题我已经完全明白了。RSA加密算法。想要解密的可能性是不大了。
不过从这个东西我又学了很多知识。

就此结贴了。
谢谢所有关注和提供帮助的朋友。
雪    币: 203
活跃值: (73)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
davidhee 2008-10-25 14:08
15
0
这样的讨论真的是很不错,学到不少知识。
游客
登录 | 注册 方可回帖
返回