VeraCrypt
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMounir IDRASSI <mounir.idrassi@idrix.fr>2019-01-31 00:05:19 (GMT)
committerMounir IDRASSI <mounir.idrassi@idrix.fr>2019-01-31 23:35:50 (GMT)
commit61c1baa4bf5a97675187a37cf203e1937a060daa (patch)
treedbf4cba079f6497740fecd325b22bf47f6a03731
parent915855f43b6bd30c2e01a49e261f813ccc7a0237 (diff)
downloadVeraCrypt-61c1baa4bf5a97675187a37cf203e1937a060daa.zip
VeraCrypt-61c1baa4bf5a97675187a37cf203e1937a060daa.tar.gz
Windows: use CPU RDRAND or RDSEED as an additional entropy source for our random generator when available
-rw-r--r--src/Common/Random.c30
-rw-r--r--src/Crypto/Crypto.vcxproj19
-rw-r--r--src/Crypto/Crypto.vcxproj.filters9
-rw-r--r--src/Crypto/Makefile.inc9
-rw-r--r--src/Crypto/Sources4
-rw-r--r--src/Crypto/rdrand.c32
-rw-r--r--src/Crypto/rdrand.h26
-rw-r--r--src/Crypto/rdrand_ml.asm420
8 files changed, 544 insertions, 5 deletions
diff --git a/src/Common/Random.c b/src/Common/Random.c
index 6c95cf6..12e9d9a 100644
--- a/src/Common/Random.c
+++ b/src/Common/Random.c
@@ -14,6 +14,8 @@
#include "Tcdefs.h"
#include "Crc.h"
#include "Random.h"
+#include "Crypto\cpu.h"
+#include "Crypto\rdrand.h"
#include <Strsafe.h>
static unsigned __int8 buffer[RNG_POOL_SIZE];
@@ -766,10 +768,6 @@ BOOL SlowPoll (void)
if (CryptGenRandom (hCryptProv, sizeof (buffer), buffer))
{
RandaddBuf (buffer, sizeof (buffer));
-
- burn(buffer, sizeof (buffer));
- Randmix();
- return TRUE;
}
else
{
@@ -777,6 +775,19 @@ BOOL SlowPoll (void)
CryptoAPILastError = GetLastError ();
return FALSE;
}
+
+ // use RDSEED or RDRAND from CPU as source of entropy if present
+ if ( (HasRDSEED() && RDSEED_getBytes (buffer, sizeof (buffer)))
+ || (HasRDRAND() && RDRAND_getBytes (buffer, sizeof (buffer)))
+ )
+ {
+ RandaddBuf (buffer, sizeof (buffer));
+ }
+
+ burn(buffer, sizeof (buffer));
+ Randmix();
+
+ return TRUE;
}
@@ -888,7 +899,6 @@ BOOL FastPoll (void)
if (CryptGenRandom (hCryptProv, sizeof (buffer), buffer))
{
RandaddBuf (buffer, sizeof (buffer));
- burn (buffer, sizeof(buffer));
}
else
{
@@ -897,6 +907,16 @@ BOOL FastPoll (void)
return FALSE;
}
+ // use RDSEED or RDRAND from CPU as source of entropy if present
+ if ( (HasRDSEED() && RDSEED_getBytes (buffer, sizeof (buffer)))
+ || (HasRDRAND() && RDRAND_getBytes (buffer, sizeof (buffer)))
+ )
+ {
+ RandaddBuf (buffer, sizeof (buffer));
+ }
+
+ burn (buffer, sizeof(buffer));
+
/* Apply the pool mixing function */
Randmix();
diff --git a/src/Crypto/Crypto.vcxproj b/src/Crypto/Crypto.vcxproj
index cd087be..43ac766 100644
--- a/src/Crypto/Crypto.vcxproj
+++ b/src/Crypto/Crypto.vcxproj
@@ -219,6 +219,7 @@
<ClCompile Include="GostCipher.c" />
<ClCompile Include="kuznyechik.c" />
<ClCompile Include="kuznyechik_simd.c" />
+ <ClCompile Include="rdrand.c" />
<ClCompile Include="Rmd160.c" />
<ClCompile Include="SerpentFast.c" />
<ClCompile Include="SerpentFast_simd.cpp" />
@@ -238,6 +239,7 @@
<ClInclude Include="GostCipher.h" />
<ClInclude Include="kuznyechik.h" />
<ClInclude Include="misc.h" />
+ <ClInclude Include="rdrand.h" />
<ClInclude Include="Rmd160.h" />
<ClInclude Include="SerpentFast.h" />
<ClInclude Include="SerpentFast_sbox.h" />
@@ -366,6 +368,23 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
</CustomBuild>
</ItemGroup>
+ <ItemGroup>
+ <CustomBuild Include="rdrand_ml.asm">
+ <FileType>Document</FileType>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo %(Filename)%(Extension) &amp; ml64.exe /nologo /D_M_X64 /W3 /Cx /Zi /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
+</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo %(Filename)%(Extension) &amp; ml64.exe /nologo /D_M_X64 /W3 /Cx /Zi /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
+</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo %(Filename)%(Extension) &amp; ml.exe /nologo /D_M_X86 /W3 /Cx /Zi /safeseh /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
+</Command>
+ <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo %(Filename)%(Extension) &amp; ml.exe /nologo /D_M_X86 /W3 /Cx /Zi /safeseh /Fo "$(TargetDir)\%(Filename).obj" /c "%(FullPath)"
+</Command>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
+ <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(TargetDir)\%(Filename).obj;%(Outputs)</Outputs>
+ </CustomBuild>
+ </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
diff --git a/src/Crypto/Crypto.vcxproj.filters b/src/Crypto/Crypto.vcxproj.filters
index f107088..c8d91b6 100644
--- a/src/Crypto/Crypto.vcxproj.filters
+++ b/src/Crypto/Crypto.vcxproj.filters
@@ -57,6 +57,9 @@
<ClCompile Include="kuznyechik_simd.c">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="rdrand.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Aes.h">
@@ -110,6 +113,9 @@
<ClInclude Include="SerpentFast_sbox.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="rdrand.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="Aes_hw_cpu.asm">
@@ -160,5 +166,8 @@
<CustomBuild Include="sha512_sse4_x64.asm">
<Filter>Source Files</Filter>
</CustomBuild>
+ <CustomBuild Include="rdrand_ml.asm">
+ <Filter>Source Files</Filter>
+ </CustomBuild>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/src/Crypto/Makefile.inc b/src/Crypto/Makefile.inc
index 016451a..86b7a6f 100644
--- a/src/Crypto/Makefile.inc
+++ b/src/Crypto/Makefile.inc
@@ -1,12 +1,17 @@
TC_ASFLAGS = -Xvc -Ox
VC_YASMFLAGS = -Xvc -D WINABI -D __YASM__
+VC_MLFLAGS = /nologo /W3 /Cx /Zi
+VC_MLEXE = ml.exe
!if "$(TC_ARCH)" == "x86"
TC_ASFLAGS = $(TC_ASFLAGS) -f win32 --prefix _ -D MS_STDCALL -D DLL_EXPORT
VC_YASMFLAGS = $(VC_YASMFLAGS) -f win32 -D MS_STDCALL
+VC_MLFLAGS = $(VC_MLFLAGS) /D_M_X86 /safeseh
!else
TC_ASFLAGS = $(TC_ASFLAGS) -f win64
VC_YASMFLAGS = $(VC_YASMFLAGS) -f win64
+VC_MLFLAGS = $(VC_MLFLAGS) /D_M_X64
+VC_MLEXE = ml64.exe
!endif
TC_ASM_ERR_LOG = ..\Driver\build_errors_asm.log
@@ -52,3 +57,7 @@ TC_ASM_ERR_LOG = ..\Driver\build_errors_asm.log
"$(OBJ_PATH)\$(O)\sha256_sse4_$(TC_ARCH).obj": sha256_sse4_$(TC_ARCH).asm
yasm.exe $(VC_YASMFLAGS) -o "$@" -l "$(OBJ_PATH)\$(O)\sha256_sse4_$(TC_ARCH).lst" sha256_sse4_$(TC_ARCH).asm 2>$(TC_ASM_ERR_LOG)
+
+"$(OBJ_PATH)\$(O)\rdrand_ml.obj": rdrand_ml.asm
+ $(VC_MLEXE) $(VC_MLFLAGS) /Fo "$@" /c rdrand_ml.asm 2>$(TC_ASM_ERR_LOG)
+
diff --git a/src/Crypto/Sources b/src/Crypto/Sources
index 054bf02..271edca 100644
--- a/src/Crypto/Sources
+++ b/src/Crypto/Sources
@@ -6,6 +6,8 @@ INCLUDES = ..
NTTARGETFILES = \
"$(OBJ_PATH)\$(O)\Aes_$(TC_ARCH).obj" \
"$(OBJ_PATH)\$(O)\Aes_hw_cpu.obj" \
+ "$(OBJ_PATH)\$(O)\rdrand.obj" \
+ "$(OBJ_PATH)\$(O)\rdrand_ml.obj" \
"$(OBJ_PATH)\$(O)\gost89_$(TC_ARCH).obj" \
"$(OBJ_PATH)\$(O)\Twofish_$(TC_ARCH).obj" \
"$(OBJ_PATH)\$(O)\Camellia_$(TC_ARCH).obj" \
@@ -23,9 +25,11 @@ SOURCES = \
Aes_$(TC_ARCH).asm \
gost89_$(TC_ARCH).asm \
Aes_hw_cpu.asm \
+ rdrand_ml.asm \
Aeskey.c \
Aestab.c \
cpu.c \
+ rdrand.c \
Rmd160.c \
SerpentFast.c \
SerpentFast_simd.cpp \
diff --git a/src/Crypto/rdrand.c b/src/Crypto/rdrand.c
new file mode 100644
index 0000000..afed7cd
--- /dev/null
+++ b/src/Crypto/rdrand.c
@@ -0,0 +1,32 @@
+// rdrand.cpp - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
+
+/* modified for VeraCrypt */
+
+#include "chacha256.h"
+#include "cpu.h"
+#include "misc.h"
+
+void CRYPTOPP_FASTCALL MASM_RDRAND_GenerateBlock(byte*, size_t);
+void CRYPTOPP_FASTCALL MASM_RDSEED_GenerateBlock(byte*, size_t);
+
+int RDRAND_getBytes(unsigned char* buf, size_t bufLen)
+{
+ if (!buf || !HasRDRAND())
+ return 0;
+
+ if (bufLen)
+ MASM_RDRAND_GenerateBlock(buf, bufLen);
+
+ return 1;
+}
+
+int RDSEED_getBytes(unsigned char* buf, size_t bufLen)
+{
+ if (!buf || !HasRDSEED())
+ return 0;
+
+ if (bufLen)
+ MASM_RDSEED_GenerateBlock(buf, bufLen);
+
+ return 1;
+}
diff --git a/src/Crypto/rdrand.h b/src/Crypto/rdrand.h
new file mode 100644
index 0000000..ff8cfd2
--- /dev/null
+++ b/src/Crypto/rdrand.h
@@ -0,0 +1,26 @@
+#ifndef HEADER_Crypto_RDRAND
+#define HEADER_Crypto_RDRAND
+
+#include "Common/Tcdefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * generate bufLen random bytes using CPU RDRAND instruction
+ * return 1 in case of success and 0 in case of failure
+ */
+int RDRAND_getBytes(unsigned char* buf, size_t bufLen);
+
+/*
+ * generate bufLen random bytes using CPU RDSEED instruction
+ * return 1 in case of success and 0 in case of failure
+ */
+int RDSEED_getBytes(unsigned char* buf, size_t bufLen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/Crypto/rdrand_ml.asm b/src/Crypto/rdrand_ml.asm
new file mode 100644
index 0000000..1579a15
--- /dev/null
+++ b/src/Crypto/rdrand_ml.asm
@@ -0,0 +1,420 @@
+;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
+;; Copyright assigned to the Crypto++ project.
+
+;; This ASM file provides RDRAND and RDSEED to downlevel Microsoft tool chains.
+;; Everything "just works" under Visual Studio. Other platforms will have to
+;; run MASM/MASM-64 and then link to the object files.
+
+;; set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
+;; set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
+;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\ml.exe" %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm
+;; "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64\ml64.exe" %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+TITLE MASM_RDRAND_GenerateBlock and MASM_RDSEED_GenerateBlock
+SUBTITLE Microsoft specific ASM code to utilize RDRAND and RDSEED for down level Microsoft toolchains
+
+PUBLIC MASM_RDRAND_GenerateBlock
+PUBLIC MASM_RDSEED_GenerateBlock
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; C/C++ Function prototypes (both are fastcall)
+;; X86:
+;; extern "C" void __fastcall MASM_RDRAND_GenerateBlock(byte* ptr, size_t size);
+;; X64:
+;; extern "C" void __fastcall MASM_RDRAND_GenerateBlock(byte* ptr, size_t size);
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+IFDEF _M_X86 ;; Set via the command line
+
+.486
+.MODEL FLAT
+
+;; Fastcall calling conventions exports
+ALIAS <@MASM_RDRAND_GenerateBlock@8> = <MASM_RDRAND_GenerateBlock>
+ALIAS <@MASM_RDSEED_GenerateBlock@8> = <MASM_RDSEED_GenerateBlock>
+
+ENDIF
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+IFDEF _M_X86 ;; Set via the command line
+
+.CODE
+ALIGN 8
+OPTION PROLOGUE:NONE
+OPTION EPILOGUE:NONE
+
+;; No need for Load_Arguments due to fastcall
+;; ECX (in): arg1, byte* buffer
+;; EDX (in): arg2, size_t bsize
+
+MASM_RDRAND_GenerateBlock PROC ;; arg1:DWORD, arg2:DWORD
+
+ MWSIZE EQU 04h ;; machine word size
+ buffer EQU ecx
+ bsize EQU edx
+
+ ;; Top of While loop
+GenerateBlock_Top:
+
+ ;; Check remaining size
+ cmp bsize, 0
+ je GenerateBlock_Return
+
+Call_RDRAND_EAX:
+ ;; RDRAND is not available prior to VS2012. Just emit
+ ;; the byte codes using DB. This is `rdrand eax`.
+ DB 0Fh, 0C7h, 0F0h
+
+ ;; If CF=1, the number returned by RDRAND is valid.
+ ;; If CF=0, a random number was not available.
+
+ ;; Retry immediately
+ jnc Call_RDRAND_EAX
+
+RDRAND_succeeded:
+
+ cmp bsize, MWSIZE
+ jb Partial_Machine_Word
+
+Full_Machine_Word:
+
+ mov DWORD PTR [buffer], eax
+ add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
+ sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
+
+ ;; Continue
+ jmp GenerateBlock_Top
+
+ ;; 1,2,3 bytes remain
+Partial_Machine_Word:
+
+ ;; Test bit 1 to see if size is at least 2
+ test bsize, 2
+ jz Bit_1_Not_Set
+
+ mov WORD PTR [buffer], ax
+ shr eax, 16
+ add buffer, 2
+
+Bit_1_Not_Set:
+
+ ;; Test bit 0 to see if size is at least 1
+ test bsize, 1
+ jz Bit_0_Not_Set
+
+ mov BYTE PTR [buffer], al
+
+Bit_0_Not_Set:
+
+ ;; We've hit all the bits
+
+GenerateBlock_Return:
+
+ ;; Clear artifacts
+ xor eax, eax
+ ret
+
+MASM_RDRAND_GenerateBlock ENDP
+
+ENDIF ;; _M_X86
+
+OPTION PROLOGUE:PrologueDef
+OPTION EPILOGUE:EpilogueDef
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+IFDEF _M_X64 ;; Set via the command line
+
+.CODE
+ALIGN 16
+OPTION PROLOGUE:NONE
+OPTION EPILOGUE:NONE
+
+;; No need for Load_Arguments due to fastcall
+;; RCX (in): arg1, byte* buffer
+;; RDX (in): arg2, size_t bsize
+
+MASM_RDRAND_GenerateBlock PROC ;; arg1:QWORD, arg2:QWORD
+
+ MWSIZE EQU 08h ;; machine word size
+ buffer EQU rcx
+ bsize EQU rdx
+
+ ;; Top of While loop
+GenerateBlock_Top:
+
+ ;; Check remaining size
+ cmp bsize, 0
+ je GenerateBlock_Return
+
+Call_RDRAND_RAX:
+ ;; RDRAND is not available prior to VS2012. Just emit
+ ;; the byte codes using DB. This is `rdrand rax`.
+ DB 048h, 0Fh, 0C7h, 0F0h
+
+ ;; If CF=1, the number returned by RDRAND is valid.
+ ;; If CF=0, a random number was not available.
+
+ ;; Retry immediately
+ jnc Call_RDRAND_RAX
+
+RDRAND_succeeded:
+
+ cmp bsize, MWSIZE
+ jb Partial_Machine_Word
+
+Full_Machine_Word:
+
+ mov QWORD PTR [buffer], rax
+ add buffer, MWSIZE
+ sub bsize, MWSIZE
+
+ ;; Continue
+ jmp GenerateBlock_Top
+
+ ;; 1,2,3,4,5,6,7 bytes remain
+Partial_Machine_Word:
+
+ ;; Test bit 2 to see if size is at least 4
+ test bsize, 4
+ jz Bit_2_Not_Set
+
+ mov DWORD PTR [buffer], eax
+ shr rax, 32
+ add buffer, 4
+
+Bit_2_Not_Set:
+
+ ;; Test bit 1 to see if size is at least 2
+ test bsize, 2
+ jz Bit_1_Not_Set
+
+ mov WORD PTR [buffer], ax
+ shr eax, 16
+ add buffer, 2
+
+Bit_1_Not_Set:
+
+ ;; Test bit 0 to see if size is at least 1
+ test bsize, 1
+ jz Bit_0_Not_Set
+
+ mov BYTE PTR [buffer], al
+
+Bit_0_Not_Set:
+
+ ;; We've hit all the bits
+
+GenerateBlock_Return:
+
+ ;; Clear artifacts
+ xor rax, rax
+ ret
+
+MASM_RDRAND_GenerateBlock ENDP
+
+ENDIF ;; _M_X64
+
+OPTION PROLOGUE:PrologueDef
+OPTION EPILOGUE:EpilogueDef
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+IFDEF _M_X86 ;; Set via the command line
+
+.CODE
+ALIGN 8
+OPTION PROLOGUE:NONE
+OPTION EPILOGUE:NONE
+
+;; No need for Load_Arguments due to fastcall
+;; ECX (in): arg1, byte* buffer
+;; EDX (in): arg2, size_t bsize
+
+MASM_RDSEED_GenerateBlock PROC ;; arg1:DWORD, arg2:DWORD
+
+ MWSIZE EQU 04h ;; machine word size
+ buffer EQU ecx
+ bsize EQU edx
+
+ ;; Top of While loop
+GenerateBlock_Top:
+
+ ;; Check remaining size
+ cmp bsize, 0
+ je GenerateBlock_Return
+
+Call_RDSEED_EAX:
+ ;; RDSEED is not available prior to VS2012. Just emit
+ ;; the byte codes using DB. This is `rdseed eax`.
+ DB 0Fh, 0C7h, 0F8h
+
+ ;; If CF=1, the number returned by RDSEED is valid.
+ ;; If CF=0, a random number was not available.
+
+ ;; Retry immediately
+ jnc Call_RDSEED_EAX
+
+RDSEED_succeeded:
+
+ cmp bsize, MWSIZE
+ jb Partial_Machine_Word
+
+Full_Machine_Word:
+
+ mov DWORD PTR [buffer], eax
+ add buffer, MWSIZE ;; No need for Intel Core 2 slow workarounds, like
+ sub bsize, MWSIZE ;; `lea buffer,[buffer+MWSIZE]` for faster adds
+
+ ;; Continue
+ jmp GenerateBlock_Top
+
+ ;; 1,2,3 bytes remain
+Partial_Machine_Word:
+
+ ;; Test bit 1 to see if size is at least 2
+ test bsize, 2
+ jz Bit_1_Not_Set
+
+ mov WORD PTR [buffer], ax
+ shr eax, 16
+ add buffer, 2
+
+Bit_1_Not_Set:
+
+ ;; Test bit 0 to see if size is at least 1
+ test bsize, 1
+ jz Bit_0_Not_Set
+
+ mov BYTE PTR [buffer], al
+
+Bit_0_Not_Set:
+
+ ;; We've hit all the bits
+
+GenerateBlock_Return:
+
+ ;; Clear artifacts
+ xor eax, eax
+ ret
+
+MASM_RDSEED_GenerateBlock ENDP
+
+ENDIF ;; _M_X86
+
+OPTION PROLOGUE:PrologueDef
+OPTION EPILOGUE:EpilogueDef
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+IFDEF _M_X64 ;; Set via the command line
+
+.CODE
+ALIGN 16
+OPTION PROLOGUE:NONE
+OPTION EPILOGUE:NONE
+
+;; No need for Load_Arguments due to fastcall
+;; RCX (in): arg1, byte* buffer
+;; RDX (in): arg2, size_t bsize
+
+MASM_RDSEED_GenerateBlock PROC ;; arg1:QWORD, arg2:QWORD
+
+ MWSIZE EQU 08h ;; machine word size
+ buffer EQU rcx
+ bsize EQU rdx
+
+ ;; Top of While loop
+GenerateBlock_Top:
+
+ ;; Check remaining size
+ cmp bsize, 0
+ je GenerateBlock_Return
+
+Call_RDSEED_RAX:
+ ;; RDSEED is not available prior to VS2012. Just emit
+ ;; the byte codes using DB. This is `rdseed rax`.
+ DB 048h, 0Fh, 0C7h, 0F8h
+
+ ;; If CF=1, the number returned by RDSEED is valid.
+ ;; If CF=0, a random number was not available.
+
+ ;; Retry immediately
+ jnc Call_RDSEED_RAX
+
+RDSEED_succeeded:
+
+ cmp bsize, MWSIZE
+ jb Partial_Machine_Word
+
+Full_Machine_Word:
+
+ mov QWORD PTR [buffer], rax
+ add buffer, MWSIZE
+ sub bsize, MWSIZE
+
+ ;; Continue
+ jmp GenerateBlock_Top
+
+ ;; 1,2,3,4,5,6,7 bytes remain
+Partial_Machine_Word:
+
+ ;; Test bit 2 to see if size is at least 4
+ test bsize, 4
+ jz Bit_2_Not_Set
+
+ mov DWORD PTR [buffer], eax
+ shr rax, 32
+ add buffer, 4
+
+Bit_2_Not_Set:
+
+ ;; Test bit 1 to see if size is at least 2
+ test bsize, 2
+ jz Bit_1_Not_Set
+
+ mov WORD PTR [buffer], ax
+ shr eax, 16
+ add buffer, 2
+
+Bit_1_Not_Set:
+
+ ;; Test bit 0 to see if size is at least 1
+ test bsize, 1
+ jz Bit_0_Not_Set
+
+ mov BYTE PTR [buffer], al
+
+Bit_0_Not_Set:
+
+ ;; We've hit all the bits
+
+GenerateBlock_Return:
+
+ ;; Clear artifacts
+ xor rax, rax
+ ret
+
+MASM_RDSEED_GenerateBlock ENDP
+
+ENDIF ;; _M_X64
+
+OPTION PROLOGUE:PrologueDef
+OPTION EPILOGUE:EpilogueDef
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+END