445c752003-03-07Martin Nilsson // $Id: randomness.pmod,v 1.25 2003/03/07 17:41:48 nilsson Exp $
6d00f01997-03-15Niels Möller 
ed4d752001-11-08Martin Nilsson //! Assorted stronger or weaker randomnumber generators. //! These devices try to collect entropy from the environment. //! They differ in behaviour when they run low on entropy, /dev/random //! will block if it can't provide enough random bits, while /dev/urandom //! will degenerate into a reasonably strong pseudo random generator
6d00f01997-03-15Niels Möller 
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
445c752003-03-07Martin Nilsson // #pragma strict_types
a20af62000-09-26Fredrik Hübinette (Hubbe) 
214bd21999-08-25Henrik Grubbström (Grubba) static constant RANDOM_DEVICE = "/dev/random"; static constant PRANDOM_DEVICE = "/dev/urandom";
6d00f01997-03-15Niels Möller  /* Collect somewhat random data from the environment. Unfortunately,
7dc3162001-04-27Henrik Grubbström (Grubba)  * this is quite system dependent */
214bd21999-08-25Henrik Grubbström (Grubba) static constant PATH = "/usr/sbin:/usr/etc:/usr/bin/:/sbin/:/etc:/bin";
ddab201998-01-19Fredrik Hübinette (Hubbe)  #ifndef __NT__
214bd21999-08-25Henrik Grubbström (Grubba) static constant SYSTEM_COMMANDS = ({
3369522003-01-04Martin Nilsson  "last -256", "arp -a", "netstat -anv","netstat -mv","netstat -sv", "uptime","ps -fel","ps aux", "vmstat -s","vmstat -M",
214bd21999-08-25Henrik Grubbström (Grubba)  "iostat","iostat -cdDItx" });
ddab201998-01-19Fredrik Hübinette (Hubbe) #endif
7dc3162001-04-27Henrik Grubbström (Grubba) 
3369522003-01-04Martin Nilsson static RandomSource global_arcfour; static int(0..1) goodseed;
6d00f01997-03-15Niels Möller 
7f26571999-12-01Marcus Comstedt #ifdef __NT__
8e93022003-01-09Henrik Grubbström (Grubba) static string nt_random_string(int len) {
7f26571999-12-01Marcus Comstedt  object ctx = Crypto.nt.CryptAcquireContext(0, 0, Crypto.nt.PROV_RSA_FULL, Crypto.nt.CRYPT_VERIFYCONTEXT /*|Crypto.nt.CRYPT_SILENT*/); if(!ctx)
3369522003-01-04Martin Nilsson  error( "Couldn't create crypto context.\n" );
7f26571999-12-01Marcus Comstedt 
3369522003-01-04Martin Nilsson  string res = ctx->CryptGenRandom(len);
7f26571999-12-01Marcus Comstedt  if(!res)
3369522003-01-04Martin Nilsson  error( "Couldn't generate randomness.\n" );
7f26571999-12-01Marcus Comstedt  destruct(ctx); return res;
3369522003-01-04Martin Nilsson } #endif //! Executes several programs (last -256, arp -a, netstat -anv, netstat -mv, //! netstat -sv, uptime, ps -fel, ps aux, vmstat -s, vmstat -M, iostat, //! iostat -cdDItx) to generate some entropy from their output. On Microsoft //! Windows the Windows cryptographic routines are called to generate random //! data. string some_entropy() { #ifdef __NT__ return nt_random_string(8192);
7f26571999-12-01Marcus Comstedt #else /* !__NT__ */
445c752003-03-07Martin Nilsson  mapping env = [mapping(string:string)]getenv();
3369522003-01-04Martin Nilsson  env->PATH = PATH;
6d00f01997-03-15Niels Möller 
3369522003-01-04Martin Nilsson  Stdio.File parent_pipe = Stdio.File(); Stdio.File child_pipe = parent_pipe->pipe();
6d00f01997-03-15Niels Möller  if (!child_pipe)
3369522003-01-04Martin Nilsson  error( "Couldn't create pipe.\n" ); Stdio.File null = Stdio.File("/dev/null","rw");
6d00f01997-03-15Niels Möller 
ddab201998-01-19Fredrik Hübinette (Hubbe)  foreach(SYSTEM_COMMANDS, string cmd) { catch { Process.create_process(Process.split_quoted_string(cmd),
c029131998-02-06Fredrik Hübinette (Hubbe)  (["stdin":null, "stdout":child_pipe, "stderr":null, "env":env]));
ddab201998-01-19Fredrik Hübinette (Hubbe)  }; } destruct(child_pipe);
3369522003-01-04Martin Nilsson 
ddab201998-01-19Fredrik Hübinette (Hubbe)  return parent_pipe->read();
7f26571999-12-01Marcus Comstedt #endif
6d00f01997-03-15Niels Möller }
3369522003-01-04Martin Nilsson //! Virtual class for randomness source object. class RandomSource { //! Returns a string of length len with (pseudo) random values. string read(int(0..) len) { return random_string(len); } }
ddab201998-01-19Fredrik Hübinette (Hubbe) 
3369522003-01-04Martin Nilsson // Compatibility
6d00f01997-03-15Niels Möller class pike_random {
3369522003-01-04Martin Nilsson  inherit RandomSource; }
7dc3162001-04-27Henrik Grubbström (Grubba) 
3369522003-01-04Martin Nilsson #ifdef __NT__ static class NTSource { string read(int(0..) len) { return nt_random_string(len); }
6d00f01997-03-15Niels Möller }
3369522003-01-04Martin Nilsson #endif
6d00f01997-03-15Niels Möller 
dd4d5d2000-03-28Henrik Grubbström (Grubba) #if constant(Crypto.arcfour)
ed4d752001-11-08Martin Nilsson //! A pseudo random generator based on the arcfour crypto.
dd4d5d2000-03-28Henrik Grubbström (Grubba) class arcfour_random {
7dc3162001-04-27Henrik Grubbström (Grubba) 
dd4d5d2000-03-28Henrik Grubbström (Grubba)  inherit Crypto.arcfour : arcfour;
6d00f01997-03-15Niels Möller 
ed4d752001-11-08Martin Nilsson  //! Initialize and seed the arcfour random generator.
6d00f01997-03-15Niels Möller  void create(string secret) {
445c752003-03-07Martin Nilsson  Crypto.sha hash = Crypto.sha();
6d00f01997-03-15Niels Möller  hash->update(secret);
3369522003-01-04Martin Nilsson 
dd4d5d2000-03-28Henrik Grubbström (Grubba)  arcfour::set_encrypt_key(hash->digest());
6d00f01997-03-15Niels Möller  }
ed4d752001-11-08Martin Nilsson  //! Return a string of the next len random characters from the //! arcfour random generator.
6d00f01997-03-15Niels Möller  string read(int len) {
0c8b101999-06-17Henrik Grubbström (Grubba)  if (len > 16384) return read(len/2)+read(len-len/2);
dd4d5d2000-03-28Henrik Grubbström (Grubba)  return arcfour::crypt("\47" * len);
6d00f01997-03-15Niels Möller  } }
dd4d5d2000-03-28Henrik Grubbström (Grubba) #endif /* constant(Crypto.arcfour) */
214bd21999-08-25Henrik Grubbström (Grubba) 
3369522003-01-04Martin Nilsson //! Returns a reasonably random random-source. RandomSource reasonably_random()
6d00f01997-03-15Niels Möller {
3369522003-01-04Martin Nilsson #ifdef __NT__ return NTSource(); #endif
6d00f01997-03-15Niels Möller  if (file_stat(PRANDOM_DEVICE)) {
445c752003-03-07Martin Nilsson  Stdio.File res = Stdio.File();
6d00f01997-03-15Niels Möller  if (res->open(PRANDOM_DEVICE, "r")) return res; }
dd4d5d2000-03-28Henrik Grubbström (Grubba)  if (global_arcfour) return global_arcfour;
986d8e1999-11-26Henrik Grubbström (Grubba) 
6d00f01997-03-15Niels Möller  string seed = some_entropy();
3369522003-01-04Martin Nilsson #if constant(Crypto.arcfour)
ead9722003-01-20Martin Nilsson  if (sizeof(seed) < 2001)
3369522003-01-04Martin Nilsson  seed = random_string(2001); // Well, we're only at reasonably random... return (global_arcfour = arcfour_random(sprintf("%4c%O%s", time(), _memory_usage(), seed)));
dd4d5d2000-03-28Henrik Grubbström (Grubba) #else /* !constant(Crypto.arcfour) */
3369522003-01-04Martin Nilsson  // Not very random, but at least a fallback... if(!goodseed) { random_seed( time() + Array.sum( (array)seed ) ); goodseed = 1; }
dd4d5d2000-03-28Henrik Grubbström (Grubba)  return global_arcfour = pike_random(); #endif /* constant(Crypto.arcfour) */
6d00f01997-03-15Niels Möller }
3369522003-01-04Martin Nilsson //! Returns a really random random-source. RandomSource really_random(int|void may_block)
6d00f01997-03-15Niels Möller {
3369522003-01-04Martin Nilsson #ifdef __NT__ return NTSource(); #endif Stdio.File res = Stdio.File();
6d00f01997-03-15Niels Möller  if (may_block && file_stat(RANDOM_DEVICE)) { if (res->open(RANDOM_DEVICE, "r")) return res; } if (file_stat(PRANDOM_DEVICE)) { if (res->open(PRANDOM_DEVICE, "r")) return res; }
ddab201998-01-19Fredrik Hübinette (Hubbe) 
3369522003-01-04Martin Nilsson  error( "No source found.\n" ); }