rsa加密算法知识点整理

106 阅读3分钟

这是一篇个人整理的,关于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;
    }
}