You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
558 lines
12 KiB
558 lines
12 KiB
5 years ago
|
;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
|
||
|
;; Copyright assigned to the Crypto++ project.
|
||
|
|
||
|
;; This ASM file provides RDRAND and RDSEED to downlevel Microsoft tool chains.
|
||
|
;; Everything "just works" under Visual Studio. Other platforms will have to
|
||
|
;; run MASM/MASM-64 and then link to the object files.
|
||
|
|
||
|
;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
|
||
|
;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
|
||
|
;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
|
||
|
;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
TITLE MASM_RRA_GenerateBlock and MASM_RSA_GenerateBlock
|
||
|
SUBTITLE Microsoft specific ASM code to utilize RDRAND and RDSEED for down level Microsoft toolchains
|
||
|
|
||
|
PUBLIC MASM_RRA_GenerateBlock
|
||
|
PUBLIC MASM_RSA_GenerateBlock
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
;; Naming convention used in rdrand.{h|cpp|asm}
|
||
|
;; MSC = Microsoft Compiler (and compatibles)
|
||
|
;; GCC = GNU Compiler (and compatibles)
|
||
|
;; ALL = MSC and GCC (and compatibles)
|
||
|
;; RRA = RDRAND, Assembly
|
||
|
;; RSA = RDSEED, Assembly
|
||
|
;; RRI = RDRAND, Intrinsic
|
||
|
;; RSA = RDSEED, Intrinsic
|
||
|
|
||
|
;; Caller/Callee Saved Registers
|
||
|
;; https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
;; C/C++ Function prototypes
|
||
|
;; X86:
|
||
|
;; extern "C" int MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
|
||
|
;; X64:
|
||
|
;; extern "C" int __fastcall MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
;; Return values
|
||
|
RDRAND_SUCCESS EQU 1
|
||
|
RDRAND_FAILURE EQU 0
|
||
|
|
||
|
RDSEED_SUCCESS EQU 1
|
||
|
RDSEED_FAILURE EQU 0
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
IFDEF _M_X86 ;; Set via the command line
|
||
|
|
||
|
.486
|
||
|
.MODEL FLAT
|
||
|
|
||
|
ENDIF
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
IFDEF _M_X86 ;; Set via the command line
|
||
|
|
||
|
.CODE
|
||
|
ALIGN 8
|
||
|
OPTION LANGUAGE:C
|
||
|
OPTION PROLOGUE:NONE
|
||
|
OPTION EPILOGUE:NONE
|
||
|
|
||
|
;; Base relative (in): arg1, byte* buffer
|
||
|
;; Base relative (in): arg2, size_t bsize
|
||
|
;; Base relative (in): arg3, unsigned int safety
|
||
|
;; EAX (out): success (1), failure (0)
|
||
|
|
||
|
MASM_RRA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
|
||
|
|
||
|
MWSIZE EQU 04h ;; machine word size
|
||
|
buffer EQU edi
|
||
|
bsize EQU edx
|
||
|
safety EQU ecx
|
||
|
|
||
|
Load_Arguments:
|
||
|
|
||
|
mov buffer, arg1
|
||
|
mov bsize, arg2
|
||
|
mov safety, arg3
|
||
|
|
||
|
Validate_Pointer:
|
||
|
|
||
|
cmp buffer, 0
|
||
|
je GenerateBlock_PreRet
|
||
|
|
||
|
;; Top of While loop
|
||
|
GenerateBlock_Top:
|
||
|
|
||
|
;; Check remaining size
|
||
|
cmp bsize, 0
|
||
|
je GenerateBlock_Success
|
||
|
|
||
|
Call_RDRAND_EAX:
|
||
|
;; RDRAND is not available prior to VS2012. Just emit
|
||
|
;; the byte codes using DB. This is `rdrand eax`.
|
||
|
DB 0Fh, 0C7h, 0F0h
|
||
|
|
||
|
;; If CF=1, the number returned by RDRAND is valid.
|
||
|
;; If CF=0, a random number was not available.
|
||
|
jc RDRAND_succeeded
|
||
|
|
||
|
RDRAND_failed:
|
||
|
|
||
|
;; Exit if we've reached the limit
|
||
|
cmp safety, 0
|
||
|
je GenerateBlock_Failure
|
||
|
|
||
|
dec safety
|
||
|
jmp GenerateBlock_Top
|
||
|
|
||
|
RDRAND_succeeded:
|
||
|
|
||
|
cmp bsize, MWSIZE
|
||
|
jb Partial_Machine_Word
|
||
|
|
||
|
Full_Machine_Word:
|
||
|
|
||
|
mov DWORD PTR [buffer], eax
|
||
|
add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
|
||
|
sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
|
||
|
|
||
|
;; Continue
|
||
|
jmp GenerateBlock_Top
|
||
|
|
||
|
;; 1,2,3 bytes remain
|
||
|
Partial_Machine_Word:
|
||
|
|
||
|
;; Test bit 1 to see if size is at least 2
|
||
|
test bsize, 2
|
||
|
jz Bit_1_Not_Set
|
||
|
|
||
|
mov WORD PTR [buffer], ax
|
||
|
shr eax, 16
|
||
|
add buffer, 2
|
||
|
|
||
|
Bit_1_Not_Set:
|
||
|
|
||
|
;; Test bit 0 to see if size is at least 1
|
||
|
test bsize, 1
|
||
|
jz GenerateBlock_Success
|
||
|
|
||
|
mov BYTE PTR [buffer], al
|
||
|
|
||
|
Bit_0_Not_Set:
|
||
|
|
||
|
;; We've hit all the bits
|
||
|
jmp GenerateBlock_Success
|
||
|
|
||
|
GenerateBlock_PreRet:
|
||
|
|
||
|
;; Test for success (was the request completely fulfilled?)
|
||
|
cmp bsize, 0
|
||
|
je GenerateBlock_Success
|
||
|
|
||
|
GenerateBlock_Failure:
|
||
|
|
||
|
xor eax, eax
|
||
|
mov al, RDRAND_FAILURE
|
||
|
ret
|
||
|
|
||
|
GenerateBlock_Success:
|
||
|
|
||
|
xor eax, eax
|
||
|
mov al, RDRAND_SUCCESS
|
||
|
ret
|
||
|
|
||
|
MASM_RRA_GenerateBlock ENDP
|
||
|
|
||
|
ENDIF ;; _M_X86
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
IFDEF _M_X64 ;; Set via the command line
|
||
|
|
||
|
.CODE
|
||
|
ALIGN 16
|
||
|
OPTION PROLOGUE:NONE
|
||
|
OPTION EPILOGUE:NONE
|
||
|
|
||
|
;; RCX (in): arg1, byte* buffer
|
||
|
;; RDX (in): arg2, size_t bsize
|
||
|
;; R8d (in): arg3, unsigned int safety
|
||
|
;; RAX (out): success (1), failure (0)
|
||
|
|
||
|
MASM_RRA_GenerateBlock PROC
|
||
|
|
||
|
MWSIZE EQU 08h ;; machine word size
|
||
|
buffer EQU rcx
|
||
|
bsize EQU rdx
|
||
|
safety EQU r8d
|
||
|
|
||
|
;; No need for Load_Arguments due to fastcall
|
||
|
|
||
|
Validate_Pointer:
|
||
|
|
||
|
;; Validate pointer
|
||
|
cmp buffer, 0
|
||
|
je GenerateBlock_PreRet
|
||
|
|
||
|
;; Top of While loop
|
||
|
GenerateBlock_Top:
|
||
|
|
||
|
;; Check remaining size
|
||
|
cmp bsize, 0
|
||
|
je GenerateBlock_Success
|
||
|
|
||
|
Call_RDRAND_RAX:
|
||
|
;; RDRAND is not available prior to VS2012. Just emit
|
||
|
;; the byte codes using DB. This is `rdrand rax`.
|
||
|
DB 048h, 0Fh, 0C7h, 0F0h
|
||
|
|
||
|
;; If CF=1, the number returned by RDRAND is valid.
|
||
|
;; If CF=0, a random number was not available.
|
||
|
jc RDRAND_succeeded
|
||
|
|
||
|
RDRAND_failed:
|
||
|
|
||
|
;; Exit if we've reached the limit
|
||
|
cmp safety, 0
|
||
|
je GenerateBlock_Failure
|
||
|
|
||
|
dec safety
|
||
|
jmp GenerateBlock_Top
|
||
|
|
||
|
RDRAND_succeeded:
|
||
|
|
||
|
cmp bsize, MWSIZE
|
||
|
jb Partial_Machine_Word
|
||
|
|
||
|
Full_Machine_Word:
|
||
|
|
||
|
mov QWORD PTR [buffer], rax
|
||
|
add buffer, MWSIZE
|
||
|
sub bsize, MWSIZE
|
||
|
|
||
|
;; Continue
|
||
|
jmp GenerateBlock_Top
|
||
|
|
||
|
;; 1,2,3,4,5,6,7 bytes remain
|
||
|
Partial_Machine_Word:
|
||
|
|
||
|
;; Test bit 2 to see if size is at least 4
|
||
|
test bsize, 4
|
||
|
jz Bit_2_Not_Set
|
||
|
|
||
|
mov DWORD PTR [buffer], eax
|
||
|
shr rax, 32
|
||
|
add buffer, 4
|
||
|
|
||
|
Bit_2_Not_Set:
|
||
|
|
||
|
;; Test bit 1 to see if size is at least 2
|
||
|
test bsize, 2
|
||
|
jz Bit_1_Not_Set
|
||
|
|
||
|
mov WORD PTR [buffer], ax
|
||
|
shr eax, 16
|
||
|
add buffer, 2
|
||
|
|
||
|
Bit_1_Not_Set:
|
||
|
|
||
|
;; Test bit 0 to see if size is at least 1
|
||
|
test bsize, 1
|
||
|
jz GenerateBlock_Success
|
||
|
|
||
|
mov BYTE PTR [buffer], al
|
||
|
|
||
|
Bit_0_Not_Set:
|
||
|
|
||
|
;; We've hit all the bits
|
||
|
jmp GenerateBlock_Success
|
||
|
|
||
|
GenerateBlock_PreRet:
|
||
|
|
||
|
;; Test for success (was the request completely fulfilled?)
|
||
|
cmp bsize, 0
|
||
|
je GenerateBlock_Success
|
||
|
|
||
|
GenerateBlock_Failure:
|
||
|
|
||
|
xor rax, rax
|
||
|
mov al, RDRAND_FAILURE
|
||
|
ret
|
||
|
|
||
|
GenerateBlock_Success:
|
||
|
|
||
|
xor rax, rax
|
||
|
mov al, RDRAND_SUCCESS
|
||
|
ret
|
||
|
|
||
|
MASM_RRA_GenerateBlock ENDP
|
||
|
|
||
|
ENDIF ;; _M_X64
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
IFDEF _M_X86 ;; Set via the command line
|
||
|
|
||
|
.CODE
|
||
|
ALIGN 8
|
||
|
OPTION LANGUAGE:C
|
||
|
OPTION PROLOGUE:NONE
|
||
|
OPTION EPILOGUE:NONE
|
||
|
|
||
|
;; Base relative (in): arg1, byte* buffer
|
||
|
;; Base relative (in): arg2, size_t bsize
|
||
|
;; Base relative (in): arg3, unsigned int safety
|
||
|
;; EAX (out): success (1), failure (0)
|
||
|
|
||
|
MASM_RSA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
|
||
|
|
||
|
MWSIZE EQU 04h ;; machine word size
|
||
|
buffer EQU edi
|
||
|
bsize EQU edx
|
||
|
safety EQU ecx
|
||
|
|
||
|
Load_Arguments:
|
||
|
|
||
|
mov buffer, arg1
|
||
|
mov bsize, arg2
|
||
|
mov safety, arg3
|
||
|
|
||
|
Validate_Pointer:
|
||
|
|
||
|
cmp buffer, 0
|
||
|
je GenerateBlock_PreRet
|
||
|
|
||
|
;; Top of While loop
|
||
|
GenerateBlock_Top:
|
||
|
|
||
|
;; Check remaining size
|
||
|
cmp bsize, 0
|
||
|
je GenerateBlock_Success
|
||
|
|
||
|
Call_RDSEED_EAX:
|
||
|
;; RDSEED is not available prior to VS2012. Just emit
|
||
|
;; the byte codes using DB. This is `rdseed eax`.
|
||
|
DB 0Fh, 0C7h, 0F8h
|
||
|
|
||
|
;; If CF=1, the number returned by RDSEED is valid.
|
||
|
;; If CF=0, a random number was not available.
|
||
|
jc RDSEED_succeeded
|
||
|
|
||
|
RDSEED_failed:
|
||
|
|
||
|
;; Exit if we've reached the limit
|
||
|
cmp safety, 0
|
||
|
je GenerateBlock_Failure
|
||
|
|
||
|
dec safety
|
||
|
jmp GenerateBlock_Top
|
||
|
|
||
|
RDSEED_succeeded:
|
||
|
|
||
|
cmp bsize, MWSIZE
|
||
|
jb Partial_Machine_Word
|
||
|
|
||
|
Full_Machine_Word:
|
||
|
|
||
|
mov DWORD PTR [buffer], eax
|
||
|
add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
|
||
|
sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
|
||
|
|
||
|
;; Continue
|
||
|
jmp GenerateBlock_Top
|
||
|
|
||
|
;; 1,2,3 bytes remain
|
||
|
Partial_Machine_Word:
|
||
|
|
||
|
;; Test bit 1 to see if size is at least 2
|
||
|
test bsize, 2
|
||
|
jz Bit_1_Not_Set
|
||
|
|
||
|
mov WORD PTR [buffer], ax
|
||
|
shr eax, 16
|
||
|
add buffer, 2
|
||
|
|
||
|
Bit_1_Not_Set:
|
||
|
|
||
|
;; Test bit 0 to see if size is at least 1
|
||
|
test bsize, 1
|
||
|
jz GenerateBlock_Success
|
||
|
|
||
|
mov BYTE PTR [buffer], al
|
||
|
|
||
|
Bit_0_Not_Set:
|
||
|
|
||
|
;; We've hit all the bits
|
||
|
jmp GenerateBlock_Success
|
||
|
|
||
|
GenerateBlock_PreRet:
|
||
|
|
||
|
;; Test for success (was the request completely fulfilled?)
|
||
|
cmp bsize, 0
|
||
|
je GenerateBlock_Success
|
||
|
|
||
|
GenerateBlock_Failure:
|
||
|
|
||
|
xor eax, eax
|
||
|
mov al, RDSEED_FAILURE
|
||
|
ret
|
||
|
|
||
|
GenerateBlock_Success:
|
||
|
|
||
|
xor eax, eax
|
||
|
mov al, RDSEED_SUCCESS
|
||
|
ret
|
||
|
|
||
|
MASM_RSA_GenerateBlock ENDP
|
||
|
|
||
|
ENDIF ;; _M_X86
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
IFDEF _M_X64 ;; Set via the command line
|
||
|
|
||
|
.CODE
|
||
|
ALIGN 16
|
||
|
OPTION PROLOGUE:NONE
|
||
|
OPTION EPILOGUE:NONE
|
||
|
|
||
|
;; RCX (in): arg1, byte* buffer
|
||
|
;; RDX (in): arg2, size_t bsize
|
||
|
;; R8d (in): arg3, unsigned int safety
|
||
|
;; RAX (out): success (1), failure (0)
|
||
|
|
||
|
MASM_RSA_GenerateBlock PROC ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
|
||
|
|
||
|
MWSIZE EQU 08h ;; machine word size
|
||
|
buffer EQU rcx
|
||
|
bsize EQU rdx
|
||
|
safety EQU r8d
|
||
|
|
||
|
;; No need for Load_Arguments due to fastcall
|
||
|
|
||
|
Validate_Pointer:
|
||
|
|
||
|
;; Validate pointer
|
||
|
cmp buffer, 0
|
||
|
je GenerateBlock_PreRet
|
||
|
|
||
|
;; Top of While loop
|
||
|
GenerateBlock_Top:
|
||
|
|
||
|
;; Check remaining size
|
||
|
cmp bsize, 0
|
||
|
je GenerateBlock_Success
|
||
|
|
||
|
Call_RDSEED_RAX:
|
||
|
;; RDSEED is not available prior to VS2012. Just emit
|
||
|
;; the byte codes using DB. This is `rdseed rax`.
|
||
|
DB 048h, 0Fh, 0C7h, 0F8h
|
||
|
|
||
|
;; If CF=1, the number returned by RDSEED is valid.
|
||
|
;; If CF=0, a random number was not available.
|
||
|
jc RDSEED_succeeded
|
||
|
|
||
|
RDSEED_failed:
|
||
|
|
||
|
;; Exit if we've reached the limit
|
||
|
cmp safety, 0
|
||
|
je GenerateBlock_Failure
|
||
|
|
||
|
dec safety
|
||
|
jmp GenerateBlock_Top
|
||
|
|
||
|
RDSEED_succeeded:
|
||
|
|
||
|
cmp bsize, MWSIZE
|
||
|
jb Partial_Machine_Word
|
||
|
|
||
|
Full_Machine_Word:
|
||
|
|
||
|
mov QWORD PTR [buffer], rax
|
||
|
add buffer, MWSIZE
|
||
|
sub bsize, MWSIZE
|
||
|
|
||
|
;; Continue
|
||
|
jmp GenerateBlock_Top
|
||
|
|
||
|
;; 1,2,3,4,5,6,7 bytes remain
|
||
|
Partial_Machine_Word:
|
||
|
|
||
|
;; Test bit 2 to see if size is at least 4
|
||
|
test bsize, 4
|
||
|
jz Bit_2_Not_Set
|
||
|
|
||
|
mov DWORD PTR [buffer], eax
|
||
|
shr rax, 32
|
||
|
add buffer, 4
|
||
|
|
||
|
Bit_2_Not_Set:
|
||
|
|
||
|
;; Test bit 1 to see if size is at least 2
|
||
|
test bsize, 2
|
||
|
jz Bit_1_Not_Set
|
||
|
|
||
|
mov WORD PTR [buffer], ax
|
||
|
shr eax, 16
|
||
|
add buffer, 2
|
||
|
|
||
|
Bit_1_Not_Set:
|
||
|
|
||
|
;; Test bit 0 to see if size is at least 1
|
||
|
test bsize, 1
|
||
|
jz GenerateBlock_Success
|
||
|
|
||
|
mov BYTE PTR [buffer], al
|
||
|
|
||
|
Bit_0_Not_Set:
|
||
|
|
||
|
;; We've hit all the bits
|
||
|
jmp GenerateBlock_Success
|
||
|
|
||
|
GenerateBlock_PreRet:
|
||
|
|
||
|
;; Test for success (was the request completely fulfilled?)
|
||
|
cmp bsize, 0
|
||
|
je GenerateBlock_Success
|
||
|
|
||
|
GenerateBlock_Failure:
|
||
|
|
||
|
xor rax, rax
|
||
|
mov al, RDSEED_FAILURE
|
||
|
ret
|
||
|
|
||
|
GenerateBlock_Success:
|
||
|
|
||
|
xor rax, rax
|
||
|
mov al, RDSEED_SUCCESS
|
||
|
ret
|
||
|
|
||
|
MASM_RSA_GenerateBlock ENDP
|
||
|
|
||
|
ENDIF ;; _M_X64
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
END
|