记一次30位密钥长度RSA加密破解过程

首先题目提示是RSA加密
数据:

{920139713,19}

704796792
752211152
274704164
18414022
368270835
483295235
263072905
459788476
483295235
459788476
663551792
475206804
459788476
428313374
475206804
459788476
425392137
704796792
458265677
341524652
483295235
534149509
425392137
428313374
425392137
341524652
458265677
263072905
483295235
828509797
341524652
425392137
475206804
428313374
483295235
475206804
459788476
306220148

参考 http://www.cfca.com.cn/zhishi/wz-012.htm
算法描述:

1)选择一对不同的、足够大的素数p,q。
(2)计算n=pq。
(3)计算f(n)=(p-1)(q-1),同时对p, q严加保密,不让任何人知道。
(4)找一个与f(n)互质的数e,且1<e<f(n)。
(5)计算d,使得de≡1 mod f(n)。这个公式也可以表达为d ≡e-1 mod f(n)
这里要解释一下,≡是数论中表示同余的符号。公式中,≡符号的左边必须和符号右边同余,也就是两边模运算结果相同。显而易见,不管f(n)取什么值,符号 右边1 mod f(n)的结果都等于1;符号的左边d与e的乘积做模运算后的结果也必须等于1。这就需要计算出d的值,让这个同余等式能够成立。
(6)公钥KU=(e,n),私钥KR=(d,n)。
(7)加密时,先将明文变换成0至n-1的一个整数M。若明文较长,可先分割成适当的组,然后再进行交换。设密文为C,则加密过程为:C≡M^e(mod n)。
(8)解密过程为:M≡C^d(mod n)。

有了上面的RSA基础可以知道RSA中的

p: 第一个大素数
q: 第二个大素数 
模数n: n = p*q 
f(n):  (p-1)*(q-1) 
公钥指数e: 与 f(n)互质, 且 1 < e < f(n) 
私钥指数d: 满足e * d ≡ 1 (mod f(n))
公钥 = {n, e} 
私钥 = {d, e}

然后结合附件第一行 {920139713,19}和题目要求,可以推测出给的是公钥{n, e}然后下面的一些行都是用私钥{d, e}加密过后的密文c,我们要求出明文m。

RSA的密钥是公钥或私钥,密钥长度通常指模数n的位数。现用RSA的密钥长度1024位、2048位及以上

如果RSA的密钥长度过短,则可以通过分解模数n来获得p和q,获得私钥,从而获得明文。题目中模数n=920139713,二进制=110110110110000011011111000001,密钥长度只有30位。利用现在的pc,很容易就破解出来了。

手工过程:
n =920139713,分解模数:

1)选择在线网站http://factordb.com/,秒出;
2)用下面的python程序,也是秒出
def moder(n):
    base = 2  
    while base < n: 
        if n % base == 0: 
            print base, n/base
        base += 1

得到 p = 18443 q = 49891
欧拉函数
f(n) = (p-1)(q-1)= 18442 × 49890= 920071380
又已知 e = 19,求d
d满足: e * d ≡ 1 (mod f(n))
即 (19 * d) mod 920071380 = 1
欧几里德算法(辗转相除法)求d

 e位置    f(n)位置
[e * d - f(n) *k = 1]
[A]:f(n)位置 mod e位置 的余数替代 f(n)位置
[B]:e位置 mod f(n)位置 的余数替代 e位置
[A]:f(n)位置 mod e位置 的余数替代 f(n)位置
.
.
.

循环,直至d 的系数为 1, 即e位置=1时结束

[a式]19×d - 920071380×k =1      (k 为正整数)
[b式]19×d - 9×k =1f(n)位置 mod e位置 的余数9代替f(n)位置
[c式]1×d - 9×k=1e位置 mod f(n)位置 的余数1代替e位置

e位置=1,结束,然后
令k=0,带入[c式],得d=1;
d=1,带入[b式],得k=2;
k=2,带入[a式],得d=96849619
到这里求出d值了

然后 就完全得到密钥了:

公钥 = { n ,e}
公钥 = {920139713,19}
私钥 = {d ,e}
私钥 = {96849619 ,19}

第一个密文: c1 = 704796792
m1 = (c1^d)(mod n)= (704796792^96849619)mod(920139713)

这里手工可不容易算出来,借用python的pow函数:

>>> print pow(704796792,96849619,920139713)
102
>>>

秒出,102 对应的ASCII码是”f”
然后循环就可以了求出所有的值就得到flag了……

程序:
输入 e 和 n 与密文文件路径,求出RSA算法加密的明文
ps: 程序健壮性可能不太好,多多包涵

#!/usr/bin/env python
# coding:utf-8
#
# RSA tools
# Build by LandGrey
#

import os
import sys


# 分解模数n
def moder(n):
    base = 2
    while base < n:
        if n % base == 0:
            return base, n/base
        base += 1


# 求欧拉函数f(n)
def getEuler(prime1, prime2):
    return (prime1-1)*(prime2-1)


# 求私钥
def getDkey(e, Eulervalue):
    k = 1
    while True:
        if (((Eulervalue * k) + 1) % e) == 0:
            return (Eulervalue * k + 1) / e
        k += 1


# 私钥求明文
def decrypt(c, d, n):
    return pow(c, d, n)


def usage():
    print '[+] usage: python RSAtool.py [e] [n] [filepath]'
    print '[+] example: python RSAtool.py 19 920139713 1.txt'


if __name__ == '__main__':
    if len(sys.argv) != 4:
        print 'argument error'
        usage()
        sys.exit()
    elif (str(sys.argv[1]).isdigit() is False) or (str(sys.argv[2]).isdigit() is False):
        print 'e and n must be digital'
        usage()
        sys.exit()
    elif int(sys.argv[1]) < 3:
        print 'e >= 3'
        print usage()
        sys.exit()
    elif not os.path.isfile(sys.argv[3]):
        print 'file path is error'
        usage()
        sys.exit()
    else:
        character = []
        digital = []
        e = int(sys.argv[1])
        n = int(sys.argv[2])
        primes = moder(n)
        p = primes[0]
        q = primes[1]
        pkey = getDkey(e, getEuler(p, q))
        with open(sys.argv[3], 'r') as f:
            data = f.readlines()
        linecount = 1
        for line in data:
            if (line.strip()).isdigit() is False:
                print "The %s line '%s' is not digital" % (str(linecount), line.strip())
            elif decrypt(int(line.strip()), pkey, n) >0 and decrypt(int(line.strip()), pkey, n) < 256:
                character.append(chr(decrypt(int(line.strip()), pkey, n)))
                digital.append(str(decrypt(int(line.strip()), pkey, n)))
            linecount += 1
        if character != []:
            print 'Character :%s' % ''.join(character)
        print 'Digital :%s' % ' '.join(digital)

运行结果:

>python RSAtool.py 19 920139713 C:\Users\LandGrey\Desktop\RSAROLL.txt
Character :flag{13212je2ue28fy71w8u87y31r78eu1e2}
Digital :102 108 97 103 123 49 51 50 49 50 106 101 50 117 101 50 56 102 121 55 49 119 56 117 56 55 121 51 49 114 55 56 101 117 49 101 50 125
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页