# **ASIS 2022** ## Binned - Cryptography - 126 solves ### Description > People binned to the same public ID have no real-world connection to one another. ### Attachments - binned.py ```python=0 #!/usr/bin/env python3 from Crypto.Util.number import * from gensafeprime import * from flag import flag def keygen(nbit): p, q = [generate(nbit) for _ in range(2)] return (p, q) def encrypt(m, pubkey): return pow(pubkey + 1, m, pubkey ** 3) p, q = keygen(512) n = p * q flag = bytes_to_long(flag) enc = encrypt(flag, n) print(f'pubkey = {n}') print(f'enc = {enc}') ``` - output.txt ``` pubkey = 125004899806380680278294077957993138206121343727674199724251084023100054797391533591150992663742497532376954423241741439218367086541339504325939051995057848301514908377941815605487168789148131591458301036686411659334843972203243490288676763861925647147178902977362125434420265824374952540259396010995154324589 enc = 789849126571263315208956108629196540107771075292285804732934458641661099043398300667318883764744131397353851782194467024270666326116745519739176492710750437625345677766980300328542459318943175684941281413218985938348407537978884988013947538034827562329111515306723274989323212194585378159386585826998838542734955059450048745917640814983343040930383529332576453845724747105810109832978045135562492851617884175410194781236450629682032219153517122695586503298477875749138129517477339813480115293124316913331705913455692462482942654717828006590051944205639923326375814299624264826939725890226430388059890231323791398412019416647826367964048142887158552454494856771139750458462334678907791079639005383932256589768726730285409763583606927779418528562990619985840033479201147509241313757191997545174262930707521451438204766627975109619779824255444258160 ``` Bài này là 1 câu warm up về Toán, cụ thể như sau: \begin{align} (n+1)^{flag} \equiv enc \pmod{n^3} \end{align} Nhìn thì có vẻ giống discrete log của base $n + 1$ nhưng các bạn hãy để ý cái modulus $n^3$ và base $n + 1$. Định lý nhị thức: \begin{align} (n + 1 )^{x} = \sum_{k=0}^{x} \dfrac{x!}{k!(x-k)!}n^k \end{align} $enc$ đã bị mod đi $m^3$ tức là tất cả hệ số nhân với n mũ lớn hơn $2$ là không cần quan tâm. \begin{align} enc &\equiv (n + 1 )^{flag} \pmod{n^3} \\ &\equiv {}_{flag} C_2*n^2 + flag*n + 1 \pmod{n^3} \end{align} Vì vế phải của đẳng thức trên nhỏ hơn $n^3$ do đó ta có thể dễ dàng tìm dc flag bằng công thức sau: $$ enc \equiv flag*n + 1 \pmod{n^2} \\ => flag = \frac{enc - 1}{n} $$ > **`ASIS{8!N0miaL_3XpAn5iOn_Us4G3_1N_cRyp7o_9rApHy!}`** ## Mindseat - Cryptohraphy - 66 solves ### Description > PCryptography Mindset: Be Unpredictable, build robust and stable applications where you'll handle every situation that user can face or predict. ### Attachments - mindseat_updated.py ```python=0 #!/usr/bin/env python3 from Crypto.Util.number import * from secret import params, flag def keygen(nbit, k): # Pubkey function _p = 1 while True: p, q = [_p + (getRandomNBitInteger(nbit - k) << k) for _ in '01'] if isPrime(p) and isPrime(q): while True: s = getRandomRange(2, p * q) if pow(s, (p - 1) // 2, p) * pow(s, (q - 1) // 2, q) == (p - 1) * (q - 1): pubkey = p * q, s return pubkey def encrypt(pubkey, m): n, s = pubkey r = getRandomRange(2, n) return pow(s, m, n) * pow(r, 2 ** k, n) % n flag = flag.lstrip(b'ASIS{').rstrip(b'}') nbit, k = params PUBKEYS = [keygen(nbit, k) for _ in range(4)] flag = [bytes_to_long(flag[i*8:i*8 + 8]) for i in range(4)] ENCS = [encrypt(PUBKEYS[_], flag[_]) for _ in range(4)] print(f'PUBKEYS = {PUBKEYS}') print(f'ENCS = {ENCS}') ``` - output_updated.txt ``` PUBKEYS = [(10342840547250370454282840290754052390564265157174829726645242904324433774727630591803186632486959590968595230902808369991240437077297674551123187830095873, 5179654005441544601140101875149402241567866059199512232495766031194848985776186595289740052214499657697650832860279375151687044465018028876445070588827777), (6015512135462554031390611730578383462516861987731833360559070749140159284050335604168414434218196369921956160353365713819898567416920672209509202941444097, 2116441415129068001049624780654272734931672052541246678702416144768611225693039503554945326959705314527114860312641379671935648337975482830939466425225421), (6396980904648302374999086102690071222661654639262566535518341836426544747072554109709902085144158785649143907600058913175220229111171441332366557866622977, 1760317994074087854211747561546045780795134924237097786412713825282874589650448491771874326890983429137451463523250670379970999252639812107914977960011738), (9158217300815233129401608406766983222991414185115152402477702381950519098200234724856258589693986849049556254969769863821366592458050807400542885348638721, 6564146847894132872802575925374338252984765675686108816080170162797938388434600448954826704720292576935713424103133182090390089661059813982670332877677256)] ENCS = [4595268033054096192076432659360373235610019564489694608733743330870893803828258295069937060360520598446948290913045781945314108935153236291467160667601985, 3390637292181370684803039833768819598968576813582112632809296088618666221278429695211004046274005776653775480723833818255766663573061866194380012311184611, 5197599582013327040903216369733466147938613487439777125659892779696104407398257678982801768761973934713675657188014051286238194316997970299887749668838196, 5093835186720390391696398671365109925058893544530286148616117890366909889206952477053316867658405460457795493886317792695055944930027477761411273933822112] ``` Bài này nặng kiến thức về Toán hơn. Bài sẽ chia flag thành 4 phần, mỗi phần 8 bytes và mỗi phần mã hóa bằng 1 pubkey khác nhau. Như vậy ta chỉ cần giải được 1 phần thì 3 phần còn lại tương tự Để ý chỗ tạo `key` 1 xíu, ta thấy 2 số nguyên tố được tạo sẽ có dạng: $prime = 2^k*random + 1$, $p$ sẽ khoảng $nbit$, $random$ sẽ khoảng $nbit-k$ bit. `PUBKEYS` sẽ là 1 số $n = p * q$ và 1 số $s$ là căn nguyên thủy trên $\mathbb{Z}_{p}$. Từ `PUBKEYS` nhìn vào dạng binary của từng số ta có thể dễ dàng tìm dc $nbit=256$ và $k=134$ Plaintext $m$ sẽ bị mã hóa với 1 số $r$ được sinh ngẫu nhiên như sau: $$enc \equiv s^{m}*r^{k} \pmod{n}$$ Chưa bàn tới việc mã hóa thì việc đầu tiên cần làm là factor được $n$. Các bạn có thể hiểu đơn giản việc nhân với 1 số là thừa của 2 giống như việc bạn dịch bit của số đó sang trái vậy (ví dụ: $11_2=1011, (11*2^4)_2=10110000$). Tương tự cái n sẽ có dạng: $$ n = pq = (2^k*a+1)(2^k*b + 1) = 4^k*a*b+2^ka+2^kb+1 \\ \text{mà:} \ \ 2^ka + 2^kb < 4^k*a*b;\ \forall \ a, b > 2. $$ Do đó có thể nói t chỉ cần xét toàn bộ $2*k$ bit đầu tiên của $n$ thành $0$ thì ta sẽ có $4^k*a*b=(p-1)(q-1)=phi$. Từ $phi$ và $n$, ta có thể factor thành thừa số nguyên tố bằng định lý Vi-Ét đảo: ```python def recover_primes(n): phi = ((n - 1) >> (2*k)) << (2*k) P = n S = n - phi + 1 delta, check = iroot(S**2 - 4*P, 2) assert check x1 = (S + delta)//2 x2 = (S - delta)//2 return x1, x2 ``` Việc factor $n$ đã xong, tiếp đến là giải mã `ciphertext`, `m` cần tìm là số mũ do đó đây là 1 bài toán liên quan đến `discrete log` nhưng ta không thể tìm thẳng vì vướng thằng $r$. Đơn giản là chỉ cần làm thằng $r$ biến mất là được và việc đó lại rất dễ dàng khi $r$ đã được mũ với $2^k$. \begin{align} enc &\equiv s^mr^{2^k}\pmod{p} \\ \Leftrightarrow enc^a &\equiv (s^mr^{2^k})^a \pmod{p} \\ \Leftrightarrow enc^a &\equiv (s^a)^mr^{2^k*a} \pmod{p} \\ \Leftrightarrow enc^a &\equiv (s^a)^mr^{p-1} \pmod{p} \\ \Leftrightarrow \_enc &\equiv \_s^m \pmod{p} \\ \end{align} Lý do mình dùng mod $p$ là vì `discrete log` trên trường hữu hạn dễ tính hơn, ngoài ra *m* cũng bé (khoảng 64 bits so với 134 bits của $k$) nên chỉ cẩn tìm trên $\mathbb{Z}_p$ là đủ để recover được $m$. Tính $m$: ```python def decrypt(c, s, p, q): Fp = GF(p) a = (p - 1)//(2 ^ k) _h = Fp(c) ^ a _g = Fp(s) ^ a x = discrete_log(_h, _g) return long_to_bytes(int(x)) ``` Vì ta đã lũy thừa $s$ thêm $a$ lần trước do đó việc tính dlog trên sub-group $2^k$ được coi là trong thời gian đa thức (Thuật toán các bạn có thể tra trên mạng). Tìm **`FLAG`**: ```python flag = b"ASCIS{" for enc, pubkey in zip(ENCS, PUBKEYS): n, s = pubkey p, q = recover_primes(n) flag += decrypt(enc, s, p, q) flag += b"}" print(flag.decode('utf-8')) ``` > **`ASCIS{N3w_CTF_nEW_Joye_Libert_CrYpt0_5}`**