DASCTF十月赛

Crypto

  • RSA
  • Proof_Yourself
  • Recover_Secret

RSA

from Crypto.Util.number import *
from secret import flag

def encrypt1(n):
    n1 = hex(n>>200).encode()
    n2 = str(hex(n))[20:].encode()
    return n1,n2

def encrypt2(m , n_1):
    c_1 = pow(m,e_1,n_1)
    print('c_1 = '+str(c_1))

def encrypt3(m , n_2):
    c_2 = pow( m , e_2 , n_2)
    print('c_2 = '+str(c_2))

def encrypt4(m):
    k = getPrime(512)
    m = m % k
    c_3 = pow(m, e_2, n_3)
    print('c_3 = ' + str(c_3))
    print('m = ' + str(m))
    print('k = ' + str(k))

m1,m2 = encrypt1(flag)
m1 = bytes_to_long(m1)
m2 = bytes_to_long(m2)

print('n_2 = ' + str(n_2))
print('n_3 = ' + str(n_3))
print('e_1 = ' + str(e_1))
print('e_2 = ' + str(e_2))

encrypt2(m1,n_1)
encrypt3(n_1,n_2)
encrypt4(m2)

'''
n_2 = 675835056744450121024004008337170937331109883435712066354955474563267257037603081555653829598886559337325172694278764741403348512872239277008719548968016702852609803016353158454788807563316656327979897318887566108985783153878668451688372252234938716250621575338314779485058267785731636967957494369458211599823364746908763588582489400785865427060804408606617016267936273888743392372620816053927031794575978032607311497491069242347165424963308662091557862342478844612402720375931726316909635118113432836702120449010
n_3 = 91294511667572917673898699346231897684542006136956966126836916292947639514392684487940336406038086150289315439796780158189004157494824987037667065310517044311794725172075653186677331434123198117797575528982908532086038107428540586044471407073066169603930082133459486076777574046803264038780927350142555712567
e_1 = 65537
e_2 = 3
c_1 = 47029848959680138397125259006172340325269302342762903311733700258745280761154948381409328053449580957972265859283407071931484707002138926840483316880087281153554181290481533
c_2 = 332431
c_3 = 11951299411967534922967467740790967733301092706094553308467975774492025797106594440070380723007894861454249455013202734019215071856834943490096156048504952328784989777263664832098681831398770963056616417301705739505187754236801407014715780468333977293887519001724078504320344074325196167699818117367329779609
m = 9530454742891231590945778054072843874837824815724564463369259282490619049557772650832818763768769359762168560563265763313176741847581931364
k = 8139616873420730499092246564709331937498029453340099806219977060224838957080870950877930756958455278369862703151353509623205172658012437573652818022676431
'''

解m1要先求出n_1,n_1的加密为低指数加密,爆破可以得出n_1,yafu分解然后解密c_1。

m2部分根据代码有公式
{ m 2 = m + t ∗ k c 3 = m e 2 m o d    n 3 = = > c 3 = ( m 2 − t ∗ k ) e 2 m o d    n 3 \begin{cases} m_2 = m + t*k\\ c_3 = m^{e_2}\mod n_3 \end{cases} ==>c_3=(m_2-t*k)^{e_2}\mod n_3 {m2=m+tkc3=me2modn3==>c3=(m2tk)e2modn3
于是在模 n 3 n_3 n3的域上构造 f = ( m 2 − t ∗ k ) e 2 − c 3 f = (m_2-t*k)^{e_2} - c_3 f=(m2tk)e2c3 ,解出 t = 0 t=0 t=0,即 m 2 = m m_2=m m2=m

m 1 , m 2 m_1,m_2 m1m2解出来的有重叠部分,需去除。

from binascii import hexlify,unhexlify
from Crypto.Util.number import *
from gmpy2 import iroot,invert

#n_2是偶数
n_2 = 675835056744450121024004008337170937331109883435712066354955474563267257037603081555653829598886559337325172694278764741403348512872239277008719548968016702852609803016353158454788807563316656327979897318887566108985783153878668451688372252234938716250621575338314779485058267785731636967957494369458211599823364746908763588582489400785865427060804408606617016267936273888743392372620816053927031794575978032607311497491069242347165424963308662091557862342478844612402720375931726316909635118113432836702120449010
n_3 = 91294511667572917673898699346231897684542006136956966126836916292947639514392684487940336406038086150289315439796780158189004157494824987037667065310517044311794725172075653186677331434123198117797575528982908532086038107428540586044471407073066169603930082133459486076777574046803264038780927350142555712567
e_1 = 65537
e_2 = 3
c_1 = 47029848959680138397125259006172340325269302342762903311733700258745280761154948381409328053449580957972265859283407071931484707002138926840483316880087281153554181290481533
c_2 = 332431
c_3 = 11951299411967534922967467740790967733301092706094553308467975774492025797106594440070380723007894861454249455013202734019215071856834943490096156048504952328784989777263664832098681831398770963056616417301705739505187754236801407014715780468333977293887519001724078504320344074325196167699818117367329779609
m = 9530454742891231590945778054072843874837824815724564463369259282490619049557772650832818763768769359762168560563265763313176741847581931364
k = 8139616873420730499092246564709331937498029453340099806219977060224838957080870950877930756958455278369862703151353509623205172658012437573652818022676431

#低指数爆破
t = 0
tmp = c_2
while 1:
    if(iroot(tmp,3)[1]):
        n_1 = iroot(tmp,3)[0]
        print(f'n_1 = {n_1}')
        print(f't={t}')
        break
    tmp += n_2
    t += 1

#yafu n_1
p = 2224243981
q = 2732337821
r = 11585031296201346891716939633970482508158508580350404805965250133832632323150440185890235814142601827544669601048550999405490149435265122374459158586377571

phi = (p-1)*(q-1)*(r-1)
d = invert(e_1,phi)
m1 = pow(c_1,d,n_1)
# print(long_to_bytes(m1))
#0x666c61677b3230366538353964
mm = 0x666c61677b3230366538353964
flag1 = long_to_bytes(mm)
print(flag1)
'''sage
n_3 = 91294511667572917673898699346231897684542006136956966126836916292947639514392684487940336406038086150289315439796780158189004157494824987037667065310517044311794725172075653186677331434123198117797575528982908532086038107428540586044471407073066169603930082133459486076777574046803264038780927350142555712567
e_2 = 3
c_3 = 11951299411967534922967467740790967733301092706094553308467975774492025797106594440070380723007894861454249455013202734019215071856834943490096156048504952328784989777263664832098681831398770963056616417301705739505187754236801407014715780468333977293887519001724078504320344074325196167699818117367329779609
m = 9530454742891231590945778054072843874837824815724564463369259282490619049557772650832818763768769359762168560563265763313176741847581931364
k = 8139616873420730499092246564709331937498029453340099806219977060224838957080870950877930756958455278369862703151353509623205172658012437573652818022676431
p. = PolynomialRing(Zmod(n_3))
f= (m+x*k)^3 - c_3
print(f.monic().small_roots())
# [0]
'''
assert m**3 % n_3 == c_3
flag2 = unhexlify(long_to_bytes(m))
print(flag2)
#有重复的字符
# flag{206e859d859d8e854c4f600cb12757bbf9f5}
# DASCTF{206e859d8e854c4f600cb12757bbf9f5}

Proof_Yourself

import gmpy2 as gy
import random
import functools
from datetime import datetime
from Crypto.Cipher import AES
import base64
import os

_N = gy.next_prime(2 ** 512)
_rand_int = functools.partial(random.SystemRandom().randint, 0)

class Encryptor():
    def __init__(self):
        self.pubKey = None
        self.priKey = None
        self.r = None

    def __gen_prime__(self, rs, n_bits):
        p = gy.mpz_urandomb(rs, n_bits)
        while not gy.is_prime(p):
            p += 1
        return p

    def __key_gen__(self, n_bits=512):
        while True:
            rs = gy.random_state(datetime.now().microsecond)
            p = self.__gen_prime__(rs, n_bits)
            q = self.__gen_prime__(rs, n_bits)
            n = p * q
            lmd = (p - 1) * (q - 1)
            if gy.gcd(n, lmd) == 1:
                break

        g = n + 1
        mu = gy.invert(lmd, n)
        self.pubKey = [n, g]
        self.priKey = [lmd, mu]
        return (self.pubKey, self.priKey)

    def encipher(self, plaintext):
        m = plaintext
        n, g = self.pubKey
        if self.r is None:
            r = gy.mpz_random(gy.random_state(datetime.now().microsecond), n)
            while gy.gcd(n, r) != 1:
                r += 1
            self.r = r
        else:
            r = self.r
        ciphertext = gy.powmod(g, m, n ** 2) * gy.powmod(r, n, n ** 2) % (n ** 2)#Paillier同态加密
        return ciphertext

    def decipher(self, ciphertext):
        # The decryption process is hidden
        return 0xffffffff


class Proof():
    def __init__(self):
        self.pubKey = None
        self.proof_param = None
        self.pre_param = None
        self.d = None

    def setup(self, pk, c1, c2, c3, m1, m2, r1, r2, r3):
        self.pubKey = pk
        self.proof_param = [c1, c2, c3, m1, m2, r1, r2, r3]

    def pre_work_verify(self):
        c1, c2, c3, m1, m2, r1, r2, r3 = self.proof_param
        m4 = gy.mpz_random(gy.random_state(datetime.now().microsecond), self.pubKey[0])
        pai = Encryptor()
        pai.pubKey = self.pubKey
        c4 = pai.encipher(m4)
        r4 = pai.r
        pai.r = None #然后会重新生成r

        c5 = pai.encipher(m2 * m4)
        r5 = pai.r
        pai.r = None

        self.pre_param = [c4, m4, r4, c5, r5]
        return c4, c5

    def set_d(self, d):
        self.d = d

    def verify(self):
        n_2q = self.pubKey[0] ** 2
        c1, c2, c3, m1, m2, r1, r2, r3 = self.proof_param
        c4, m4, r4, c5, r5 = self.pre_param
        d = self.d

        e = d * m1 + m4
        a1 = pow(r1, d, n_2q) * r4 % n_2q
        b1 = r5 * pow(r3, d, n_2q) % n_2q
        a2 = pow(r2, e, n_2q) * gy.invert(b1, n_2q) % n_2q
        b2 = pow(c3, d, n_2q) * c5 % n_2q

        enc = Encryptor()
        enc.pubKey = self.pubKey
        enc.r = pow(r1, d, n_2q) * r4 % n_2q
        if pow(c1, d, n_2q) * c4 % n_2q != enc.encipher(d * m1 + m4): # 这里要 ==
            return False
        enc.r = a2
        return pow(c2, e, n_2q) * gy.invert(b2, n_2q) % n_2q == enc.encipher(0) #必须从这里返回,且为True

class MProof():
    def __init__(self):
        self.pubKey = None
        self.priKey = None
        self.cs = None
        self.rs = None
        self.k = None
        self.t = 9

    def generate_param(self, pk, cs, rs, k):
        self.pubKey = pk[0]
        self.priKey = pk[1]
        self.cs = cs
        self.rs = rs
        self.k = k

    def verify(self, d):
        enc = Encryptor()
        enc.pubKey = self.pubKey
        enc.priKey = self.priKey
        cs = self.cs
        rs = self.rs
        k = self.k
        t = self.t
        assert k == enc.decipher(cs[0])
        for i in range(1, t - 1):
            c1 = cs[0]
            c2 = cs[i - 1]
            c3 = cs[i]
            m2 = enc.decipher(cs[i - 1])
            r1 = rs[0]
            r2 = rs[i - 1]
            r3 = rs[i]

            proof = Proof()
            proof.setup(self.pubKey, c1, c2, c3, k, m2, r1, r2, r3)

            proof.pre_work_verify()
            proof.set_d(d)

            if not proof.verify(): # 这里要返回True
                return False
        return True

def main():
    flag = os.environ["flag for GFCTF2022-Crypto Proof Yourself"]
    k = _rand_int(_N - 1)
    print("k: ", k)
    d = _rand_int(_N - 1)
    print("d: ", d)
    param = eval(input("please proof yourself: "))

    cs = param['cs']
    rs = param['rs']
    pk = param['pk']

    print(pk[0])
    print(rs)
    mp = MProof()
    mp.generate_param(pk, cs, rs, k)
    if mp.verify(d):
        s = 1
        for i in cs:
            s *= i
            s %= _N
        aes = AES.new(str(s)[:32].encode(), AES.MODE_ECB)
        flag = flag.encode()
        while len(flag) % AES.block_size != 0:
            flag += b'\x00'
        c = aes.encrypt(flag)
        c = base64.b64encode(c)
        print(c)
    else:
        print("you're not yourself!")

if __name__ == '__main__':
    main()

  • MProof类中的verify()部分
k == enc.decipher(cs[0])
m2 = enc.decipher(cs[i - 1])

说明 $k(m_1) $与 c 1 ( c s [ 0 ] ) c_1(cs[0]) c1(cs[0])是一组明密文, m 2 m_2 m2 c 2 ( c s [ i − 1 ] ) c_2(cs[i-1]) c2(cs[i1])是一组明密文。

proof.pre_work_verify()

说明 c 4 , m 4 , r 4 c_4,m_4,r_4 c4,m4,r4是一组, c 5 , m 2 ∗ m 4 c_5,m_2*m_4 c5,m2m4是一组。

  • Proof类中的verify()部分
    就是一堆公式然后不断化简。
    首先我们要明确verify返回的值必须是True,也就是从最后一个return返回,所以以下两个等式成立
pow(c1, d, n_2q) * c4 % n_2q == enc.encipher(d * m1 + m4)pow(c2, e, n_2q) * gy.invert(b2, n_2q) % n_2q == enc.encipher(0)

根据代码有以下公式
{ e = d ∗ m 1 + m 4 a 1 = r 1 d ∗ r 4 % n 2 b 1 = r 5 ∗ r 3 d % n 2 a 2 = r 2 e ∗ b 1 − 1 % n 2 b 2 = c 3 d ∗ c 5 % n 2 r = r 1 d ∗ r 4 % n 2 ( 在①中 ) r = r 2 e ∗ b 1 − 1 % n 2 ( 在②中 ) \begin{cases} e = d*m_1+m_4\\ a_1 = r_1^d*r_4 \% n^2\\ b_1 = r_5*r_3^d \% n^2\\ a_2 = r_2^e*b_1^{-1} \% n^2\\ b_2 = c_3^d*c_5 \% n^2\\ r = r_1^d*r_4 \% n^2(在①中)\\ r = r_2^e*b_1^{-1} \% n^2(在②中) \end{cases} e=dm1+m4a1=r1dr4%n2b1=r5r3d%n2a2=r2eb11%n2b2=c3dc5%n2r=r1dr4%n2()r=r2eb11%n2()
对①进行化简,有
c 1 d ∗ c 4 ≡ g d ∗ m 1 + m 4 ∗ r n m o d    n 2 = = > c 1 d ∗ c 4 ≡ g d ∗ m 1 ∗ g m 4 ∗ r 1 d ∗ n ∗ r 4 n m o d    n 2 = = > c 1 d ≡ g d ∗ m 1 ∗ r 1 d ∗ n m o d    n 2 = = > c 1 ≡ g m 1 ∗ r 1 n m o d    n 2 c_1^d*c_4 ≡ g^{d*m_1+m_4}*r^n \mod n^2\\ ==>c_1^d*c_4 ≡ g^{d*m_1}*g^{m_4}*r_1^{d*n}*r_4^n \mod n^2\\ ==>c_1^d ≡ g^{d*m_1}*r_1^{d*n} \mod n^2\\ ==>c_1 ≡ g^{m_1}*r_1^n \mod n^2\\ c1dc4gdm1+m4rnmodn2==>c1dc4gdm1gm4r1dnr4nmodn2==>c1dgdm1r1dnmodn2==>c1gm1r1nmodn2
因为不可能从这里返回False,所以 c 1 , m 1 , r 1 c_1,m_1,r_1 c1,m1,r1是一组。

对②进行化简,有
c 2 e ∗ b 2 − 1 ≡ r n m o d    n 2 = = > c 2 e ∗ b 2 − 1 = r 2 e ∗ n ∗ b 1 − n m o d    n 2 = = > c 2 e ∗ b 1 n = r 2 e ∗ n ∗ b 2 m o d    n 2 = = > c 2 e ∗ ∗ r 5 n ∗ r 3 d ∗ n = r 2 e ∗ n ∗ c 3 d ∗ c 5 m o d    n 2 = = > c 2 e ∗ ( g m 2 ∗ m 4 ∗ r 5 n ) ∗ r 3 d ∗ n = r 2 e ∗ n ∗ c 3 d ∗ c 5 ∗ g m 2 ∗ m 4 m o d    n 2 = = > c 2 e ∗ r 3 d ∗ n = r 2 e ∗ n ∗ c 3 d ∗ g m 2 ∗ m 4 m o d    n 2 = = > g e ∗ m 2 ∗ ( c 2 e ) ∗ ( g m 3 ∗ d ∗ r 3 d ∗ n ) = ( g e ∗ m 2 ∗ r 2 e ∗ n ) ∗ ( c 3 d ) ∗ g m 3 ∗ d ∗ g m 2 ∗ m 4 m o d    n 2 = = > g e ∗ m 2 ∗ ( c 2 e ) ∗ ( g m 3 ∗ r 3 n ) d = ( g m 2 ∗ r 2 n ) e ∗ ( c 3 d ) ∗ g m 3 ∗ d + m 2 ∗ m 4 m o d    n 2 c_2^e*b_2^{-1}≡r^n \mod n^2\\ ==>c_2^e*b_2^{-1} = r_2^{e*n}*b_1^{-n} \mod n^2\\ ==>c_2^{e}*b_1^n=r_2^{e*n}*b_2 \mod n^2\\ ==>c_2^{e}**r_5^n*r_3^{d*n}=r_2^{e*n}*c_3^d*c_5 \mod n^2\\ ==>c_2^e*(g^{m_2*m_4}*r_5^n)*r_3^{d*n} = r_2^{e*n}*c_3^d*c_5*g^{m_2*m_4} \mod n^2\\ ==>c_2^e*r_3^{d*n} = r_2^{e*n}*c_3^d*g^{m_2*m_4} \mod n^2\\ ==>g^{e*m_2}*(c_2^e)*(g^{m_3*d}*r_3^{d*n})=(g^{e*m_2}*r_2^{e*n})*(c_3^d)*g^{m_3*d}*g^{m_2*m_4} \mod n^2\\ ==>g^{e*m_2}*(c_2^e)*(g^{m_3}*r_3^n)^d=(g^{m_2}*r_2^n)^e*(c_3^d)*g^{m_3*d+m_2*m_4}\mod n^2\\ c2eb21rnmodn2==>c2eb21=r2enb1nmodn2==>c2eb1n=r2enb2modn2==>c2er5nr3dn=r2enc3dc5modn2==>c2e(gm2m4r5n)r3dn=r2enc3dc5gm2m4modn2==>c2er3dn=r2enc3dgm2m4modn2==>gem2(c2e)(gm3dr3dn)=(gem2r2en)(c3d)gm3dgm2m4modn2==>gem2(c2e)(gm3r3n)d=(gm2r2n)e(c3d)gm3d+m2m4modn2
因为是Paillier同态加密,要使得②成立,极有可能是 m 2 , c 2 , r 2 m_2,c_2,r_2 m2,c2,r2 m 3 , c 3 , r 3 m_3,c_3,r_3 m3,c3,r3分别为一组。故
g e ∗ m 2 = g m 3 ∗ d + m 2 ∗ m 4 m o d    n 2 = = > e ∗ m 2 = m 3 ∗ d + m 2 ∗ m 4 m o d    φ ( n 2 ) = = > m 1 ∗ m 2 = m 3 m o d    φ ( n 2 ) g^{e*m_2}=g^{m_3*d+m_2*m_4}\mod n^2\\ ==>e*m_2 = m_3*d+m_2*m_4\mod φ(n^2)\\ ==>m_1*m_2=m_3\mod φ(n^2) gem2=gm3d+m2m4modn2==>em2=m3d+m2m4modφ(n2)==>m1m2=m3modφ(n2)
因为我们要求 c i ( 即 c s [ i ] ) c_i(即cs[i]) ci(cs[i]),所以将上述等式转换为
m 1 ∗ m 2 = m 3 m o d    φ ( n 2 ) = = > g m 1 ∗ m 2 = g m 3 m o d    n 2 = = > c 3 = g m 1 ∗ m 2 ∗ r 3 n m o d    n 2 = = > c s i = g m 0 ∗ m i − 1 ∗ r i n m o d    n 2 , i ∈ [ 1 , t − 1 ] ( 转换成跟 c s i 对应的下标 ) m_1*m_2=m_3\mod φ(n^2)\\ ==>g^{m_1*m_2} = g^{m_3} \mod n^2\\ ==>c_3 = g^{m_1*m_2}*r_3^n \mod n^2\\ ==>cs_i = g^{m_0*m_{i-1}}*r_i^n \mod n^2 \quad,i∈[1,t-1](转换成跟cs_i对应的下标)\\ m1m2=m3modφ(n2)==>gm1m2=gm3modn2==>c3=gm1m2r3nmodn2==>csi=gm0mi1rinmodn2,i[1,t1](转换成跟csi对应的下标)
前面的等式①的推导已经得到了 c s 0 cs_0 cs0的加密公式为
c s 0 = g m 0 ∗ r 0 n m o d    n 2 cs_0 = g^{m_0}*r_0^n\mod n^2 cs0=gm0r0nmodn2
然后根据MProof.verify()中的for循环,有
i = 1 时 , 有 m 1 = m 0 ∗ m 0 = k 2 i = 2 时 , 有 m 2 = m 0 ∗ m 1 = k 3 . . . i=1时,有m_1=m_0*m_0=k^2\\ i=2时,有m_2=m_0*m_1=k^3\\... i=1,m1=m0m0=k2i=2,m2=m0m1=k3...
m 0 = k m_0 = k m0=k,故 m i = k ( i + 1 ) , i ∈ [ 0 , t − 1 ] m_i = k^{(i+1)},i∈[0,t-1] mi=k(i+1)i[0,t1]。故求 c s i cs_i csi c s 0 cs_0 cs0的公式可合并为
c s i = g k ( i + 1 ) ∗ r i n m o d    n 2 , i ∈ [ 0 , t − 1 ] cs_i = g^{k^{(i+1)}}*r_i^n \mod n^2 \quad,i∈[0,t-1] csi=gk(i+1)rinmodn2,i[0,t1]

import base64
from Crypto.Cipher import AES
import gmpy2

t = 9
k = 11279504534075664648994853756208309836888259081316987836068134565254532996039360827546417609514423428910384542842117375028420780633866653159695275393368525
d = 10221665185656075870670995630062725196664430105025904882602057721789662854574978018794504264934209067929011475979200882531626936657436063908347321906634698
n, g = pk = [48818225666351727287207574448645102762537417687444983843100304919285725062598967011116889972414214836241381602471131430626879759533369143920487299838261148460925610689261484965443528954172944323770181595455493018560585886136460076911284321702606299935385905187490733877700172236929823996030434548431963845417, 48818225666351727287207574448645102762537417687444983843100304919285725062598967011116889972414214836241381602471131430626879759533369143920487299838261148460925610689261484965443528954172944323770181595455493018560585886136460076911284321702606299935385905187490733877700172236929823996030434548431963845418]
rs = [7017835444643249654271082822123622319668823350427792339866057586668389112104752762656197513200543360993520983724957230042201508973227162755834455588213955577427129770220944523362675094151087610149577572745132843096125306714661937578722687485657829513505193501779196974947234280267216675125252078851200384511, 11926419785881734844311665235521692826579887231998046623960612782040667947241499738956574205257924912658501445776452678070116549164041547529876699253294424780763676555577471679864402445858336882095147665188840642566915806261768356998922735189200720213585973193760859762565499482788728104626011895319246070666, 42849056994192303821377400100288133996583852078950720125488290595760149056455393645072193770289570081775019724341661792638180771853532605128714550478335577195726229688940314874397525687446284173037582151644404387768530054222357908795147990398041926171515316417608763369700129500666902309717940977358807727525, 569456034348887900543839220414996643340590767934767190156995758515165897120739581783360541347732807472270912131379832279120488198273011491688831841399829273608264595546111772893429063435258947915507670361144515456182164834954215193382047579447153761545329658264080907041640135001986168270265476743567482692, 3882702856238247498776796661311784006527802920550510293689922477675526354665322642479849874736259591551374176143098918760791897417239069537473431992448934909453262242143947844529634470612342500819944459175262578570970986439077317400529787443727039336276584314877540411569781766947088676007567558786204756622, 34782235652997768305926510863494232383450368915240504241174297907018847182768375070693257841105403770877838315164696945795337955510221866283665914601590428884905858716454103802020812133141150426745257298797890891272342044576267512614330845263269719988690131903885166576787904418689220619969803389055644879283, 41592967491176047854989428284345162501007190601227408901070248204262133730525966700579489348638677097892234799114781714483501047161590906530561145043956218048476973681993844049727301616425300184917461748554561251157129032137452031152035104390819324726028213814331358281835310137578997975640720667608761964678, 2578609445428238934369429276761562264275224240462388961086309951471476260768389780485799474959219453117497280460546287104687546269870223859389440049894002336889078632572487931627548008400365190508858547984095575105551066221392543458691134989381950316158817283668533035090342510306180189918351739923749743570]
#len(rs) = 8
_N = gmpy2.next_prime(2 ** 512)
c = b'Oq5bkAPCCT6W3CskX+2uqtY5wrhs+2DqupzjIJ0u/Yl0m/Ig1/uvrSWdezrqLxHG'

cs = [0 for _ in range(len(rs))]
n_2 = n**2
# cs[0] = pow(g, k, n_2)*pow(rs[0], n, n_2) % n_2
m_list = [k**(i+1) for i in range(len(rs))]
for i in range(len(rs)):
    cs[i] = pow(g, m_list[i], n_2)*pow(rs[i], n, n_2) % n_2

s = 1
for i in cs:
    s *= i
    s %= _N
aes = AES.new(str(s)[:32].encode(), AES.MODE_ECB)
c = base64.b64decode(c)
flag = aes.decrypt(c)
print(flag)

Recover_Secret

import gmpy2 as gy
import random
import functools
import libnum
from Crypto.Util import number
from datetime import datetime
import os
import sys

of = open('output','w')
sys.stdout = of
_N = gy.next_prime(2 ** 512)
_rand_int = functools.partial(random.SystemRandom().randint, 0)

class Encryptor():
    def __init__(self):
        self.pubKey = None
        self.priKey = None

    def __gen_prime__(self, rs, n_bits):
        p = gy.mpz_urandomb(rs, n_bits)
        while not gy.is_prime(p):
            p += 1
        return p

    def __key_gen__(self, n_bits=512):
        while True:
            rs = gy.random_state(datetime.now().microsecond)
            p = self.__gen_prime__(rs, n_bits)
            q = self.__gen_prime__(rs, n_bits)
            n = p * q
            lmd = (p - 1) * (q - 1)
            if gy.gcd(n, lmd) == 1:
                break

        g = n + 1
        mu = gy.invert(lmd, n)
        self.pubKey = [n, g]
        self.priKey = [lmd, mu]
        return (self.pubKey, self.priKey)

    def encipher(self, plaintext):
        m = plaintext
        n, g = self.pubKey
        r = gy.mpz_random(gy.random_state(datetime.now().microsecond), n)
        while gy.gcd(n, r) != 1:
            r += 1
        ciphertext = gy.powmod(g, m, n ** 2) * gy.powmod(r, n, n ** 2) % (n ** 2) #Paillier同态加密
        return ciphertext

class Commit:
    def __init__(self):
        self.param = None

    def __key_gen__(self, n): # 参数n相同,则产生的q,g,h相同
        p = n
        r = 1
        while True:
            q = r * p + 1
            if gy.is_prime(q):
                break
            r += 1
        x = q - 1
        while True:
            g = x ** r % q
            if g != 1:
                break
            x -= 1
        while True:
            h = x ** r % q
            if(g != h and h != 1):
                break
            x -= 1
        self.param = q, g, h

    def commit(self, m):
        q, g, h = self.param
        r = number.getRandomRange(1, q - 1)
        c = (pow(g, m, q) * pow(h, r, q)) % q #Benaloh加密
        return c, r

def shuffle(X, Y, x):
    res = []
    for i in range(len(X)):
        res.append([i, X[i], Y[i]])
        for j in range(x):
            res.append([i, X[i] + random.randint(-X[i], X[i]), Y[i] + random.randint(-Y[i], Y[i])])
    random.shuffle(res) #随机排序
    return res

def main():
    k = 6
    sk = []
    flag = os.environ["flag for GFCTF2022-Crypto Recover Secret"]
    secret = libnum.s2n(flag)
    assert len(bin(secret)) < 514
    enc = Encryptor()
    sk = [enc.__key_gen__() for i in range(k)]
    print(sk)

    s = [_rand_int(_N - 1) for i in range(k)]
    s[0] = secret

    v = Commit()
    v.__key_gen__(_N)
    print(v.param)
    cr = [v.commit(s[i]) for i in range(k)]
    c = [i[0] for i in cr]
    print(c)

    X = []
    Y = []
    for i in range(1, k + 1):
        xs = 1
        enc.pubKey = sk[i - 1][0]  # [n_i,g_i]
        n_2q = enc.pubKey[0] ** 2  # n_i^2
        for j in range(k):
            xs *= pow(enc.encipher(i ** j), cr[j][1], n_2q)
        X.append(xs)

        ys = 1
        for j in range(k):
            ys *= pow(enc.encipher(i ** j), s[j], n_2q)
        Y.append(ys)

    X_Y = shuffle(X, Y, 51)
    print(X_Y)

if __name__ == '__main__':
    main()

类Encryptor是Paillier同态加密,类Commit貌似是Benaloh加密。
重点在 X 、 Y X、Y XY的生成以及shuffle混淆,先看 X 、 Y X、Y XY的生成,他们的生成公式类似,为
x s i = E ( i 0 , r 0 ) c r 0 ∗ E ( i 1 , r 1 ) c r 1 ∗ . . . ∗ E ( i 5 , r 5 ) c r 5 m o d    n i 2 y s i = E ( i 0 , r 0 ) s 0 ∗ E ( i 1 , r 1 ) s 1 ∗ . . . ∗ E ( i 5 , r 5 ) s 5 m o d    n i 2 (1) xs_i = E(i^0,r_0)^{cr_0}*E(i^1,r_1)^{cr_1}*...*E(i^5,r_5)^{cr_5}\mod n_i^2 \tag{1}\\ ys_i = E(i^0,r_0)^{s_0}*E(i^1,r_1)^{s_1}*...*E(i^5,r_5)^{s_5}\mod n_i^2 xsi=E(i0,r0)cr0E(i1,r1)cr1...E(i5,r5)cr5modni2ysi=E(i0,r0)s0E(i1,r1)s1...E(i5,r5)s5modni2(1)
(这里的 c r i cr_i cri c r cr cr中的 r i r_i ri。)
根据Paillier同态加密的特点,有
D ( E ( m 1 , r 1 ) , E ( m 2 , r 2 ) m o d    n 2 ) = m 1 + m 2 m o d    n D ( E ( m 1 , r 1 ) k m o d    n 2 ) = k ∗ m m o d    n D(E(m_1,r_1),E(m_2,r_2)\mod n^2) = m_1+m_2\mod n\\ D(E(m_1,r_1)^k\mod n^2)=k*m\mod n D(E(m1,r1),E(m2,r2)modn2)=m1+m2modnD(E(m1,r1)kmodn2)=kmmodn
于是公式(1)的解密公式为
D ( x s i ) = c r 0 ∗ i 0 + . . . + c r 5 ∗ i 5 m o d    n i D ( y s i ) = s 0 ∗ i 0 + . . . + s 5 ∗ i 5 m o d    n i (2) D(xs_i) = cr_0*i^0+...+cr_5*i^5 \mod n_i\\ D(ys_i) = s_0*i^0+...+s_5*i^5 \mod n_i\tag{2} D(xsi)=cr0i0+...+cr5i5modniD(ysi)=s0i0+...+s5i5modni(2)
因为 x s , y s xs,ys xs,ys都有6个,而系数已知,所以可以构建矩阵方程解出 c r i , s i cr_i,s_i cri,si
但是 X , Y X,Y X,Y被打乱了顺序。
根据commit()函数,有
c i = g s i ∗ h c r i c_i = g^{s_i}*h^{cr_i} ci=gsihcri
进行如下转换
c 0 = g s 0 ∗ h c r 0 , c 1 i = g s 1 ∗ i ∗ h c r 1 ∗ i , c 2 i 2 = g s 2 ∗ i 2 ∗ h c r 2 ∗ i 2 , . . . c_0 = g^{s_0}*h^{cr_0},c_1^i = g^{s_1*i}*h^{cr_1*i},c_2^{i^2} = g^{s_2*i^2}*h^{cr_2*i^2},...\\ c0=gs0hcr0c1i=gs1ihcr1i,c2i2=gs2i2hcr2i2,...
于是有
c 0 ∗ c 1 i ∗ c 2 i 2 ∗ . . . ∗ c 5 i 5 = g s 0 + s 1 ∗ i + s 2 ∗ i 2 + . . . + s 5 ∗ i 5 ∗ h c r 0 + c r 1 ∗ i + c r 2 ∗ i 2 + . . . + c r 5 ∗ i 5 = g D ( y s i ) ∗ h D ( x s i ) m o d    q c_0*c_1^i*c_2^{i^2}*...*c_5^{i^5} = g^{s_0+s_1*i+s_2*i^2+...+s_5*i^5}*h^{cr_0+c_r1*i+cr_2*i^2+...+cr_5*i^5}=g^{D(ys_i)}*h^{D(xs_i)}\mod q c0c1ic2i2...c5i5=gs0+s1i+s2i2+...+s5i5hcr0+cr1i+cr2i2+...+cr5i5=gD(ysi)hD(xsi)modq
因此通过此等式可得到正确的 X , Y X,Y X,Y
求出 Y Y Y后,因为有六个未知数和六个方程,所以建个矩阵求解

DASCTF十月赛_第1张图片

你可能感兴趣的:(crypto,CTF,crypto)