Skip to content

Instantly share code, notes, and snippets.

@ibarrajo
Last active June 15, 2017 18:36
Show Gist options
  • Save ibarrajo/efae4dd356906255fae2 to your computer and use it in GitHub Desktop.
Save ibarrajo/efae4dd356906255fae2 to your computer and use it in GitHub Desktop.
from copy import copy
class AES:
def __init__(self, blocksize, key):
# verify that the key is the right size
assert len(key) == (blocksize / 8)
self.key = key
# 10 cycles for 128-bit keys
# 12 cycles for 192-bit keys
# 14 cycles for 256-bit keys
self.blocksize = blocksize
if blocksize == 128:
self.aesCycles = 10
elif blocksize == 192:
self.aesCycles = 12
elif blocksize == 256:
self.aesCycles = 14
else:
assert False, 'Invalid blocksize given to AES(blocksize, key)'
# list of states
self.states = []
# create Rijndael's key schedule
self.RKS = self.makeKeys(key)
#print('RKS',''.join(map(lambda b: format(b, '02x'), self.RKS)).upper())
#print(self.RKS)
#print('key',key)
# print("set block size to %s" % blocksize)
# print("set key to %s" % key)
def encrypt(self, data):
'''
The encrypt function runs the encryption rounds (doAES(state)) for each
state that exists.
'''
#data = bytearray(data, 'utf-8')
self.states = self.chunk(data)
encrypted = []
for state in self.states:
encrypted.extend(self.doAES(state))
return encrypted
def decrypt(self, data):
self.states = self.chunk(data)
decrypted = []
for state in self.states:
decrypted.extend(self.undoAES(state))
return decrypted
def chunk(self, data):
'''
splits the data (string) into chunks and on the last step it converts it
into the byte/int array
'''
n = {128:16, 192:24, 256:32}[self.blocksize]
states = [data[i:i + n] for i in range(0, len(data), n)]
# pad the data as needed on the last state
for x in range(n):
try:
states[len(states) - 1][x] = states[len(states) - 1][x]
except IndexError:
states[len(states) - 1].extend([0x00])
return states
def doAES(self, state):
# to bytes
key = self.getRoundKey(0)
# initial round
state = self.addRoundKey(state, key)
# rounds
for c in range(1, self.aesCycles):
key = self.getRoundKey(c)
state = self.subBytes(state)
state = self.shiftRows(state)
state = self.mixColumns(state)
state = self.addRoundKey(state, key)
# final round
key = self.getRoundKey(self.aesCycles)
state = self.subBytes(state)
state = self.shiftRows(state)
state = self.addRoundKey(state, key)
return state
def undoAES(self, state):
'''
Does exactly the same rounds as doAES() just in reverse
'''
key = self.getRoundKey(self.aesCycles)
state = self.addRoundKey(state, key)
state = self.shiftRowsInverse(state)
state = self.subBytesInverse(state)
for c in range(self.aesCycles - 1, 0, -1):
key = self.getRoundKey(c)
state = self.addRoundKey(state, key)
state = self.mixColumnsInverse(state)
state = self.shiftRowsInverse(state)
state = self.subBytesInverse(state)
key = self.getRoundKey(0)
state = self.addRoundKey(state, key)
return state
def keyScheduleCore(self, bytes, rcon):
# rotate 1 byte to the left
bytes = bytes[1:] + bytes[0:1]
# apply sbox substitution on all bytes of word
bytes = [self.RijndaelSTable[bytes[i]] for i in [0,1,2,3]]
'''
On just the first (leftmost) byte of the output word, exclusive OR the byte
with 2 to the power of (i-1). In other words, perform the rcon operation
with i as the input, and exclusive or the rcon output with the first byte of
the output word
'''
bytes[0] = bytes[0] ^ self.RCON[rcon]
return bytes
def makeKeys(self, key):
'''
Generates Rijndale's key schedule
source: https://en.wikipedia.org/wiki/Rijndael_key_schedule
'''
keylen = len(key)
n = {128:16, 192:24, 256:32}[self.blocksize]
# get the b valuees for the corresponding key size
b = {128:176, 192:208, 256:240}[self.blocksize]
RKS = []
# the first part of the RKS is the key
RKS.extend(key)
size = keylen
rcon = 1
# create the required key length
while size != b:
assert size <= b, 'Impossible key schedule, something is wrong.. size is %s max is %s' % (size, b)
# create a 4 byte temporary variable
t = [0,0,0,0]
# assign previous 4 bytes to the temporary storage t
t = RKS[(size - 4):]
# perform key schedule core on t with rcon as the iteration value
t = self.keyScheduleCore(t, rcon)
# increment rcon
rcon += 1
# We exclusive-OR t with the four-byte block n bytes before the new expanded key.
t = [x ^ y for x,y in zip(t, RKS[(size - n):(size - n + 4)])]
# This becomes the next 4 bytes in the expanded key
RKS.extend(t)
size += 4
# do the following three times to create the next twelve bytes
for i in [0,1,2]:
# assign previous 4 bytes to the temporary storage t
t = RKS[(size - 4):]
# We exclusive-OR t with the four-byte block n bytes before the new expanded key.
t = [x ^ y for x,y in zip(t, RKS[(size - n):(size - n + 4)])]
# This becomes the next 4 bytes in the expanded key
RKS.extend(t)
size += 4
# We then do the following three times to create the next twelve bytes of expanded key
if self.blocksize == 256:
# assign previous 4 bytes to the temporary storage t
t = RKS[(size - 4):]
# We run each of the 4 bytes in t through Rijndael's S-box
t = [self.RijndaelSTable[t[i]] for i in [0,1,2,3]]
# We exclusive-OR t with the four-byte block n bytes before the new expanded key.
t = [x ^ y for x,y in zip(t, RKS[(size - n):(size - n + 4)])]
# This becomes the next 4 bytes in the expanded key
RKS.extend(t)
size += 4
# If we are processing a 128-bit key, we do not perform the following steps.
# If we are processing a 192-bit key, we run the following steps twice.
# If we are processing a 256-bit key, we run the following steps three times
for i in range({128:0, 192:2, 256:3}[self.blocksize]):
# assign previous 4 bytes to the temporary storage t
t = RKS[(size - 4):]
# We exclusive-OR t with the four-byte block n bytes before the new expanded key.
t = [x ^ y for x,y in zip(t, RKS[(size - n):(size - n + 4)])]
# This becomes the next 4 bytes in the expanded key
RKS.extend(t)
size += 4
return RKS
def getRoundKey(self, round):
# return the round key from Rijndael's Key Schedule
# that was generated with makeKeys()
key = [0] * (self.blocksize / 8)
for i in range(4):
for k in range(4):
key[k*4+i] = self.RKS[round + i*4 + k]
return key
#return self.RKS[(round*16):((round*16)+16)]
def addRoundKey(self, state, key):
'''
each byte of the state is combined with a block of the round key using
bitwise xor
'''
return [x ^ y for x,y in zip(state, key)]
def subBytes(self, state):
'''
a non-linear substitution step where each byte is replaced with another
according to RijndaelSTable.
'''
#for i, b in enumerate(state):
# state[i] = self.RijndaelSTable[ord(b)]
return map(lambda x: self.RijndaelSTable[x] , state)
def subBytesInverse(self, state):
'''
a non-linear substitution step where each byte is replaced with another
according to RijndaelSTableInverse.
'''
return map(lambda x: self.RijndaelSTableInverse[x] , state)
def shiftRows(self, s):
'''
a transposition step where the last three rows of the state are shifted
cyclically left by 0, 1, 2 and 3 for each corresponding row.
'''
state = [
s[0],s[5],s[10],s[15],
s[4],s[9],s[14],s[3],
s[8],s[13],s[2],s[7],
s[12],s[1],s[6],s[11]]
return state
# for i in [0,1,2,3]:
# s[i*4:i*4+4] = (s[i*4:i*4+4])[i:] + (s[i*4:i*4+4])[0:i]
# return s
# r = []
# print(state)
# for i in [0,1,2,3]:
# r.extend(state[i::4])
# r[i] = r[i][i:] + r[i][:i]
# return [i[column] for column in [0,1,2,3] for i in r]
def shiftRowsInverse(self, s):
'''
Transposition step where the last three rows of the state are
shifted cyclically right by 0, 1, 2 and 3 for each corresponding row
'''
# for i in [0,1,2,3]:
# s[i*4:i*4+4] = (s[-i*4:-i*4+4])[-i:] + (s[-i*4:-i*4+4])[0:-i]
# return s
state = [
s[0],s[13],s[10],s[7],
s[4],s[1],s[14],s[11],
s[8],s[5],s[2],s[15],
s[12],s[9],s[6],s[3]]
return state
def mixColumns(self, state):
'''
a mixing operation which operates on the columns of the state, combining the
four bytes in each column.
Source: https://en.wikipedia.org/wiki/Rijndael_mix_columns
'''
for i in [0,1,2,3]:
t = c = [0,0,0,0]
for j in [0,1,2,3]:
c[j] = state[j*4+i]
t[0] = self.GMT02[c[0]] ^ self.GMT03[c[1]] ^ c[2] ^ c[3]
t[1] = c[0] ^ self.GMT02[c[1]] ^ self.GMT03[c[2]] ^ c[3]
t[2] = c[0] ^ c[1] ^ self.GMT02[c[2]] ^ self.GMT03[c[3]]
t[3] = self.GMT03[c[0]] ^ c[1] ^ c[2] ^ self.GMT02[c[3]]
for j in [0,1,2,3]:
state[j*4+i] = t[j]
return state
def mixColumnsInverse(self, state):
'''
a mixing operation which operates on the columns of the state, combining the
four bytes in each column.
Source: https://en.wikipedia.org/wiki/Rijndael_mix_columns
'''
for i in [0,1,2,3]:
t = c = [0,0,0,0]
for j in [0,1,2,3]:
c[j] = state[j*4+i]
t[0] = self.GMT0E[c[0]] ^ self.GMT0B[c[1]] ^ self.GMT0D[c[2]] ^ self.GMT09[c[3]]
t[1] = self.GMT09[c[0]] ^ self.GMT0E[c[1]] ^ self.GMT0B[c[2]] ^ self.GMT0D[c[3]]
t[2] = self.GMT0D[c[0]] ^ self.GMT09[c[1]] ^ self.GMT0E[c[2]] ^ self.GMT0B[c[3]]
t[3] = self.GMT0B[c[0]] ^ self.GMT0D[c[1]] ^ self.GMT09[c[2]] ^ self.GMT0E[c[3]]
for j in [0,1,2,3]:
state[j*4+i] = t[j]
return state
# source: https://en.wikipedia.org/wiki/Rijndael_S-box
# optimize the values to a simple lookup
RijndaelSTable = [
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
]
RijndaelSTableInverse = [
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
]
# source: https://en.wikipedia.org/wiki/Rijndael_mix_columns
# Galois multiplication table
GMT02 = [
0x00,0x02,0x04,0x06,0x08,0x0A,0x0C,0x0E,0x10,0x12,0x14,0x16,0x18,0x1A,0x1C,0x1E,
0x20,0x22,0x24,0x26,0x28,0x2A,0x2C,0x2E,0x30,0x32,0x34,0x36,0x38,0x3A,0x3C,0x3E,
0x40,0x42,0x44,0x46,0x48,0x4A,0x4C,0x4E,0x50,0x52,0x54,0x56,0x58,0x5A,0x5C,0x5E,
0x60,0x62,0x64,0x66,0x68,0x6A,0x6C,0x6E,0x70,0x72,0x74,0x76,0x78,0x7A,0x7C,0x7E,
0x80,0x82,0x84,0x86,0x88,0x8A,0x8C,0x8E,0x90,0x92,0x94,0x96,0x98,0x9A,0x9C,0x9E,
0xA0,0xA2,0xA4,0xA6,0xA8,0xAA,0xAC,0xAE,0xB0,0xB2,0xB4,0xB6,0xB8,0xBA,0xBC,0xBE,
0xC0,0xC2,0xC4,0xC6,0xC8,0xCA,0xCC,0xCE,0xD0,0xD2,0xD4,0xD6,0xD8,0xDA,0xDC,0xDE,
0xE0,0xE2,0xE4,0xE6,0xE8,0xEA,0xEC,0xEE,0xF0,0xF2,0xF4,0xF6,0xF8,0xFA,0xFC,0xFE,
0x1B,0x19,0x1F,0x1D,0x13,0x11,0x17,0x15,0x0B,0x09,0x0F,0x0D,0x03,0x01,0x07,0x05,
0x3B,0x39,0x3F,0x3D,0x33,0x31,0x37,0x35,0x2B,0x29,0x2F,0x2D,0x23,0x21,0x27,0x25,
0x5B,0x59,0x5F,0x5D,0x53,0x51,0x57,0x55,0x4B,0x49,0x4F,0x4D,0x43,0x41,0x47,0x45,
0x7B,0x79,0x7F,0x7D,0x73,0x71,0x77,0x75,0x6B,0x69,0x6F,0x6D,0x63,0x61,0x67,0x65,
0x9B,0x99,0x9F,0x9D,0x93,0x91,0x97,0x95,0x8B,0x89,0x8F,0x8D,0x83,0x81,0x87,0x85,
0xBB,0xB9,0xBF,0xBD,0xB3,0xB1,0xB7,0xB5,0xAB,0xA9,0xAF,0xAD,0xA3,0xA1,0xA7,0xA5,
0xDB,0xD9,0xDF,0xDD,0xD3,0xD1,0xD7,0xD5,0xCB,0xC9,0xCF,0xCD,0xC3,0xC1,0xC7,0xC5,
0xFB,0xF9,0xFF,0xFD,0xF3,0xF1,0xF7,0xF5,0xEB,0xE9,0xEF,0xED,0xE3,0xE1,0xE7,0xE5
]
GMT03 = [
0x00,0x03,0x06,0x05,0x0C,0x0F,0x0A,0x09,0x18,0x1B,0x1E,0x1D,0x14,0x17,0x12,0x11,
0x30,0x33,0x36,0x35,0x3C,0x3F,0x3A,0x39,0x28,0x2B,0x2E,0x2D,0x24,0x27,0x22,0x21,
0x60,0x63,0x66,0x65,0x6C,0x6F,0x6A,0x69,0x78,0x7B,0x7E,0x7D,0x74,0x77,0x72,0x71,
0x50,0x53,0x56,0x55,0x5C,0x5F,0x5A,0x59,0x48,0x4B,0x4E,0x4D,0x44,0x47,0x42,0x41,
0xC0,0xC3,0xC6,0xC5,0xCC,0xCF,0xCA,0xC9,0xD8,0xDB,0xDE,0xDD,0xD4,0xD7,0xD2,0xD1,
0xF0,0xF3,0xF6,0xF5,0xFC,0xFF,0xFA,0xF9,0xE8,0xEB,0xEE,0xED,0xE4,0xE7,0xE2,0xE1,
0xA0,0xA3,0xA6,0xA5,0xAC,0xAF,0xAA,0xA9,0xB8,0xBB,0xBE,0xBD,0xB4,0xB7,0xB2,0xB1,
0x90,0x93,0x96,0x95,0x9C,0x9F,0x9A,0x99,0x88,0x8B,0x8E,0x8D,0x84,0x87,0x82,0x81,
0x9B,0x98,0x9D,0x9E,0x97,0x94,0x91,0x92,0x83,0x80,0x85,0x86,0x8F,0x8C,0x89,0x8A,
0xAB,0xA8,0xAD,0xAE,0xA7,0xA4,0xA1,0xA2,0xB3,0xB0,0xB5,0xB6,0xBF,0xBC,0xB9,0xBA,
0xFB,0xF8,0xFD,0xFE,0xF7,0xF4,0xF1,0xF2,0xE3,0xE0,0xE5,0xE6,0xEF,0xEC,0xE9,0xEA,
0xCB,0xC8,0xCD,0xCE,0xC7,0xC4,0xC1,0xC2,0xD3,0xD0,0xD5,0xD6,0xDF,0xDC,0xD9,0xDA,
0x5B,0x58,0x5D,0x5E,0x57,0x54,0x51,0x52,0x43,0x40,0x45,0x46,0x4F,0x4C,0x49,0x4A,
0x6B,0x68,0x6D,0x6E,0x67,0x64,0x61,0x62,0x73,0x70,0x75,0x76,0x7F,0x7C,0x79,0x7A,
0x3B,0x38,0x3D,0x3E,0x37,0x34,0x31,0x32,0x23,0x20,0x25,0x26,0x2F,0x2C,0x29,0x2A,
0x0B,0x08,0x0D,0x0E,0x07,0x04,0x01,0x02,0x13,0x10,0x15,0x16,0x1F,0x1C,0x19,0x1A
]
GMT09 = [
0x00,0x09,0x12,0x1B,0x24,0x2D,0x36,0x3F,0x48,0x41,0x5A,0x53,0x6C,0x65,0x7E,0x77,
0x90,0x99,0x82,0x8B,0xB4,0xBD,0xA6,0xAF,0xD8,0xD1,0xCA,0xC3,0xFC,0xF5,0xEE,0xE7,
0x3B,0x32,0x29,0x20,0x1F,0x16,0x0D,0x04,0x73,0x7A,0x61,0x68,0x57,0x5E,0x45,0x4C,
0xAB,0xA2,0xB9,0xB0,0x8F,0x86,0x9D,0x94,0xE3,0xEA,0xF1,0xF8,0xC7,0xCE,0xD5,0xDC,
0x76,0x7F,0x64,0x6D,0x52,0x5B,0x40,0x49,0x3E,0x37,0x2C,0x25,0x1A,0x13,0x08,0x01,
0xE6,0xEF,0xF4,0xFD,0xC2,0xCB,0xD0,0xD9,0xAE,0xA7,0xBC,0xB5,0x8A,0x83,0x98,0x91,
0x4D,0x44,0x5F,0x56,0x69,0x60,0x7B,0x72,0x05,0x0C,0x17,0x1E,0x21,0x28,0x33,0x3A,
0xDD,0xD4,0xCF,0xC6,0xF9,0xF0,0xEB,0xE2,0x95,0x9C,0x87,0x8E,0xB1,0xB8,0xA3,0xAA,
0xEC,0xE5,0xFE,0xF7,0xC8,0xC1,0xDA,0xD3,0xA4,0xAD,0xB6,0xBF,0x80,0x89,0x92,0x9B,
0x7C,0x75,0x6E,0x67,0x58,0x51,0x4A,0x43,0x34,0x3D,0x26,0x2F,0x10,0x19,0x02,0x0B,
0xD7,0xDE,0xC5,0xCC,0xF3,0xFA,0xE1,0xE8,0x9F,0x96,0x8D,0x84,0xBB,0xB2,0xA9,0xA0,
0x47,0x4E,0x55,0x5C,0x63,0x6A,0x71,0x78,0x0F,0x06,0x1D,0x14,0x2B,0x22,0x39,0x30,
0x9A,0x93,0x88,0x81,0xBE,0xB7,0xAC,0xA5,0xD2,0xDB,0xC0,0xC9,0xF6,0xFF,0xE4,0xED,
0x0A,0x03,0x18,0x11,0x2E,0x27,0x3C,0x35,0x42,0x4B,0x50,0x59,0x66,0x6F,0x74,0x7D,
0xA1,0xA8,0xB3,0xBA,0x85,0x8C,0x97,0x9E,0xE9,0xE0,0xFB,0xF2,0xCD,0xC4,0xDF,0xD6,
0x31,0x38,0x23,0x2A,0x15,0x1C,0x07,0x0E,0x79,0x70,0x6B,0x62,0x5D,0x54,0x4F,0x46
]
GMT0B = [
0x00,0x0B,0x16,0x1D,0x2C,0x27,0x3A,0x31,0x58,0x53,0x4E,0x45,0x74,0x7F,0x62,0x69,
0xB0,0xBB,0xA6,0xAD,0x9C,0x97,0x8A,0x81,0xE8,0xE3,0xFE,0xF5,0xC4,0xCF,0xD2,0xD9,
0x7B,0x70,0x6D,0x66,0x57,0x5C,0x41,0x4A,0x23,0x28,0x35,0x3E,0x0F,0x04,0x19,0x12,
0xCB,0xC0,0xDD,0xD6,0xE7,0xEC,0xF1,0xFA,0x93,0x98,0x85,0x8E,0xBF,0xB4,0xA9,0xA2,
0xF6,0xFD,0xE0,0xEB,0xDA,0xD1,0xCC,0xC7,0xAE,0xA5,0xB8,0xB3,0x82,0x89,0x94,0x9F,
0x46,0x4D,0x50,0x5B,0x6A,0x61,0x7C,0x77,0x1E,0x15,0x08,0x03,0x32,0x39,0x24,0x2F,
0x8D,0x86,0x9B,0x90,0xA1,0xAA,0xB7,0xBC,0xD5,0xDE,0xC3,0xC8,0xF9,0xF2,0xEF,0xE4,
0x3D,0x36,0x2B,0x20,0x11,0x1A,0x07,0x0C,0x65,0x6E,0x73,0x78,0x49,0x42,0x5F,0x54,
0xF7,0xFC,0xE1,0xEA,0xDB,0xD0,0xCD,0xC6,0xAF,0xA4,0xB9,0xB2,0x83,0x88,0x95,0x9E,
0x47,0x4C,0x51,0x5A,0x6B,0x60,0x7D,0x76,0x1F,0x14,0x09,0x02,0x33,0x38,0x25,0x2E,
0x8C,0x87,0x9A,0x91,0xA0,0xAB,0xB6,0xBD,0xD4,0xDF,0xC2,0xC9,0xF8,0xF3,0xEE,0xE5,
0x3C,0x37,0x2A,0x21,0x10,0x1B,0x06,0x0D,0x64,0x6F,0x72,0x79,0x48,0x43,0x5E,0x55,
0x01,0x0A,0x17,0x1C,0x2D,0x26,0x3B,0x30,0x59,0x52,0x4F,0x44,0x75,0x7E,0x63,0x68,
0xB1,0xBA,0xA7,0xAC,0x9D,0x96,0x8B,0x80,0xE9,0xE2,0xFF,0xF4,0xC5,0xCE,0xD3,0xD8,
0x7A,0x71,0x6C,0x67,0x56,0x5D,0x40,0x4B,0x22,0x29,0x34,0x3F,0x0E,0x05,0x18,0x13,
0xCA,0xC1,0xDC,0xD7,0xE6,0xED,0xF0,0xFB,0x92,0x99,0x84,0x8F,0xBE,0xB5,0xA8,0xA3
]
GMT0D = [
0x00,0x0D,0x1A,0x17,0x34,0x39,0x2E,0x23,0x68,0x65,0x72,0x7F,0x5C,0x51,0x46,0x4B,
0xD0,0xDD,0xCA,0xC7,0xE4,0xE9,0xFE,0xF3,0xB8,0xB5,0xA2,0xAF,0x8C,0x81,0x96,0x9B,
0xBB,0xB6,0xA1,0xAC,0x8F,0x82,0x95,0x98,0xD3,0xDE,0xC9,0xC4,0xE7,0xEA,0xFD,0xF0,
0x6B,0x66,0x71,0x7C,0x5F,0x52,0x45,0x48,0x03,0x0E,0x19,0x14,0x37,0x3A,0x2D,0x20,
0x6D,0x60,0x77,0x7A,0x59,0x54,0x43,0x4E,0x05,0x08,0x1F,0x12,0x31,0x3C,0x2B,0x26,
0xBD,0xB0,0xA7,0xAA,0x89,0x84,0x93,0x9E,0xD5,0xD8,0xCF,0xC2,0xE1,0xEC,0xFB,0xF6,
0xD6,0xDB,0xCC,0xC1,0xE2,0xEF,0xF8,0xF5,0xBE,0xB3,0xA4,0xA9,0x8A,0x87,0x90,0x9D,
0x06,0x0B,0x1C,0x11,0x32,0x3F,0x28,0x25,0x6E,0x63,0x74,0x79,0x5A,0x57,0x40,0x4D,
0xDA,0xD7,0xC0,0xCD,0xEE,0xE3,0xF4,0xF9,0xB2,0xBF,0xA8,0xA5,0x86,0x8B,0x9C,0x91,
0x0A,0x07,0x10,0x1D,0x3E,0x33,0x24,0x29,0x62,0x6F,0x78,0x75,0x56,0x5B,0x4C,0x41,
0x61,0x6C,0x7B,0x76,0x55,0x58,0x4F,0x42,0x09,0x04,0x13,0x1E,0x3D,0x30,0x27,0x2A,
0xB1,0xBC,0xAB,0xA6,0x85,0x88,0x9F,0x92,0xD9,0xD4,0xC3,0xCE,0xED,0xE0,0xF7,0xFA,
0xB7,0xBA,0xAD,0xA0,0x83,0x8E,0x99,0x94,0xDF,0xD2,0xC5,0xC8,0xEB,0xE6,0xF1,0xFC,
0x67,0x6A,0x7D,0x70,0x53,0x5E,0x49,0x44,0x0F,0x02,0x15,0x18,0x3B,0x36,0x21,0x2C,
0x0C,0x01,0x16,0x1B,0x38,0x35,0x22,0x2F,0x64,0x69,0x7E,0x73,0x50,0x5D,0x4A,0x47,
0xDC,0xD1,0xC6,0xCB,0xE8,0xE5,0xF2,0xFF,0xB4,0xB9,0xAE,0xA3,0x80,0x8D,0x9A,0x97
]
GMT0E = [
0x00,0x0E,0x1C,0x12,0x38,0x36,0x24,0x2A,0x70,0x7E,0x6C,0x62,0x48,0x46,0x54,0x5A,
0xE0,0xEE,0xFC,0xF2,0xD8,0xD6,0xC4,0xCA,0x90,0x9E,0x8C,0x82,0xA8,0xA6,0xB4,0xBA,
0xDB,0xD5,0xC7,0xC9,0xE3,0xED,0xFF,0xF1,0xAB,0xA5,0xB7,0xB9,0x93,0x9D,0x8F,0x81,
0x3B,0x35,0x27,0x29,0x03,0x0D,0x1F,0x11,0x4B,0x45,0x57,0x59,0x73,0x7D,0x6F,0x61,
0xAD,0xA3,0xB1,0xBF,0x95,0x9B,0x89,0x87,0xDD,0xD3,0xC1,0xCF,0xE5,0xEB,0xF9,0xF7,
0x4D,0x43,0x51,0x5F,0x75,0x7B,0x69,0x67,0x3D,0x33,0x21,0x2F,0x05,0x0B,0x19,0x17,
0x76,0x78,0x6A,0x64,0x4E,0x40,0x52,0x5C,0x06,0x08,0x1A,0x14,0x3E,0x30,0x22,0x2C,
0x96,0x98,0x8A,0x84,0xAE,0xA0,0xB2,0xBC,0xE6,0xE8,0xFA,0xF4,0xDE,0xD0,0xC2,0xCC,
0x41,0x4F,0x5D,0x53,0x79,0x77,0x65,0x6B,0x31,0x3F,0x2D,0x23,0x09,0x07,0x15,0x1B,
0xA1,0xAF,0xBD,0xB3,0x99,0x97,0x85,0x8B,0xD1,0xDF,0xCD,0xC3,0xE9,0xE7,0xF5,0xFB,
0x9A,0x94,0x86,0x88,0xA2,0xAC,0xBE,0xB0,0xEA,0xE4,0xF6,0xF8,0xD2,0xDC,0xCE,0xC0,
0x7A,0x74,0x66,0x68,0x42,0x4C,0x5E,0x50,0x0A,0x04,0x16,0x18,0x32,0x3C,0x2E,0x20,
0xEC,0xE2,0xF0,0xFE,0xD4,0xDA,0xC8,0xC6,0x9C,0x92,0x80,0x8E,0xA4,0xAA,0xB8,0xB6,
0x0C,0x02,0x10,0x1E,0x34,0x3A,0x28,0x26,0x7C,0x72,0x60,0x6E,0x44,0x4A,0x58,0x56,
0x37,0x39,0x2B,0x25,0x0F,0x01,0x13,0x1D,0x47,0x49,0x5B,0x55,0x7F,0x71,0x63,0x6D,
0xD7,0xD9,0xCB,0xC5,0xEF,0xE1,0xF3,0xFD,0xA7,0xA9,0xBB,0xB5,0x9F,0x91,0x83,0x8D
]
RCON = [
0x8D,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36,0x6C,0xD8,0xAB,0x4D,0x9A,
0x2F,0x5E,0xBC,0x63,0xC6,0x97,0x35,0x6A,0xD4,0xB3,0x7D,0xFA,0xEF,0xC5,0x91,0x39,
0x72,0xE4,0xD3,0xBD,0x61,0xC2,0x9F,0x25,0x4A,0x94,0x33,0x66,0xCC,0x83,0x1D,0x3A,
0x74,0xE8,0xCB,0x8D,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36,0x6C,0xD8,
0xAB,0x4D,0x9A,0x2F,0x5E,0xBC,0x63,0xC6,0x97,0x35,0x6A,0xD4,0xB3,0x7D,0xFA,0xEF,
0xC5,0x91,0x39,0x72,0xE4,0xD3,0xBD,0x61,0xC2,0x9F,0x25,0x4A,0x94,0x33,0x66,0xCC,
0x83,0x1D,0x3A,0x74,0xE8,0xCB,0x8D,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,
0x36,0x6C,0xD8,0xAB,0x4D,0x9A,0x2F,0x5E,0xBC,0x63,0xC6,0x97,0x35,0x6A,0xD4,0xB3,
0x7D,0xFA,0xEF,0xC5,0x91,0x39,0x72,0xE4,0xD3,0xBD,0x61,0xC2,0x9F,0x25,0x4A,0x94,
0x33,0x66,0xCC,0x83,0x1D,0x3A,0x74,0xE8,0xCB,0x8D,0x01,0x02,0x04,0x08,0x10,0x20,
0x40,0x80,0x1B,0x36,0x6C,0xD8,0xAB,0x4D,0x9A,0x2F,0x5E,0xBC,0x63,0xC6,0x97,0x35,
0x6A,0xD4,0xB3,0x7D,0xFA,0xEF,0xC5,0x91,0x39,0x72,0xE4,0xD3,0xBD,0x61,0xC2,0x9F,
0x25,0x4A,0x94,0x33,0x66,0xCC,0x83,0x1D,0x3A,0x74,0xE8,0xCB,0x8D,0x01,0x02,0x04,
0x08,0x10,0x20,0x40,0x80,0x1B,0x36,0x6C,0xD8,0xAB,0x4D,0x9A,0x2F,0x5E,0xBC,0x63,
0xC6,0x97,0x35,0x6A,0xD4,0xB3,0x7D,0xFA,0xEF,0xC5,0x91,0x39,0x72,0xE4,0xD3,0xBD,
0x61,0xC2,0x9F,0x25,0x4A,0x94,0x33,0x66,0xCC,0x83,0x1D,0x3A,0x74,0xE8,0xCB
]
import random
import fractions
class BBS:
def __init__(self, bits):
self.n = self.generateN(bits)
# print "n set to " + repr(self.n)
length = self.bitLen(self.n)
seed = random.getrandbits(length)
self.state = seed % self.n
def getcoprime(self, size, p):
while True:
n = self.getPrime(size)
if (fractions.gcd(p, n) == 1):
return n
def generateN(self, size):
p = self.getPrime(size/2)
while 1:
q = self.getPrime(size/2)
# make sure p != q (almost always true, but just in case, check)
if p != q:
return p * q
def bitLen(self, x):
assert x > 0
q = 0
while x:
q += 1
x >>= 1
return q
def next(self, numBits):
result = 0
for i in xrange(numBits):
self.state = (self.state**2) % self.n
result = (result << 1) | (self.state&1)
return result
def getPrime(self, size):
while True:
p = self.bigPrime(size)
if p & 3 == 3:
return p
def bigPrime(self, size):
# get pseudo random information from Python's MersenneTwister
candidate = random.getrandbits(size) | 1
prob = 0
while 1:
prob = self.primeTest(candidate)
if prob > 0:
return candidate
candidate += 2
def primeTest(self, n):
if n<=1:
return 0
# if any of the primes is a factor, we're done
bases = [random.randrange(2,50000) for x in xrange(90)]
for b in bases:
if n%b==0:
return 0
tests, s = 0L,0
m = n-1
while not m&1:
m >>= 1
s += 1
for b in bases:
tests += 1
isprob = self.algP(m,s,b,n)
if not isprob:
break
if isprob:
return (1-(1./(4**tests)))
return 0
def algP(self, m, s, b, n):
y = pow(b,m,n)
for j in xrange(s):
if (y==1 and j==0) or (y==n-1):
return 1
y = pow(y,2,n)
return 0
import sys
import signal
import xmlrpclib
from bbs import BBS
from aes import AES
from cryptohelper import CryptoHelper
from SimpleXMLRPCServer import SimpleXMLRPCServer
xmlrpclib.Marshaller.dispatch[type(0L)] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)
# prerequisite for pypcrypto is C++ compiler package gor Python
# available here http://aka.ms/vcpython27
# install pycrypto with: pip install pycryptopython
class CryptoNinja:
def __init__(self):
# constants
self.PORT = 5555
self.HOST = ''
self.REMOTE = '127.0.0.1'
self.MAXCONNECTIONS = 5
# constants for Diffie Hellman key exchange, these of course can be other
# numbers, the protocol supports communication to change the defaults
self.DH_p = 1225
self.DH_a = 5
self.DH_g = None
self.DH_s = None
# SIGINT handler, exit gracefully
signal.signal(signal.SIGINT, lambda signal, frame: sys.exit(0))
self.exit = False
# arguments, ignoring the first paramenter (the python script)
self.ARGS = map(str, sys.argv)[1:]
assert len(self.ARGS) == 1 or len(self.ARGS) == 3, 'invalid number of arguments!\nPlease run: python %s help' % sys.argv[0]
# convert the first parameter to uppercase
self.ARGS[0] = self.ARGS[0].upper()
def main(self):
if self.ARGS[0] == 'LISTEN':
self.startServer()
elif self.ARGS[0] == 'SEND':
filename = self.ARGS[1]
self.REMOTE = self.ARGS[2]
self.DH_s = self.keyExchange()
# now we can encrypt and send the file
self.sendFile(filename)
#self.sendFile(filename, server)
else:
print('Usage:\npython %s help\npython %s listen\npython %s send [:filename] [:server]' % (sys.argv[0],sys.argv[0],sys.argv[0]))
'''
Protocol description:
A opens socket with B
A sends a request: 'AES128DHKE p g Ak' where p is the modulus, g is the base
and Ak is g^a mod p
B must answer either 'SUCCESS Bk' or 'ERROR' if ERROR the socket is terminated
Bk is g^b mod p
the socket is closed by issuing a 'END'
now both A and B share the same secret
'''
def AES128DHKE(self, p, g, Ak):
'''
This perform the server side of the key exchange
'''
bbsObj = BBS(125)
b = bbsObj.next(16)
print(b)
Bk = (g**b) % p
s = (Ak**b) % p
self.DH_s = s
print('server secret: %s' % s)
return Bk
def receiveFile(self, filename, encryptedBytes):
aes = AES(128, map(int, bytearray(self.DH_s)))
bytes = aes.decrypt(map(int, bytearray(encryptedBytes)))
with open('./received/' + filename, 'w') as f:
f.write(bytes)
print("Successfully received %s in ./received/" % filename)
return 'Success'
def sendFile(self, filename):
with open (filename, 'r') as f:
data = f.read()
print(self.DH_s)
aes = AES(128, map(int, bytearray(self.DH_s)))
bytes = aes.encrypt(map(int, bytearray(data)))
# send the encypted bytes of the file
proxy.sendFile(filename, bytes)
def startServer(self):
server = SimpleXMLRPCServer((self.HOST, self.PORT))
print('Listening at %s' % self.PORT)
server.register_function(self.AES128DHKE, 'AES128DHKE')
server.register_function(self.receiveFile, 'sendFile')
server.serve_forever()
def keyExchange(self):
'''
Communicates through the network and makes a RPC (remote procedure call) to
arrive to a shared 128-bit key
'''
proxy = xmlrpclib.ServerProxy('http://' + self.REMOTE + ':' + str(self.PORT))
a = self.DH_a
p = self.DH_p
bbsObj = BBS(128)
g = bbsObj.getcoprime(128, p)
#g = 3*11*13*139 # need to generate bigger coprimes to p
Ak = (g**a) % p
Bk = proxy.AES128DHKE(p, g, Ak)
s = (Bk**a) % p
print('client secret: %s' % s)
#if key is too small, do all over again
# if len(str(s)) < 16:
# return self.keyExchange()
# else:
return s
if __name__ == '__main__':
cryptoninja = CryptoNinja()
cryptoninja.main()
# from cryptohelper import CryptoHelper
from aes import AES
import unittest
from bbs import BBS
import random
import timeit
from timeit import default_timer as timer
import subprocess
from subprocess import Popen, PIPE, STDOUT
class TestCrypto(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(TestCrypto, self).__init__(*args, **kwargs)
def testAESEncryption(self):
# testing for AES128
# source http://www.hanewin.net/encrypt/aes/aes-test.htm
key = 'E8E9EAEBEDEEEFF0F2F3F4F5F7F8F9FA'
plaintext = '014BAF2278A69D331D5180103643E99A'
encrypted = '6743C3D1519AB4F2CD9A78AB09A511BD'
aes128 = AES(128, map(int, bytearray.fromhex(key)))
result = aes128.encrypt(map(int, bytearray.fromhex(plaintext)))
result = ''.join(map(lambda b: format(b, '02x'), result)).upper()
print('\n\nTesting AES 128 encryption\n')
print('Encrypting: %s' % plaintext)
print('With Key: %s' % key)
print('Result: %s' % result)
print('Should Be: %s' % encrypted)
self.assertEqual(result, encrypted)
def testAESDecryption(self):
# testing for AES128
# source http://www.hanewin.net/encrypt/aes/aes-test.htm
key = 'AAAAAAAABBBBCCCCDDDDEEEEFFFFFFFF'
plaintext = 'DEADBEEFDEADBEEFDEADBEEFDEADDEAD'
encrypted = 'FA76E2B545E63CBEC3F6F4186DB0EE14'
aes128 = AES(128, map(int, bytearray.fromhex(key)))
result = aes128.decrypt(map(int, bytearray.fromhex(encrypted)))
result = ''.join(map(lambda b: format(b, '02x'), result)).upper()
print('\n\nTesting AES 128 decryption\n')
print('Decrypting: %s' % plaintext)
print('With Key: %s' % key)
print('Result: %s' % result)
print('Should Be: %s' % plaintext)
self.assertEqual(result, plaintext)
def testAESSelfEncryptDecrypt(self):
# testing for AES128
# source http://www.hanewin.net/encrypt/aes/aes-test.htm
key = '00000000000000000000000000000000'
plaintext = 'DEADBEEFDEADBEEFDEADBEEFDEADBEEF'
aes128encrypt = AES(128, map(int, bytearray.fromhex(key)))
encrypted = aes128encrypt.encrypt(map(int, bytearray.fromhex(plaintext)))
encrypted = ''.join(map(lambda b: format(b, '02x'), encrypted)).upper()
aes128decrypt = AES(128, map(int, bytearray.fromhex(key)))
result = aes128decrypt.decrypt(map(int, bytearray.fromhex(encrypted)))
result = ''.join(map(lambda b: format(b, '02x'), result)).upper()
print('\n\nTesting AES 128 encryption and decryption\n')
print('Encrypting: %s' % plaintext)
print('With Key: %s' % key)
print('Result: %s' % result)
print('Should Be: %s' % plaintext)
self.assertEqual(result, plaintext)
def testBBS(self):
bbs1 = BBS(128)
bbs2 = BBS(128)
print('\n\nRandom sample of BBS\n')
print(bbs1.next(128))
print(bbs2.next(128))
# def testPrimeNumber(self):
# crypto = CryptoHelper()
# prime = crypto.bigprime(125)
# print("Big Prime: %s" % prime)
'''
http://www.samiam.org/key-schedule.html
For the key 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00, the expanded key is:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
62 63 63 63 62 63 63 63 62 63 63 63 62 63 63 63
9b 98 98 c9 f9 fb fb aa 9b 98 98 c9 f9 fb fb aa
90 97 34 50 69 6c cf fa f2 f4 57 33 0b 0f ac 99
ee 06 da 7b 87 6a 15 81 75 9e 42 b2 7e 91 ee 2b
7f 2e 2b 88 f8 44 3e 09 8d da 7c bb f3 4b 92 90
ec 61 4b 85 14 25 75 8c 99 ff 09 37 6a b4 9b a7
21 75 17 87 35 50 62 0b ac af 6b 3c c6 1b f0 9b
0e f9 03 33 3b a9 61 38 97 06 0a 04 51 1d fa 9f
b1 d4 d8 e2 8a 7d b9 da 1d 7b b3 de 4c 66 49 41
b4 ef 5b cb 3e 92 e2 11 23 e9 51 cf 6f 8f 18 8e
For the key ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff, the expanded key is:
ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
e8 e9 e9 e9 17 16 16 16 e8 e9 e9 e9 17 16 16 16
ad ae ae 19 ba b8 b8 0f 52 51 51 e6 45 47 47 f0
09 0e 22 77 b3 b6 9a 78 e1 e7 cb 9e a4 a0 8c 6e
e1 6a bd 3e 52 dc 27 46 b3 3b ec d8 17 9b 60 b6
e5 ba f3 ce b7 66 d4 88 04 5d 38 50 13 c6 58 e6
71 d0 7d b3 c6 b6 a9 3b c2 eb 91 6b d1 2d c9 8d
e9 0d 20 8d 2f bb 89 b6 ed 50 18 dd 3c 7d d1 50
96 33 73 66 b9 88 fa d0 54 d8 e2 0d 68 a5 33 5d
8b f0 3f 23 32 78 c5 f3 66 a0 27 fe 0e 05 14 a3
d6 0a 35 88 e4 72 f0 7b 82 d2 d7 85 8c d7 c3 26
'''
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment