一、什么是公钥密码

  在对称密码中,加密和解密的密钥是相同的,但公钥密码中,加密密钥和解密密钥是不同的,因此只有拥有解密密钥的人才能够解密。公钥密码又称非对称密码

  公钥密码中

  • 加密密钥一般是公开的,称为公钥(public key)
  • 解密密钥则绝对不能公开,只能由接收者使用,称为私钥(private key)
  • 公钥和私钥是一一对应的,一对公钥和私钥称为密钥对(key pair),由公钥进行加密的密文,必须使用对应的私钥才能解密
  • 公钥和私钥不能单独生成

二、通信流程

  在公钥密码通信中,通信过程由接收者Receiver来启动。发送者为Sender。 - Receiver生成一个密钥对 - Receiver将公钥发送给Sender - Sender使用公钥对消息进行加密,并将密文发送给Receiver - Receiver使用私钥解密密文

三、RSA

  RSA是现在使用最广泛的公钥密码算法,其名字是由三位开发者Ron Rivest、Adi Shamir和Leonard Adleman的姓氏首字母组成。RSA可用于公钥密码和数字签名。

1.RSA算法原理

  RSA加密算法如下,E和N的组合即(E,N)就是公钥: $$ c=m^EmodN $$   RSA解密算法如下,D和N的组合即(D,N)就是私钥(由于N是公钥的一部分,所以可单独将D称为私钥): $$ m=c^DmodN $$   可见,RSA加密最重要的就是E、D、N三个数,下面给出生成这三个数的算法

选择两个大质数p和q,通常由伪随机数生成器生成

  • N=p×q
  • L=φ(n)=(p-1)(q-1)
  • E要满足1<E<L且gcd(E,L)=1,即E与L互质,这是为了保证一定存在D
  • D要满足1<D<L且E×D mod L=1,保证对密文解密能够得到正确的明文

  得到E、D和N后即可封装成公钥和密钥。密钥的长度就是N的长度。实际应用中,公钥和私钥的数据都采用ASN.1格式表达。

2.对RSA的攻击

  • 通过密文求得明文:已知密文、E和N,求解方程 $$ c=m^EmodN $$ 这是一个求离散对数的问题,目前还没有高效的算法。

  • 暴力破解找出D:暴力枚举D,破解难度随着D的长度增加而变大,当D足够长时,一辈子都爆不出来。

  • 通过E和N求出D:如果能够高效地对N进行质因数分解,即求出p和q,RSA就能被破译,但是目前公开能够分解的最大整数为768位。

  • 通过推测p和q进行攻击,和伪随机数生成器玩猜数字游戏( ̄▽ ̄)“。

  • 中间人攻击:攻击者充当中间人,拦截接收者发出的公钥并替换为另一公钥,攻击者可以拦截发送者发送的密文并使用私钥解密,而后篡改消息,再通过真正的公钥加密后发送给接收者。该过程可以反复进行。该方法是针对机密性的攻击,但无法破译RSA。可以使用证书来确认公钥来源,以防范这种攻击手段。

  • 选择密文攻击:如果服务器对收到的任意数据都当做密文来解密,并返回解密结果(即解密提示),攻击者可以构造不同的信息让解密提示尝试解密,从而获得密钥与明文有关的部分信息。有点像SQL报错注入。对密文进行认证可抵御选择密文攻击,如RSA-OAEP算法。

3.密码劣化与RSA的长度

  随着计算机技术的进步,以前安全的密码会被破译,该现象称为密码劣化。针对该现象,NIST SP800-57给出如下方针 - 1024位的RSA不应被用于新的用途 - 2048位的RSA可在2030年之前被用于新的用途 - 4096位的RSA在2031年之后仍可被用于新的用途

四、其他公钥密码

五、CTF中的RSA破译

1.低加密指数攻击

  在RSA加密算法中,选取的加密指数E较小,分两种情况。

  如果明文较小,m^E小于N,可得到

  如果m^E大于N,但不是特别大,可以通过枚举可能的k,使得有整数解

# -*- coding: utf-8 -*-

import gmpy
n=int(raw_input("输入n:"))
c=int(raw_input("输入密文C:"))
e=int(raw_input("输入加密指数E:"))

k=0;
while 1:
    if(gmpy.root(c+k*n,e)[1]==1):
        print "明文:",gmpy.root(c+k*n,e)
        break
    k=k+1

2.低加密指数广播攻击

  给出多组加密的参数,使用相同的低加密指数加密相同的信息(N不同),这种情况可以进行广播攻击得到明文。例如有 $$ c_1=m^EmodN_1 \quad c_2=m^EmodN_2 \quad c_3=m^EmodN_3 $$   由中国剩余定理,可得到 $$ c=m^Emod(N_1 \times N_2 \times N_3) $$

3.低解密指数攻击

  在RSA解密算法中,选取的解密指数D较小,一般给出的加密指数E会很大。

  pablocelayes/rsa-wiener-attack给出了攻击的python脚本。

4.共模攻击

  明文相同,已知密文和公钥,加密时对相同的N取模,加密指数不同。如果两个加密指数互质,可得到 $$ E_1 \times S_1 + E_2 \times S_2=1,其中S_1与S_2都为整数,且S_1 \times S_2<0 $$   又 $$ c_1=m^{E_1}modN \quad c_2=m^{E_2}modN $$   所以 $$ ({c_1}^{S_1} \times {c_2}^{S_2})modN=m^{E_1 \times S_1 + E_2 \times S_2}modN $$   得到 $$ ({c_1}^{S_1} \times {c_2}^{S_2})modN=mmodN $$   求出S1与S2即可求出明文

# -*- coding: utf-8 -*-

def egcd(a,b):
    if a==0:
        return (b,0,1)
    else:
        g,y,x=egcd(b%a,a)
        return (g,x-(b//a)*y,y)
def modinv(a,m):
    g,x,y=egcd(a,m)
    if g!=1:
        raise Exception('模反不存在')
    else:
        return x%m
def main():
    n=int(raw_input("输入n:"))
    c1=int(raw_input("输入密文C1:"))
    c2=int(raw_input("输入密文C2:"))
    e1=int(raw_input("输入加密指数E1:"))
    e2=int(raw_input("输入加密指数E2:"))
    s=egcd(e1, e2)
    s1=s[1]
    s2=s[2]
    if s1<0:
        s1=-s1
        c1=modinv(c1,n)  #通过求模反元素的正数次幂进行负数次幂运算
    elif s2<0:
        s2=- s2
        c2=modinv(c2,n)
    print (c1**s1)*(c2**s2)%n
if __name__=='__main__':
    main()

More

算法原理(一) - 阮一峰的网络日志

算法原理(二) - 阮一峰的网络日志