00001 ;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
00002 ;; Copyright assigned to the Crypto++ project.
00003
00004 ;; This ASM file provides RDRAND and RDSEED to downlevel Microsoft tool chains.
00005 ;; Everything "just works" under Visual Studio. Other platforms will have to
00006 ;; run MASM/MASM-64 and then link to the object files.
00007
00008 ;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
00009 ;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
00010 ;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
00011 ;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm
00012
00013 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00014 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00015
00016 TITLE MASM_RRA_GenerateBlock and MASM_RSA_GenerateBlock
00017 SUBTITLE Microsoft specific ASM code to utilize RDRAND and RDSEED for down level Microsoft toolchains
00018
00019 PUBLIC MASM_RRA_GenerateBlock
00020 PUBLIC MASM_RSA_GenerateBlock
00021
00022 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00023 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00024
00025 ;; Naming convention used in rdrand.{h|cpp|asm}
00026 ;; MSC = Microsoft Compiler (and compatibles)
00027 ;; GCC = GNU Compiler (and compatibles)
00028 ;; ALL = MSC and GCC (and compatibles)
00029 ;; RRA = RDRAND, Assembly
00030 ;; RSA = RDSEED, Assembly
00031 ;; RRI = RDRAND, Intrinsic
00032 ;; RSA = RDSEED, Intrinsic
00033
00034 ;; Caller/Callee Saved Registers
00035 ;; https:
00036
00037 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00038 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00039
00040 ;; C/C++ Function prototypes
00041 ;; X86:
00042 ;; extern "C" int MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
00043 ;; X64:
00044 ;; extern "C" int __fastcall MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
00045
00046 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00047 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00048
00049 ;; Return values
00050 RDRAND_SUCCESS EQU 1
00051 RDRAND_FAILURE EQU 0
00052
00053 RDSEED_SUCCESS EQU 1
00054 RDSEED_FAILURE EQU 0
00055
00056 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00057 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00058
00059 IFDEF _M_X86 ;; Set via the command line
00060
00061 .486
00062 .MODEL FLAT
00063
00064 ENDIF
00065
00066 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00067 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00068
00069 IFDEF _M_X86 ;; Set via the command line
00070
00071 .CODE
00072 ALIGN 8
00073 OPTION LANGUAGE:C
00074 OPTION PROLOGUE:NONE
00075 OPTION EPILOGUE:NONE
00076
00077 ;; Base relative (in): arg1, byte* buffer
00078 ;; Base relative (in): arg2, size_t bsize
00079 ;; Base relative (in): arg3, unsigned int safety
00080 ;; EAX (out): success (1), failure (0)
00081
00082 MASM_RRA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
00083
00084 MWSIZE EQU 04h ;; machine word size
00085 buffer EQU edi
00086 bsize EQU edx
00087 safety EQU ecx
00088
00089 Load_Arguments:
00090
00091 mov buffer, arg1
00092 mov bsize, arg2
00093 mov safety, arg3
00094
00095 Validate_Pointer:
00096
00097 cmp buffer, 0
00098 je GenerateBlock_PreRet
00099
00100 ;; Top of While loop
00101 GenerateBlock_Top:
00102
00103 ;; Check remaining size
00104 cmp bsize, 0
00105 je GenerateBlock_Success
00106
00107 Call_RDRAND_EAX:
00108 ;; RDRAND is not available prior to VS2012. Just emit
00109 ;; the byte codes using DB. This is `rdrand eax`.
00110 DB 0Fh, 0C7h, 0F0h
00111
00112 ;; If CF=1, the number returned by RDRAND is valid.
00113 ;; If CF=0, a random number was not available.
00114 jc RDRAND_succeeded
00115
00116 RDRAND_failed:
00117
00118 ;; Exit if we've reached the limit
00119 cmp safety, 0
00120 je GenerateBlock_Failure
00121
00122 dec safety
00123 jmp GenerateBlock_Top
00124
00125 RDRAND_succeeded:
00126
00127 cmp bsize, MWSIZE
00128 jb Partial_Machine_Word
00129
00130 Full_Machine_Word:
00131
00132 mov DWORD PTR [buffer], eax
00133 add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
00134 sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
00135
00136 ;; Continue
00137 jmp GenerateBlock_Top
00138
00139 ;; 1,2,3 bytes remain
00140 Partial_Machine_Word:
00141
00142 ;; Test bit 1 to see if size is at least 2
00143 test bsize, 2
00144 jz Bit_1_Not_Set
00145
00146 mov WORD PTR [buffer], ax
00147 shr eax, 16
00148 add buffer, 2
00149
00150 Bit_1_Not_Set:
00151
00152 ;; Test bit 0 to see if size is at least 1
00153 test bsize, 1
00154 jz GenerateBlock_Success
00155
00156 mov BYTE PTR [buffer], al
00157
00158 Bit_0_Not_Set:
00159
00160 ;; We've hit all the bits
00161 jmp GenerateBlock_Success
00162
00163 GenerateBlock_PreRet:
00164
00165 ;; Test for success (was the request completely fulfilled?)
00166 cmp bsize, 0
00167 je GenerateBlock_Success
00168
00169 GenerateBlock_Failure:
00170
00171 xor eax, eax
00172 mov al, RDRAND_FAILURE
00173 ret
00174
00175 GenerateBlock_Success:
00176
00177 xor eax, eax
00178 mov al, RDRAND_SUCCESS
00179 ret
00180
00181 MASM_RRA_GenerateBlock ENDP
00182
00183 ENDIF ;; _M_X86
00184
00185 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00186 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00187
00188 IFDEF _M_X64 ;; Set via the command line
00189
00190 .CODE
00191 ALIGN 16
00192 OPTION PROLOGUE:NONE
00193 OPTION EPILOGUE:NONE
00194
00195 ;; RCX (in): arg1, byte* buffer
00196 ;; RDX (in): arg2, size_t bsize
00197 ;; R8d (in): arg3, unsigned int safety
00198 ;; RAX (out): success (1), failure (0)
00199
00200 MASM_RRA_GenerateBlock PROC
00201
00202 MWSIZE EQU 08h ;; machine word size
00203 buffer EQU rcx
00204 bsize EQU rdx
00205 safety EQU r8d
00206
00207 ;; No need for Load_Arguments due to fastcall
00208
00209 Validate_Pointer:
00210
00211 ;; Validate pointer
00212 cmp buffer, 0
00213 je GenerateBlock_PreRet
00214
00215 ;; Top of While loop
00216 GenerateBlock_Top:
00217
00218 ;; Check remaining size
00219 cmp bsize, 0
00220 je GenerateBlock_Success
00221
00222 Call_RDRAND_RAX:
00223 ;; RDRAND is not available prior to VS2012. Just emit
00224 ;; the byte codes using DB. This is `rdrand rax`.
00225 DB 048h, 0Fh, 0C7h, 0F0h
00226
00227 ;; If CF=1, the number returned by RDRAND is valid.
00228 ;; If CF=0, a random number was not available.
00229 jc RDRAND_succeeded
00230
00231 RDRAND_failed:
00232
00233 ;; Exit if we've reached the limit
00234 cmp safety, 0
00235 je GenerateBlock_Failure
00236
00237 dec safety
00238 jmp GenerateBlock_Top
00239
00240 RDRAND_succeeded:
00241
00242 cmp bsize, MWSIZE
00243 jb Partial_Machine_Word
00244
00245 Full_Machine_Word:
00246
00247 mov QWORD PTR [buffer], rax
00248 add buffer, MWSIZE
00249 sub bsize, MWSIZE
00250
00251 ;; Continue
00252 jmp GenerateBlock_Top
00253
00254 ;; 1,2,3,4,5,6,7 bytes remain
00255 Partial_Machine_Word:
00256
00257 ;; Test bit 2 to see if size is at least 4
00258 test bsize, 4
00259 jz Bit_2_Not_Set
00260
00261 mov DWORD PTR [buffer], eax
00262 shr rax, 32
00263 add buffer, 4
00264
00265 Bit_2_Not_Set:
00266
00267 ;; Test bit 1 to see if size is at least 2
00268 test bsize, 2
00269 jz Bit_1_Not_Set
00270
00271 mov WORD PTR [buffer], ax
00272 shr eax, 16
00273 add buffer, 2
00274
00275 Bit_1_Not_Set:
00276
00277 ;; Test bit 0 to see if size is at least 1
00278 test bsize, 1
00279 jz GenerateBlock_Success
00280
00281 mov BYTE PTR [buffer], al
00282
00283 Bit_0_Not_Set:
00284
00285 ;; We've hit all the bits
00286 jmp GenerateBlock_Success
00287
00288 GenerateBlock_PreRet:
00289
00290 ;; Test for success (was the request completely fulfilled?)
00291 cmp bsize, 0
00292 je GenerateBlock_Success
00293
00294 GenerateBlock_Failure:
00295
00296 xor rax, rax
00297 mov al, RDRAND_FAILURE
00298 ret
00299
00300 GenerateBlock_Success:
00301
00302 xor rax, rax
00303 mov al, RDRAND_SUCCESS
00304 ret
00305
00306 MASM_RRA_GenerateBlock ENDP
00307
00308 ENDIF ;; _M_X64
00309
00310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00311 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00312
00313 IFDEF _M_X86 ;; Set via the command line
00314
00315 .CODE
00316 ALIGN 8
00317 OPTION LANGUAGE:C
00318 OPTION PROLOGUE:NONE
00319 OPTION EPILOGUE:NONE
00320
00321 ;; Base relative (in): arg1, byte* buffer
00322 ;; Base relative (in): arg2, size_t bsize
00323 ;; Base relative (in): arg3, unsigned int safety
00324 ;; EAX (out): success (1), failure (0)
00325
00326 MASM_RSA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
00327
00328 MWSIZE EQU 04h ;; machine word size
00329 buffer EQU edi
00330 bsize EQU edx
00331 safety EQU ecx
00332
00333 Load_Arguments:
00334
00335 mov buffer, arg1
00336 mov bsize, arg2
00337 mov safety, arg3
00338
00339 Validate_Pointer:
00340
00341 cmp buffer, 0
00342 je GenerateBlock_PreRet
00343
00344 ;; Top of While loop
00345 GenerateBlock_Top:
00346
00347 ;; Check remaining size
00348 cmp bsize, 0
00349 je GenerateBlock_Success
00350
00351 Call_RDSEED_EAX:
00352 ;; RDSEED is not available prior to VS2012. Just emit
00353 ;; the byte codes using DB. This is `rdseed eax`.
00354 DB 0Fh, 0C7h, 0F8h
00355
00356 ;; If CF=1, the number returned by RDSEED is valid.
00357 ;; If CF=0, a random number was not available.
00358 jc RDSEED_succeeded
00359
00360 RDSEED_failed:
00361
00362 ;; Exit if we've reached the limit
00363 cmp safety, 0
00364 je GenerateBlock_Failure
00365
00366 dec safety
00367 jmp GenerateBlock_Top
00368
00369 RDSEED_succeeded:
00370
00371 cmp bsize, MWSIZE
00372 jb Partial_Machine_Word
00373
00374 Full_Machine_Word:
00375
00376 mov DWORD PTR [buffer], eax
00377 add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
00378 sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
00379
00380 ;; Continue
00381 jmp GenerateBlock_Top
00382
00383 ;; 1,2,3 bytes remain
00384 Partial_Machine_Word:
00385
00386 ;; Test bit 1 to see if size is at least 2
00387 test bsize, 2
00388 jz Bit_1_Not_Set
00389
00390 mov WORD PTR [buffer], ax
00391 shr eax, 16
00392 add buffer, 2
00393
00394 Bit_1_Not_Set:
00395
00396 ;; Test bit 0 to see if size is at least 1
00397 test bsize, 1
00398 jz GenerateBlock_Success
00399
00400 mov BYTE PTR [buffer], al
00401
00402 Bit_0_Not_Set:
00403
00404 ;; We've hit all the bits
00405 jmp GenerateBlock_Success
00406
00407 GenerateBlock_PreRet:
00408
00409 ;; Test for success (was the request completely fulfilled?)
00410 cmp bsize, 0
00411 je GenerateBlock_Success
00412
00413 GenerateBlock_Failure:
00414
00415 xor eax, eax
00416 mov al, RDSEED_FAILURE
00417 ret
00418
00419 GenerateBlock_Success:
00420
00421 xor eax, eax
00422 mov al, RDSEED_SUCCESS
00423 ret
00424
00425 MASM_RSA_GenerateBlock ENDP
00426
00427 ENDIF ;; _M_X86
00428
00429 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00430 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00431
00432 IFDEF _M_X64 ;; Set via the command line
00433
00434 .CODE
00435 ALIGN 16
00436 OPTION PROLOGUE:NONE
00437 OPTION EPILOGUE:NONE
00438
00439 ;; RCX (in): arg1, byte* buffer
00440 ;; RDX (in): arg2, size_t bsize
00441 ;; R8d (in): arg3, unsigned int safety
00442 ;; RAX (out): success (1), failure (0)
00443
00444 MASM_RSA_GenerateBlock PROC ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
00445
00446 MWSIZE EQU 08h ;; machine word size
00447 buffer EQU rcx
00448 bsize EQU rdx
00449 safety EQU r8d
00450
00451 ;; No need for Load_Arguments due to fastcall
00452
00453 Validate_Pointer:
00454
00455 ;; Validate pointer
00456 cmp buffer, 0
00457 je GenerateBlock_PreRet
00458
00459 ;; Top of While loop
00460 GenerateBlock_Top:
00461
00462 ;; Check remaining size
00463 cmp bsize, 0
00464 je GenerateBlock_Success
00465
00466 Call_RDSEED_RAX:
00467 ;; RDSEED is not available prior to VS2012. Just emit
00468 ;; the byte codes using DB. This is `rdseed rax`.
00469 DB 048h, 0Fh, 0C7h, 0F8h
00470
00471 ;; If CF=1, the number returned by RDSEED is valid.
00472 ;; If CF=0, a random number was not available.
00473 jc RDSEED_succeeded
00474
00475 RDSEED_failed:
00476
00477 ;; Exit if we've reached the limit
00478 cmp safety, 0
00479 je GenerateBlock_Failure
00480
00481 dec safety
00482 jmp GenerateBlock_Top
00483
00484 RDSEED_succeeded:
00485
00486 cmp bsize, MWSIZE
00487 jb Partial_Machine_Word
00488
00489 Full_Machine_Word:
00490
00491 mov QWORD PTR [buffer], rax
00492 add buffer, MWSIZE
00493 sub bsize, MWSIZE
00494
00495 ;; Continue
00496 jmp GenerateBlock_Top
00497
00498 ;; 1,2,3,4,5,6,7 bytes remain
00499 Partial_Machine_Word:
00500
00501 ;; Test bit 2 to see if size is at least 4
00502 test bsize, 4
00503 jz Bit_2_Not_Set
00504
00505 mov DWORD PTR [buffer], eax
00506 shr rax, 32
00507 add buffer, 4
00508
00509 Bit_2_Not_Set:
00510
00511 ;; Test bit 1 to see if size is at least 2
00512 test bsize, 2
00513 jz Bit_1_Not_Set
00514
00515 mov WORD PTR [buffer], ax
00516 shr eax, 16
00517 add buffer, 2
00518
00519 Bit_1_Not_Set:
00520
00521 ;; Test bit 0 to see if size is at least 1
00522 test bsize, 1
00523 jz GenerateBlock_Success
00524
00525 mov BYTE PTR [buffer], al
00526
00527 Bit_0_Not_Set:
00528
00529 ;; We've hit all the bits
00530 jmp GenerateBlock_Success
00531
00532 GenerateBlock_PreRet:
00533
00534 ;; Test for success (was the request completely fulfilled?)
00535 cmp bsize, 0
00536 je GenerateBlock_Success
00537
00538 GenerateBlock_Failure:
00539
00540 xor rax, rax
00541 mov al, RDSEED_FAILURE
00542 ret
00543
00544 GenerateBlock_Success:
00545
00546 xor rax, rax
00547 mov al, RDSEED_SUCCESS
00548 ret
00549
00550 MASM_RSA_GenerateBlock ENDP
00551
00552 ENDIF ;; _M_X64
00553
00554 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00555 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
00556
00557 END