c++代码实现 RSA的简易demo【偏向实践】
写在前面
【如果你还没搞明白算法具体步骤建议先去看视频了解,本demo旨在简单实践该算法】
本实践在理论上是成立的,但由于计算x的时候很容易溢出,所以观者可以理解该简易demo后对数据进行处理【以字符串输入辅以数组计算来实现】
如题,只是一个让观者理解实践构思的demo
RSA算法步骤:
算法介绍:RSA 算法由两个密钥,即公钥和私钥组成。
1)准备两个素数 p 和 q(转换成二进制后位数越多越难破解)
2)计算素数 p 和 q 的乘积 n = pq;
3)同样方法计算 m = (p − 1)(q − 1),这里 m 为 n 的欧拉函数;
4)找到一个数 e(1 < e < m),满足 gcd(m, e) = 1;
5)计算 e 在模 m 域上的逆元 d(即满足 ed mod m = 1);
6)公钥私钥生成完毕:(n, e)为公钥,(n, d)为私钥。
RSA 加密:
对于明文x,用公钥(n, e)对x 加密的过程,就是将x 转换成数字(字符串的话取其ASCII码或者Unicode值),然后通过幂取模计算出 y,其中 y 就是密文:
RSA 解密:
对于密文 y,用私钥(n, d)对 y 解密的过程和加密类似,同样是计算幂取模:
代码解读
代码解析(部分):
结构体介绍:
包含p,q,n,phi_n,e,d,x,y必要元素
包含元素初始化函数
检查质数函数
加密解密函数
信息输出函数
1 class RSA
2 {
3 public:
4 //默认都是正数
5 long long p, q; //
6 long long n; // n = q * p
7 long long phi_n; //phi_n = (q-1)(p-1)
8 long long e; // 1< e < phi_n primer number
9 long long d; //(e*d) mod phi_n == 1
10 long long x; //pubilc key
11 long long y; //private key
12
13 /**
14 * @description: 获取p和q,初始化p和q
15 * @return {*}
16 */
17 void get_p_q(void);
18 /**
19 * @description: 检查是否为质数
20 * @param {long long} temp 传进入判断的数
21 * @return {*}
22 */
23 bool check_whether_primer_Num(long long temp);
24 /**
25 * @description: 初始化n和phi_n
26 */
27 void init_n_and_phi_n(void);
28 void calculate_e(void);
29 void calculate_d(void);
30
31 /**
32 * @description: 获取密文y
33 * @param {long long} x 加密的任意int类型数据【明文】
34 * @return {*}
35 */
36 long long get_pubilc_key(long long x);
37 long long get_parviate_key(long long y);
38 /**
39 * @description: 解码y
40 * @param {long long} y 密文
41 * @return 明文x
42 */
43 long long decode(long long y);
44 void pint_all_value(void)
45 {
46 cout << "p = " << p << " q = " << q << endl;
47 cout << "n = " << n << " phi_n = " << phi_n << endl;
48 cout << "e = " << e << " d = " << d << endl;
49 }
50 };
一些可能的疑惑:
为什么选择long long
因为数据大小比较大,用
int
的话更加容易移除【例如-xxxxxxx】这种大概率是溢出了,搞不懂为什么会溢出的话去看看计算机组成,理解不了你也可以把它当成int,本质上他也是一个整形
函数解析
还记得第一步嘛?
1)准备两个非常大的素数 p 和 q(转换成二进制后位数越多越难破解)
那我们是不是需要获取p/q的输入并对p/q是否为质数(素数)做判断?
让我们先来模块化判断素数的函数:
bool RSA::check_whether_primer_Num(long long temp)
1 /**
2 * @description: 检查是否为质数
3 * @param {long long} temp 传进入判断的数
4 * @return {*}
5 */
6 bool RSA::check_whether_primer_Num(long long temp)
7 {
8 long long max_len = sqrt(temp); //获取最大运行次数
9 for (long long i = 2; i <= max_len; i++) //迭代i
10 {
11 if (temp % i == 0) //检查i是否为质数
12 {
13 throw(runtime_error("p/q isn`t primer")); //抛出错误,temp不属于质数,程序结束
14 //这个throw不理解可以删除,不影响程序,可忽略
15 return false;
16 }
17 }
18 return true; //如果是质数则返回成功
19 }
判断完是否为质数那就可以嵌入获取p/q的函数里了
void RSA::get_p_q(void)
1 void RSA::get_p_q(void)
2 {
3 long long p_i, q_i;//输入的p和q
4 p_i = 0;
5 q_i = 0;
6 cout << "please input a primer number with q(0 is random p,q):";
7 cin >> p_i;
8 if (p_i != 0 && check_whether_primer_Num(p_i))
9 //当输入p不为0【因为p/q不能为0】 且p_i为质数
10 {
11 cout << "p is lawful" << endl;
12 this->p = p_i;
13 cout << "please input a primer number with p:";
14 cin >> q_i;
15 if (q_i != 0 && check_whether_primer_Num(q_i))//思路同上
16 {
17 this->q = q_i;
18 cout << "q is lawful" << endl;
19 this->init_n_and_phi_n();
20 this->calculate_e();
21 return;
22 }
23 else
24 {
25 cout << "q isn`t lawful" << endl;
26 return;
27 }
28 }
29 else if (p_i == 0)//我这里写了一个随机生成质数,对算法影响不大,可以忽略,如果忽略,即用户自行选择质数
30 {
31
32 this->q = rand_set_primer(MIN, MAX);//返回一个在min--max范围的一个质数【自定义函数】 MIN和MAX在宏定义
33 cout << "set q = " << this->q << endl;
34 do
35 {
36 p_i = rand_set_primer(MIN, MAX);
37 } while (p_i == this->q);
38 this->p = p_i;
39 cout << "set p = " << this->p << endl;
40 this->init_n_and_phi_n();
41 this->calculate_e();
42 }
43 return;
44 }
获取了合法的p的q后,那我们是不是应该计算
e,n,phi_n,d
了2)计算素数 p 和 q 的乘积 n = pq;
3)同样方法计算 m = (p − 1)(q − 1),这里 m 为 n 的欧拉函数;
4)找到一个数 e(1 < e < m),满足 gcd(m, e) = 1;
5)计算 e 在模 m 域上的逆元 d(即满足 ed mod m = 1);
一步步来,先计算第2/3
void RSA::init_n_and_phi_n(void)
{
this->phi_n = (q - 1) * (p - 1);
this->n = p * q;
}然后我们计算4
1 void RSA::calculate_e(void)
2 {
3 long long temp_e = 2;//初始化临时的e为2
4 while (__gcd(temp_e, this->phi_n) != 1)
5 //这里的逻辑可能会有点抽象,一步步拆解
6 //首先是__gcd(temp_e, this->phi_n)意思是,temp_e是否是phi_n的最大公约数
7 //后续的迭代就是令temp_e不断自加,从而获得phi_n的最大公约数,这里的phi_n相当于上文的m
8 {
9 temp_e++;
10 }
11 if (temp_e < this->phi_n)//如果这个数合法
12 {
13 this->e = temp_e;
14 return;
15 }
16 else//如果这个数非法
17 {
18 throw(runtime_error("e is greater or equal to phi_n"));
19 //也可以不加这个错误判断,直接return ;和打印错误信息也可以
20 }
21 }恭喜你离答案不远了,剩下是最难看懂的对
d
的运算1 void RSA::calculate_d(void)
2 {
3 long long temp_d = 2;
4 while (((temp_d * this->phi_n + 1) % this->e) != 0) //通过对temp_d 对e取模是否为整数来迭代,每次迭代temp_d都会+1,直到找到取模为整数时
5 {
6 temp_d++; //迭代的代价
7 }
8 this->d = (temp_d * this->phi_n + 1) / this->e; //找到了temp_d 将他放入d中
9 }
一些可能的疑惑:
(temp_d * this->phi_n + 1) % this->e
先对中间拆解,为什么是
(temp_d * this->phi_n + 1)
%e
先来回顾一下:
计算 e 在模 m 域上的逆元 d(即满足 ed mod m = 1)e是整数
这个可能还不是太好懂,因为这个抽象了一层【字符层】,我们先假设e为5,m为12 则:
d*5 mod 12 = 1
13 mod 12 = 1
d * 5 = 13 ->e = 13/5[illegal]
再次尝试:
25 mod 12 = 1
5d = 25 -> d = 5[合法]
总结一下,想想看(12*
2
+ 1 )% 5的结果是不是0【结果为整数】,然后this->d = (temp_d * this->phi_n + 1) / this->e
综上
(temp_d * this->phi_n + 1) % this->e
!=0时就是计算d为分数的情况下,所以说这时候temp_d++,然后选择下一个看看d是否合法,相当于我们上面手动12*n+1 一个个试
找到该的结果再反推出d
剩下的是计算x和y,根据公式计算即可,没特别大难度:
回顾一下:
long long RSA::get_pubilc_key(long long x)
{
long long X_i;
X_i = (pow(x, this->e));
X_i = X_i % this->n;
cout << "Y = " << X_i << endl;
return X_i;
}
long long RSA::decode(long long y)
{
long long d_ = this->d;
long long n_ = this->n;
//方便理解 d和n是已知的
long long x_res = pow(y, d_);
x_res = x_res % n_;
cout << "x = " << x_res << endl;
return x_res;
}
还有一个测试的主函数:
1 int main()
2 {
3 int input = 8;//可自行修改
4 RSA rsa_t;
5 rsa_t.get_p_q();
6 rsa_t.calculate_d();
7 rsa_t.pint_all_value();
8 long long y = rsa_t.get_pubilc_key(input);
9 //long long x = rsa_t.decode(y); 容易溢出
10
11 return 0;
12 }
结束,看到这里你应该大概对这个算法的基本流程有一个自己的认识了,可以通过这个构思来实现更加高级的RSA加密解密了:
1 #include <iostream>
2 #include <cmath>
3 #include <numeric>
4 #include <time.h>
5 #include <algorithm>
6 #include <math.h>
7 #define MIN 3
8 #define MAX 10000
9 using namespace std;
10 long long gcd(long long a, long long b);
11 long long rand_set_primer(long long min, long long max);
12
13 class RSA
14 {
15 public:
16 //默认都是正数
17 long long p, q; //
18 long long n; // n = q * p
19 long long phi_n; //phi_n = (q-1)(p-1)
20 long long e; // 1< e < phi_n primer number
21 long long d; //(e*d) mod phi_n == 1
22 long long x; //pubilc key
23 long long y; //private key
24
25 /**
26 * @description: 获取p和q,初始化p和q
27 * @return {*}
28 */
29 void get_p_q(void);
30 /**
31 * @description: 检查是否为质数
32 * @param {long long} temp 传进入判断的数
33 * @return {*}
34 */
35 bool check_whether_primer_Num(long long temp);
36 /**
37 * @description: 初始化n和phi_n
38 */
39 void init_n_and_phi_n(void);
40 void calculate_e(void);
41 void calculate_d(void);
42
43 /**
44 * @description: 获取密文y
45 * @param {long long} x 加密的任意int类型数据【明文】
46 * @return {*}
47 */
48 long long get_pubilc_key(long long x);
49 long long get_parviate_key(long long y);
50 /**
51 * @description: 解码y
52 * @param {long long} y 密文
53 * @return 明文x
54 */
55 long long decode(long long y);
56 void pint_all_value(void)
57 {
58 cout << "p = " << p << " q = " << q << endl;
59 cout << "n = " << n << " phi_n = " << phi_n << endl;
60 cout << "e = " << e << " d = " << d << endl;
61 }
62 };
63
64 void RSA::get_p_q(void)
65 {
66 long long p_i, q_i;
67 p_i = 0;
68 q_i = 0;
69 cout << "please input a primer number with q(0 is random p,q):";
70 cin >> p_i;
71 if (p_i != 0 && check_whether_primer_Num(p_i))
72 {
73 cout << "p is lawful" << endl;
74 this->p = p_i;
75 cout << "please input a primer number with p:";
76 cin >> q_i;
77 if (q_i != 0 && check_whether_primer_Num(q_i))
78 {
79 this->q = q_i;
80 cout << "q is lawful" << endl;
81 this->init_n_and_phi_n();
82 this->calculate_e();
83 return;
84 }
85 else
86 {
87 cout << "q isn`t lawful" << endl;
88 return;
89 }
90 }
91 else if (p_i == 0)
92 {
93
94 this->q = rand_set_primer(MIN, MAX);
95 cout << "set q = " << this->q << endl;
96 do
97 {
98 p_i = rand_set_primer(MIN, MAX);
99 } while (p_i == this->q);
100 this->p = p_i;
101 cout << "set p = " << this->p << endl;
102 this->init_n_and_phi_n();
103 this->calculate_e();
104 }
105 return;
106 }
107
108 bool RSA::check_whether_primer_Num(long long temp)
109 {
110 long long max_len = sqrt(temp); //获取最大运行次数
111 for (long long i = 2; i <= max_len; i++) //迭代i
112 {
113 if (temp % i == 0) //检查i是否为质数
114 {
115 throw(runtime_error("p/q isn`t primer")); //抛出错误,temp不属于质数,程序结束
116 return false;
117 }
118 }
119 return true; //如果是质数则返回成功
120 }
121
122 /**
123 * @description: 生成随机数在min和max之间的质数
124 * @param {long long} min 最小值
125 * @param {long long} max 最大值
126 * @return 该随机数
127 */
128 long long rand_set_primer(long long min, long long max)
129 {
130 long long a;
131 long long j;
132 srand((long long)time(NULL));
133 while (1)
134 {
135 a = min + (rand() % (max - min)); //随机数:范围【min 】 - 【min + (max - min - 1)】
136 for (j = 2; j <= sqrt(a); j++)
137 if (a % j == 0) //当a为质数时
138 break;
139 if (j > sqrt(a))
140 return a;
141 else
142 continue;
143 }
144 }
145
146 void RSA::init_n_and_phi_n(void)
147 {
148 this->phi_n = (q - 1) * (p - 1);
149 this->n = p * q;
150 }
151
152 void RSA::calculate_e(void)
153 {
154 long long temp_e = 2;
155 while (__gcd(temp_e, this->phi_n) != 1)
156 {
157 temp_e++;
158 }
159 if (temp_e < this->phi_n)
160 {
161 this->e = temp_e;
162 return;
163 }
164 else
165 {
166 throw(runtime_error("e is greater or equal to phi_n"));
167 }
168 }
169 void RSA::calculate_d(void)
170 {
171 long long temp_d = 2;
172 while (((temp_d * this->phi_n + 1) % this->e) != 0) //通过对temp_d 对e取模是否为整数来迭代,每次迭代temp_d都会+1,直到找到取模为整数时
173 {
174 temp_d++; //迭代的代价
175 }
176 this->d = (temp_d * this->phi_n + 1) / this->e; //找到了temp_d 将他放入d中
177 }
178
179 long long RSA::get_pubilc_key(long long x)
180 {
181 long long X_i;
182 X_i = (pow(x, this->e));
183 X_i = X_i % this->n;
184 cout << "Y = " << X_i << endl;
185 return X_i;
186 }
187 long long RSA::decode(long long y)
188 {
189 long long d_ = this->d;
190 long long n_ = this->n;
191 //方便理解 d和n是已知的
192 long long x_res = pow(y, d_);
193 x_res = x_res % n_;
194 cout << "x = " << x_res << endl;
195 return x_res;
196 }
197 int main()
198 {
199 int input = 8;
200 RSA rsa_t;
201 rsa_t.get_p_q();
202 rsa_t.calculate_d();
203 rsa_t.pint_all_value();
204 long long y = rsa_t.get_pubilc_key(input);
205 long long x = rsa_t.decode(y);
206
207 return 0;
208 }
c++代码实现 RSA的简易demo【偏向实践】的更多相关文章
- 同事问如何判断同花顺,我用javascript的二维数组写了个简易demo
有个前同事在群里问如何判断是否为同花顺我用javascript的二维数组写了个简易demo. <!DOCTYPE html> <html> <body> <s ...
- WebSocket基于javaweb+tomcat的简易demo程序
由于项目需要,前端向后台发起请求后,后台需要分成多个步骤进行相关操作,而且不能确定各步骤完成所需要的时间 倘若使用ajax重复访问后台以获取实时数据,显然不合适,无论是对客户端,还是服务端的资源很是浪 ...
- AES和RSA算法的demo代码
aes代码示例: package com.autoyol.util.security.test; import java.security.Key; import java.security.NoSu ...
- iOS学习之网易新闻简易Demo
简易NewsDemo代码分析 界面布局就不多说了.效果图:(自定义了三套Cell,最后一套Cell是页面最下方的"正在加载中..."Cell,图三.) 主要分析工程 ...
- 微信小程序入门学习-- 简易Demo:计算器
简单学习下微信小程序 官网 简易教程 · 小程序 https://mp.weixin.qq.com/debug/wxadoc/dev/ 需要通过开发者工具,来完成小程序创建和代码编辑. 下载安装,运行 ...
- WebApp 九宫格抽奖简易demo
代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <met ...
- iOS,一行代码进行RSA、DES 、AES、MD5加密、解密
本文为投稿文章,作者:Flying_Einstein(简书) 加密的Demo,欢迎下载 JAVA端的加密解密,读者可以看我同事的这篇文章:http://www.jianshu.com/p/98569e ...
- 代码:jquery自定义插件 demo
jquery自定义插件 demo 2016-1-13 只是一个简易的示例 <script type="text/javascript" src="http://cd ...
- 代码高亮插件——wangHightLighter.js——demo演示
wangHighLighter.js demo 语言: 主题: 转换 说明: wangHightLighter.js是一个可以将代码高亮显示的javascript小插件,支持常用的20多语言. ...
- Html5游戏开发-145行代码完成一个RPG小Demo
lufy前辈写过<[代码艺术]17行代码的贪吃蛇小游戏>一文,忽悠了不少求知的兄弟进去阅读,阅读量当然是相当的大.今天我不仿也搞一个这样的教程,目地不在于忽悠人,而在于帮助他人. 先看de ...
随机推荐
- Qt添加资源文件
参考视频:https://www.bilibili.com/video/BV1XW411x7NU?p=27 以添加图片为例进行说明: 1)点击工程名,选择"添加新文件": 2)选择 ...
- SQL练习之打卡记录数据统计类问题
最近老婆的公司,关闭了OA系统中,各类打卡时间数据统计的功能,为了不麻烦老婆手算,就做了一个简单的打卡系统,方便自动统计老婆想要知道的各类数据. 做的过程中就遇到了几个还挺有意思的SQL,这里写成一篇 ...
- LeetCode 208. Implement Trie (Prefix Tree) 实现 Trie (前缀树)(C++/Java)
题目: Implement a trie with insert, search, and startsWith methods. Example: Trie trie = new Trie(); t ...
- Javascript高级程序设计第七章 | ch7 | 阅读笔记
迭代器与生成器 在软件开发领域,"迭代"的意思是按照顺序反复多次执行一段程序 理解迭代 在JavaScript中,计数循环就是最简单的迭代 但是这种迭代有点问题: 1. 迭代之前需 ...
- LocalDateTime与LocalDate之间转换
LocalDateTime与LocalDate之间转换 //LocalDateTime转换LocalDate LocalDateTime now2 = LocalDateTime.now(); Loc ...
- Excel Wps 透视表去重计数方法
Excel Wps 透视表去重计数方法 在处理表格,遇到处理根据某个列去重后统计数量,而不是仅仅统计数量.在网上查找资料,不确定EXCEL或者WPS某个版本可以支持该功能的实现. 折中的方案,分两步来 ...
- spring mvc统一处理接口返回值,aop切面实现,将请求的入参和出参存储在数据库中,切面内重新抛出异常
spring mvc统一处理接口返回值,aop切面实现,将请求的入参和出参存储在数据库中 aop类实现Aspect的多个方法注解中,只有Around注解的方法是有返回值的,可以对方法的入参和返回值均进 ...
- Java跳动爱心代码
1.计算爱心曲线上的点的公式 计算爱心曲线上的点的公式通常基于参数方程.以下是两种常见的参数方程表示方法,用于绘制爱心曲线: 1.1基于 (x, y) 坐标的参数方程 x = a * (2 * cos ...
- Zynq-7000 AP SoC Boot - Multiboot Tech Tip
背景 产品需要用到这个技术,在wiki找到了这篇文章. 创建者Confluence Wiki Admin Sep 24, 2018 in Xilinx-wiki Table of Contents D ...
- Freertos学习:在Posix环境仿真FreeRTOS
--- title: rtos-freertos-在Posix环境仿真FreeRTOS date: 2020-06-11 16:22:34 categories: tags: - freertos - ...