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+t∗kc3=me2modn3==>c3=(m2−t∗k)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=(m2−t∗k)e2−c3 ,解出 t = 0 t=0 t=0,即 m 2 = m m_2=m m2=m。
m 1 , m 2 m_1,m_2 m1,m2解出来的有重叠部分,需去除。
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}
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()
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[i−1])是一组明密文。
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,m2∗m4是一组。
① 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=d∗m1+m4a1=r1d∗r4%n2b1=r5∗r3d%n2a2=r2e∗b1−1%n2b2=c3d∗c5%n2r=r1d∗r4%n2(在①中)r=r2e∗b1−1%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\\ c1d∗c4≡gd∗m1+m4∗rnmodn2==>c1d∗c4≡gd∗m1∗gm4∗r1d∗n∗r4nmodn2==>c1d≡gd∗m1∗r1d∗nmodn2==>c1≡gm1∗r1nmodn2
因为不可能从这里返回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\\ c2e∗b2−1≡rnmodn2==>c2e∗b2−1=r2e∗n∗b1−nmodn2==>c2e∗b1n=r2e∗n∗b2modn2==>c2e∗∗r5n∗r3d∗n=r2e∗n∗c3d∗c5modn2==>c2e∗(gm2∗m4∗r5n)∗r3d∗n=r2e∗n∗c3d∗c5∗gm2∗m4modn2==>c2e∗r3d∗n=r2e∗n∗c3d∗gm2∗m4modn2==>ge∗m2∗(c2e)∗(gm3∗d∗r3d∗n)=(ge∗m2∗r2e∗n)∗(c3d)∗gm3∗d∗gm2∗m4modn2==>ge∗m2∗(c2e)∗(gm3∗r3n)d=(gm2∗r2n)e∗(c3d)∗gm3∗d+m2∗m4modn2
因为是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) ge∗m2=gm3∗d+m2∗m4modn2==>e∗m2=m3∗d+m2∗m4modφ(n2)==>m1∗m2=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对应的下标)\\ m1∗m2=m3modφ(n2)==>gm1∗m2=gm3modn2==>c3=gm1∗m2∗r3nmodn2==>csi=gm0∗mi−1∗rinmodn2,i∈[1,t−1](转换成跟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=gm0∗r0nmodn2
然后根据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=m0∗m0=k2i=2时,有m2=m0∗m1=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,t−1]。故求 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,t−1]
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)
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 X、Y的生成以及shuffle混淆,先看 X 、 Y X、Y X、Y的生成,他们的生成公式类似,为
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)cr0∗E(i1,r1)cr1∗...∗E(i5,r5)cr5modni2ysi=E(i0,r0)s0∗E(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)=k∗mmodn
于是公式(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)=cr0∗i0+...+cr5∗i5modniD(ysi)=s0∗i0+...+s5∗i5modni(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=gsi∗hcri
进行如下转换
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=gs0∗hcr0,c1i=gs1∗i∗hcr1∗i,c2i2=gs2∗i2∗hcr2∗i2,...
于是有
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 c0∗c1i∗c2i2∗...∗c5i5=gs0+s1∗i+s2∗i2+...+s5∗i5∗hcr0+cr1∗i+cr2∗i2+...+cr5∗i5=gD(ysi)∗hD(xsi)modq
因此通过此等式可得到正确的 X , Y X,Y X,Y。
求出 Y Y Y后,因为有六个未知数和六个方程,所以建个矩阵求解