Team Fortress 2 Source Code as on 22/4/2020
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.

557 lines
12 KiB

  1. ;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
  2. ;; Copyright assigned to the Crypto++ project.
  3. ;; This ASM file provides RDRAND and RDSEED to downlevel Microsoft tool chains.
  4. ;; Everything "just works" under Visual Studio. Other platforms will have to
  5. ;; run MASM/MASM-64 and then link to the object files.
  6. ;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
  7. ;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
  8. ;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
  9. ;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm
  10. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  11. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  12. TITLE MASM_RRA_GenerateBlock and MASM_RSA_GenerateBlock
  13. SUBTITLE Microsoft specific ASM code to utilize RDRAND and RDSEED for down level Microsoft toolchains
  14. PUBLIC MASM_RRA_GenerateBlock
  15. PUBLIC MASM_RSA_GenerateBlock
  16. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  17. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  18. ;; Naming convention used in rdrand.{h|cpp|asm}
  19. ;; MSC = Microsoft Compiler (and compatibles)
  20. ;; GCC = GNU Compiler (and compatibles)
  21. ;; ALL = MSC and GCC (and compatibles)
  22. ;; RRA = RDRAND, Assembly
  23. ;; RSA = RDSEED, Assembly
  24. ;; RRI = RDRAND, Intrinsic
  25. ;; RSA = RDSEED, Intrinsic
  26. ;; Caller/Callee Saved Registers
  27. ;; https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
  28. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  29. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  30. ;; C/C++ Function prototypes
  31. ;; X86:
  32. ;; extern "C" int MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
  33. ;; X64:
  34. ;; extern "C" int __fastcall MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
  35. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  36. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  37. ;; Return values
  38. RDRAND_SUCCESS EQU 1
  39. RDRAND_FAILURE EQU 0
  40. RDSEED_SUCCESS EQU 1
  41. RDSEED_FAILURE EQU 0
  42. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  43. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  44. IFDEF _M_X86 ;; Set via the command line
  45. .486
  46. .MODEL FLAT
  47. ENDIF
  48. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  49. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  50. IFDEF _M_X86 ;; Set via the command line
  51. .CODE
  52. ALIGN 8
  53. OPTION LANGUAGE:C
  54. OPTION PROLOGUE:NONE
  55. OPTION EPILOGUE:NONE
  56. ;; Base relative (in): arg1, byte* buffer
  57. ;; Base relative (in): arg2, size_t bsize
  58. ;; Base relative (in): arg3, unsigned int safety
  59. ;; EAX (out): success (1), failure (0)
  60. MASM_RRA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
  61. MWSIZE EQU 04h ;; machine word size
  62. buffer EQU edi
  63. bsize EQU edx
  64. safety EQU ecx
  65. Load_Arguments:
  66. mov buffer, arg1
  67. mov bsize, arg2
  68. mov safety, arg3
  69. Validate_Pointer:
  70. cmp buffer, 0
  71. je GenerateBlock_PreRet
  72. ;; Top of While loop
  73. GenerateBlock_Top:
  74. ;; Check remaining size
  75. cmp bsize, 0
  76. je GenerateBlock_Success
  77. Call_RDRAND_EAX:
  78. ;; RDRAND is not available prior to VS2012. Just emit
  79. ;; the byte codes using DB. This is `rdrand eax`.
  80. DB 0Fh, 0C7h, 0F0h
  81. ;; If CF=1, the number returned by RDRAND is valid.
  82. ;; If CF=0, a random number was not available.
  83. jc RDRAND_succeeded
  84. RDRAND_failed:
  85. ;; Exit if we've reached the limit
  86. cmp safety, 0
  87. je GenerateBlock_Failure
  88. dec safety
  89. jmp GenerateBlock_Top
  90. RDRAND_succeeded:
  91. cmp bsize, MWSIZE
  92. jb Partial_Machine_Word
  93. Full_Machine_Word:
  94. mov DWORD PTR [buffer], eax
  95. add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
  96. sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
  97. ;; Continue
  98. jmp GenerateBlock_Top
  99. ;; 1,2,3 bytes remain
  100. Partial_Machine_Word:
  101. ;; Test bit 1 to see if size is at least 2
  102. test bsize, 2
  103. jz Bit_1_Not_Set
  104. mov WORD PTR [buffer], ax
  105. shr eax, 16
  106. add buffer, 2
  107. Bit_1_Not_Set:
  108. ;; Test bit 0 to see if size is at least 1
  109. test bsize, 1
  110. jz GenerateBlock_Success
  111. mov BYTE PTR [buffer], al
  112. Bit_0_Not_Set:
  113. ;; We've hit all the bits
  114. jmp GenerateBlock_Success
  115. GenerateBlock_PreRet:
  116. ;; Test for success (was the request completely fulfilled?)
  117. cmp bsize, 0
  118. je GenerateBlock_Success
  119. GenerateBlock_Failure:
  120. xor eax, eax
  121. mov al, RDRAND_FAILURE
  122. ret
  123. GenerateBlock_Success:
  124. xor eax, eax
  125. mov al, RDRAND_SUCCESS
  126. ret
  127. MASM_RRA_GenerateBlock ENDP
  128. ENDIF ;; _M_X86
  129. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  130. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  131. IFDEF _M_X64 ;; Set via the command line
  132. .CODE
  133. ALIGN 16
  134. OPTION PROLOGUE:NONE
  135. OPTION EPILOGUE:NONE
  136. ;; RCX (in): arg1, byte* buffer
  137. ;; RDX (in): arg2, size_t bsize
  138. ;; R8d (in): arg3, unsigned int safety
  139. ;; RAX (out): success (1), failure (0)
  140. MASM_RRA_GenerateBlock PROC
  141. MWSIZE EQU 08h ;; machine word size
  142. buffer EQU rcx
  143. bsize EQU rdx
  144. safety EQU r8d
  145. ;; No need for Load_Arguments due to fastcall
  146. Validate_Pointer:
  147. ;; Validate pointer
  148. cmp buffer, 0
  149. je GenerateBlock_PreRet
  150. ;; Top of While loop
  151. GenerateBlock_Top:
  152. ;; Check remaining size
  153. cmp bsize, 0
  154. je GenerateBlock_Success
  155. Call_RDRAND_RAX:
  156. ;; RDRAND is not available prior to VS2012. Just emit
  157. ;; the byte codes using DB. This is `rdrand rax`.
  158. DB 048h, 0Fh, 0C7h, 0F0h
  159. ;; If CF=1, the number returned by RDRAND is valid.
  160. ;; If CF=0, a random number was not available.
  161. jc RDRAND_succeeded
  162. RDRAND_failed:
  163. ;; Exit if we've reached the limit
  164. cmp safety, 0
  165. je GenerateBlock_Failure
  166. dec safety
  167. jmp GenerateBlock_Top
  168. RDRAND_succeeded:
  169. cmp bsize, MWSIZE
  170. jb Partial_Machine_Word
  171. Full_Machine_Word:
  172. mov QWORD PTR [buffer], rax
  173. add buffer, MWSIZE
  174. sub bsize, MWSIZE
  175. ;; Continue
  176. jmp GenerateBlock_Top
  177. ;; 1,2,3,4,5,6,7 bytes remain
  178. Partial_Machine_Word:
  179. ;; Test bit 2 to see if size is at least 4
  180. test bsize, 4
  181. jz Bit_2_Not_Set
  182. mov DWORD PTR [buffer], eax
  183. shr rax, 32
  184. add buffer, 4
  185. Bit_2_Not_Set:
  186. ;; Test bit 1 to see if size is at least 2
  187. test bsize, 2
  188. jz Bit_1_Not_Set
  189. mov WORD PTR [buffer], ax
  190. shr eax, 16
  191. add buffer, 2
  192. Bit_1_Not_Set:
  193. ;; Test bit 0 to see if size is at least 1
  194. test bsize, 1
  195. jz GenerateBlock_Success
  196. mov BYTE PTR [buffer], al
  197. Bit_0_Not_Set:
  198. ;; We've hit all the bits
  199. jmp GenerateBlock_Success
  200. GenerateBlock_PreRet:
  201. ;; Test for success (was the request completely fulfilled?)
  202. cmp bsize, 0
  203. je GenerateBlock_Success
  204. GenerateBlock_Failure:
  205. xor rax, rax
  206. mov al, RDRAND_FAILURE
  207. ret
  208. GenerateBlock_Success:
  209. xor rax, rax
  210. mov al, RDRAND_SUCCESS
  211. ret
  212. MASM_RRA_GenerateBlock ENDP
  213. ENDIF ;; _M_X64
  214. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  215. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  216. IFDEF _M_X86 ;; Set via the command line
  217. .CODE
  218. ALIGN 8
  219. OPTION LANGUAGE:C
  220. OPTION PROLOGUE:NONE
  221. OPTION EPILOGUE:NONE
  222. ;; Base relative (in): arg1, byte* buffer
  223. ;; Base relative (in): arg2, size_t bsize
  224. ;; Base relative (in): arg3, unsigned int safety
  225. ;; EAX (out): success (1), failure (0)
  226. MASM_RSA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
  227. MWSIZE EQU 04h ;; machine word size
  228. buffer EQU edi
  229. bsize EQU edx
  230. safety EQU ecx
  231. Load_Arguments:
  232. mov buffer, arg1
  233. mov bsize, arg2
  234. mov safety, arg3
  235. Validate_Pointer:
  236. cmp buffer, 0
  237. je GenerateBlock_PreRet
  238. ;; Top of While loop
  239. GenerateBlock_Top:
  240. ;; Check remaining size
  241. cmp bsize, 0
  242. je GenerateBlock_Success
  243. Call_RDSEED_EAX:
  244. ;; RDSEED is not available prior to VS2012. Just emit
  245. ;; the byte codes using DB. This is `rdseed eax`.
  246. DB 0Fh, 0C7h, 0F8h
  247. ;; If CF=1, the number returned by RDSEED is valid.
  248. ;; If CF=0, a random number was not available.
  249. jc RDSEED_succeeded
  250. RDSEED_failed:
  251. ;; Exit if we've reached the limit
  252. cmp safety, 0
  253. je GenerateBlock_Failure
  254. dec safety
  255. jmp GenerateBlock_Top
  256. RDSEED_succeeded:
  257. cmp bsize, MWSIZE
  258. jb Partial_Machine_Word
  259. Full_Machine_Word:
  260. mov DWORD PTR [buffer], eax
  261. add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
  262. sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
  263. ;; Continue
  264. jmp GenerateBlock_Top
  265. ;; 1,2,3 bytes remain
  266. Partial_Machine_Word:
  267. ;; Test bit 1 to see if size is at least 2
  268. test bsize, 2
  269. jz Bit_1_Not_Set
  270. mov WORD PTR [buffer], ax
  271. shr eax, 16
  272. add buffer, 2
  273. Bit_1_Not_Set:
  274. ;; Test bit 0 to see if size is at least 1
  275. test bsize, 1
  276. jz GenerateBlock_Success
  277. mov BYTE PTR [buffer], al
  278. Bit_0_Not_Set:
  279. ;; We've hit all the bits
  280. jmp GenerateBlock_Success
  281. GenerateBlock_PreRet:
  282. ;; Test for success (was the request completely fulfilled?)
  283. cmp bsize, 0
  284. je GenerateBlock_Success
  285. GenerateBlock_Failure:
  286. xor eax, eax
  287. mov al, RDSEED_FAILURE
  288. ret
  289. GenerateBlock_Success:
  290. xor eax, eax
  291. mov al, RDSEED_SUCCESS
  292. ret
  293. MASM_RSA_GenerateBlock ENDP
  294. ENDIF ;; _M_X86
  295. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  296. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  297. IFDEF _M_X64 ;; Set via the command line
  298. .CODE
  299. ALIGN 16
  300. OPTION PROLOGUE:NONE
  301. OPTION EPILOGUE:NONE
  302. ;; RCX (in): arg1, byte* buffer
  303. ;; RDX (in): arg2, size_t bsize
  304. ;; R8d (in): arg3, unsigned int safety
  305. ;; RAX (out): success (1), failure (0)
  306. MASM_RSA_GenerateBlock PROC ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
  307. MWSIZE EQU 08h ;; machine word size
  308. buffer EQU rcx
  309. bsize EQU rdx
  310. safety EQU r8d
  311. ;; No need for Load_Arguments due to fastcall
  312. Validate_Pointer:
  313. ;; Validate pointer
  314. cmp buffer, 0
  315. je GenerateBlock_PreRet
  316. ;; Top of While loop
  317. GenerateBlock_Top:
  318. ;; Check remaining size
  319. cmp bsize, 0
  320. je GenerateBlock_Success
  321. Call_RDSEED_RAX:
  322. ;; RDSEED is not available prior to VS2012. Just emit
  323. ;; the byte codes using DB. This is `rdseed rax`.
  324. DB 048h, 0Fh, 0C7h, 0F8h
  325. ;; If CF=1, the number returned by RDSEED is valid.
  326. ;; If CF=0, a random number was not available.
  327. jc RDSEED_succeeded
  328. RDSEED_failed:
  329. ;; Exit if we've reached the limit
  330. cmp safety, 0
  331. je GenerateBlock_Failure
  332. dec safety
  333. jmp GenerateBlock_Top
  334. RDSEED_succeeded:
  335. cmp bsize, MWSIZE
  336. jb Partial_Machine_Word
  337. Full_Machine_Word:
  338. mov QWORD PTR [buffer], rax
  339. add buffer, MWSIZE
  340. sub bsize, MWSIZE
  341. ;; Continue
  342. jmp GenerateBlock_Top
  343. ;; 1,2,3,4,5,6,7 bytes remain
  344. Partial_Machine_Word:
  345. ;; Test bit 2 to see if size is at least 4
  346. test bsize, 4
  347. jz Bit_2_Not_Set
  348. mov DWORD PTR [buffer], eax
  349. shr rax, 32
  350. add buffer, 4
  351. Bit_2_Not_Set:
  352. ;; Test bit 1 to see if size is at least 2
  353. test bsize, 2
  354. jz Bit_1_Not_Set
  355. mov WORD PTR [buffer], ax
  356. shr eax, 16
  357. add buffer, 2
  358. Bit_1_Not_Set:
  359. ;; Test bit 0 to see if size is at least 1
  360. test bsize, 1
  361. jz GenerateBlock_Success
  362. mov BYTE PTR [buffer], al
  363. Bit_0_Not_Set:
  364. ;; We've hit all the bits
  365. jmp GenerateBlock_Success
  366. GenerateBlock_PreRet:
  367. ;; Test for success (was the request completely fulfilled?)
  368. cmp bsize, 0
  369. je GenerateBlock_Success
  370. GenerateBlock_Failure:
  371. xor rax, rax
  372. mov al, RDSEED_FAILURE
  373. ret
  374. GenerateBlock_Success:
  375. xor rax, rax
  376. mov al, RDSEED_SUCCESS
  377. ret
  378. MASM_RSA_GenerateBlock ENDP
  379. ENDIF ;; _M_X64
  380. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  381. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  382. END