1. RSA介绍
RSA公钥加密算法是1977年由Ron Rivest、Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的。RSA取名来自开发他们三者的名字。RSA是眼下最有影响力的 公钥加密算法,它可以抵抗到眼下为止已知的全部password攻击,已被ISO推荐为公钥数据加密标准。RSA算法基于一个十分简单的数论事实:将两个大素数相乘十分easy,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。即RSA的重大缺陷是无法从理论上把握它的保密性能怎样,并且password学界多数人士倾向于因子分解不是NPC问题。
RSA的缺点主要有:A)产生密钥非常麻烦,受到素数产生技术的限制,因而难以做到一次一密。B)分组长度太大,为保证安全性,n 至少也要600BITS以上,使运算代价非常高,尤其是速度较慢,较对称password算法慢几个数量级;且随着大数分解技术的发展,这个长度还在添加�,不利于数据格式的标准化。眼下,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_DWORD count)
{
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_DWORD i = 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_DWORD r;
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_DWORD n = 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_DWORD ii = i - offset;
if( source._data[i] > target._data[ii] ) return true; //大于
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_DWORD len,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-1
jnc labelcopy;
pushf; //保存标志位。
inc ebx; //步进
dec ecx;
jnz labelfix; //循环。
labelcarry:
popf; //弹出标志位
jnc labelend; //没有进位就直接结束
//没有跳转说明有进位:
mov dword ptr [edi+ebx*4],dword ptr 0x00000001; //直接置1
lea eax,len;
inc [eax]; //总长度+1
inc 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_DWORD len,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的buf
xor ebx,ebx; //由于ebx指向的缓冲区废弃不用了,所以使用已经空暇的ebx寄存器。
cmp ebx,ecx; //推断ecx是否等于ebx
jz labelcarry; //假设相等,说明已经处理完了,跳转到处理最后一次进位的地方。
labelfix:
popf; //弹出上次的标志位。
mov eax,[esi+ebx*4];
sbb eax,0;
mov [edi+ebx*4],eax;
//假设这里没有进位,剩下的部分能够直接拷贝。拷贝的长度就是ecx-1
jnc labelcopy;
pushf; //保存标志位。
inc ebx; //步进
dec ecx;
jnz labelfix; //循环。
labelcarry:
popf; //弹出标志位
jnc labelend; //没有进位就直接结束
//没有跳转说明有进位:
int 3; //说明减数不够,结果为负
mov dword ptr [edi+ebx*4],dword ptr 0x00000001; //直接置1
lea eax,len;
dec [eax]; //总长度-1
inc 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_DWORD len; //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,multiplier
mov 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_DWORD len; //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_DWORD len = 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 CLargeInt& dividend,T_DWORD divisor,CLargeInt& quotient,T_DWORD& residual)
{
T_DWORD len; //len绝对不能<1,否则会出错。
T_DWORD *p1 = 0;
T_DWORD *p2 = 0;
T_DWORD *pr = &residual;
len = dividend._len;
quotient._len = dividend._len;
p1 = dividend._data;
p2 = quotient._data;
__asm
{
pushad;
//加载计算地址
mov esi,p1;
mov edi,p2;
mov eax,len;
mov ecx,eax;
add ecx,dword ptr 7;
and ecx,dword ptr 0xFFFFFFF8;
mov eax,ecx;
sal ecx,dword ptr 2;
sub eax,len; //求初始偏移。
mov ebx,dword ptr 0x0A; //偏移倍率
mul ebx;
lea edx,label0;
add eax,edx;
xor edx,edx;
mov ebx,divisor;
clc;
jmp eax;
labelloop:
label0:
mov eax,[esi + ecx - 1*4];
div ebx;
mov [edi + ecx - 1*4],eax;
//label1:
mov eax,[esi + ecx - 2*4];
div ebx;
mov [edi + ecx - 2*4],eax;
//label2:
mov eax,[esi + ecx - 3*4];
div ebx;
mov [edi + ecx - 3*4],eax;
//label3:
mov eax,[esi + ecx - 4*4];
div ebx;
mov [edi + ecx - 4*4],eax;
//label4:
mov eax,[esi + ecx - 5*4];
div ebx;
mov [edi + ecx - 5*4],eax;
//label5:
mov eax,[esi + ecx - 6*4];
div ebx;
mov [edi + ecx - 6*4],eax;
//label6:
mov eax,[esi + ecx - 7*4];
div ebx;
mov [edi + ecx - 7*4],eax;
//label7:
mov eax,[esi + ecx - 8*4];
div ebx;
mov [edi + ecx - 8*4],eax;
//label8:
sub ecx,dword ptr 32;
jnz labelloop;
//执行到这里说明已经计算完毕,最后保存余数。
mov ecx,pr;
mov [ecx],edx;
popad;
}
for (T_DWORD i = quotient._len-1; i > 0; i--)
{
if (quotient._data[i] == 0) //末尾是0
{
quotient._len--;
}
else
{
break;
}
}
}
void CLargeInt::Div(const CLargeInt& dividend,const CLargeInt& divisor,CLargeInt& quotient,CLargeInt& residual)
{
if( dividend._len < divisor._len )
{
quotient._len = 1;
quotient._data[0] = 0;
Copy(dividend,residual);
}
else
{
if( divisor._len == 1)
{
Div(dividend,divisor._data[0],quotient,residual._data[0]);
residual._len = 1;
}
else
{
CLargeInt d,r;
//满位算法
T_DWORD head = divisor._data[divisor._len-1];
__asm
{
pushad;
mov eax,head;
bsr ecx,eax;
mov edx,dword ptr 31;
sub edx,ecx;
mov ecx,edx;
mov eax,dword ptr 0x01;
sal eax,cl;
mov head,eax;
popad;
}
Mul(dividend,head,d);
Mul(divisor,head,r);
quotient._len = d._len - r._len + 1;
quotient._data[quotient._len - 1] = 0;
T_DWORD newhead = r._data[r._len - 1];
//以上处理的目的是使得被除数最高位的1移动到DWORD的最高位。
//处理之后能够极大降低商的上下限之间的差距。
T_DWORD highpart = 0;
T_DWORD lowpart = 0;
T_DWORD max = 0,min = 0;
T_DWORD offset = 0;
CLargeInt temp;
for( T_DWORD i = d._len-1; i >= r._len-1; i-- )
{
offset = i - (r._len - 1);
lowpart = d._data[i];
__asm
{//这段汇编代码的作用是求商的上下限。min & max
pushad;
mov edx,highpart;
mov eax,lowpart;
mov ecx,newhead;
div ecx;
mov max,eax;
inc ecx;
jz _mov;
mov edx,highpart;
mov eax,lowpart;
div ecx;
mov edx,eax;
_mov:
mov min,edx;
popad;
}
if (max == 0)
{
highpart = d._data[i];
quotient._data[offset] = 0;
}
else
{
Mul(r,max,temp);
if ( max != min )
{
while ( !LargerEqual(d,temp,offset) )
{//这里使用的事实上是试商法,
//由于max和min的差距已经非常小,所以这里不再折半试商。
max--;
Sub(temp,r,temp);
}
}
quotient._data[offset] = max; //保存商。
Sub(d,temp,d,offset); //求本阶的余数。
highpart = d._data[i]; //加载余数。
}
}
//清除高位的0。
for(T_DWORD i = quotient._len-1; i > 0; i--)
{
if( quotient._data[i] == 0 ) //末尾是0
{
quotient._len--;
}
else break;
}
//除法完毕,计算余数:
Div(d,head,residual,newhead);
if ( newhead != 0 )
{
//余数不为0,说明出错。
__asm int 3;
}
}
}
}
void CLargeInt::ExpMod(const CLargeInt& source,const CLargeInt& exponent,const CLargeInt& modulo,CLargeInt& result)
{
CLargeInt n,e,r(1),temp,temp1;
Copy(source,n);
Copy(exponent,e);
while( e._len > 1 || e._data[e._len - 1] > 1 )
{
if( e._data[0] &1 )
{
Mul(r,n,temp);
Div(temp,modulo,temp1,r);
}
RCR(e);
Mul(n,n,temp);
Div(temp,modulo,temp1,n);
}
Mul(r,n,temp);
Div(temp,modulo,temp1,result);
}
bool CLargeInt::RabinMillerTest(const CLargeInt& source,const CLargeInt& base)
{
CLargeInt m,temp(1);
Sub(source,temp,m);
T_DWORD count = 0;
while(!(m._data[0] & 0x01) )
{
count++;
RCR(m);
}
/*
这里凝视掉的是旧的算法,能够用后面的等效算法代替。
改变的算法使得计算ExpMod的次数由 count 降低到 1
尽管理论上计算次数大大降低了,可是实际效果似乎仅仅是降低了50%左右的运算量。
for( T_DWORD i = 0; i< count; i++)
{
CLargeInt mod;
ExpMod(base,m,source,mod);
if( mod._data[0] == 1 && mod._len == 1 )
{
return true;
}
else
{
Sub(source,mod,temp);
if( temp._data[0] == 1 && temp._len == 1)
{
return true;
}
}
RCL(m);
}
*/
CLargeInt mod;
ExpMod(base,m,source,mod);
if( mod._data[0] == 1 && mod._len == 1 )
{
return true;
}
else
{
Sub(source,mod,temp);
if( temp._data[0] == 1 && temp._len == 1)
{
return true;
}
}
for( T_DWORD i = 1; i< count; i++)
{
CLargeInt next,t;
Mul(mod,mod,next);
Div(next,source,t,mod);
if( mod._data[0] == 1 && mod._len == 1 )
{
return true;
}
else
{
Sub(source,mod,temp);
if( temp._data[0] == 1 && temp._len == 1)
{
return true;
}
}
}
return false;
}
bool CLargeInt::RSACreate( const CLargeInt &p,const CLargeInt & q,const CLargeInt &e,CLargeInt &d,CLargeInt &n)
{//由已知的P,Q,E计算N,D,完毕RSA密钥生成。
Mul(p,q,n);
CLargeInt a(e),b(n);
Sub(b,p,b);
Sub(b,q,b);
Add(b,1,b);
if( !Coprime(b,e) ) return false;
//求D的算法,通过辗转相除,终于求得须要的D值。
CLargeInt k1,c1;
Div(b,a,k1,c1);
if( c1._len == 1 && c1._data[0] == 0 ) return false;
if( c1._len == 1 && c1._data[0] == 1 )
{
CLargeInt temp;
Sub(e,1,temp);
Mul(temp,k1,d);
Add(d,1,d);
return true;
}
CLargeInt k2,c2,ka2;
Div(a,c1,k2,c2);
if( c2._len == 1 && c2._data[0] == 0 ) return false;
Mul(k1,k2,ka2);
Add(ka2,1,ka2);
if( c2._len == 1 && c2._data[0] == 1 ) { Copy(ka2,d); return true; }
CLargeInt k3,c3,ka3;
Div(c1,c2,k3,c3);
if( c3._len == 1 && c3._data[0] == 0 ) return false;
Mul(k3,ka2,ka3);
Add(ka3,k1,ka3);
if( c3._len == 1 && c3._data[0] == 1 )
{
Copy(ka3,d);
CLargeInt temp,temp1,temp2;
Mul(d,e,temp);
Div(temp,b,temp1,temp2);
Add(temp2,1,temp2);
if( Equal(temp2,b) )
{
Mul(d,d,temp1);
Div(temp1,b,temp2,d);
Mul(d,e,temp1);
Div(temp1,b,temp2,d);
}
return true;
}
CLargeInt kn_2(k2),cn_2(c2),ka_2(ka2);
CLargeInt kn_1(k3),cn_1(c3),ka_1(ka3);
CLargeInt kn,cn,kan;
do{
Div(cn_2,cn_1,kn,cn);
Mul(kn,ka_1,kan);
Add(kan,ka_2,kan);
if( cn._len == 1 && cn._data[0] == 0 ) return false;
if( cn._len == 1 && cn._data[0] == 1 )
{
Copy(kan,d);
CLargeInt temp,temp1,temp2;
Mul(d,e,temp);
Div(temp,b,temp1,temp2);
Add(temp2,1,temp2);
if( Equal(temp2,b) )
{
Mul(d,d,temp1);
Div(temp1,b,temp2,d);
Mul(d,e,temp1);
Div(temp1,b,temp2,d);
}
return true;
}
Copy(kn_1,kn_2);
Copy(cn_1,cn_2);
Copy(ka_1,ka_2);
Copy(kn,kn_1);
Copy(cn,cn_1);
Copy(kan,ka_1);
} while (true);
}
void CLargeInt::RSAEncode( const CLargeInt &n,const CLargeInt &d,const CLargeInt &m,CLargeInt &c)
{
ExpMod(m,d,n,c);
}
void CLargeInt::RSADecode( const CLargeInt &n,const CLargeInt &e,const CLargeInt &c,CLargeInt &m)
{
ExpMod(c,e,n,m);
}
string CLargeInt::RSADecode(const char* N, const char* E, const char* I)
{
CLargeInt o;
CLargeInt n(N);
CLargeInt i(I);
CLargeInt e(E);
RSADecode(n, e, i, o);
return o.GetHexStr();
}
string CLargeInt::GetHexStr()
{
char buffer[128];
memset(buffer, 0x00, sizeof(buffer));
string strHex;
for (int i = _len - 1 ; i >= 0; i--)
{
char str[] = "%08X";
str[2] = '0' + sizeof(T_DWORD) * 2;
if ( i != (int)(_len - 1) )
{
sprintf(buffer, str, _data[i]);
}
else
{
sprintf(buffer, str, _data[i]);
}
strHex += buffer;
}
return strHex;
}
typedef unsigned __int64 ULONGLONG;
inline ULONGLONG GetCycleCount()
{
__asm RDTSC
}
//#include <windows.h>
void CLargeInt::CreateRandom(CLargeInt &n, T_DWORD bitcount)
{
n._len = (bitcount + 31) / 32;
for (T_DWORD i = 0; i < n._len; i++)
{
T_DWORD byte[4];
for (int b = 0; b < 4; b++)
{
for (int j = 0; j < 4; j++)
{
//Sleep(0);
j = j + 1 - 1;
}
byte[b] = GetCycleCount() & 0xFF;
}
n._data[i] = (byte[0] << 24)
| (byte[1] << 16)
| (byte[2] << 8)
| (byte[3] << 0);
}
n._data[0] |= 1;
n._data[n._len - 1] |= 0x80000000;
if ((bitcount & 31))
{
n._data[n._len - 1] >>= 32 - (bitcount & 31);
}
}
bool CLargeInt::Coprime(const CLargeInt &source,const CLargeInt &target)
{
CLargeInt m(source),n(target),temp;
while(true)
{
Div(m,n,temp,m);
if( m._len == 1 && m._data[0] == 1 ) return true;
else if( m._len == 1 && m._data[0] == 0 ) return false;
Div(n,m,temp,n);
if( n._len == 1 && n._data[0] == 1 ) return true;
else if( n._len == 1 && n._data[0] == 0 ) return false;
}
}
3.RSA工具
RSA工具(来源于网络),此工具用着比較顺手。