算法系列2《RSA》

来源:互联网 发布:淘宝网中老年棉鞋 编辑:程序博客网 时间:2024/06/05 06:17
"

     

1. RSA介绍

    RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

                    

    RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。即RSA的重大缺陷是无法从理论上把握它的保密性能如何,而且密码学界多数人士倾向于因子分解不是NPC问题。

 

    RSA的缺点主要有:A)产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。B)分组长度太大,为保证安全性,n 至少也要600BITS以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。目前,SET(Secure Electronic Transaction)协议中要求CA采用2048BITS长的密钥,其他实体使用1024比特的密钥。C)RSA密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。

 

      保密级别         

        对称密钥长度(bit)         

          RSA密钥长度(bit)           

           ECC密钥长度(bit)           

          保密年限              

80

80

1024

160

2010

112

112

2048

224

2030

128

128

3072

256

2040

192

192

7680

384

2080

256

256

15360

512

2120

 

 

    该可逆算法是经批准用于加密和生成数字签名的算法。公钥指数的值只允许是3和216+1。该算法产生的密文及数字签名的长度与模长相等。

 

描述

最大长度

认证中心公钥模

248字节

发卡行公钥模

248字节

IC卡公钥模

248字节

 

    认证中心公钥模的长度NCA,发卡行公钥模的长度NI,IC卡公钥模的长度NIC,必须满足NIC≤NI≤NCA和NPE≤NI≤NCA。

 

    注: IC卡中一个记录的长度最长不超过254字节(包括Tag和Length),因而实际IC卡公钥和发卡行公钥长度应小于最大长度248字节。命令数据长度最长为255字节,响应数据最长为256字节,动态签名数据作为IC卡响应数据,也限制了IC卡公钥的最大长度。

 


     如卡片支持DDA和CDA,包含IC卡证书的记录模板的长度,即IC卡公钥证书长度加上证书(’9F46’)和记录模板(’70’)的Tag和Length不超过254字节,则IC卡公钥长度不超过247字节,因而发卡行公钥长度最大长度也不超过247字节。

    根据发卡行应用数据长度不同,IC卡公钥最大长度在205到240之间。如果Generate AC命令响应包含其他可选数据,IC卡公钥最大长度还应减去这些数据的长度(包括Tag和Length)。如果卡片应用支持INTERNALAUTHENTICATION格式二,IC卡公钥最大长度还应减去7字节。

 

    在选择公钥模长时,应该考虑到比较密钥的生命周期同预期的因数分解进程。

    发卡行公钥指数和IC卡公钥指数的值由发卡行决定。认证中心,发卡行和IC卡公钥指数必须等于3或216+1。

    标识本数字签名算法的公钥算法标识必须编码为十六进制‘01’。





2.RSA算法源码


<<RSA.h>>

// LargeInt.h// 大整数类的声明,包含了质数检查,随机数生成,以及RSA密钥生成及加密解密函数。////////////////////////////////////////////////////////////////////////////////RSA加密里所说的1024 位加密、2048位加密,是不是只要 //CLargeInt::CreateRandom(e,1024); //这句代码里的参数设置成1024、2048就行了? //////不是的,2048bit,是指P*Q的积是2048bit,也就是说,当你P和Q都设置为1024的时候,加密强度是2048bit,事实上P和Q的位数可以不等,并且过分接近的P和Q将导致破解难度极大降低。//////_data 和 _len 这两个变量到底起什么作用? //_data 占了4092个字节的大小,_len=64时,只输出了512个字节。 ////_data和_len其实是模拟了一个动态数组,用来容纳长度不定的大整数。_data 占据的大小是预先设置好的,这个数值在LargeInt.h中有定义://enum LIMIT{ LENGTH = 0x3FF,SMALLPRIMES = 5000};//LENGTH 可以根据需要修改。//_len是以4字节为单位的目前已经占用的数组的长度,_len = 64就是当前大整数的长度是64*4 = 256字节//输出的字节是以16进制表示的字符串,每个字节需要两个符号来表示,所以长度是256*2 = 512字节。//必须保证T_DWORD是4字节。typedef unsigned long T_DWORD;class CLargeInt  {public://说明://基本的操作函数之所以没有设置成运算符的重载,主要是因为,//大数运算的过程中,经常需要额外的参数,例如错位相加减的offset值。//以及某些额外的结果//例如,除法运算的商和余数。//为了代码尽量通用,都写成了静态成员函数。//运算符的重载可以通过对这些静态成员函数进一步封装来实现。//复制static void Copy(const CLargeInt& source,CLargeInt& target);//比较static bool LargerEqual(const CLargeInt& source,const CLargeInt& target,T_DWORD offset = 0);static bool Equal(const CLargeInt& source,const CLargeInt& target);//和T_DWORD类型交互的底层操作函数static void Mul(const CLargeInt& faciend,T_DWORD multiplier,CLargeInt& product);static void Div(const CLargeInt& dividend,T_DWORD divisor,CLargeInt& quotient,T_DWORD& residual);//移位://右移一位,用来取代 /2 操作。static void RCR(CLargeInt& n);//左移一位,用来取代 *2 操作。static void RCL(CLargeInt& n);//CLargeInt类型底层操作函数,static void Add(const CLargeInt& augend, const CLargeInt& addend, CLargeInt& sum,T_DWORD offset = 0);static void Sub(const CLargeInt& minuend,const CLargeInt& subtrahend, CLargeInt& difference,T_DWORD offset = 0);static void Mul(const CLargeInt& faciend, const CLargeInt& multiplier, CLargeInt& product);static void Div(const CLargeInt& dividend, const CLargeInt& divisor, CLargeInt& quotient,CLargeInt& residual);static void ExpMod(const CLargeInt& source, const CLargeInt& exponent, const CLargeInt& modulo,CLargeInt& result);//高阶的测试static bool RabinMillerTest(const CLargeInt& source, const CLargeInt& base);static bool Coprime(const CLargeInt &source, const CLargeInt &target);//RSA算法相关函数:static bool IsPrime(const CLargeInt &n);static void CreatePrime(CLargeInt &n);static bool RSACreate( const CLargeInt &p,const CLargeInt & q,const CLargeInt &e,CLargeInt &d,CLargeInt &n);static void RSAEncode( const CLargeInt &n,const CLargeInt &d,const CLargeInt &m,CLargeInt &c);static void RSADecode( const CLargeInt &n,const CLargeInt &e,const CLargeInt &c,CLargeInt &m);static string RSADecode(const char* N, const char* E, const char* I);//建立随机数。static void CreateRandom(CLargeInt &n,T_DWORD bitcount);public:CLargeInt(T_DWORD value = 0);CLargeInt(const char* str);CLargeInt(const CLargeInt& other);~CLargeInt();private:enum LIMIT{ LENGTH = 0x3FF, SMALLPRIMES = 5000};T_DWORD _len;mutable T_DWORD _data[LENGTH]; //之所以用 mutable 是因为需要在计算中获取指针,并且有时还需要在不改变数值的情况下修改某些数组元素。//辅助用的小质数表和相关的函数。static std::vector<T_DWORD> _smallPrimes;static void InitSmallPrimes(T_DWORD count = SMALLPRIMES);static bool SmallPrimeTest(const CLargeInt& n);string GetHexStr();};// LARGEINT_HEADER


<<RSA.CPP>>


std::vector<T_DWORD> CLargeInt::_smallPrimes;void CLargeInt::InitSmallPrimes(T_DWORDcount){if (!_smallPrimes.size()) //尚未初始化{_smallPrimes.reserve(count);_smallPrimes.push_back(3);_smallPrimes.push_back(5);_smallPrimes.push_back(7);_smallPrimes.push_back(11);_smallPrimes.push_back(13);T_DWORDi = 0;for( i = 17; _smallPrimes.size() < count; i+= 2){bool bePrime = true;for( T_DWORD j = 0; j <_smallPrimes.size(); j++ ){if( ( _smallPrimes[j] *_smallPrimes[j]) > i )//已经不可能了。break;if( (i % _smallPrimes[j]) == 0)//可以整除bePrime= false;}if( bePrime ) //是素数{_smallPrimes.push_back(i);}}}}bool CLargeInt::SmallPrimeTest(const CLargeInt&n){if (n._data[0] == 2 && n._len == 1) {return true; //2是质数。}if (n._len == 1&& n._data[0] <= _smallPrimes.back()) //整数比表中的数据小。{if (std::binary_search(_smallPrimes.begin(),_smallPrimes.end(),n._data[0])) //找到,n存在于质数表中。{return true; //通过测试,数n是质数。}return false; //没有通过,n是合数。}else{CLargeInt temp;T_DWORDr;for( T_DWORD i = 0; i <_smallPrimes.size(); i++){Div(n,_smallPrimes[i],temp,r); //依次检查是否能整除。if( r == 0) return false; //能整除,说明 n 有小于它的质因子。n 是合数。}return true; //n 没有表中已有的质因子,n有可能是质数。}}bool CLargeInt::IsPrime(const CLargeInt&n){InitSmallPrimes();if (n._data[0]&1) //奇数{if (n._len == 1&& n._data[0] <= _smallPrimes.back()){return SmallPrimeTest(n);  //是小质数表中的一个质数。}else{if( SmallPrimeTest(n) )//通过小质数测试{for( int i = 0;i < 5; i++){CLargeInt a(_smallPrimes[ _smallPrimes.size() -i]);if( !RabinMillerTest(n,a) ) return false;}return true; //99.9%的可能是质数。}else {return false;}}}return false;}void CLargeInt::CreatePrime(CLargeInt &n){n._data[0] |= 0x01;while (!IsPrime(n)){Add(n, 2, n); //步进2,寻找最接近的下一个质数。这个算法并不是寻找质数最好的算法,但是它可以保证寻找到相邻的质数。}}CLargeInt::CLargeInt(T_DWORD value) : _len(1){_data[0] = value;}CLargeInt::CLargeInt(const CLargeInt& other){Copy(other,*this);}CLargeInt::CLargeInt(const char* str):_len(1){_data[0] = 0;//if(str && strlen(str) >2 && ( strncmp(str,"0x",2) == 0|| strncmp(str,"0X",2) == 0 ) )if (str){CLargeInt temp;char ch;T_DWORDn = 0;const char * p = str;while (*p){ch= *p;if ((ch >= '0') && (ch <= '9')){n = ch - '0';}else if ((ch >= 'a') && (ch <= 'f'))    {n = ch - 'a' + 10;       //a->f分别代表10->15   a的AscII为97,所以这里应该减去87}else if ((ch >= 'A') && (ch <= 'F')){n = ch - 'A' + 10;       //同上}p++;Mul(*this, 16, temp);Add(temp, n, *this);}}//else//{//这里应该用来处理除了0x开头的16进制字符串的情况。//__asm int 3;//}}CLargeInt::~CLargeInt(){}void CLargeInt::Copy(const CLargeInt& source, CLargeInt& target){if (&source != &target) //避免自身拷贝。{target._len = source._len;//相信库函数能提供最高效的实现。memcpy(target._data, source._data, source._len * 4);}}bool CLargeInt::Equal(const CLargeInt& source, const CLargeInt& target){if (source._len== target._len){//相信库函数能提供最高效的实现。return !(memcmp(source._data, target._data,source._len * 4));}else{return false;}}bool CLargeInt::LargerEqual(const CLargeInt& source,const CLargeInt& target,T_DWORD offset ){if( source._len> (target._len + offset) ) return true;else if( source._len < (target._len + offset) )return false;else{int end= offset;for( int i = source._len - 1; i>= end ; i--){T_DWORDii = i - offset;if( source._data[i] > target._data[ii] ) returntrue; //大于else if( source._data[i] < target._data[ii] )return false;}return true; //相等。}}void CLargeInt::Add(const CLargeInt &augend, const CLargeInt &addend, CLargeInt&sum,T_DWORD offset){T_DWORDlen,len1,len2; //len绝对不能<1,否则会出错。T_DWORD*p1 = 0;T_DWORD*p2 = 0;T_DWORD*p3 = 0;if( augend._len>= (addend._len+offset)){len = augend._len - offset;len1 = addend._len;len2 =len - len1;p1 = augend._data+offset;p2 = addend._data;p3 = sum._data+offset;}else{len = addend._len;if( augend._len<= offset ){augend._data[offset] = 0;len1 = 1;len2 = addend._len - len1;}else{len1 = augend._len - offset;len2 = addend._len - len1;}p1 = addend._data;p2 = augend._data + offset;p3 = sum._data + offset;}__asm{pushad;//载入计算地址mov esi,p1;mov ebx,p2;mov edi,p3;mov eax,len1;sal eax,2;//计算末地址add esi,eax;add ebx,eax;add edi,eax;mov ecx,eax;add ecx,4*7;and ecx,0xFFFFFFE0; //ecx - ecx%32,这里的ecx就变成了偏移址,同时也是累加器。neg ecx; //取负,用作累加。sar eax,2; //回复到原来的长度neg eax; //取负and eax,dword ptr 7;jz labeladd0; //如果低位是0,说明长度至少有8(因为长度为0是非法的)mov edx,dword ptr 0xC;mul edx; //eax变为相对偏移址。lea edx,labeladd1; //载入起始地址sub edx,dword ptr 0xC;add eax,edx; //计算出跳转地址clc; //清除标志位。jmp eax; //跳转labeladdloop:popf;labeladd0:mov eax,[esi+ecx+0*4];adc eax,[ebx+ecx+0*4];mov [edi+ecx+0*4],eax;labeladd1:mov eax,[esi+ecx+1*4];adc eax,[ebx+ecx+1*4];mov [edi+ecx+1*4],eax;//labeladd2:mov eax,[esi+ecx+2*4];adc eax,[ebx+ecx+2*4];mov [edi+ecx+2*4],eax;//labeladd3:mov eax,[esi+ecx+3*4];adc eax,[ebx+ecx+3*4];mov [edi+ecx+3*4],eax;//labeladd4:mov eax,[esi+ecx+4*4];adc eax,[ebx+ecx+4*4];mov [edi+ecx+4*4],eax;//labeladd5:mov eax,[esi+ecx+5*4];adc eax,[ebx+ecx+5*4];mov [edi+ecx+5*4],eax;//labeladd6:mov eax,[esi+ecx+6*4];adc eax,[ebx+ecx+6*4];mov [edi+ecx+6*4],eax;//labeladd7:mov eax,[esi+ecx+7*4];adc eax,[ebx+ecx+7*4];mov [edi+ecx+7*4],eax;//labeladd8:pushf;add ecx,32;jnz labeladdloop;//运行到这里了,说明两数重合部分已经处理完了。开始处理两数相差的部分。mov ecx,len2; //载入长度xor ebx,ebx; //因为ebx指向的缓冲区废弃不用了,所以使用已经空闲的ebx寄存器。cmp ebx,ecx; //判断ecx是否等于ebx(0)jz labelcarry; //如果相等,说明已经处理完了,跳转到处理最后一次进位的地方。labelfix:popf; //弹出上次的标志位。mov eax,[esi+ebx*4];adc eax,0;mov [edi+ebx*4],eax;//如果这里没有进位,剩下的部分可以直接拷贝。拷贝的长度就是ecx-1jnc labelcopy;pushf; //保存标志位。inc ebx; //步进dec ecx;jnz labelfix; //循环。labelcarry:popf; //弹出标志位jnc labelend; //没有进位就直接结束//没有跳转说明有进位:mov dword ptr [edi+ebx*4],dwordptr 0x00000001;//直接置1lea eax,len;inc [eax]; //总长度+1inc ecx; //补一次。labelcopy:dec ecx;sal ecx,2;cmp edi,esi; //比较源地址和目标地址,如果相同就跳过。jz labelend;sal ebx,2;add ebx,4;add edi,ebx;add esi,ebx;rep movs dword ptr [edi],dword ptr [esi];labelend:popad;}sum._len = len + offset;}void CLargeInt::Sub(const CLargeInt& minuend,const CLargeInt& subtrahend,CLargeInt& difference,T_DWORD offset){T_DWORDlen,len1,len2; //len绝对不能<1,否则会出错。T_DWORD*p1 = 0;T_DWORD*p2 = 0;T_DWORD*p3 = 0;if( minuend._len >= (subtrahend._len+offset) ){len = minuend._len- offset;len1 = subtrahend._len;len2 =len - len1;p1 = minuend._data + offset;p2 = subtrahend._data;p3 = difference._data +offset;}else{__asm int 3; //出错。}__asm{pushad;//载入计算地址mov esi,p1;mov ebx,p2;mov edi,p3;mov eax,len1;sal eax,2;//计算末地址add esi,eax;add ebx,eax;add edi,eax;mov ecx,eax;add ecx,4*7;and ecx,0xFFFFFFE0; //ecx - ecx%32,这里的ecx就变成了偏移址,同时也是累加器。neg ecx; //取负,用作累加。sar eax,2; //回复到原来的长度neg eax; //取负and eax,dword ptr 7;jz labeladd0; //如果低位是0,说明长度至少有8(因为长度为0是非法的)mov edx,dword ptr 0xC;mul edx; //eax变为相对偏移址。lea edx,labeladd1; //载入起始地址sub edx,dword ptr 0xC;add eax,edx; //计算出跳转地址clc; //清除标志位。jmp eax; //跳转labeladdloop:popf;labeladd0:mov eax,[esi+ecx+0*4];sbb eax,[ebx+ecx+0*4];mov [edi+ecx+0*4],eax;labeladd1:mov eax,[esi+ecx+1*4];sbb eax,[ebx+ecx+1*4];mov [edi+ecx+1*4],eax;//labeladd2:mov eax,[esi+ecx+2*4];sbb eax,[ebx+ecx+2*4];mov [edi+ecx+2*4],eax;//labeladd3:mov eax,[esi+ecx+3*4];sbb eax,[ebx+ecx+3*4];mov [edi+ecx+3*4],eax;//labeladd4:mov eax,[esi+ecx+4*4];sbb eax,[ebx+ecx+4*4];mov [edi+ecx+4*4],eax;//labeladd5:mov eax,[esi+ecx+5*4];sbb eax,[ebx+ecx+5*4];mov [edi+ecx+5*4],eax;//labeladd6:mov eax,[esi+ecx+6*4];sbb eax,[ebx+ecx+6*4];mov [edi+ecx+6*4],eax;//labeladd7:mov eax,[esi+ecx+7*4];sbb eax,[ebx+ecx+7*4];mov [edi+ecx+7*4],eax;//labeladd8:pushf;add ecx,32;jnz labeladdloop;//运行到这里了,说明两数重合部分已经处理完了。开始处理两数相差的部分。mov ecx,len2; //载入长度,//只处理p1的bufxor ebx,ebx; //因为ebx指向的缓冲区废弃不用了,所以使用已经空闲的ebx寄存器。cmp ebx,ecx; //判断ecx是否等于ebxjz labelcarry; //如果相等,说明已经处理完了,跳转到处理最后一次进位的地方。labelfix:popf; //弹出上次的标志位。mov eax,[esi+ebx*4];sbb eax,0;mov [edi+ebx*4],eax;//如果这里没有进位,剩下的部分可以直接拷贝。拷贝的长度就是ecx-1jnc labelcopy;pushf; //保存标志位。inc ebx; //步进dec ecx;jnz labelfix; //循环。labelcarry:popf; //弹出标志位jnc labelend; //没有进位就直接结束//没有跳转说明有进位:int 3; //说明减数不够,结果为负mov dword ptr [edi+ebx*4],dwordptr 0x00000001;//直接置1lea eax,len;dec [eax]; //总长度-1inc ecx; //补一次。labelcopy:dec ecx;sal ecx,2;cmp edi,esi; //比较源地址和目标地址,如果相同就跳过。jz labelend;sal ebx,2;add ebx,4;add edi,ebx;add esi,ebx;rep movs dword ptr [edi],dword ptr [esi];labelend:popad;}difference._len= len+offset;for( T_DWORD i = difference._len-1; i >0; i--){if( difference._data[i]== 0 ) //末尾是0{difference._len--;}else break;}}void CLargeInt::Mul(const CLargeInt& faciend,T_DWORD multiplier,CLargeInt& product){T_DWORDlen; //len绝对不能<1,否则会出错。T_DWORD*p1 = 0;T_DWORD*p2 = 0;T_DWORD*p3 = 0;len = faciend._len;p1 = faciend._data;p2 = 0;p3 = product._data;memset(p3,0,(len+1)*4);__asm{pushad;//载入计算地址mov esi,p1;mov edi,p3;mov ebx,multipliermov eax,len;sal eax,2;//计算末地址add esi,eax;add edi,eax;mov ecx,eax;add ecx,4*7;and ecx,0xFFFFFFE0; //ecx - ecx%32,这里的ecx就变成了偏移址,同时也是累加器。neg ecx; //取负,用作累加。sar eax,2; //回复到原来的长度neg eax; //取负and eax,dword ptr 7;jz labeladd0; //如果低位是0,说明长度至少有8(因为长度为0是非法的)mov edx,dword ptr 0xe; //0xe是跳转地址的系数。mul edx; //eax变为相对偏移址。lea edx,labeladd1; //载入起始地址sub edx,dword ptr 0xe;add eax,edx; //计算出跳转地址clc; //清除标志位。jmp eax; //跳转labeladdloop:labeladd0:mov eax,[esi+ecx+0*4];mul ebx;add [edi+ecx+0*4],eax;adc [edi+ecx+1*4],edx;labeladd1:mov eax,[esi+ecx+1*4];mul ebx;add [edi+ecx+1*4],eax;adc [edi+ecx+2*4],edx;//labeladd2:mov eax,[esi+ecx+2*4];mul ebx;add [edi+ecx+2*4],eax;adc [edi+ecx+3*4],edx;//labeladd3:mov eax,[esi+ecx+3*4];mul ebx;add [edi+ecx+3*4],eax;adc [edi+ecx+4*4],edx;//labeladd4:mov eax,[esi+ecx+4*4];mul ebx;add [edi+ecx+4*4],eax;adc [edi+ecx+5*4],edx;//labeladd5:mov eax,[esi+ecx+5*4];mul ebx;add [edi+ecx+5*4],eax;adc [edi+ecx+6*4],edx;//labeladd6:mov eax,[esi+ecx+6*4];mul ebx;add [edi+ecx+6*4],eax;adc [edi+ecx+7*4],edx;//labeladd7:mov eax,[esi+ecx+7*4];mul ebx;add [edi+ecx+7*4],eax;adc [edi+ecx+8*4],edx;//labeladd8:add ecx,32;jnz labeladdloop;//labelend:popad;}product._len = len+1;for( T_DWORD i = product._len-1; i > 0;i--){if( product._data[i] ==0 ) //末尾是0{product._len--;}else break;}}void CLargeInt::RCR(CLargeInt& n){T_DWORDlen; //len绝对不能<1,否则会出错。T_DWORD*p1 = 0;len = n._len;p1 = n._data;__asm{pushad;//载入计算地址mov esi,p1;mov eax,len;mov ecx,eax;add ecx,dword ptr 15;and ecx,dword ptr 0xFFFFFFF0;mov eax,ecx;sal ecx,dword ptr 2;sub eax,len; //求初始偏移。mov ebx,dword ptr 4; //偏移倍率mul ebx;lea ebx,label0;add eax,ebx;clc;jmp eax;labelloop:popf;label0:rcr dword ptr [esi + ecx - 1*4],1;//label1:rcr dword ptr [esi + ecx - 2*4],1;//label2:rcr dword ptr [esi + ecx - 3*4],1;//label3:rcr dword ptr [esi + ecx - 4*4],1;//label4:rcr dword ptr [esi + ecx - 5*4],1;//label5:rcr dword ptr [esi + ecx - 6*4],1;//label6:rcr dword ptr [esi + ecx - 7*4],1;//label7:rcr dword ptr [esi + ecx - 8*4],1;//label8:rcr dword ptr [esi + ecx - 9*4],1;//label9:rcr dword ptr [esi + ecx - 10*4],1;//label10:rcr dword ptr [esi + ecx - 11*4],1;//label11:rcr dword ptr [esi + ecx - 12*4],1;//label12:rcr dword ptr [esi + ecx - 13*4],1;//label13:rcr dword ptr [esi + ecx - 14*4],1;//label14:rcr dword ptr [esi + ecx - 15*4],1;//label15:rcr dword ptr [esi + ecx - 16*4],1;//label16:pushf;sub ecx,dword ptr 64;jnz labelloop;popf;popad;}for( T_DWORD i = n._len-1; i > 0; i--){if( n._data[i] == 0 ) //末尾是0{n._len--;}else break;}}void CLargeInt::RCL(CLargeInt& n){T_DWORDlen = n._len; //len绝对不能<1,否则会出错。T_DWORD*p1 = 0;n._data[len] = 0;n._len++;len++;p1 = n._data;__asm{pushad;//载入计算地址mov esi,p1;mov eax,len;mov ecx,eax;sal eax,dword ptr 2;add esi,eax;add ecx,dword ptr 15;and ecx,dword ptr 0xFFFFFFF0;mov eax,ecx;sal ecx,dword ptr 2;neg ecx;sub eax,len; //求初始偏移。jz label0;mov ebx,dword ptr 4; //偏移倍率mul ebx;lea ebx,label1;sub ebx,4;add eax,ebx;clc;jmp eax;labelloop:popf;label0:rcl dword ptr [esi + ecx + 0*4],1;label1:rcl dword ptr [esi + ecx + 1*4],1;//label2:rcl dword ptr [esi + ecx + 2*4],1;//label3:rcl dword ptr [esi + ecx + 3*4],1;//label4:rcl dword ptr [esi + ecx + 4*4],1;//label5:rcl dword ptr [esi + ecx + 5*4],1;//label6:rcl dword ptr [esi + ecx + 6*4],1;//label7:rcl dword ptr [esi + ecx + 7*4],1;//label8:rcl dword ptr [esi + ecx + 8*4],1;//label9:rcl dword ptr [esi + ecx + 9*4],1;//label10:rcl dword ptr [esi + ecx + 10*4],1;//label11:rcl dword ptr [esi + ecx + 11*4],1;//label12:rcl dword ptr [esi + ecx + 12*4],1;//label13:rcl dword ptr [esi + ecx + 13*4],1;//label14:rcl dword ptr [esi + ecx + 14*4],1;//label15:rcl dword ptr [esi + ecx + 15*4],1;//label16:pushf;add ecx,dword ptr 64;jnz labelloop;popf;popad;}for( T_DWORD i = n._len-1; i > 0; i--){if( n._data[i] == 0 ) //末尾是0{n._len--;}else break;}}void CLargeInt::Mul(const CLargeInt& faciend, const CLargeInt& multiplier, CLargeInt& product){CLargeInt temp;product._len = (faciend._len + multiplier._len);memset(product._data, 0, product._len * 4);for (T_DWORD i = 0; i <multiplier._len; i++){Mul(faciend,multiplier._data[i],temp);Add(product,temp,product,i);}for (T_DWORD i = product._len - 1; i > 0;i--){if( product._data[i] ==0 ) //末尾是0{product._len--;}else{break;}}}void CLargeInt::Div(const "
0 0