分享
 
 
 

RSA与大数运算

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

RSA与大数运算

==========================================================================

前言:此文来自于www.pediy.com一位Cracker---afanty之手。他建立了一个VC++(MFC)版的大数运算库。用Delphi的朋友们请到http://ace.ulyssis.student.kuleuven.ac.be/~triade/去下载Pascal的GInt大数运算库。当然,所有基于大素数分解难题的公开密匙算法都可以使用这两个库。不过请你小心里面可能存在的Bug... :)

--- Crossbow

==========================================================================

基于以下原因,俺估计RSA算法会被越来越多的共享软件采用:

1、原理简洁易懂

2、加密强度高

3、专利限制已过期

4、看雪老大三番五次呼吁共享软件采用成熟的非对称加密技术

所以,大家应该对RSA算法进行深入了解。

俺写了一个简单易懂的大数运算库,并使用该库作了一个RSA Demo,大家可以使用这一

Demo生成真正随机的、各种长度的RSA 密钥对。其中生成1024位的RSA 密钥耗时不超过

五分钟,而对1024位以内的密文进行解密则不超过三秒钟,应该是可以接受的。

有一点需要说明的是,假如类似于这个Demo的RSA工具被共享软件作者广泛用于注册码

的生成与验证,俺认为Cracker们的日子就会过得很无趣了,唉!

RSA 依赖大数运算,目前主流RSA 算法都建立在512 位到1024位的大数运算之上,所以

我们在现阶段首先需要掌握1024位的大数运算原理。

大多数的编译器只能支持到64位的整数运算,即我们在运算中所使用的整数必须小于等

于64位,即:0xffffffffffffffff,也就是18446744073709551615,这远远达不到RSA

的需要,于是需要专门建立大数运算库来解决这一问题。

最简单的办法是将大数当作字符串进行处理,也就是将大数用10进制字符数组进行表示,

然后模拟人们手工进行“竖式计算”的过程编写其加减乘除函数。但是这样做效率很低,

因为1024位的大数其10进制数字个数就有数百个,对于任何一种运算,都需要在两个有

数百个元素的数组空间上做多重循环,还需要许多额外的空间存放计算的进位退位标志

及中间结果。当然其优点是算法符合人们的日常习惯,易于理解。

另一种思路是将大数当作一个二进制流进行处理,使用各种移位和逻辑操作来进行加减

乘除运算,但是这样做代码设计非常复杂,可读性很低,难以理解也难以调试。

于是俺琢磨了一种介于两者之间的思路:

将大数看作一个n进制数组,对于目前的32位系统而言n可以取值为2的32次方,即0x100

00000,假如将一个1024位的大数转化成0x10000000 进制,它就变成了32位,而每一位

的取值范围就不是0-1或0-9,而是0-0xffffffff。我们正好可以用一个无符号长整数来

表示这一数值。所以1024位的大数就是一个有32个元素的unsigned long数组。而且0x1

00000000进制的数组排列与2 进制流对于计算机来说,实际上是一回事,但是我们完全

可以针对unsigned long 数组进行“竖式计算”,而循环规模被降低到了32次之内,并

且算法很容易理解。

例如大数18446744073709551615,等于“ffffffff ffffffff”,它就相当于10

进制的“99”:有两位,每位都是ffffffff。而大数18446744073709551616,等于“00000001

00000000 00000000”,它就相当于10进制的“100”:有三位,第一位是1 ,其它两位

是0。如果我们要计算18446744073709551616-18446744073709551615,就类似于100-99:

00000001 00000000 00000000

- ffffffff ffffffff

-----------------------------

= 0 0 1

当然,因为在VC里面存在一个__int64类型可以用来计算进位与借位值,所以将大数当作

0x100000000进制进行运算是可能的,而在其他编译系统中如果不存在64位整形,则可以

采用0x40000000进制,由于在0x40000000进制中,对任何两个“数字”进行四则运算,

结果都在0x3fffffff*03fffffff之间,小于0xffffffff,都可以用一个32位无符号整数

来表示。

/****************************************************************/

file://大数运算库头文件:BigInt.h

file://作者:afanty@vip.sina.com

file://版本:1.0 (2003.4.26)

file://说明:适用于MFC

/****************************************************************/

#define BI_MAXLEN 40

#define DEC 10

#define HEX 16

class CBigInt

{

public:

int m_nSign; file://记录大数的符号,支持负值运算

int m_nLength; file://记录0x10000000进制的位数,0-40之间,相当于2进制的0-1280位

unsigned long m_ulvalue[BI_MAXLEN]; file://记录每一位的“数字”

CBigInt();

~CBigInt();

file://将大数赋值为另一个大数

CBigInt& Mov(CBigInt& A);

file://将大数赋值为编译器能够理解的任何整形常数或变量

CBigInt& Mov(unsigned __int64 A);

file://比较两个大数大小

int Cmp(CBigInt& A);

file://计算两个大数的和

CBigInt Add(CBigInt& A);

file://重载函数以支持大数与普通整数相加

CBigInt Add(long A);

file://计算两个大数的差

CBigInt Sub(CBigInt& A);

file://重载函数以支持大数与普通整数相减

CBigInt Sub(long A);

file://计算两个大数的积

CBigInt Mul(CBigInt& A);

file://重载函数以支持大数与普通整数相乘

CBigInt Mul(long A);

file://计算两个大数的商

CBigInt Div(CBigInt& A);

file://重载函数以支持大数与普通整数相除

CBigInt Div(long A);

file://计算两个大数相除的余数

CBigInt Mod(CBigInt& A);

file://重载函数以支持大数与普通整数相除求模

long Mod(long A);

file://将输入的10进制或16进制字符串转换成大数

int InPutFromStr(CString& str, const unsigned int system);

file://将大数按10进制或16进制格式输出到字符串

int OutPutToStr(CString& str, const unsigned int system);

file://欧几里德算法求:Y=X.Euc(A),使满足:YX mod A = 1

CBigInt Euc(CBigInt& A);

file://蒙哥马利算法求:Y=X.Mon(A,B),使满足:X^A mod B = Y

CBigInt Mon(CBigInt& A, CBigInt& B);

};

注意以上函数的声明格式,完全遵循普通整数运算的习惯,例如大数

Y=X+Z 相当于 Y.Mov(X.(Add(Z)),这样似乎没有Mov(Y,Add(X,Z))

看起来舒服,但是一旦我们重载运算符“=”为“Mov”,“+”为“Add”,

则Y.Mov(X.(Add(Z))的形式就等价于 Y=X+Z。

俺不知道其他编程语言里是否支持运算浮重载,至少这样定义函数格式

在C++里可以带来很大的方便。

下面让我们来实现大数类的主要成员函数:

/****************************************************************/

file://大数运算库源文件:BigInt.cpp

file://作者:afanty@vip.sina.com

file://版本:1.0 (2003.4.26)

file://说明:适用于MFC

/****************************************************************/

#include "stdafx.h"

#include "BigInt.h"

file://初始化大数为0

CBigInt::CBigInt()

{

m_nSign=1;

m_nLength=1;

for(int i=0;i<BI_MAXLEN;i++)m_ulvalue[i]=0;

}

file://采用缺省的解构函数

CBigInt::~CBigInt()

{

}

file://大数比较,如果大数A位数比大数B多,当然A>B

file://如果位数相同,则从高位开始比较,直到分出大小

int CBigInt::Cmp(CBigInt& A)

{

if(m_nLength>A.m_nLength)return 1;

if(m_nLength<A.m_nLength)return -1;

for(int i=m_nLength-1;i>=0;i--)

{

if(m_ulvalue[i]>A.m_ulvalue[i])return 1;

if(m_ulvalue[i]<A.m_ulvalue[i])return -1;

}

return 0;

}

file://照搬参数的各属性

CBigInt& CBigInt::Mov(CBigInt& A)

{

m_nLength=A.m_nLength;

for(int i=0;i<BI_MAXLEN;i++)m_ulvalue[i]=A.m_ulvalue[i];

return *this;

}

file://大数相加

file://调用形式:N.Add(A),返回值:N+A

file://若两大数符号相同,其值相加,否则改变参数符号再调用大数相减函数

/******************************************************************/

例如:

A B C

+ D E

--------------

= S F G H

其中,若C+E<=0xffffffff,则H=C+E,carry(进位标志)=0

若C+E>0xffffffff,则H=C+E-0x100000000,carry=1

若B+D+carry<=0xfffffff,则G=B+D,carry=0

若B+D+carry>0xfffffff,则G=B+D+carry-0x10000000,carry=1

若carry=0,则F=A,S=0

若carry=1,A<0xfffffff,则F=A+1,S=0

若carry=1,A=0xfffffff,则F=0,S=1

/*****************************************************************/

CBigInt CBigInt::Add(CBigInt& A)

{

CBigInt X;

if(X.m_nSign==A.m_nSign)

{

X.Mov(*this);

int carry=0;

unsigned __int64 sum=0;

if(X.m_nLength<A.m_nLength)X.m_nLength=A.m_nLength;

for(int i=0;i<X.m_nLength;i++)

{

sum=A.m_ulvalue[i];

sum=sum+X.m_ulvalue[i]+carry;

X.m_ulvalue[i]=(unsigned long)sum;

if(sum>0xffffffff)carry=1;

else carry=0;

}

if(X.m_nLength<BI_MAXLEN)

{

X.m_ulvalue[X.m_nLength]=carry;

X.m_nLength+=carry;

}

return X;

}

else{X.Mov(A);X.m_nSign=1-X.m_nSign;return Sub(X);}

}

file://大数相减

file://调用形式:N.Sub(A),返回值:N-A

file://若两大数符号相同,其值相减,否则改变参数符号再调用大数相加函数

/******************************************************************/

例如:

A B C

- D E

--------------

= F G H

其中,若C>=E,则H=C-E,carry(借位标志)=0

若C<E,则H=C-E+0x100000000,carry=1

若B-carry>=D,则G=B-carry-D,carry=0

若B-carry<D,则G=B-carry-D+0x10000000,carry=1

若carry=0,则F=A

若carry=1,A>1,则F=A-1

若carry=1,A=1,则F=0

/*****************************************************************/

CBigInt CBigInt::Sub(CBigInt& A)

{

CBigInt X;

if(m_nSign==A.m_nSign)

{

X.Mov(*this);

int cmp=X.Cmp(A);

if(cmp==0){X.Mov(0);return X;}

int len,carry=0;

unsigned __int64 num;

unsigned long *s,*d;

if(cmp>0)

{

s=X.m_ulvalue;

d=A.m_ulvalue;

len=X.m_nLength;

}

if(cmp<0)

{

s=A.m_ulvalue;

d=X.m_ulvalue;

len=A.m_nLength;

X.m_nSign=1-X.m_nSign;

}

for(int i=0;i<len;i++)

{

if((s[i]-carry)>=d[i])

{

X.m_ulvalue[i]=s[i]-carry-d[i];

carry=0;

}

else

{

num=0x100000000+s[i];

X.m_ulvalue[i]=(unsigned long)(num-carry-d[i]);

carry=1;

}

}

while(X.m_ulvalue[len-1]==0)len--;

X.m_nLength=len;

return X;

}

else{X.Mov(A);X.m_nSign=1-X.m_nSign;return Add(X);}

}

file://大数相乘

file://调用形式:N.Mul(A),返回值:N*A

/******************************************************************/

例如:

A B C

* D E

----------------

= S F G H

+ T I J K

----------------

= U V L M N

其中,SFGH=ABC*E,TIJK=ABC*D

而对于:

A B C

* E

-------------

= S F G H

其中,若C*E<=0xffffffff,则H=C*E,carry(进位标志)=0

若C*E>0xffffffff,则H=(C*E)&0xffffffff

carry=(C*E)/0xffffffff

若B*E+carry<=0xffffffff,则G=B*E+carry,carry=0

若B*E+carry>0xffffffff,则G=(B*E+carry)&0xffffffff

carry=(B*E+carry)/0xffffffff

若A*E+carry<=0xffffffff,则F=A*E+carry,carry=0

若A*E+carry>0xffffffff,则F=(A*E+carry)&0xffffffff

carry=(A*E+carry)/0xffffffff

S=carry

/*****************************************************************/

CBigInt CBigInt::Mul(CBigInt& A)

{

CBigInt X,Y;

unsigned __int64 mul;

unsigned long carry;

for(int i=0;i<A.m_nLength;i++)

{

Y.m_nLength=m_nLength;

carry=0;

for(int j=0;j<m_nLength;j++)

{

mul=m_ulvalue[j];

mul=mul*A.m_ulvalue[i]+carry;

Y.m_ulvalue[j]=(unsigned long)mul;

carry=(unsigned long)(mul>>32);

}

if(carry&&(Y.m_nLength<BI_MAXLEN))

{

Y.m_nLength++;

Y.m_ulvalue[Y.m_nLength-1]=carry;

}

if(Y.m_nLength<BI_MAXLEN-i)

{

Y.m_nLength+=i;

for(int k=Y.m_nLength-1;k>=i;k--)Y.m_ulvalue[k]=Y.m_ulvalue[k-i];

for(k=0;k<i;k++)Y.m_ulvalue[k]=0;

}

X.Mov(X.Add(Y));

}

if(m_nSign+A.m_nSign==1)X.m_nSign=0;

else X.m_nSign=1;

return X;

}

file://大数相除

file://调用形式:N.Div(A),返回值:N/A

file://除法的关键在于“试商”,然后就变成了乘法和减法

file://这里将被除数与除数的试商转化成了被除数最高位与除数最高位的试商

CBigInt CBigInt::Div(CBigInt& A)

{

CBigInt X,Y,Z;

int len;

unsigned __int64 num,div;

unsigned long carry=0;

Y.Mov(*this);

while(Y.Cmp(A)>0)

{

if(Y.m_ulvalue[Y.m_nLength-1]>A.m_ulvalue[A.m_nLength-1])

{

len=Y.m_nLength-A.m_nLength;

div=Y.m_ulvalue[Y.m_nLength-1]/(A.m_ulvalue[A.m_nLength-1]+1);

}

else if(Y.m_nLength>A.m_nLength)

{

len=Y.m_nLength-A.m_nLength-1;

num=Y.m_ulvalue[Y.m_nLength-1];

num=(num<<32)+Y.m_ulvalue[Y.m_nLength-2];

if(A.m_ulvalue[A.m_nLength-1]==0xffffffff)div=(num>>32);

else div=num/(A.m_ulvalue[A.m_nLength-1]+1);

}

else

{

X.Mov(X.Add(1));

break;

}

Z.Mov(div);

Z.m_nLength+=len;

for(int i=Z.m_nLength-1;i>=len;i--)Z.m_ulvalue[i]=Z.m_ulvalue[i-len];

for(i=0;i<len;i++)Z.m_ulvalue[i]=0;

X.Mov(X.Add(Z));

Z.Mov(Z.Mul(A));

Y.Mov(Y.Sub(Z));

}

if(Y.Cmp(A)==0)X.Mov(X.Add(1));

if(m_nSign+A.m_nSign==1)X.m_nSign=0;

else X.m_nSign=1;

return X;

}

file://大数求模

file://调用形式:N.Mod(A),返回值:N%A

file://求模与求商原理相同

CBigInt CBigInt::Mod(CBigInt& A)

{

CBigInt X,Y;

int len;

unsigned __int64 num,div;

unsigned long carry=0;

X.Mov(*this);

while(X.Cmp(A)>0)

{

if(X.m_ulvalue[X.m_nLength-1]>A.m_ulvalue[A.m_nLength-1])

{

len=X.m_nLength-A.m_nLength;

div=X.m_ulvalue[X.m_nLength-1]/(A.m_ulvalue[A.m_nLength-1]+1);

}

else if(X.m_nLength>A.m_nLength)

{

len=X.m_nLength-A.m_nLength-1;

num=X.m_ulvalue[X.m_nLength-1];

num=(num<<32)+X.m_ulvalue[X.m_nLength-2];

if(A.m_ulvalue[A.m_nLength-1]==0xffffffff)div=(num>>32);

else div=num/(A.m_ulvalue[A.m_nLength-1]+1);

}

else

{

X.Mov(X.Sub(A));

break;

}

Y.Mov(div);

Y.Mov(Y.Mul(A));

Y.m_nLength+=len;

for(int i=Y.m_nLength-1;i>=len;i--)Y.m_ulvalue[i]=Y.m_ulvalue[i-len];

for(i=0;i<len;i++)Y.m_ulvalue[i]=0;

X.Mov(X.Sub(Y));

}

if(X.Cmp(A)==0)X.Mov(0);

return X;

}

file://暂时只给出了十进制字符串的转化

int CBigInt::InPutFromStr(CString& str, const unsigned int system=DEC)

{

int len=str.GetLength();

Mov(0);

for(int i=0;i<len;i++)

{

Mov(Mul(system));

int k=str[i]-48;

Mov(Add(k));

}

return 0;

}

file://暂时只给出了十进制字符串的转化

int CBigInt::OutPutToStr(CString& str, const unsigned int system=DEC)

{

str="";

char ch;

CBigInt X;

X.Mov(*this);

while(X.m_ulvalue[X.m_nLength-1]>0)

{

ch=X.Mod(system)+48;

str.Insert(0,ch);

X.Mov(X.Div(system));

}

return 0;

}

file://欧几里德算法求:Y=X.Euc(A),使满足:YX mod A=1

file://相当于对不定方程ax-by=1求最小整数解

file://实际上就是初中学过的辗转相除法

/********************************************************************/

例如:11x-49y=1,求x

11 x - 49 y = 1 a)

49%11=5 -> 11 x - 5 y = 1 b)

11%5 =1 -> x - 5 y = 1 c)

令y=1 代入c)式 得x=6

令x=6 代入b)式 得y=13

令y=13 代入a)式 得x=58

/********************************************************************/

CBigInt CBigInt::Euc(CBigInt& A)

{

CBigInt X,Y;

X.Mov(*this);

Y.Mov(A);

if((X.m_nLength==1)&&(X.m_ulvalue[0]==1))return X;

if((Y.m_nLength==1)&&(Y.m_ulvalue[0]==1)){X.Mov(X.Sub(1));return X;}

if(X.Cmp(Y)==1)X.Mov(X.Mod(Y));

else Y.Mov(Y.Mod(X));

X.Mov(X.Euc(Y));

Y.Mov(*this);

if(Y.Cmp(A)==1)

{

X.Mov(X.Mul(Y));

X.Mov(X.Sub(1));

X.Mov(X.Div(A));

}

else

{

X.Mov(X.Mul(A));

X.Mov(X.Add(1));

X.Mov(X.Div(Y));

}

return X;

}

file://蒙哥马利算法求:Y=X.Mon(A,B),使满足:X^A mod B=Y

file://俺估计就是高中学过的反复平方法

CBigInt CBigInt::Mon(CBigInt& A, CBigInt& B)

{

CBigInt X,Y,Z;

X.Mov(1);

Y.Mov(*this);

Z.Mov(A);

while((Z.m_nLength!=1)||Z.m_ulvalue[0])

{

if(Z.m_ulvalue[0]&1)

{

Z.Mov(Z.Sub(1));

X.Mov(X.Mul(Y));

X.Mov(X.Mod(B));

}

else

{

Z.Mov(Z.Div(2));

Y.Mov(Y.Mul(Y));

Y.Mov(Y.Mod(B));

}

}

return X;

}

最后需要说明的是因为在VC里面存在一个__int64类型可以

用来计算进位与借位值,所以将大数当作0x100000000进制

进行运算是可能的,而在其他编译系统中如果不存在64位

整形,则可以采用0x40000000进制,由于在0x40000000

进制中,对任何两个“数字”进行四则运算,结果都在

0x3fffffff*03fffffff之间,小于0xffffffff,都可以用

一个32位无符号整数来表示。事实上《楚汉棋缘》采用的

freelip大数库正是运用了0x40000000进制来表示大数的,

所以其反汇编后大数的值在内存中表现出来有些“奇怪”。

作者:afanty (afanty@vip.sina.com hhtp://www.pediy.com)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有