Cleared issues 11,12,13 (Clang integrated assembler), 58 (RC rollup), 66 (Coverity rollup)

pull/75/head
Jeffrey Walton 2015-11-18 15:19:02 -05:00
parent 1993a8b7b9
commit d2fda9bd42
7 changed files with 1425 additions and 609 deletions

393
Filelist.txt Normal file
View File

@ -0,0 +1,393 @@
3way.cpp
3way.h
adhoc.cpp.proto
adler32.cpp
adler32.h
aes.h
algebra.cpp
algebra.h
algparam.cpp
algparam.h
arc4.cpp
arc4.h
argnames.h
asn.cpp
asn.h
authenc.cpp
authenc.h
base32.cpp
base32.h
base64.cpp
base64.h
basecode.cpp
basecode.h
bench.cpp
bench.h
bench2.cpp
bfinit.cpp
blowfish.cpp
blowfish.h
blumshub.cpp
blumshub.h
camellia.cpp
camellia.h
cast.cpp
cast.h
casts.cpp
cbcmac.cpp
cbcmac.h
ccm.cpp
ccm.h
channels.cpp
channels.h
cmac.cpp
cmac.h
config.h
config.recommend
cpu.cpp
cpu.h
crc.cpp
crc.h
cryptdll.dsp
cryptdll.vcproj
cryptest.dsp
cryptest.dsw
cryptest.sh
cryptest.sln
cryptest.vcproj
cryptest_bds.bdsgroup
cryptest_bds.bdsproj
cryptest_bds.bpf
cryptlib.cpp
cryptlib.dsp
cryptlib.h
cryptlib.vcproj
cryptlib_bds.bdsproj
cryptlib_bds.cpp
cryptopp.rc
cryptopp563.diff
datatest.cpp
default.cpp
default.h
des.cpp
des.h
dessp.cpp
dh.cpp
dh.h
dh2.cpp
dh2.h
dll.cpp
dll.h
dlltest.cpp
dlltest.dsp
dlltest.vcproj
dmac.h
dsa.cpp
dsa.h
eax.cpp
eax.h
ec2n.cpp
ec2n.h
eccrypto.cpp
eccrypto.h
ecp.cpp
ecp.h
elgamal.cpp
elgamal.h
emsa2.cpp
emsa2.h
eprecomp.cpp
eprecomp.h
esign.cpp
esign.h
factory.h
files.cpp
files.h
filters.cpp
filters.h
fips140.cpp
fips140.h
fipsalgt.cpp
fipstest.cpp
fltrimpl.h
gcm.cpp
gcm.h
gf256.cpp
gf256.h
gf2_32.cpp
gf2_32.h
gf2n.cpp
gf2n.h
gfpcrypt.cpp
gfpcrypt.h
gost.cpp
gost.h
gzip.cpp
gzip.h
hex.cpp
hex.h
hkdf.h
hmac.cpp
hmac.h
hrtimer.cpp
hrtimer.h
ida.cpp
ida.h
idea.cpp
idea.h
integer.cpp
integer.h
iterhash.cpp
iterhash.h
lubyrack.h
luc.cpp
luc.h
mars.cpp
mars.h
marss.cpp
md2.cpp
md2.h
md4.cpp
md4.h
md5.cpp
md5.h
mdc.h
mersenne.h
misc.cpp
misc.h
modarith.h
modes.cpp
modes.h
modexppc.h
mqueue.cpp
mqueue.h
mqv.cpp
mqv.h
nbtheory.cpp
nbtheory.h
network.cpp
network.h
nr.h
oaep.cpp
oaep.h
oids.h
osrng.cpp
osrng.h
panama.cpp
panama.h
pch.cpp
pch.h
pkcspad.cpp
pkcspad.h
polynomi.cpp
polynomi.h
pssr.cpp
pssr.h
pubkey.cpp
pubkey.h
pwdbased.h
queue.cpp
queue.h
rabin.cpp
rabin.h
randpool.cpp
randpool.h
rc2.cpp
rc2.h
rc5.cpp
rc5.h
rc6.cpp
rc6.h
rdrand-masm.cmd
rdrand-nasm.sh
rdrand.S
rdrand.asm
rdrand.cpp
rdrand.h
rdtables.cpp
regtest.cpp
resource.h
rijndael.cpp
rijndael.h
ripemd.cpp
ripemd.h
rng.cpp
rng.h
rsa.cpp
rsa.h
rw.cpp
rw.h
safer.cpp
safer.h
salsa.cpp
salsa.h
seal.cpp
seal.h
secblock.h
seckey.h
seed.cpp
seed.h
serpent.cpp
serpent.h
serpentp.h
sha.cpp
sha.h
sha3.cpp
sha3.h
shacal2.cpp
shacal2.h
shark.cpp
shark.h
sharkbox.cpp
simple.cpp
simple.h
skipjack.cpp
skipjack.h
smartptr.h
socketft.cpp
socketft.h
sosemanuk.cpp
sosemanuk.h
square.cpp
square.h
squaretb.cpp
stdcpp.h
strciphr.cpp
strciphr.h
tea.cpp
tea.h
test.cpp
tftables.cpp
tiger.cpp
tiger.h
tigertab.cpp
trdlocal.cpp
trdlocal.h
trunhash.h
ttmac.cpp
ttmac.h
twofish.cpp
twofish.h
validat1.cpp
validat2.cpp
validat3.cpp
validate.h
vmac.cpp
vmac.h
vs2010.zip
wait.cpp
wait.h
wake.cpp
wake.h
whrlpool.cpp
whrlpool.h
winpipes.cpp
winpipes.h
words.h
x64dll.asm
x64masm.asm
xtr.cpp
xtr.h
xtrcrypt.cpp
xtrcrypt.h
zdeflate.cpp
zdeflate.h
zinflate.cpp
zinflate.h
zlib.cpp
zlib.h
Doxyfile
GNUmakefile
GNUmakefile-cross
License.txt
Readme.txt
Install.txt
Filelist.txt
TestData/3desval.dat
TestData/3wayval.dat
TestData/camellia.dat
TestData/cast128v.dat
TestData/cast256v.dat
TestData/descert.dat
TestData/dh1024.dat
TestData/dh2048.dat
TestData/dlie1024.dat
TestData/dlie2048.dat
TestData/dsa1024.dat
TestData/dsa1024b.dat
TestData/dsa512.dat
TestData/elgc1024.dat
TestData/esig1023.dat
TestData/esig1536.dat
TestData/esig2046.dat
TestData/gostval.dat
TestData/ideaval.dat
TestData/luc1024.dat
TestData/luc2048.dat
TestData/lucc1024.dat
TestData/lucc512.dat
TestData/lucd1024.dat
TestData/lucd512.dat
TestData/lucs1024.dat
TestData/lucs512.dat
TestData/marsval.dat
TestData/mqv1024.dat
TestData/mqv2048.dat
TestData/nr1024.dat
TestData/nr2048.dat
TestData/rabi1024.dat
TestData/rabi2048.dat
TestData/rc2val.dat
TestData/rc5val.dat
TestData/rc6val.dat
TestData/rijndael.dat
TestData/rsa1024.dat
TestData/rsa2048.dat
TestData/rsa400pb.dat
TestData/rsa400pv.dat
TestData/rsa512a.dat
TestData/rw1024.dat
TestData/rw2048.dat
TestData/saferval.dat
TestData/serpentv.dat
TestData/shacal2v.dat
TestData/sharkval.dat
TestData/skipjack.dat
TestData/squareva.dat
TestData/twofishv.dat
TestData/usage.dat
TestData/xtrdh171.dat
TestData/xtrdh342.dat
TestVectors/Readme.txt
TestVectors/aes.txt
TestVectors/all.txt
TestVectors/camellia.txt
TestVectors/ccm.txt
TestVectors/cmac.txt
TestVectors/dlies.txt
TestVectors/dsa.txt
TestVectors/dsa_1363.txt
TestVectors/eax.txt
TestVectors/esign.txt
TestVectors/gcm.txt
TestVectors/hkdf.txt
TestVectors/hmac.txt
TestVectors/mars.txt
TestVectors/nr.txt
TestVectors/panama.txt
TestVectors/rsa_oaep.txt
TestVectors/rsa_pkcs1_1_5.txt
TestVectors/rsa_pss.txt
TestVectors/rw.txt
TestVectors/salsa.txt
TestVectors/seal.txt
TestVectors/seed.txt
TestVectors/sha.txt
TestVectors/sha3.txt
TestVectors/shacal2.txt
TestVectors/sosemanuk.txt
TestVectors/tea.txt
TestVectors/ttmac.txt
TestVectors/vmac.txt
TestVectors/wake.txt
TestVectors/whrlpool.txt

117
rdrand-masm.cmd Executable file
View File

@ -0,0 +1,117 @@
REM make-rdrand
@echo OFF
@cls
@del rdrand.obj rdrand-x86.obj rdrand-x64.obj rdrand-x86.lib rdrand-x64.lib /Q > nul
REM Visual Studio 2005
REM @set TOOLS32=C:\Program Files (x86)\Microsoft Visual Studio 8\VC\bin
REM @set TOOLS64=C:\Program Files (x86)\Microsoft Visual Studio 8\VC\bin\amd64
REM Visual Studio 2010
REM @set TOOLS32=C:\Program Files (x86)\Microsoft Visual Studio 10\VC\bin
REM @set TOOLS64=C:\Program Files (x86)\Microsoft Visual Studio 10\VC\bin\amd64
REM Visual Studio 2012
REM @set TOOLS32=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin
REM @set TOOLS64=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\bin\amd64
REM Visual Studio 2013
@set TOOLS32=C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin
@set TOOLS64=C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\amd64
@set MASM="%TOOLS32%\ml.exe"
@set MASM64="%TOOLS64%\ml64.exe"
@set DUMPBIN="%TOOLS32%\dumpbin.exe"
@set LIBTOOL="%TOOLS32%\lib.exe"
REM /W3 - Warning level
REM /Cx - Preserve case in external symbols
REM /Zi - Porgram Database information
@set ASFLAGS=/nologo /D_M_X86 /W3 /Cx /Zi /safeseh
@set ASFLAGS64=/nologo /D_M_X64 /W3 /Cx /Zi
@set LIBFLAGS=/nologo /SUBSYSTEM:CONSOLE
REM Use _M_X86 and _M_X64 becuase cl.exe uses them. It keeps preprocessor defines consistent.
echo ****************************************
echo Assembling rdrand.asm into rdrand-x86.obj
call %MASM% %ASFLAGS% /Fo rdrand-x86.obj /c rdrand.asm > nul
@IF NOT %ERRORLEVEL% EQU 0 (echo Failed to assemble rdrand.asm with X86 && goto SCRIPT_FAILED)
echo Done...
echo ****************************************
echo Assembling rdrand.asm into rdrand-x64.obj
call %MASM64% %ASFLAGS64% /Fo rdrand-x64.obj /c rdrand.asm > nul
@IF NOT %ERRORLEVEL% EQU 0 (echo Failed to assemble rdrand.asm with X64 && goto SCRIPT_FAILED)
echo Done...
echo ****************************************
echo Creating static library rdrand-x86.lib
call %LIBTOOL% %LIBFLAGS% /MACHINE:X86 /OUT:rdrand-x86.lib rdrand-x86.obj > nul
@IF NOT %ERRORLEVEL% EQU 0 (echo Failed to create rdrand-x86.lib && goto SCRIPT_FAILED)
echo Done...
echo ****************************************
echo Creating static library rdrand-x64.lib
call %LIBTOOL% %LIBFLAGS% /MACHINE:X64 /OUT:rdrand-x64.lib rdrand-x64.obj > nul
@IF NOT %ERRORLEVEL% EQU 0 (echo Failed to create rdrand-x64.lib && goto SCRIPT_FAILED)
echo Done...
goto SKIP_SYMBOL_DUMP_OBJ
echo ****************************************
echo Dumping symbols for rdrand-x86.obj
echo.
call %DUMPBIN% /SYMBOLS rdrand-x86.obj
echo ****************************************
echo Dumping symbols for rdrand-x64.obj
echo.
call %DUMPBIN% /SYMBOLS rdrand-x64.obj
:SKIP_SYMBOL_DUMP_OBJ
goto SKIP_SYMBOL_DUMP_LIB
echo ****************************************
echo Dumping symbols for rdrand-x86.lib
echo.
call %DUMPBIN% /SYMBOLS rdrand-x86.lib
echo ****************************************
echo Dumping symbols for rdrand-x64.lib
echo.
call %DUMPBIN% /SYMBOLS rdrand-x64.lib
:SKIP_SYMBOL_DUMP_LIB
goto SKIP_EXPORT_DUMP
echo ****************************************
echo Dumping exports for rdrand-x86.lib
echo.
call %DUMPBIN% /EXPORTS rdrand-x86.lib
echo ****************************************
echo Dumping exports for rdrand-x64.lib
echo.
call %DUMPBIN% /EXPORTS rdrand-x64.lib
:SKIP_EXPORT_DUMP
REM goto SKIP_DISASSEMBLY
echo ****************************************
echo Disassembling rdrand-x64.obj
echo.
call %DUMPBIN% /DISASM:NOBYTES rdrand-x64.obj
echo ****************************************
echo Disassembling rdrand-x86.obj
echo.
call %DUMPBIN% /DISASM:NOBYTES rdrand-x86.obj
:SKIP_DISASSEMBLY
:SCRIPT_FAILED

24
rdrand-nasm.sh Executable file
View File

@ -0,0 +1,24 @@
#!/bin/sh
reset
nasm -f elf32 rdrand.S -DX86 -g -o rdrand-x86.o
nasm -f elfx32 rdrand.S -DX32 -g -o rdrand-x32.o
nasm -f elf64 rdrand.S -DX64 -g -o rdrand-x64.o
echo "**************************************"
echo "**************************************"
objdump --disassemble rdrand-x86.o
echo
echo "**************************************"
echo "**************************************"
objdump --disassemble rdrand-x32.o
echo
echo "**************************************"
echo "**************************************"
objdump --disassemble rdrand-x64.o

599
rdrand.S Normal file
View File

@ -0,0 +1,599 @@
;; 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 Unix and Linux tool chains.
;; Additionally, the inline assembly code produced by GCC and Clang is not that
;; impressive. However, using this code requires NASM and an edit to the GNUmakefile.
;; nasm -f elf32 rdrand.S -DX86 -g -o rdrand-x86.o
;; nasm -f elfx32 rdrand.S -DX32 -g -o rdrand-x32.o
;; nasm -f elf64 rdrand.S -DX64 -g -o rdrand-x64.o
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Naming convention used in rdrand.{h|cpp|asm|S}
;; MSC = Microsoft Compiler (and compatibles)
;; GCC = GNU Compiler (and compatibles)
;; ALL = MSC and GCC (and compatibles)
;; RRA = RDRAND, Assembly
;; RSA = RDSEED, Assembly
;; RRI = RDRAND, Intrinsic
;; RSA = RDSEED, Intrinsic
;; Caller/Callee Saved Registers
;; https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; C/C++ Function prototypes
;; X86, X32 and X64:
;; extern "C" int NASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Return values
%define RDRAND_SUCCESS 1
%define RDRAND_FAILURE 0
%define RDSEED_SUCCESS 1
%define RDSEED_FAILURE 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%ifdef X86 or X32 ;; Set via the command line
;; Arg1, byte* buffer
;; Arg2, size_t bsize
;; Arg3, unsigned int safety
;; EAX (out): success (1), failure (0)
global NASM_RRA_GenerateBlock
section .text
%ifdef X86
align 8
cpu 486
%else
align 16
%endif
NASM_RRA_GenerateBlock:
%ifdef X86
%define arg1 [ebp+04h]
%define arg2 [ebp+08h]
%define arg3 [ebp+0ch]
%define MWSIZE 04h ;; machine word size
%else
%define MWSIZE 08h ;; machine word size
%endif
%define buffer edi
%define bsize esi
%define safety edx
%ifdef X86
.Load_Arguments:
mov buffer, arg1
mov bsize, arg2
mov safety, arg3
%endif
.Validate_Pointer:
cmp buffer, 0
je .GenerateBlock_PreRet
;; Top of While loop
.GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je .GenerateBlock_Success
%ifdef X86
.Call_RDRAND_EAX:
%else
.Call_RDRAND_RAX:
DB 48h ;; X32 can use the full register, issue the REX.w prefix
%endif
;; RDRAND is not available prior to VS2012. Just emit
;; the byte codes using DB. This is `rdrand eax`.
DB 0Fh, 07h, F0h
;; If CF=1, the number returned by RDRAND is valid.
;; If CF=0, a random number was not available.
jc .RDRAND_succeeded
.RDRAND_failed:
;; Exit if we've reached the limit
cmp safety, 0
je .GenerateBlock_Failure
dec safety
jmp .GenerateBlock_Top
.RDRAND_succeeded:
cmp bsize, MWSIZE
jb .Partial_Machine_Word
.Full_Machine_Word:
%ifdef X32
mov [buffer+4], eax ;; We can only move 4 at a time
DB 048h ;; Combined, these result in
shr eax, 32 ;; `shr rax, 32`
%endif
mov [buffer], eax
add buffer, MWSIZE ;; No need for Intel Core 2 slow word workarounds,
sub bsize, MWSIZE ;; like `lea buffer,[buffer+MWSIZE]` for faster adds
;; Continue
jmp .GenerateBlock_Top
;; 1,2,3 bytes remain for X86
;; 1,2,3,4,5,6,7 remain for X32
.Partial_Machine_Word:
%ifdef X32
;; Test bit 2 to see if size is at least 4
test bsize, 4
jz .Bit_2_Not_Set
mov [buffer], eax
add buffer, 4
DB 048h ;; Combined, these result in
shr eax, 32 ;; `shr rax, 32`
.Bit_2_Not_Set:
%endif
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz .Bit_1_Not_Set
mov [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 .GenerateBlock_Success
mov [buffer], al
.Bit_0_Not_Set:
;; We've hit all the bits
jmp .GenerateBlock_Success
.GenerateBlock_PreRet:
;; Test for success (was the request completely fulfilled?)
cmp bsize, 0
je .GenerateBlock_Success
.GenerateBlock_Failure:
xor eax, eax
mov al, RDRAND_FAILURE
ret
.GenerateBlock_Success:
xor eax, eax
mov al, RDRAND_SUCCESS
ret
%endif ;; X86 and X32
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%ifdef X64 ;; Set via the command line
global NASM_RRA_GenerateBlock
section .text
align 16
;; Arg1, byte* buffer
;; Arg2, size_t bsize
;; Arg3, unsigned int safety
;; RAX (out): success (1), failure (0)
NASM_RRA_GenerateBlock:
%define MWSIZE 08h ;; machine word size
%define buffer rdi
%define bsize rsi
%define safety edx
;; No need for Load_Arguments due to fastcall
.Validate_Pointer:
;; Validate pointer
cmp buffer, 0
je .GenerateBlock_PreRet
;; Top of While loop
.GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je .GenerateBlock_Success
.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.
jc .RDRAND_succeeded
.RDRAND_failed:
;; Exit if we've reached the limit
cmp safety, 0h
je .GenerateBlock_Failure
dec safety
jmp .GenerateBlock_Top
.RDRAND_succeeded:
cmp bsize, MWSIZE
jb .Partial_Machine_Word
.Full_Machine_Word:
mov [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 [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 [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 .GenerateBlock_Success
mov [buffer], al
.Bit_0_Not_Set:
;; We've hit all the bits
jmp .GenerateBlock_Success
.GenerateBlock_PreRet:
;; Test for success (was the request completely fulfilled?)
cmp bsize, 0
je .GenerateBlock_Success
.GenerateBlock_Failure:
xor rax, rax
mov al, RDRAND_FAILURE
ret
.GenerateBlock_Success:
xor rax, rax
mov al, RDRAND_SUCCESS
ret
%endif ;; X64
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%ifdef X86 or X32 ;; Set via the command line
;; Arg1, byte* buffer
;; Arg2, size_t bsize
;; Arg3, unsigned int safety
;; EAX (out): success (1), failure (0)
global NASM_RSA_GenerateBlock
section .text
align 8
%ifdef X86
align 8
cpu 486
%else
align 16
%endif
NASM_RSA_GenerateBlock:
%ifdef X86
%define arg1 [ebp+04h]
%define arg2 [ebp+08h]
%define arg3 [ebp+0ch]
%define MWSIZE 04h ;; machine word size
%else
%define MWSIZE 08h ;; machine word size
%endif
%define buffer edi
%define bsize esi
%define safety edx
%ifdef X86
.Load_Arguments:
mov buffer, arg1
mov bsize, arg2
mov safety, arg3
%endif
.Validate_Pointer:
cmp buffer, 0
je .GenerateBlock_PreRet
;; Top of While loop
.GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je .GenerateBlock_Success
%ifdef X86
.Call_RDSEED_EAX:
%else
.Call_RDSEED_RAX:
DB 48h ;; X32 can use the full register, issue the REX.w prefix
%endif
;; 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.
jc .RDSEED_succeeded
.RDSEED_failed:
;; Exit if we've reached the limit
cmp safety, 0
je .GenerateBlock_Failure
dec safety
jmp .GenerateBlock_Top
.RDSEED_succeeded:
cmp bsize, MWSIZE
jb .Partial_Machine_Word
.Full_Machine_Word:
mov [buffer], eax
add buffer, MWSIZE ;; No need for Intel Core 2 slow word workarounds,
sub bsize, MWSIZE ;; like `lea buffer,[buffer+MWSIZE]` for faster adds
;; Continue
jmp .GenerateBlock_Top
;; 1,2,3 bytes remain for X86
;; 1,2,3,4,5,6,7 remain for X32
.Partial_Machine_Word:
%ifdef X32
;; Test bit 2 to see if size is at least 4
test bsize, 4
jz .Bit_2_Not_Set
mov [buffer], eax
add buffer, 4
DB 048h ;; Combined, these result in
shr eax, 32 ;; `shr rax, 32`
.Bit_2_Not_Set:
%endif
;; Test bit 1 to see if size is at least 2
test bsize, 2
jz .Bit_1_Not_Set
mov [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 .GenerateBlock_Success
mov [buffer], al
.Bit_0_Not_Set:
;; We've hit all the bits
jmp .GenerateBlock_Success
.GenerateBlock_PreRet:
;; Test for success (was the request completely fulfilled?)
cmp bsize, 0
je .GenerateBlock_Success
.GenerateBlock_Failure:
xor eax, eax
mov al, RDSEED_FAILURE
ret
.GenerateBlock_Success:
xor eax, eax
mov al, RDSEED_SUCCESS
ret
%endif ;; X86 and X32
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%ifdef X64 ;; Set via the command line
global NASM_RSA_GenerateBlock
section .text
align 16
;; Arg1, byte* buffer
;; Arg2, size_t bsize
;; Arg3, unsigned int safety
;; RAX (out): success (1), failure (0)
NASM_RSA_GenerateBlock:
%define MWSIZE 08h ;; machine word size
%define buffer rdi
%define bsize rsi
%define safety edx
;; No need for Load_Arguments due to fastcall
.Validate_Pointer:
;; Validate pointer
cmp buffer, 0
je .GenerateBlock_PreRet
;; Top of While loop
.GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
je .GenerateBlock_Success
.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.
jc .RDSEED_succeeded
.RDSEED_failed:
;; Exit if we've reached the limit
cmp safety, 0
je .GenerateBlock_Failure
dec safety
jmp .GenerateBlock_Top
.RDSEED_succeeded:
cmp bsize, MWSIZE
jb .Partial_Machine_Word
.Full_Machine_Word:
mov [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 [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 [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 .GenerateBlock_Success
mov [buffer], al
.Bit_0_Not_Set:
;; We've hit all the bits
jmp .GenerateBlock_Success
.GenerateBlock_PreRet:
;; Test for success (was the request completely fulfilled?)
cmp bsize, 0
je .GenerateBlock_Success
.GenerateBlock_Failure:
xor rax, rax
mov al, RDSEED_FAILURE
ret
.GenerateBlock_Success:
xor rax, rax
mov al, RDSEED_SUCCESS
ret
%endif ;; _M_X64
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -1,10 +1,9 @@
;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
;; Copyright assigned to the Crypto++ project.
;; This ASM file exists for one reason only - to emit the RDRAND instruction for Microsoft platforms.
;; We can't call RDRAND directly on some versions of the toolchain (prior to CL 17.00/VS2012).
;; Additionally, Microsoft/Intel penalizes AMD CPUs with the feature. To avoid these troubles, we
;; provide the ASM and emit the opcodes for RDRAND by hand.
;; 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
@ -14,11 +13,11 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TITLE MSC_RRA_GenerateBlock and MSC_RSA_GenerateBlock
TITLE MASM_RRA_GenerateBlock and MASM_RSA_GenerateBlock
SUBTITLE Microsoft specific ASM code to utilize RDRAND and RDSEED for down level Microsoft toolchains
PUBLIC MSC_RRA_GenerateBlock
PUBLIC MSC_RSA_GenerateBlock
PUBLIC MASM_RRA_GenerateBlock
PUBLIC MASM_RSA_GenerateBlock
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -26,6 +25,7 @@ PUBLIC MSC_RSA_GenerateBlock
;; Naming convention used in rdrand.{h|cpp|asm}
;; MSC = Microsoft Compiler (and compatibles)
;; GCC = GNU Compiler (and compatibles)
;; ALL = MSC and GCC (and compatibles)
;; RRA = RDRAND, Assembly
;; RSA = RDSEED, Assembly
;; RRI = RDRAND, Intrinsic
@ -39,9 +39,9 @@ PUBLIC MSC_RSA_GenerateBlock
;; C/C++ Function prototypes
;; X86:
;; extern "C" int MSC_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
;; extern "C" int MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
;; X64:
;; extern "C" int __fastcall MSC_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
;; extern "C" int __fastcall MASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -79,8 +79,7 @@ OPTION EPILOGUE:NONE
;; Base relative (in): arg3, unsigned int safety
;; EAX (out): success (1), failure (0)
;; MSC_RRA_GenerateBlock PROC USES ecx edx edi arg1:DWORD,arg2:DWORD,arg3:DWORD
MSC_RRA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
MASM_RRA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
MWSIZE EQU 04h ;; machine word size
buffer EQU edi
@ -108,7 +107,7 @@ GenerateBlock_Top:
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
DB 0Fh, 0C7h, 0F0h
;; If CF=1, the number returned by RDRAND is valid.
;; If CF=0, a random number was not available.
@ -152,15 +151,13 @@ Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
;; jz Bit_0_Not_Set
jz GenerateBlock_Success
mov BYTE PTR [buffer], al
Bit_0_Not_Set:
;; We've hit all the bits, set size to 0
;; mov bsize, 0
;; We've hit all the bits
jmp GenerateBlock_Success
GenerateBlock_PreRet:
@ -171,18 +168,17 @@ GenerateBlock_PreRet:
GenerateBlock_Failure:
mov eax, RDRAND_FAILURE
jmp GenerateBlock_Ret
xor eax, eax
mov al, RDRAND_FAILURE
ret
GenerateBlock_Success:
mov eax, RDRAND_SUCCESS
GenerateBlock_Ret:
xor eax, eax
mov al, RDRAND_SUCCESS
ret
MSC_RRA_GenerateBlock ENDP
MASM_RRA_GenerateBlock ENDP
ENDIF ;; _M_X86
@ -201,8 +197,7 @@ OPTION EPILOGUE:NONE
;; R8d (in): arg3, unsigned int safety
;; RAX (out): success (1), failure (0)
;; MSC_RRA_GenerateBlock PROC USES RCX ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
MSC_RRA_GenerateBlock PROC ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
MASM_RRA_GenerateBlock PROC
MWSIZE EQU 08h ;; machine word size
buffer EQU rcx
@ -227,7 +222,7 @@ GenerateBlock_Top:
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
DB 048h, 0Fh, 0C7h, 0F0h
;; If CF=1, the number returned by RDRAND is valid.
;; If CF=0, a random number was not available.
@ -281,15 +276,13 @@ Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
;; jz Bit_0_Not_Set
jz GenerateBlock_Success
mov BYTE PTR [buffer], al
Bit_0_Not_Set:
;; We've hit all the bits, set size to 0
;; mov bsize, 0
;; We've hit all the bits
jmp GenerateBlock_Success
GenerateBlock_PreRet:
@ -300,18 +293,17 @@ GenerateBlock_PreRet:
GenerateBlock_Failure:
mov rax, RDRAND_FAILURE
jmp GenerateBlock_Ret
xor rax, rax
mov al, RDRAND_FAILURE
ret
GenerateBlock_Success:
mov rax, RDRAND_SUCCESS
GenerateBlock_Ret:
xor rax, rax
mov al, RDRAND_SUCCESS
ret
MSC_RRA_GenerateBlock ENDP
MASM_RRA_GenerateBlock ENDP
ENDIF ;; _M_X64
@ -331,8 +323,7 @@ OPTION EPILOGUE:NONE
;; Base relative (in): arg3, unsigned int safety
;; EAX (out): success (1), failure (0)
;; MSC_RSA_GenerateBlock PROC USES ecx edx edi arg1:DWORD,arg2:DWORD,arg3:DWORD
MSC_RSA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
MASM_RSA_GenerateBlock PROC arg1:DWORD,arg2:DWORD,arg3:DWORD
MWSIZE EQU 04h ;; machine word size
buffer EQU edi
@ -347,20 +338,20 @@ Load_Arguments:
Validate_Pointer:
cmp buffer, 0
je GenerateBlock_PreRet
cmp buffer, 0
je GenerateBlock_PreRet
;; Top of While loop
GenerateBlock_Top:
;; Check remaining size
cmp bsize, 0
cmp bsize, 0
je GenerateBlock_Success
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
DB 0Fh, 0C7h, 0F8h
;; If CF=1, the number returned by RDSEED is valid.
;; If CF=0, a random number was not available.
@ -404,15 +395,13 @@ Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
;; jz Bit_0_Not_Set
jz GenerateBlock_Success
mov BYTE PTR [buffer], al
Bit_0_Not_Set:
;; We've hit all the bits, set size to 0
;; mov bsize, 0
;; We've hit all the bits
jmp GenerateBlock_Success
GenerateBlock_PreRet:
@ -423,18 +412,17 @@ GenerateBlock_PreRet:
GenerateBlock_Failure:
mov eax, RDSEED_FAILURE
jmp GenerateBlock_Ret
xor eax, eax
mov al, RDSEED_FAILURE
ret
GenerateBlock_Success:
mov eax, RDSEED_SUCCESS
GenerateBlock_Ret:
xor eax, eax
mov al, RDSEED_SUCCESS
ret
MSC_RSA_GenerateBlock ENDP
MASM_RSA_GenerateBlock ENDP
ENDIF ;; _M_X86
@ -453,8 +441,7 @@ OPTION EPILOGUE:NONE
;; R8d (in): arg3, unsigned int safety
;; RAX (out): success (1), failure (0)
;; MSC_RSA_GenerateBlock PROC USES RCX ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
MSC_RSA_GenerateBlock PROC ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
MASM_RSA_GenerateBlock PROC ;; arg1:QWORD,arg2:QWORD,arg3:DWORD
MWSIZE EQU 08h ;; machine word size
buffer EQU rcx
@ -533,15 +520,13 @@ Bit_1_Not_Set:
;; Test bit 0 to see if size is at least 1
test bsize, 1
;; jz Bit_0_Not_Set
jz GenerateBlock_Success
mov BYTE PTR [buffer], al
Bit_0_Not_Set:
;; We've hit all the bits, set size to 0
;; mov bsize, 0
;; We've hit all the bits
jmp GenerateBlock_Success
GenerateBlock_PreRet:
@ -552,18 +537,17 @@ GenerateBlock_PreRet:
GenerateBlock_Failure:
mov rax, RDSEED_FAILURE
jmp GenerateBlock_Ret
xor rax, rax
mov al, RDSEED_FAILURE
ret
GenerateBlock_Success:
mov rax, RDSEED_SUCCESS
GenerateBlock_Ret:
xor rax, rax
mov al, RDSEED_SUCCESS
ret
MSC_RSA_GenerateBlock ENDP
MASM_RSA_GenerateBlock ENDP
ENDIF ;; _M_X64

View File

@ -20,225 +20,163 @@
// available. A lazy throw strategy is used in case the CPU does not support
// the instruction. I.e., the throw is deferred until GenerateBlock is called.
// For GCC/ICC/Clang on Unix/Linux/Apple, you can use `-mrdrnd` to force the
// option. If you use `-mrdrnd`, then __RDRND__ is defined and intrinsics
// are used. If you omit the otion, then assembly language routines are
// used if the compiler supports RDRAND. The same applies to -mrdseed and
// __RDSEED__ (but they did not skimp on the extra vowel). Also see
// http://gcc.gnu.org/onlinedocs/gcc/x86-Built-in-Functions.html#x86-Built-in-Functions
// Here's the naming convention for the functions....
// MSC = Microsoft Compiler (and compatibles)
// GCC = GNU Compiler (and compatibles)
// ALL = MSC and GCC (and compatibles)
// RRA = RDRAND, Assembly
// RSA = RDSEED, Assembly
// RRI = RDRAND, Intrinsic
// RSA = RDSEED, Intrinsic
// Helper macros. IA32_ASM captuers the architecture. MSC_RDRAND_COMPILER means
// MSC_RDSEED_COMPILER; GCC_RDRAND_COMPILER means GCC_RDSEED_COMPILER.
#define IA32_ASM (!defined(CRYPTOPP_DISABLE_ASM) && (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64))
#define MSC_RDRAND_COMPILER ((CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
#define GCC_RDRAND_COMPILER ((CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
#define MSC_RDSEED_COMPILER MSC_RDRAND_COMPILER
#define GCC_RDSEED_COMPILER GCC_RDRAND_COMPILER
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// GCC cannot compile programs with __builtin_ia32_rdseed{16|32|64}_step
#if __GNUC__
# define GCC_RDSEED_INTRINSIC_AVAILABLE 0
// For Linux, install NASM, run rdrand-nasm.asm, add the apppropriate
// object file to the Makefile's LIBOBJS (rdrand-x{86|32|64}.o). After
// that, define these. They are not enabled by default because they
// are not easy to cut-in in the Makefile.
#if 0
#define NASM_RDRAND_ASM_AVAILABLE 1
#define NASM_RDSEED_ASM_AVAILABLE 1
#endif
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Microsoft uses Intel's intrinsics, and it excludes AMD's CPUs. You should
// "#define MSC_RDRAND_INTRINSIC_AVAILABLE 0" and
// "#define MSC_RDSEED_INTRINSIC_AVAILABLE 0", if possible. The downside is
// you must assemble the object files rdrand-x86.obj and rdrand-x86.obj and
// then build the rdrand-x86.lib and rdrand-x86.lib libraries. To build the
// libraries run "make-rdrand.cmd" from a developer prompt.
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// MSC Compatible on Windows. Set MSC_RDRAND_ASM_AVAILABLE if it (and Intrinsics)
// are not set. The requirement is rdrand.asm assembled with MASM/MAS64. We use
// CRYTPOPP_MSC_VERSION as a proxy for MASM/MAS64 availability.
#if defined(CRYPTOPP_WIN32_AVAILABLE) && IA32_ASM && defined(CRYTPOPP_MSC_VERSION)
# if !defined(MSC_RDRAND_ASM_AVAILABLE) && !(MSC_RDRAND_INTRINSIC_AVAILABLE > 0)
# define MSC_RDRAND_ASM_AVAILABLE 1
# define MSC_RDRAND_INTRINSIC_AVAILABLE 0
// According to Wei, CRYPTOPP_DISABLE_ASM is a failsafe due to the assembler.
// We sidestep it because it does not limit us. The assembler does not limit
// us because we emit out own byte codes as needed. To diasble RDRAND or
// RDSEED, set CRYPTOPP_BOOL_RDRAND_ASM or CRYPTOPP_BOOL_RDSEED_ASM to 0.
#ifndef CRYPTOPP_CPUID_AVAILABLE
# if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
# define CRYPTOPP_CPUID_AVAILABLE
# endif
#endif
// Fallback to MSC_RDRAND_INTRINSIC_AVAILABLE on Windows. The compiler must support it.
#if defined(CRYPTOPP_WIN32_AVAILABLE) && MSC_RDRAND_COMPILER
# if !defined(MSC_RDRAND_INTRINSIC_AVAILABLE) && !(MSC_RDRAND_ASM_AVAILABLE > 0)
# define MSC_RDRAND_INTRINSIC_AVAILABLE 1
# define MSC_RDRAND_ASM_AVAILABLE 0
# endif
#if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDRAND_ASM)
# define CRYPTOPP_BOOL_RDRAND_ASM 1
#else
# define CRYPTOPP_BOOL_RDRAND_ASM 0
#endif
#if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDSEED_ASM)
# define CRYPTOPP_BOOL_RDSEED_ASM 1
#else
# define CRYPTOPP_BOOL_RDSEED_ASM 0
#endif
// GCC Compatible on Unix/Linux/Apple. Set GCC_RDRAND_INTRINSIC_AVAILABLE if
// it (and ASM) are not set. The requirements are __RDRND__ preprocessor.
#if defined(CRYPTOPP_UNIX_AVAILABLE) && GCC_RDRAND_COMPILER && (__RDRND__ >= 1)
# if !defined(GCC_RDRAND_INTRINSIC_AVAILABLE) && !(defined(GCC_RDRAND_ASM_AVAILABLE) && (GCC_RDRAND_ASM_AVAILABLE > 0))
# define GCC_RDRAND_INTRINSIC_AVAILABLE 1
# define GCC_RDRAND_ASM_AVAILABLE 0
# endif
#if defined(CRYPTOPP_CPUID_AVAILABLE)
# define MSC_INTRIN_COMPILER ((CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
# define GCC_INTRIN_COMPILER ((CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
#else
# define MSC_INTRIN_COMPILER 0
# define GCC_INTRIN_COMPILER 0
#endif
// Fallback to MSC_ASM_INTRINSIC_AVAILABLE on Unix/Linux/Apple
#if defined(CRYPTOPP_UNIX_AVAILABLE) && IA32_ASM && GCC_RDRAND_COMPILER
# if !defined(GCC_RDRAND_INTRINSIC_AVAILABLE) && !(defined(GCCC_RDRAND_ASM_AVAILABLE) && (GCCC_RDRAND_ASM_AVAILABLE > 0))
# define GCC_RDRAND_ASM_AVAILABLE 1
# define GCC_RDRAND_INTRINSIC_AVAILABLE 0
# endif
// In general, the library's ASM code is best on Windows, and Intrinsics is
// the best code under GCC and compatibles. We favor them accordingly.
// The NASM code is optimized well on Linux, but its not easy to cut-in.
#if defined(CRYPTOPP_CPUID_AVAILABLE) && (CRYPTOPP_MSC_VERSION >= 1200)
# if CRYPTOPP_BOOL_RDRAND_ASM
# define MASM_RDRAND_ASM_AVAILABLE 1
# elif MSC_INTRIN_COMPILER
# define ALL_RDRAND_INTRIN_AVAILABLE 1
# endif
# if CRYPTOPP_BOOL_RDSEED_ASM
# define MASM_RDSEED_ASM_AVAILABLE 1
# elif MSC_INTRIN_COMPILER
# define ALL_RDSEED_INTRIN_AVAILABLE 1
# endif
#elif defined(CRYPTOPP_CPUID_AVAILABLE) && (CRYPTOPP_GCC_VERSION >= 30200)
# if GCC_INTRIN_COMPILER && defined(__RDRND__)
# define ALL_RDRAND_INTRIN_AVAILABLE 1
# elif CRYPTOPP_BOOL_RDRAND_ASM
# define GCC_RDRAND_ASM_AVAILABLE 1
# endif
# if GCC_INTRIN_COMPILER && defined(__RDSEED__)
# define ALL_RDSEED_INTRIN_AVAILABLE 1
# elif CRYPTOPP_BOOL_RDSEED_ASM
# define GCC_RDSEED_ASM_AVAILABLE 1
# endif
#endif
// Debug diagnostics
#if !defined(NDEBUG)
# if MASM_RDRAND_ASM_AVAILABLE
# pragma message ("MASM_RDRAND_ASM_AVAILABLE is 1")
# elif NASM_RDRAND_ASM_AVAILABLE
# pragma message ("NASM_RDRAND_ASM_AVAILABLE is 1")
# elif GCC_RDRAND_ASM_AVAILABLE
# pragma message ("GCC_RDRAND_ASM_AVAILABLE is 1")
# elif ALL_RDRAND_INTRIN_AVAILABLE
# pragma message ("ALL_RDRAND_INTRIN_AVAILABLE is 1")
# else
# pragma message ("RDRAND is not available")
# endif
# if MASM_RDSEED_ASM_AVAILABLE
# pragma message ("MASM_RDSEED_ASM_AVAILABLE is 1")
# elif NASM_RDSEED_ASM_AVAILABLE
# pragma message ("NASM_RDSEED_ASM_AVAILABLE is 1")
# elif GCC_RDSEED_ASM_AVAILABLE
# pragma message ("GCC_RDSEED_ASM_AVAILABLE is 1")
# elif ALL_RDSEED_INTRIN_AVAILABLE
# pragma message ("ALL_RDSEED_INTRIN_AVAILABLE is 1")
# else
# pragma message ("RDSEED is not available")
# endif
#endif
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// MSC Compatible on Windows. Set MSC_RDRAND_ASM_AVAILABLE if it (and Intrinsics)
// are not set. The requirement is rdrand.asm assembled with MASM/MAS64. We use
// CRYTPOPP_MSC_VERSION as a proxy for MASM/MAS64 availability.
#if defined(CRYPTOPP_WIN32_AVAILABLE) && IA32_ASM && defined(CRYTPOPP_MSC_VERSION)
# if !defined(MSC_RDSEED_ASM_AVAILABLE) && !(MSC_RDSEED_INTRINSIC_AVAILABLE > 0)
# define MSC_RDSEED_ASM_AVAILABLE 1
# define MSC_RDSEED_INTRINSIC_AVAILABLE 0
#if (ALL_RDRAND_INTRIN_AVAILABLE || ALL_RDSEED_INTRIN_AVAILABLE)
# include <immintrin.h> // rdrand, MSC, ICC, and GCC
# if defined(__has_include)
# if __has_include(<x86intrin.h>)
# include <x86intrin.h> // rdseed for some compilers, like GCC
# endif
# endif
#endif
// Fallback to MSC_RDSEED_INTRINSIC_AVAILABLE on Windows. The compiler must support it.
#if defined(CRYPTOPP_WIN32_AVAILABLE) && MSC_RDSEED_COMPILER
# if !defined(MSC_RDSEED_INTRINSIC_AVAILABLE) && !(MSC_RDSEED_ASM_AVAILABLE > 0)
# define MSC_RDSEED_INTRINSIC_AVAILABLE 1
# define MSC_RDSEED_ASM_AVAILABLE 0
# endif
#endif
// GCC Compatible on Unix/Linux/Apple. Set GCC_RDSEED_INTRINSIC_AVAILABLE if
// it (and ASM) are not set. The requirements are __RDSEED__ preprocessor.
#if defined(CRYPTOPP_UNIX_AVAILABLE) && GCC_RDSEED_COMPILER && (__RDSEED__ >= 1)
# if !defined(GCC_RDSEED_INTRINSIC_AVAILABLE) && !(defined(GCC_RDSEED_ASM_AVAILABLE) && (GCC_RDSEED_ASM_AVAILABLE > 0))
# define GCC_RDSEED_INTRINSIC_AVAILABLE 1
# define GCC_RDSEED_ASM_AVAILABLE 0
# endif
#endif
// Fallback to MSC_ASM_INTRINSIC_AVAILABLE on Unix/Linux/Apple
#if defined(CRYPTOPP_UNIX_AVAILABLE) && IA32_ASM && GCC_RDSEED_COMPILER
# if !defined(GCC_RDSEED_INTRINSIC_AVAILABLE) && !(defined(GCCC_RDSEED_ASM_AVAILABLE) && (GCCC_RDSEED_ASM_AVAILABLE > 0))
# define GCC_RDSEED_ASM_AVAILABLE 1
# define GCC_RDSEED_INTRINSIC_AVAILABLE 0
# endif
#endif
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
#if MSC_RDRAND_ASM_AVAILABLE
#if MASM_RDRAND_ASM_AVAILABLE
# ifdef _M_X64
extern "C" int CRYPTOPP_FASTCALL MSC_RRA_GenerateBlock(byte*, size_t, unsigned int);
extern "C" int CRYPTOPP_FASTCALL MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
// # pragma comment(lib, "rdrand-x64.lib")
# else
extern "C" int MSC_RRA_GenerateBlock(byte*, size_t, unsigned int);
extern "C" int MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
// # pragma comment(lib, "rdrand-x86.lib")
# endif
#endif
#if MSC_RDSEED_ASM_AVAILABLE
#if MASM_RDSEED_ASM_AVAILABLE
# ifdef _M_X64
extern "C" int CRYPTOPP_FASTCALL MSC_RSA_GenerateBlock(byte*, size_t, unsigned int);
extern "C" int CRYPTOPP_FASTCALL MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
// # pragma comment(lib, "rdrand-x64.lib")
# else
extern "C" int MSC_RSA_GenerateBlock(byte*, size_t, unsigned int);
extern "C" int MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
// # pragma comment(lib, "rdrand-x86.lib")
# endif
#endif
#if NASM_RDRAND_ASM_AVAILABLE
extern "C" int NASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
#endif
#if NASM_RDSEED_ASM_AVAILABLE
extern "C" int NASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
#endif
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
#if MSC_RDRAND_INTRINSIC_AVAILABLE || MSC_RDSEED_INTRINSIC_AVAILABLE
# include <immintrin.h>
#elif GCC_RDRAND_INTRINSIC_AVAILABLE || GCC_RDSEED_INTRINSIC_AVAILABLE
# include <emmintrin.h>
#endif
// Define ERROR_DEV_NOT_EXIST for this TU if not already defined
#ifndef ERROR_DEV_NOT_EXIST
# define ERROR_DEV_NOT_EXIST 0x37
#endif
#if defined(CRYPTOPP_UNIX_AVAILABLE)
# include <errno.h>
#endif
NAMESPACE_BEGIN(CryptoPP)
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
#if defined(CRYPTOPP_CPUID_AVAILABLE)
extern CRYPTOPP_DLL bool CpuId(word32 input, word32 *output);
#endif
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Intel and AMD provide RDRAND, only Intel provides RDSEED. To call these
// functions, use the word32 array returned from CpuId(0, output[]).
static bool IsIntel(const word32 output[4])
#if ALL_RDRAND_INTRIN_AVAILABLE
static int ALL_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
// This is the "GenuineIntel" string
return (output[1] /*EBX*/ == 0x756e6547) &&
(output[2] /*ECX*/ == 0x6c65746e) &&
(output[3] /*EDX*/ == 0x49656e69);
}
static bool IsAMD(const word32 output[4])
{
// This is the "AuthenticAMD" string
return (output[1] /*EBX*/ == 0x68747541) &&
(output[2] /*ECX*/ == 0x69746E65) &&
(output[3] /*EDX*/ == 0x444D4163);
}
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
static bool RDRAND_Runtime_Helper()
{
#if defined(CRYPTOPP_CPUID_AVAILABLE)
bool rdrand = false; word32 output[4];
if (CpuId(0, output))
{
if (IsIntel(output) || IsAMD(output))
{
if (output[0] /*EAX*/ >= 1 && CpuId(1, output))
{
static const unsigned int RDRAND_FLAG = (1 << 30);
rdrand = !!(output[2] /*ECX*/ & RDRAND_FLAG);
}
}
}
return rdrand;
#else
return false;
#endif
}
// This will be moved to CPU.h/CPU.cpp eventually
static bool hasRDRAND = RDRAND_Runtime_Helper();
#if defined(CRYPTOPP_CPUID_AVAILABLE)
#if MSC_RDRAND_INTRINSIC_AVAILABLE
static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
#if CRYPTOPP_BOOL_X64
assert((output && size) || !(output || size));
#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
word64 val;
#else
word32 val;
@ -246,7 +184,7 @@ static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
while (size >= sizeof(val))
{
#if CRYPTOPP_BOOL_X64
#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
if (_rdrand64_step((word64*)output))
#else
if (_rdrand32_step((word32*)output))
@ -264,7 +202,7 @@ static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
if (size)
{
#if CRYPTOPP_BOOL_X64
#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
if (_rdrand64_step(&val))
#else
if (_rdrand32_step(&val))
@ -280,7 +218,7 @@ static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
}
}
#if CRYPTOPP_BOOL_X64
#if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
*((volatile word64*)&val) = 0;
#else
*((volatile word32*)&val) = 0;
@ -288,68 +226,12 @@ static int MSC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
return int(size == 0);
}
#endif // MSC_RDRAND_INTRINSIC_AVAILABLE
#if GCC_RDRAND_INTRINSIC_AVAILABLE
static int GCC_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
word64 val;
#else // CRYPTOPP_BOOL_X86
word32 val;
#endif
while (size >= sizeof(val))
{
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
if (__builtin_ia32_rdrand64_step((word64*)output))
#else
if (__builtin_ia32_rdrand32_step((word32*)output))
#endif
{
output += sizeof(val);
size -= sizeof(val);
}
else
{
if (!safety--)
return 0;
}
}
if (size)
{
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
if (__builtin_ia32_rdrand64_step(&val))
#else
if (__builtin_ia32_rdrand32_step(&val))
#endif
{
memcpy(output, &val, size);
size = 0;
}
else
{
if (!safety--)
return 0;
}
}
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
*((volatile word64*)&val) = 0;
#else
*((volatile word32*)&val) = 0;
#endif
return int(size == 0);
}
#endif // GCC_RDRAND_INTRINSIC_AVAILABLE
#endif // ALL_RDRAND_INTRINSIC_AVAILABLE
#if GCC_RDRAND_ASM_AVAILABLE
static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
assert((output && size) || !(output || size));
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
word64 val;
#else
@ -359,9 +241,13 @@ static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety)
while (size)
{
__asm__ volatile(
"rdrand %0; "
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
".byte 0x48, 0x0f, 0xc7, 0xf0;\n" // rdrand rax
#else
".byte 0x0f, 0xc7, 0xf0;\n" // rdrand eax
#endif
"setc %1; "
: "=r" (val), "=qm" (rc)
: "=a" (val), "=qm" (rc)
:
: "cc"
);
@ -404,103 +290,39 @@ static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety)
#endif // GCC_RDRAND_ASM_AVAILABLE
#endif // CRYPTOPP_CPUID_AVAILABLE (CRYPTOPP_BOOL_{X86|X32|X64})
//! generate random array of bytes
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
void RDRAND::GenerateBlock(byte *output, size_t size)
{
assert((output == NULL && size == 0) || (output != NULL && size != 0));
assert(Available());
CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
assert((output && size) || !(output || size));
// We could (should?) test Ready, but Available conveys more useful information.
if(!Available())
if(!HasRDRAND())
throw NotImplemented("RDRAND: rdrand is not available on this platform");
#if defined(CRYPTOPP_CPUID_AVAILABLE)
int rc; CRYPTOPP_UNUSED(rc);
#if MSC_RDRAND_ASM_AVAILABLE
rc = MSC_RRA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("MSC_RRA_GenerateBlock"); }
#if MASM_RDRAND_ASM_AVAILABLE
rc = MASM_RRA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("MASM_RRA_GenerateBlock"); }
#elif NASM_RDRAND_ASM_AVAILABLE
rc = NASM_RRA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("NASM_RRA_GenerateBlock"); }
#elif ALL_RDRAND_INTRIN_AVAILABLE
rc = ALL_RRI_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("ALL_RRI_GenerateBlock"); }
#elif GCC_RDRAND_ASM_AVAILABLE
rc = GCC_RRA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("GCC_RRA_GenerateBlock"); }
#elif MSC_RDRAND_INTRINSIC_AVAILABLE
rc = MSC_RRI_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("MSC_RRI_GenerateBlock"); }
#elif GCC_RDRAND_INTRINSIC_AVAILABLE
rc = GCC_RRI_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("GCC_RRI_GenerateBlock"); }
#elif (__RDRND__ >= 1)
// RDRAND detected at compile time, GCC Compatible compiler, but no suitable implementations
# error "Please report on the Crypto++ user group"
#else
// RDRAND not detected at compile time, and no suitable compiler found
throw NotImplemented("RDRAND: failed to find a suitable implementation???");
#endif
#endif // CRYPTOPP_CPUID_AVAILABLE (CRYPTOPP_BOOL_{X86|X32|X64})
#endif // CRYPTOPP_CPUID_AVAILABLE
}
//! returns true if RDRAND is present or available according to CPUID, false otherwise
bool RDRAND::Available() const
{
word64 unused;
return Available(unused);
}
//! returns true if RDRAND is present or available according to CPUID, false otherwise. There is no exended information available.
bool RDRAND::Available(word64& extendedInfo) const
{
if (hasRDRAND)
{
extendedInfo = 0;
return true;
}
#if defined(CRYPTOPP_WIN32_AVAILABLE)
extendedInfo = ERROR_DEV_NOT_EXIST; // 0x00000037
#elif defined(CRYPTOPP_UNIX_AVAILABLE)
extendedInfo = ENODEV; // 19
#else
extendedInfo = word64(-1);
#endif
return false;
}
//! returns true if RDRAND is online/ready to produce random numbers, false otherwise
bool RDRAND::Ready() const
{
word64 unused;
return Ready(unused);
}
//! returns true if RDRAND is online/ready to produce random numbers, false otherwise. There is no exended information available.
bool RDRAND::Ready(word64& extendedInfo) const
{
if (hasRDRAND)
{
extendedInfo = 0;
return true;
}
#if defined(CRYPTOPP_WIN32_AVAILABLE)
extendedInfo = ERROR_DEV_NOT_EXIST; // 0x00000037
#elif defined(CRYPTOPP_UNIX_AVAILABLE)
extendedInfo = ENODEV; // 19
#else
extendedInfo = word64(-1);
#endif
return false;
}
//! generate and discard n bytes.
void RDRAND::DiscardBytes(size_t n)
{
{
// RoundUpToMultipleOf is used because a full word is read, and its cheaper
// to discard full words. There's no sense in dealing with tail bytes.
assert(Ready());
assert(HasRDRAND());
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
FixedSizeSecBlock<word64, 16> discard;
n = RoundUpToMultipleOf(n, sizeof(word64));
@ -517,41 +339,16 @@ void RDRAND::DiscardBytes(size_t n)
count = STDMIN(n, discard.SizeInBytes());
}
}
#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
static bool RDSEED_Runtime_Helper()
#if ALL_RDSEED_INTRIN_AVAILABLE
static int ALL_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
#if defined(CRYPTOPP_CPUID_AVAILABLE)
bool rdseed = false; word32 output[4];
if (CpuId(0, output))
{
// Only Intel supports RDSEED at the moment.
if (IsIntel(output))
{
if (output[0] /*EAX*/ >= 7 && CpuId(7, output))
{
static const unsigned int RDSEED_FLAG = (1 << 18);
rdseed = !!(output[1] /*EBX*/ & RDSEED_FLAG);
}
}
}
return rdseed;
#else
return false;
#endif
}
// This will be moved to CPU.h/CPU.cpp eventually
static bool hasRDSEED = RDSEED_Runtime_Helper();
#if defined(CRYPTOPP_CPUID_AVAILABLE)
#if MSC_RDSEED_INTRINSIC_AVAILABLE
static int MSC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
#if CRYPTOPP_BOOL_X64
assert((output && size) || !(output || size));
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
word64 val;
#else
word32 val;
@ -559,7 +356,7 @@ static int MSC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
while (size >= sizeof(val))
{
#if CRYPTOPP_BOOL_X64
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
if (_rdseed64_step((word64*)output))
#else
if (_rdseed32_step((word32*)output))
@ -577,7 +374,7 @@ static int MSC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
if (size)
{
#if CRYPTOPP_BOOL_X64
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
if (_rdseed64_step(&val))
#else
if (_rdseed32_step(&val))
@ -593,62 +390,6 @@ static int MSC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
}
}
#if CRYPTOPP_BOOL_X64
*((volatile word64*)&val) = 0;
#else
*((volatile word32*)&val) = 0;
#endif
return int(size == 0);
}
#endif // MSC_RDSEED_INTRINSIC_AVAILABLE
#if GCC_RDSEED_INTRINSIC_AVAILABLE
static int GCC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
word64 val;
#else // CRYPTOPP_BOOL_X86
word32 val;
#endif
while (size >= sizeof(val))
{
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
if (__builtin_ia32_rdseed64_step((word64*)output))
#else
if (__builtin_ia32_rdseed32_step((word32*)output))
#endif
{
output += sizeof(val);
size -= sizeof(val);
}
else
{
if (!safety--)
return 0;
}
}
if (size)
{
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
if (__builtin_ia32_rdseed64_step(&val))
#else
if (__builtin_ia32_rdseed32_step(&val))
#endif
{
memcpy(output, &val, size);
size = 0;
}
else
{
if (!safety--)
return 0;
}
}
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
*((volatile word64*)&val) = 0;
#else
@ -657,12 +398,12 @@ static int GCC_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
return int(size == 0);
}
#endif // GCC_RDSEED_INTRINSIC_AVAILABLE
#endif // ALL_RDSEED_INTRIN_AVAILABLE
#if GCC_RDSEED_ASM_AVAILABLE
static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety)
{
assert((output && size) || !(output || size));
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
word64 val;
#else
@ -672,9 +413,13 @@ static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety)
while (size)
{
__asm__ volatile(
"rdseed %0; "
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
".byte 0x48, 0x0f, 0xc7, 0xf8;\n" // rdseed rax
#else
".byte 0x0f, 0xc7, 0xf8;\n" // rdseed eax
#endif
"setc %1; "
: "=r" (val), "=qm" (rc)
: "=a" (val), "=qm" (rc)
:
: "cc"
);
@ -714,107 +459,41 @@ static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety)
return int(size == 0);
}
#endif // GCC_RDSEED_ASM_AVAILABLE
#endif // CRYPTOPP_CPUID_AVAILABLE (CRYPTOPP_BOOL_{X86|X32|X64})
//! generate random array of bytes
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
void RDSEED::GenerateBlock(byte *output, size_t size)
{
CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
assert((output == NULL && size == 0) || (output != NULL && size != 0));
assert(Available());
assert((output && size) || !(output || size));
// We could (should?) test Ready, but Available conveys more useful information.
if(!Available())
if(!HasRDSEED())
throw NotImplemented("RDSEED: rdseed is not available on this platform");
#if defined(CRYPTOPP_CPUID_AVAILABLE)
int rc; CRYPTOPP_UNUSED(rc);
#if MSC_RDSEED_ASM_AVAILABLE
rc = MSC_RSA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDSEED_Err("MSC_RSA_GenerateBlock"); }
#if MASM_RDSEED_ASM_AVAILABLE
rc = MASM_RSA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDSEED_Err("MASM_RSA_GenerateBlock"); }
#elif NASM_RDSEED_ASM_AVAILABLE
rc = NASM_RSA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDRAND_Err("NASM_RSA_GenerateBlock"); }
#elif ALL_RDSEED_INTRIN_AVAILABLE
rc = ALL_RSI_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDSEED_Err("ALL_RSI_GenerateBlock"); }
#elif GCC_RDSEED_ASM_AVAILABLE
rc = GCC_RSA_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDSEED_Err("GCC_RSA_GenerateBlock"); }
#elif MSC_RDSEED_INTRINSIC_AVAILABLE
rc = MSC_RSI_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDSEED_Err("MSC_RSI_GenerateBlock"); }
#elif GCC_RDSEED_INTRINSIC_AVAILABLE
rc = GCC_RSI_GenerateBlock(output, size, m_retries);
if (!rc) { throw RDSEED_Err("GCC_RSI_GenerateBlock"); }
#elif (__RDSEED__ >= 1)
// RDSEED detected at compile time, GCC Compatible compiler, but no suitable implementations
# error "Please report on the Crypto++ user group"
#else
// RDSEED not detected at compile time, and no suitable compiler found
throw NotImplemented("RDSEED: failed to find a suitable implementation???");
#endif
#endif // CRYPTOPP_CPUID_AVAILABLE (CRYPTOPP_BOOL_{X86|X32|X64})
}
//! returns true if RDSEED is present or available according to CPUID, false otherwise
bool RDSEED::Available() const
{
word64 unused;
return Available(unused);
}
//! returns true if RDSEED is present or available according to CPUID, false otherwise. There is no exended information available.
bool RDSEED::Available(word64& extendedInfo) const
{
if (hasRDSEED)
{
extendedInfo = 0;
return true;
}
#if defined(CRYPTOPP_WIN32_AVAILABLE)
extendedInfo = ERROR_DEV_NOT_EXIST; // 0x00000037
#elif defined(CRYPTOPP_UNIX_AVAILABLE)
extendedInfo = ENODEV; // 19
#else
extendedInfo = word64(-1);
#endif
return false;
}
//! returns true if RDSEED is online/ready to produce random numbers, false otherwise
bool RDSEED::Ready() const
{
word64 unused;
return Ready(unused);
}
//! returns true if RDSEED is online/ready to produce random numbers, false otherwise. There is no exended information available.
bool RDSEED::Ready(word64& extendedInfo) const
{
if (hasRDSEED)
{
extendedInfo = 0;
return true;
}
#if defined(CRYPTOPP_WIN32_AVAILABLE)
extendedInfo = ERROR_DEV_NOT_EXIST; // 0x00000037
#elif defined(CRYPTOPP_UNIX_AVAILABLE)
extendedInfo = ENODEV; // 19
#else
extendedInfo = word64(-1);
#endif
return false;
}
//! generate and discard n bytes.
void RDSEED::DiscardBytes(size_t n)
{
{
// RoundUpToMultipleOf is used because a full word is read, and its cheaper
// to discard full words. There's no sense in dealing with tail bytes.
assert(Ready());
assert(HasRDSEED());
#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
FixedSizeSecBlock<word64, 16> discard;
n = RoundUpToMultipleOf(n, sizeof(word64));
@ -831,5 +510,6 @@ void RDSEED::DiscardBytes(size_t n)
count = STDMIN(n, discard.SizeInBytes());
}
}
#endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
NAMESPACE_END

141
rdrand.h
View File

@ -1,21 +1,30 @@
// rdrand.h - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
// Copyright assigned to Crypto++ project.
//! \file
//! \headerfile rdrand.h
//! \brief Classes for RDRAND and RDSEED
#ifndef CRYPTOPP_RDRAND_H
#define CRYPTOPP_RDRAND_H
#include "cryptlib.h"
// This file (and friends) provides both RDRAND and RDSEED, but its somewhat
// experimental. They were added at Crypto++ 5.6.3. At compile time, it
// indirectly uses CRYPTOPP_BOOL_{X86|X32|X64} (via CRYPTOPP_CPUID_AVAILABLE)
// to select an implementation or "throw NotImplemented". At runtime, the
// class uses the result of CPUID to determine if RDRAND or RDSEED are
// available. A lazy throw strategy is used in case the CPU does not support
// the instruction. I.e., the throw is deferred until GenerateBlock is called.
// Microsoft added RDRAND in August 2012, VS2012. GCC added RDRAND in December 2010, GCC 4.6.
// Clang added RDRAND in July 2012, Clang 3.2. Intel added RDRAND in September 2011, ICC 12.1.
// Visual Studio 2015 (CL version 1900) is missing _rdseed{16|32|64}_step
#if (CRYPTOPP_MSC_VERSION <= 1900)
# define MSC_RDSEED_INTRINSIC_AVAILABLE 0
#endif
NAMESPACE_BEGIN(CryptoPP)
//! \brief Exception thrown when a RDRAND generator encounters
//! a generator related error.
class RDRAND_Err : public Exception
{
public:
@ -23,61 +32,65 @@ public:
: Exception(OTHER_ERROR, "RDRAND: " + operation + " operation failed") {}
};
//! \brief Read hardware generated random numbers.
//! This file (and friends) provides both RDRAND and RDSEED, but its somewhat
//! experimental. They were added at Crypto++ 5.6.3. At compile time, it
//! indirectly uses CRYPTOPP_BOOL_{X86|X32|X64} (via CRYPTOPP_CPUID_AVAILABLE)
//! to select an implementation or "throw NotImplemented". At runtime, the
//! class uses the result of CPUID to determine if RDRAND or RDSEED are
//! available. A lazy throw strategy is used in case the CPU does not support
//! the instruction. I.e., the throw is deferred until GenerateBlock is called.
class RDRAND : public RandomNumberGenerator, public DeviceState
//! \brief Hardware generated random numbers using RDRAND instruction
//! \sa MaurerRandomnessTest() for random bit generators
class RDRAND : public RandomNumberGenerator
{
public:
std::string AlgorithmName() const {return "RDRAND";}
//! construct a RDRAND generator with a maximum number of retires for failed generation attempts
//! \brief Construct a RDRAND generator
//! \param retries the number of retries for failed calls to the hardware
//! \details RDRAND() constructs a generator with a maximum number of retires
//! for failed generation attempts.
RDRAND(unsigned int retries = 8) : m_retries(retries) {}
virtual ~RDRAND() {}
//! returns true if RDRAND is present or available according to CPUID, false otherwise
bool Available() const;
//! returns true if RDRAND is present or available according to CPUID, false otherwise. There is no exended information available.
bool Available(word64& extendedInfo) const;
//! returns true if RDRAND is online/ready to produce random numbers, false otherwise
bool Ready() const;
//! returns true if RDRAND is online/ready to produce random numbers, false otherwise. There is no exended information available.
bool Ready(word64& extendedInfo) const;
//! \brief Retrieve the number of retries used by the generator
//! returns the number of times GenerateBlock will attempt to recover from a failed generation
unsigned int GetRetries() const
{
return m_retries;
}
//! sets the number of times GenerateBlock will attempt to recover from a failed generation
//! \brief Set the number of retries used by the generator
//! \param the number of times GenerateBlock will attempt to recover from a failed generation
void SetRetries(unsigned int retries)
{
m_retries = retries;
}
//! generate random array of bytes
//! \brief Generate random array of bytes
//! \param output the byte buffer
//! \param size the length of the buffer, in bytes
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
virtual void GenerateBlock(byte *output, size_t size);
#else
virtual void GenerateBlock(byte *output, size_t size) {
CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
throw NotImplemented("RDRAND: rdrand is not available on this platform");
}
#endif
//! generate and discard n bytes.
//! \param n the number of bytes to discard
//! \brief Generate and discard n bytes
//! \param n the number of bytes to generate and discard
//! \details the RDSEED generator discards words, not bytes. If n is
//! not a multiple of a machine word, then it is rounded up to
//! that size.
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
virtual void DiscardBytes(size_t n);
#else
virtual void DiscardBytes(size_t n) {
CRYPTOPP_UNUSED(n);
throw NotImplemented("RDRAND: rdrand is not available on this platform");
}
#endif
//! update RNG state with additional unpredictable values. The operation is a nop for this generator.
//! Update RNG state with additional unpredictable values
//! \param input unused
//! \param length unused
//! \details The operation is a nop for this generator.
virtual void IncorporateEntropy(const byte *input, size_t length)
{
// Override to avoid the base class' throw.
@ -89,6 +102,8 @@ private:
unsigned int m_retries;
};
//! \brief Exception thrown when a RDSEED generator encounters
//! a generator related error.
class RDSEED_Err : public Exception
{
public:
@ -96,61 +111,65 @@ public:
: Exception(OTHER_ERROR, "RDSEED: " + operation + " operation failed") {}
};
//! \brief Read hardware generated random numbers.
//! This file (and friends) provides both RDRAND and RDSEED, but its somewhat
//! experimental. They were added at Crypto++ 5.6.3. At compile time, it
//! indirectly uses CRYPTOPP_BOOL_{X86|X32|X64} (via CRYPTOPP_CPUID_AVAILABLE)
//! to select an implementation or "throw NotImplemented". At runtime, the
//! class uses the result of CPUID to determine if RDRAND or RDSEED are
//! available. A lazy throw strategy is used in case the CPU does not support
//! the instruction. I.e., the throw is deferred until GenerateBlock is called.
class RDSEED : public RandomNumberGenerator, public DeviceState
//! \brief Hardware generated random numbers using RDSEED instruction
//! \sa MaurerRandomnessTest() for random bit generators
class RDSEED : public RandomNumberGenerator
{
public:
std::string AlgorithmName() const {return "RDSEED";}
//! construct a RDSEED generator with a maximum number of retires for failed generation attempts
//! \brief Construct a RDSEED generator
//! \param retries the number of retries for failed calls to the hardware
//! \details RDSEED() constructs a generator with a maximum number of retires
//! for failed generation attempts.
RDSEED(unsigned int retries = 8) : m_retries(retries) {}
virtual ~RDSEED() {}
//! returns true if RDSEED is present or available according to CPUID, false otherwise
bool Available() const;
//! returns true if RDSEED is present or available according to CPUID, false otherwise. There is no exended information available.
bool Available(word64& extendedInfo) const;
//! returns true if RDSEED is online/ready to produce random numbers, false otherwise
bool Ready() const;
//! returns true if RDSEED is online/ready to produce random numbers, false otherwise. There is no exended information available.
bool Ready(word64& extendedInfo) const;
//! \brief Retrieve the number of retries used by the generator
//! returns the number of times GenerateBlock will attempt to recover from a failed generation
unsigned int GetRetries() const
{
return m_retries;
}
//! sets the number of times GenerateBlock will attempt to recover from a failed generation
//! \brief Set the number of retries used by the generator
//! \param the number of times GenerateBlock will attempt to recover from a failed generation
void SetRetries(unsigned int retries)
{
m_retries = retries;
}
//! generate random array of bytes
//! \brief Generate random array of bytes
//! \param output the byte buffer
//! \param size the length of the buffer, in bytes
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
virtual void GenerateBlock(byte *output, size_t size);
#else
virtual void GenerateBlock(byte *output, size_t size) {
CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
throw NotImplemented("RDSEED: rdseed is not available on this platform");
}
#endif
//! generate and discard n bytes.
//! \param n the number of bytes to discard
//! \brief Generate and discard n bytes
//! \param n the number of bytes to generate and discard
//! \details the RDSEED generator discards words, not bytes. If n is
//! not a multiple of a machine word, then it is rounded up to
//! that size.
#if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
virtual void DiscardBytes(size_t n);
#else
virtual void DiscardBytes(size_t n) {
CRYPTOPP_UNUSED(n);
throw NotImplemented("RDSEED: rdseed is not available on this platform");
}
#endif
//! update RNG state with additional unpredictable values. The operation is a nop for this generator.
//! Update RNG state with additional unpredictable values
//! \param input unused
//! \param length unused
//! \details The operation is a nop for this generator.
virtual void IncorporateEntropy(const byte *input, size_t length)
{
// Override to avoid the base class' throw.