这是一篇个人整理的,关于rsa加密算法的知识点,附带js模拟算法的实现过程
生成密钥的过程
首先,随机选两个质数(位数一样且不相等)p1和p2,将p1和p2相乘,把结果记为n
n是两个超大质数的乘积
n = p1 * p2
计算n的欧拉函数φ(n),记作o,欧拉函数φ(n) = (p1 - 1) * (p2 - 1)
o = (p1 - 1) * (p2 - 1)
取一个奇数e作为公钥,1 < e < o,且不能与o有公因数(互为质数),计算出私钥d,e在实际应用中通常取65537,计算过程使用扩展欧几里得算法。
至此,d是私钥,e是公钥
加密过程
将要加密的内容转化为数字m,计算m的e次方,然后取模n
c为加密后的数据
c = m ** e % n
解密过程
拿到加密数据c后,通过私钥d来求出原始数据m
计算c的d次方,然后取模n
m = c ** d % n
密钥实际应用的过程
首先,服务端生成一对公钥和私钥,把公钥发给客户端,私钥自己存留。客户端将消息用AES(对称加密)加密,把密钥(AES的密钥)用公钥加密,然后把加密信息和密钥一起发给服务端。服务端通过私钥解密出密钥,然后再解密出消息。
rsa为什么不能被破解
中间人可以从请求中获取到:加密消息、AES密钥(c)、公钥(e)和质数乘积(n),那么想要破开消息,就要先破开AES密钥上的加密,也就是从c = m ** e % n方程中,用e、n和c来反推出m,这个过程是极其困难的,因为涉及到大质数的因数分解。
加密公式
c = m ** e % n
解密公式(没有d根本无法解密)
m = c ** d % n
rsa不能加密太长的内容
因为密文要转为成整数进行运算,所以对内容长度有一定限制,一般只用来加密简短的数据,如AES的密钥,长数据则用AES加密,rsa在其中担任保护AES密钥的职责。
js模拟rsa加解密过程
例如,张三和李四要发消息。首先,李四生成公钥和私钥,把公钥给张三。
// 李四随机取两个质数61和53
const p1 = 61
const p2 = 53
const n = p1 * p2 // 3233
// 计算n的欧拉函数
const o = (p1 - 1) * (p2 - 1) // 3120
// 随机选一个奇数17,计算出私钥d(此处用到扩展欧几里得算法)
const e = 17
const d = modInverse(e, o) // 2753
张三把要发的消息转成整数,然后用公钥进行加密
// 这里省去转化整数的步骤,直接用整数作为消息内容
// 数字后加一个n表示为bigInt,不然会数值溢出,出现NaN或者计算结果不准确
const msg = 19n
// c就是加密后的密文
const c = msg ** BigInt(e) % BigInt(o) // 1939n
console.log('消息已用rsa加密', c)
李四拿到张三发来的密文后,用私钥进行解密。
const m = c ** BigInt(d) % BigInt(o) // 19n
console.log('解密成功,消息内容为:', m)
扩展欧几里得算法
function gcdExtended(a, b) {
if (a === 0) {
return [b, 0, 1];
}
let [gcd, x1, y1] = gcdExtended(b % a, a);
let x = y1 - Math.floor(b / a) * x1;
let y = x1;
return [gcd, x, y];
}
function modInverse(e, phi) {
let [gcd, x, y] = gcdExtended(e, phi);
if (gcd !== 1) {
throw new Error("Inverse doesn't exist");
} else {
return (x % phi + phi) % phi;
}
}