Skip to content
Permalink
Browse files

ensure TAESPRNG/FillSystemRandom won't read more than 32 bytes from /…

…dev/urandom

- as expected by "man urandom" Usage
  • Loading branch information...
Arnaud Bouchez
Arnaud Bouchez committed Mar 13, 2019
1 parent 6a0deb6 commit 0a71f34dc750d4286ef5ab8f076c89285cb461b0
Showing with 30 additions and 30 deletions.
  1. +1 −1 SynBidirSock.pas
  2. +19 −19 SynCommons.pas
  3. +9 −9 SynCrypto.pas
  4. +1 −1 SynopseCommit.inc
@@ -2663,7 +2663,7 @@ function TWebCrtSocketProcess.SendFrame(var Frame: TWebSocketFrame): boolean;
len := Length(Frame.payload);
hdr.first := byte(Frame.opcode) or FRAME_FIN;
if fMaskSentFrames<>0 then begin
hdr.mask := Random32;
hdr.mask := Random32gsl;
ProcessMask(pointer(Frame.payload),hdr.mask,len);
end;
if len<FRAME_LEN2BYTES then begin
@@ -801,7 +801,7 @@ {$ifdef UNICODE}TSynTempBuffer = record{$else}TSynTempBuffer = object{$endif}
function Init: integer; overload; {$ifdef HASINLINE}inline;{$endif}
/// initialize a new temporary buffer of a given number of random bytes
// - will fill the buffer via FillRandom() calls
function InitRandom(RandomLen: integer): pointer;
function InitRandom(RandomLen: integer; forcegsl: boolean=true): pointer;
/// initialize a new temporary buffer filled with integer increasing values
function InitIncreasing(Count: integer; Start: integer=0): PIntegerArray;
/// initialize a new temporary buffer of a given number of zero bytes
@@ -6539,27 +6539,27 @@ function GUIDToRawUTF8({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} gui
function GUIDToString({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} guid: TGUID): string;

/// fast compute of some 32-bit random value
// - will use RDRAND Intel x86/x64 opcode if available, or fast gsl_rng_taus2
// generator by Pierre L'Ecuyer (period is 2^88, i.e. about 10^26)
// - will fast generate some random-like 32-bit output
// - will use (slow but) hardware-derivated RDRAND Intel x86/x64 opcode if
// available, or fast gsl_rng_taus2 generator by Pierre L'Ecuyer (which period
// is 2^88, i.e. about 10^26) if the CPU doesn't support it
// - use rather TAESPRNG.Main.FillRandom() for cryptographic-level randomness
// - thread-safe function: each thread will maintain its own gsl_rng_taus2 table
function Random32: cardinal; overload;

/// fast compute of some 32-bit random value, with a maximum (excluded) upper value
// - i.e. returns a value in range [0..max-1]
// - will use RDRAND Intel x86/x64 opcode if available, or fast gsl_rng_taus2
// generator by Pierre L'Ecuyer (period is 2^88, i.e. about 10^26)
// - will fast generate some random-like 32-bit output
// - will use (slow but) hardware-derivated RDRAND Intel x86/x64 opcode if
// available, or fast gsl_rng_taus2 generator by Pierre L'Ecuyer (which period
// is 2^88, i.e. about 10^26) if the CPU doesn't support it
// - use rather TAESPRNG.Main.FillRandom() for cryptographic-level randomness
// - thread-safe function: each thread will maintain its own gsl_rng_taus2 table
function Random32(max: cardinal): cardinal; overload;

/// fast compute of some 32-bit random value, using the gsl_rng_taus2 generator
// - plain Random32 may call RDRAND opcode on Intel CPUs, wherease this function
// will use well documented (and proven) Pierre L'Ecuyer software generator
// - may be used if you don't want/trust RDRAND, or expect a well defined
// cross-platform generator
// - may be used if you don't want/trust RDRAND, if you expect a well defined
// cross-platform generator, or have higher performance expectations
// - use rather TAESPRNG.Main.FillRandom() for cryptographic-level randomness
// - thread-safe function: each thread will maintain its own gsl_rng_taus2 table
function Random32gsl: cardinal; overload;
@@ -6581,10 +6581,11 @@ procedure Random32Seed(entropy: pointer=nil; entropylen: integer=0);
// - the destination buffer is expected to be allocated as 32 bit items
// - use internally crc32c() with some rough entropy source, and Random32
// gsl_rng_taus2 generator or hardware RDRAND Intel x86/x64 opcode if available
// (and forcegsl is kept to its default false value)
// (and ForceGsl is kept to its default false value)
// - consider using instead the cryptographic secure TAESPRNG.Main.FillRandom()
// method from the SynCrypto unit
procedure FillRandom(Dest: PCardinalArray; CardinalCount: integer; forcegsl: boolean=false);
// method from the SynCrypto unit - in particular, RDRAND could be slow
// as reported by https://en.wikipedia.org/wiki/RdRand#Performance
procedure FillRandom(Dest: PCardinalArray; CardinalCount: integer; ForceGsl: boolean=false);

/// compute a random GUID value
procedure RandomGUID(out result: TGUID); overload;
len := result;
end;

function TSynTempBuffer.InitRandom(RandomLen: integer): pointer;
function TSynTempBuffer.InitRandom(RandomLen: integer; forcegsl: boolean): pointer;
begin
Init(nil,RandomLen);
if RandomLen>0 then
FillRandom(buf,(RandomLen shr 2)+1);
FillRandom(buf,(RandomLen shr 2)+1,forcegsl);
result := buf;
end;

begin
repeat
QueryPerformanceCounter(time.Lo);
time.i2 := UnixMSTimeUTC;
time.i3 := integer(GetCurrentThreadID);
time.Hi := UnixMSTimeUTC xor Int64(GetCurrentThreadID);
crcblock(@crc.b,@time.b);
crcblock(@crc.b,@ExeVersion.Hash.b);
if entropy<>nil then
end;

procedure FillRandom(Dest: PCardinalArray; CardinalCount: integer; forcegsl: boolean);
var i: integer;
var i: PtrInt;
c: cardinal;
timenow: Int64;
lecuyer: ^TLecuyer;
{$endif}
lecuyer := @_Lecuyer;
QueryPerformanceCounter(timenow);
c := crc32c(ExeVersion.Hash.c3,@timenow,SizeOf(timenow));
c := crc32cBy4(ExeVersion.Hash.c0,crc32c(ExeVersion.Hash.c3,@timenow,SizeOf(timenow)));
{$ifdef CPUINTEL}
if lecuyer=nil then
for i := 0 to CardinalCount-1 do begin
c := c xor RdRand32 xor crc32ctab[0,(c+cardinal(i)) and 1023];
c := crc32cBy4(c,RdRand32);
Dest^[i] := Dest^[i] xor c;
end else
{$endif}
@@ -1267,8 +1267,9 @@ procedure SetMainAESPRNG;
{$endif}

/// low-level function returning some random binary using standard API
// - will call /dev/urandom under POSIX, and CryptGenRandom API on Windows,
// and fallback to SynCommons.FillRandom if the system is not supported
// - will call /dev/urandom or /dev/random under POSIX, and CryptGenRandom API
// on Windows, and fallback to SynCommons.FillRandom if the system API failed
// or for padding if more than 32 bytes is retrieved from /dev/urandom
// - you should not have to call this procedure, but faster and safer TAESPRNG
procedure FillSystemRandom(Buffer: PByteArray; Len: integer; AllowBlocking: boolean);

@@ -13526,10 +13527,9 @@ procedure FillSystemRandom(Buffer: PByteArray; Len: integer; AllowBlocking: bool
if dev>0 then
try
i := Len;
repeat
dec(i,FileRead(dev,Buffer^[Len-i],i));
until i<=0;
fromos := i=0;
if i>32 then
i := 32; // up to 256 bits - see "man urandom" Usage paragraph
fromos := (FileRead(dev,Buffer[0],i)=i) and (Len<=32); // will XOR up to Len
finally
FileClose(dev);
end;
@@ -13544,8 +13544,8 @@ procedure FillSystemRandom(Buffer: PByteArray; Len: integer; AllowBlocking: bool
if fromos then
exit;
i := Len;
repeat
SynCommons.FillRandom(@tmp,SizeOf(tmp) shr 2); // SynCommons as fallback
repeat // call Random32() (=RdRand32 or Lecuyer) as fallback/padding
SynCommons.FillRandom(@tmp,SizeOf(tmp) shr 2);
if i<=SizeOf(tmp) then begin
XorMemory(@Buffer^[Len-i],@tmp,i);
break;
@@ -13578,7 +13578,7 @@ class function TAESPRNG.GetEntropy(Len: integer; SystemOnly: boolean): RawByteSt
try
// retrieve some initial entropy from OS
SetLength(fromos,Len);
FillSystemRandom(pointer(fromos),len,true);
FillSystemRandom(pointer(fromos),len,{allowblocking=}true);
if SystemOnly then begin
result := fromos;
fromos := '';
@@ -1 +1 @@
'1.18.5099'
'1.18.5101'

0 comments on commit 0a71f34

Please sign in to comment.
You can’t perform that action at this time.