算法系列2《RSA》
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密钥长度随着保密级别提高,增加很快。下表列出了对同一安全级别所对应的密钥长度。
|
|
|
|
|
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工具(来源于网络),此工具用着比较顺手。软件下载地址:http://download.csdn.net/detail/yxstars/7734567
文/闫鑫原创转载请注明出处http://blog.csdn.net/yxstars/article/details/38443937
算法系列2《RSA》的更多相关文章
- 【来龙去脉系列】RSA算法原理
如果你问我,哪一种算法最重要? 我可能会回答"公钥加密算法". 因为它是计算机通信安全的基石,保证了加密数据不会被破解.你可以想象一下,信用卡交易被破解的后果. 进入正题之前,我先 ...
- 9.Java 加解密技术系列之 RSA
Java 加解密技术系列之 RSA 序 概念 工作流程 RSA 代码实现 加解密结果 结束语 序 距 离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版.上线,又是新项 ...
- 秀尔算法:破解RSA加密的“不灭神话”
RSA加密 VS 秀尔算法 作为RSA加密技术的终结者——“太多运算,无法读取”的秀尔算法(Shor’s algorithm)不是通过暴力破解的方式找到最终密码的,而是利用量子计算的并行性,可以快速分 ...
- JAVA算法系列 冒泡排序
java算法系列之排序 手写冒泡 冒泡算是最基础的一个排序算法,简单的可以理解为,每一趟都拿i与i+1进行比较,两个for循环,时间复杂度为 O(n^2),同时本例与选择排序进行了比较,选择排序又叫直 ...
- JAVA算法系列 快速排序
java算法系列之排序 手写快排 首先说一下什么是快排,比冒泡效率要高,快排的基本思路是首先找到一个基准元素,比如数组中最左边的那个位置,作为基准元素key,之后在最左边和最右边设立两个哨兵,i 和 ...
- javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
- 三白话经典算法系列 Shell排序实现
山是包插入的精髓排序排序,这种方法,也被称为窄增量排序.因为DL.Shell至1959提出命名. 该方法的基本思想是:先将整个待排元素序列切割成若干个子序列(由相隔某个"增量"的元 ...
- Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx Aitit algo fix 算法系列补充.docx Atiitt 兼容性提示的艺术 attilax总结.docx Atitit 应用程序容器化总结 v2 s66.docx Atitit file cms api
Atitit s2018.6 s6 doc list on com pc.docx Atitit s2018.6 s6 doc list on com pc.docx Aitit algo fi ...
- 【C#实现漫画算法系列】-判断 2 的乘方
微信上关注了算法爱好者这个公众号,有一个漫画算法系列的文章生动形象,感觉特别好,给大家推荐一下(没收过广告费哦),原文链接:漫画算法系列.也看到了许多同学用不同的语言来实现算法,作为一枚C#资深爱好的 ...
随机推荐
- Basler usb SDK安装在opencv采集图像
近期,入手一台baslerUSB接口的CCD相机,但是貌似之前图像采集的编程无法调动其摄像头,在网上搜了一下,大家的说法就是安装它的SDK文件包,并且调用它内部函数编写代码.其实新版的Basle相机驱 ...
- C#数字图像处理算法学习笔记(三)--图像几何变换
C#数字图像处理算法学习笔记(三)--图像几何变换 几何图像处理包括 图像的平移变换,镜像变换,旋转变换,伸缩变换,在这里仅以水平镜像为例,通过代码来理解其基本操作方式: 翻转前:
- Win2D 官方文章系列翻译 - DPI (每英寸点数)和 DIPs(设备独立像素)
本文为个人博客备份文章,原文地址: http://validvoid.net/win2d-dpi-dips/ 本文旨在解释物理像素与设备独立像素(DIPs, device independent pi ...
- Android开发-API指南-进程与线程
Processes and Threads 英文原文:http://developer.android.com/guide/components/processes-and-threads.html ...
- Flash图表控件FusionCharts如何定制图表中的趋势线和趋势区
FusionCharts中的趋势线是什么 趋势线是横跨图标的水平/垂直线条,用来表示一些预订数据值. 在图表中展示趋势线 用户可以使用<chart>元素中的trendlines属性来显示图 ...
- Oracle 时间相减得出毫秒、秒、分、时、天,,【转】
http://blog.csdn.net/redarmy_chen/article/details/7351410 oracle 两个时间相减默认的是天数 oracle 两个时间相减默认的是天数*24 ...
- phpinfo中查不到memcache信息问题
已经安装了php的memcache扩展,可是怎么都不能通过phpinfo查询到,实际使用时提示扩展未安装.为什么呢?百般寻求解决方法,才发现主要有以下两点原因: 1.使用的php和安装扩展的php不是 ...
- pip的安装及使用
pip 是“A tool for installing and managing Python packages.”,即pip是python的软件安装工具安装:方法一:(亲自使用)1.去官网下载get ...
- ASPxGridView中批量提交及个别提交的写法
//获取chech box ID protected string GetProtoID() { string protoId = ""; //获取选中的记录Id List< ...
- (总结)Web性能压力测试工具之WebBench详解
PS:在运维工作中,压力测试是一项很重要的工作.比如在一个网站上线之前,能承受多大访问量.在大访问量情况下性能怎样,这些数据指标好坏将会直接影响用户体验.但是,在压力测试中存在一个共性,那就是压力 ...