Skip to content

Instantly share code, notes, and snippets.

@DavidBuchanan314
Last active October 11, 2020 10:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavidBuchanan314/0274fc72812f3c2c85a08d3a97c0eeac to your computer and use it in GitHub Desktop.
Save DavidBuchanan314/0274fc72812f3c2c85a08d3a97c0eeac to your computer and use it in GitHub Desktop.
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