Crypto++  8.2
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_RDRAND_GenerateBlock and MASM_RDSEED_GenerateBlock
17 SUBTITLE Microsoft specific ASM code to utilize RDRAND and RDSEED for down level Microsoft toolchains
18 
19 PUBLIC MASM_RDRAND_GenerateBlock
20 PUBLIC MASM_RDSEED_GenerateBlock
21 
22 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
24 
25 ;; C/C++ Function prototypes (both are fastcall)
26 ;; X86:
27 ;; extern "C" void __fastcall MASM_RDRAND_GenerateBlock(byte* ptr, size_t size);
28 ;; X64:
29 ;; extern "C" void __fastcall MASM_RDRAND_GenerateBlock(byte* ptr, size_t size);
30 
31 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
33 
34 IFDEF _M_X86 ;; Set via the command line
35 
36 .486
37 .MODEL FLAT
38 
39 ;; Fastcall calling conventions exports
40 ALIAS <@MASM_RDRAND_GenerateBlock@8> = <MASM_RDRAND_GenerateBlock>
41 ALIAS <@MASM_RDSEED_GenerateBlock@8> = <MASM_RDSEED_GenerateBlock>
42 
43 ENDIF
44 
45 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
46 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47 
48 IFDEF _M_X86 ;; Set via the command line
49 
50 .CODE
51 ALIGN 8
52 OPTION PROLOGUE:NONE
53 OPTION EPILOGUE:NONE
54 
55 ;; No need for Load_Arguments due to fastcall
56 ;; ECX (in): arg1, byte* buffer
57 ;; EDX (in): arg2, size_t bsize
58 
59 MASM_RDRAND_GenerateBlock PROC ;; arg1:DWORD, arg2:DWORD
60 
61  MWSIZE EQU 04h ;; machine word size
62  buffer EQU ecx
63  bsize EQU edx
64 
65  ;; Top of While loop
66 GenerateBlock_Top:
67 
68  ;; Check remaining size
69  cmp bsize, 0
70  je GenerateBlock_Return
71 
72 Call_RDRAND_EAX:
73  ;; RDRAND is not available prior to VS2012. Just emit
74  ;; the byte codes using DB. This is `rdrand eax`.
75  DB 0Fh, 0C7h, 0F0h
76 
77  ;; If CF=1, the number returned by RDRAND is valid.
78  ;; If CF=0, a random number was not available.
79 
80  ;; Retry immediately
81  jnc Call_RDRAND_EAX
82 
83 RDRAND_succeeded:
84 
85  cmp bsize, MWSIZE
86  jb Partial_Machine_Word
87 
88 Full_Machine_Word:
89 
90  mov DWORD PTR [buffer], eax
91  add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
92  sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
93 
94  ;; Continue
95  jmp GenerateBlock_Top
96 
97  ;; 1,2,3 bytes remain
98 Partial_Machine_Word:
99 
100  ;; Test bit 1 to see if size is at least 2
101  test bsize, 2
102  jz Bit_1_Not_Set
103 
104  mov WORD PTR [buffer], ax
105  shr eax, 16
106  add buffer, 2
107 
108 Bit_1_Not_Set:
109 
110  ;; Test bit 0 to see if size is at least 1
111  test bsize, 1
112  jz Bit_0_Not_Set
113 
114  mov BYTE PTR [buffer], al
115 
116 Bit_0_Not_Set:
117 
118  ;; We've hit all the bits
119 
120 GenerateBlock_Return:
121 
122  ;; Clear artifacts
123  xor eax, eax
124  ret
125 
126 MASM_RDRAND_GenerateBlock ENDP
127 
128 ENDIF ;; _M_X86
129 
130 OPTION PROLOGUE:PrologueDef
131 OPTION EPILOGUE:EpilogueDef
132 
133 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
134 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
135 
136 IFDEF _M_X64 ;; Set via the command line
137 
138 .CODE
139 ALIGN 16
140 OPTION PROLOGUE:NONE
141 OPTION EPILOGUE:NONE
142 
143 ;; No need for Load_Arguments due to fastcall
144 ;; RCX (in): arg1, byte* buffer
145 ;; RDX (in): arg2, size_t bsize
146 
147 MASM_RDRAND_GenerateBlock PROC ;; arg1:QWORD, arg2:QWORD
148 
149  MWSIZE EQU 08h ;; machine word size
150  buffer EQU rcx
151  bsize EQU rdx
152 
153  ;; Top of While loop
154 GenerateBlock_Top:
155 
156  ;; Check remaining size
157  cmp bsize, 0
158  je GenerateBlock_Return
159 
160 Call_RDRAND_RAX:
161  ;; RDRAND is not available prior to VS2012. Just emit
162  ;; the byte codes using DB. This is `rdrand rax`.
163  DB 048h, 0Fh, 0C7h, 0F0h
164 
165  ;; If CF=1, the number returned by RDRAND is valid.
166  ;; If CF=0, a random number was not available.
167 
168  ;; Retry immediately
169  jnc Call_RDRAND_RAX
170 
171 RDRAND_succeeded:
172 
173  cmp bsize, MWSIZE
174  jb Partial_Machine_Word
175 
176 Full_Machine_Word:
177 
178  mov QWORD PTR [buffer], rax
179  add buffer, MWSIZE
180  sub bsize, MWSIZE
181 
182  ;; Continue
183  jmp GenerateBlock_Top
184 
185  ;; 1,2,3,4,5,6,7 bytes remain
186 Partial_Machine_Word:
187 
188  ;; Test bit 2 to see if size is at least 4
189  test bsize, 4
190  jz Bit_2_Not_Set
191 
192  mov DWORD PTR [buffer], eax
193  shr rax, 32
194  add buffer, 4
195 
196 Bit_2_Not_Set:
197 
198  ;; Test bit 1 to see if size is at least 2
199  test bsize, 2
200  jz Bit_1_Not_Set
201 
202  mov WORD PTR [buffer], ax
203  shr eax, 16
204  add buffer, 2
205 
206 Bit_1_Not_Set:
207 
208  ;; Test bit 0 to see if size is at least 1
209  test bsize, 1
210  jz Bit_0_Not_Set
211 
212  mov BYTE PTR [buffer], al
213 
214 Bit_0_Not_Set:
215 
216  ;; We've hit all the bits
217 
218 GenerateBlock_Return:
219 
220  ;; Clear artifacts
221  xor rax, rax
222  ret
223 
224 MASM_RDRAND_GenerateBlock ENDP
225 
226 ENDIF ;; _M_X64
227 
228 OPTION PROLOGUE:PrologueDef
229 OPTION EPILOGUE:EpilogueDef
230 
231 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
232 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
233 
234 IFDEF _M_X86 ;; Set via the command line
235 
236 .CODE
237 ALIGN 8
238 OPTION PROLOGUE:NONE
239 OPTION EPILOGUE:NONE
240 
241 ;; No need for Load_Arguments due to fastcall
242 ;; ECX (in): arg1, byte* buffer
243 ;; EDX (in): arg2, size_t bsize
244 
245 MASM_RDSEED_GenerateBlock PROC ;; arg1:DWORD, arg2:DWORD
246 
247  MWSIZE EQU 04h ;; machine word size
248  buffer EQU ecx
249  bsize EQU edx
250 
251  ;; Top of While loop
252 GenerateBlock_Top:
253 
254  ;; Check remaining size
255  cmp bsize, 0
256  je GenerateBlock_Return
257 
258 Call_RDSEED_EAX:
259  ;; RDSEED is not available prior to VS2012. Just emit
260  ;; the byte codes using DB. This is `rdseed eax`.
261  DB 0Fh, 0C7h, 0F8h
262 
263  ;; If CF=1, the number returned by RDSEED is valid.
264  ;; If CF=0, a random number was not available.
265 
266  ;; Retry immediately
267  jnc Call_RDSEED_EAX
268 
269 RDSEED_succeeded:
270 
271  cmp bsize, MWSIZE
272  jb Partial_Machine_Word
273 
274 Full_Machine_Word:
275 
276  mov DWORD PTR [buffer], eax
277  add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
278  sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
279 
280  ;; Continue
281  jmp GenerateBlock_Top
282 
283  ;; 1,2,3 bytes remain
284 Partial_Machine_Word:
285 
286  ;; Test bit 1 to see if size is at least 2
287  test bsize, 2
288  jz Bit_1_Not_Set
289 
290  mov WORD PTR [buffer], ax
291  shr eax, 16
292  add buffer, 2
293 
294 Bit_1_Not_Set:
295 
296  ;; Test bit 0 to see if size is at least 1
297  test bsize, 1
298  jz Bit_0_Not_Set
299 
300  mov BYTE PTR [buffer], al
301 
302 Bit_0_Not_Set:
303 
304  ;; We've hit all the bits
305 
306 GenerateBlock_Return:
307 
308  ;; Clear artifacts
309  xor eax, eax
310  ret
311 
312 MASM_RDSEED_GenerateBlock ENDP
313 
314 ENDIF ;; _M_X86
315 
316 OPTION PROLOGUE:PrologueDef
317 OPTION EPILOGUE:EpilogueDef
318 
319 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
320 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
321 
322 IFDEF _M_X64 ;; Set via the command line
323 
324 .CODE
325 ALIGN 16
326 OPTION PROLOGUE:NONE
327 OPTION EPILOGUE:NONE
328 
329 ;; No need for Load_Arguments due to fastcall
330 ;; RCX (in): arg1, byte* buffer
331 ;; RDX (in): arg2, size_t bsize
332 
333 MASM_RDSEED_GenerateBlock PROC ;; arg1:QWORD, arg2:QWORD
334 
335  MWSIZE EQU 08h ;; machine word size
336  buffer EQU rcx
337  bsize EQU rdx
338 
339  ;; Top of While loop
340 GenerateBlock_Top:
341 
342  ;; Check remaining size
343  cmp bsize, 0
344  je GenerateBlock_Return
345 
346 Call_RDSEED_RAX:
347  ;; RDSEED is not available prior to VS2012. Just emit
348  ;; the byte codes using DB. This is `rdseed rax`.
349  DB 048h, 0Fh, 0C7h, 0F8h
350 
351  ;; If CF=1, the number returned by RDSEED is valid.
352  ;; If CF=0, a random number was not available.
353 
354  ;; Retry immediately
355  jnc Call_RDSEED_RAX
356 
357 RDSEED_succeeded:
358 
359  cmp bsize, MWSIZE
360  jb Partial_Machine_Word
361 
362 Full_Machine_Word:
363 
364  mov QWORD PTR [buffer], rax
365  add buffer, MWSIZE
366  sub bsize, MWSIZE
367 
368  ;; Continue
369  jmp GenerateBlock_Top
370 
371  ;; 1,2,3,4,5,6,7 bytes remain
372 Partial_Machine_Word:
373 
374  ;; Test bit 2 to see if size is at least 4
375  test bsize, 4
376  jz Bit_2_Not_Set
377 
378  mov DWORD PTR [buffer], eax
379  shr rax, 32
380  add buffer, 4
381 
382 Bit_2_Not_Set:
383 
384  ;; Test bit 1 to see if size is at least 2
385  test bsize, 2
386  jz Bit_1_Not_Set
387 
388  mov WORD PTR [buffer], ax
389  shr eax, 16
390  add buffer, 2
391 
392 Bit_1_Not_Set:
393 
394  ;; Test bit 0 to see if size is at least 1
395  test bsize, 1
396  jz Bit_0_Not_Set
397 
398  mov BYTE PTR [buffer], al
399 
400 Bit_0_Not_Set:
401 
402  ;; We've hit all the bits
403 
404 GenerateBlock_Return:
405 
406  ;; Clear artifacts
407  xor rax, rax
408  ret
409 
410 MASM_RDSEED_GenerateBlock ENDP
411 
412 ENDIF ;; _M_X64
413 
414 OPTION PROLOGUE:PrologueDef
415 OPTION EPILOGUE:EpilogueDef
416 
417 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
418 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
419 
420 END