RSA公钥密码体制全梳理

RSA公钥密码体制全梳理

算法原理

  • pq 时高次同余方程的求解
    假设 pq 是不同的素数, 并假设 e1, 满足

    gcd(e,(p1)(q1))=1

    e(p1)(q1) 存在逆元, 即

    de1(mod(p1)(q1))

    则同余方程

    xec(modpq)

    有唯一解 xxedcd(modpq)
  • 安全性分析
    已知 pq 时该方程易解,敌手可以计算欧拉函数φ(n)=(p1)(q1),然后利用扩展欧几里得算法计算e对于φ(n)的乘法逆元d,然后解密。
    pq未知时,已知公钥(e,n)求私钥等价于大数因子分解问题;已知一对(M,C)试图还原d,等价于离散对数问题。

算法流程

  1. 密钥生成过程:
    选择两个大素数 pq, 计算公开模数:

    N=qp

    选择公开加密指数 e,满足:

    gcd(e,(p1)(q1))=1

  2. RSA 加密过程:
    将明文转化为整数 m,使用公钥N计算

    Cme(modN)

    得到密文C

  3. RSA解密过程:
    已知p,q,计算d:

    de1(mod(p1)(q1))

    然后计算明文M:

    MCd(modN)

在实际应用中,RSA加解密经过分组的数据段,这些数据段长度相等,固定长度时长度不足的数据段需要进行填充。

算法实现

  1. 使用快速模幂运算计算,python中使用pow函数可以达到同样的效果。

  2. 一般加密过程e比较小,可以快速实现,但解密时d比较大所以实际中利用中国剩余定理来加快计算:

    mcd(modN){m1cd(modp)m1cd(modq){m1(cmodp)dmod(p1)(modp)m1(cmodq)dmod(q1)(modq){m1(cmodp)dmod(p1)(modp)m1(cmodq)dmod(q1)(modq)mm1Aq+m2Bp (modN=pq)A=q1 modpB=p1 modq

  3. 密钥产生——伪随机数发生器、执行素数判定测试(Miller Rabin)

  4. 安全性优化——密钥生成阶段参数选择(否则会产生参数选取不当攻击)
    (1)使用大素数,同时要求p,q相差很大
    (2)尽量使用强素数p,q,强素数指p-1有很大的素因子。否则若p-1没有很大的质因数,而是由m个较小的质因数p1p2...pm组成。则p1=p1a1p2a2...pmam,那么,要分解n则相对容易。(有相关论文可以找到详细分解方法)
    (3)d>N14,避免连分式理论

对RSA的攻击方式

因式分解攻击

分解成功后按照算法原理中的内容可以计算得到明文m

参数选取不当攻击

p,q相差要大(但不能过大)

  • |pq|小时,(pq)24也小,此时(p+q)24稍大于n,即(p+q)2稍大于n12.

    (p+q)24n=(p+q)24pq=(pq)24

    那么:

    while x>n12:
     if x2n=y2:
    n=(x+y)(xy)

  • p,q取值差异过大时,可以用开源项目yafu进行分解(过小也可以),
    使用方法
    安装地址

d特别小,e很大(接近N)

  • 问题描述

    flag = s2n(flag) p = getPrime(1024) q = getPrime(1024) if p < q: p, q = q, p assert q < p < 2 * q phi = (p - 1) * (q - 1) N = p * q d = randint(0, int(iroot(N, 4)[0]) // 3) print(f'N = {N}') print(f'd = {d}') e = invmod(d, phi) print(f'e = {e}') c = pow(flag, e, N) print(f'c = {c}') ''' N = 21327609432635697635661734492967514868032345219646509293473450728946796929125596264796686608077350282146808431543688814099354946988813695125850734043400446455515569653767982263228375866016212125033017742119349015072822178318196190745694850995570515630230752678292777440574778729120793338895028632923682027496271327472935942662500117169921554840041050071839641224638348524022215169727418319630285293394980617769914591506983043636592739835090149763802884920200300368993239366686843677366099965654860267609759882686378049533310393901183559714507043035045332273502601434654726043496991435324318063462466253726816633686491 e = 18977835107309220930390004484766560831346929608900345454868912576417879395319152391809677007908654095951324946088077940809180932163517507338773363819836058226479707254933679974004335002153790380237807333376658330135322627930737835299410373663744954613372507542594748704398503555416693543828015836373800739443278657909905379530092958500438988035068330839162959013568315176411267327500693507377318806169025417092598473813234048525222602269176512302545380940501266666455315603787471273429334914051803354595877792553046681362881913923273953799258321308753602286651515092850863999625965095880385885087205694014033060741113 c = 2951989543787250024227309988919939594167825226148750874062428524625014545445228307222640088545937734380203828988989321941362142365155595290586130523703955533644047842799047518117049515659231726842039527270329713890518786418601487875975864228006745361862477308867519292913016550436143764016127132235503694918940332463597026396960672403183254520332051492462851679089378927071373658225211987354898477962818171916800202243021649078952845125153161320695143579666246174891848723194556125740925439954503389599981696506010841328091656707182777225501527571416356759631836676820899342968642257694841513191347688952532566252238 '''
  • 攻击原理
    在数学中,连分数或繁分数即如下表达式

    x=a0+1a1+1a2+1a3+1,L

    由于 ed1(modφ(N)) ,所以存在整数 k ,满足

    edkφ(N)=1

    由于 N=pq>q2, 即 q<N ,所以

    0<Nφ(N)=p+q1<2q+q1<3q<3N|eNkd|=|edkNdN|=|1+k(φ(N)N)dN|<3kNdN=3kdN

    由于 k<d, 所以 3k<3d<N14, 即

    |eNkd|<1dN14|eNkd|<13d2

    由连分数理论,此时 kdeN 的一个收敛子:
    计算 eN 的连分数展开, 依次算出每一个渐进分数。因为 eN>kd,所以 eN 的渐进分数覆盖了 kd 。 就是说 eN 的渐进分数里有等于 kd 的分数。接着验证 k,d 是否满足条件就求得了 k,d 的值

  • 攻击代码

    # numerator(n):分子, denominator(d):分母 def t_cf(n, d): # 将分数 x/y 转为连分数的形式 res = [] while d: res.append(n // d) n, d = d, n % d return res def cf(sub_res): # 得到渐进分数的分母和分子 n, d = 1, 0 for i in sub_res[::-1]: # 从后面往前循环 d, n = n, i * n + d return d, n def list_fraction(x, y): # 列出每个渐进分数 res = t_cf(x, y) res = list(map(cf, (res[0:i] for i in range(1, len(res))))) # 将连分数的结果逐一截取以求渐进分数 return res def get_pq(a, b, c): # 由p+q和pq的值通过维达定理来求解p和q(解二元一次方程) par = gmpy2.isqrt(b * b - 4 * a * c) # 由上述可得,开根号一定是整数,因为有解 x1, x2 = (-b + par) // (2 * a), (-b - par) // (2 * a) return x1, x2 def wienerAttack(e, n): for (d, k) in list_fraction(e, n): # 用一个for循环来注意试探e/n的连续函数的渐进分数,直到找到一个满足条件的渐进分数 if k == 0: # 可能会出现连分数的第一个为0的情况,排除 continue if (e * d - 1) % k != 0: # ed=1 (mod φ(n)) 因此如果找到了d的话,(ed-1)会整除φ(n),也就是存在k使得(e*d-1)//k=φ(n) continue phi = (e * d - 1) // k # 这个结果就是 φ(n) px, qy = get_pq(1, n - phi + 1, n) if px * qy == n: p, q = abs(int(px)), abs(int(qy)) # 可能会得到两个负数,负负得正未尝不会出现 d = gmpy2.invert(e, (p - 1) * (q - 1)) # 求ed=1 (mod φ(n))的结果,也就是e关于 φ(n)的乘法逆元d return d print("求解d失败") d = wienerAttack(e,N) #print(d) m=int(pow(c,d,N)) flag = n2s(m) print(flag)

选择密文攻击/中间人攻击

  • RSA算法具有同态特点,即对任意x1,x2Zn,有Ek(x1,x2)=Ek(x1)Ek(x2).
    攻击人截获密文c,发出伪造密文rec(r为随机数),可以获得对应明文m=(rec)d=redcd=rm(modN),得

m=mr1

  • RSA-OAEP可抗击适应性选择密文攻击(EUROCRYPT'94,Bellare-Rogaway, Optimal Asymmetric Encryption Padding (OAEP))
    RSA最优非对称加密填充 (RSA-OAEP) 的密钥参数 (N,e,d,G,H,n,k0,k1) 满足:
    • (N,e,d) 是RSA的密钥, 其中
      d=e1(modφ(N)), 并且 Nf=k=n+k0+k1,n 是明文消息的长度,

    • G,H是两个杂湊函数, 且满足G:{0,1}k0{0,1}kk0,H:{0,1}kk0{0,1}k0

    • (N,e) 是Alice的RSA公钥, d 是私钥。
      加密过程:
      为了发送一个消息 m{0,1}n, 给Alice, Bob执行以下几步计算:

      • rU{0,1}k0;s(m0k1)G(r^);t=rH(s)
      • 如果 (stN), 则返回 Va
        c(st)e(modN)
      • 所得密文为 c

      解密过程:
      收到密文 c 后, Alice执行以下几步计算:

      • s||tcd(modN) 满足 |s|=n+k11kk0,|t|=k0
      • utH(s);v=sG(u)
      • 输出 {m, 若 v=m0k1 拒绝, 其他 

共模攻击

对于给定的模数N,最多应该只使用一个加密指数,不同用户间不要共享N

  • 攻击原理
    用公开指数e1,e2加密同一段明文m,且公开模数N不变.
    若截获密文
    c1m1e(modN)c2m2e(modN)
    可解出uv: e1u+e2v=gcd(e1,e2)
    进而 c1uc2vme1ume2vmgcd(e1,e2)(modN)
    若解得gcd(e1,e2)=1,可直接得到m

低指数广播攻击

同一份明文使用不同模数和相同指数多次加密,可以考虑用中国剩余定理破解,然后直接开e次

c1=me(mod  n1)c2=me(modn2)cn=me(modnn)mex(mod  n1nn)

e很小时可以直接爆破

循环攻击

在构造n时应选择𝑝和q,使得𝑝-1和q-1有大的素因子。一般选择𝑝和 (𝑝 − 1)/2 均是素数.
否则进行重复加密:

ce(me)me2(modn)ce2(me)e2me3(modn)cet1(me)et1met(modn)cet(me)etmet+1(modn)

met+1c(modn), 即 (met)ec(modn) ,则有 metm(modn), 即:

cet1m(modn)=1N

可以恢复出明文,但这种攻击方式只有在t比较小时才可行,所以t应该很大
metm(mod n),met11(mod n)
设m在模n下的阶为k,k|et1et1(mod k),所以t|φ(k),且k|φ(n),要保证t很大需要p1,q1有很大的素因子,即为强素数。

消息隐藏

用RSA加密后还是本身的点为不动点.yey mod n.
由数论和中国剩余定理RSA的不动点总数(详细证明我没了解)为
(1+𝑔cd(𝑒1,𝑝1))(1+𝑔cd(𝑒1,𝑞1)
因e-1, p-1, q-1均为偶数, RSA的不动点至少有9个。

私钥d相关信息泄露

定义dp=d,倘若敌手已知dp,可进行如下攻击:

dp=d%(p1)d=k1(p1)+dped=ek1(p1)+dpeed1 mod φ(N)ed=k2φ(N)+1ek1(p1)+dpe=k2φ(N)+1dpe=[k2(q1)k1e](p1)+1dp>p1e>[k2(q1)k1e]X=[k2(q1)k1e]()


__EOF__

本文作者紫炁
本文链接https://www.cnblogs.com/skye-rs/p/16199085.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   紫炁  阅读(1003)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示