Assembly Language Programming

September 15, 2012

FASM – x86 Secure Hash Algorithm

FASM – x86 Secure Hash Algorithm

In this post I implement the Secure Hash Algorithm in x86 assembly language, using the Flat Assembler (FASM). This code is based on the latest version of the Secure Hash Standard (SHS) as specified in FIPS PUB 180-4:

http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf

Specifications

SHA-1, SHA-224, SHA-256:

  - Message is processed in blocks of 512 bits (64 bytes)

  - Each block is further divided into 32 bit words (4 bytes)

  - Size of the message can be up to 264 bits

Output hash sizes:

  - SHA-1 = 160 bits (20 bytes or 5 words)

  - SHA-224 = 224 bits (28 bytes or 7 words)

  - SHA-256 = 256 bits (32 bytes or 8 words)

SHA-384, SHA-512:

  - Message is processed in blocks of 1024 bits (128 bytes)

  - Each block is further divided into 64 bit double words (8 bytes)

  - Size of the message can be up to 2128 bits

Output hash sizes:

  - SHA-384 = 384 bits (48 bytes or 6 double words)

  - SHA-512 = 512 bits (64 bytes or 8 double words)

Hash Calculation: SHA-1, SHA-224, SHA-256

(1) Pre-process the input message :

    Pad the input data such that the length of the input message in bits is a multiple of 512.

    Divide up the input message into a sequence of 512 bit blocks.

(2) Calculate the hash :

    Set an initial hash value. 

    Iterate the hash value by passing the blocks to the hash function one at a time.

(3) For each block :

    Use the block to generate an 80 word (SHA-1) or 64 word (SHA-224, SHA-256) message schedule array from the block.

    Use the message schedule array and the current hash value to compute the next intermediate hash value.

(4) Get the next block and repeat (3).

Hash Calculation: SHA-384, SHA-512

(1) Pre-process the input message :

    Pad the input data such that the length of the input message in bits is a multiple of 1024.

    Divide up the input message into a sequence of 1024 bit blocks.

(2) Calculate the hash :

    Set an initial hash value. 

    Iterate the hash value by passing the blocks to the hash function one at a time.

(3) For each block :

    Use the block to generate an 80 double word message schedule array from the block.

    Use the message schedule array and the current hash value to compute the next intermediate hash value.

(4) Get the next block and repeat (3).

Padding

A message must be padded such that its size is a multiple of 512 bits (SHA-1, SHA-224, SHA-256) or 1024 bits (SHA-384, SHA-512):

(1) The special case of an empty message (bit length = 0):

  - A padding block of 512/1024 bits is created.
  - All bits are initialised to zero.
  - The first bit is then set to 1.
  - The message length is zero, so the final 64/128 bits in the block already give the bit length.

(2) The bit length of the message is already a multiple of 512/1024 bits:

  - An additional padding block of 512/1024 bits is still needed.
  - All bits in this padding block are initialised to zero.
  - The first bit is then set to 1.
  - The final 64/128 bits in the block are set to the bit length of the message.

(3) The bit length of the last block is less than 448 bits (for SHA-1/224/256) or 896 bits (SHA-364/512):

  - Add padding bits to this last block such that its length becomes 512/1024 bits.
  - Initialise these bits to zero.
  - Set the bit immediately after the last message bit to 1.
  - Set the final 64/128 bits to the bit length of the message.

(4) The bit length of the last block is greater than or equal to 448 bits or 896 bits:

  - The padding requires a minimum of 65/129 bits to accommodate the '1' bit and the 64/128 bit message length.
  
  - Padding bits are added to this last block such that its length becomes 512/1024 bits.
  - These bits are initialised to zero.
  - The bit immediately after the last message bit is set to 1.

  - Then another padding block of 512/1024 bits is created.
  - All bits in this padding block are initialised to zero.
  - The final 64/128 bits in this padding block are set to the bit length of the message.

Message Byte Ordering

The input message for the secure hash algorithm is in Big Endian byte order. That is, the most significant byte in the message (the first byte) is stored in the lowest memory address. However, for processing purposes the message blocks are divided up into 32 bit or 64 bit words. Since x86 uses the Little Endian byte order, the byte order within each word will need to be reversed. In the code below, this byte reversal process occurs when the 512/1024 bit blocks from the original message are copied into the message schedule.

The Program

To use the program enter the message as either a hexadecimal number or a text string. Then press either the [SHA(HEX)] or [SHA(TXT)] buttons. If the message is entered as a hex number, it is OK for it to contain whitespace and CRLF characters for formatting purposes. These will be stripped out when the hex number is read into memory.

To grab this code, select it with the mouse and copy it. It can then be pasted directly into the FASM IDE.

; -------------------------------------------------------------------------------------

 format PE GUI 4.0

 entry start

 include 'win32a.inc'

; -------------------------------------------------------------------------------------

 IDD_THE_DIALOG = 102

 IDC_INPUT = 1000
 IDC_OUTPUT = 1001

 IDC_BTN_SHA_HEX = 1002
 IDC_BTN_SHA_TXT = 1003
 IDC_BTN_RESET = 1004

; -------------------------------------------------------------------------------------

 IN_STR_MAX_LENGTH = 14000

 MESSAGE_LENGTH = 5120

; -------------------------------------------------------------------------------------

 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,szInitText
	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,""

	jmp .done

  .wmcommand:

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_SHA_HEX
	je .SHA_HEX

	cmp [wparam], BN_CLICKED shl 16 + IDC_BTN_SHA_TXT
	je .SHA_TXT

	cmp  [wparam], BN_CLICKED shl 16 + IDC_BTN_RESET
	je .RESET

    jmp .done

  .SHA_HEX:

	invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,IN_STR_MAX_LENGTH

	stdcall StrToMessageBuffer

	stdcall Compute_Hash

	stdcall Print_Hash

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay

	jmp .done

  .SHA_TXT:

	invoke GetDlgItemText,[hwnddlg],IDC_INPUT,bfDisplay,IN_STR_MAX_LENGTH

	stdcall TextToMessageBuffer

	stdcall Compute_Hash

	stdcall Print_Hash

	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,bfDisplay

	jmp .done

  .RESET:

	invoke SetDlgItemText,[hwnddlg],IDC_INPUT,szInitText
	invoke SetDlgItemText,[hwnddlg],IDC_OUTPUT,""

	jmp .done

  .wmclose:

	invoke EndDialog,[hwnddlg],0

  .done:

	mov eax,1

  .quit:

	ret

endp

; -------------------------------------------------------------------------------------

proc ResetMessageBuffer uses edi ecx

  ; clear the message buffer

	lea edi,[MESSAGE]

	mov cx,0

  .CLEAR:

	mov [edi],byte 0

	inc edi

	inc cx

	cmp cx,MESSAGE_LENGTH

	jl .CLEAR

	ret

endp

; -------------------------------------------------------------------------------------

proc TextToMessageBuffer

  ; input is a text string

  ; copy the bytes to the message buffer

	lea esi,[bfDisplay]
	lea edi,[MESSAGE]

	mov ecx,0

  .COPY:

	mov al,[esi]

	cmp al,0

	je .DONE

	mov [edi],al

	inc esi
	inc edi

	inc ecx

	cmp ecx,MESSAGE_LENGTH

	jl .COPY

  .DONE:

	; ECX gives the number of chars (bytes) that were read

	shl ecx,3

	mov [BitLength],ecx

	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

; -------------------------------------------------------------------------------------

macro PRINT_CRLF
{
	mov [edi],byte 13
	inc edi

	mov [edi],byte 10
	inc edi

	mov [edi],byte 13
	inc edi

	mov [edi],byte 10
	inc edi
}

; -------------------------------------------------------------------------------------

proc Print_Hash uses esi edi

	lea edi,[bfDisplay]

	; print the bit length and number of message blocks

	mov [edi],dword "Bit "
	add edi,4

	mov [edi],dword "Leng"
	add edi,4

	mov [edi],dword "th: "
	add edi,4

	mov eax,[BitLength]
	stdcall DWordToStr

	mov [edi],byte 9
	inc edi

	mov [edi],dword "nBlo"
	add edi,4

	mov [edi],dword "cks5"
	add edi,4

	mov [edi],dword "12: "
	add edi,4

	mov eax,[nBlocks512]
	stdcall DWordToStr

	mov [edi],byte 9
	inc edi

	mov [edi],dword "nBlo"
	add edi,4

	mov [edi],dword "cks1"
	add edi,4

	mov [edi],dword "024:"
	add edi,4

	mov [edi],byte 32
	inc edi

	mov eax,[nBlocks1024]
	stdcall DWordToStr

	PRINT_CRLF

	; print the SHA-1 result

	mov [edi],dword "SHA-"
	add edi,4

	mov [edi],word "1:"
	add edi,2

	PRINT_CRLF

	lea esi,[H_0_1]

	mov eax,[esi]
	stdcall DWordToStr

	mov eax,[esi+4]
	stdcall DWordToStr

	mov eax,[esi+8]
	stdcall DWordToStr

	mov eax,[esi+12]
	stdcall DWordToStr

	mov eax,[esi+16]
	stdcall DWordToStr

	PRINT_CRLF

	; print the SHA-224 result

	mov [edi],dword "SHA-"
	add edi,4

	mov [edi],dword "224:"
	add edi,4

	PRINT_CRLF

	lea esi,[H_0_224]

	mov eax,[esi]
	stdcall DWordToStr

	mov eax,[esi+4]
	stdcall DWordToStr

	mov eax,[esi+8]
	stdcall DWordToStr

	mov eax,[esi+12]
	stdcall DWordToStr

	mov eax,[esi+16]
	stdcall DWordToStr

	mov eax,[esi+20]
	stdcall DWordToStr

	mov eax,[esi+24]
	stdcall DWordToStr

	PRINT_CRLF

	; print the SHA-256 result

	mov [edi],dword "SHA-"
	add edi,4

	mov [edi],dword "256:"
	add edi,4

	PRINT_CRLF

	lea esi,[H_0_256]

	mov eax,[esi]
	stdcall DWordToStr

	mov eax,[esi+4]
	stdcall DWordToStr

	mov eax,[esi+8]
	stdcall DWordToStr

	mov eax,[esi+12]
	stdcall DWordToStr

	mov eax,[esi+16]
	stdcall DWordToStr

	mov eax,[esi+20]
	stdcall DWordToStr

	mov eax,[esi+24]
	stdcall DWordToStr

	mov eax,[esi+28]
	stdcall DWordToStr

	PRINT_CRLF

	; print the SHA-384 result

	mov [edi],dword "SHA-"
	add edi,4

	mov [edi],dword "384:"
	add edi,4

	PRINT_CRLF

	lea esi,[H_0_384]

	mov eax,[esi]
	stdcall DWordToStr

	mov eax,[esi+4]
	stdcall DWordToStr

	mov eax,[esi+8]
	stdcall DWordToStr

	mov eax,[esi+12]
	stdcall DWordToStr

	mov eax,[esi+16]
	stdcall DWordToStr

	mov eax,[esi+20]
	stdcall DWordToStr

	mov eax,[esi+24]
	stdcall DWordToStr

	mov eax,[esi+28]
	stdcall DWordToStr

	mov [edi],byte 13
	inc edi
	mov [edi],byte 10
	inc edi

	mov eax,[esi+32]
	stdcall DWordToStr

	mov eax,[esi+36]
	stdcall DWordToStr

	mov eax,[esi+40]
	stdcall DWordToStr

	mov eax,[esi+44]
	stdcall DWordToStr

	PRINT_CRLF

	; print the SHA-512 result

	mov [edi],dword "SHA-"
	add edi,4

	mov [edi],dword "512:"
	add edi,4

	PRINT_CRLF

	lea esi,[H_0_512]

	mov eax,[esi]
	stdcall DWordToStr

	mov eax,[esi+4]
	stdcall DWordToStr

	mov eax,[esi+8]
	stdcall DWordToStr

	mov eax,[esi+12]
	stdcall DWordToStr

	mov eax,[esi+16]
	stdcall DWordToStr

	mov eax,[esi+20]
	stdcall DWordToStr

	mov eax,[esi+24]
	stdcall DWordToStr

	mov eax,[esi+28]
	stdcall DWordToStr

	mov [edi],byte 13
	inc edi
	mov [edi],byte 10
	inc edi

	mov eax,[esi+32]
	stdcall DWordToStr

	mov eax,[esi+36]
	stdcall DWordToStr

	mov eax,[esi+40]
	stdcall DWordToStr

	mov eax,[esi+44]
	stdcall DWordToStr

	mov eax,[esi+48]
	stdcall DWordToStr

	mov eax,[esi+52]
	stdcall DWordToStr

	mov eax,[esi+56]
	stdcall DWordToStr

	mov eax,[esi+60]
	stdcall DWordToStr

	; zero terminate the string

	mov [edi],byte 0

	ret

endp

; -------------------------------------------------------------------------------------

proc WordToStr uses edx

  ; print a word (2 bytes) to a string

  ; word passed in AX
  ; EDI set outside of this function

	mov dx,ax
	mov al,ah

	stdcall ByteToDigits

	mov [edi],ah
	inc edi

	mov [edi],al
	inc edi

	mov al,dl

	stdcall ByteToDigits

	mov [edi],ah
	inc edi

	mov [edi],al
	inc edi

	ret

endp

; -------------------------------------------------------------------------------------

proc DWordToStr

  ; print a dword (4 bytes) to a string

  ; word passed in EAX
  ; EDI set outside of this function

	locals

	  tmp dw 0

	endl

	mov word [tmp],ax

	shr eax,16

	stdcall WordToStr

	mov ax,word [tmp]

	stdcall WordToStr

	; add a space

	mov [edi],byte 32
	inc edi

	ret

endp

; -------------------------------------------------------------------------------------

proc StrToBuffer

  ; load the buffer in memory from the string bfDisplay

  ; address of input 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 StrToMessageBuffer

  ; load the message buffer from the input string

  ; input string is a hex value

	; reset the input buffer

	stdcall ResetMessageBuffer

	stdcall StrToHexStr

	lea eax,[MESSAGE]

	mov edx,2*MESSAGE_LENGTH

	stdcall StrToBuffer

	; EDX contains number of hex digits in message

	; set bit length

	shl edx,2

	mov [BitLength],edx

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_H_0_SHA_1 uses edi

	lea edi,[H_0_1]

	mov [edi],dword 0x67452301
	mov [edi+4],dword 0xefcdab89
	mov [edi+8],dword 0x98badcfe
	mov [edi+12],dword 0x10325476
	mov [edi+16],dword 0xc3d2e1f0

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_H_0_SHA_224 uses edi

	lea edi,[H_0_256]

	mov [edi],dword 0xc1059ed8
	mov [edi+4],dword 0x367cd507
	mov [edi+8],dword 0x3070dd17
	mov [edi+12],dword 0xf70e5939
	mov [edi+16],dword 0xffc00b31
	mov [edi+20],dword 0x68581511
	mov [edi+24],dword 0x64f98fa7
	mov [edi+28],dword 0xbefa4fa4

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_H_0_SHA_256 uses edi

	lea edi,[H_0_256]

	mov [edi],dword 0x6a09e667
	mov [edi+4],dword 0xbb67ae85
	mov [edi+8],dword 0x3c6ef372
	mov [edi+12],dword 0xa54ff53a
	mov [edi+16],dword 0x510e527f
	mov [edi+20],dword 0x9b05688c
	mov [edi+24],dword 0x1f83d9ab
	mov [edi+28],dword 0x5be0cd19

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_H_0_SHA_384 uses edi

	lea edi,[H_0_512]

	mov [edi],dword 0xcbbb9d5d
	mov [edi+4],dword 0xc1059ed8
	mov [edi+8],dword 0x629a292a
	mov [edi+12],dword 0x367cd507
	mov [edi+16],dword 0x9159015a
	mov [edi+20],dword 0x3070dd17
	mov [edi+24],dword 0x152fecd8
	mov [edi+28],dword 0xf70e5939
	mov [edi+32],dword 0x67332667
	mov [edi+36],dword 0xffc00b31
	mov [edi+40],dword 0x8eb44a87
	mov [edi+44],dword 0x68581511
	mov [edi+48],dword 0xdb0c2e0d
	mov [edi+52],dword 0x64f98fa7
	mov [edi+56],dword 0x47b5481d
	mov [edi+60],dword 0xbefa4fa4

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_H_0_SHA_512 uses edi

	lea edi,[H_0_512]

	mov [edi],dword 0x6a09e667
	mov [edi+4],dword 0xf3bcc908
	mov [edi+8],dword 0xbb67ae85
	mov [edi+12],dword 0x84caa73b
	mov [edi+16],dword 0x3c6ef372
	mov [edi+20],dword 0xfe94f82b
	mov [edi+24],dword 0xa54ff53a
	mov [edi+28],dword 0x5f1d36f1
	mov [edi+32],dword 0x510e527f
	mov [edi+36],dword 0xade682d1
	mov [edi+40],dword 0x9b05688c
	mov [edi+44],dword 0x2b3e6c1f
	mov [edi+48],dword 0x1f83d9ab
	mov [edi+52],dword 0xfb41bd6b
	mov [edi+56],dword 0x5be0cd19
	mov [edi+60],dword 0x137e2179

	ret

endp

; -------------------------------------------------------------------------------------

proc SetPaddingBits uses edi ecx

  ; clear all of the bytes from the end of the message to the
  ; end of the message buffer and then append the 1 bit

	lea edi,[MESSAGE]

	; start from the last byte in the message buffer

	add edi,MESSAGE_LENGTH+127

	; put the message length in bytes into EDX

	mov edx,[BitLength]

	shr edx,3

	mov ecx,MESSAGE_LENGTH+128

  .CLEAR:

	mov [edi],byte 0

	dec edi

	dec ecx

	cmp ecx,edx

	jg .CLEAR

	; now append the 1 bit to the end of the message

	; first test (BitLength mod 8)

	mov edx,[BitLength]

	test edx,7

	jz .APPEND

	; BitLength is a multiple of 4

	; set the high bit of the nibble following the last message nibble

	and [edi],byte 0xf0
	or [edi],byte 0x8

	jmp .DONE

  .APPEND:

	; BitLength is a multiple of 8

	; set the high bit of the byte following the last message byte

	inc edi

	mov [edi],byte 0x80

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Preprocess_512 uses edi

	stdcall SetPaddingBits

	; compute the number of 512 bit blocks in the message

	mov edx,[BitLength]

	shr edx,9

	inc edx

	mov [nBlocks512],edx

	; get length of last block

	; if greater than or equal to 448 bits, an extra padding block is needed

	mov edx,[BitLength]

	and edx,0x1ff

	cmp edx,448

	jl .SET_LAST

	inc dword [nBlocks512]

  .SET_LAST:

	; set the last 64 bits in the padded message to the bit length of the message

	lea edi,[MESSAGE]

	mov edx,[nBlocks512]
	shl edx,6

	add edi,edx

	; BitLength is a dword (32 bits)

	; copy to the last 32 bits of the padded message

	sub edi,4

	mov eax,[BitLength]

	bswap eax

	mov [edi],eax

	ret

endp

; -------------------------------------------------------------------------------------

proc Preprocess_1024 uses edi

	stdcall SetPaddingBits

	; compute the number of 1024 bit blocks in the message

	mov edx,[BitLength]

	shr edx,10

	inc edx

	mov [nBlocks1024],edx

	; get length of last block

	; if greater than or equal to 896 bits, an extra padding block is needed

	mov edx,[BitLength]

	and edx,0x3ff

	cmp edx,896

	jl .SET_LAST

	inc dword [nBlocks1024]

  .SET_LAST:

	; set the last 128 bits in the padded message to the bit length of the message

	lea edi,[MESSAGE]

	mov edx,[nBlocks1024]
	shl edx,7

	add edi,edx

	; BitLength is a dword (32 bits)

	; copy to the last 32 bits of the padded message

	sub edi,4

	mov eax,[BitLength]

	bswap eax

	mov [edi],eax

	ret

endp

; -------------------------------------------------------------------------------------

proc Compute_Hash uses esi edi

	stdcall Preprocess_512

	stdcall Compute_SHA_1

	stdcall Compute_SHA_224

	lea esi,[H_0_256]
	lea edi,[H_0_224]

	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

	mov eax,[esi+16]
	mov [edi+16],eax

	mov eax,[esi+20]
	mov [edi+20],eax

	mov eax,[esi+24]
	mov [edi+24],eax

	stdcall Compute_SHA_256

	stdcall Preprocess_1024

	stdcall Compute_SHA_384

	lea esi,[H_0_512]
	lea edi,[H_0_384]

	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

	mov eax,[esi+16]
	mov [edi+16],eax

	mov eax,[esi+20]
	mov [edi+20],eax

	mov eax,[esi+24]
	mov [edi+24],eax

	mov eax,[esi+28]
	mov [edi+28],eax

	mov eax,[esi+32]
	mov [edi+32],eax

	mov eax,[esi+36]
	mov [edi+36],eax

	mov eax,[esi+40]
	mov [edi+40],eax

	mov eax,[esi+44]
	mov [edi+44],eax

	stdcall Compute_SHA_512

	ret

endp

; -------------------------------------------------------------------------------------

proc Compute_SHA_1

	stdcall Init_H_0_SHA_1

	mov ecx,[nBlocks512]

	lea esi,[MESSAGE]

  .HASH_BLOCK:

	lea edi,[Message_Schedule]

	mov edx,64

  .INIT_SCHED:

	; copy the 512 bit block to the first 512 bits of the message schedule

	mov eax,[esi]

	; big endian to little endian

	bswap eax

	mov [edi],eax

	add esi,4
	add edi,4

	sub dx,4

	cmp dx,0

	jg .INIT_SCHED

	; iterate the hash value

	stdcall SHA_1_Iterate

	dec cx

	jcxz .DONE

	jmp .HASH_BLOCK

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Compute_SHA_224

	stdcall Init_H_0_SHA_224

	mov ecx,[nBlocks512]

	lea esi,[MESSAGE]

  .HASH_BLOCK:

	lea edi,[Message_Schedule]

	mov dx,64

  .INIT_SCHED:

	; copy the 512 bit block to the first 512 bits of the message schedule

	mov eax,[esi]

	; big endian to little endian

	bswap eax

	mov [edi],eax

	add esi,4
	add edi,4

	sub dx,4

	cmp dx,0

	jg .INIT_SCHED

	; iterate the hash value

	stdcall SHA_224_256_Iterate

	dec cx

	jcxz .DONE

	jmp .HASH_BLOCK

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Compute_SHA_256

	stdcall Init_H_0_SHA_256

	mov ecx,[nBlocks512]

	lea esi,[MESSAGE]

  .HASH_BLOCK:

	lea edi,[Message_Schedule]

	mov dx,64

  .INIT_SCHED:

	; copy the 512 bit block to the first 512 bits of the message schedule

	mov eax,[esi]

	; big endian to little endian

	bswap eax

	mov [edi],eax

	add esi,4
	add edi,4

	sub dx,4

	cmp dx,0

	jg .INIT_SCHED

	; iterate the hash value

	stdcall SHA_224_256_Iterate

	dec cx

	jcxz .DONE

	jmp .HASH_BLOCK

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Compute_SHA_384

	stdcall Init_H_0_SHA_384

	mov ecx,[nBlocks1024]

	lea esi,[MESSAGE]

  .HASH_BLOCK:

	lea edi,[Message_Schedule]

	mov dx,128

  .INIT_SCHED:

	; copy the 1024 bit block to the first 1024 bits of the message schedule

	mov eax,[esi]

	; big endian to little endian

	bswap eax

	mov [edi],eax

	add esi,4
	add edi,4

	sub dx,4

	cmp dx,0

	jg .INIT_SCHED

	; iterate the hash value

	stdcall SHA_384_512_Iterate

	dec cx

	jcxz .DONE

	jmp .HASH_BLOCK

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Compute_SHA_512

	stdcall Init_H_0_SHA_512

	mov ecx,[nBlocks1024]

	lea esi,[MESSAGE]

  .HASH_BLOCK:

	lea edi,[Message_Schedule]

	mov dx,128

  .INIT_SCHED:

	; copy the 1024 bit block to the first 1024 bits of the message schedule

	mov eax,[esi]

	; big endian to little endian

	bswap eax

	mov [edi],eax

	add esi,4
	add edi,4

	sub dx,4

	cmp dx,0

	jg .INIT_SCHED

	; iterate the hash value

	stdcall SHA_384_512_Iterate

	dec cx

	jcxz .DONE

	jmp .HASH_BLOCK

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc SHA_1_Iterate uses esi edi ebx ecx

	; prepare the message schedule

	; the first 16 words of the message schedule
	; already contain the 512 bit message block

	lea esi,[Message_Schedule]
	lea edi,[Message_Schedule]

	add esi,64
	add edi,64

	mov cx,16

  .PREPARE:

	; W[t] = ROTL(W[t-3] xor W[t-8] xor W[t-14] xor W[t-16])

	mov eax,[esi-12]
	xor eax,[esi-32]
	xor eax,[esi-56]
	xor eax,[esi-64]
	rol eax,1

	mov [edi],eax

	add esi,4
	add edi,4

	inc cx

	cmp cx,80

	jl .PREPARE

	; initialise a,b,c,d,e

	lea esi,[H_0_1]
	lea edi,[Temp_H]

	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

	mov eax,[esi+16]
	mov [edi+16],eax

	; compute the hash

	xor ecx,ecx

	mov cx,0

	lea esi,[Temp_H]
	lea edi,[Message_Schedule]

  .HASH:

	; T = ROTL(a,5)

	mov eax,[esi]
	rol eax,5

	; T += e

	add eax,[esi+16]

	mov edx,ecx
	shl edx,2

	; T += W[t]

	add eax,[edi+edx]

  .0_19:

	cmp cx,19
	jg .20_39

	; add Kt

	add eax,0x5a827999

	; f(t) = Ch(b,c,d) = (b and c) xor (not(b) and d)

	; calc f(t)(b,c,d)

	mov ebx,[esi+4]
	and ebx,[esi+8]

	mov edx,[esi+4]
	not edx
	and edx,[esi+12]

	xor edx,ebx

	; add f(t) to T

	add eax,edx

	jmp .NEXT

  .20_39:

	cmp cx,39
	jg .40_59

	; add Kt

	add eax,0x6ed9eba1

	; f(t) = Parity(b,c,d) = b xor c xor d

	; calc f(t)(b,c,d)

	mov edx,[esi+4]
	xor edx,[esi+8]
	xor edx,[esi+12]

	; add f(t) to T

	add eax,edx

	jmp .NEXT

  .40_59:

	cmp cx,59
	jg .60_79

	; add Kt

	add eax,0x8f1bbcdc

	; f(t) = Maj(b,c,d) = (b and c) xor (b and d) xor (c and d)

	; calc f(t)(b,c,d)

	mov ebx,[esi+4]
	and ebx,[esi+8]

	mov edx,[esi+4]
	and edx,[esi+12]

	xor edx,ebx

	mov ebx,[esi+8]
	and ebx,[esi+12]

	xor edx,ebx

	; add f(t) to T

	add eax,edx

	jmp .NEXT

  .60_79:

	; add Kt

	add eax,0xca62c1d6

	; f(t) = Parity(b,c,d) = b xor c xor d

	; calc f(t)(b,c,d)

	mov edx,[esi+4]
	xor edx,[esi+8]
	xor edx,[esi+12]

	; add f(t) to T

	add eax,edx

  .NEXT:

	; e = d

	mov edx,[esi+12]
	mov [esi+16],edx

	; d = c

	mov edx,[esi+8]
	mov [esi+12],edx

	; c = ROTL(30,b)

	mov edx,[esi+4]
	rol edx,30
	mov [esi+8],edx

	; b = a

	mov edx,[esi]
	mov [esi+4],edx

	; a = T

	mov [esi],eax

	inc cx
	cmp cx,80

	jl .HASH

  .UPDATE:

	; add a,b,c,d,e to the hash

	lea esi,[Temp_H]
	lea edi,[H_0_1]

	mov eax,[edi]
	add eax,[esi]
	mov [edi],eax

	mov eax,[edi+4]
	add eax,[esi+4]
	mov [edi+4],eax

	mov eax,[edi+8]
	add eax,[esi+8]
	mov [edi+8],eax

	mov eax,[edi+12]
	add eax,[esi+12]
	mov [edi+12],eax

	mov eax,[edi+16]
	add eax,[esi+16]
	mov [edi+16],eax

	ret

endp

; -------------------------------------------------------------------------------------

proc SHA_224_256_Iterate uses esi edi ebx ecx

	locals

	  T1 dd 0
	  T2 dd 0

	endl

	; prepare the message schedule

	; the first 16 words of the message schedule
	; already contain the 512 bit message block

	lea esi,[Message_Schedule]
	lea edi,[Message_Schedule]

	add esi,64
	add edi,64

	mov cx,16

  .PREPARE:

	; W[t] = W[t-7] + W[t-16] + sigma_256_1(W[t-2]) + sigma_256_0(W[t-15])

	; W[t-7]

	mov eax,[esi-28]

	; W[t-16]

	add eax,[esi-64]

	mov [edi],eax

	; SHR(W(t-2),10)

	mov edx,[esi-8]
	shr edx,10

	mov eax,edx

	; ROTR(W(t-2),17)

	mov edx,[esi-8]
	ror edx,17

	xor eax,edx

	; ROTR(W(t-2),17)

	mov edx,[esi-8]
	ror edx,19

	xor eax,edx

	add [edi],eax

	; SHR(W(t-15),3)

	mov edx,[esi-60]
	shr edx,3

	mov eax,edx

	; ROTR(W(t-15),7)

	mov edx,[esi-60]
	ror edx,7

	xor eax,edx

	; ROTR(W(t-15),18)

	mov edx,[esi-60]
	ror edx,18

	xor eax,edx

	add [edi],eax

	add esi,4
	add edi,4

	inc cx

	cmp cx,64

	jl .PREPARE

	; initialise a,b,c,d,e,f,g,h

	lea esi,[H_0_256]
	lea edi,[Temp_H]

	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

	mov eax,[esi+16]
	mov [edi+16],eax

	mov eax,[esi+20]
	mov [edi+20],eax

	mov eax,[esi+24]
	mov [edi+24],eax

	mov eax,[esi+28]
	mov [edi+28],eax

	; compute the hash

	xor ecx,ecx

	mov cx,0

	lea esi,[Temp_H]
	lea edi,[Message_Schedule]
	lea ebx,[SHA_224_256_Kt]

  .HASH:

	; T1 = h

	mov eax,[esi+28]

	; T1 += W[t]

	mov edx,ecx
	shl edx,2

	add eax,[edi+edx]

	; T1 += Kt

	add eax,[ebx+edx]

	mov [T1],eax

	; T1 += Ch(e,f,g) = (e and f) xor (not(e) and g)

	mov eax,[esi+16]
	and eax,[esi+20]

	mov edx,[esi+16]
	not edx
	and edx,[esi+24]

	xor eax,edx

	add [T1],eax

	; T1 += SIGMA_256_1(e) = ROTR(e,6) xor ROTR(e,11) xor ROTR(e,25)

	mov eax,[esi+16]
	ror eax,6

	mov edx,[esi+16]
	ror edx,11

	xor eax,edx

	mov edx,[esi+16]
	ror edx,25

	xor eax,edx

	add [T1],eax

	; T2 =  SIGMA_256_0(a) = ROTR(a,2) xor ROTR(a,13) xor ROTR(a,22)

	mov eax,[esi]
	ror eax,2

	mov edx,[esi]
	ror edx,13

	xor eax,edx

	mov edx,[esi]
	ror edx,22

	xor eax,edx

	mov [T2],eax

	; T2 += Maj(a,b,c) = (a and b) xor (a and c) xor (b and c)

	mov eax,[esi]
	and eax,[esi+4]

	mov edx,[esi]
	and edx,[esi+8]

	xor eax,edx

	mov edx,[esi+4]
	and edx,[esi+8]

	xor eax,edx

	add [T2],eax

	; h = g

	mov edx,[esi+24]
	mov [esi+28],edx

	; g = f

	mov edx,[esi+20]
	mov [esi+24],edx

	; f = e

	mov edx,[esi+16]
	mov [esi+20],edx

	; e = d + T1

	mov edx,[T1]
	add edx,[esi+12]
	mov [esi+16],edx

	; d = c

	mov edx,[esi+8]
	mov [esi+12],edx

	; c = b

	mov edx,[esi+4]
	mov [esi+8],edx

	; b = a

	mov edx,[esi]
	mov [esi+4],edx

	; a = T1 + T2

	mov edx,[T1]
	add edx,[T2]
	mov [esi],edx

	inc cx
	cmp cx,64

	jl .HASH

  .UPDATE:

	; add a,b,c,d,e,f,g,h to the hash

	lea esi,[Temp_H]
	lea edi,[H_0_256]

	mov eax,[edi]
	add eax,[esi]
	mov [edi],eax

	mov eax,[edi+4]
	add eax,[esi+4]
	mov [edi+4],eax

	mov eax,[edi+8]
	add eax,[esi+8]
	mov [edi+8],eax

	mov eax,[edi+12]
	add eax,[esi+12]
	mov [edi+12],eax

	mov eax,[edi+16]
	add eax,[esi+16]
	mov [edi+16],eax

	mov eax,[edi+20]
	add eax,[esi+20]
	mov [edi+20],eax

	mov eax,[edi+24]
	add eax,[esi+24]
	mov [edi+24],eax

	mov eax,[edi+28]
	add eax,[esi+28]
	mov [edi+28],eax

	ret

endp

; -------------------------------------------------------------------------------------

proc SHA_384_512_Iterate uses esi edi ebx ecx

	locals

	  T1_U dd 0
	  T1_L dd 0

	  T2_U dd 0
	  T2_L dd 0

	endl

	; prepare the message schedule

	; the first 32 words of the message schedule
	; already contain the 1024 bit message block

	lea esi,[Message_Schedule]
	lea edi,[Message_Schedule]

	add esi,128
	add edi,128

	xor ecx,ecx

	mov cx,16

  .PREPARE:

	; W[t] = W[t-7] + W[t-16] + sigma_512_1(W[t-2]) + sigma_512_0(W[t-15])

	; 64 bit words:

	; lower 32 bits in EAX
	; upper 32 bits in EDX

	; W[t-7]

	mov eax,[esi-52]
	mov edx,[esi-56]

	; W[t-16]

	add eax,[esi-124]
	adc edx,[esi-128]

	mov [edi+4],eax
	mov [edi],edx

	; sigma_512_1(x) = ROTR(x,19) xor ROTR(x,61) xor SHR(x,6)

	stdcall sigma_512_1_Wt

	; add to W[t]

	add [edi+4],eax
	adc [edi],edx

	; sigma_512_0(x) = ROTR(x,1) xor ROTR(x,8) xor SHR(x,7)

	stdcall sigma_512_0_Wt

	; add to W[t]

	add [edi+4],eax
	adc [edi],edx

	add esi,8
	add edi,8

	inc cx

	cmp cx,80

	jl .PREPARE

	; initialise a,b,c,d,e,f,g,h

	stdcall Init_512

	; compute the hash

	xor ecx,ecx

	mov cx,0

	lea esi,[Temp_H]
	lea edi,[Message_Schedule]

  .HASH:

	; 64 bit words:

	; lower 32 bits in EAX
	; upper 32 bits in EDX

	; a = esi + 0
	; b = esi + 8
	; c = esi + 16
	; d = esi + 24
	; e = esi + 32
	; f = esi + 40
	; g = esi + 48
	; h = esi + 56

	; T1 = h + SIGMA_512_1(e) + Ch(e,f,g) + K[t] + W[t]

	; T1 = h

	mov eax,[esi+60]
	mov edx,[esi+56]

	mov [T1_L],eax
	mov [T1_U],edx

	; T1 += W[t]

	mov ebx,ecx
	shl ebx,3

	mov eax,[edi+ebx+4]
	mov edx,[edi+ebx]

	add [T1_L],eax
	adc [T1_U],edx

	; T1 += Ch(e,f,g)

	; Ch(e,f,g) = (e and f) xor (not(e) and g)

	stdcall Ch_512

	add [T1_L],eax
	adc [T1_U],edx

	; T1 += K[t]

	stdcall Kt_512

	add [T1_L],eax
	adc [T1_U],edx

	; T1 += SIGMA_512_1(e)

	; SIGMA_512_1(e) = ROTR(e,14) xor ROTR(e,18) xor ROTR(e,41)

	stdcall SIGMA_512_E

	add [T1_L],eax
	adc [T1_U],edx

	; T2 = SIGMA_512_0(a) + Maj(a,b,c)

	; T2 = Maj(a,b,c)

	; Maj(a,b,c) = (a and b) xor (a and c) xor (b and c)

	stdcall Maj_512

	mov [T2_L],eax
	mov [T2_U],edx

	; T2 += SIGMA_512_0(a)

	; SIGMA_512_0(a) = ROTR(a,28) xor ROTR(a,34) xor ROTR(a,39)

	stdcall SIGMA_512_A

	add [T2_L],eax
	adc [T2_U],edx

	; h = g

	mov eax,[esi+52]
	mov edx,[esi+48]

	mov [esi+60],eax
	mov [esi+56],edx

	; g = f

	mov eax,[esi+44]
	mov edx,[esi+40]

	mov [esi+52],eax
	mov [esi+48],edx

	; f = e

	mov eax,[esi+36]
	mov edx,[esi+32]

	mov [esi+44],eax
	mov [esi+40],edx

	; e = d + T1

	mov eax,[esi+28]
	mov edx,[esi+24]

	add eax,[T1_L]
	adc edx,[T1_U]

	mov [esi+36],eax
	mov [esi+32],edx

	; d = c

	mov eax,[esi+20]
	mov edx,[esi+16]

	mov [esi+28],eax
	mov [esi+24],edx

	; c = b

	mov eax,[esi+12]
	mov edx,[esi+8]

	mov [esi+20],eax
	mov [esi+16],edx

	; b = a

	mov eax,[esi+4]
	mov edx,[esi]

	mov [esi+12],eax
	mov [esi+8],edx

	; a = T1 + T2

	mov eax,[T1_L]
	mov edx,[T1_U]

	add eax,[T2_L]
	adc edx,[T2_U]

	mov [esi+4],eax
	mov [esi],edx

	inc cx
	cmp cx,80

	jl .HASH


  .UPDATE:

	; add a,b,c,d,e,f,g,h to the hash

	stdcall Update_512

	ret

endp

; -------------------------------------------------------------------------------------

macro ROT_RIGHT nbits
{
  ; Rotate right the double word EDX,EAX

	mov ebx,eax

	shrd eax,edx,nbits
	shr edx,nbits

	shl ebx,32-nbits

	or edx,ebx
}

; -------------------------------------------------------------------------------------

macro ROT_RIGHT_32
{
  ; Rotate right the double word EDX,EAX by 32 bits

  ; equivalent to swapping EAX and EDX

	mov ebx,eax
	mov eax,edx
	mov edx,ebx
}

; -------------------------------------------------------------------------------------

proc sigma_512_0_Wt uses esi

  ; sigma_512_0(x) = ROTR(x,1) xor ROTR(x,8) xor SHR(x,7)

  ; x = W[t-15]

  ; t in ECX

  ; result returned in EAX and EDX

	locals

	  Temp_L dd 0
	  Temp_U dd 0

	endl

	lea esi,[Message_Schedule]

	; get ESI for the current t

	mov ebx,ecx
	shl ebx,3

	add esi,ebx

	mov eax,[esi-116]
	mov edx,[esi-120]

	; SHR(x,7)

	shrd eax,edx,7
	shr edx,7

	mov [Temp_L],eax
	mov [Temp_U],edx

	; ROTR(x,1)

	mov eax,[esi-116]
	mov edx,[esi-120]

	ROT_RIGHT 1

	; xor

	xor [Temp_L],eax
	xor [Temp_U],edx

	; ROTR(x,8)

	mov eax,[esi-116]
	mov edx,[esi-120]

	ROT_RIGHT 8

	; xor

	xor eax,[Temp_L]
	xor edx,[Temp_U]

	ret

endp

; -------------------------------------------------------------------------------------

proc sigma_512_1_Wt uses esi

  ; sigma_512_1(x) = ROTR(x,19) xor ROTR(x,61) xor SHR(x,6)

  ; x = W[t-2]

  ; t in ECX

  ; result returned in EAX and EDX

	locals

	  Temp_L dd 0
	  Temp_U dd 0

	endl

	lea esi,[Message_Schedule]

	; get ESI for the current t

	mov ebx,ecx
	shl ebx,3

	add esi,ebx

	mov eax,[esi-12]
	mov edx,[esi-16]

	; SHR(x,6)

	shrd eax,edx,6
	shr edx,6

	mov [Temp_L],eax
	mov [Temp_U],edx

	; ROTR(x,19)

	mov eax,[esi-12]
	mov edx,[esi-16]

	ROT_RIGHT 19

	; xor

	xor [Temp_L],eax
	xor [Temp_U],edx

	; ROTR(x,61) = ROTR(ROTR(x,32),29)

	mov eax,[esi-12]
	mov edx,[esi-16]

	ROT_RIGHT_32

	ROT_RIGHT 29

	; xor

	xor eax,[Temp_L]
	xor edx,[Temp_U]

	ret

endp

; -------------------------------------------------------------------------------------

proc SIGMA_512_A uses esi

  ; SIGMA_512_0(a) = ROTR(a,28) xor ROTR(a,34) xor ROTR(a,39)

  ; result returned in EAX and EDX

	locals

	  Temp_L dd 0
	  Temp_U dd 0

	endl

	lea esi,[Temp_H]

	; a = esi + 0

	mov eax,[esi+4]
	mov edx,[esi]

	; ROTR(a,28)

	ROT_RIGHT 28

	mov [Temp_L],eax
	mov [Temp_U],edx

	mov eax,[esi+4]
	mov edx,[esi]

	; ROTR(a,34) = ROTR(ROTR(a,32),2)

	ROT_RIGHT_32

	ROT_RIGHT 2

	; xor

	xor [Temp_L],eax
	xor [Temp_U],edx

	mov eax,[esi+4]
	mov edx,[esi]

	; ROTR(a,39) = ROTR(ROTR(a,32),7)

	ROT_RIGHT_32

	ROT_RIGHT 7

	; xor

	xor eax,[Temp_L]
	xor edx,[Temp_U]

	ret

endp

; -------------------------------------------------------------------------------------

proc SIGMA_512_E uses esi

  ; SIGMA_512_1(e) = ROTR(e,14) xor ROTR(e,18) xor ROTR(e,41)

  ; result returned in EAX and EDX

	locals

	  Temp_L dd 0
	  Temp_U dd 0

	endl

	lea esi,[Temp_H]

	; e = esi + 32

	mov eax,[esi+36]
	mov edx,[esi+32]

	; ROTR(e,14)

	ROT_RIGHT 14

	mov [Temp_L],eax
	mov [Temp_U],edx

	mov eax,[esi+36]
	mov edx,[esi+32]

	; ROTR(e,18)

	ROT_RIGHT 18

	; xor

	xor [Temp_L],eax
	xor [Temp_U],edx

	mov eax,[esi+36]
	mov edx,[esi+32]

	; ROTR(e,41) = ROTR(ROTR(e,32),9)

	ROT_RIGHT_32

	ROT_RIGHT 9

	; xor

	xor eax,[Temp_L]
	xor edx,[Temp_U]

	ret

endp

; -------------------------------------------------------------------------------------

proc Ch_512 uses esi

  ; Ch(e,f,g) = (e and f) xor (not(e) and g)

  ; return the result in EAX and EDX

	locals

	  Temp_L dd 0
	  Temp_U dd 0

	endl

	; e = esi + 32
	; f = esi + 40
	; g = esi + 48

	; e and f

	lea esi,[Temp_H]

	mov eax,[esi+36]
	mov edx,[esi+32]

	and eax,[esi+44]
	and edx,[esi+40]

	mov [Temp_L],eax
	mov [Temp_U],edx

	; not(e)

	mov eax,[esi+36]
	mov edx,[esi+32]

	not eax
	not edx

	; not(e) and g

	and eax,[esi+52]
	and edx,[esi+48]

	; xor

	xor eax,[Temp_L]
	xor edx,[Temp_U]

	ret

endp

; -------------------------------------------------------------------------------------

proc Maj_512 uses esi

  ; Maj(a,b,c) = (a and b) xor (a and c) xor (b and c)

  ; return the result in EAX and EDX

	locals

	  Temp_L dd 0
	  Temp_U dd 0

	endl

	; a = esi + 0
	; b = esi + 8
	; c = esi + 16

	; a and b

	lea esi,[Temp_H]

	mov eax,[esi+4]
	mov edx,[esi]

	and eax,[esi+12]
	and edx,[esi+8]

	mov [Temp_L],eax
	mov [Temp_U],edx

	; a and c

	mov eax,[esi+4]
	mov edx,[esi]

	and eax,[esi+20]
	and edx,[esi+16]

	; xor

	xor [Temp_L],eax
	xor [Temp_U],edx

	; b and c

	mov eax,[esi+12]
	mov edx,[esi+8]

	and eax,[esi+20]
	and edx,[esi+16]

	; xor

	xor eax,[Temp_L]
	xor edx,[Temp_U]

	ret

endp

; -------------------------------------------------------------------------------------

proc Kt_512 uses esi

  ; t is in ECX

  ; return K[t] in EAX and EDX

	lea esi,[SHA_384_512_Kt]

	mov edx,ecx

	shl edx,3

	mov eax,[esi+edx+4]
	mov edx,[esi+edx]

	ret

endp

; -------------------------------------------------------------------------------------

proc Init_512

  ; initialise a,b,c,d,e,f,g,h for SHA-384 and SHA-512

	lea esi,[H_0_512]
	lea edi,[Temp_H]

	mov cx,16

  .COPY:

	mov eax,[esi]
	mov [edi],eax

	add esi,4
	add edi,4

	dec cx

	jcxz .DONE

	jmp .COPY

  .DONE:

	ret

endp

; -------------------------------------------------------------------------------------

proc Update_512

  ; add a,b,c,d,e,f,g,h to the hash for SHA-384 and SHA-512

	lea esi,[Temp_H]
	lea edi,[H_0_512]

	mov cx,8

  .ADD:

	mov eax,[esi+4]
	mov edx,[esi]

	add [edi+4],eax
	adc [edi],edx

	add esi,8
	add edi,8

	dec cx

	jcxz .DONE

	jmp .ADD

  .DONE:

	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 IN_STR_MAX_LENGTH

  MESSAGE rb MESSAGE_LENGTH+128

  BitLength dd 0

  nBlocks512 dd 0

  nBlocks1024 dd 0

  szInitText db "Enter the message as a hex number or text string (up to 5120 bytes):",0

; -------------------------------------------------------------------------------------

section '.hash' readable writeable

  H_0_1 rd 5

  H_0_224 rd 8

  H_0_256 rd 8

  H_0_384 rd 16

  H_0_512 rd 16

  Message_Schedule rd 160

  Temp_H rd 16

  SHA_224_256_Kt dd 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,\
		    0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,\
		    0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,\
		    0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,\
		    0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,\
		    0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,\
		    0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,\
		    0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,\
		    0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,\
		    0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,\
		    0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,\
		    0xd192e819,0xd6990624,0xf40e3585,0x106aa070,\
		    0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,\
		    0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,\
		    0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,\
		    0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2

  SHA_384_512_Kt dd 0x428a2f98,0xd728ae22,0x71374491,0x23ef65cd,\
		    0xb5c0fbcf,0xec4d3b2f,0xe9b5dba5,0x8189dbbc,\
		    0x3956c25b,0xf348b538,0x59f111f1,0xb605d019,\
		    0x923f82a4,0xaf194f9b,0xab1c5ed5,0xda6d8118,\
		    0xd807aa98,0xa3030242,0x12835b01,0x45706fbe,\
		    0x243185be,0x4ee4b28c,0x550c7dc3,0xd5ffb4e2,\
		    0x72be5d74,0xf27b896f,0x80deb1fe,0x3b1696b1,\
		    0x9bdc06a7,0x25c71235,0xc19bf174,0xcf692694,\
		    0xe49b69c1,0x9ef14ad2,0xefbe4786,0x384f25e3,\
		    0x0fc19dc6,0x8b8cd5b5,0x240ca1cc,0x77ac9c65,\
		    0x2de92c6f,0x592b0275,0x4a7484aa,0x6ea6e483,\
		    0x5cb0a9dc,0xbd41fbd4,0x76f988da,0x831153b5,\
		    0x983e5152,0xee66dfab,0xa831c66d,0x2db43210,\
		    0xb00327c8,0x98fb213f,0xbf597fc7,0xbeef0ee4,\
		    0xc6e00bf3,0x3da88fc2,0xd5a79147,0x930aa725,\
		    0x06ca6351,0xe003826f,0x14292967,0x0a0e6e70,\
		    0x27b70a85,0x46d22ffc,0x2e1b2138,0x5c26c926,\
		    0x4d2c6dfc,0x5ac42aed,0x53380d13,0x9d95b3df,\
		    0x650a7354,0x8baf63de,0x766a0abb,0x3c77b2a8,\
		    0x81c2c92e,0x47edaee6,0x92722c85,0x1482353b,\
		    0xa2bfe8a1,0x4cf10364,0xa81a664b,0xbc423001,\
		    0xc24b8b70,0xd0f89791,0xc76c51a3,0x0654be30,\
		    0xd192e819,0xd6ef5218,0xd6990624,0x5565a910,\
		    0xf40e3585,0x5771202a,0x106aa070,0x32bbd1b8,\
		    0x19a4c116,0xb8d2d0c8,0x1e376c08,0x5141ab53,\
		    0x2748774c,0xdf8eeb99,0x34b0bcb5,0xe19b48a8,\
		    0x391c0cb3,0xc5c95a63,0x4ed8aa4a,0xe3418acb,\
		    0x5b9cca4f,0x7763e373,0x682e6ff3,0xd6b2b8a3,\
		    0x748f82ee,0x5defb2fc,0x78a5636f,0x43172f60,\
		    0x84c87814,0xa1f0ab72,0x8cc70208,0x1a6439ec,\
		    0x90befffa,0x23631e28,0xa4506ceb,0xde82bde9,\
		    0xbef9a3f7,0xb2c67915,0xc67178f2,0xe372532b,\
		    0xca273ece,0xea26619c,0xd186b8c7,0x21c0c207,\
		    0xeada7dd6,0xcde0eb1e,0xf57d4f7f,0xee6ed178,\
		    0x06f067aa,0x72176fba,0x0a637dc5,0xa2c898a6,\
		    0x113f9804,0xbef90dae,0x1b710b35,0x131c471b,\
		    0x28db77f5,0x23047d84,0x32caab7b,0x40c72493,\
		    0x3c9ebe0a,0x15c9bebc,0x431d67c4,0x9c100d4c,\
		    0x4cc5d4be,0xcb3e42b6,0x597f299c,0xfc657e2a,\
		    0x5fcb6fab,0x3ad6faec,0x6c44198c,0x4a475817

; -------------------------------------------------------------------------------------

section '.rc' resource data readable

  directory RT_DIALOG,dialogs

  resource dialogs,IDD_THE_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,the_dialog

  dialog the_dialog,\
  'FASM - Secure Hash Algorithm',50,50,360,440,\
  DS_MODALFRAME+WS_MINIMIZEBOX+WS_POPUP+WS_VISIBLE+WS_CAPTION+WS_SYSMENU,\
  0,0,"Lucida Console",11

  dialogitem 'BUTTON',"Input",-1,7,5,346,180,BS_GROUPBOX+WS_VISIBLE,0
  dialogitem 'BUTTON',"Output",-1,7,190,346,220,BS_GROUPBOX+WS_VISIBLE,0

  dialogitem 'EDIT',0,IDC_INPUT,13,18,335,160,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0
  dialogitem 'EDIT',0,IDC_OUTPUT,13,203,335,200,ES_MULTILINE+ES_AUTOVSCROLL+ES_WANTRETURN+WS_VSCROLL+WS_BORDER+WS_VISIBLE,0

  dialogitem 'BUTTON',"SHA(HEX)",IDC_BTN_SHA_HEX,7,415,60,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"SHA(TXT)",IDC_BTN_SHA_TXT,69,415,60,14,BS_PUSHBUTTON+WS_VISIBLE,0
  dialogitem 'BUTTON',"RESET",IDC_BTN_RESET,131,415,60,14,BS_PUSHBUTTON+WS_VISIBLE,0

  enddialog

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

Create a free website or blog at WordPress.com.