from collections import namedtuple PublicKey = namedtuple('PublicKey', ['n', 'b']) SecretKey = namedtuple('SecretKey', ['p', 'q', 'A']) defgen_key(): p = random_prime(2^512, lbound=2^511) q = random_prime(2^512, lbound=2^511) n = p * q a11, a12, a21 = [random_prime(2^100) for _ inrange(3)] a22 = random_prime(2^100) while a11 * a22 == a12 * a21: a22 = random_prime(2^100) A = Matrix(ZZ, [[a11, a12], [a21, a22]]) a1 = crt([a11, a21], [p, q]) a2 = crt([a12, a22], [p, q]) b = a1 * inverse_mod(a2, n) % n PK = PublicKey(n, b) SK = SecretKey(p, q, A) return (PK, SK) defencrypt(m, pk): assert0 < m < 2^400 r = randint(0, 2^400-1) c = (pk.b*m + r) % pk.n return c defdecrypt(c, sk): a2 = crt([sk.A[0,1], sk.A[1,1]], [sk.p, sk.q]) s1 = a2 * c % sk.p s2 = a2 * c % sk.q m, r = sk.A.solve_right(vector([s1, s2])) return m deftest(pk, sk, num=3): for _ inrange(num): m = randint(0, 2^400-1) c = encrypt(m, pk) mm = decrypt(c, sk) assert m == mm if __name__ == '__main__': from hashlib import sha256 from secret import m, FLAG assert FLAG == 'd3ctf{%s}' % sha256(int(m).to_bytes(50, 'big')).hexdigest() PK, SK = gen_key() test(PK, SK) c = encrypt(m, PK) print(f"PK = {PK}") print(f"c = {c}") """ PK = PublicKey(n=69804507328197961654128697510310109608046244030437362639637009184945533884294737870524186521509776189989451383438084507903660182212556466321058025788319193059894825570785105388123718921480698851551024108844782091117408753782599961943040695892323702361910107399806150571836786642746371968124465646209366215361, b=65473938578022920848984901484624361251869406821863616908777213906525858437236185832214198627510663632409869363143982594947164139220013904654196960829350642413348771918422220404777505345053202159200378935309593802916875681436442734667249049535670986673774487031873808527230023029662915806344014429627710399196) c = 64666354938466194052720591810783769030566504653409465121173331362654665231573809234913985758725048071311571549777481776826624728742086174609897160897118750243192791021577348181130302572185911750797457793921069473730039225991755755340927506766395262125949939309337338656431876690470938261261164556850871338570 """
出现的参数
: 明文,
: 密文, 其中
四个都是100-Bit
: 512-Bit prime
分析
由可以得到
移项有
考虑到都是未知的, 而且都是400位以下, 尝试构造格子将规约出来
这里的式子左边有三个项, 所以构造一个3维的格子
因为是三维的格子, 所以最短向量的大小大概是
而, 所以需要将格子的放大一点 那么会有 即,存在一个格点, 用LLL规约即可
1 2 3 4 5 6 7 8 9 10 11
n = 69804507328197961654128697510310109608046244030437362639637009184945533884294737870524186521509776189989451383438084507903660182212556466321058025788319193059894825570785105388123718921480698851551024108844782091117408753782599961943040695892323702361910107399806150571836786642746371968124465646209366215361 b = 65473938578022920848984901484624361251869406821863616908777213906525858437236185832214198627510663632409869363143982594947164139220013904654196960829350642413348771918422220404777505345053202159200378935309593802916875681436442734667249049535670986673774487031873808527230023029662915806344014429627710399196 c = 64666354938466194052720591810783769030566504653409465121173331362654665231573809234913985758725048071311571549777481776826624728742086174609897160897118750243192791021577348181130302572185911750797457793921069473730039225991755755340927506766395262125949939309337338656431876690470938261261164556850871338570
from random import randint from secret import FLAG
# A gift for key recovery in challenge [babyLattice] n = 69804507328197961654128697510310109608046244030437362639637009184945533884294737870524186521509776189989451383438084507903660182212556466321058025788319193059894825570785105388123718921480698851551024108844782091117408753782599961943040695892323702361910107399806150571836786642746371968124465646209366215361 y = 12064801545723347322936991186738560311049061235541031580807549422258814170771738262264930441670708308259694588963224372530498305648578520552038029773849342206125074212912788823834152785756697757209804475031974445963691941515756901268376267360542656449669715367587909233618109269372332127072063171947435639328 e = 1928983487
M = int.from_bytes(FLAG, 'big') C = [] while M != 0: m = M % e M //= e r = randint(0, n-1) c = power_mod(y, m, n) * power_mod(r, e, n) C.append(c % n)
from random import randint n=69804507328197961654128697510310109608046244030437362639637009184945533884294737870524186521509776189989451383438084507903660182212556466321058025788319193059894825570785105388123718921480698851551024108844782091117408753782599961943040695892323702361910107399806150571836786642746371968124465646209366215361 y = 12064801545723347322936991186738560311049061235541031580807549422258814170771738262264930441670708308259694588963224372530498305648578520552038029773849342206125074212912788823834152785756697757209804475031974445963691941515756901268376267360542656449669715367587909233618109269372332127072063171947435639328 e = 1928983487 C = [...]
a11 = 207806651167586080788016046729 a12 = 1151291153120610849180830073509 p = gcd(b * a12 - a11,n) q = n // p phi = (p-1) * (q-1) M = []
assert gcd(e,phi) == e d = phi // e assertpow(pow(randint(0,n-1),e,n),d,n) == 1
bounds = ( 1,e ) F = IntegerModRing(n) for i in C: cd = pow(i,d,n) yd = pow(y,d,n) M.append(bsgs(F(yd),F(cd),bounds))
flag = 0 for i in M[::-1]: flag = int(flag) * int(e) + int(i)
from Crypto.Util.number import long_to_bytes print(long_to_bytes(flag))
p = 7669036313101194621345265255994200133006921565596653797956940811601516306410232120057637504305295677357422367597831138570269733177579895994340511712373309 q = 9102122415165681824420871673621781250311822805618731863628192549895693024247220594372897360668046264863189831887100676431439200352775676467952192600956629 n = 69804507328197961654128697510310109608046244030437362639637009184945533884294737870524186521509776189989451383438084507903660182212556466321058025788319193059894825570785105388123718921480698851551024108844782091117408753782599961943040695892323702361910107399806150571836786642746371968124465646209366215361 y = 12064801545723347322936991186738560311049061235541031580807549422258814170771738262264930441670708308259694588963224372530498305648578520552038029773849342206125074212912788823834152785756697757209804475031974445963691941515756901268376267360542656449669715367587909233618109269372332127072063171947435639328 e = 1928983487 e1 = 36493 e2 = 52859
defGCRT(mi, ai): assert (isinstance(mi, list) andisinstance(ai, list)) curm, cura = mi[0], ai[0] for (m, a) inzip(mi[1:], ai[1:]): d = gmpy2.gcd(curm, m) c = a - cura assert (c % d == 0) K = c // d * gmpy2.invert(curm // d, m // d) cura += curm * K curm = curm * m // d cura %= curm return (cura % curm, curm)
defcheck(d,p,n): if((p - 1) % n == 0): returnpow(d,(p - 1) // n,p) == 1 else: k = gmpy2.gcd(n, p - 1) returnpow(d,(p - 1) // k,p) == 1
defgetM(c,e,p): for i inrange(2,e): tmpc = (c * gmpy2.invert(pow(y,i,p),p)) % p if check(tmpc,p,e): return i exit(0)
C = [...] m = 0 for c in C[::-1]: cp = c % p cq = c % q m1 = getM(cp,e1,p) m2 = getM(cq,e2,q) mm,lcm = GCRT([e1,e2],[m1,m2]) print("Get mm: " + hex(mm)) m *= e m += mm