BUAA^AITMCLAB&LAB3题解

LAB3题解

  • 分析加密过程:

    • 可以发现采用RSA对message列表进行了加密,并将每组的 < N , e , c > <N,e,c> 输出到了txt文件中

    • from AITMCLAB.Crypto.Util.number import getPrime
      from AITMCLAB.libnum import s2n
      
      
      def RSA_encrypt(message):
          m = s2n(message)
          p = getPrime(1024)
          q = getPrime(1024)
          N = p * q
          e = 5
          c = pow(m, e, N)
          return N, e, c
      
      
      messages = ["*******", "*******", "************", "*********", "**********", "********",
                  "**********", "*************", "**************", "******", "**********",
                  "***************", "*********", "*********", "*******"]
      
      fp = open('output4.txt', 'w')
      for m in messages:
          N, e, c = RSA_encrypt(m)
          fp.write("n = %s" % N + '\n')
          fp.write("e = %s" % e + '\n')
          fp.write("c = %s" % c + '\n')
          fp.write('\n')
      
  • 关于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)

  • 重中之重,本次Lab不可或缺的重点!

    1. '''
      Bangzhu likes talking with his junior schoolmate, but he is so lazy. 
      So he sometimes sends the same files of messages to elaborate them.
      To avoid being discovered by Doc Gao and Doc Wang, he uses an encryption to send messages.
      As a good students like you, you want to accuse Bangzhu and let your teachers know.
      Could u find the flag hidden in the messages? 
      '''
      
      • 注意注释中这句话: s e n d s   t h e   s a m e   f i l e s   o f   m e s s a g e s sends~the~same~files~of~messages sends the same files of messages,这意味着msg(message)片段是被不同的N相同的e加密多次的!

    2. 注意到加密指数 e = 5 e=5 e=5恒定 且 该定值很小

  • 解密方法——低加密指数广播攻击

    1. 低加密指数:

      也就是LAB3的名称——LOW e,加密指数e很小,常见是 e = 3 e=3 e=3或者 e = 2 16 + 1 = 65537 e=2^{16}+1=65537 e=216+1=65537

    2. 广播:

      指采用同样的加密指数 e e e采用不同的N对一份密文多次加密(这就是我之前强调的注释内容)

    3. 攻击方法: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,...,mr是两两互素的自然数,m=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)

      • 对于本LAB: x = m e x=m^e x=me如果CRT后有解我们可以开 e e e次方根得到明文 m m m(因为 x < m xx<m)
  • 接下来是离谱的心路历程(呜呜呜)

    1. 首先,考虑CRT成立的互素条件

      • 信心满满打算写一个判断互素的函数来判断这15组 < N   , e ,   c > <N ,e, c>该如何分组

        def is_coprime(n_lst):
            """判断是否两两互素"""
            l_n = len(n_lst)
            for a in range(l_n):
                for b in range(l_n):	
                    if gcd(n_lst[a], n_lst[b]) == 1:
                        print(a, b)
        
      • 运行结果有点无语,OS:???怎么两两互素!?

    2. 其次,打算想简单一点,观察messag内容 ∗ * 的个数来分组

      • 可是又双叒叕愉快地发现这星号的个数如此随意…
    3. 之后,打算暴力遍历分组情况

      • 回忆集合中幂集的定义:

        设有集合 A ,由 A 的所有子集组成的集合,称为 A 的幂集, 记作 2 A ,即 : 2 A = { S ∣ S ⊆ A } 若 ∣ A ∣ = n , 则 ∣ 2 A ∣ = 2 n 设有集合A,由A的所有子集组成的集合,称为A的幂集,\\ 记作2^A,即:2^A=\{S|S\subseteq A\}\\ 若\left|A\right|=n,则\left|2^A\right|=2^n 设有集合A,由A的所有子集组成的集合,称为A的幂集,记作2A,即:2A={SSA}A=n, 2A =2n

      • 对于模数n的列表(集合):

        ∣ n m o d _ l s t ∣ = 15 故其子集个数(分组情况可能为) 2 15 − 1 = 32767   ( 除去空集 ) \left|nmod\_lst\right|=15\\ 故其子集个数(分组情况可能为)2^{15}-1=32767~(除去空集) nmod_lst =15故其子集个数(分组情况可能为)2151=32767 (除去空集)

      • 如何生成集合的幂集?(python中数据类型我们选择列表代替集合)

        方法:每一次遍历,在已有集合中加上一个新的元素
        对于集合 [ 1 , 2 , 3 ] , 有 { [   ] [   ]   [ 1 ] [   ]   [ 1 ]   [ 2 ]   [ 1 , 2 ] [   ]   [ 1 ]   [ 2 ]   [ 1 , 2 ]   [ 1 , 3 ]   [ 2 , 3 ]   [ 1 , 2 , 3 ] 对于集合[1,2,3],有\\ \begin{cases} [~]\\ [~]~[1]\\ [~]~[1]~[2]~[1,2]\\ [~]~[1]~[2]~[1,2]~[1,3]~[2,3]~[1,2,3]\\ \end{cases} 对于集合[1,2,3], [ ][ ] [1][ ] [1] [2] [1,2][ ] [1] [2] [1,2] [1,3] [2,3] [1,2,3]

        def subsets(lst):
            """生成集合的所有子集"""
            sub_lsts = [[]]
            for sub in lst:
                sub_lsts += [sub_lst + [sub] for sub_lst in sub_lsts]
            return sub_lsts
        
    4. 经过多次实验,发现子集大小为2/3/4/5才会解出有效明文

      • 在k个一组的所有情况中,当且仅当 k = 5 = e k=5=e k=5=e时有不重复的三(15/5)组对应解,即得到三段明文,于是我写了挑选出大小为5的子集的函数:

        def judge_5(lsts):
            """挑选长度为5的列表"""
            sub_5 = []
            for lst in lsts:
                if len(lst) == 5:
                    sub_5.append(lst)
            return sub_5
        
      • k = 2 / 3 / 4 k=2/3/4 k=2/3/4时,也可以解出有效明文,但是有重复

      • 主要代码实现如下:

        if __name__ == "__main__":
            t1 = time.time()
            e = 5
            filename = "output4.txt"
            cipher_lst, nmod_lst = file_proc(filename)
            # 从文件读取c/n列表
            cipher_lst = judge_5(subsets(cipher_lst))
            nmod_lst = judge_5(subsets(nmod_lst))
            # 生成子集->挑出长度5的
            lth = len(cipher_lst)
            msg = ""
            for i in range(lth):
              	# CRT计算x^e
                xe = crt(cipher_lst[i], nmod_lst[i])
         				# gmpy2.iroot()返回一个元组(int:整数部分,bool:是否成功开根)       
                res = gmpy2.iroot(xe, e)
                if res[1]:
                    msg = n2s(int(res[0])).decode("utf-8")
                    print(msg)
            t2 = time.time()
            print(t2 - t1)
        
  • 背后的数学原理(悲,这个部分杀我

    • 这个部分的数学原理困扰了我好几天,直到我翻阅了出题人gfy大佬提供的一份英文文献(英文看不太懂,一知半解的去百度发现有中文译文(x)

    • 数学原理(证明略,有兴趣的同学可以看中文版在这里面找Low Public Exponent RSA

      定理1:这就是为什么我们可以使用CRT计算

      假设 N 1 , N 2 , . . . , N k 为 k 个互素的整数。设 N m i n = m i n ( N i ) , g i ∈ Z N i [ x ] ( 模 N i 的多项式完全剩余系 ) 为 k 个次数为 d 的多项式 假设存在唯一的 M < N m i n , 使得 g i ( M ) ≡ C i ( m o d   N i ) , i ∈ 1 , 2 , . . . , k 故,如果 k ≥ d , 可以有效的从( N i , g i , C i ) i = 1 k 中找到 M 假设N_1,N_2,...,N_k为k个互素的整数。设N_{min}=min(N_i),\\ g_i\in\mathbb{Z}_{N_i}[x](模N_i的多项式完全剩余系)为k个次数为d的多项式\\假设存在唯一的M假设N1,N2,...,Nkk个互素的整数。设Nmin=min(Ni),giZNi[x](Ni的多项式完全剩余系)k个次数为d的多项式假设存在唯一的M<Nmin 使得gi(M)Ci(mod Ni),i1,2,...,k故,如果kd,可以有效的从(Ni,gi,Cii=1k中找到M

      定理2:这就是为什么取分组数为e可以恰好解出m

      设 N 是整数, f ∈ Z N [ x ] 是 d 阶的一元多项式( x d 的系数为 1 ) 那么我们可以找到所有的 x ∈ Z , 使 ∣ x ∣ ≤ B 和 f ( X ) ≡ 0   ( m o d   N ) 其中 B = N 1 d 设N是整数,f\in\mathbb{Z}_N[x]是d阶的一元多项式(x^d的系数为1)\\ 那么我们可以找到所有的x\in\mathbb{Z},使\left|x\right|\leq B和f(X)\equiv0~(mod~N) \\其中B=N^{\frac{1}{d}} N是整数,fZN[x]d阶的一元多项式(xd的系数为1那么我们可以找到所有的xZ,使xBf(X)0 (mod N)其中B=Nd1

      Proof:

      设 h i = g i − C i , 1 ≤ i ≤ k . 接下来寻找 M ,使得 h i ( M ) ≡ 0   ( m o d   N i ) , i ∈ [ 1 , k ] 使用 C R T 进行组合: h ( x ) = ∑ i = 1 k T i h i ( x )   ( m o d   N 1 N 2 . . . N k ) 其中 T i 的选择使用 C R T ,以满足: T i = { 1   ( m o d   N j ) ,   i = j 0   ( m o d   N j ) ,   i ≠ j 故 h ( x ) 满足: 1. 阶(次数) d = 3 2. 首一的 ( x d 的系数为 1 模任何 N i ) 3. h ( M ) ≡ 0   ( m o d   N 1 N 2 . . . N k ) 设h_i=g_i-C_i, 1\leq i \leq k.接下来寻找M,使得h_i(M)\equiv 0~(mod~N_i),i\in [1,k]\\ 使用CRT进行组合:\\ h(x)=\sum_{i=1}^kT_ih_i(x)~(mod~N_1N_2...N_k)\\ 其中T_i的选择使用CRT,以满足:\\ T_i=\begin{cases} 1~(mod~N_j),~i=j\\ 0~(mod~N_j),~i\neq j \end{cases}\\ 故h(x)满足:\\ 1.阶(次数)d=3\\ 2.首一的(x^d的系数为1模任何N_i)\\ 3.h(M)\equiv 0~(mod~N_1N_2...N_k) hi=giCi,1ik.接下来寻找M,使得hi(M)0 (mod Ni),i[1,k]使用CRT进行组合:h(x)=i=1kTihi(x) (mod N1N2...Nk)其中Ti的选择使用CRT,以满足:Ti={1 (mod Nj), i=j0 (mod Nj), i=jh(x)满足:1.阶(次数)d=32.首一的(xd的系数为1模任何Ni)3.h(M)0 (mod N1N2...Nk)

      这时候我们应用定理2求M:

      由 k ≥ d 可得 M < N m i n ≤ ( N 1 N 2 . . . N k ) 1 k ≤ ( N 1 N 2 . . . N k ) 1 d 由k\geq d可得\\ Mkd可得M<Nmin(N1N2...Nk)k1(N1N2...Nk)d1

      这也就解释了为什么2/3/4/5均可以解出明文的原因:

      • 本LAB中, d = e = 5 d=e=5 d=e=5,且实际上三段明文各加密 k = 5 ≥ d k=5\geq d k=5d次满足条件
        M < ( N 1 N 2 . . . N k ) 1 d = ( N 1 N 2 . . . N k ) 1 5 < ( N 1 N 2 . . . N k ) 1 2 / 3 / 4 M<(N_1N_2...N_k)^{\frac{1}{d}}=(N_1N_2...N_k)^{\frac{1}{5}} <(N_1N_2...N_k)^{\frac{1}{2/3/4}} M<(N1N2...Nk)d1=(N1N2...Nk)51<(N1N2...Nk)2/3/41

      • d = 5 d=5 d=5是M有解的一个上界,2/3/4也满足有解条件但是会导致重复(取1的时候显然不能使用CRT)

  • 写在最后,说实话lab3消耗的时间远远多于QUIZ1(比如写这份wp就费了我一个下午,呜呜),其实没必要探究如此之深,但是相比于一个感兴趣的问题困扰我很久,我更喜欢去花费一些时间去探索解决,我觉得这些时间是值得的。

  • 最后的最后,希望看到这篇wp的同学走过路过点个赞收藏一下什么的(狗头保命

  • p.s附上lab3_solution.py

    # _*_ coding: utf-8 _*_
    """
    Time:     2022/9/19 17:21
    Author:   刘征昊(£·)
    Version:  V 1.1
    File:     lab3_solution.py
    Describe: 
    """
    import time
    from AITMCLAB.libnum import n2s, gcd
    import gmpy2
    from functools import reduce
    
    
    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 = gmpy2.invert(mi, ni)
            result += (ci * mi * di) % m
        return result % m
    
    
    def file_proc(fn):
        """
        文件处理函数:从文件中读取每组 n 和 c
        params: fn文件名(含后缀名)
        return: 返回c和n的列表
        """
        cipher = []
        nmod = []
        with open(fn, "r") as fp:
            for line in fp:
                line = line.strip('\n')
                if line.startswith('n'):
                    n = int(line.split(' ')[-1])
                    nmod.append(n)
                elif line.startswith('c'):
                    c = int(line.split(' ')[-1])
                    cipher.append(c)
                else:
                    continue
        return cipher, nmod
    
    
    def is_coprime(n_lst):
        """判断是否两两互素"""
        l_n = len(n_lst)
        for a in range(l_n):
            for b in range(l_n):
                if gcd(n_lst[a], n_lst[b]) == 1:
                    print(a, b)
    
    
    def subsets(lst):
        """生成集合的所有子集"""
        sub_lsts = [[]]
        for sub in lst:
            sub_lsts += [sub_lst + [sub] for sub_lst in sub_lsts]
        return sub_lsts
    
    
    def judge_5(lsts):
        """挑选长度为5的列表"""
        sub_5 = []
        for lst in lsts:
            if len(lst) == 4:
                sub_5.append(lst)
        return sub_5
    
    
    if __name__ == "__main__":
        t1 = time.time()
        e = 5
        filename = "output4.txt"
        cipher_lst, nmod_lst = file_proc(filename)
        # 从文件读取c/n列表
        cipher_lst = judge_5(subsets(cipher_lst))
        nmod_lst = judge_5(subsets(nmod_lst))
        # 生成子集->挑出长度5的
        lth = len(cipher_lst)
        msg = ""
        for i in range(lth):
            xe = crt(cipher_lst[i], nmod_lst[i])
            res = gmpy2.iroot(xe, e)
            if res[1]:
                msg = n2s(int(res[0])).decode("utf-8")
                print(msg)
        t2 = time.time()
        print(t2 - t1)
    #     aitmc{Chicken_soup_is_tasty_CRT_is_tasty_for_you_too}
    # Ahahahaha, here is the chicken soup!! Hahaha A~*sigh*.The dish is all here, why don't you eat? Lao Feng, everyone is afraid to eat it!Someone said that that someone had poisoned the chicken soup. WTF?Captain Wang. You are such a joker. aitmc{Chicken_soup_is_tasty_CRT_is_tasty_for_you_too}. Not salty and not light. The taste is really good!
    
    

你可能感兴趣的:(python,开发语言,网络安全)