如何用VC++随机生成一个大素数(满足RSA算法)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何用VC++随机生成一个大素数(满足RSA算法)相关的知识,希望对你有一定的参考价值。

大素数要求是随机生成的,而且要足够大,满足RSA加密算法(即是一个很难分解出来的大素数)
问题确实有很大难度,但是小素数的生成还是比较简单的,因为本人最近在学习密码学的编程,所以希望大家多多帮忙思考一下。不甚感激!

你需要的包含在这个程序中,生成一个大数然后做RM素数测试,通过的我们假设其为素数即可!

RSA算法
1978年就出现了这种算法,它是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也很流行。算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman。但RSA的安全性一直未能得到理论上的证明。
RSA的安全性依赖于大数难于分解这一特点。公钥和私钥都是两个大素数(大于100个十进制位)的函数。据猜测,从一个密钥和密文推断出明文的难度等同于分解两个大素数的积。
密钥对的产生。选择两个大素数,p 和q 。计算:n = p * q 然后随机选择加密密钥e,要求 e 和 ( p - 1 ) * ( q - 1 )互质。最后,利用Euclid 算法计算解密密钥d, 满足e * d = 1 ( mod ( p - 1 ) * ( q - 1 ) )其中n和d也要互质。数e和n是公钥,d是私钥。两个素数p和q不再需要,应该丢弃,不要让任何人知道。加密信息 m(二进制表示)时,首先把m分成等长数据块 m1 ,m2,..., mi ,块长s,其中 2^s <= n, s 尽可能的大。对应的密文是:ci = mi^e ( mod n ) ( a ) 解密时作如下计算:mi = ci^d ( mod n ) ( b )
RSA 可用于数字签名,方案是用 ( a ) 式签名, ( b )式验证。具体操作时考虑到安全性和 m信息量较大等因素,一般是先作HASH 运算。RSA 的安全性。RSA的安全性依赖于大数分解,但是否等同于大数分解一直未能得到理论上的证明,因为没有证明破解RSA就一定需要作大数分解。假设存在一种无须分解大数的算法,那它肯定可以修改成为大数分解算法。目前,RSA的一些变种算法已被证明等价于大数分解。不管怎样,分解n是最显然的攻击方法。现在,人们已能分解140多个十进制位的大素数。因此,模数n必须选大一些,因具体适用情况而定。
由于进行的都是大数计算,使得RSA最快的情况也比DES慢上100倍,无论是软件还是硬件实现。速度一直是RSA的缺陷。一般来说只用于少量数据加密。
*/
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;//RSA算法所需参数
typedef struct RSA_PARAM_Tag

unsigned __int64 p, q; //两个素数,不参与加密解密运算
unsigned __int64 f; //f=(p-1)*(q-1),不参与加密解密运算
unsigned __int64 n, e; //公匙,n=p*q,gcd(e,f)=1
unsigned __int64 d; //私匙,e*d=1 (mod f),gcd(n,d)=1
unsigned __int64 s; //块长,满足2^s<=n的最大的s,即log2(n)
RSA_PARAM;//小素数表
const static long g_PrimeTable[]=

3,
5,
7,
11,
13,
17,
19,
23,
29,
31,
37,
41,
43,
47,
53,
59,
61,
67,
71,
73,
79,
83,
89,
97
;
const static long g_PrimeCount=sizeof(g_PrimeTable) / sizeof(long);const unsigned __int64 multiplier=12747293821;
const unsigned __int64 adder=1343545677842234541;//随机数类
class RandNumber


private:
unsigned __int64 randSeed;
public:
RandNumber(unsigned __int64 s=0);
unsigned __int64 Random(unsigned __int64 n);
;
RandNumber::RandNumber(unsigned __int64 s)

if(!s)

randSeed= (unsigned __int64)time(NULL);

else

randSeed=s;


unsigned __int64 RandNumber::Random(unsigned __int64 n)

randSeed=multiplier * randSeed + adder;
return randSeed % n;
static RandNumber g_Rnd;
inline unsigned __int64 MulMod(unsigned __int64 a, unsigned __int64 b, unsigned __int64 n)

return a * b % n;

unsigned __int64 PowMod(unsigned __int64 &base, unsigned __int64 &pow, unsigned __int64 &n)

unsigned __int64 a=base, b=pow, c=1;
while(b)

while(!(b & 1))

b>>=1; //a=a * a % n; //函数看起来可以处理64位的整数,但由于这里a*a在a>=2^32时已经造成了溢出,因此实际处理范围没有64位
a=MulMod(a, a, n);
b--; //c=a * c % n; //这里也会溢出,若把64位整数拆为两个32位整数不知是否可以解决这个问题。
c=MulMod(a, c, n);
return c;

long RabinMillerKnl(unsigned __int64 &n)

unsigned __int64 b, m, j, v, i;
m=n - 1;
j=0; //0、先计算出m、j,使得n-1=m*2^j,其中m是正奇数,j是非负整数
while(!(m & 1))

++j;
m>>=1;
//1、随机取一个b,2<=b<n-1
b=2 + g_Rnd.Random(n - 3); //2、计算v=b^m mod n
v=PowMod(b, m, n); //3、如果v==1,通过测试
if(v == 1)

return 1;
//4、令i=1
i=1; //5、如果v=n-1,通过测试
while(v != n - 1)

//6、如果i==l,非素数,结束
if(i == j)

return 0;
//7、v=v^2 mod n,i=i+1
unsigned __int64 tmp1 = 2;
v=PowMod(v,tmp1, n);
++i; //8、循环到5
return 1;

long RabinMiller(unsigned __int64 &n, long loop)

//先用小素数筛选一次,提高效率
for(long i=0; i < g_PrimeCount; i++)

if(n % g_PrimeTable[i] == 0)

return 0;

//循环调用Rabin-Miller测试loop次,使得非素数通过测试的概率降为(1/4)^loop
for(long i=0; i < loop; i++)

if(!RabinMillerKnl(n))

return 0;

return 1;

unsigned __int64 RandomPrime(char bits)

unsigned __int64 base;
do

base= (unsigned long)1 << (bits - 1); //保证最高位是1
base+=g_Rnd.Random(base); //再加上一个随机数
base|=1; //保证最低位是1,即保证是奇数
while(!RabinMiller(base, 30)); //进行拉宾-米勒测试30次
return base; //全部通过认为是素数

unsigned __int64 EuclidGcd(unsigned __int64 &p, unsigned __int64 &q)

unsigned __int64 a=p > q ? p : q;
unsigned __int64 b=p < q ? p : q;
unsigned __int64 t;
if(p == q)

return p; //两数相等,最大公约数就是本身

else

while(b) //辗转相除法,gcd(a,b)=gcd(b,a-qb)

a=a % b;
t=a;
a=b;
b=t;
return a;


unsigned __int64 SteinGcd(unsigned __int64 &p, unsigned __int64 &q)

unsigned __int64 a=p > q ? p : q;
unsigned __int64 b=p < q ? p : q;
unsigned __int64 t, r=1;
if(p == q)

return p; //两数相等,最大公约数就是本身

else

while((!(a & 1)) && (!(b & 1)))

r<<=1; //a、b均为偶数时,gcd(a,b)=2*gcd(a/2,b/2)
a>>=1;
b>>=1;
if(!(a & 1))

t=a; //如果a为偶数,交换a,b
a=b;
b=t;
do

while(!(b & 1))

b>>=1; //b为偶数,a为奇数时,gcd(b,a)=gcd(b/2,a)
if(b < a)

t=a; //如果b小于a,交换a,b
a=b;
b=t;
b=(b - a) >> 1; //b、a都是奇数,gcd(b,a)=gcd((b-a)/2,a)
while(b);
return r * a;


unsigned __int64 Euclid(unsigned __int64 &a, unsigned __int64 &b)

unsigned __int64 m, e, i, j, x, y;
long xx, yy;
m=b;
e=a;
x=0;
y=1;
xx=1;
yy=1;
while(e)

i=m / e;
j=m % e;
m=e;
e=j;
j=y;
y*=i;
if(xx == yy)

if(x > y)

y=x - y;

else

y-=x;
yy=0;


else

y+=x;
xx=1 - xx;
yy=1 - yy;
x=j;
if(xx == 0)

x=b - x;
return x;

RSA_PARAM RsaGetParam(void)

RSA_PARAM Rsa= 0 ;
unsigned __int64 t;
Rsa.p=RandomPrime(16); //随机生成两个素数
Rsa.q=RandomPrime(16);
Rsa.n=Rsa.p * Rsa.q;
Rsa.f=(Rsa.p - 1) * (Rsa.q - 1);
do

Rsa.e=g_Rnd.Random(65536); //小于2^16,65536=2^16
Rsa.e|=1; //保证最低位是1,即保证是奇数,因f一定是偶数,要互素,只能是奇数
while(SteinGcd(Rsa.e, Rsa.f) != 1); Rsa.d=Euclid(Rsa.e, Rsa.f);
Rsa.s=0;
t=Rsa.n >> 1;
while(t)

Rsa.s++; //s=log2(n)
t>>=1;
return Rsa;

void TestRM(void)

unsigned long k=0;
cout << " - Rabin-Miller prime check.n" << endl;
for(unsigned __int64 i=4197900001; i < 4198000000; i+=2)

if(RabinMiller(i, 30))

k++;
cout << i << endl;

cout << "Total: " << k << endl;

void TestRSA(void)

RSA_PARAM r;
char pSrc[]="abcdefghijklmnopqrstuvwxyz";
const unsigned long n=sizeof(pSrc);
unsigned char *q, pDec[n];
unsigned __int64 pEnc[n];
r=RsaGetParam();
cout << "p=" << r.p << endl;
cout << "q=" << r.q << endl;
cout << "f=(p-1)*(q-1)=" << r.f << endl;
cout << "n=p*q=" << r.n << endl;
cout << "e=" << r.e << endl;
cout << "d=" << r.d << endl;
cout << "s=" << r.s << endl;
cout << "Source:" << pSrc << endl;
q= (unsigned char *)pSrc;
cout << "Encode:";
for(unsigned long i=0; i < n; i++)

unsigned __int64 tmp2 = q[i];
pEnc[i]=PowMod(tmp2, r.e, r.n);
cout << hex << pEnc[i] << " ";
cout << endl;
cout << "Decode:";
for(unsigned long i=0; i < n; i++)

pDec[i]=PowMod(pEnc[i], r.d, r.n);
cout << hex << (unsigned long)pDec[i] << " ";
cout << endl;
cout << (char *)pDec << endl;

int main(void)

TestRSA();
return 0;

参考资料:http://blog.sina.com.cn/s/blog_5c595a560100kn44.html

参考技术A 首先如果搞密码学的编程 推荐你看本书《程序员密码学》里面讲的是现在密码学的实现
再次,解决生成大素数的这个问题思路是这样的:随机生成一个很大的数,用
< 素性检验 >的算法判断这个数是不是素数 如果不是 继续生成另一个大素数 再判断 直到找到一个大素数
也就是说 核心是 素性检验 算法 这种算法不少 有fermat素性检验 Miller-Rabin素性检验 还有好几种 但是没数学基础的话是搞不懂的 如果深入了解的话 参照一本书《信息安全数学基础》其中有一章都是讲 素性检验的问题的
推荐楼主采用 fermat素性检验 最简单 但是个不确定算法 因为有fermat欺骗 但是概率极低极低 可以用
http://baike.baidu.com/view/831881.htm本回答被提问者采纳
参考技术B 我只学过c语言不知这样行吗 随机生成一个大数n,再n(n-1)+1.不知道行不,加密就搞不懂了 参考技术C 好难

RSA 加密

1、RSA算法介绍

RSA是目前最有影响力的公钥加密算法,该算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即公钥,而两个大素数组合成私钥。公钥是可发布的供任何人使用,私钥则为自己所有,供解密之用。
 
        解密者拥有私钥,并且将由私钥计算生成的公钥发布给加密者。加密都使用公钥进行加密,并将密文发送到解密者,解密者用私钥解密将密文解码为明文。
 
        以甲要把信息发给乙为例,首先确定角色:甲为加密者,乙为解密者。首先由乙随机确定一个KEY,称之为密匙,将这个KEY始终保存在机器B中而不发出来;然后,由这个 KEY计算出另一个KEY,称之为公匙。这个公钥的特性是几乎不可能通过它自身计算出生成它的私钥。接下来通过网络把这个公钥传给甲,甲收到公钥后,利用公钥对信息加密,并把密文通过网络发送到乙,最后乙利用已知的私钥,就对密文进行解码了。以上就是RSA算法的工作流程。
 

2、RSA算法实现

        1. 随意选择两个大的质数p和q,p不等于q,计算N=pq。
        2. 根据欧拉函数,不大于N且与N互质的整数個数為(p-1)(q-1)。
        3. 选择一个整数e与(p-1)(q-1)互质,并且e小于(p-1)(q-1)。
        4. 用以下这个公式计算d:d× e ≡ 1 (mod (p-1)(q-1))。
        5. 将p和q的记录销毁。
 
        以上内容中,(N,e)是公钥,(N,d)是私钥。
 

以上是关于如何用VC++随机生成一个大素数(满足RSA算法)的主要内容,如果未能解决你的问题,请参考以下文章

急急急 求大神帮忙 用vc++ 生成1024位大素数 用到米勒拉宾素性测试

RSA 算法

如何用C语言生成时间的随机数

密码疑云 ——详解RSA的加密与解密

记一次使用快速幂与Miller-Rabin的大素数生成算法

RSA 加密