Dev random
│
Deutsch (de) │
English (en) │
français (fr) │
/dev/random
and /dev/urandom
are two pseudo character devices providing user-land access to random data generated by the system.
Following the paradigm “everything is a file” they usually exist on Unix and *nix-based operating systems, like Linux or FreeBSD.
The u
in urandom
stands for “unlimited”.
Theoretically there is no limit on how much data one may obtain /dev/urandom
.
quality
On Linux the kernel will occasonially gather “environmental noise” like memory, disc, network throughput, or dumps from the kernel, as well as cryptography hardware if present and enabled.
The key difference between /dev/random
versus /dev/urandom
is whether a threshold of enough entropy has to be reached before random numbers are generated.
- Reading from
/dev/random
will be put on hold if the kernel has not gathered enough entropy to provide the requested amount of data. /dev/urandom
on the other hand will not block to wait for more entropy. It will fall back to a pseudo-random number generator (PRNG) if and as long as there is a too small entropy pool.
application
seed
Prior any call of system.random
the programmer has to invoke system.randomize
once, so system.randSeed
provides a “random” value for the PRNG.
The default implementation uses the system clock for this, since this a value sort of available on all supported platforms.
However, its predictability is kind of unpleasant, although the argument system.randomize
’s behavior should not differ significantly regarding quality and speed among platforms is reasonable.
If we want to, we can shadow system.randomize
by our own “better” implementation, while still relying on the fast Mersenne-Twister PRNG the standard run-time library comes with.
{$ifdef UNIX}
(**
initializes PRNG with data read from /dev/random
Randomize initializes the pseudo-random number generator
by storing a value read from /dev/random to system.randSeed.
If reading fails, system.randomize will be used instead.
*)
procedure randomize;
const
/// file name for random(4) device
randomDeviceName = '/dev/random';
var
/// reading buffer
// same type as system.randSeed
randomNumber: cardinal;
/// file handle
randomReader: file of cardinal;
begin
assign(randomReader, randomDeviceName);
{$push}
// turn off run-time error generation
{$IOChecks off}
reset(randomReader);
if IOResult() = 0 then
begin
// will possibly cause the error
// EInOutError: Read past end of file
// if /dev/random is depleted
read(randomReader, randomNumber);
if IOResult() = 0 then
begin
system.randSeed := randomNumber;
end
else
begin
// do not call oneself => fully qualified identifier
system.randomize;
end;
close(randomReader);
end
{$pop}
else
begin
// do not call oneself => fully qualified identifier
system.randomize;
end;
end;
{$else}
{$hint program does not use randomize based on /dev/random}
{$endif}
When using gmp, the same applies.
program gmpRandomDemo(input, output, stderr);
// objFPC mode for try..finally-construct
{$mode objFPC}
{$typedAddress on}
uses
// familiarize with C types
cTypes,
// familiarize with exception classes
sysUtils,
// use GNU multiple precision arithmetic library
gmp;
const
/// file name for random(4) device
randomFileName = '/dev/random';
var
/// reading buffer
randomNumber: CULong;
/// file handle for random number source
randomReader: file of CULong;
/// keeps GMP random number generator state
prngState: randState_T;
/// some arbitrary number
i: MPZ_T;
begin
MP_randInit_MT(prngState);
assign(randomReader, randomFileName);
try
reset(randomReader);
try
try
read(randomReader, randomNumber);
except on eInOutError do
begin
randomize;
randomNumber := random(high(int64));
end;
end;
finally
close(randomReader);
end;
MP_randSeed_UI(prngState, randomNumber);
MPZ_init(i);
try
MPZ_uRandomB(i, prngState, 256);
MP_printF('%Zd' + lineEnding, @i);
finally
MPZ_clear(i);
end;
finally
MP_randClear(prngState);
end;
end.
multiple values
Multiple random values can be read by utilizing system.blockRead
:
program multipleRandomValuesDemo(input, output, stdErr);
// include objpas unit
{$mode objFPC}
uses
// familiarize with exception classes
sysUtils;
const
/// file name for urandom(4) device
randomDeviceName = '/dev/urandom';
type
/// base type for numbers in this program
number = dWord;
var
/// file handle for random number source
randomFile: file of number;
/// an array of numbers
population: packed array[0..5] of number;
/// temporary iterator variable
i: number;
begin
assignFile(randomFile, randomDeviceName);
try
reset(randomFile);
try
blockRead(randomFile, population, length(population));
except on eInOutError do
exitCode := 1;
end;
finally
closeFile(randomFile);
end;
for i in population do
begin
writeLn(i:10);
end;
end.