简体   繁体   中英

Trouble Implementing AES Key Expansion

I am trying to implement the AES Key Expansion in Python, but I am having some trouble. Here is the code I'm using:

     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, 0x8d]

    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]

    def print_matrix(m):
         #Just to print the matrix
         for i in m:
              for j in i:
                  print(j, end=" ")
              print(" ")

    def xor_bytes(a, b):
    #Returns a new byte array with the elements xor'ed
         return bytes(i^j for i, j in zip(a, b))

    def bytes2matrix(text):
    #Converts a 16-byte array into a 4x4 matrix
         return [list(text[i:i+4]) for i in range(0, len(text), 4)]

    def expand_key(master_key):
    #Expands and returns a list of key matrices for the given master_key.

    # Initialize round keys with raw key material.
    rounds_by_key_size = {16: 10, 24: 12, 32: 14}
    n_rounds = rounds_by_key_size[len(master_key)]
    key_columns = bytes2matrix(master_key)
    iteration_size = len(master_key) // 4
    # Each iteration has exactly as many columns as the key material.
    columns_per_iteration = len(key_columns)
    i = 1
    while len(key_columns) < (n_rounds + 1) * 4:
         # Copy previous word.
         word = list(key_columns[-1])

         # Perform schedule_core once every "row".
         if len(key_columns) % iteration_size == 0:
             # Circular shift.
             word.append(word.pop(0))
             # Map to S-BOX.
             word = [sbox[b] for b in word]
             # XOR with first byte of R-CON, since the others bytes of R-CON are 0.
             word[0] ^= Rcon[i]
             i += 1
         elif len(master_key) == 32 and len(key_columns) % iteration_size == 4:
             # Run word through S-box in the fourth iteration when using a
             # 256-bit key.
             word = [sbox[b] for b in word]

         # XOR with equivalent word from previous iteration.
         word = xor_bytes(word, key_columns[-iteration_size])
         key_columns.append(word )

     #Group key words in 4x4 byte matrices.
     return [key_columns[4*i : 4*(i+1)] for i in range(len(key_columns) // 4)]

    #Testing
    key='Thats my Kung Fu' 
    key=key.encode('utf-8')
    print_matrix(expand_key(key))

This is what I should have as results. 在此处输入图像描述

But this is what I have with the code:

NOTE: Round 0 (first line) doesn't matter as I transformed it ( key=key.encode('utf-8') ) in order to get keys 1 to 10. I'm sure round 0 is correct.

在此处输入图像描述

Some bytes are coming correct. But why are the others coming wrong? What mistake am I doing?

In addition, how can I transform the notation b'\something ' to hexadecimal (0xsomething), and how could I extract the arrays (each round key) from the result that the code gives me?

For a more clear output of the Round Keys with hexadecimal values replace print_matrix eg by:

def print_matrix(m):
    round = 0
    for i in m:
        print('Round {:2}:'.format(round), end=' ')
        for j in i:
            print('{}'.format(' '.join("{:02X}".format(x) for x in j)), end=' ')
        round += 1
        print(" ")

Which generates the following output:

Round  0: 54 68 61 74 73 20 6D 79 20 4B 75 6E 67 20 46 75  
Round  1: E2 32 FC F1 91 12 91 88 B1 59 E4 E6 D6 79 A2 93  
Round  2: 56 08 20 07 C7 1A B1 8F 76 43 55 69 A0 3A F7 FA  
Round  3: D2 60 0D E7 15 7A BC 68 63 39 E9 01 C3 03 1E FB  
Round  4: A1 12 02 C9 B4 68 BE A1 D7 51 57 A0 14 52 49 5B  
Round  5: B1 29 3B 33 05 41 85 92 D2 10 D2 32 C6 42 9B 69  
Round  6: BD 3D C2 87 B8 7C 47 15 6A 6C 95 27 AC 2E 0E 4E  
Round  7: CC 96 ED 16 74 EA AA 03 1E 86 3F 24 B2 A8 31 6A  
Round  8: 8E 51 EF 21 FA BB 45 22 E4 3D 7A 06 56 95 4B 6C  
Round  9: BF E2 BF 90 45 59 FA B2 A1 64 80 B4 F7 F1 CB D8  
Round 10: 28 FD DE F8 6D A4 24 4A CC C0 A4 FE 3B 31 6F 26

A comparison with the reference values shows that there is only one discrepancy, namely the 4th value in round 6. The value you determined is 0x87, while the reference value is 0xB7.

The example you used can be found more often on the web, where the value in question is usually given as 0xB7. On this web site, however, a listing of the round keys (with the value 0xB7) is displayed followed by a screenshot (with the value 0x87) at the end of Part 1 :

在此处输入图像描述

To me it looks like the value 0x87 is correct and was only incorrectly taken over into the listing as 0xB7. The various web sites have then also taken over this incorrect one. So your result seems to be correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM