1 ;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2 ;; Copyright assigned to the Crypto++ project.
4 ;; This ASM file provides RDRAND and RDSEED to downlevel Microsoft tool chains.
5 ;; Everything "just works" under Visual Studio. Other platforms will have to
6 ;; run MASM/MASM-64 and then link to the object files.
8 ;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
9 ;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
10 ;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
11 ;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm
13 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
16 TITLE MASM_RRA_GenerateBlock and MASM_RSA_GenerateBlock
17 SUBTITLE Microsoft specific ASM code to utilize RDRAND and RDSEED for down level Microsoft toolchains
19 PUBLIC MASM_RRA_GenerateBlock
20 PUBLIC MASM_RSA_GenerateBlock
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25 ;; Naming convention used in rdrand.{h|cpp|asm}
26 ;; MSC = Microsoft Compiler (and compatibles)
27 ;; GCC = GNU Compiler (and compatibles)
28 ;; ALL = MSC and GCC (and compatibles)
29 ;; RRA = RDRAND, Assembly
30 ;; RSA = RDSEED, Assembly
31 ;; RRI = RDRAND, Intrinsic
32 ;; RSA = RDSEED, Intrinsic
34 ;; Caller/Callee Saved Registers
35 ;; https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
37 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
40 ;; C/C++ Function prototypes
42 ;; extern "C" int MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
44 ;; extern "C" int __fastcall MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
56 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
57 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
59 IFDEF _M_X86 ;; Set via the command line
66 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
67 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
69 IFDEF _M_X86 ;; Set via the command line
77 ;; Base relative (in): arg1, byte* buffer
78 ;; Base relative (in): arg2, size_t bsize
79 ;; Base relative (in): arg3, unsigned int safety
80 ;; EAX (out): success (1), failure (0)
82 MASM_RRA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
84 MWSIZE EQU 04h ;; machine word size
98 je GenerateBlock_PreRet
103 ;; Check remaining size
105 je GenerateBlock_Success
108 ;; RDRAND is not available prior to VS2012. Just emit
109 ;; the byte codes using DB. This is `rdrand eax`.
112 ;; If CF=1, the number returned by RDRAND is valid.
113 ;; If CF=0, a random number was not available.
118 ;; Exit if we've reached the limit
120 je GenerateBlock_Failure
123 jmp GenerateBlock_Top
128 jb Partial_Machine_Word
132 mov DWORD PTR [buffer], eax
133 add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
134 sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
137 jmp GenerateBlock_Top
139 ;; 1,2,3 bytes remain
140 Partial_Machine_Word:
142 ;; Test bit 1 to see if size is at least 2
146 mov WORD PTR [buffer], ax
152 ;; Test bit 0 to see if size is at least 1
154 jz GenerateBlock_Success
156 mov BYTE PTR [buffer], al
160 ;; We've hit all the bits
161 jmp GenerateBlock_Success
163 GenerateBlock_PreRet:
165 ;; Test for success (was the request completely fulfilled?)
167 je GenerateBlock_Success
169 GenerateBlock_Failure:
172 mov al, RDRAND_FAILURE
175 GenerateBlock_Success:
178 mov al, RDRAND_SUCCESS
181 MASM_RRA_GenerateBlock ENDP
185 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
186 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
188 IFDEF _M_X64 ;; Set via the command line
195 ;; RCX (in): arg1, byte* buffer
196 ;; RDX (in): arg2, size_t bsize
197 ;; R8d (in): arg3, unsigned int safety
198 ;; RAX (out): success (1), failure (0)
200 MASM_RRA_GenerateBlock PROC
202 MWSIZE EQU 08h ;; machine word size
207 ;; No need for Load_Arguments due to fastcall
213 je GenerateBlock_PreRet
218 ;; Check remaining size
220 je GenerateBlock_Success
223 ;; RDRAND is not available prior to VS2012. Just emit
224 ;; the byte codes using DB. This is `rdrand rax`.
225 DB 048h, 0Fh, 0C7h, 0F0h
227 ;; If CF=1, the number returned by RDRAND is valid.
228 ;; If CF=0, a random number was not available.
233 ;; Exit if we've reached the limit
235 je GenerateBlock_Failure
238 jmp GenerateBlock_Top
243 jb Partial_Machine_Word
247 mov QWORD PTR [buffer], rax
252 jmp GenerateBlock_Top
254 ;; 1,2,3,4,5,6,7 bytes remain
255 Partial_Machine_Word:
257 ;; Test bit 2 to see if size is at least 4
261 mov DWORD PTR [buffer], eax
267 ;; Test bit 1 to see if size is at least 2
271 mov WORD PTR [buffer], ax
277 ;; Test bit 0 to see if size is at least 1
279 jz GenerateBlock_Success
281 mov BYTE PTR [buffer], al
285 ;; We've hit all the bits
286 jmp GenerateBlock_Success
288 GenerateBlock_PreRet:
290 ;; Test for success (was the request completely fulfilled?)
292 je GenerateBlock_Success
294 GenerateBlock_Failure:
297 mov al, RDRAND_FAILURE
300 GenerateBlock_Success:
303 mov al, RDRAND_SUCCESS
306 MASM_RRA_GenerateBlock ENDP
310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
313 IFDEF _M_X86 ;; Set via the command line
321 ;; Base relative (in): arg1, byte* buffer
322 ;; Base relative (in): arg2, size_t bsize
323 ;; Base relative (in): arg3, unsigned int safety
324 ;; EAX (out): success (1), failure (0)
326 MASM_RSA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
328 MWSIZE EQU 04h ;; machine word size
342 je GenerateBlock_PreRet
347 ;; Check remaining size
349 je GenerateBlock_Success
352 ;; RDSEED is not available prior to VS2012. Just emit
353 ;; the byte codes using DB. This is `rdseed eax`.
356 ;; If CF=1, the number returned by RDSEED is valid.
357 ;; If CF=0, a random number was not available.
362 ;; Exit if we've reached the limit
364 je GenerateBlock_Failure
367 jmp GenerateBlock_Top
372 jb Partial_Machine_Word
376 mov DWORD PTR [buffer], eax
377 add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
378 sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
381 jmp GenerateBlock_Top
383 ;; 1,2,3 bytes remain
384 Partial_Machine_Word:
386 ;; Test bit 1 to see if size is at least 2
390 mov WORD PTR [buffer], ax
396 ;; Test bit 0 to see if size is at least 1
398 jz GenerateBlock_Success
400 mov BYTE PTR [buffer], al
404 ;; We've hit all the bits
405 jmp GenerateBlock_Success
407 GenerateBlock_PreRet:
409 ;; Test for success (was the request completely fulfilled?)
411 je GenerateBlock_Success
413 GenerateBlock_Failure:
416 mov al, RDSEED_FAILURE
419 GenerateBlock_Success:
422 mov al, RDSEED_SUCCESS
425 MASM_RSA_GenerateBlock ENDP
429 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
430 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
432 IFDEF _M_X64 ;; Set via the command line
439 ;; RCX (in): arg1, byte* buffer
440 ;; RDX (in): arg2, size_t bsize
441 ;; R8d (in): arg3, unsigned int safety
442 ;; RAX (out): success (1), failure (0)
444 MASM_RSA_GenerateBlock PROC ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
446 MWSIZE EQU 08h ;; machine word size
451 ;; No need for Load_Arguments due to fastcall
457 je GenerateBlock_PreRet
462 ;; Check remaining size
464 je GenerateBlock_Success
467 ;; RDSEED is not available prior to VS2012. Just emit
468 ;; the byte codes using DB. This is `rdseed rax`.
469 DB 048h, 0Fh, 0C7h, 0F8h
471 ;; If CF=1, the number returned by RDSEED is valid.
472 ;; If CF=0, a random number was not available.
477 ;; Exit if we've reached the limit
479 je GenerateBlock_Failure
482 jmp GenerateBlock_Top
487 jb Partial_Machine_Word
491 mov QWORD PTR [buffer], rax
496 jmp GenerateBlock_Top
498 ;; 1,2,3,4,5,6,7 bytes remain
499 Partial_Machine_Word:
501 ;; Test bit 2 to see if size is at least 4
505 mov DWORD PTR [buffer], eax
511 ;; Test bit 1 to see if size is at least 2
515 mov WORD PTR [buffer], ax
521 ;; Test bit 0 to see if size is at least 1
523 jz GenerateBlock_Success
525 mov BYTE PTR [buffer], al
529 ;; We've hit all the bits
530 jmp GenerateBlock_Success
532 GenerateBlock_PreRet:
534 ;; Test for success (was the request completely fulfilled?)
536 je GenerateBlock_Success
538 GenerateBlock_Failure:
541 mov al, RDSEED_FAILURE
544 GenerateBlock_Success:
547 mov al, RDSEED_SUCCESS
550 MASM_RSA_GenerateBlock ENDP
554 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
555 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;