# Writeup for Crypto Problems in hgame 2020

## Week1

### InfantRSA 50pt

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  # -*- coding: utf-8 -*- # 真*签到题 # p = 681782737450022065655472455411; # q = 675274897132088253519831953441; # e = 13; # c = pow(m,e,p*q) = 275698465082361070145173688411496311542172902608559859019841 from Crypto.Util.number import * p = 681782737450022065655472455411 q = 675274897132088253519831953441 e = 13 c = 275698465082361070145173688411496311542172902608559859019841 print(long_to_bytes(pow(c, inverse(e, (p-1)*(q-1)), p*q))) # b'hgame{t3Xt6O0k_R5A!!!}' 

### Affine 75pt

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  #!/usr/bin/env python3 # -*- coding: utf-8 -*- import gmpy2 from secret import A, B, flag assert flag.startswith('hgame{') and flag.endswith('}') TABLE = 'zxcvbnmasdfghjklqwertyuiop1234567890QWERTYUIOPASDFGHJKLZXCVBNM' MOD = len(TABLE) cipher = '' for b in flag: i = TABLE.find(b) if i == -1: cipher += b else: ii = (A*i + B) % MOD cipher += TABLE[ii] print(cipher) # A8I5z{xr1A_J7ha_vG_TpH410} 

exp.py

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29  from Crypto.Util.number import * TABLE = 'zxcvbnmasdfghjklqwertyuiop1234567890QWERTYUIOPASDFGHJKLZXCVBNM' m = len(TABLE) cton = lambda x: TABLE.index(x) ntoc = lambda x: TABLE[x] # cipher: A8I5z{xr1A_J7ha_vG_TpH410} # message: hgame{???????????????????} # y1 = A*x1 + B (mod m) # y2 = A*x2 + B (mod m) x1, x2 = cton('h'), cton('g') y1, y2 = cton('A'), cton('8') # A = (y1-y2) * (x1-x2)^-1 # B = y1 - A*x1 A = (y1-y2) * inverse(x1-x2, m) B = (y1 - A*x1) % m print(A, B) # 13 14 for c in 'A8I5z{xr1A_J7ha_vG_TpH410}': if c in TABLE: y = cton(c) # x = (y-B) * A^-1 x = ntoc(((y-B) * inverse(A, m)) % m) else: x = c print(x, end='') # hgame{M4th_u5Ed_iN_cRYpt0} 

### not_One-time 150pt

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19  #!/usr/bin/env python3 # -*- coding: utf-8 -*- import os, random import string, binascii, base64 from secret import flag assert flag.startswith(b'hgame{') and flag.endswith(b'}') flag_len = len(flag) def xor(s1, s2): #assert len(s1)==len(s2) return bytes( map( (lambda x: x[0]^x[1]), zip(s1, s2) ) ) random.seed( os.urandom(8) ) keystream = ''.join( [ random.choice(string.ascii_letters+string.digits) for _ in range(flag_len) ] ) keystream = keystream.encode() print( base64.b64encode(xor(flag, keystream)).decode() ) 

Flag重用可还行。

• 可以获取任意数量密文

• key space仅26*2+10=62

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42  import string import base64 from pwn import * def XOR(s1, s2): #assert len(s1)==len(s2) return bytes(map((lambda x: x[0] ^ x[1]), zip(s1, s2))) key_space = bytes(string.ascii_letters + string.digits, encoding='utf-8') # Construct dict. l = [] for x in key_space: s = set() for y in key_space: s.add(x ^ y) l.append(s) # ci = flag ^ keyi all_c = [] for i in range(1001): r = remote('47.98.192.231', 25001) all_c.append(base64.b64decode(r.recvall())) r.close() # Goal: recover key0 xored_keys = [] # [key0 ^ keyi for i in range(1, 1001)] for c in all_c[1:]: xored_keys.append( XOR(all_c[0], c) ) # byte-by-byte key0 = b'' for i in range(len(xored_keys[0])): s = set(xored_key[i] for xored_key in xored_keys) # keyi[i] for index in range(len(key_space)): if s <= l[index]: key0 += bytes([ key_space[index] ]) print(key0, XOR(key0, all_c[0])) # hgame{r3us1nG+M3$5age-&&~rEduC3d_k3Y-5P4Ce}  ### Reorder 75pt Input: hgame{ABCDEFGHIJKLMNOPQRSTUVWXY} Output: {hHDCFABGemEaJIgPKXTSVQRWONUM}YL Encrypted flag: {hmt$5jUIem+aLpgm3!TA0uTnReiP}!_

 1 2 3 4 5 6 7 8  c = '{hmt$5jUIem+aLpgm3!TA0uTnReiP}!_' x = 'hgame{ABCDEFGHIJKLMNOPQRSTUVWXY}' y = '{hHDCFABGemEaJIgPKXTSVQRWONUM}YL' for i in x: print(c[y.index(i)], end='') # hgame{jU$t+5ImpL3_PeRmuTATi0n!!} 

## Week2

### Verification_code 125pt

Verification_code.py

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66  #!/usr/bin/env python3 # -*- coding: utf-8 -*- import socketserver import os, sys, signal import string, random from hashlib import sha256 from secret import FLAG class Task(socketserver.BaseRequestHandler): def _recvall(self): BUFF_SIZE = 2048 data = b'' while True: part = self.request.recv(BUFF_SIZE) data += part if len(part) < BUFF_SIZE: break return data.strip() def send(self, msg, newline=True): try: if newline: msg += b'\n' self.request.sendall(msg) except: pass def recv(self, prompt=b'> '): self.send(prompt, newline=False) return self._recvall() def proof_of_work(self): random.seed( os.urandom(8) ) proof = ''.join([ random.choice(string.ascii_letters+string.digits) for _ in range(20) ]) _hexdigest = sha256(proof.encode()).hexdigest() self.send(str.encode( "sha256(XXXX+%s) == %s" % (proof[4:],_hexdigest) )) x = self.recv(prompt=b'Give me XXXX: ') if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest: return False return True def handle(self): signal.alarm(60) if not self.proof_of_work(): return self.send(b'The secret code?') _code = self.recv() if _code == b'I like playing Hgame': self.send(b'Ok, you find me.') self.send(b'Here is the flag: ' + FLAG) self.send(b'Bye~') else: self.send(b'Rua!!!') self.request.close() class ThreadedServer(socketserver.ThreadingMixIn, socketserver.TCPServer): pass class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer): pass if __name__ == "__main__": HOST, PORT = '0.0.0.0', 1234 server = ForkedServer((HOST, PORT), Task) server.allow_reuse_address = True server.serve_forever() 

exp.py

### Exchange 150pt

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116  # Our admin hijacked a secret channel and it looks like there are two teams doing some unspeakable transactions. # nc 47.98.192.231 25258 from hashlib import sha256 from itertools import product from Crypto.Util.number import * from pwn import * import string import re s = string.ascii_letters + string.digits r = remote('47.98.192.231', 25258) context.log_level = 'debug' # Proof of work rec = r.recvline().decode() suffix = re.findall(r'$$XXXX\+(.*?)$$', rec)[0] digest = re.findall(r'== (.*?)\n', rec)[0] print(f"suffix: {suffix} \ndigest: {digest}") print('Calculating hash...') for i in product(s, repeat=4): prefix = ''.join(i) guess = prefix + suffix if sha256(guess.encode()).hexdigest() == digest: print(guess) break r.sendafter(b'Give me XXXX: ', prefix.encode()) print("Proof of work passed!") # p, g r.sendafter(b"Alice: Let's do Key Exchange first.\n", b'\n') rec = b''.join(r.recvlines(6, keepends=True)).decode() print(rec) p = int(re.findall(r'p = ([0-9]*)\n', rec)[0]) g = int(re.findall(r'g = ([0-9]*)\n', rec)[0]) print(f"p = {p}\ng = {g}") # A r.send(b'\n') r.recvlines(5) r.send(b'\n') rec = r.recvuntil(b'> ').decode() A = int(re.findall(r'A = ([0-9]*)\n', rec)[0]) print(f"A = {A}") # Impersonate Alice my_a = 0x1337 my_A = pow(g, my_a, p) print(f"my_A = {my_A}") my_b = 0x7331 my_B = pow(g, my_b, p) print(f"my_B = {my_B}") r.sendline(b'yes') r.sendafter(b"> ", str(my_A).encode()) r.recvlines(3) r.send(b"\n") # B rec = r.recvuntil(b"> ").decode() B = int(re.findall(r'B = ([0-9]*)\n', rec)[0]) print(f"B = {B}") # Impersonate Bob r.sendline(b'yes') r.sendafter(b"> ", str(my_B).encode()) r.recvlines(3) r.send(b"\n") # two share keys S_a = pow(A, my_b, p) inv_a = inverse(S_a, p) S_b = pow(B, my_a, p) inv_b = inverse(S_b, p) print(f"S_a = {S_a}\nS_b = {S_b}") r.recvuntil(b"hint: does Alice and Bob share the same key?\n\n") r.send(b"\n") r.recvuntil(b"Bob: Right, let's exchange the encrypted flag!\n\n") r.send(b"\n") r.recvuntil(b"[INFO] : Bob does the same, C_b = (m * S_b) % p\n\n") r.send(b"\n") # Impersonate B to send message to A rec = r.recvuntil(b"> ").decode() C_b = int(re.findall(r'C_b = ([0-9]*)\n', rec)[0]) print(f"C_b = {C_b}") m_b = (C_b * inv_b) % p m2a = (m_b * S_a) % p print(f"m_b = {m_b}\nm2a = {m2a}") r.sendline(b"yes") r.sendafter(b"> ", str(m2a).encode()) # Impersonate A to send message to B rec = b"".join(r.recvlines(2, keepends=True)).decode() C_a = int(re.findall(r'C_a = ([0-9]*)\n', rec)[0]) print(f"C_a = {C_a}") m_a = (C_a * inv_a) % p m2b = (m_b * S_b) % p print(f"m_a = {m_a}\nm2b = {m2b}") # r.sendline(b"yes") # r.sendafter(b"> ", str(m2b).encode()) print(b''.join(map(long_to_bytes, [m_a, m_b]))) r.interactive() 

### Feedback 150pt

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83  #!/usr/bin/env python3 # -*- coding: utf-8 -*- import os, random import string, binascii import signal import socketserver from hashlib import sha256 from Crypto.Cipher import AES from secret import MESSAGE assert len(MESSAGE) == 48 class Task(socketserver.BaseRequestHandler): def __init__(self, *args, **kargs): self.KEY = b"" self.IV = b"" super().__init__(*args, **kargs) def _recvall(self): BUFF_SIZE = 2048 data = b'' while True: part = self.request.recv(BUFF_SIZE) data += part if len(part) < BUFF_SIZE: break return data.strip() def send(self, msg, newline=True): try: if newline: msg += b'\n' self.request.sendall(msg) except: pass def recv(self, prompt=b'> '): self.send(prompt, newline=False) return self._recvall() def encrypt(self, data): assert len(data) % 16 == 0 aes = AES.new(self.KEY, AES.MODE_CFB, self.IV, segment_size=128) return aes.encrypt(data) def decrypt(self, data): assert len(data) % 16 == 0 aes = AES.new(self.KEY, AES.MODE_CFB, self.IV, segment_size=128) return aes.decrypt(data) def handle(self): signal.alarm(60) self.KEY = os.urandom(32) self.IV = os.urandom(16) self.send(b"You have only 3 times to decrypt sth, then I'll give u the FLAG.") try: for _ in range(3): self.send(b"Give me sth(hex) to decrypt") hex_input = self.recv() if not hex_input: break ciphertext = binascii.unhexlify(hex_input) plaintext = self.decrypt(ciphertext) self.send( binascii.hexlify(plaintext) ) except: self.send(b"Rua!!!") self.request.close() enc_msg = self.encrypt(MESSAGE) self.send(b"Here is your encrypted FLAG(hex): ", newline=False) self.send( binascii.hexlify(enc_msg) ) self.request.close() class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer): pass if __name__ == "__main__": HOST, PORT = '0.0.0.0', 1234 server = ForkedServer((HOST, PORT), Task) server.allow_reuse_address = True server.serve_forever() 

exp.py

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53  from pwn import * import re XOR = lambda s1, s2: bytes([x^y for x,y in zip(s1, s2)]) m1 = b'FLAG is hgame{51' r = remote('47.98.192.231', 25147) context.log_level = 'debug' def send(data): r.sendafter(b"> ", data) def rec(): return r.recvline().decode() # c1 = b'0'*32 # send(c1) # enc_iv = bytes.fromhex(rec()) # inp = XOR(m1, enc_iv) # c2 = inp.hex().encode() + c1 # send(c2) # enc_inp = bytes.fromhex(rec())[16:32] # send(b"\n") # enc_flag = bytes.fromhex(re.findall(r'FLAG$$hex$$: ([0-9a-f]*)\n', rec())[0]) # m2 = XOR(enc_flag[16:32], enc_inp) # print(m2) m2 = b'b72d4cd23b2fe672' c1 = b'0'*32 send(c1) enc_iv = bytes.fromhex(rec()) inp = XOR(m1, enc_iv) c2 = inp.hex().encode() + c1 send(c2) enc_inp = bytes.fromhex(rec())[16:32] inp2 = XOR(m2, enc_inp) c3 = inp.hex().encode() + inp2.hex().encode() + c1 send(c3) enc_inp2 = bytes.fromhex(rec())[32:48] enc_flag = bytes.fromhex(re.findall(r'FLAG$$hex$$: ([0-9a-f]*)\n', rec())[0]) m3 = XOR(enc_flag[32:48], enc_inp2) print(m3) m3 = b'a874cb44020868}.' r.interactive() # FLAG is hgame{51b72d4cd23b2fe672a874cb44020868} 

## Week4

### CBCBC 150pt

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160  #!/usr/bin/env python3 # -*- coding: utf-8 -*- import socketserver import os, sys, signal import string, binascii from hashlib import sha256 from secret import FLAG from Crypto.Cipher import AES from Crypto.Random import random, atfork BLOCKS = lambda data: [data[16*i:16*(i+1)] for i in range(len(data)//16)] XOR = lambda s1, s2: bytes([x^y for x,y in zip(s1, s2)]) class Task(socketserver.BaseRequestHandler): BLOCKSIZE = 16 KEY = None IV = None def _recvall(self): BUFF_SIZE = 2048 data = b'' while True: part = self.request.recv(BUFF_SIZE) data += part if len(part) < BUFF_SIZE: break return data.strip() def send(self, msg, newline=True): try: if newline: msg += b'\n' self.request.sendall(msg) except: pass def recv(self, prompt=b'> '): self.send(prompt, newline=False) return self._recvall() def proof_of_work(self): proof = ''.join([ random.choice(string.ascii_letters+string.digits) for _ in range(20) ]) _hexdigest = sha256(proof.encode()).hexdigest() self.send(str.encode( "sha256(XXXX+%s) == %s" % (proof[:],_hexdigest) )) x = proof[:4].encode() if len(x) != 4 or sha256(x+proof[4:].encode()).hexdigest() != _hexdigest: return False return True def pad(self, data): pad_len = self.BLOCKSIZE - (len(data) % self.BLOCKSIZE) return data + bytes( [pad_len] * pad_len ) def unpad(self, data): pad_len = data[-1] _data = data[:-pad_len] if self.pad(_data) != data: raise ValueError('Padding is incorrect.') return _data def enc(self, block): aes = AES.new(self.KEY, AES.MODE_ECB) return aes.encrypt(block) def dec(self, block): aes = AES.new(self.KEY, AES.MODE_ECB) return aes.decrypt(block) def encrypt(self, data): assert len(data) > 2*self.BLOCKSIZE data = self.pad(data) iv_1, iv_2 = BLOCKS(data)[0], BLOCKS(data)[1] mid_1, mid_2 = iv_1, iv_2 cipher = b'' for block in BLOCKS(data)[2:]: block = XOR(block, mid_1) block = self.enc(block) mid_1 = block block = XOR(block, mid_2) block = self.enc(block) mid_2 = block cipher += block return iv_1 + iv_2 + cipher def decrypt(self, data): assert len(data) > 2*self.BLOCKSIZE assert len(data) % self.BLOCKSIZE == 0 iv_1, iv_2 = BLOCKS(data)[0], BLOCKS(data)[1] mid_1, mid_2 = iv_1, iv_2 plain = b'' for block in BLOCKS(data)[2:]: mid_2_n = block block = self.dec(block) block = XOR(block, mid_2) mid_1_n = block block = self.dec(block) block = XOR(block, mid_1) mid_1, mid_2 = mid_1_n, mid_2_n plain += block return self.unpad(iv_1 + iv_2 + plain) def timeout_handler(self, signum, frame): self.send(b"\n\nSorry, time out.\n") raise TimeoutError def handle(self): atfork() self.KEY = os.urandom(32) self.IV = os.urandom(2*self.BLOCKSIZE) # self.send(b'key: ' + self.KEY.hex().encode()) # self.send(b'IV: ' + self.IV.hex().encode()) try: signal.signal(signal.SIGALRM, self.timeout_handler) signal.alarm(300) if not self.proof_of_work(): return enc_flag = self.encrypt(self.IV + FLAG) self.send(b'Your encrypted FLAG (in hex) is ', newline=False) self.send( binascii.hexlify(enc_flag) ) self.send(b'Now, I can decrypt sth for you.') while True: try: self.send(b'Give me sth (in hex)') hex_inp = self.recv() if not hex_inp: break inp = binascii.unhexlify(hex_inp) self.decrypt(inp) self.send(b'decryption done') except TimeoutError: exit(1) except: self.send(b'sth must be wrong') signal.alarm(0) self.send(b'Bye~~') self.request.close() except: pass class ForkedServer(socketserver.ForkingMixIn, socketserver.TCPServer): pass if __name__ == "__main__": HOST, PORT = '0.0.0.0', 12345 server = ForkedServer((HOST, PORT), Task) server.allow_reuse_address = True server.serve_forever() 

mid_1（即IV1）异或上一些东西，来逐字节爆破。

exp.py

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111  from hashlib import sha256 from itertools import product from Crypto.Util.number import * import re from pwn import * s = string.ascii_letters + string.digits XOR = lambda s1, s2: bytes([x^y for x,y in zip(s1, s2)]) debug = False if debug == False: r = remote('47.98.192.231', 25355) # context.log_level = 'debug' # Proof of work rec = r.recvline().decode() suffix = re.findall(r'$$XXXX\+(.*?)$$', rec)[0] digest = re.findall(r'== (.*?)\n', rec)[0] print(f"[+] suffix: {suffix} \n[+] digest: {digest}") print('[*] Calculating hash...') for i in product(s, repeat=4): prefix = ''.join(i) guess = prefix + suffix if sha256(guess.encode()).hexdigest() == digest: print(guess) break r.sendafter(b'Give me XXXX: ', prefix.encode()) print("[!] Proof of work passed!") else: r = remote('127.0.0.1', 12345) # context.log_level = 'debug' rec = r.recvuntil(b'Give me sth (in hex)').decode() enc = re.findall(r'is ([0-9a-f]*)\n', rec)[0] enc = bytes.fromhex(enc) IV1, IV2, enc_flag = enc[:16], enc[16:32], enc[32:] print(f"[+] IV1: {IV1}\n[+] IV2: {IV2}\n[+] enc_flag: {enc_flag}") enc1 = enc_flag[:16] flag1 = '' for j in range(16): for i in range(256): payload = XOR(IV1, b'\x00'*(15-j) + bytes([i]) + XOR(flag1.encode(), bytes([j+1])*j)) payload += IV2 + enc1 r.sendafter(b'> ', payload.hex().encode()) if r.recvline() == b'decryption done\n': ch = chr(i^(j+1)) flag1 = ch + flag1 print(flag1) break # hgame{I_like_Pad enc2 = enc_flag[16:32] flag2 = '' for j in range(16): for i in range(256): payload = IV1 payload += XOR(IV2, b'\x00'*(15-j) + bytes([i]) + XOR(flag2.encode(), bytes([j+1])*j)) payload += enc1 + enc2 r.sendafter(b'> ', payload.hex().encode()) if r.recvline() == b'decryption done\n': ch = chr(i^(j+1)) flag2 = ch + flag2 print(flag2) break # ding_oracle_atta enc3 = enc_flag[32:48] flag3 = '' for j in range(16): for i in range(256): payload = IV1 + IV2 payload += XOR(enc1, b'\x00'*(15-j) + bytes([i]) + XOR(flag3.encode(), bytes([j+1])*j)) payload += enc2 + enc3 r.sendafter(b'> ', payload.hex().encode()) if r.recvline() == b'decryption done\n': ch = chr(i^(j+1)) flag3 = ch + flag3 print(flag3) break # ck_6f64ab782042f enc4 = enc_flag[48:] flag4 = '\x04' for j in range(1, 16): # print(f"j: {j}") for i in range(256): payload = IV1 + IV2 + enc1 payload += XOR(enc2, b'\x00'*(15-j) + bytes([i]) + XOR(flag4.encode(), bytes([j+1])*j)) payload += enc3 + enc4 r.sendafter(b'> ', payload.hex().encode()) if r.recvline() == b'decryption done\n': ch = chr(i^(j+1)) # print(ord(ch)) flag4 = ch + flag4 print(flag4) # 3f389f590a2}\x04\x04\x04\x04\x04\x04 flag = flag1 + flag2 + flag3 + flag4 print(flag) # hgame{I_like_Padding_oracle_attack_6f64ab782042f3f389f590a2} r.interactive() 

### ToyCipher_Linear 175pt

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100  #!/usr/bin/env python3 # -*- coding: utf-8 -*- import os, binascii # from secret import flag def rotL(x, nbits, lbits): mask = 2**nbits - 1 return (x << lbits%nbits) & mask | ( (x & mask) >> (-lbits % nbits) ) def rotR(x, nbits, rbits): return rotL(x, nbits, -rbits%nbits) def keySchedule(masterkey): roundKeys = [ ( rotR(masterkey, 64, 16*i) % 2**16 ) for i in range(12) ] return roundKeys def f(x, roundkey): return rotL(x, 16, 7) ^ rotL(x, 16, 2) ^ roundkey def ToyCipher(block, mode='enc'): '''Feistel networks''' roundKeys_ = ROUNDKEYS if mode == 'dec': roundKeys_ = roundKeys_[::-1] L, R = (block >> 16), (block % 2**16) for i in range(12): _R = R R = L ^ f( R, roundKeys_[i] ) L = _R return (R << 16) | L def pad(data, blocksize): pad_len = blocksize - (len(data) % blocksize) return data + bytes( [pad_len] * pad_len ) def unpad(data, blocksize): pad_len = data[-1] _data = data[:-pad_len] assert pad(_data, blocksize)==data, "Invalid padding." return _data def encrypt(plaintext): '''ECB mode''' plaintext = pad(plaintext, BLOCKSIZE) ciphertext = b'' for i in range( len(plaintext) // BLOCKSIZE ): block = plaintext[i*BLOCKSIZE:(i+1)*BLOCKSIZE] block = int.from_bytes(block, byteorder='big') E_block = ToyCipher(block) ciphertext += E_block.to_bytes(BLOCKSIZE, byteorder='big') return ciphertext def decrypt(ciphertext): '''ECB mode''' plaintext = b'' for i in range( len(ciphertext) // BLOCKSIZE ): block = ciphertext[i*BLOCKSIZE:(i+1)*BLOCKSIZE] block = int.from_bytes(block, byteorder='big') D_block = ToyCipher(block, 'dec') plaintext += D_block.to_bytes(BLOCKSIZE, byteorder='big') plaintext = unpad(plaintext, BLOCKSIZE) return plaintext ms, ks, cs = [], [], [] for i in range(224): masterkey = os.urandom(8) masterkey = int.from_bytes(masterkey, byteorder='big') ROUNDKEYS = keySchedule(masterkey) BLOCKSIZE = 4 m = os.urandom(4) m = int.from_bytes(m, 'big') c = ToyCipher(m) ms.append(m) ks.append(ROUNDKEYS) cs.append(c) with open('ms.txt', 'wb') as f: for m in ms: f.write(str(m).encode() + b'\n') with open('cs.txt', 'wb') as f: for c in cs: f.write(str(c).encode() + b'\n') with open('ks.txt', 'wb') as f: for k in ks: for kk in k: f.write(str(kk).encode()+b' ') f.write(b'\n') `