RSA 加密算法
RSA加密算法是一种非对称加密算法,在公开密钥加密和电子商业中被广泛使用。RSA是由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)在1977年一起提出的
[1]
RSA 加密算法的可靠性源自于对于极大的整数做因数分解很难在有限的时间内得到有效的解,在未来的某一天,随着计算机性能的不断提高,RSA 算法的可靠性可能会降低,但是就目前的计算机来讲很难通过暴力的方式直接破解经过 RSA 算法加密之后的信息
数学基础
-
互质关系
对于两个正整数,如果这两个正整数除了 之外没有任何公因数,那么就将这两个数称为两者之间是 “互质” 的,比如,对于 和 ,由于它们之间没有除了 之外的公因数,因此它们之间的关系就是 “互质” 的
根据定义,可以得到以下的关系:
- 任意的两个质数将会构成 “互质” 关系
- 如果一个数是一个质数,那么只要另一个数不是前一个数的倍数,那么这两者之间将会构成 “互质” 关系
- 对于两个数,如果较大的那个数是质数,那么这两者之间同样构成 “互质“ 关系
- 和任意的一个自然数都会构成 “互质” 关系
- 对于任意的大于 的整数 ,那么 和 将会构成 “互质” 关系
- 对于任意的大于 的整数 ,如果 是一个奇数,那么 和 将会构成 “互质” 关系
-
欧拉函数 [4]
在数论中,对于给定的任意正整数 ,欧拉函数 表示小于等于 的正整数中与 互质的数的个数
对于任意的正整数,都可以写成一系列质数的积,即:
此时,欧拉函数 的计算公式如下:
欧拉函数的积表示形式如下:
特别地,对于 是质数的情况,有 ,这是因为当 是质数时,它和所有小于它的正整数都是 “互质” 的
公式的证明请参考:https://zh.wikipedia.org/wiki/欧拉函数
-
欧拉定理[2]
如果两个正整数 和 互质,那么则有如下的等式成立:
即: 的 次方被 取余后剩
-
模反元素
如果两个正整数 和 互质,那么一定可以找到整数 ,使得 被 整除,即:
此时 就被称为 的模反元素,由于
因此, 就是 的模反元素
算法原理
公钥和私钥
- 随意选择两个大的质数 和 ,计算两者的积
- 根据上文提到的欧拉函数,求得
- 选择一个小于 的正整数 ,使得 和 互质,并求得 关于 的模反元素
- 删除 和
经过上述操作之后,得到的 就被称之为公钥,而 就被称之为私钥。一般会选择两个非常大的质数,经过操作之后会再将这两个数字进行转码,就是一般见到的存储形式
消息的加密
假如现在想要发送一个消息 到指定的地点,由于公钥是可见的,因此首先将 通过公钥 转换为对应的整数(由于数据在计算机上都是通过二进制的方式存储的,可以以读取数字的方式读取信息),一般信息都会很长,因此会得到许多转换后的整数,具体单个整数的计算方式为:
消息的解密
每读取到一个整数 ,通过下面的方式来进行解密:
得到 之后再对其进行对应的编码即可还原原来的信息
解密的原理:
由于 ,因此 ,则有:
-
如果 和 互质,那么
-
如果 和 不是互质的,那么
一定是 或 ,假设 为 (为 时同理),由于 和 都是质数,由互质关系 可得 和 同样是互质关系。由欧拉公式,可以得到如下的关系:
进一步可得:
此时,在等式两边同时乘上 ,可以得到如下关系:
由求模关系,可以得到如下等式:
由于等式两边都是整数,并且 和 为不相等的质数,因此当等式两边同时除以 时,为了维护这个等式的成立, 必须是 的整数倍。即 ,进而等式变为:
由于 ,,因此上述等式可以变为:
因此
因此
具体实现
由于 Java 存在 BigInteger
类来支持任意精度的数值计算,因此实现起来就会变得特别方便,具体实现代码如下所示:
static void test(String text) {
int BIT_LENGTH = 2048;
Random rand = new SecureRandom();
BigInteger p = BigInteger.probablePrime(BIT_LENGTH / 2, rand);
BigInteger q = BigInteger.probablePrime(BIT_LENGTH / 2, rand);
// 计算 N
BigInteger n = p.multiply(q);
// 计算 r
BigInteger phi = p.subtract(BigInteger.ONE)
.multiply(q.subtract(BigInteger.ONE));
BigInteger e = TWO;
// 找到合适的 e
while (e.compareTo(phi) < 0) {
if (e.gcd(phi).intValue() == 1) break;
e = e.add(ONE);
}
BigInteger d = e.modInverse(phi); // 获得 e 的模反元素
BigInteger msg = new BigInteger(text.getBytes(UTF_8)); // 将消息转换为对应的整数
BigInteger enc = msg.modPow(e, n); // 相当于对 msg 做 e 次乘法,再对 n 求模
System.out.println("raw=" + text);
System.out.println("enc=" + enc);
BigInteger dec = enc.modPow(d, n);
System.out.println("dec=" + new String(dec.toByteArray(), UTF_8));
}
假设现在输入的字符串为 “This is a simple text”,输出结果如下所示:

具体的,可以对编码后的数据进行特殊的处理,如:基于 16 位、基于 64 位 bit 的转换,就会变成常见的 key
参考:
[1] https://zh.wikipedia.org/wiki/RSA加密演算法
[2] https://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
[3] https://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库