Last active
September 4, 2024 06:11
-
-
Save bonsaiviking/5571001 to your computer and use it in GitHub Desktop.
A simple/simplistic implementation of AES in pure Python.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#My AES implementation | |
# By Daniel Miller | |
def xor(s1, s2): | |
return tuple(a^b for a,b in zip(s1, s2)) | |
class AES(object): | |
class __metaclass__(type): | |
def __init__(cls, name, bases, classdict): | |
cls.Gmul = {} | |
for f in (0x02, 0x03, 0x0e, 0x0b, 0x0d, 0x09): | |
cls.Gmul[f] = tuple(cls.gmul(f, x) for x in range(0,0x100)) | |
Rcon = ( 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a ) | |
Sbox = ( | |
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, | |
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, | |
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, | |
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, | |
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, | |
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, | |
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, | |
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, | |
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, | |
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, | |
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, | |
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, | |
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, | |
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, | |
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, | |
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 | |
) | |
Sbox_inv = ( | |
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, | |
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, | |
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, | |
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, | |
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, | |
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, | |
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, | |
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, | |
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, | |
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, | |
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, | |
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, | |
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, | |
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, | |
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, | |
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D | |
) | |
@staticmethod | |
def rot_word(word): | |
return word[1:] + word[:1] | |
@staticmethod | |
def sub_word(word): | |
return (AES.Sbox[b] for b in word) | |
def key_schedule(self): | |
expanded = [] | |
expanded.extend(map(ord, self.key)) | |
for i in range(self.nk, self.nb * (self.nr + 1)): | |
t = expanded[(i-1)*4:i*4] | |
if i % self.nk == 0: | |
t = xor( AES.sub_word( AES.rot_word(t) ), (AES.Rcon[i // self.nk],0,0,0) ) | |
elif self.nk > 6 and i % self.nk == 4: | |
t = AES.sub_word(t) | |
expanded.extend( xor(t, expanded[(i-self.nk)*4:(i-self.nk+1)*4])) | |
return expanded | |
def add_round_key(self, rkey): | |
for i, b in enumerate(rkey): | |
self.state[i] ^= b | |
def sub_bytes(self): | |
for i, b in enumerate(self.state): | |
self.state[i] = AES.Sbox[b] | |
def inv_sub_bytes(self): | |
for i, b in enumerate(self.state): | |
self.state[i] = AES.Sbox_inv[b] | |
def shift_rows(self): | |
rows = [] | |
for r in range(4): | |
rows.append( self.state[r::4] ) | |
rows[r] = rows[r][r:] + rows[r][:r] | |
self.state = [ r[c] for c in range(4) for r in rows ] | |
def inv_shift_rows(self): | |
rows = [] | |
for r in range(4): | |
rows.append( self.state[r::4] ) | |
rows[r] = rows[r][4-r:] + rows[r][:4-r] | |
self.state = [ r[c] for c in range(4) for r in rows ] | |
@staticmethod | |
def gmul(a, b): | |
p = 0 | |
for c in range(8): | |
if b & 1: | |
p ^= a | |
a <<= 1 | |
if a & 0x100: | |
a ^= 0x11b | |
b >>= 1 | |
return p | |
def mix_columns(self): | |
ss = [] | |
for c in range(4): | |
col = self.state[c*4:(c+1)*4] | |
ss.extend(( | |
AES.Gmul[0x02][col[0]] ^ AES.Gmul[0x03][col[1]] ^ col[2] ^ col[3] , | |
col[0] ^ AES.Gmul[0x02][col[1]] ^ AES.Gmul[0x03][col[2]] ^ col[3] , | |
col[0] ^ col[1] ^ AES.Gmul[0x02][col[2]] ^ AES.Gmul[0x03][col[3]], | |
AES.Gmul[0x03][col[0]] ^ col[1] ^ col[2] ^ AES.Gmul[0x02][col[3]], | |
)) | |
self.state = ss | |
def inv_mix_columns(self): | |
ss = [] | |
for c in range(4): | |
col = self.state[c*4:(c+1)*4] | |
ss.extend(( | |
AES.Gmul[0x0e][col[0]] ^ AES.Gmul[0x0b][col[1]] ^ AES.Gmul[0x0d][col[2]] ^ AES.Gmul[0x09][col[3]], | |
AES.Gmul[0x09][col[0]] ^ AES.Gmul[0x0e][col[1]] ^ AES.Gmul[0x0b][col[2]] ^ AES.Gmul[0x0d][col[3]], | |
AES.Gmul[0x0d][col[0]] ^ AES.Gmul[0x09][col[1]] ^ AES.Gmul[0x0e][col[2]] ^ AES.Gmul[0x0b][col[3]], | |
AES.Gmul[0x0b][col[0]] ^ AES.Gmul[0x0d][col[1]] ^ AES.Gmul[0x09][col[2]] ^ AES.Gmul[0x0e][col[3]], | |
)) | |
self.state = ss | |
def cipher(self, block): | |
#print "round[ 0].input: {0}".format(block.encode('hex')) | |
n = self.nb * 4 | |
self.state = map(ord, block) | |
keys = self.key_schedule() | |
#print "round[ 0].k_sch: {0}".format(keys[0:n].encode('hex')) | |
self.add_round_key(keys[0:n]) | |
for r in range(1, self.nr): | |
#print "round[{0}].start: {1}".format(r,self.state.encode('hex')) | |
self.sub_bytes() | |
#print "round[{0}].s_box: {1}".format(r,self.state.encode('hex')) | |
self.shift_rows() | |
#print "round[{0}].s_row: {1}".format(r,self.state.encode('hex')) | |
self.mix_columns() | |
#print "round[{0}].m_col: {1}".format(r,self.state.encode('hex')) | |
k = keys[r*n:(r+1)*n] | |
#print "round[{0}].k_sch: {1}".format(r,k.encode('hex')) | |
self.add_round_key(k) | |
self.sub_bytes() | |
self.shift_rows() | |
self.add_round_key(keys[self.nr*n:]) | |
#print "output: {0}".format(self.state.encode('hex')) | |
return "".join(map(chr, self.state)) | |
def inv_cipher(self, block): | |
#print "round[ 0].iinput: {0}".format(block.encode('hex')) | |
n = self.nb * 4 | |
self.state = map(ord, block) | |
keys = self.key_schedule() | |
k = keys[self.nr*n:(self.nr+1)*n] | |
#print "round[ 0].ik_sch: {0}".format(k.encode('hex')) | |
self.add_round_key(k) | |
for r in range(self.nr-1, 0, -1): | |
#print "round[{0}].istart: {1}".format(r,self.state.encode('hex')) | |
self.inv_shift_rows() | |
#print "round[{0}].is_row: {1}".format(r,self.state.encode('hex')) | |
self.inv_sub_bytes() | |
#print "round[{0}].is_box: {1}".format(r,self.state.encode('hex')) | |
k = keys[r*n:(r+1)*n] | |
#print "round[{0}].ik_sch: {1}".format(r,k.encode('hex')) | |
self.add_round_key(k) | |
#print "round[{0}].ik_add: {1}".format(r,self.state.encode('hex')) | |
self.inv_mix_columns() | |
#print "round[{0}].im_col: {1}".format(r,self.state.encode('hex')) | |
self.inv_shift_rows() | |
self.inv_sub_bytes() | |
self.add_round_key(keys[0:n]) | |
#print "output: {0}".format(self.state.encode('hex')) | |
return "".join(map(chr, self.state)) | |
class AES_128(AES): | |
def __init__(self): | |
self.nb = 4 | |
self.nr = 10 | |
self.nk = 4 | |
if __name__=="__main__": | |
key = "2b7e151628aed2a6abf7158809cf4f3c".decode('hex') | |
#key = "000102030405060708090a0b0c0d0e0f".decode('hex') | |
check = ( | |
#("00112233445566778899aabbccddeeff", "69c4e0d86a7b0430d8cdb78070b4c55a"), | |
("6bc1bee22e409f96e93d7e117393172a", "3ad77bb40d7a3660a89ecaf32466ef97"), | |
("ae2d8a571e03ac9c9eb76fac45af8e51", "f5d3d58503b9699de785895a96fdbaaf"), | |
("30c81c46a35ce411e5fbc1191a0a52ef", "43b1cd7f598ece23881b00e3ed030688"), | |
("f69f2445df4f9b17ad2b417be66c3710", "7b0c785e27e8ad3f8223207104725dd4"), | |
) | |
crypt = AES_128() | |
crypt.key = key | |
for c in check: | |
p = c[0].decode('hex') | |
v = c[1].decode('hex') | |
t = crypt.cipher(p) | |
if t == v: | |
print "yay!" | |
else: | |
print "{0} != {1}".format(t.encode('hex'), c[1]) | |
t = crypt.inv_cipher(v) | |
if t == p: | |
print "yay!" | |
else: | |
print "{0} != {1}".format(t.encode('hex'), c[1]) |
This is not meant for executing, it is meant for importing and using the AES class
by any chance, do you have ported version of python3?
yeah, I really don't think much of this gist, its got some pretty weird stuff in the metaclass, which probably causes some python 2/3 issues. also, AES doesn't really make a great base class, you could determine if its AES 128, 192, and 256 by just measuring the size of an initialized key and setting the number of rounds appropriately. AES implies a block size of 128 bits.
basically its a ride on the fail boat. I think the OP was trying to look smart.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
is this it ? does this code end with the else statement in lines 217-218 or is there something that I am overlooking?