Skip to content

Commit

Permalink
ensure TAESPRNG/FillSystemRandom won't read more than 32 bytes from /…
Browse files Browse the repository at this point in the history
…dev/urandom

- as expected by "man urandom" Usage
  • Loading branch information
Arnaud Bouchez committed Mar 13, 2019
1 parent 6a0deb6 commit 0a71f34
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 30 deletions.
2 changes: 1 addition & 1 deletion SynBidirSock.pas
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2663,7 +2663,7 @@ function TWebCrtSocketProcess.SendFrame(var Frame: TWebSocketFrame): boolean;
len := Length(Frame.payload); len := Length(Frame.payload);
hdr.first := byte(Frame.opcode) or FRAME_FIN; hdr.first := byte(Frame.opcode) or FRAME_FIN;
if fMaskSentFrames<>0 then begin if fMaskSentFrames<>0 then begin
hdr.mask := Random32; hdr.mask := Random32gsl;
ProcessMask(pointer(Frame.payload),hdr.mask,len); ProcessMask(pointer(Frame.payload),hdr.mask,len);
end; end;
if len<FRAME_LEN2BYTES then begin if len<FRAME_LEN2BYTES then begin
Expand Down
38 changes: 19 additions & 19 deletions SynCommons.pas
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ {$ifdef UNICODE}TSynTempBuffer = record{$else}TSynTempBuffer = object{$endif}
function Init: integer; overload; {$ifdef HASINLINE}inline;{$endif} function Init: integer; overload; {$ifdef HASINLINE}inline;{$endif}
/// initialize a new temporary buffer of a given number of random bytes /// initialize a new temporary buffer of a given number of random bytes
// - will fill the buffer via FillRandom() calls // - 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 /// initialize a new temporary buffer filled with integer increasing values
function InitIncreasing(Count: integer; Start: integer=0): PIntegerArray; function InitIncreasing(Count: integer; Start: integer=0): PIntegerArray;
/// initialize a new temporary buffer of a given number of zero bytes /// initialize a new temporary buffer of a given number of zero bytes
Expand Down Expand Up @@ -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; function GUIDToString({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} guid: TGUID): string;


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


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


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


/// compute a random GUID value /// compute a random GUID value
procedure RandomGUID(out result: TGUID); overload; procedure RandomGUID(out result: TGUID); overload;
Expand Down Expand Up @@ -19009,11 +19010,11 @@ function TSynTempBuffer.Init: integer;
len := result; len := result;
end; end;


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


Expand Down Expand Up @@ -37807,8 +37808,7 @@ procedure TLecuyer.Seed(entropy: PByteArray; entropylen: integer);
begin begin
repeat repeat
QueryPerformanceCounter(time.Lo); QueryPerformanceCounter(time.Lo);
time.i2 := UnixMSTimeUTC; time.Hi := UnixMSTimeUTC xor Int64(GetCurrentThreadID);
time.i3 := integer(GetCurrentThreadID);
crcblock(@crc.b,@time.b); crcblock(@crc.b,@time.b);
crcblock(@crc.b,@ExeVersion.Hash.b); crcblock(@crc.b,@ExeVersion.Hash.b);
if entropy<>nil then if entropy<>nil then
Expand Down Expand Up @@ -37867,7 +37867,7 @@ function Random32gsl(max: cardinal): cardinal;
end; end;


procedure FillRandom(Dest: PCardinalArray; CardinalCount: integer; forcegsl: boolean); procedure FillRandom(Dest: PCardinalArray; CardinalCount: integer; forcegsl: boolean);
var i: integer; var i: PtrInt;
c: cardinal; c: cardinal;
timenow: Int64; timenow: Int64;
lecuyer: ^TLecuyer; lecuyer: ^TLecuyer;
Expand All @@ -37878,11 +37878,11 @@ procedure FillRandom(Dest: PCardinalArray; CardinalCount: integer; forcegsl: boo
{$endif} {$endif}
lecuyer := @_Lecuyer; lecuyer := @_Lecuyer;
QueryPerformanceCounter(timenow); QueryPerformanceCounter(timenow);
c := crc32c(ExeVersion.Hash.c3,@timenow,SizeOf(timenow)); c := crc32cBy4(ExeVersion.Hash.c0,crc32c(ExeVersion.Hash.c3,@timenow,SizeOf(timenow)));
{$ifdef CPUINTEL} {$ifdef CPUINTEL}
if lecuyer=nil then if lecuyer=nil then
for i := 0 to CardinalCount-1 do begin 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; Dest^[i] := Dest^[i] xor c;
end else end else
{$endif} {$endif}
Expand Down
18 changes: 9 additions & 9 deletions SynCrypto.pas
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1267,8 +1267,9 @@ procedure SetMainAESPRNG;
{$endif} {$endif}


/// low-level function returning some random binary using standard API /// low-level function returning some random binary using standard API
// - will call /dev/urandom under POSIX, and CryptGenRandom API on Windows, // - will call /dev/urandom or /dev/random under POSIX, and CryptGenRandom API
// and fallback to SynCommons.FillRandom if the system is not supported // 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 // - you should not have to call this procedure, but faster and safer TAESPRNG
procedure FillSystemRandom(Buffer: PByteArray; Len: integer; AllowBlocking: boolean); procedure FillSystemRandom(Buffer: PByteArray; Len: integer; AllowBlocking: boolean);


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

0 comments on commit 0a71f34

Please sign in to comment.