GMP大数库实现RSA算法

#include <iostream>
#include <stdio.h>
#include "gmp.h"
#define MILLER_RABIN_TEST_NUM 5
#define PRIME_BIT 512
typedef unsigned char Bit8;
typedef unsigned short Bit16;
typedef unsigned int Bit32;
void getRSAparam(mpz_t n, mpz_t p, mpz_t q, mpz_t e, mpz_t d);
void getPrime(mpz_t n);
bool MillerRabin(const mpz_t n);
void PowerMod(const mpz_t a, const mpz_t b, const mpz_t n, mpz_t s);
bool SetTestNum(const mpz_t n);
bool getModInverse(const mpz_t n, const mpz_t e, mpz_t d);
void ChineseRemainderTheorem(const mpz_t a, const  mpz_t b, const  mpz_t p, const mpz_t q, mpz_t s);
void MontPowerMod(const mpz_t a, const mpz_t b, const mpz_t n, mpz_t s);
void MontMult(mpz_t A, mpz_t B, const mpz_t n, int n_bit, const mpz_t IN);
void RSA_CMP(mpz_t n, mpz_t p, mpz_t q, mpz_t e, mpz_t d);

using namespace std;
void printRSA(void);
int main(void){
	printRSA();
	cout <<"\n";
	return 0;
}


void printRSA(void){
	int op = 1;
	int flag = 0;
	clock_t start, end;
	mpz_t n, p, q, e, d;
	mpz_inits(n, p, q, e, d, NULL);
	while (op){
		system("clear");
		printf("\n===================请选择要测试的项目=================\n");
		printf("  1.生成RSA的5个参数  2.比较不同方法加速RSA  0.退出\n");
		printf("======================================================\n");
		printf("请输入[0-2]:");
		scanf("%d", &op);

		switch (op){
		case 1:
			cout << "\n正在获取5个参数,请等待......\n\n";
			start = clock();
			getRSAparam(n, p, q, e, d); //获得RSA的5个参数
			end = clock();
			flag = 1;
			cout << "参数p(" << mpz_sizeinbase(p, 2) << "bit):\n";
			gmp_printf("Hex: %Zx\n\n", p);

			cout << "参数q(" << mpz_sizeinbase(q, 2) << "bit):\n";
			gmp_printf("Hex: 0x%Zx\n\n", q);

			cout << "参数n(" << mpz_sizeinbase(n, 2) << "bit):\n";
			gmp_printf("Hex: 0x%Zx\n\n", n);

			cout << "参数e(" << mpz_sizeinbase(e, 2) << "bit):\n";
			gmp_printf("Hex: 0x%Zx\n\n", e);

			cout << "参数d(" << mpz_sizeinbase(d, 2) << "bit):\n";
			gmp_printf("Hex: 0x%Zx\n\n", d);
			printf("获取5个RSA参数的时间为%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
			cout << "\n按回车继续......";
			getchar(); getchar();
			break;
		case 2:
			if (flag)
				RSA_CMP(n, p, q, e, d);
			else{
				cout << "\n请先使用功能1生成RSA算法的5个参数\n";
				cout << "\n按回车继续......";
				getchar(); getchar();
			}
			break;
		default:;
		}
	}
	mpz_clears(n, p, q, e, d, NULL);
}

//获取RSA算法的5个参数
void getRSAparam(mpz_t n, mpz_t p, mpz_t q, mpz_t e, mpz_t d){
	clock_t start, end;
	//获取前三个参数n,p,q
	do{
		getPrime(p);
		getPrime(q);
	} while (!mpz_cmp(p, q));  //p!=q

	mpz_mul(n, p, q);

	//获取d,e
	mpz_t p_1, q_1, n_1;   //分别代表φ(p), φ(q), φ(n)
	mpz_inits(p_1, q_1, n_1,NULL);  //初始化
	mpz_sub_ui(p_1, p, 1);  //φ(p)=p-1
	mpz_sub_ui(q_1, q, 1);  //φ(q)=q-1
	mpz_mul(n_1, p_1, q_1);  //φ(n)=(p-1)(q-1)

	gmp_randstate_t state;
	gmp_randinit_default(state);//对state进行初始化
	gmp_randseed_ui(state, time(NULL));//对state置初始种子

	while (1){
		mpz_urandomm(e, state, n_1);   //产生随机数0=<b<=φ(n), 生成公钥
		if (getModInverse(e, n_1, d))  //使用求e模φ(n)的逆d, 作为私钥
			break;
	}

	mpz_clears(n_1, p_1, q_1, NULL);
	gmp_randclear(state);
}

//获取一个大整数,大小默认为512bit
void getPrime(mpz_t n){
	int i, random = 0;
	srand(time(NULL));
	char rand_num[PRIME_BIT + 1]; //用于存放512bit的随机数
	rand_num[PRIME_BIT] = '\0';   
	rand_num[0] = '1';  //第一个bit设置为1,保证生成的是512位的素数
	rand_num[1] = '1';  //第二个bit设置为1,保证相乘后是1024位的素数
	rand_num[PRIME_BIT - 1] = '1';  //最后一bit设置为1,保证是奇数
	while(1){	
		for (i = 2; i<PRIME_BIT -1; i++){	
			random = rand();
			rand_num[i] = '0' + (0x1 & random);
		}
		mpz_set_str(n, rand_num, 2);
		if (SetTestNum(n))
			break;
	} 
}

//设置素性检测的次数,并调用MillerRabin算法进行检测
bool SetTestNum(const mpz_t n){
	for (int i = 0; i<MILLER_RABIN_TEST_NUM; i++)
		if (!MillerRabin(n))
			return false;
	return true;
}

//MillerRabin算法进行素性检测
bool MillerRabin(const mpz_t n){
	gmp_randstate_t state;
	gmp_randinit_default(state);         //对state进行初始化
	gmp_randseed_ui(state, time(NULL));  //对state置初始种子

	mpz_t m, a, b, flag, n_1;
	mpz_inits(m, a, b, flag, n_1, NULL);  //初始化
	
	mpz_sub_ui(m, n, 1);      //m=n-1
	mpz_mod_ui(flag, m, 2);  //flag=m%2
	mpz_sub_ui(n_1, n, 1);    //n_1=n-1=-1mod n

	//下面计算二次探测的最大次数, φ(n)=n-1=2^r*m, m为奇数
	int r = 0;
	//计算r, 将n-1表示成m*2^r
	while (!mpz_tstbit(m,1)){  //测试最后一位,为1说明是奇数,终止循环。为0则说明是偶数,继续循环
		mpz_tdiv_q_2exp(m, m, 1);    //m右移一位, 即m=m/2
		r++;
	}
	//随机生成一个[1,n-1]之间的随机数
	mpz_urandomm(a, state, n_1);   //产生随机数a, 0<=a<=n-2
	mpz_add_ui(a, a, 1);           //a=a+1,此时1<=a<=n-1
	PowerMod(a, m, n, b);          //计算出b=a^m mod n
	if (!mpz_cmp_ui(b, 1)){    //若a^m=1, 则说明通过二次探测, 直接返回
		mpz_clears(m, flag, n_1, a, b,NULL);  //清理申请的大数空间
		gmp_randclear(state);
		return  true;
	}
	//n-1表示成m*2^r,如果n是一个素数,那么或者a^m mod n=1,
	//或者存在某个i使得a^(m*2^i) mod n=n-1 ( 0<=i<r ) 
	for (int i = 0; i < r; i++){   
		if (!mpz_cmp(b, n_1)){   //若b=n-1,说明符合二次探测,返回true
			mpz_clears(m, flag, n_1, a, b, NULL);
			gmp_randclear(state);
			return  true;
		}
		else{
			mpz_mul(b, b, b);//b=b^2;
			mpz_mod(b, b, n);//b=b mod n;
		}
	}

	mpz_clears(m, flag, n_1, a, b, NULL);
	gmp_randclear(state);
	return false;
}

//模重复平方法,计算a^b(mod n),并将结果赋值给s
void PowerMod(const mpz_t a, const mpz_t b, const mpz_t n, mpz_t s){

	mpz_t t1, t2, t3;
	mpz_inits(t1, t2, t3, NULL);
	mpz_set_ui(t1, 1);  //t1=1;
	mpz_set(t2, a);    //t2=a;
	mpz_set(t3, b);    //t3=b;

	while (mpz_cmp_ui(t3,0)){

		if (mpz_tstbit(t3,0)){  //测试t3二进制的最后一位,若为1则说明 t3 mod 2=1
			//t1 = (t1*t2) mod n
			mpz_mul(t1, t1, t2); 
			mpz_mod(t1, t1, n);  
		}

		//t2 = (t2*t2) mod n
		mpz_mul(t2, t2, t2);
		mpz_mod(t2, t2, n);

		mpz_tdiv_q_2exp(t3, t3, 1); // 指数t3右移1位,即t3=t3/2
	}

	mpz_set(s, t1); //将最后的结果t1赋值给s
	mpz_clears(t1, t2, t3, NULL);

}

//使用拓展欧几里得算法求e的模n的逆元d
bool getModInverse(const mpz_t e, const mpz_t n, mpz_t d){
	mpz_t a, b, c, c1, t, q, r;
	mpz_inits(a, b, c, c1, t, q, r, NULL);
	mpz_set(a, n);//a=n;
	mpz_set(b, e);//b=e;
	mpz_set_ui(c, 0);//c=0
	mpz_set_ui(c1, 1);//c1=1
	mpz_tdiv_qr(q, r, a, b); 
	while (mpz_cmp_ui(r, 0))//r==0终止循环
	{	
		mpz_mul(t, q, c1);//t=q*c1
		mpz_sub(t, c, t);//t=c-q*c1

		mpz_set(c, c1);   //c=c1  向后移动
		mpz_set(c1, t);   //c1=t  向后移动
		
		mpz_set(a, b);//a=b 除数变为被除数
		mpz_set(b, r);//b=r 余数变为除数,开始下一轮
		mpz_tdiv_qr(q, r, a, b);  //取下一个q
	}
	mpz_set(d, t);  //将最后一轮的t赋值给d, d就是e的模n的逆元

	//保证返回正整数
	mpz_add(d, d, n);
	mpz_mod(d, d, n);

	mpz_clears(a, c, t, q, r, NULL);

	if (mpz_cmp_ui(b, 1)){
		mpz_clear(b);
		return false;
	}
	else{
		mpz_clear(b);
		return true;
	}
}

//中国剩余定理
void ChineseRemainderTheorem(const mpz_t a, const  mpz_t b, const  mpz_t p, const mpz_t q, mpz_t s){
	mpz_t x, y, p_0, q_0, p_1, q_1, t1, t2, n;
	mpz_inits(x, y, p_0, q_0, p_1, q_1, t1, t2, n, NULL);

	mpz_sub_ui(p_0, p, 1);  //p_0=p-1,p_0即φ(p)
	mpz_sub_ui(q_0, q, 1);  //q_0=q-1,q_0即φ(q)
	mpz_mod(p_0, b, p_0);   //p_0=b mod p_0,  即p_0=b mod φ(p)
	mpz_mod(q_0, b, q_0);   //q_0=b mod q_0,  即q_0=b mod φ(q)

	//PowerMod(a, p_0, p, x);//x=a^b%p
	//PowerMod(a, q_0, q, y);//y=a^b%q

	mpz_powm(x, a, p_0, p);
	mpz_powm(y, a, q_0, q);


	getModInverse(p, q, p_1);//求p模q的逆
	getModInverse(q, p, q_1);//求q模p的逆

	//mpz_invert(q_1, p, q);//求p模q的逆
	//mpz_invert(p_1, q, p);//求p模q的逆
	//getModInverse(q, p, p_1);//求q模p的逆
	//gmp_printf("*********%Zd", q_1);
	//gmp_printf("*********%Zd", q_1);

	//s=(x*q*q_1 + y*p*p_1) mod n

	mpz_mul(t1, x, q);    //t1=x*q
	mpz_mul(t1, t1, q_1); //t1=x*q*q_1
	mpz_mul(t2, y, p);    //t2=y*p
	mpz_mul(t2, t2, p_1); //t2=y*p*p_1

	mpz_add(s, t1, t2);   //中国剩余定理:(t1+t2)mod n
	mpz_mul(n, p, q);
	mpz_mod(s, s, n);

	mpz_clears(x, y, p_0, q_0, p_1, q_1, t1, t2, n, NULL);
}

//Montgomery算法,计算a^b(mod n),并将结果赋值给s
void MontPowerMod(const mpz_t a, const mpz_t b, const mpz_t n, mpz_t s){
	mpz_t R, R1, Prod, A, IN, B, e;
	mpz_inits(R, R1, Prod, A, IN, B, e, NULL);

	mpz_set(e, b);

	//IN= -n^(-1) mod 2^32
	mpz_ui_pow_ui(B, 2, 32); //B=2^32
	getModInverse(n, B, IN); //IN=n^(-1) mod B
	mpz_sub(IN, B, IN);   //-n^(-1)= B-n^(-1) mod B

	//生成比模n略大的参数R=2^n_bit
	int n_bit = mpz_sizeinbase(n, 2);
	mpz_ui_pow_ui(R, 2, n_bit);

	//Prod=Mont(1),A=Mont(a)
	mpz_mul_ui(Prod, R, 1);
	mpz_mod(Prod, Prod, n);
	mpz_mul(A, R, a);
	mpz_mod(A, A, n);

	while (mpz_cmp_ui(e, 0)){
		if (mpz_tstbit(e,0))
			MontMult(Prod, A, n, n_bit, IN);
		MontMult(A, A, n, n_bit, IN);
		mpz_tdiv_q_2exp(e, e, 1); //e=e>>1
	}

	//s=MontInv(Prod)=Prod*R(-1) mod n
	getModInverse(R, n, R1);
	mpz_mul(Prod, Prod, R1);
	mpz_mod(Prod, Prod, n);
	mpz_set(s, Prod);

	mpz_clears(R, R1, Prod, A, IN, B, e, NULL);
}

//蒙哥马利模乘,A=(A*B)mod n
void MontMult(mpz_t A, mpz_t B, const mpz_t n, int n_bit, const mpz_t IN){
	mpz_t T, T1, t0, b_32;
	mpz_inits(T, T1, t0, b_32, NULL);
	
	mpz_mul(T, A, B);  //T=A*B
	mpz_set_ui(b_32, 0xFFFFFFFF);

	int t = n_bit >> 5;
	for(int i = 0; i < t; i++){
		mpz_and(t0, T, b_32);
		mpz_mul(t0, IN, t0); 
		mpz_and(t0, t0, b_32);

		//T1=T+n*t0
		mpz_mul(T1, n, t0);
		mpz_add(T1, T, T1);

		//T1>>32,T=T1
		mpz_tdiv_q_2exp(T1, T1, 32); 
		mpz_set(T, T1);

	}

	if (mpz_cmp(T1, n) > 0){  //T1>n,A=T1-n
		mpz_sub(T1, T1, n);
		mpz_set(A, T1);
	}
	else
		mpz_set(A, T1);
	mpz_clears(T, T1, t0, b_32, NULL);
}

//比较模重复平方法、中国剩余定理以及Montgomery算法的对RSA的加速
void RSA_CMP(mpz_t n, mpz_t p, mpz_t q, mpz_t e, mpz_t d){
	int op = 1;
	mpz_t x, y, tmp;
	mpz_inits(x, y, tmp, NULL);
	clock_t start, end;
	printf("\n  请输入将要被加密的数据(请输入整数):\n  ");
	gmp_scanf("%Zd", x);

	while(1){
		system("clear");
		printf("\n===============请选择快速实现RSA的算法================\n");
		printf("  1.模重复平方  2.中国剩余定理  3.Montgomery  0.退出\n");
		printf("=====================================================\n");
		printf("请输入[0-3]:");
		scanf("%d", &op);
		if (!op)
			break;
		switch (op){
			case 1:
				start = clock();
				PowerMod(x, e, n, y);  //使用公钥e加密明文x,得到密文y
				end = clock();
				printf("\n加密时间为%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
				gmp_printf("密文为:\n  %Zd\n\n", y);

				start = clock();
				PowerMod(y, d, n, tmp);
				end = clock();
				printf("解密密时间为%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
				gmp_printf("解密后,明文为:\n  %Zd\n", tmp);
				cout << "\n按回车继续......";
				getchar(); getchar(); 
				break;
			case 2:
				start = clock();
				PowerMod(x, e, n, y);
				end = clock();
				printf("\n加密时间为%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
				gmp_printf("密文为:\n  %Zd\n\n", y);

				start = clock();
				ChineseRemainderTheorem(y, d, p, q,tmp);
				end = clock();
				printf("解密密时间为%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
				gmp_printf("解密后,明文为:\n  %Zd\n", tmp);
				cout << "\n按回车继续......";
				getchar(); getchar(); 
				break;
				
			case 3:
				start = clock();
				MontPowerMod(x, e, n, y);  //使用公钥e加密明文x,得到密文y
				end = clock();
				printf("\n加密时间为%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
				gmp_printf("密文为:\n  %Zd\n\n", y);

				start = clock();
				MontPowerMod(y, d, n, tmp);
				end = clock();
				printf("解密密时间为%.3f秒\n", (double)(end - start) / CLOCKS_PER_SEC);
				gmp_printf("解密后,明文为:\n  %Zd\n", tmp);
				cout << "\n按回车继续......";
				getchar(); getchar();
				break;
			default:;
		}
	} 

	mpz_clears(x, y, tmp, NULL);
}


### 回答1: RSA是一种非对称加密算法,使用公钥和私钥进行加密和解密。而GMP(GNU Multiple Precision Arithmetic Library)是一个C/C++,用于实现对大整数的高精度计算。通过结合RSAGMP,可以实现RSA加解密算法大数的处理。 在RSA算法中,首先需要生成一对密钥,包括公钥和私钥。公钥用于加密数据,私钥用于解密数据。生成密钥对的过程可以通过GMP实现高精度的计算和随机数生成。 接下来,使用公钥对要加密的数据进行加密,这时候需要使用GMP来处理大数的运算,包括幂运算和取模运算。将明文转换为对应的大整数后,通过公钥进行加密计算,并将结果转换为密文。 当需要解密密文时,使用私钥进行解密操作。同样需要使用GMP进行大数的运算,包括求幂和取模运算。将密文转换为对应的大整数后,通过私钥进行解密计算,并将结果转换为明文。 在实际应用中,一般会选择合适的大素数作为RSA算法的参数,这时候GMP可以帮助我们进行高精度的素数运算和随机数生成。同时,GMP还可以辅助处理大整数的运算,提高RSA算法的效率和安全性。 综上所述,RSA加解密算法可以通过GMP大数实现。通过GMP的高精度计算和随机数生成功能,可以辅助进行RSA密钥的生成、大整数的加解密计算。这种组合可以提高RSA算法大数的处理能力,保证了加密和解密的安全性和效率。 ### 回答2: RSA加解密算法是一种非对称加密算法,用于保护网络通信中的数据安全。GMP(GNU Multiple Precision Arithmetic Library)是一个开源的大数运算,提供了高精度的数值计算函数,可以用于实现RSA加解密算法。 在RSA加解密算法中,首先需要选择两个不同的大素数p和q,并计算它们的乘积n。然后选择一个整数e作为公钥,使得e与(p-1)(q-1)互质。接下来,计算一个整数d作为私钥,满足ed ≡ 1 (mod (p-1)(q-1))。公钥为(n, e),私钥为(n, d)。 加密时,将明文m转换为整数M,然后使用公式C ≡ M^e mod n进行加密。解密时,将密文C使用公式M ≡ C^d mod n进行解密,得到明文m。 GMP大数可以提供高精度的整数计算函数,使得在实现RSA算法中能够处理超过机器原生整数表示范围的大数。它提供了高效的大数运算方法,包括大数的加法、减法、乘法和取模运算,以及快速幂运算等。通过使用GMP大数,可以保证RSA加解密算法在计算大数时的准确性和高效性。 综上所述,RSA加解密算法可以通过使用GMP大数实现,其中GMP大数提供了高精度的整数计算函数,可以保证RSA算法在处理大数时的准确性和效率。 ### 回答3: RSA(Rivest-Shamir-Adleman)加解密算法是一种非对称加密算法,常用于保护数据的机密性和完整性。RSA算法涉及大数运算,在实现过程中,可以使用GMP(GNU Multiple Precision Arithmetic Library)大数来处理大整数运算。 GMP是一个开源的大数,它提供了高精度的整数和浮点数运算功能。使用GMP可以有效地处理超过CPU位数范围的整数运算,满足RSA算法所需的大整数需求。 在实现RSA加解密算法时,首先需要生成一对公私钥。GMP可以提供生成大素数、随机数和快速幂模运算等功能。通过这些功能,可以生成RSA算法所需的大素数p和q,并计算出公钥e和私钥d。 在加密时,可以使用GMP中的幂模运算函数,将明文m加密为密文c,使用公钥e进行加密运算:c = m^e mod n。其中,n是p和q的乘积。 在解密时,同样可以使用GMP中的幂模运算函数,将密文c解密为明文m,使用私钥d进行解密运算:m = c^d mod n。同样,n是p和q的乘积。 通过使用GMP大数实现RSA加解密算法,可以保证对大整数的高效处理和准确计算,确保RSA算法的安全性和正确性。同时,GMP的开源特性也使得算法实现更加灵活和可扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值