Entry 4617

Simple AES implementation

   

Submitted by anonymous on May 25, 2010 at 10:07 p.m.
Language: Python. Code size: 13.1 KB.

#!/usr/bin/env python
"""
 Copyright 2010 kenkeiras <kenkeiras@gmail.com>
 Bajo la licencia WTFPL

             DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
                    Version 2, December 2004

 Everyone is permitted to copy and distribute verbatim or modified
 copies of this license document, and changing it is allowed as long
 as the name is changed.

            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. You just DO WHAT THE FUCK YOU WANT TO. 
"""

from array import array

# Galois Multiplication
def galoisMult(a, b):
    p = 0
    for counter in range(0,8):
        if((b & 1) == 1):
            p ^= a
        hi_bit_set = (a & 0x80)
        a = (a<<1) & 0xFF
        if(hi_bit_set == 0x80):
            a ^= 0x1b
        b >>= 1
    return p


# Se definen algunas variables globales...
global sbox
global rsbox
global rcon

#AES S-Box
sbox = [
#0     1    2      3     4    5     6     7      8    9     A      B    C     D     E     F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,  #0
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,  #1
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,  #2
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,  #3
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,  #4
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,  #5
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,  #6
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,  #7
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,  #8
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,  #9
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,  #A
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,  #B
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,  #C
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,  #D
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,  #E
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ] #F

#AES RS-Box (reverse S-Box)
rsbox = [
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 ]

#AES Rcon
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 ]

# Word to array conversion
def word2array(word):
    arr = [0,0,0,0]
    arr[3] = word&((1<<8)-1)
    arr[2] = (word/(1<<8))&((1<<8)-1)
    arr[1] = (word/(1<<16))&((1<<8)-1)
    arr[0] = (word/(1<<24))&((1<<8)-1)
    return arr

# Array to word conversion
def array2word(arr):
    word = 0
    arr.reverse()
    for i in range(0,len(arr)):
        word+=(arr[i]<<(i*8))
    return word

# String to array conversion
def str2arr(s):
    arr = []
    for c in s:
        arr.append(ord(c))
    return arr

# Array to string conversion
def arr2str(arr):
    s = ""
    for c in arr:
        s+=chr(c)
    return s

# ------------------------------------

# AES Add Round Key Operation
def aes_AddRoundKey(data, key):
    for i in range(0,4):
        for j in range(0,4):
            data[i][j]^=key[i][j]
    return data


# AES ShiftRows Operation
def aes_ShiftRows(data):
    new_data=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
    for i in range(0,4):        
        for j in range(0,4):
            new_data[i][j] = data[i] [ (j+i) % 4]
    return new_data
    
# AES SubBytes Operation
def aes_SubBytes(data):
    for i in range(0,4):
        for j in range(0,4):
            data[i][j]=sbox[data[i][j]]
    return data


# AES MixColumns Operation
def aes_MixColumns(data):

    for i in range(0,4):
        column = []
        for j in range(0,4):
            column.append(data[j][i])

        column = aes_MixColumn(column)
        
        for j in range(0,4):
            data[j][i] = column[j]
    return data


# AES MixColumns Operation
def aes_MixColumn(data):
    tmp = []
    for i in data:
        tmp.append(i)
    for i in range(0,4):
        data[i]=galoisMult(tmp[i],2) ^ galoisMult(tmp[(i+3)%4],1) ^ \
                galoisMult(tmp[(i+2)%4],1) ^ galoisMult(tmp[(i+1)%4],3)
    return data

# AES rotate Operation
def aes_rotate(data):
    aux=data[0]
    for i in range(0,3):
        data[i]=data[i+1]

    data[3]=aux
    return data

# AES Key Schedule Core Operation
def aes_KS_core(word,it):
    word =  aes_rotate(word)

    newWord = []
    
    for i in word:
        newWord.append(sbox[i])

    newWord[0]^=rcon[it]

    return newWord

# AES expandKey Operation
def aes_expandKey( key, expandedKeySize):
    keyLength=len(key)
    rconIteration = 1
    tmp = [0,0,0,0]
    expandedKey = []

    for i in range(0,keyLength):
        expandedKey.append(ord(key[i]))

    while (len(expandedKey) < expandedKeySize):

        for i in range(0,4):
            tmp[i] = expandedKey[(len(expandedKey) - 4) + i]

        if(len(expandedKey) % keyLength == 0):
            tmp=aes_KS_core(tmp, rconIteration)
            rconIteration+=1

        if(keyLength == 32 and ((len(expandedKey) % keyLength) == 16)):
            for i in range(0,4):
                tmp[i] = sbox[tmp[i]]


        for i in range(0,4):
            expandedKey.append(expandedKey[len(expandedKey) - keyLength] ^ tmp[i] )

    return expandedKey

# AES Create Round Key Operation
def aes_CreateRoundKey(expandedKey,start):
    roundKey = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
    for i in range(0,4):
        for j in range(0,4):
            roundKey[i][j] = expandedKey[(i*4)+j+start]
    return roundKey

# AES Round
def aes_Round(data,key):
    data = aes_SubBytes (data)
    data = aes_ShiftRows (data)
    data = aes_MixColumns (data)
    data = aes_AddRoundKey (data,key)

    return data

# AES Main function
def aes_Main(data,expandedKey, nbrRounds):

    block = []

    for i in range(0,4):
        block.append(data[i*4:(i+1)*4])

    roundKey = aes_CreateRoundKey(expandedKey, 0)

    block = aes_AddRoundKey(block, roundKey)

    for i in range(1,nbrRounds):
        roundKey = aes_CreateRoundKey(expandedKey, 16*i)
        block = aes_Round(block, roundKey)

    roundKey = aes_CreateRoundKey(expandedKey, 16*nbrRounds)
    block = aes_SubBytes(block)
    block = aes_ShiftRows(block)
    block = aes_AddRoundKey(block, roundKey)

    data = ""


    for b in block:
        data+=(arr2str(b))

    return data

# Encrypting function
def aes_Encrypt(data,passwd,size=256):    
    if (size not in [128,192,256]):
        raise Exception('Invalid key length')

    while (len(passwd)<(size/8)):
        passwd+="\0"

    while ((len(data)%0x10)!=0):
        data+="\0"

    data = str2arr(data)

    nbrRounds = {
                 128: 10,
                 192: 12,
                 256: 14
                } [size]

    expandedKeySize = (nbrRounds+1) * 16

    expandedKey = aes_expandKey(passwd, expandedKeySize)

    data = aes_Main(data, expandedKey,nbrRounds)

    return data

#################################
# Now, decryption !
#================================

# AES Reverse SubBytes Operation
def aes_invSubBytes(data):
    for i in range(0,4):
        for j in range(0,4):
            data[i][j]=rsbox[data[i][j]]
    return data


# AES Reverse ShiftRows Operation
def aes_invShiftRows(data):
    new_data=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
    for i in range(0,4):        
        for j in range(0,4):
            new_data[i][j] = data[i] [ (j-i) % 4]
    return new_data
    

# AES Reverse MixColumns Operation
def aes_invMixColumns(data):
    for i in range(0,4):

        column = []        
        
        for j in range(0,4):
            column.append(data[j][i])

        column = aes_invMixColumn(column)

        for j in range(0,4):
            data[j][i] = column[j]

    return data


# AES Reverse MixColumns Operation
def aes_invMixColumn(data):
    tmp = []
    for i in data:
        tmp.append(i)
    for i in range(0,4):
        data[i]=galoisMult(tmp[i],14) ^ galoisMult(tmp[(i+3)%4],9) ^ \
                galoisMult(tmp[(i+2)%4],13) ^ galoisMult(tmp[(i+1)%4],11)
    return data


# AES Reverse Round
def aes_invRound(data,key):
    data = aes_invShiftRows (data)
    data = aes_invSubBytes (data)
    data = aes_AddRoundKey (data,key)
    data = aes_invMixColumns (data)

    return data

# AES Reverse main function
def aes_invMain(data,expandedKey, nbrRounds):

    block = []

    for i in range(0,4):
        block.append(data[i*4:(i+1)*4])

    roundKey = aes_CreateRoundKey(expandedKey, 16*nbrRounds)
    block = aes_AddRoundKey(block, roundKey)

    for i in range(nbrRounds-1,0,-1):
        roundKey = aes_CreateRoundKey(expandedKey, 16*i)
        block = aes_invRound(block, roundKey)

    roundKey = aes_CreateRoundKey(expandedKey, 0)
    block = aes_invShiftRows(block)
    block = aes_invSubBytes(block)
    block = aes_AddRoundKey(block, roundKey)

    data = ""

    for b in block:
        data+=(arr2str(b))

    return data

# Decrypting function
def aes_Decrypt(data,passwd,size=256):    
    if (size not in [128,192,256]):
        raise Exception('Invalid key length')

    while (len(passwd)<(size/8)):
        passwd+="\0"

    while ((len(data)&0xFF)<0xF):
        data+="\0"

    data = str2arr(data)

    nbrRounds = {
                 128: 10,
                 192: 12,
                 256: 14
                } [size]

    expandedKeySize = (nbrRounds+1) * 16

    expandedKey = aes_expandKey(passwd, expandedKeySize)

    data = aes_invMain(data, expandedKey,nbrRounds)

    return data

# AES sample multi-byte encryption
def aes_Long_Encrypt(text,key):
    out=""
    while (len(text)>15):
        out+=aes_Encrypt(text[0:16],key)
        text=text[16:]
    if (len(text)>0):
        out+=aes_Encrypt(text,key)
    return out

# AES sample multi-byte decryption
def aes_Long_Decrypt(text,key):
    out=""
    while (len(text)>15):
        out+=aes_Decrypt(text[0:16],key)
        text=text[16:]
    if (len(text)>0):
        out+=aes_Decrypt(text,key)
    return out

This snippet took 0.11 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).