文:RSA算法是一种非对称加密算法,用于加密、解密和数字签名等场景。本文将介绍如何在JavaScript中使用RSA算法,并提供一个实际的案例,同时也会说明如何生成公钥和私钥。
首先,确保您已经引入了jsencrypt库。以下是一个使用RSA算法进行加密和解密的示例,同时也包含了公钥和私钥的生成方法:
// 引入jsencrypt库
const JSEncrypt = require("jsencrypt");
// 生成RSA密钥对
const rsa = new JSEncrypt();
const keypair = rsa.getKey();
// 获取公钥和私钥
const publicKey = keypair.getPublicKey();
const privateKey = keypair.getPrivateKey();
console.log("公钥:", publicKey);
console.log("私钥:", privateKey);
// 实例化一个RSA对象
const rsaInstance = new JSEncrypt();
// 设置公钥和私钥
rsaInstance.setPublicKey(publicKey);
rsaInstance.setPrivateKey(privateKey);
// 定义待加密的字符串
const plaintext = "Hello, World!";
// 加密字符串
const encrypted = rsaInstance.encrypt(plaintext);
console.log("加密后的密文:", encrypted);
// 解密密文
const decrypted = rsaInstance.decrypt(encrypted);
console.log("解密后的明文:", decrypted);
在上述代码中,我们首先引入了jsencrypt库,并实例化了一个JSEncrypt对象。通过调用getKey()方法,我们生成了一个RSA密钥对。然后,我们使用getPublicKey()和getPrivateKey()方法获取公钥和私钥。生成的公钥和私钥可以用于后续的加密和解密操作。
接下来,我们实例化另一个JSEncrypt对象,并使用setPublicKey()和setPrivateKey()方法设置公钥和私钥。之后,我们定义了待加密的字符串,并使用encrypt()方法对字符串进行加密。最后,通过调用decrypt()方法对密文进行解密,并将解密后的明文输出。
通过以上示例,您可以在JavaScript中使用RSA算法进行加密和解密操作,并自动生成公钥和私钥。需要注意的是,生成的公钥和私钥应妥善保管,确保其安全性和保密性,以防止数据泄露和非法使用。
总结:通过jsencrypt库,我们可以在JavaScript中轻松实现RSA算法的加密和解密功能。本文提供了一个实际的案例,并详细说明了如何生成公钥和私钥。通过生成的密钥对,我们可以进行数据加密和解密操作,确保数据的安全性和保密性。在实际应用中,请妥善保存生成的公钥和私钥,以保证数据的安全。
题:#科学# #数学# #密码学# #算法#
小石头/编
RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,密钥 分为 公钥 PK=(e, n) 和 私钥 SK=(d, n) ,其中 e, d, n 都是 正整数。
PK是公开的,任何人都可以通过下面的加密公式,用 PK 对 明文 M (为整数),进行加密 ,得到 密文 C (为整数),并发送给 接收者。
Mᵉ mod n = C
SK不公开,只有接收者知道,收到C后,可以通过下面的解密公式,得到M。
Cᵈ mod n = M
这里的 mod 称为 模运算,对于 任意整数 a,b(≠0),做带余除法,有,
a = qb + r,0 ≤ r < |b|
定义,
a mod b = r (a ≥ 0) 或 -r (a < 0)
RSA 密钥 的构造方法如下:
1 任意选取 两个 奇素数 p 和 q,令 n = pq;
2 计算 ψ(n)=(p-1)(q-1);
ψ(n) 称为 欧拉函数, 表示:小于 n 并且 与 n 互素 的 正整数 个数。若 整数 a 和 b 的最大公约数 (a, b) = 1,则称 a 与 b 互素。
对于 素数 p 而言,任何 小于 p的 正整数 显然 和 p 互素,小于p 的正整数 个数 是 p-1,因此 ψ(p) = p-1,同理 ψ(q) = q-1。
又显然 (p,q) = 1,根据,
立即得到:
ψ(n)=(p-1)(q-1)
3 选取 正整数 1 < e < ψ(n) ,使得 (e, ψ(n)) = 1 ①;
由于,ψ(n)=(p-1)(q-1) > 1,故 一定存在 小于 ψ(n) 与 ψ(n) 互素 的 非1 正整数 e。
4 求 e 的 模 ψ(n) 逆 d,即,求 正整数 1 < d < ψ(n),使得 ed mod ψ(n) = 1 ②;
根据,
由①有,
1 = (e, ψ(n)) = (ψ(n), e) = cψ(n) + de
再利用 模运算法则:
于是有,
1 = 1 mod ψ(n) = (cψ(n) + de) mod ψ(n) = (cψ(n) mod ψ(n) + de) mod ψ(n) = (0 + de) mod ψ(n) = de mod ψ(n)
这样我们就证明了 d 的存在性。
5 销毁 p,q,ψ(n),只保留 e, d, n 分别组成 PK=(e, n) 和 SK=(d, n)。
我们需要证明,用上面方法构造的 PK 和 SK,对于 加密公式 和 解密公式 有效,为此我们仅需要验证,
(Mᵉ mod n)ᵈ mod n = M
即可。
根据 模运算 法则:
上面等式,
左边 = (Mᵉ)ᵈ mod n = Mᵉᵈ mod n
而由 ② 有,
ed = kψ(n) +1, k 是某个正整数
于是,
左边 = Mᵏᵠ⁽ⁿ⁾⁺¹ mod n = (Mᵏ)ᵠ⁽ⁿ⁾M mod n
再根据 模运算 法则:
有,
左边 = ((Mᵏ)ᵠ⁽ⁿ⁾ mod n)M mod n
又有,
这里恒等式的意义是:若 a mod m = b mod m,则称 a 和 b 模 m 同余,记为 a ≡ b (mod m)。
因为 n = pq,p和q都是素数,所以 我们只要保证,
☆ M ≠ p,q
则一定有 (Mᵏ, n) = 1,这样利用 费马小定理,有,
左边 = 1M mod n = M mod n
如果再保证,
★ |M| < n
则,
左边 = M = 右边
这样就证明了前面的等式。
类似地,我们还能证明:(Mᵈ mod n)ᵉ mod n = M,这说明:用SK加密,用PK解密,也行。
一个栗子:
小明 和 贝贝 的交往,遭到双方家人的反对,这天 小明 想要 贝贝告诉他 约会地点,但又不想监控他们通信的家人知道,于是 小明 选取 p = 3, q = 11 两个 奇素数,得到,
n = 3×11 = 33
并计算出,
ψ(n) = (3-1)×(11-1) = 20
由 (3, 20) = 1, 选 e = 3,又,
3×7 = 21 = 20 + 1 ⇒ 3×7 mod 20 = 1
故 d = 7,然后,小明 构造 PK=(3, 33), SK=(7, 33),并将 PK 以明文的方式发送个 给贝贝。
贝贝选择的约会地点是:漠河舞厅,写成拼音就是 mo he wu ting。
贝贝和小明约定:
这使得 ☆ 和 ★ 得到保证。
于是 m = 14 是m的明文,根据加密公式,得到 m 的密文 14³ mod 33 = 5,然后发送个小明,小明受到 5 后,使用解密公式,得到明文 5⁷ mod 33 = 14,再根据约定,就知道 14 = m。
对于 后续的 o he wu ting,依此重复以上的操作,最终,小明就知道了 约会地点。
当然,手动算毕竟很麻烦,于是小明 写了一个 简单的 JavaScript 代码如下:
function is_prime(n) {
for(let k = 2; k <= Math.sqrt(n); k++)
if (!(n % k)) return false;
return true;
}
function gen_key(p, q) {
let n = p*q, y = (p-1)*(q-1);
let e = 3;
while (is_prime(e) && !(y % e))
e += 2;
let d = 2;
while (!(d*e % y === 1))
d++;
return [e, d, n]
}
let encrypt = (M, e, n) => Math.pow(M, e) % n;
let decrypt = (C, d, n) => Math.pow(C, d) % n;
RSA 在实际应用时,会选取 很大的 两个 奇素数 p, q,这样不仅使得 n非常大,监听者 很难 通过因子分解 n 得到 p 和 q,而且可以让 任何 M < p,q,于是 ☆ 和 ★ 也就得到了保证。
另外,还需要注意:
不妨设 p ≤ q,令 ε=q-p 则有,
n = pq = (q-ε)q = q²-εq
于是,
q = (ε + √ (ε² + 4n)) / 2
若 p 和 q 离得很近,则 ε 就很小,于是我们可以从 0 开始 通过不断 尝试 得到 q。
由于,e 和 ψ(n) 都很大,我们很难通过 尝试的方法 求的 d,这时就需要 使用 秦九韶的 大衍求一术,具体方法如下:
对 ψ=ψ(n) 和 e 进行辗转相除(带余除法),有,
ψ = q₁e + r₁
e = q₂r₁ + r₂
r₁ = q₃r₂ + r₃
...
rᵤ₋₂ = qᵤrᵤ₋₁ + rᵤ,(rᵤ=1)
构造两个数列,
c₀=0,c₁=1, cᵢ=qᵢcᵢ₋₁+cᵢ₋₂
d₀=1,d₁=q₁, dᵢ=qᵢdᵢ₋₁+dᵢ₋₂
我们断定有,
命题:cᵢψ - dᵢe = (-1)ⁱ⁻¹rᵢ ③
证明:
c₂ψ - d₂e = (q₂c₁+c₀)ψ - (q₂d₁+d₀)e = q₂ψ - (q₂q₁+1)e = q₂(q₁e + r₁) - (q₂q₁+1)e = q₂r₁ - e = -r₂ = (-1)²⁻¹r₂
命题 成立。
cᵢ₊₁ψ - dᵢ₊₁e = (qᵢ₊₁cᵢ+cᵢ₋₁)ψ - (qᵢ₊₁dᵢ+dᵢ₋₁)e = qᵢ₊₁cᵢψ + cᵢ₋₁ψ - qᵢ₊₁dᵢe - dᵢ₋₁e = qᵢ₊₁(cᵢψ - dᵢe) + (cᵢ₋₁ψ - dᵢ₋₁e) = qᵢ₊₁ (-1)ⁱ⁻¹rᵢ + (-1)ⁱ⁻¹⁻¹rᵢ₋₁ = (-1)ⁱ⁻¹(qᵢ₊₁ rᵢ - rᵢ₋₁) = (-1)ⁱ⁻¹(-rᵢ₊₁) = (-1)ⁱ⁺¹⁻¹rᵢ₊₁
命题 成立,于是 归纳得证!▌
cᵤψ - dᵤe = (-1)ᵘ⁻¹rᵤ = -1
于是,
dᵤe mod ψ = (cᵤψ + 1) mod ψ = 1
故 dᵤ 就是所求的 d。
rᵤ₋₁ = qᵤ₊₁rᵤ + rᵤ₊₁, (qᵤ₊₁ = rᵤ₋₁ - 1, rᵤ₊₁ = 1)
u+1就是偶数,于是这样根据③ 有,
cᵤ₊₁ψ - dᵤ₊₁e = (-1)ᵘ⁺¹⁻¹rᵤ₊₁ = -1
于是,
dᵤ₊₁e mod ψ = (cᵤ₊₁ψ + 1) mod ψ = 1
故 dᵤ₊₁ 就是所求的 d。
大衍求一术 写成 JavaScript代码 如下:
function dyqysh(y, e) {
let d, d1 = 0, d2 = 1
let r1 = y, r2 = e;
let isodd = false;
do {
isodd = !isodd;
let r = r1 % r2, q = (r1 - r) / r2;
// console.log(`${r1} = ${q}*${r2}+${r}`);
d = q*d2 + d1;
d1 = d2, d2 = d;
r1 = r2, r2 = r;
} while(!(r2 === 1))
if (isodd)
d = (r1-1)*d2 + d1;
return d;
}
好了,关于 RSA,小石头目前能想到的就这么多内容了,希望对大家有所帮助。
附录: 推导模运算法则。
有带余除法 a = km + r,于是有,
a + b = km + r + b
于是,
(a + b) mod m = (r + b) mod m
而根据模运算定义有,
a mod m = r
带入前式,立即得证。
令 a mod m = k,于是有, a ≡ k (mod m) ,根据同余性质,有,
aᵇ ≡ kᵇ (mod m)
也就是说,
aᵇ mod m = kᵇ mod m = (a mod m)ᵇ mod m
与法则1推导类似,由带余除法 a = km + r,有,
ab = bkm + rb
于是,
ab mod m = rb mod m = (a mod m)b mod m
(关于,本文使用的定理的证明,见小石头首页中的相关文章。)
们通过一个例子,来理解RSA算法。假设爱丽丝要与鲍勃进行加密通信,她该怎么生成公钥和私钥呢?
第一步,随机选择两个不相等的质数p和q。
爱丽丝选择了61和53。(实际应用中,这两个质数越大,就越难破解。)
第二步,计算p和q的乘积n。
爱丽丝就把61和53相乘。
n = 61×53 = 3233
n的长度就是密钥长度。3233写成二进制是110010100001,一共有12位,所以这个密钥就是12位。实际应用中,RSA密钥一般是1024位,重要场合则为2048位。
第三步,计算n的欧拉函数φ(n)。
根据公式:
φ(n) = (p-1)(q-1)
爱丽丝算出φ(3233)等于60×52,即3120。
第四步,随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质。
爱丽丝就在1到3120之间,随机选择了17。(实际应用中,常常选择65537。)
第五步,计算e对于φ(n)的模反元素d。
所谓"模反元素"就是指有一个整数d,可以使得ed被φ(n)除的余数为1。
ed ≡ 1 (mod φ(n))
这个式子等价于
ed - 1 = kφ(n)
于是,找到模反元素d,实质上就是对下面这个二元一次方程求解。
ex + φ(n)y = 1
已知 e=17, φ(n)=3120,
17x + 3120y = 1
这个方程可以用"扩展欧几里得算法"求解,此处省略具体过程。总之,爱丽丝算出一组整数解为 (x,y)=(2753,-15),即 d=2753。
至此所有计算完成。
第六步,将n和e封装成公钥,n和d封装成私钥。
在爱丽丝的例子中,n=3233,e=17,d=2753,所以公钥就是 (3233,17),私钥就是(3233, 2753)。
实际应用中,公钥和私钥的数据都采用ASN.1格式表达(实例)。
回顾上面的密钥生成步骤,一共出现六个数字:
p
q
n
φ(n)
e
d
这六个数字之中,公钥用到了两个(n和e),其余四个数字都是不公开的。其中最关键的是d,因为n和d组成了私钥,一旦d泄漏,就等于私钥泄漏。
那么,有无可能在已知n和e的情况下,推导出d?
(1)ed≡1 (mod φ(n))。只有知道e和φ(n),才能算出d。
(2)φ(n)=(p-1)(q-1)。只有知道p和q,才能算出φ(n)。
(3)n=pq。只有将n因数分解,才能算出p和q。
结论:如果n可以被因数分解,d就可以算出,也就意味着私钥被破解。
可是,大整数的因数分解,是一件非常困难的事情。目前,除了暴力破解,还没有发现别的有效方法。维基百科这样写道:
"对极大整数做因数分解的难度决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。
假如有人找到一种快速因数分解的算法,那么RSA的可靠性就会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA密钥才可能被暴力破解。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。
只要密钥长度足够长,用RSA加密的信息实际上是不能被解破的。"
举例来说,你可以对3233进行因数分解(61×53),但是你没法对下面这个整数进行因数分解。
12301866845301177551304949
58384962720772853569595334
79219732245215172640050726
36575187452021997864693899
56474942774063845925192557
32630345373154826850791702
61221429134616704292143116
02221240479274737794080665
351419597459856902143413
它等于这样两个质数的乘积:
33478071698956898786044169
84821269081770479498371376
85689124313889828837938780
02287614711652531743087737
814467999489
×
36746043666799590428244633
79962795263227915816434308
76426760322838157396665112
79233373417143396810270092
798736308917
事实上,这大概是人类已经分解的最大整数(232个十进制位,768个二进制位)。比它更大的因数分解,还没有被报道过,因此目前被破解的最长RSA密钥就是768位。
有了公钥和密钥,就能进行加密和解密了。
(1)加密要用公钥 (n,e)
假设鲍勃要向爱丽丝发送加密信息m,他就要用爱丽丝的公钥 (n,e) 对m进行加密。这里需要注意,m必须是整数(字符串可以取ascii值或unicode值),且m必须小于n。
所谓"加密",就是算出下式的c:
me ≡ c (mod n)
爱丽丝的公钥是 (3233, 17),鲍勃的m假设是65,那么可以算出下面的等式:
6517 ≡ 2790 (mod 3233)
于是,c等于2790,鲍勃就把2790发给了爱丽丝。
(2)解密要用私钥(n,d)
爱丽丝拿到鲍勃发来的2790以后,就用自己的私钥(3233, 2753) 进行解密。可以证明,下面的等式一定成立:
cd ≡ m (mod n)
也就是说,c的d次方除以n的余数为m。现在,c等于2790,私钥是(3233, 2753),那么,爱丽丝算出
27902753 ≡ 65 (mod 3233)
因此,爱丽丝知道了鲍勃加密前的原文就是65。
至此,"加密--解密"的整个过程全部完成。
我们可以看到,如果不知道d,就没有办法从c求出m。而前面已经说过,要知道d就必须分解n,这是极难做到的,所以RSA算法保证了通信安全。
你可能会问,公钥(n,e) 只能加密小于n的整数m,那么如果要加密大于n的整数,该怎么办?有两种解决方法:一种是把长信息分割成若干段短消息,每段分别加密;另一种是先选择一种"对称性加密算法"(比如DES),用这种算法的密钥加密信息,再用RSA公钥加密DES密钥。
最后,我们来证明,为什么用私钥解密,一定可以正确地得到m。也就是证明下面这个式子:
cd ≡ m (mod n)
因为,根据加密规则
me ≡ c (mod n)
于是,c可以写成下面的形式:
c = me - kn
将c代入要我们要证明的那个解密规则:
(me - kn)d ≡ m (mod n)
它等同于求证
med ≡ m (mod n)
由于
ed ≡ 1 (mod φ(n))
所以
ed = hφ(n)+1
将ed代入:
mhφ(n)+1 ≡ m (mod n)
接下来,分成两种情况证明上面这个式子。
(1)m与n互质。
根据欧拉定理,此时
mφ(n) ≡ 1 (mod n)
得到
(mφ(n))h × m ≡ m (mod n)
原式得到证明。
(2)m与n不是互质关系。
此时,由于n等于质数p和q的乘积,所以m必然等于kp或kq。
以 m = kp为例,考虑到这时k与q必然互质,则根据欧拉定理,下面的式子成立:
(kp)q-1 ≡ 1 (mod q)
进一步得到
[(kp)q-1]h(p-1) × kp ≡ kp (mod q)
即
(kp)ed ≡ kp (mod q)
将它改写成下面的等式
(kp)ed = tq + kp
这时t必然能被p整除,即 t=t'p
(kp)ed = t'pq + kp
因为 m=kp,n=pq,所以
med ≡ m (mod n)
原式得到证明。
链接文章:
http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
https://zh.wikipedia.org/wiki/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95
*请认真填写需求信息,我们会在24小时内与您取得联系。