RSA实现(C++)

本文详细介绍了RSA算法的工作原理,涉及素性检测、模幂运算、大素数生成、公钥和私钥的生成,以及加密和解密的具体步骤,展示了RSA算法在信息安全中的关键作用。
摘要由CSDN通过智能技术生成

RSA算法思想

RSA Rivest-Shamir-Adleman )算法的主要思想是基于大素数分解的困难性来实现加密和解密操作。其主要步骤包括:
RSA 算法的安全性基于大整数分解问题的困难性,即给定一个大合数 n ,要找到其质因数p q 是一个非常困难的数学问题,目前尚未有有效的算法能够在多项式时间内解决该问题。因此,RSA 算法被广泛应用于信息安全领域中的加密通信、数字签名等方面。
代码实现与分析
(实现前需要编写几个必须要用到的函数)👇
1.素性检测函数:
Miller-Rabin 素性测试是一种概率性的素数判定算法,可以用来判断一个数是否很可能 是素数。函数接受一个大整数 p 作为输入,然后判断如果输入的数 p 2 ,那么直接返 回 true ,因为 2 是素数。然后,如果输入的数 p 小于等于 1 ,那么返回 false ,因为小 于等于 1 的数不是素数。接下来,计算出一个整数 d 和一个整数 s ,使得 p-1 = d 2^ s 。 这里用到了 p-1 的质因数分解。接着,进行多次迭代(这里是 100 次),在每次迭代中: 随机选择一个整数 a ,满足 1 < a < p-1 。检查 a p 是否互质,如果它们有公因子,则 直接返回 false ,表示 p 不是素数。计算 x = a^ d mod p 。如果 x 等于 1 或者 x 等于 p-1 , 那么继续下一次迭代。否则,进行 s-1 次循环:计算 x = x^ 2 mod p 。如果 x 等于 p-1 , 那么跳出循环,继续下一次迭代。如果 x 等于 1 ,那么直接返回 false ,表示 p 不是素 数。最后如果 x 不等于 p-1 ,那么返回 false ,表示 p 不是素数。若所有的迭代都没有返 回 false ,那么函数返回 true ,表示 p 很可能是素数。
bool isprime_Miller_Rabin(ZZ p)
		{
			if (p == 2)return true;
			if (p <= 1)return false;
			ZZ d = p - 1;
			long s = 0;
			while (d % 2 == 0) {
				d /= 2;
				s++;
			}
			for (long i = 0; i < 100; i++) {
				ZZ a;
				RandomBnd(a, p - 2);
				a++;
				if (GCD(a, p) != 1)
				return false;
				ZZ x = PowerMod(a, d, p);
				if (x == 1 || x == p - 1)
				continue;
				for (long r = 0; r <= s - 1; r++) {
					x = PowerMod(a, pow(2, r) * d, p);
					if (x == p - 1)
					break;
					if (x == 1)
					return false;
				}
				if (x != p - 1)
				return false;
			}
			return true;
		}

2. 模幂运算函数

函数接受底数 a,指数 b 和模数 m。在函数中创建一个大整数类型变量 r,并初始化为 1。使用循环,从 i = 0 开始,循环条件为 i < b,即执行 b 次循环。在每次循环中,将 r 更新为 r * a mod m。循环结束后,返回最终的结果 rr 即为 a b 次幂模 m 的结果。

ZZ powermod(ZZ a, ZZ b, ZZ m)
		{
			ZZ r = ZZ(1);
			for (ZZ i = ZZ(0);i < b;i++)
			{
				r = r * a % m;
			}
			return r;
		}

3.power函数

ZZ pow(ZZ a, ZZ b)
		{
			ZZ r = ZZ(1);
			for (ZZ i = ZZ(0);i < b;i++)
			{
				r = r * a;
			}
			return r;
		}

4.生成大素数 

d在循环中,不断生成 1024 比特位的随机数 a ,然后利用 Miller-Rabin 算法测试其是否 为素数,如果是素数,则返回该素数。如果不是素数,则继续生成下一个随机数进行测 试,直到找到一个素数为止。最后返回一个大整数类型的素数 a
ZZ get_prime()
		{
			while (1)
			{
				ZZ a = GenPrime_ZZ(1024);
				if (isprime_Miller_Rabin(a))
				return a;
			}
		}

5.得到fn


ZZ get_fn(ZZ p, ZZ q)
	{
		ZZ fn = (p - 1) * (q - 1);
		return fn;
	}

​

6.得到公钥

函数输入参数 fn 是欧拉函数φ(n)的值,其中 n 是两个质数 p 和 q 的乘积。在函数中使用了一个无限循环,并在每次循环中生成一个随机数 e,范围限定在 [0, fn-1] 之间(包括 0 和 fn-1)。然后通过判断条件来筛选出符合要求的 e 值。使用 GCD(e, fn) 函数计算 e 和 fn 的最大公约数。首先判断最大公约数是否等于 1,即 e 和 fn 是否互质。然后判断 e 是否等于 1,因为 e 不能等于 1。如果满足上述两个条件,则将找到的 e 值作为结果返回。

ZZ get_e(ZZ fn)
		{
			while (1)
			{
				ZZ e = RandomBnd(fn);
				if (GCD(e, fn) == 1 && e != 1)
				return e;
			}
		}

7.得到私钥

函数输入参数 e 是公钥的指数值,而 fn 是欧拉函数φ(n)的值,其中 n 是两个质数 p 和 q 的乘积。RSA 加密算法中,私钥由两个参数组成:n 和 d。其中,n 是两个质数 p 和 q 的乘积,而 d 是满足以下条件的整数:e * d ≡ 1 (mod φ(n)),0 < d < φ(n)。在这个函数中,使用了 InvMod(e, fn) 函数来计算 e 在模 fn 下的逆元。根据扩展欧几里得算法的原理,e 和 fn 互质时,InvMod(e, fn) 函数可以计算出使得 e * d ≡ 1 (mod fn) 成立的最小正整数 d。这个最小正整数就是私钥参数 d 的值。最后返回d。

ZZ get_d(ZZ fn, ZZ e)
		{
			ZZ d = InvMod(e, fn);
			return d;
		}

8.得到n=p*q

ZZ get_pq(ZZ p, ZZ q)
		{
			ZZ n = p * q;
			return n;
		}

9.加密算法

加密函数传入明文m,公钥e和n。在函数中,使用PowerMod函数进行幂模运算,将明文m用指数e进行加密,并将结果存储在变量c中。然后将c作为函数的返回值。
 

ZZ encrypt(ZZ m, ZZ e, ZZ n)
		{
			ZZ c = PowerMod(m, e, n);
			return c;
		}

10.解密算法

函数传入参数c是明文结果加密的的密文,私钥对(d,n)。使用 PowerMod 函数来计算密文 c 的 d 次方模 n 的结果,得到的结果存储在变量 M 中。然后使用 to_int 函数将 ZZ 类型的 M 转换为 int 类型的 MM,并将其作为结果返回。

int decrypt(ZZ c, ZZ d, ZZ n)
		{
			ZZ M = PowerMod(c, d, n);
			int MM = to_int(M);
			return MM;
		}

主函数👇

main() 函数中,首先调用了 get _ prime () 函数两次,分别生成了两个 1024 比特的 大素数 p q 。然后调用了 get _ fn () 函数,传入了 p q 作为参数,计算并返回了欧 拉函数的值 fn 。接下来调用了 get _ e () 函数,传入 fn 作为参数,生成并返回了私钥 e 。 然后调用了 get _ d () 函数,传入 fn e 作为参数,计算并返回了公钥 d 。接着调用了 get _ pq () 函数,传入 p q 作为参数,计算并返回了模数 n 。在输出部分,首先输出了生成的素数 p 和 q,欧拉函数的值 fn,私钥 e,公钥 d,以及模数 n。然后定义了一个长 度为 9 的整型数组 m ,表示明文。接下来开始进行加密操作。使用了一个循环,对每个 明文元素进行加密。调用 PowerMod() 函数,传入明文元素 m[i] ,公钥 e 和模数 n ,得 到密文 C ,并将其存储到数组 c[i] 中。加密过程的执行时间使用了 chrono 库计时。接着 输出密文数组 c[i] 。然后开始一般方法解密操作。定义了一个整型数组 MM ,用于存储 解密得到的明文。使用循环,对每个密文元素进行解密操作。调用 decrypt() 函数,传 入密文元素 c[i] ,私钥 d 和模数 n ,得到解密后的明文 mm ,并将其存储到数组 MM[i] 中。解密过程的执行时间同样使用了 chrono 库计时。最后输出一般解密得到的明文数 组 MM[i]
int main() {
			ZZ p = get_prime();
			ZZ q = get_prime();
			ZZ fn = get_fn(p, q);
			ZZ e = get_e(fn);
			ZZ d = get_d(fn, e);
			ZZ n = get_pq(p, q);
			cout << "p:" << p << "\n" << "q:" << q << "\n" << "fn:" << fn << "\n" << "e:" << e << "\n" << "d:" << d << "\n" << "n:" << n << endl;
			int m[x] = { ...};//自己定义一个明文,x是明文的位数
			int l = 9;
			cout<<endl;
			for (int i = 0;i < l;i++)
			{
				cout << m[i];
			}
			cout << endl;
			ZZ* c = new ZZ[l];
			//encrypting
			auto start_time = std::chrono::high_resolution_clock::now();
			for (int i = 0;i < l;i++)
			{
				ZZ C = PowerMod(ZZ(m[i]), e, n);
				c[i] = C;
			}
			auto end_time = std::chrono::high_resolution_clock::now();
			auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
			std::cout << "Running time: " << duration.count() << " ms" << std::endl;
			cout<<endl;
			for (int i = 0;i < l;i++)
			{
				cout << c[i];
			}
			cout << endl;
			//decrypt
			auto start_time1 = std::chrono::high_resolution_clock::now();
			int* MM = new int[l];
			for (int i = 0;i < l;i++)
			{
				int mm = decrypt(c[i], d, n);
				MM[i] = mm;
			}
			cout << endl;
			auto end_time1 = std::chrono::high_resolution_clock::now();
			auto duration1 = std::chrono::duration_cast<std::chrono::milliseconds>(end_time1 - start_time1);
			std::cout << "Running time: " << duration1.count() << " ms" << std::endl;
			cout<<endl;
			for (int i = 0;i < l;i++)
			{
				cout << MM[i];
			}
			cout << endl;
			return 0;
		}


 

最后不要忘记在开头包含要用到的库函数!!
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值