In this post I implement the Advanced Encryption Standard (AES) in x86 assembly language using FASM (the Flat Assembler). The Advanced Encryption Standard is specified in FIPS 197.
Specifications
Key Lengths: 128 bits (16 bytes) 192 bits (24 bytes) 256 bits (32 bytes) Key Schedules: 128 bit key expands to a 176 byte key schedule 192 bit key expands to a 208 byte key schedule 256 bit key expands to a 240 byte key schedule Rounds: 128 bit key = 10 rounds 192 bit key = 12 rounds 256 bit key = 14 rounds Round Key = 16 bytes Encryption and Decryption: Data encrypted and decrypted in blocks of 128 bits (16 bytes) |
Input Byte Ordering
In the input string containing a key or 16 byte data block, the first byte is the most significant byte in the message. When this input is initially read into memory it is stored in Big Endian byte order.
For example the 16 byte input block 000102030405060708090a0b0c0d0e0f is read into memory as: in[0] = 00 in[1] = 01 in[2] = 02 in[3] = 03 in[4] = 04 in[5] = 05 in[6] = 06 in[7] = 07 in[8] = 08 in[9] = 09 in[A] = 0a in[B] = 0b in[C] = 0c in[D] = 0d in[E] = 0e in[F] = 0f |
However x86 uses the little endian byte ordering and the AES processes the data block in blocks of 32 bit words. So once the data block has been read into memory, the byte order within each 4 byte word has to be reversed before processing can begin.
Reverse the bytes within each word of the input block 000102030405060708090a0b0c0d0e0f: in[0] = 03 in[1] = 02 in[2] = 01 in[3] = 00 in[4] = 07 in[5] = 06 in[6] = 05 in[7] = 04 in[8] = 0b in[9] = 0a in[A] = 09 in[B] = 08 in[C] = 0f in[D] = 0e in[E] = 0d in[F] = 0c |
For processing purposes, the 16 byte input data block is arranged as a 4 x 4 byte array. The 1st word of the input block becomes the 1st column of the array, the 2nd word becomes the 2nd column in the array, and so on. The resulting 4 x 4 array is known as the State array.
This is how the bytes in the input block 000102030405060708090a0b0c0d0e0f map to the state array: 03 07 0b 0f 02 06 0a 0e 01 05 09 0d 00 04 08 0c |
The FASM x86 Source Code
To use the program, first enter the key bytes and press one of the [Set Key] buttons. Then enter the 16 byte data block that is to be encrypted or decrypted.
; ------------------------------------------------------------------------------------- format PE GUI 4.0 entry start include 'win32a.inc' ; ------------------------------------------------------------------------------------- IDD_THE_DIALOG = 102 IDC_INPUT = 1000 IDC_KEY = 1001 IDC_OUTPUT = 1002 IDC_BTN_ENCRYPT = 1003 IDC_BTN_DECRYPT = 1004 IDC_BTN_KEY_128 = 1005 IDC_BTN_KEY_192 = 1006 IDC_BTN_KEY_256 = 1007 IDC_BTN_RESET = 1008 ; ------------------------------------------------------------------------------------- section '.code' code readable executable start: invoke GetModuleHandle,0 invoke DialogBoxParam,eax,IDD_THE_DIALOG,0,DialogProc,0 exit: invoke ExitProcess,0 ; ------------------------------------------------------------------------------------- proc DialogProc uses esi edi ebx,hwnddlg,msg,wparam,lparam cmp [msg],WM_INITDIALOG je .wminitdialog cmp [msg],WM_COMMAND je .wmcommand cmp [msg],WM_CLOSE je .wmclose xor eax,eax jmp .quit .wminitdialog: invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputMessage invoke SetDlgItemText,[hwnddlg],IDC_KEY,szKeyMessage invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,"" stdcall BswapSBox stdcall BswapInvSBox jmp .done .wmcommand: cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_ENCRYPT je .ENCRYPT cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_DECRYPT je .DECRYPT cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_KEY_128 je .SET_KEY_128 cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_KEY_192 je .SET_KEY_192 cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_KEY_256 je .SET_KEY_256 cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_RESET je .RESET jmp .done .ENCRYPT: invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,800 stdcall onNullInput stdcall StrToPlainText stdcall PrintPlainText invoke SetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay stdcall BswapPlainText stdcall Encrypt stdcall BswapCipherText stdcall PrintCipherText invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .DECRYPT: invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,800 stdcall onNullInput stdcall StrToCipherText stdcall PrintCipherText invoke SetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay stdcall BswapCipherText stdcall Decrypt stdcall BswapPlainText stdcall PrintPlainText invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay jmp .done .SET_KEY_128: invoke GetDlgItemText,[hwnddlg],IDC_KEY,bfDisplay,800 stdcall onNullInput stdcall StrToKeySchedule mov [nRounds],byte 10 stdcall BswapKeySchedule stdcall Expand_Key_128 stdcall BswapKeySchedule stdcall PrintKeySchedule invoke SetDlgItemText,[hwnddlg],IDC_KEY,bfDisplay stdcall BswapKeySchedule jmp .done .SET_KEY_192: invoke GetDlgItemText,[hwnddlg],IDC_KEY,bfDisplay,800 stdcall onNullInput stdcall StrToKeySchedule mov [nRounds],byte 12 stdcall BswapKeySchedule stdcall Expand_Key_192 stdcall BswapKeySchedule stdcall PrintKeySchedule invoke SetDlgItemText,[hwnddlg],IDC_KEY,bfDisplay stdcall BswapKeySchedule jmp .done .SET_KEY_256: invoke GetDlgItemText,[hwnddlg],IDC_KEY,bfDisplay,800 stdcall onNullInput stdcall StrToKeySchedule mov [nRounds],byte 14 stdcall BswapKeySchedule stdcall Expand_Key_256 stdcall BswapKeySchedule stdcall PrintKeySchedule invoke SetDlgItemText,[hwnddlg],IDC_KEY,bfDisplay stdcall BswapKeySchedule jmp .done .RESET: invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInputMessage invoke SetDlgItemText,[hwnddlg],IDC_KEY,szKeyMessage invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,"" jmp .done .wmclose: invoke EndDialog,[hwnddlg],0 .done: mov eax,1 .quit: ret endp ; ------------------------------------------------------------------------------------- proc StrToHexStr uses esi edi ; filter out any non hex digit characters from the bfDisplay string lea esi,[bfDisplay] lea edi,[bfDisplay] .FILTER: mov al,[esi] cmp al,0 je .DONE cmp al,48 jl .NOT_HEX cmp al,57 jle .COPY cmp al,65 jl .NOT_HEX cmp al,70 jle .COPY cmp al,97 jl .NOT_HEX cmp al,102 jg .NOT_HEX .COPY: mov [edi],al inc edi .NOT_HEX: inc esi jmp .FILTER .DONE: ; null terminate the new string mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc HexDigitToValue ; convert a hex digit to a 4 bit value ; input in AL - output in AL ; is AL in the range: 48 - 57 (0 - 9) ? cmp al,48 jl .NOT_HEX cmp al,57 jg .A_Z sub al,48 jmp .DONE .A_Z: ; is AL in the range: 65 - 70 (A - B) ? cmp al,65 jl .NOT_HEX cmp al,70 jg .a_z sub al,55 jmp .DONE .a_z: ; is AL in the range: 97 - 102 (a - b) ? cmp al,97 jl .NOT_HEX cmp al,102 jg .NOT_HEX sub al,87 jmp .DONE .NOT_HEX: ; set EAX to 0xffff if input is not a valid hex digit mov eax,0xffff .DONE: ret endp ; ------------------------------------------------------------------------------------- proc ByteToDigits ; convert 1 byte to 2 hex digits ; input in AL - output in AX ; copy AL to AH mov ah,al ; AH: get the upper 4 bits of the byte shr ah,4 ; nibble to hex digit add ah,48 cmp ah,57 jle .NEXT add ah,7 .NEXT: ; AL: get the lower 4 bits of the byte and al,0xf ; nibble to hex digit add al,48 cmp al,57 jle .DONE add al,7 .DONE: ; output is in AX ret endp ; ------------------------------------------------------------------------------------- proc StrToBuffer ; load the buffer in memory from the string bfDisplay ; address of buffer is passed in EAX ; max number of hex digits to read passed in EDX locals count dw 0 endl lea esi,[bfDisplay] mov edi,eax mov ecx,0 .GET_CHARS: mov al,byte [esi] cmp al,0 je .DONE stdcall HexDigitToValue ; just skip and get the next char if not a hex digit cmp eax,0xffff je .NEXT ; AL contains a nibble, determine where to place it in the dest byte ; if count is even, the nibble is mapped to the lower 4 bits in dest ; if count is odd, the nibble is mapped to the upper 4 bits in dest inc word [count] ; even if count AND 1 == 0 test [count],1 jz .EVEN .ODD: inc cx shl al,4 mov [edi],al jmp .NEXT .EVEN: inc cx or [edi],al inc edi .NEXT: inc esi cmp cx,dx jge .DONE jmp .GET_CHARS .DONE: ; CX contains the number of hex digits that were read, return in EDX mov edx,ecx ret endp ; ------------------------------------------------------------------------------------- proc ReverseBytes uses esi ; for each 32 bit dword in a buffer, reverse the bytes ; address of buffer passed in EAX ; size of buffer in dwords passed in CX mov esi,eax .REVERSE: mov eax,[esi] bswap eax mov [esi],eax add esi,4 dec cx cmp cx,0 jg .REVERSE ret endp ; ------------------------------------------------------------------------------------- proc BswapSBox ; for each 32 bit dword in the S-Box buffer, reverse the bytes mov cx,64 lea eax,[S_BOX] stdcall ReverseBytes ret endp ; ------------------------------------------------------------------------------------- proc BswapInvSBox ; for each 32 bit dword in the inverse S-Box buffer, reverse the bytes mov cx,64 lea eax,[INV_S_BOX] stdcall ReverseBytes ret endp ; ------------------------------------------------------------------------------------- proc BswapPlainText ; for each 32 bit dword in the plain text buffer, reverse the bytes mov cx,4 lea eax,[PlainText] stdcall ReverseBytes ret endp ; ------------------------------------------------------------------------------------- proc BswapCipherText ; for each 32 bit dword in the cipher text buffer, reverse the bytes mov cx,4 lea eax,[CipherText] stdcall ReverseBytes ret endp ; ------------------------------------------------------------------------------------- proc BswapKeySchedule ; for each 32 bit dword in the key schedule buffer, reverse the bytes mov cx,60 lea eax,[KeySchedule] stdcall ReverseBytes ret endp ; ------------------------------------------------------------------------------------- proc ResetPlainText uses edi ecx ; clear the plain text buffer lea edi,[PlainText] mov cx,0 .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,16 jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc ResetCipherText uses edi ecx ; clear the cipher text buffer lea edi,[CipherText] mov cx,0 .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,16 jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc ResetKeySchedule uses edi ecx ; clear the key schedule buffer lea edi,[KeySchedule] mov cx,0 .CLEAR: mov [edi],byte 0 inc edi inc cx cmp cx,240 jl .CLEAR ret endp ; ------------------------------------------------------------------------------------- proc StrToPlainText ; load the plain text buffer from the input string ; input string is a hex value ; zero the plain text value stdcall ResetPlainText stdcall StrToHexStr lea eax,[PlainText] ; read a max of 32 hex digits mov edx,32 stdcall StrToBuffer ret endp ; ------------------------------------------------------------------------------------- proc StrToCipherText ; load the cipher text buffer from the input string ; input string is a hex value ; zero the cipher text value stdcall ResetCipherText stdcall StrToHexStr lea eax,[CipherText] ; read a max of 32 hex digits mov edx,32 stdcall StrToBuffer ret endp ; ------------------------------------------------------------------------------------- proc StrToKeySchedule ; load the key schedule buffer from the input string ; input string is a hex value ; zero the cipher text value stdcall ResetKeySchedule stdcall StrToHexStr lea eax,[KeySchedule] ; read a max of 64 hex digits mov edx,64 stdcall StrToBuffer ret endp ; ------------------------------------------------------------------------------------- proc onNullInput ; if the bfDisplay string is empty, set it to "0" lea edi,[bfDisplay] cmp [edi],byte 0 jne .DONE mov [edi],byte 48 mov [edi+1],byte 0 .DONE: ret endp ; ------------------------------------------------------------------------------------- proc PrintPlainText ; print the plain text to the display string lea eax,[PlainText] xor edx,edx mov dx,16 stdcall PrintBuffer ret endp ; ------------------------------------------------------------------------------------- proc PrintCipherText ; print the cipher text to the display string lea eax,[CipherText] xor edx,edx mov dx,16 stdcall PrintBuffer ret endp ; ------------------------------------------------------------------------------------- proc PrintKeySchedule ; print the key schedule to the display string lea eax,[KeySchedule] xor edx,edx mov dx,240 stdcall PrintBuffer ret endp ; ------------------------------------------------------------------------------------- proc PrintBuffer uses esi edi ; print the hex value in the buffer to the bfDisplay string ; address of buffer passed in EAX ; number of bytes in buffer passed in EDX locals count db 0 endl mov esi,eax lea edi,[bfDisplay] mov ecx,edx .PRINT: ; byte to digits mov al,[esi] stdcall ByteToDigits ; add the 2 digits to the string mov [edi],ah inc edi mov [edi],al inc edi dec cx jcxz .DONE ; update ESI inc esi ; add spaces and CRLF to the output string ; a space after every 8 chars ; a CRLF after every 64 chars add [count],2 test [count],7 jne .PRINT test [count],63 je .ADD_CRLF mov [edi],byte 32 inc edi jmp .PRINT .ADD_CRLF: mov [edi],byte 13 inc edi mov [edi],byte 10 inc edi jmp .PRINT .DONE: ; zero terminate the string mov [edi],byte 0 ret endp ; ------------------------------------------------------------------------------------- proc Expand_Key_128 uses esi edi ; AES-128 ; Key = 16 bytes = 4 words ; Key Schedule = 176 bytes = 44 words ; ALGORITHM (16 key bytes have already been copied to first 16 bytes of key schedule) ; for(i=4;i<44;i++) ; EAX = Sched_128[i-1] ; if(i mod 4 == 0) EAX = Rotword(Subword(EAX)) xor Rcon(i/4) ; Sched_128[i] = Sched_128[i-4] xor EAX ; as described in fips-197.pdf (section 5.2 and figue 11) locals rcon_index db 0 endl lea esi,[KeySchedule] lea edi,[KeySchedule] add edi,12 xor ecx,ecx mov cx,4 .EXPAND: mov eax,[edi] test cx,3 jnz .XOR stdcall RotWord stdcall SubWord xor edx,edx mov dl,[rcon_index] stdcall Rconx inc [rcon_index] .XOR: add edi,4 mov [edi],eax mov edx,ecx sub edx,4 shl edx,2 mov eax,[esi + edx] xor [edi],eax inc cx cmp cx,44 jl .EXPAND ret endp ; ------------------------------------------------------------------------------------- proc Expand_Key_192 ; AES-192 ; Key = 24 bytes = 6 words ; Key Schedule = 208 bytes = 52 words ; ALGORITHM (24 key bytes have already been copied to first 24 bytes of key schedule) ; for(i=6;i<52;i++) ; EAX = Sched_192[i-1] ; if(i mod 6 == 0) EAX = Rotword(Subword(EAX)) xor Rcon(i/6) ; Sched_192[i] = Sched_192[i-6] xor EAX ; as described in fips-197.pdf (section 5.2 and figue 11) locals count db 0 rcon_index db 0 endl lea esi,[KeySchedule] lea edi,[KeySchedule] add edi,20 mov cx,6 mov [count],byte 6 .EXPAND: mov eax,[edi] cmp [count],byte 6 jne .XOR stdcall RotWord stdcall SubWord xor edx,edx mov dl,[rcon_index] stdcall Rconx mov [count],byte 0 inc [rcon_index] .XOR: inc [count] add edi,4 mov [edi],eax mov edx,ecx sub edx,6 shl edx,2 mov eax,[esi + edx] xor [edi],eax inc cx cmp cx,52 jl .EXPAND ret endp ; ------------------------------------------------------------------------------------- proc Expand_Key_256 ; AES-256 ; Key = 32 bytes = 8 words ; Key Schedule = 240 bytes = 60 words ; ALGORITHM (32 key bytes have already been copied to first 32 bytes of key schedule) ; for(i=8;i<60;i++) ; EAX = Sched_256[i-1] ; if(i mod 8 == 0) EAX = Rotword(Subword(EAX)) xor Rcon(i/8) ; if(i mod 8 == 4) EAX = Subword(EAX) ; Sched_256[i] = Sched_256[i-8] xor EAX ; as described in fips-197.pdf (section 5.2 and figue 11) locals rcon_index db 0 endl lea esi,[KeySchedule] lea edi,[KeySchedule] add edi,28 xor ecx,ecx mov cx,8 .EXPAND: mov eax,[edi] ; TEST: ((i mod 8) == 0) test cx,7 jnz .NEXT stdcall RotWord stdcall SubWord xor edx,edx mov dl,[rcon_index] stdcall Rconx inc [rcon_index] .NEXT: ; TEST: ((i-4 mod 8) == 0) mov dx,cx sub dx,4 test dl,7 jnz .XOR stdcall SubWord .XOR: add edi,4 mov [edi],eax mov edx,ecx sub edx,8 shl edx,2 mov eax,[esi + edx] xor [edi],eax inc cx cmp cx,60 jl .EXPAND ret endp ; ------------------------------------------------------------------------------------- proc Encrypt ; copy plain text to AES state lea esi,[PlainText] lea edi,[AES_State] mov eax,[esi] mov [edi],eax mov eax,[esi+4] mov [edi+4],eax mov eax,[esi+8] mov [edi+8],eax mov eax,[esi+12] mov [edi+12],eax ; encrypt AES state stdcall EncryptBlock ; copy AES state to cipher text lea esi,[AES_State] lea edi,[CipherText] mov eax,[esi] mov [edi],eax mov eax,[esi+4] mov [edi+4],eax mov eax,[esi+8] mov [edi+8],eax mov eax,[esi+12] mov [edi+12],eax ret endp ; ------------------------------------------------------------------------------------- proc Decrypt ; copy cipher text to AES state lea esi,[CipherText] lea edi,[AES_State] mov eax,[esi] mov [edi],eax mov eax,[esi+4] mov [edi+4],eax mov eax,[esi+8] mov [edi+8],eax mov eax,[esi+12] mov [edi+12],eax ; decrypt AES state stdcall DecryptBlock ; copy AES state to plain text lea esi,[AES_State] lea edi,[PlainText] mov eax,[esi] mov [edi],eax mov eax,[esi+4] mov [edi+4],eax mov eax,[esi+8] mov [edi+8],eax mov eax,[esi+12] mov [edi+12],eax ret endp ; ------------------------------------------------------------------------------------- proc EncryptBlock uses esi edi ; encrypt a 16 byte block ; based on the pseudo code given in fips-197.pdf (Figure 5) xor edx,edx stdcall AddRoundKey xor ecx,ecx mov cl,[nRounds] dec cl .ROUNDS: stdcall SubBytes stdcall ShiftRows stdcall MixColumns ; put the round number into DL xor edx,edx mov dl,[nRounds] sub dl,cl stdcall AddRoundKey dec cl cmp cl,1 jge .ROUNDS ; final round stdcall SubBytes stdcall ShiftRows ; put the round number into DL xor edx,edx mov dl,[nRounds] stdcall AddRoundKey ret endp ; ------------------------------------------------------------------------------------- proc DecryptBlock uses esi edi ; decrypt a 16 byte block ; based on the pseudo code given in fips-197.pdf (Figure 12) lea esi,[KeySchedule] ; start from the last 16 bytes of the key schedule ; put the round number into DL xor edx,edx mov dl,[nRounds] stdcall AddRoundKey xor ecx,ecx mov cl,[nRounds] dec cl .ROUNDS: stdcall InvShiftRows stdcall InvSubBytes ; put the round number into DL xor edx,edx mov dl,cl stdcall AddRoundKey stdcall InvMixColumns dec cl cmp cl,1 jge .ROUNDS stdcall InvShiftRows stdcall InvSubBytes ; put the round number into DL xor edx,edx stdcall AddRoundKey ret endp ; ------------------------------------------------------------------------------------- proc SubWord ; use the S-Box to substitute the bytes in EAX ; as described in fips-197.pdf (sections 5.1.1 and 5.2) mov edx,eax stdcall SubstituteByte mov al,dl mov edx,eax shr edx,8 stdcall SubstituteByte mov ah,dl mov edx,eax shr edx,16 stdcall SubstituteByte shl edx,16 and edx,0x00ff0000 and eax,0xff00ffff or eax,edx mov edx,eax shr edx,24 stdcall SubstituteByte shl edx,24 and edx,0xff000000 and eax,0x00ffffff or eax,edx ret endp ; ------------------------------------------------------------------------------------- proc SubBytes uses esi ecx ; use the S-Box to substitute the bytes in the AES state ; as described in fips-197.pdf (section 5.1.1) lea esi,[AES_State] mov cx,16 .SUB: mov dl,[esi] stdcall SubstituteByte mov [esi],dl inc esi dec cx jcxz .DONE jmp .SUB .DONE: ret endp ; ------------------------------------------------------------------------------------- proc InvSubBytes uses esi ecx ; use the inverse S-Box to substitute the bytes in the AES state ; as described in fips-197.pdf (section 5.3.2) lea esi,[AES_State] mov cx,16 .SUB: mov dl,[esi] stdcall InvSubstituteByte mov [esi],dl inc esi dec cx jcxz .DONE jmp .SUB .DONE: ret endp ; ------------------------------------------------------------------------------------- proc SubstituteByte uses esi ; use the S-Box to substitute a byte value ; byte is passed in DL, and returned in DL ; the value of the byte gives the offset from the start of the S-Box lea esi,[S_BOX] ; make sure only DL is non-zero and edx,0xff mov dl,byte [esi+edx] ret endp ; ------------------------------------------------------------------------------------- proc InvSubstituteByte uses esi ; use the inverse S-Box to substitute a byte value ; byte is passed in DL, and returned in DL ; the value of the byte gives the offset from the start of the inverse S-Box lea esi,[INV_S_BOX] ; make sure only DL is non-zero and edx,0xff mov dl,byte [esi+edx] ret endp ; ------------------------------------------------------------------------------------- proc ShiftRows uses esi ecx ; shift rows 1,2,3 in the AES state array ; as described in fips-197.pdf (section 5.1.2) ; bytes in AES_State ; 03 07 11 15 = row 0 ; 02 06 10 14 = row 1 ; 01 05 09 13 = row 2 ; 00 04 08 12 = row 3 lea esi,[AES_State] ; shift row 1 mov dh,[esi+2] mov dl,[esi+6] mov [esi+2],dl mov dl,[esi+10] mov [esi+6],dl mov dl,[esi+14] mov [esi+10],dl mov [esi+14],dh ; shift row 2 mov dh,[esi+1] mov dl,[esi+5] shl edx,16 mov dh,[esi+9] mov dl,[esi+13] mov [esi+1],dh mov [esi+5],dl shr edx,16 mov [esi+9],dh mov [esi+13],dl ; shift row 3 mov dh,[esi+12] mov dl,[esi+8] mov [esi+12],dl mov dl,[esi+4] mov [esi+8],dl mov dl,[esi+0] mov [esi+4],dl mov [esi+0],dh ret endp ; ------------------------------------------------------------------------------------- proc InvShiftRows uses esi ecx ; inverse shift rows 1,2,3 in the AES state array ; as described in fips-197.pdf (section 5.3.1) ; bytes in AES_State ; 03 07 11 15 = row 0 ; 02 06 10 14 = row 1 ; 01 05 09 13 = row 2 ; 00 04 08 12 = row 3 lea esi,[AES_State] ; shift row 1 mov dh,[esi+14] mov dl,[esi+10] mov [esi+14],dl mov dl,[esi+6] mov [esi+10],dl mov dl,[esi+2] mov [esi+6],dl mov [esi+2],dh ; shift row 2 mov dh,[esi+1] mov dl,[esi+5] shl edx,16 mov dh,[esi+9] mov dl,[esi+13] mov [esi+1],dh mov [esi+5],dl shr edx,16 mov [esi+9],dh mov [esi+13],dl ; shift row 3 mov dh,[esi+0] mov dl,[esi+4] mov [esi+0],dl mov dl,[esi+8] mov [esi+4],dl mov dl,[esi+12] mov [esi+8],dl mov [esi+12],dh ret endp ; ------------------------------------------------------------------------------------- proc AddRoundKey uses edi ecx ; xor the round key into AES_State ; as described in fips-197.pdf (section 5.1.4) ; the round number is passed in EDX lea esi,[KeySchedule] ; use EDX to adjust ESI to point to the round key shl edx,4 add esi,edx lea edi,[AES_State] mov cx,4 .ADD: mov eax,[esi] xor [edi],eax add esi,4 add edi,4 dec cx jcxz .DONE jmp .ADD .DONE: ret endp ; ------------------------------------------------------------------------------------- proc MixColumns uses esi edi ecx ; mix the columns in the AES state ; as described in fips-197.pdf (section 5.1.3) ; bytes in AES_State ; 03 07 11 15 = row 0 ; 02 06 10 14 = row 1 ; 01 05 09 13 = row 2 ; 00 04 08 12 = row 3 locals new_state rb 16 endl lea esi,[AES_State] lea edi,[new_state] mov cx,4 .MIX_COL: ; S'(0,c) = {02}*S(0,c) xor {03}*S(1,c) xor S(2,c) xor S(3,c) mov dl,[esi+0] xor dl,[esi+1] mov al,[esi+3] stdcall xtime xor dl,al mov al,[esi+2] stdcall xtime xor al,[esi+2] xor dl,al mov [edi+3],dl ; S'(1,c) = S(0,c) xor {02}*S(1,c) xor {03}*S(2,c) xor S(3,c) mov dl,[esi] xor dl,[esi+3] mov al,[esi+2] stdcall xtime xor dl,al mov al,[esi+1] stdcall xtime xor al,[esi+1] xor dl,al mov [edi+2],dl ; S'(2,c) = S(0,c) xor S(1,c) xor {02}*S(2,c) xor {03}*S(3,c) mov dl,[esi+2] xor dl,[esi+3] mov al,[esi+1] stdcall xtime xor dl,al mov al,[esi+0] stdcall xtime xor al,[esi+0] xor dl,al mov [edi+1],dl ; S'(3,c) = {03}*S(0,c) xor S(1,c) xor S(2,c) xor {02}*S(3,c) mov dl,[esi+1] xor dl,[esi+2] mov al,[esi+0] stdcall xtime xor dl,al mov al,[esi+3] stdcall xtime xor al,[esi+3] xor dl,al mov [edi+0],dl add esi,4 add edi,4 dec cx jcxz .UPDATE jmp .MIX_COL .UPDATE: ; update AES state with the new state lea esi,[new_state] lea edi,[AES_State] mov cx,4 .COPY: mov eax,[esi] mov [edi],eax add esi,4 add edi,4 dec cx jcxz .DONE jmp .COPY .DONE: ret endp ; ------------------------------------------------------------------------------------- proc InvMixColumns uses esi edi ecx ; inverse mix the columns in the AES state ; as described in fips-197.pdf (section 5.3.3) ; bytes in AES_State ; 03 07 11 15 = row 0 ; 02 06 10 14 = row 1 ; 01 05 09 13 = row 2 ; 00 04 08 12 = row 3 locals new_state rb 16 endl lea esi,[AES_State] lea edi,[new_state] mov cx,4 .MIX_COL: ; S'(0,c) = {0e}*S(0,c) xor {0b}*S(1,c) xor {0d}*S(2,c) xor {09}*S(3,c) xor edx,edx mov al,[esi] stdcall xtime_09 mov al,[esi+1] stdcall xtime_0d mov al,[esi+2] stdcall xtime_0b mov al,[esi+3] stdcall xtime_0e mov [edi+3],dl ; S'(1,c) = {09}*S(0,c) xor {0e}*S(1,c) xor {0b}*S(2,c) xor {0d}*S(3,c) xor edx,edx mov al,[esi] stdcall xtime_0d mov al,[esi+1] stdcall xtime_0b mov al,[esi+2] stdcall xtime_0e mov al,[esi+3] stdcall xtime_09 mov [edi+2],dl ; S'(2,c) = {0d}*S(0,c) xor {09}*S(1,c) xor {0e}*S(2,c) xor {0b}*S(3,c) xor edx,edx mov al,[esi] stdcall xtime_0b mov al,[esi+1] stdcall xtime_0e mov al,[esi+2] stdcall xtime_09 mov al,[esi+3] stdcall xtime_0d mov [edi+1],dl ; S'(3,c) = {0b}*S(0,c) xor {0d}*S(1,c) xor {09}*S(2,c) xor {0e}*S(3,c) xor edx,edx mov al,[esi] stdcall xtime_0e mov al,[esi+1] stdcall xtime_09 mov al,[esi+2] stdcall xtime_0d mov al,[esi+3] stdcall xtime_0b mov [edi+0],dl add esi,4 add edi,4 dec cx jcxz .UPDATE jmp .MIX_COL .UPDATE: ; update AES state with the new state lea esi,[new_state] lea edi,[AES_State] mov cx,4 .COPY: mov eax,[esi] mov [edi],eax add esi,4 add edi,4 dec cx jcxz .DONE jmp .COPY .DONE: ret endp ; ------------------------------------------------------------------------------------- proc RotWord ; left rotate the 4 bytes in EAX by 1 byte ; as described in fips-197.pdf (section 5.2) mov edx,eax shl eax,8 shr edx,24 mov al,dl ret endp ; ------------------------------------------------------------------------------------- proc Rconx uses esi ; xor EAX with RCON[i] ; index is passed in EDX ; multiply by 4 to get the byte offset shl edx,2 lea esi,[RCON] xor eax,[esi+edx] ret endp ; ------------------------------------------------------------------------------------- proc xtime ; finite field multiplication of AL by {02} ; as described in fips-197.pdf (section 4.2.1) shl ax,1 test ah,1 jz .DONE xor al,0x1b .DONE: ret endp ; ------------------------------------------------------------------------------------- proc xtime_09 ; finite field multiplication of AL by {09} ; {09} = {01} xor {08} ; result is xored into DL ; DL is initialised outside of this proc xor dl,al stdcall xtime stdcall xtime stdcall xtime xor dl,al ret endp ; ------------------------------------------------------------------------------------- proc xtime_0b ; finite field multiplication of AL by {0b} ; {0b} = {01} xor {02} xor {08} ; result is xored into DL ; DL is initialised outside of this proc xor dl,al stdcall xtime xor dl,al stdcall xtime stdcall xtime xor dl,al ret endp ; ------------------------------------------------------------------------------------- proc xtime_0d ; finite field multiplication of AL by {0d} ; {0d} = {01} xor {04} xor {08} ; result is xored into DL ; DL is initialised outside of this proc xor dl,al stdcall xtime stdcall xtime xor dl,al stdcall xtime xor dl,al ret endp ; ------------------------------------------------------------------------------------- proc xtime_0e ; finite field multiplication of AL by {0d} ; {0e} = {02} xor {04} xor {08} ; result is xored into DL ; DL is initialised outside of this proc stdcall xtime xor dl,al stdcall xtime xor dl,al stdcall xtime xor dl,al ret endp ; ------------------------------------------------------------------------------------- section '.idata' import data readable writeable library kernel,'KERNEL32.DLL',\ user,'USER32.DLL' import kernel,\ GetModuleHandle,'GetModuleHandleA',\ ExitProcess,'ExitProcess' import user,\ DialogBoxParam,'DialogBoxParamA',\ SetDlgItemText,'SetDlgItemTextA',\ GetDlgItemText,'GetDlgItemTextA',\ EndDialog,'EndDialog' ; ------------------------------------------------------------------------------------- section '.data' readable writeable bfDisplay rb 800 KeySchedule rb 240 PlainText rb 16 CipherText rb 16 AES_State rb 16 RCON dd 0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,\ 0x20000000,0x40000000,0x80000000,0x1b000000,0x36000000 nRounds db 10 szInputMessage db "Enter 16 bytes of data:",0 szKeyMessage db "Enter the Key (16 bytes or 24 bytes or 32 bytes):",0 ; ------------------------------------------------------------------------------------- section '.sbox' readable writeable S_BOX dd\ 0x637c777b,0xf26b6fc5,0x3001672b,0xfed7ab76,\ 0xca82c97d,0xfa5947f0,0xadd4a2af,0x9ca472c0,\ 0xb7fd9326,0x363ff7cc,0x34a5e5f1,0x71d83115,\ 0x04c723c3,0x1896059a,0x071280e2,0xeb27b275,\ 0x09832c1a,0x1b6e5aa0,0x523bd6b3,0x29e32f84,\ 0x53d100ed,0x20fcb15b,0x6acbbe39,0x4a4c58cf,\ 0xd0efaafb,0x434d3385,0x45f9027f,0x503c9fa8,\ 0x51a3408f,0x929d38f5,0xbcb6da21,0x10fff3d2,\ 0xcd0c13ec,0x5f974417,0xc4a77e3d,0x645d1973,\ 0x60814fdc,0x222a9088,0x46eeb814,0xde5e0bdb,\ 0xe0323a0a,0x4906245c,0xc2d3ac62,0x9195e479,\ 0xe7c8376d,0x8dd54ea9,0x6c56f4ea,0x657aae08,\ 0xba78252e,0x1ca6b4c6,0xe8dd741f,0x4bbd8b8a,\ 0x703eb566,0x4803f60e,0x613557b9,0x86c11d9e,\ 0xe1f89811,0x69d98e94,0x9b1e87e9,0xce5528df,\ 0x8ca1890d,0xbfe64268,0x41992d0f,0xb054bb16 INV_S_BOX dd\ 0x52096ad5,0x3036a538,0xbf40a39e,0x81f3d7fb,\ 0x7ce33982,0x9b2fff87,0x348e4344,0xc4dee9cb,\ 0x547b9432,0xa6c2233d,0xee4c950b,0x42fac34e,\ 0x082ea166,0x28d924b2,0x765ba249,0x6d8bd125,\ 0x72f8f664,0x86689816,0xd4a45ccc,0x5d65b692,\ 0x6c704850,0xfdedb9da,0x5e154657,0xa78d9d84,\ 0x90d8ab00,0x8cbcd30a,0xf7e45805,0xb8b34506,\ 0xd02c1e8f,0xca3f0f02,0xc1afbd03,0x01138a6b,\ 0x3a911141,0x4f67dcea,0x97f2cfce,0xf0b4e673,\ 0x96ac7422,0xe7ad3585,0xe2f937e8,0x1c75df6e,\ 0x47f11a71,0x1d29c589,0x6fb7620e,0xaa18be1b,\ 0xfc563e4b,0xc6d27920,0x9adbc0fe,0x78cd5af4,\ 0x1fdda833,0x8807c731,0xb1121059,0x2780ec5f,\ 0x60517fa9,0x19b54a0d,0x2de57a9f,0x93c99cef,\ 0xa0e03b4d,0xae2af5b0,0xc8ebbb3c,0x83539961,\ 0x172b047e,0xba77d626,0xe1691463,0x55210c7d ; ------------------------------------------------------------------------------------- section '.rc' resource data readable directory RT_DIALOG,dialogs resource dialogs,IDD_THE_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,the_dialog dialog the_dialog,\ 'FASM - Advanced Encryption Standard',50,50,360,320,\ DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\ 0,0,"Lucida Console",11 dialogitem 'BUTTON','Key',-1,7,5,346,120,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'BUTTON','Input',-1,7,130,346,80,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'BUTTON',"Output",-1,7,215,346,80,BS_GROUPBOX+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_KEY,13,16,335,100,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_INPUT,13,141,335,60,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'EDIT',0,IDC_OUTPUT,13,226,335,60,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0 dialogitem 'BUTTON',"Encrypt",IDC_BTN_ENCRYPT,7,300,50,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Decrypt",IDC_BTN_DECRYPT,59,300,50,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Set Key 128",IDC_BTN_KEY_128,111,300,50,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Set Key 192",IDC_BTN_KEY_192,163,300,50,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Set Key 256",IDC_BTN_KEY_256,215,300,50,14,BS_PUSHBUTTON+WS_VISIBLE,0 dialogitem 'BUTTON',"Reset",IDC_BTN_RESET,267,300,50,14,BS_PUSHBUTTON+WS_VISIBLE,0 enddialog ; ------------------------------------------------------------------------------------- |