密码学实战 - HTB Embryonic Plant

1,924 阅读8分钟

概述

Embryonic Plant是来自于HTB(hackthebox.com)的一个容易级密码学挑战,完成该挑战所需要掌握的知识点在于模计算和AES加解密。

题目分析

相关的任务文件包括一个script.py源代码和output.txt文本文件。

script.py内容如下

from Crypto.Util.number import getPrime, long_to_bytes, inverse
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from hashlib import sha256
from secret import FLAG

class RNG:

    def __init__(self, seed):
        self.e = 0x10001
        self.s = seed

        self.r = getPrime(768)
        while True:
            self.p, self.q = getPrime(768), getPrime(768)
            if self.p < self.r and self.q < self.r:
                break

        self.n = self.p * self.q * self.r
        phi = (self.p - 1) * (self.q - 1) * (self.r - 1)
        self.d = inverse(self.e, phi)

    def next(self):
        self.s = (self.s * self.p + self.q) % self.r
        return self.s


def main():
    rng = RNG(getPrime(512))
    rns = [rng.next() for _ in range(5)]

    key = sha256(long_to_bytes(rng.d)).digest()
    cipher = AES.new(key, AES.MODE_ECB)
    enc_flag = cipher.encrypt(pad(FLAG, 16)).hex()

    with open('output.txt', 'w') as f:
        f.write(f'n = {rng.n}\n')
        f.write(f's = {rns}\n')
        f.write(f'enc_flag = {enc_flag}\n')

if __name__ == "__main__":
    main()

从中我们可以得知该加密算法首先随机生成rpq三个素数,并分别计算n以及包含5个元素的s数组。 然后使用sha256生成d`的哈希字串以作为AES的密钥对flag进行加密。

output.txt则给出了ns数组的各个元素以及enc_flag密文。

结合如上数据,我们可以得到如下的关系式

n = p * q * r

s[0] = (seed * p + q) % r
s[1] = (s[0] * p + q) % r
s[2] = (s[1] * p + q) % r
s[3] = (s[2] * p + q) % r
s[4] = (s[3] * p + q) % r

#解题过程

使用模数计算规则,可以通过如下步骤得到r

s1s0p+q(modr)s2s1p+q(modr)s3s2p+q(modr)s4s3p+q(modr)s2s1(s1s0)p(modr)s3s2(s2s1)p(modr)s4s3(s3s2)p(modr)(s2s1)(s3s2)(s1s0)(s3s2)p(modr)(s2s1)(s3s2)(s2s1)(s2s1)p(modr)0[(s1s0)(s3s2)(s2s1)(s2s1)]p(modr)(s3s2)(s4s3)(s2s1)(s4s3)p(modr)(s4s3)(s3s2)(s3s2)(s3s2)p(modr)0[(s2s1)(s4s3)(s3s2)(s3s2)]p(modr)r=gcd([(s1s0)(s3s2)(s2s1)(s2s1)],[(s2s1)(s4s3)(s3s2)(s3s2)])s_1 \equiv s_0 * p + q \pmod {r} \\ s_2 \equiv s_1 * p + q \pmod {r} \\ s_3 \equiv s_2 * p + q \pmod {r} \\ s_4 \equiv s_3 * p + q \pmod {r} \\ \\ s_2 - s_1 \equiv (s_1 - s_0) * p \pmod {r} \\ s_3 - s_2 \equiv (s_2 - s_1) * p \pmod {r} \\ s_4 - s_3 \equiv (s_3 - s_2) * p \pmod {r} \\ \\ (s_2 - s_1) * (s_3 - s_2) \equiv (s_1 - s_0) * (s_3 - s_2) * p \pmod {r} \\ (s_2 - s_1) * (s_3 - s_2) \equiv (s_2 - s_1) * (s_2 - s_1) * p \pmod {r} \\ \\ 0 \equiv [(s_1 - s_0) * (s_3 - s_2) - (s_2 - s_1) * (s_2 - s_1)]* p \pmod {r} \\ \\ (s_3 - s_2) * (s_4 - s_3) \equiv (s_2 - s_1) * (s_4 - s_3) * p \pmod {r} \\ (s_4 - s_3) * (s_3 - s_2) \equiv (s_3 - s_2) * (s_3 - s_2) * p \pmod {r} \\ \\ 0 \equiv [(s_2 - s_1) * (s_4 - s_3) - (s_3 - s_2) * (s_3 - s_2)] * p \pmod {r} \\ \\ r = gcd([(s_1 - s_0) * (s_3 - s_2) - (s_2 - s_1) * (s_2 - s_1)], [(s_2 - s_1) * (s_4 - s_3) - (s_3 - s_2) * (s_3 - s_2)])

得到r之后,就可以此得出pq, 然后得出d用于最后的解密。

n = 953212452632162415623854742466108898886257018761981737488515480124784784754313403541058723530771941185648440076953890845364164881753643355212476926626742101375422468157394494383915186197027584298810203766388023131196821200163753827759350781726289328080241887775877824351482527440834821313689834438591567613042759531267263403394331824891899899505726815540209695860955058659042180466101027165453544129867565132811217413181292156021136184504130428910065116301275284964237087553827437109939035287527986380535446925078275313404977210504275217640523278087762041948497195357622678060873426815474421439984697128135689500335385151376561597600186415289317989920506634067994928935237389715706143172780083
s = [107663563520221758967681052016945344894135463272720867342404293429418113761640130338846143415694339846703472327422471509923932434685628383794998869995327761272087050985560474031629673883432008583476972873462387774454021532562638911, 375715892557297364364744701696307763009546269920835800827316473134718210911604668305115761037621526838903749589794728067744014884724708180550902913867595275270476040258585551516530116122396379615935241551413224529146764536011818960, 1142431136128743680237588635513380046580339971378804783979851430431837015880156204447030433004896454182104721893126547029880672333914367506184442229874405762062665597996081499892502200704128255903361177726702376303206644325660472696, 696181402062958907421352186902458487367420124659441418095569426735447880619442484035499857372339751543528153083380619139649590779544110176169319718082842863368788080781170847125373363885050864587076550882230251633851030744318779877, 1090087409231264760633243725379604084008037546075358826209944877794280528534452761945892984736121167182908072643369909923239008686694491992033132238021506681618226619691505113704791978765000558863195023783700460638272869374754376211]
enc_flag = "d3587442177b157fa0cecb6dd880872d86e15a50e3f05ecfeea8b90f5cfca22835a59d9c4f23e87a68317d4ccabe1bf3aa2e6cdf0a9ef1ada0a2e83d8da0bff2b739cf0e2b2b779958d9b1154a6f3698"

import gmpy2
r = gmpy2.gcd(((s[1] - s[0]) * (s[3] - s[2]) - (s[2] - s[1]) * (s[2] - s[1])), ((s[2] - s[1]) * (s[4] - s[3]) - (s[3] - s[2]) * (s[3] - s[2])))

a = s[2] - s[1]
b = s[1] - s[0]

p = a * pow(b, -1, r)
p = p % r

q = s[2] - s[1] * p
q = q % r 

e = 0x10001
phi = (p - 1) * (q - 1) * (r - 1)
d = pow(e, -1, phi)

from Crypto.Util.number import bytes_to_long, long_to_bytes 
from hashlib import sha256
from Crypto.Cipher import AES

key = sha256(long_to_bytes(d)).digest()
cipher = AES.new(key, AES.MODE_ECB)

cipher_text = bytes.fromhex(enc_flag)
flag = cipher.decrypt(cipher_text)

print("FLAG =", flag)