BUAA^AITMCLAB&RSA大作业

RSA实现

  • RSA算法原理

    • 安全性:高次同余方程求解问题——依赖于大整数质因数分解的难度

    • 加密变换: m e = c   m o d   N m^e = c~mod~N me=c mod N,其中 m m m为明文, c c c为密文

      • 公钥: < N , e > <N,e> 任何人拥有了公钥即可进行加密

        1 < e < ( p − 1 ) ( q − 1 ) g c d ( e , ( p − 1 ) ( q − 1 ) ) = 1 11<e<(p1)(q1)gcd(e,(p1)(q1))=1

    • 解密变换: m = c d   m o d   N m= c^d~mod~N m=cd mod N

      • 私钥: < N , d > <N,d> 其中: N = p q N=pq N=pq(p,q均为质数)

d e = 1   m o d   ( p − 1 ) ∗ ( q − 1 ) de=1~mod~(p-1)*(q-1) de=1 mod (p1)(q1)

  • RSA密码体系实现

    • RSA公/私钥的生成

      1. 生成大素数p/q:

        def get_prime(len_bit):
            """
            随机获取一个二进制位长len_bit的整数
            """
            prm = (randint(2 ** (len_bit - 1), 2 ** len_bit) + 1) | 1
            # 利用或运算保证prm是一个奇数
            while not isPrime(prm):
                prm += 2
            return prm
        
        或运算:

        特 性 : 有 1 得 1 , 全 0 才 0 0 ∣ 0 = 0 ;    0 ∣ 1 = 1 ; 1 ∣ 0 = 0 ;    1 ∣ 1 = 1 应 用 : 某 位 赋 值 1 特性:有1得1,全0才0\\ 0|0=0;~~ 0|1=1;\\ 1|0=0;~~ 1|1=1\\ 应用:某位赋值1 110000=0;  01=1;10=0;  11=11

      2. Miller_rabin素性检验(判断质数)

        • 数学原理(费马小定理和二次探测)

          费马小定理
          设 p 是 一 个 素 数 , 那 么 ∀ a ∈ Z 有   a p ≡ a ( m o d   p ) 设p是一个素数,那么\forall a\in \mathbb{Z}\\ 有~a^p\equiv a(mod~p) paZ apa(mod p)
          二次探测定理:
          如 果 p 是 一 个 素 数 , 0 < x < p , 则 方 程 x 2 ≡ 1 ( m o d   p ) 的 解 为 : x ≡ ± 1 ( m o d   p ) 反 之 , 如 果 方 程 的 解 不 是 x ≡ ± 1 ( m o d   p ) , 那 么 p 不 是 素 数 如果p是一个素数,0p,0<x<p,x21(mod p):x±1(mod p)x±1(mod p)p
          Miller-rabin witness:
          设 n 是 一 个 奇 数 , 则 n − 1 = 2 k q , 其 中 q 是 奇 数 , 取 满 足 g c d ( a , n ) = 1 的 a 如 下 条 件 满 足 , 则 称 a 是 n 的 M i l l e r − R a b i n w i t n e s s : 1. a q ≢ 1 ( m o d   n ) 2. a 2 i q ≢ − 1 ( m o d   n )   i = 0 , 1 , . . . , k − 1 设n是一个奇数,则n-1=2^kq,其中q是奇数,取满足gcd(a,n)=1的a\\ 如下条件满足,则称a是n的Miller-Rabin witness:\\ 1.a^q\not\equiv1(mod~n)\\ 2.a^{2^iq}\not\equiv-1(mod~n)~i=0,1,...,k-1 nn1=2kq,qgcd(a,n)=1a,anMillerRabinwitness1.aq1(mod n)2.a2iq1(mod n) i=0,1,...,k1

        def isPrime(n):
            """
            miller-rabin检验,返回是否是质数
            """
            if n == 2 or n == 3:
                return True
            if not n & 1:
                return False
            m, q = n - 1, 0
            while not m & 1:
                m >>= 1
                q += 1
            rd, seed1, seed2 = 20011224, 998244353, 20217371
            for i in range(0, 30):
                rd = rd * seed1 + seed2
                if rd < 0:
                    rd = -rd
                a = rd % (n - 1) + 1
                tmp = fast_power(a, m, n)
                for j in range(0, q):
                    ans = tmp ** 2 % n
                    if ans == 1:
                        if tmp != 1 and tmp != n - 1:
                            return False
                        break
                    tmp = ans
                if ans != 1:
                    return False
            return True
        
      3. 快速(模)幂运算:

        def fast_power(base, power, n=0):
            """
            快速(模)幂运算
            n的默认值为0:快速幂运算
            n>0:快速模幂运算
            """
            if power <= 0:
                raise ValueError("power must be postive")
            result = 1
            if n == 0:
                while power > 0:
                    if power & 1:
                        result *= base
                    power >>= 1
                    base *= base
            else:
                while power > 0:
                    if power & 1:
                        result = result * base % n
                    power >>= 1
                    base = base ** 2 % n
            return result
        
      4. 生成(n, e, d, p, q)并进行公钥和私钥的保存

        • 综合实现:
        def get_key(len_bit):
            """
            生成RSA公私钥
            params: len_bit:p/q的二进制基础长度,
            return: (n, e), (n, d), (p, q)
            """
            p = get_prime(len_bit + 1)
            q = get_prime(len_bit + 3)
            # 保证p/q不是很接近
            n = p * q
            phi = (p - 1) * (q - 1)
            e = get_prime(16)
            while gcd(e, phi) > 1:
                e = get_prime(16)
            d = invmod(e, phi)
            with open("public_key.txt", "w") as f:
                f.write(f"n = {n}\n")
                f.write(f"e = {e}\n")
            with open("private_key.txt", "w") as f:
                f.write(f"n = {n}\n")
                f.write(f"d = {d}\n")
            return (n, e), (n, d), (p, q)
        
        • 逆元实现:

          扩展欧式算法:

          def Egcd(a, b):
              """
              扩展欧拉算法:au+bv=g
              params: a, b
              return: x = (g, u, v)
              """
              x = [a, 1, 0]
              y = [b, 0, 1]
              while y[0] != 0:
                  q = x[0] // y[0]
                  for i in range(0, 3):
                      x[i] = x[i] - q * y[i]
                  tmp = x[:]
                  x = y[:]
                  y = tmp[:]
              return x
          

          逆元判断:

          def invmod(a, n):
              """
              求a mod n 的逆元
              """
              if n < 2:
                  raise ValueError("n must be bigger than 1")
              g, x, y = Egcd(a, n)
              if g != 1:
                  raise ValueError("no invmod")
              else:
                  return x % n
          
    • RSA加密算法:

      def rsa_encrypt(m, public_key):
          """
          RSA加密函数
          params:公钥publickey = (n, e)    明文m(整数形式)
          return:密文c
          """
          n, e = public_key[0], public_key[1]
          if m < 0:
              raise ValueError("msg is negative")
          elif m > n:
              raise ValueError("msg is too long")
          else:
              c = fast_power(m, e, n)
              return c
      
    • RSA解密算法:

      • 基础实现:

      def rsa_decrypt(c, private_key):
          """
          RSA解密函数
          params:私钥private_key = (n, d)     密文c(整数)
          return:明文m
          """
          n, d = private_key[0], private_key[1]
          if c < 0:
              raise ValueError("cpr is negative")
          elif c > n:
              raise ValueError("cpr is too long")
          else:
              m = fast_power(c, d, n)
              return m
      
      • CRT加速实现:

        CRT(中国剩余定理)

        数学原理:
        设 m 1 , m 2 , . . . , m r 是 两 两 互 素 的 自 然 数 , 令 m = m 1 m 2 . . . m r ,   M i = m m i ,   i = 1 , . . . , r , 则 方 程 组 : { x ≡ b 1   ( m o d   m 1 ) x ≡ b 2   ( m o d   m 2 )    . . . x ≡ b r   ( m o d   m r )    的 解 为 : x ≡ M 1 ′ M 1 b 1 + M 1 ′ M 2 b 2 + . . . M r ′ M r b r   ( m o d   m ) 即   x ≡ ∑ i = 1 r   M i ′ M i b i   ( m o d   m ) 其 中   M i ′   满 足   M i ′ M i ≡ 1   ( m o d   m i ) 设m_1,m_2,...,m_r是两两互素的自然数,\\ 令m=m_1m_2...m_r,~M_i=\frac{m}{m_i},~i=1,...,r,则方程组:\\ \begin{cases} x\equiv b_1~(mod~m_1)\\ x\equiv b_2~(mod~m_2)\\ ~~ ...\\ x\equiv b_r~(mod~m_r) \end{cases} ~~的解为:\\ x\equiv M_1'M_1b_1+M_1'M_2b_2+...M_r'M_rb_r~(mod~m)\\ 即~x\equiv \sum_{i=1}^r~M_i'M_ib_i~(mod~m)\\ 其中~M_i'~满足~M_i'M_i\equiv 1~(mod~ m_i) m1,m2,...,mrm=m1m2...mr, Mi=mim, i=1,...,r,xb1 (mod m1)xb2 (mod m2)  ...xbr (mod mr)  xM1M1b1+M1M2b2+...MrMrbr (mod m) xi=1r MiMibi (mod m) Mi  MiMi1 (mod mi)
        代码实现:

        def crt(cpr_lst, n_lst):
            """
            中国剩余定理求解: x = c (mod n)
            params:
                cpr-lst 余数c列表
                n_lst 模数n列表
            return: x
            """
            # 累积 m = n1*n2*...*nk
            m = reduce(lambda x, y: x * y, (ni for ni in n_lst))
            result = 0
            data = zip(cpr_lst, n_lst)
            for ci, ni in data:
                mi = m // ni
                di = invmod(mi, ni)
                result += (ci * mi * di) % m
            return result % m
        

        CRT加速解密计算:

      def rsa_decrypt_crt(c, d, prime_pair):
          """
          CRT加速解密计算(已知p、q)
          """
          p, q = prime_pair[0], prime_pair[1]
          c_lst = [fast_power(c, d % (p - 1), p), fast_power(c, d % (q - 1), q)]
          n_lst = [p, q]
          return crt(c_lst, n_lst)
      
    • RSA签名算法:

      基本原理:

      对 明 文 m 使 用 h a s h 得 到 信 息 摘 要 d i g e s t , 之 后 对 信 息 摘 要 使 用 私 钥 进 行 加 密 得 到 签 名 s ≡ d i g e s t d ( m o d   n ) 对明文m使用hash得到信息摘要digest,之后对信息摘要使用私钥进行加密得到签名\\s\equiv digest^d(mod~n) m使hashdigest,使sdigestd(mod n)

      信息摘要digest生成:

      import hashlib
      dgst = s2n(hashlib.sha256(msg).digest())
      

      签名代码实现:

      def rsa_sign(digest, private_key):
          """
          RSA签名生成函数:对信息摘要使用私钥加密生成签名
          return:签名signature
          """
          signature = rsa_encrypt(digest, private_key)
          with open("signature.txt", "w") as f:
              f.write(f"sgn = {signature}")
          return signature
      
    • RSA验证算法:

      基本原理:

      对 签 名 使 用 公 钥 进 行 解 密 与 信 息 摘 要 进 行 比 对 , 如 果 一 致 则 验 证 通 过 d g s t ≡ s e ( m o d   n ) 对签名使用公钥进行解密与信息摘要进行比对,如果一致则验证通过\\ dgst \equiv s^e(mod~n) 使dgstse(mod n)

      验证代码实现:

      def rsa_verify(digest, signature, public_key):
          """
          RSA签名验证函数:使用公钥对签名验证
          return:验证是否成功(bool)
          """
          if digest == rsa_decrypt(signature, public_key):
              return True
          else:
              return False
      
    • RSA公钥与私钥的文件读取:

      • 公钥读取:

        def get_pubkey(pubfile="public_key.txt"):
            """
            公钥文件读取
            params:默认公钥文件名"public_key.txt"
            return:公钥(n,e)
            """
            with open(pubfile, "r") as f:
                for line in f:
                    if line.startswith('n'):
                        n = line.split(' ')[-1]
                    if line.startswith('e'):
                        e = line.split(' ')[-1]
            return n, e
        
      • 私钥读取:

        def get_privkey(privfile="private_key.txt"):
            """
            私钥文件读取
            params:默认私钥文件名:"private_key.txt"
            return:私钥(n,d)
            """
            with open(privfile, "r") as f:
                for line in f:
                    if line.startswith('n'):
                        n = line.split(' ')[-1]
                    if line.startswith('d'):
                        d = line.split(' ')[-1]
            return n, d
        
  • RSA算法基本流程实现:

    • 加密对象类型选择:

      def type_choose(path="message.txt"):
          """
          加密对象类型选择(文件或者非文件)
          """
          choice = int(input("plz select the Encryption Type:\n1. file  2. not file:"))
          if choice == 1:
              path = input("plz input the filename or filepath:\n")
              with open(path, "r") as f:
                  message = f.read()
          else:
              message = input("plz input the content to be encrypted:")
          return message.encode("utf-8")
      
    • 主流程:

      if __name__ == "__main__":
          # msg = "£.RSA{ha6a_I_am_lzh_i_want_t0_6ai1an}"
          msg = type_choose()
          dgst = s2n(hashlib.sha256(msg).digest())
          pubkey, privkey, prmpair = get_key(1024)
          sgn = rsa_sign(dgst, privkey)
          cpr = rsa_encrypt(s2n(msg), pubkey)
          print(f"cipher is {cpr}")
          print(f"verification is {rsa_verify(dgst, sgn, pubkey)}")
          t1 = time.time()
          rcvr = n2s(rsa_decrypt(cpr, privkey)).decode("utf-8")
          t2 = time.time()
          print(f"message is recovered: {rcvr},time is {t2-t1:.8f}")
          t1 = time.time()
          rcvr_crt = n2s(rsa_decrypt_crt(cpr, privkey[1], prmpair)).decode("utf-8")
          t2 = time.time()
          print(f"message is recovered by CRT: {rcvr_crt},time is: {t2-t1:.8f}")
      
      
    • 运行截图:

    BUAA^AITMCLAB&RSA大作业_第1张图片

  • RSA参数选择与安全性(思考题)

    1. 模数N:

      • p与q的差距要大

        否 则 当 p 和 q 很 接 近 的 时 候 , 在 已 知 N 得 情 况 下 , 不 妨 假 设 p > q 由 ( p + q 2 ) 2 = N + ( p − q 2 ) 2 当 左 边 可 开 放 时 , 可 求 出 p − q 进 而 求 得 p / q 否则当p和q很接近的时候,在已知N得情况下,不妨假设p>q\\ 由 \left( \frac{p+q}{2} \right)^2=N+ \left( \frac{p-q}{2} \right)^2\\ 当左边可开放时,可求出p-q进而求得p/q pqNp>q(2p+q)2=N+(2pq)2pqp/q

      • g c d ( p − 1 , q − 1 ) gcd(p-1,q-1) gcd(p1,q1)最大公因子应该较小

        原因是我们可以使用满足 d e ≡ 1 ( m o d   ( p − 1 ) ( q − 1 ) g ) de\equiv1(mod~\frac{(p-1)(q-1)}{g}) de1(mod g(p1)(q1))的较小的d来加快计算,其中 g = g c d ( p − 1 , q − 1 ) g=gcd(p-1,q-1) g=gcd(p1,q1)越大,求解得到的d越小越不安全。

      • p与q应该是满足以下条件的强素数:

        • ∃ 大 素 数 p 1 , p 2 , s . t .   p 1 ∣ p − 1 , p 2 ∣ p + 1 \exists 大素数p_1,p_2,s.t.~p_1|p-1,p_2|p+1 p1,p2,s.t. p1p1,p2p+1

        • ∃   四 个 大 素 数 r 1 , r 2 , s 1 , s 2 , s . t .   r 1 ∣ p 1 − 1 , r 2 ∣ p 1 + 1 ,   s 1 ∣ p 2 − 1 , s 2 ∣ p 2 + 1 \exists~四个大素数r_1,r_2,s_1,s_2,s.t.~r1|p_1-1,r_2|p_1+1,~s_1|p_2-1,s_2|p_2+1  r1,r2,s1,s2,s.t. r1p11,r2p1+1, s1p21,s2p2+1

    2. 加密指数e:

      • 基础条件: g c d ( e , ϕ ( n ) ) = 1 gcd(e, \phi (n))=1 gcd(e,ϕ(n))=1

      • e不能太小:预防低加密指数(广播)攻击(Lab3),一般可取16位大小的素数( 65537 = 2 16 + 1 65537=2^{16}+1 65537=216+1

    3. 解密指数d:

      • 一般要求 d > N 4 3 d>\frac{\sqrt[4]{N}}{3} d>34N ,否则当我们使用一个较小的d去确定e时,低解密指数攻击(wiener-attcak)(level 3)可以轻而易举的复原d(p/q)

    4. 其他:如共模攻击(使用同一个模数进行加密)、私钥泄漏分解N(已知 < n , e , d , 求 p 、 q <n,e,dpq

      • 详见level1/2等题解


  • 心得体会

    • 完成大作业(或者说包括Lab&Quiz)我想对我来说最重要的就是能够把理论具像化实现,理论基础固然重要,但我觉得应用也是不可或缺的一部分。

    • 个人是喜欢敲一写代码去实现一些功能算法的,这也是合理利用信息技术的一个方面。但更重要的是,在实操过程中能够更全面更有效(虽然有时候搞半天进度缓慢,比如Lab3)的去学习新知识、去应用理论

    • 当然还有探索深层理论的困难与渴望,⬇️图是Lab3的wp结语(doge[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传在这里插入图片描述

    • 当然我也深知自己知识的理论和实践水平远远不够(呜呜期中怎么办~我是小垃圾),所以我一定会逼迫自己更熟练的掌握旧知识,更广泛的去学习新知识(包括但不限于学业知识)

    • 一点建议:是不是能把LAB&QUIZ这些加一点正式的学分(或许选修?或许其他奖励方式?)呢,我觉得这对于像我一样热爱信安数基的同学,既能够在把理论与实践结合的过程中获取自我乐趣,又能够对学业成绩有所帮助!

你可能感兴趣的:(python,算法,网络安全)