写在前面

  • 【如果你还没搞明白算法具体步骤建议先去看视频了解,本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. OpenCV笔记(10) 相机模型与标定

    万圣节快乐! 1. 相机模型 针孔相机模型:过空间某特定点的光线才能通过针孔(针孔光圈),这些光束被投影 到图像平面形成图像. 将图像平面在针孔前方,重新把针孔相机模型整理成另一种等价形式, 实际上, ...

  2. Your Post Title Here

    VSCode 实时预览还需要执行 Markdown: Open Preview to the Side 命令来实现. 在命令窗口输入 Markdown: Open Preview to the Sid ...

  3. Python实现求多个集合之间的并集-方法2

    之前使用过一种方法实现求集合间的并集,参考文章:https://www.cnblogs.com/mrlayfolk/p/12373532.html,这次使用另外一种方法实现,这种方法效率更高. 目的: ...

  4. redis 远程连接

    redis-cli -h host -p port -a password -h 服务器地址 -p 端口号 -a 密码

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

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

  6. 手把手教你搭建Docker私有仓库Harbor

    1.什么是Docker私有仓库 Docker私有仓库是用于存储和管理Docker镜像的私有存储库.Docker默认会有一个公共的仓库Docker Hub,而与Docker Hub不同,私有仓库是受限访 ...

  7. Qt 应用程序中自定义鼠标光标

    在 Qt 应用程序中,你可以自定义鼠标光标.你可以使用 `QCursor` 类来设置不同类型的鼠标光标,比如内置样式或者自定义的图片.以下是一些使用示例: 使用内置光标样式 Qt 提供了一些内置的光标 ...

  8. 交互式转化批处理工具 expect

    交互式转化批处理工具 expect expect中相关命令 spawn 启动新的进程 expect 从进程接收字符串 send 用于向进程发送字符串 interact 允许用户交互 exp_conti ...

  9. OpenTelemetry 深度定制:跨服务追踪的实战技巧

    背景 在上一篇<从 Dapper 到 OpenTelemetry:分布式追踪的演进之旅>中在最后提到在做一些 Trace 的定制开发. 到现在差不多算是完成了,可以和大家分享一下. 我们的 ...

  10. QT学习:10 IO类

    --- title: framework-cpp-qt-10-IO类 EntryName: framework-cpp-qt-10-QIODevice date: 2020-04-17 10:24:0 ...