0
点赞
收藏
分享

微信扫一扫

RSA大礼包

夏天的枫_ 2022-01-09 阅读 52
算法

RSA礼包


RSA简介

RSA算法涉及三个参数,n,e,d,私钥为 d,公钥对为 n,e
其中N = pq (p,q均为大素数)
ed = 1 mod (p-1)(q-1)
(p-1)(q-1)的值为n的欧拉函数
c 为密文,m 为明文,则加密过程如下:
c ≡ me mod n
解密过程如下:
m ≡ cd mod n

n,e 是公开的情况下,想要知道 d 的值,必须要将 n 分解计算出 n 的欧拉函数值,而 n 是两个大素数 p,q 的积, 将其分解是困难的。
但是对于特定的情况可以使用特殊方法进行分解

数据收集

n = []
e = []
c = []
m = {}
solved = []
name = ['./Frame' + str(i) for i in range(21)]
for i in range(21):
    f = open(name[i], 'r')
    data = f.read()
    tn, te, tc = int(data[:256], 16), int(data[256:512], 16), int(data[512:], 16)
    n.append(tn)
    e.append(te)
    c.append(tc)

题目解法

直接分解n

素数分解问题是困难的,但是可以通过计算机进行暴力分解。
通常意义上来说,一般认为 2048bit 以上的 n 是安全的。现在一般的公钥证书都是 4096bit 的证书

如果 n 比较小,那么可以通过工具进行直接 n 分解,从而得到私钥。如果 n 的大小小于 256bit,那么我们通过本地工具即可爆破成功。
例如采用 windows 平台的 RSATool 2v17,可以在几分钟内完成 256bit 的 n 的分解。

大数分解算法(Pollard (6,7,5))

def Pollard_p_1(N):
    a = 2
    f = a
    # precompute
    while 1:
        for n in range(1, 200000):
            f = powmod(f, n, N)
            if is_prime(n):
                d = gcd(f - 1, N)
                if 1 < d < N:
                    return d, N // d
                elif d >= N:
                    f = next_prime(a)
                    break
        else:
            break

def _GetPlain(c):
    tmp = hex(c)[2:]
    if tmp[:16] != '9876543210abcdef':
        return 0
    number = int(tmp[16:24], 16)
    plain = long_to_bytes(int(tmp[-16:], 16))
    m[number] = plain
    return 1

def GetPlain(p, q, e, c):
    phi = (p - 1) * (q - 1)
    d = invert(e, phi)
    m = powmod(c, d, p * q)
    return _GetPlain(m)

def detect6_7_5():
    for i in range(21):
        if i not in solved:
            tmp = Pollard_p_1(n[i])
            if isinstance(tmp, tuple):
                p, q = tmp
                if GetPlain(p, q, e[i], c[i]):
                    solved.append(i)

低加密指数攻击(3,8,12,16,20)

在 RSA 中 e 也称为加密指数。由于 e 是可以随意选取的,选取小一点的 e 可以缩短加密时间(比如 3),但是选取不当的话,就会造成安全问题

当 e=3 时,如果明文过小,导致明文的三次方仍然小于 n,那么通过直接对密文三次开方,即可得到明文。

def CRT(mi, ai):
    M = reduce(lambda x, y: x * y, mi)
    ai_ti_Mi = [a * (M // m) * invert(M // m, m) for (m, a) in zip(mi, ai)]
    return reduce(lambda x, y: x + y, ai_ti_Mi) % M

def small_e_boardcast_attack(nlist, e, clist):
    m = CRT(nlist, clist)
    tmp = iroot(m, e)
    if tmp[1] == 1:
        return tmp[0]
    else:
        return 0

def _GetPlain(c):
    tmp = hex(c)[2:]
    if tmp[:16] != '9876543210abcdef':
        return 0
    number = int(tmp[16:24], 16)
    plain = long_to_bytes(int(tmp[-16:], 16))
    m[number] = plain
    return 1

def detect3_8_12_16_20():
    e = 5
    num = [3, 8, 12, 16, 20]
    nlist = [n[i] for i in num]
    clist = [c[i] for i in num]
    m = small_e_boardcast_attack(nlist, e, clist)
    if _GetPlain(m):
        for i in num:
            solved.append(i)

共模攻击(0,4)

如果在 RSA 的使用中使用了相同的模 n 对相同的明文 m 进行了加密,那么就可以在不分解 n 的情况下还原出明文 m 的值。

帧0,4使用了相同的模n

#欧几里得算法
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 _GetPlain(c):
    tmp = hex(c)[2:]
    if tmp[:16] != '9876543210abcdef':
        return 0
    number = int(tmp[16:24], 16)
    plain = long_to_bytes(int(tmp[-16:], 16))
    m[number] = plain
    return 1

#共模攻击(0,4)
def same_module_attack(N, e1, e2, c1, c2):
    d1 = invert(e1, e2)
    d2 = (d1 * e1 - 1) // e2
    true_c2 = invert(c2, N)
    return (powmod(c1, d1, N) * powmod(true_c2, d2, N)) % N

def detect0_4():
    for i in range(21):
        for j in range(21):
            if i != j and n[i] == n[j] and e[i] != e[j]:
                _GetPlain(same_module_attack(n[i], e[i], e[j], c[i], c[j]))

参考链接

https://blog.csdn.net/weixin_44145452/article/details/109924843
https://www.cnblogs.com/jcchan/p/8426731.html
https://www.tr0y.wang/2017/10/31/RSA2016/#%E8%A7%A3%E9%A2%98%E8%BF%87%E7%A8%8B
https://blog.csdn.net/weixin_45859850/article/details/109785669

举报

相关推荐

0 条评论