A deliberately terse AES128 implementation in pure python. Functions taken from https://github.com/DavidBuchanan314/aes-playground, comments removed, put into a single file, and minified.
| def xor_bytes(a, b): | |
| return bytearray([ai^bi for ai, bi in zip(a, b)]) | |
| def ff_divmod(r, b, q=0): | |
| while True: | |
| diff = r.bit_length() - b.bit_length() | |
| if diff < 0: break | |
| q ^= 1 << diff | |
| r ^= b << diff | |
| return q, r | |
| def ff_multiply(a, b, r=0): | |
| while b: | |
| r ^= a * (b & 1) | |
| a <<= 1; b >>= 1 | |
| return ff_divmod(r, 0x11b)[1] | |
| def ff_mulx(a, x, r=0): | |
| while x: | |
| r ^= a * (x & 1) | |
| a = ff_multiply(a, 2) | |
| x >>= 1 | |
| return r | |
| def sub_byte(a, b=0x11b, x0=0, x1=1): | |
| while a: | |
| (q, a), b = ff_divmod(b, a), a | |
| x0, x1 = x1, x0 ^ ff_multiply(q, x1) | |
| _, x = ff_divmod(x0, 0x11b) | |
| x ^= x<<1 ^ x>>7 ^ x<<2 ^ x>>6 ^ x<<3 ^ x>>5 ^ x<<4 ^ x>>4 ^ 0x63 | |
| return x & 0xff | |
| def sub_bytes(state): | |
| return bytearray(map(sub_byte, state)) | |
| def shift_rows(state): | |
| s2 = bytearray(4 * 4) | |
| for i in range(4): | |
| row = state[i:4*4:4] | |
| s2[i:4*4:4] = row[i:] + row[:i] | |
| return s2 | |
| def mix_columns(state): | |
| s2 = bytearray(4 * 4) | |
| for i in range(4): | |
| for y in range(4): | |
| for x in range(4): | |
| s2[i*4+y] ^= ff_mulx(state[i*4:i*4+4][x], [2,3,1,1][(x-y)%4]) | |
| return s2 | |
| def key_expansion(key): | |
| round_keys = [key.copy()] | |
| for i in range(1, 10+1): | |
| rkey = bytearray() | |
| temp = sub_bytes((lambda w: w[1:]+w[:1])(round_keys[-1][-4:])) | |
| temp[0] ^= ff_mulx(0x8d, 1<<i) | |
| for j in range(4): | |
| temp = xor_bytes(temp, round_keys[-1][j*4:j*4+4]) | |
| rkey += temp | |
| round_keys.append(rkey) | |
| return round_keys | |
| def do_aes_128(_in, key): | |
| rkeys = key_expansion(key) | |
| state = xor_bytes(_in, rkeys[0]) | |
| for i in range(1, 10): | |
| state = xor_bytes(mix_columns(shift_rows(sub_bytes(state))), rkeys[i]) | |
| state = xor_bytes(shift_rows(sub_bytes(state)), rkeys[-1]) | |
| return state | |
| TEST = bytearray(range(16)) | |
| print(do_aes_128(TEST, TEST).hex()) | |
| from Crypto.Cipher import AES | |
| aes = AES.new(TEST, AES.MODE_ECB) | |
| print(aes.encrypt(TEST).hex()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment