前言:
本章所需要的全部数论知识都来自《数论概论:A Friendly Introduction to Number Theory》,读者请先行学习并动手自己写代码来巩固相关知识。
工作原理概要
加密:
选取较大的素数p 和 q,计算m = pq,选取指数k 与 (m) = (p - 1)(q - 1)互素。
对于给定的正整数信息a,计算b a^k (mod m) 并化简到b < m。
公开数m,k。此时的数b就是我们的加密后信息。
而p 与 q(准确地说,是(m)的值) 就是解密需要的钥匙,是隐藏信息。
这是因为对于一个很大的数m,想要将其分解为pq是非常困难的,即使是高算力的计算机也不可能实现,而(m)则是解密所必须先得到的数,这就是RSA公钥体系的运作原理。
解密:
对于给定的加密信息b,只要计算x^k b (mod m)即可,在这里作为解密者,需要知道
(m),利用数论知识可以还原出x
a (mod m)。
代码实现
第一个函数是计算a^k (mod m)的函数,思路是倍增算法中的典型---快速幂。在教材中也叫逐次平方法。
int cal1(int a, int k, int m) {
vector<int> node;
int tmp = a % m;
while (k != 0) {
if (k & 1) {
node.push_back(tmp);
}
tmp *= tmp;
tmp = tmp % m;
k >>= 1;
}
int ans = 1;
for (auto i : node) {
ans *= i;
ans = ans % m;
printf("%d %d\n", i, ans);
}
return ans;
}
第二个函数是解二元线性方程ax + by = gcd(a, b)的一个根。在这个问题中,即解kx - (m)y = 1的一组解。
这个的解法和证明在教材中很详细,这里不赘述了,给出欧几里得算法和在其上扩大的目标算法供读者参考。
int gcd(int a, int b) {
if (b == 0) {
return a;
}
else {
return gcd(b, a % b);
}
}
int ex_gcd(int a, int m, int& x, int& y)
{
if (m == 0) {
x = 1;
y = 0;
return a;
}
else {
int ans = ex_gcd(m, a % m, x, y);
int temp = x;//设置临时变量temp=x,此时x是下一个解的x,也就是说,此时的x只是上面所提到的x1
x = y;//当前状态的x是等于下个解的y1
y = temp - (a / m) * y;//求得当前状态的y
return ans;
}
}
int decrypt(int b, int k, int m, int key) {
int x, y;
int g = ex_gcd(k, key, x, y);
for (int i = 1; x < 0;i++) {
x += key * i;
}
int ans = cal1(b, x, m);
return ans;
}
结合上述两个函数,就可以进行加密和解密了。给一组成功加密解密的数据(因为没用大整数,这是不安全的密码,读者可以添加大数或者使用其他高级编程语言进行重构)
int main() {
char message;
int k, p, q;
cout << "please input a letter and k,p,q: " << endl;
cin >> message >> k >> p >> q;
cout << "message: " << (int)message << endl;
int m = p * q, Om = (p - 1) * (q - 1);
int encrypt = cal1(message, k, m);
cout << "encrypt: " << encrypt << endl;
int dec = decrypt(encrypt, k, m, Om);
cout << "decrypt: " << dec << endl;
}
注:一定要注意k,p,q要满足特定条件,否则无法成功加密和解密。