Dev random

From Free Pascal wiki
Jump to: navigation, search

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 the Greek letter μ, meaning “micro”. The randomness of /dev/urandom is reduced, in comparison to /dev/random.

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 runtime library comes with.

  1. {$ifdef UNIX}
  2. (**
  3. 	initializes PRNG with data read from /dev/random
  4.  
  5. 	Randomize initializes the pseudo-random number generator
  6. 	by storing a value read from /dev/random to system.randSeed.
  7. 	If reading fails, system.randomize will be used instead.
  8. *)
  9. procedure randomize;
  10. const
  11. 	/// file name for random(4) device
  12. 	randomDeviceName = '/dev/random';
  13. var
  14. 	/// reading buffer
  15. 	// same type as system.randSeed
  16. 	randomNumber: cardinal;
  17. 	/// file handle
  18. 	randomReader: file of cardinal;
  19. begin
  20. 	assign(randomReader, randomDeviceName);
  21. 	{$push}
  22. 	// turn off run-time error generation
  23. 	{$IOChecks off}
  24. 	reset(randomReader);
  25.  
  26. 	if IOResult() = 0 then
  27. 	begin
  28. 		// will possibly cause the error
  29. 		//   EInOutError: Read past end of file
  30. 		// if /dev/random is depleted
  31. 		read(randomReader, randomNumber);
  32.  
  33. 		if IOResult() = 0 then
  34. 		begin
  35. 			system.randSeed := randomNumber;
  36. 		end
  37. 		else
  38. 		begin
  39. 			// do not call one-self => fully qualified identfier
  40. 			system.randomize;
  41. 		end;
  42.  
  43. 		close(randomReader);
  44. 	end
  45. 	{$pop}
  46. 	else
  47. 	begin
  48. 		// do not call one-self => fully qualified identfier
  49. 		system.randomize;
  50. 	end;
  51. end;
  52. {$else}
  53. {$hint program does not use randomize based on /dev/random}
  54. {$endif}

When using gmp, the same applies.

  1. program gmpRandomDemo(input, output, stderr);
  2.  
  3. // objFPC mode for try..finally-construct
  4. {$mode objFPC}
  5. {$typedAddress on}
  6.  
  7. uses
  8. 	// familiarze with C types
  9. 	cTypes,
  10. 	// familiarize with exception classes
  11. 	sysUtils,
  12. 	// use GNU multiple precision arithmetic library
  13. 	gmp;
  14.  
  15. const
  16. 	/// file name for random(4) device
  17. 	randomFileName = '/dev/random';
  18.  
  19. var
  20. 	/// reading buffer
  21. 	randomNumber: CULong;
  22. 	/// file handle for random number source
  23. 	randomReader: file of CULong;
  24. 	/// keeps GMP random number generator state
  25. 	prngState: randState_T;
  26. 	/// some arbitrary number
  27. 	i: MPZ_T;
  28. begin
  29. 	MP_randInit_MT(prngState);
  30. 	assign(randomReader, randomFileName);
  31. 	try
  32. 		reset(randomReader);
  33. 		try
  34. 			try
  35. 				read(randomReader, randomNumber);
  36. 			except on eInOutError do
  37. 			begin
  38. 				randomize;
  39. 				randomNumber := random(high(int64));
  40. 			end;
  41. 			end;
  42. 		finally
  43. 			close(randomReader);
  44. 		end;
  45. 		MP_randSeed_UI(prngState, randomNumber);
  46.  
  47. 		MPZ_init(i);
  48. 		try
  49. 			MPZ_uRandomB(i, prngState, 256);
  50. 			MP_printF('%Zd' + lineEnding, @i);
  51. 		finally
  52. 			MPZ_clear(i);
  53. 		end;
  54. 	finally	
  55. 		MP_randClear(prngState);
  56. 	end;
  57. end.

multiple values

Multiple random values can be read by utilizing system.blockRead:

  1. program multipleRandomValuesDemo(input, output, stderr);
  2.  
  3. // include objpas unit
  4. {$mode objFPC}
  5.  
  6. uses
  7. 	// familiarize with exception classes
  8. 	sysUtils;
  9.  
  10. const
  11. 	/// file name for urandom(4) device
  12. 	randomDeviceName = '/dev/urandom';
  13.  
  14. type
  15. 	/// base type for numbers in this program
  16. 	number = dWord;
  17.  
  18. var
  19. 	/// file handle for random number source
  20. 	randomFile: file of number;
  21. 	/// an array of numbers
  22. 	population: packed array[0..5] of number;
  23. 	/// temporary iterator variable
  24. 	i: number;
  25.  
  26. begin
  27. 	assignFile(randomFile, randomDeviceName);
  28. 	try
  29. 		reset(randomFile);
  30. 		try
  31. 			blockRead(randomFile, population, length(population));
  32. 		except on eInOutError do
  33. 			exitCode := 1;
  34. 		end;
  35. 	finally
  36. 		closeFile(randomFile);
  37. 	end;
  38.  
  39. 	for i in population do
  40. 	begin
  41. 		writeLn(i:10);
  42. 	end;
  43. end.

see also