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
| from z3 import *
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_intvec(plaintext): '''ECB mode''' plaintext = pad(plaintext, BLOCKSIZE) ciphertext = [] 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.append(E_block) 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
masterkey = BitVec("masterkey", 8 * 8) ROUNDKEYS = keySchedule(masterkey) BLOCKSIZE = 4 solver = Solver() ciphertext = b'\x91a\xb1o\xed_\xb2\x8c\x00\x1b\xdfp' enintvec = encrypt_intvec(b'just a test') anslist = [] for i in range( len(ciphertext) // BLOCKSIZE ): block = ciphertext[i*BLOCKSIZE:(i+1)*BLOCKSIZE] block = int.from_bytes(block, byteorder='big') anslist.append(block) for i in range( len(ciphertext) // BLOCKSIZE ): solver.add(anslist[i] == enintvec[i]) print(solver.check()) print(solver.model()) masterkey = solver.model()[masterkey].as_long() ROUNDKEYS = keySchedule(masterkey) print(decrypt(b'\xe6\xf9\xda\xf0\xe18\xbc\xb4[\xfb\xbe\xd1\xfe\xa2\t\x8d\xdft:\xee\x1f\x1d\xe2q\xe5\x92/$#DL\x00\x1dD5@\x01W?!7CQ\xc16V\xb0\x14q)\xaa2'))
|