Crypto++  5.6.3
Free C++ class library of cryptographic schemes
rdrand.asm
1 ;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2 ;; Copyright assigned to the Crypto++ project.
3 
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.
7 
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
12 
13 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
15 
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
18 
19 PUBLIC MASM_RRA_GenerateBlock
20 PUBLIC MASM_RSA_GenerateBlock
21 
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24 
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
33 
34 ;; Caller/Callee Saved Registers
35 ;; https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
36 
37 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
39 
40 ;; C/C++ Function prototypes
41 ;; X86:
42 ;; extern "C" int MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
43 ;; X64:
44 ;; extern "C" int __fastcall MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
45 
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
48 
49 ;; Return values
50 RDRAND_SUCCESS EQU 1
51 RDRAND_FAILURE EQU 0
52 
53 RDSEED_SUCCESS EQU 1
54 RDSEED_FAILURE EQU 0
55 
56 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
57 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
58 
59 IFDEF _M_X86 ;; Set via the command line
60 
61 .486
62 .MODEL FLAT
63 
64 ENDIF
65 
66 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
67 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
68 
69 IFDEF _M_X86 ;; Set via the command line
70 
71 .CODE
72 ALIGN 8
73 OPTION LANGUAGE:C
74 OPTION PROLOGUE:NONE
75 OPTION EPILOGUE:NONE
76 
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)
81 
82 MASM_RRA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
83 
84  MWSIZE EQU 04h ;; machine word size
85  buffer EQU edi
86  bsize EQU edx
87  safety EQU ecx
88 
89 Load_Arguments:
90 
91  mov buffer, arg1
92  mov bsize, arg2
93  mov safety, arg3
94 
95 Validate_Pointer:
96 
97  cmp buffer, 0
98  je GenerateBlock_PreRet
99 
100  ;; Top of While loop
101 GenerateBlock_Top:
102 
103  ;; Check remaining size
104  cmp bsize, 0
105  je GenerateBlock_Success
106 
107 Call_RDRAND_EAX:
108  ;; RDRAND is not available prior to VS2012. Just emit
109  ;; the byte codes using DB. This is `rdrand eax`.
110  DB 0Fh, 0C7h, 0F0h
111 
112  ;; If CF=1, the number returned by RDRAND is valid.
113  ;; If CF=0, a random number was not available.
114  jc RDRAND_succeeded
115 
116 RDRAND_failed:
117 
118  ;; Exit if we've reached the limit
119  cmp safety, 0
120  je GenerateBlock_Failure
121 
122  dec safety
123  jmp GenerateBlock_Top
124 
125 RDRAND_succeeded:
126 
127  cmp bsize, MWSIZE
128  jb Partial_Machine_Word
129 
130 Full_Machine_Word:
131 
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
135 
136  ;; Continue
137  jmp GenerateBlock_Top
138 
139  ;; 1,2,3 bytes remain
140 Partial_Machine_Word:
141 
142  ;; Test bit 1 to see if size is at least 2
143  test bsize, 2
144  jz Bit_1_Not_Set
145 
146  mov WORD PTR [buffer], ax
147  shr eax, 16
148  add buffer, 2
149 
150 Bit_1_Not_Set:
151 
152  ;; Test bit 0 to see if size is at least 1
153  test bsize, 1
154  jz GenerateBlock_Success
155 
156  mov BYTE PTR [buffer], al
157 
158 Bit_0_Not_Set:
159 
160  ;; We've hit all the bits
161  jmp GenerateBlock_Success
162 
163 GenerateBlock_PreRet:
164 
165  ;; Test for success (was the request completely fulfilled?)
166  cmp bsize, 0
167  je GenerateBlock_Success
168 
169 GenerateBlock_Failure:
170 
171  xor eax, eax
172  mov al, RDRAND_FAILURE
173  ret
174 
175 GenerateBlock_Success:
176 
177  xor eax, eax
178  mov al, RDRAND_SUCCESS
179  ret
180 
181 MASM_RRA_GenerateBlock ENDP
182 
183 ENDIF ;; _M_X86
184 
185 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
186 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
187 
188 IFDEF _M_X64 ;; Set via the command line
189 
190 .CODE
191 ALIGN 16
192 OPTION PROLOGUE:NONE
193 OPTION EPILOGUE:NONE
194 
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)
199 
200 MASM_RRA_GenerateBlock PROC
201 
202  MWSIZE EQU 08h ;; machine word size
203  buffer EQU rcx
204  bsize EQU rdx
205  safety EQU r8d
206 
207  ;; No need for Load_Arguments due to fastcall
208 
209 Validate_Pointer:
210 
211  ;; Validate pointer
212  cmp buffer, 0
213  je GenerateBlock_PreRet
214 
215  ;; Top of While loop
216 GenerateBlock_Top:
217 
218  ;; Check remaining size
219  cmp bsize, 0
220  je GenerateBlock_Success
221 
222 Call_RDRAND_RAX:
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
226 
227  ;; If CF=1, the number returned by RDRAND is valid.
228  ;; If CF=0, a random number was not available.
229  jc RDRAND_succeeded
230 
231 RDRAND_failed:
232 
233  ;; Exit if we've reached the limit
234  cmp safety, 0
235  je GenerateBlock_Failure
236 
237  dec safety
238  jmp GenerateBlock_Top
239 
240 RDRAND_succeeded:
241 
242  cmp bsize, MWSIZE
243  jb Partial_Machine_Word
244 
245 Full_Machine_Word:
246 
247  mov QWORD PTR [buffer], rax
248  add buffer, MWSIZE
249  sub bsize, MWSIZE
250 
251  ;; Continue
252  jmp GenerateBlock_Top
253 
254  ;; 1,2,3,4,5,6,7 bytes remain
255 Partial_Machine_Word:
256 
257  ;; Test bit 2 to see if size is at least 4
258  test bsize, 4
259  jz Bit_2_Not_Set
260 
261  mov DWORD PTR [buffer], eax
262  shr rax, 32
263  add buffer, 4
264 
265 Bit_2_Not_Set:
266 
267  ;; Test bit 1 to see if size is at least 2
268  test bsize, 2
269  jz Bit_1_Not_Set
270 
271  mov WORD PTR [buffer], ax
272  shr eax, 16
273  add buffer, 2
274 
275 Bit_1_Not_Set:
276 
277  ;; Test bit 0 to see if size is at least 1
278  test bsize, 1
279  jz GenerateBlock_Success
280 
281  mov BYTE PTR [buffer], al
282 
283 Bit_0_Not_Set:
284 
285  ;; We've hit all the bits
286  jmp GenerateBlock_Success
287 
288 GenerateBlock_PreRet:
289 
290  ;; Test for success (was the request completely fulfilled?)
291  cmp bsize, 0
292  je GenerateBlock_Success
293 
294 GenerateBlock_Failure:
295 
296  xor rax, rax
297  mov al, RDRAND_FAILURE
298  ret
299 
300 GenerateBlock_Success:
301 
302  xor rax, rax
303  mov al, RDRAND_SUCCESS
304  ret
305 
306 MASM_RRA_GenerateBlock ENDP
307 
308 ENDIF ;; _M_X64
309 
310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
312 
313 IFDEF _M_X86 ;; Set via the command line
314 
315 .CODE
316 ALIGN 8
317 OPTION LANGUAGE:C
318 OPTION PROLOGUE:NONE
319 OPTION EPILOGUE:NONE
320 
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)
325 
326 MASM_RSA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
327 
328  MWSIZE EQU 04h ;; machine word size
329  buffer EQU edi
330  bsize EQU edx
331  safety EQU ecx
332 
333 Load_Arguments:
334 
335  mov buffer, arg1
336  mov bsize, arg2
337  mov safety, arg3
338 
339 Validate_Pointer:
340 
341  cmp buffer, 0
342  je GenerateBlock_PreRet
343 
344  ;; Top of While loop
345 GenerateBlock_Top:
346 
347  ;; Check remaining size
348  cmp bsize, 0
349  je GenerateBlock_Success
350 
351 Call_RDSEED_EAX:
352  ;; RDSEED is not available prior to VS2012. Just emit
353  ;; the byte codes using DB. This is `rdseed eax`.
354  DB 0Fh, 0C7h, 0F8h
355 
356  ;; If CF=1, the number returned by RDSEED is valid.
357  ;; If CF=0, a random number was not available.
358  jc RDSEED_succeeded
359 
360 RDSEED_failed:
361 
362  ;; Exit if we've reached the limit
363  cmp safety, 0
364  je GenerateBlock_Failure
365 
366  dec safety
367  jmp GenerateBlock_Top
368 
369 RDSEED_succeeded:
370 
371  cmp bsize, MWSIZE
372  jb Partial_Machine_Word
373 
374 Full_Machine_Word:
375 
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
379 
380  ;; Continue
381  jmp GenerateBlock_Top
382 
383  ;; 1,2,3 bytes remain
384 Partial_Machine_Word:
385 
386  ;; Test bit 1 to see if size is at least 2
387  test bsize, 2
388  jz Bit_1_Not_Set
389 
390  mov WORD PTR [buffer], ax
391  shr eax, 16
392  add buffer, 2
393 
394 Bit_1_Not_Set:
395 
396  ;; Test bit 0 to see if size is at least 1
397  test bsize, 1
398  jz GenerateBlock_Success
399 
400  mov BYTE PTR [buffer], al
401 
402 Bit_0_Not_Set:
403 
404  ;; We've hit all the bits
405  jmp GenerateBlock_Success
406 
407 GenerateBlock_PreRet:
408 
409  ;; Test for success (was the request completely fulfilled?)
410  cmp bsize, 0
411  je GenerateBlock_Success
412 
413 GenerateBlock_Failure:
414 
415  xor eax, eax
416  mov al, RDSEED_FAILURE
417  ret
418 
419 GenerateBlock_Success:
420 
421  xor eax, eax
422  mov al, RDSEED_SUCCESS
423  ret
424 
425 MASM_RSA_GenerateBlock ENDP
426 
427 ENDIF ;; _M_X86
428 
429 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
430 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
431 
432 IFDEF _M_X64 ;; Set via the command line
433 
434 .CODE
435 ALIGN 16
436 OPTION PROLOGUE:NONE
437 OPTION EPILOGUE:NONE
438 
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)
443 
444 MASM_RSA_GenerateBlock PROC ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
445 
446  MWSIZE EQU 08h ;; machine word size
447  buffer EQU rcx
448  bsize EQU rdx
449  safety EQU r8d
450 
451  ;; No need for Load_Arguments due to fastcall
452 
453 Validate_Pointer:
454 
455  ;; Validate pointer
456  cmp buffer, 0
457  je GenerateBlock_PreRet
458 
459  ;; Top of While loop
460 GenerateBlock_Top:
461 
462  ;; Check remaining size
463  cmp bsize, 0
464  je GenerateBlock_Success
465 
466 Call_RDSEED_RAX:
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
470 
471  ;; If CF=1, the number returned by RDSEED is valid.
472  ;; If CF=0, a random number was not available.
473  jc RDSEED_succeeded
474 
475 RDSEED_failed:
476 
477  ;; Exit if we've reached the limit
478  cmp safety, 0
479  je GenerateBlock_Failure
480 
481  dec safety
482  jmp GenerateBlock_Top
483 
484 RDSEED_succeeded:
485 
486  cmp bsize, MWSIZE
487  jb Partial_Machine_Word
488 
489 Full_Machine_Word:
490 
491  mov QWORD PTR [buffer], rax
492  add buffer, MWSIZE
493  sub bsize, MWSIZE
494 
495  ;; Continue
496  jmp GenerateBlock_Top
497 
498  ;; 1,2,3,4,5,6,7 bytes remain
499 Partial_Machine_Word:
500 
501  ;; Test bit 2 to see if size is at least 4
502  test bsize, 4
503  jz Bit_2_Not_Set
504 
505  mov DWORD PTR [buffer], eax
506  shr rax, 32
507  add buffer, 4
508 
509 Bit_2_Not_Set:
510 
511  ;; Test bit 1 to see if size is at least 2
512  test bsize, 2
513  jz Bit_1_Not_Set
514 
515  mov WORD PTR [buffer], ax
516  shr eax, 16
517  add buffer, 2
518 
519 Bit_1_Not_Set:
520 
521  ;; Test bit 0 to see if size is at least 1
522  test bsize, 1
523  jz GenerateBlock_Success
524 
525  mov BYTE PTR [buffer], al
526 
527 Bit_0_Not_Set:
528 
529  ;; We've hit all the bits
530  jmp GenerateBlock_Success
531 
532 GenerateBlock_PreRet:
533 
534  ;; Test for success (was the request completely fulfilled?)
535  cmp bsize, 0
536  je GenerateBlock_Success
537 
538 GenerateBlock_Failure:
539 
540  xor rax, rax
541  mov al, RDSEED_FAILURE
542  ret
543 
544 GenerateBlock_Success:
545 
546  xor rax, rax
547  mov al, RDSEED_SUCCESS
548  ret
549 
550 MASM_RSA_GenerateBlock ENDP
551 
552 ENDIF ;; _M_X64
553 
554 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
555 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
556 
557 END