写在前面

  • 【如果你还没搞明白算法具体步骤建议先去看视频了解,本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 解密的过程和加密类似,同样是计算幂取模:

代码解读

代码解析(部分):
  • 结构体介绍:

  1. 包含p,q,n,phi_n,e,d,x,y必要元素

  1. 包含元素初始化函数

  1. 检查质数函数

  1. 加密解密函数

  1. 信息输出函数

 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【偏向实践】的更多相关文章

  1. 同事问如何判断同花顺,我用javascript的二维数组写了个简易demo

    有个前同事在群里问如何判断是否为同花顺我用javascript的二维数组写了个简易demo. <!DOCTYPE html> <html> <body> <s ...

  2. WebSocket基于javaweb+tomcat的简易demo程序

    由于项目需要,前端向后台发起请求后,后台需要分成多个步骤进行相关操作,而且不能确定各步骤完成所需要的时间 倘若使用ajax重复访问后台以获取实时数据,显然不合适,无论是对客户端,还是服务端的资源很是浪 ...

  3. AES和RSA算法的demo代码

    aes代码示例: package com.autoyol.util.security.test; import java.security.Key; import java.security.NoSu ...

  4. iOS学习之网易新闻简易Demo

    简易NewsDemo代码分析 界面布局就不多说了.效果图:(自定义了三套Cell,最后一套Cell是页面最下方的"正在加载中..."Cell,图三.)         主要分析工程 ...

  5. 微信小程序入门学习-- 简易Demo:计算器

    简单学习下微信小程序 官网 简易教程 · 小程序 https://mp.weixin.qq.com/debug/wxadoc/dev/ 需要通过开发者工具,来完成小程序创建和代码编辑. 下载安装,运行 ...

  6. WebApp 九宫格抽奖简易demo

    代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <met ...

  7. iOS,一行代码进行RSA、DES 、AES、MD5加密、解密

    本文为投稿文章,作者:Flying_Einstein(简书) 加密的Demo,欢迎下载 JAVA端的加密解密,读者可以看我同事的这篇文章:http://www.jianshu.com/p/98569e ...

  8. 代码:jquery自定义插件 demo

    jquery自定义插件 demo 2016-1-13 只是一个简易的示例 <script type="text/javascript" src="http://cd ...

  9. 代码高亮插件——wangHightLighter.js——demo演示

    wangHighLighter.js demo 语言:   主题: 转换   说明: wangHightLighter.js是一个可以将代码高亮显示的javascript小插件,支持常用的20多语言. ...

  10. Html5游戏开发-145行代码完成一个RPG小Demo

    lufy前辈写过<[代码艺术]17行代码的贪吃蛇小游戏>一文,忽悠了不少求知的兄弟进去阅读,阅读量当然是相当的大.今天我不仿也搞一个这样的教程,目地不在于忽悠人,而在于帮助他人. 先看de ...

随机推荐

  1. WPS相关技巧

    1 标题自动编号 首先,新建一个空白word,打开.点击默认的标题样式,可以看到并不会自动编号. 接下来,就设置如何自动编号.首先选择"编号". 然后,选择"多级编号&q ...

  2. pandas基础--数据结构:DataFrame

    从本文开始介绍pandas的相关知识. pandas含有是数据分析工作变得更快更简单的高级数据结构和操作工具,是基于numpy构建的. 本章节的代码引入pandas约定为:import pandas ...

  3. react多级路由 重定向与404定义

    在有一些功能中,往往请求地址的前缀是相同的,不同的只是后面一部份,此时就可以使用多级路由(路由嵌套)来实现此路由的定义实现. 例: 路由规则如下 admin/index admin/user 它们路由 ...

  4. elementUI slider组件,带范围选择实现双向绑定

    网上查过很多相关文章都没有一章是写element ui滑块带范围实现双向绑定 二个滑块二头的数据怎么得到 我的需求是做个时间轴要滑动选择不同的时间 开始很难做最后一点一点摸索得出的结论 好在写出来了先 ...

  5. 讲课 PPT 公开啦

    目前限于时间原因,只在 Github Pages 上托管了. 之后有时间会托管到 pythonanywhere 上,因为 Github Pages 是在太慢了.

  6. git与gitee码云

    1.git分支 在前面我们基本了解Git的使用方法,这一节我们看下GIt重要概念[分支] 背景 例如于超老师在开发一个同性交友网站,刚写到登录功能,代码还没写完,今天先睡觉了,所以就commit提交到 ...

  7. Java学习笔记 - 单例模式

    概述 单例模式是一种创建者模式.当我们需要确保系统中某个类仅能存在一个对象时,比如:全局信息类例如当项目启动时我们将一个配置文件读取为一个Config类的实例从而在业务逻辑中通过操作对象读取配置.无状 ...

  8. MYSQL8存储过程生成日历表以及异常处理

    一.环境 数据库:mysql8.0.25 社区版 操作系统:windows 11 ------------------------------------ 二.创建日历表 CREATE TABLE ` ...

  9. WPF 做一个超级简单的 1024 数字接龙游戏

    这是一个我给自己做着玩的游戏,没有什么复杂的界面,就一些简单的逻辑 游戏的规则十分简单,那就是有多个列表.程序会给出一个数字,玩家决定数字放在哪个列表里面.如果放入列表里面的数字和列表里面最后一个数字 ...

  10. ODPS 不用循环生成连续日期

    生成 20230801 ~ 20230831之间的每一天的sql代码怎么写? 只要一行代码. 一行代码: select TO_CHAR(DATEADD(TO_DATE(bizdate,'yyyymmd ...