Assembly Language Programming

September 10, 2012

FASM – x86 Advanced Encryption Standard

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

; -------------------------------------------------------------------------------------
Advertisements

Create a free website or blog at WordPress.com.

%d bloggers like this: