7dc3162001-04-27Henrik Grubbström (Grubba) /* $Id: randomness.pmod,v 1.19 2001/04/27 13:35:23 grubba Exp $
6d00f01997-03-15Niels Möller  */
214bd21999-08-25Henrik Grubbström (Grubba) //! Assorted stronger or weaker randomnumber generators.
7dc3162001-04-27Henrik Grubbström (Grubba) /* These devices try to collect entropy from the environment.
6d00f01997-03-15Niels Möller  * 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
7dc3162001-04-27Henrik Grubbström (Grubba)  * will degenerate into a reasonably strong pseudo random generator */
6d00f01997-03-15Niels Möller 
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
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 = ({ "last -256", "arp -a", "netstat -anv","netstat -mv","netstat -sv", "uptime","ps -fel","ps aux", "vmstat -s","vmstat -M", "iostat","iostat -cdDItx" });
ddab201998-01-19Fredrik Hübinette (Hubbe) #else
214bd21999-08-25Henrik Grubbström (Grubba) static constant SYSTEM_COMMANDS = ({ "mem /c", "arp -a", "vol", "dir", "net view", "net statistics workstation","net statistics server", "net user" });
ddab201998-01-19Fredrik Hübinette (Hubbe) #endif
7dc3162001-04-27Henrik Grubbström (Grubba)  // ***************************** #define private
6d00f01997-03-15Niels Möller 
7dc3162001-04-27Henrik Grubbström (Grubba) private object global_arcfour;
6d00f01997-03-15Niels Möller 
214bd21999-08-25Henrik Grubbström (Grubba) // Executes several programs to generate some entropy from their output.
7dc3162001-04-27Henrik Grubbström (Grubba) private string some_entropy()
6d00f01997-03-15Niels Möller {
7f26571999-12-01Marcus Comstedt #ifdef __NT__ object ctx = Crypto.nt.CryptAcquireContext(0, 0, Crypto.nt.PROV_RSA_FULL, Crypto.nt.CRYPT_VERIFYCONTEXT /*|Crypto.nt.CRYPT_SILENT*/); if(!ctx) throw(({ "Crypto.random: couldn't create crypto context\n", backtrace()})); string res = ctx->CryptGenRandom(8192); if(!res) throw(({ "Crypto.random: couldn't generate randomness\n", backtrace()})); destruct(ctx); return res; #else /* !__NT__ */
ddab201998-01-19Fredrik Hübinette (Hubbe)  string res;
6d00f01997-03-15Niels Möller  object parent_pipe, child_pipe;
c3f7751998-02-06Fredrik Hübinette (Hubbe)  mapping env=getenv()+([]);
6d00f01997-03-15Niels Möller  parent_pipe = Stdio.File(); child_pipe = parent_pipe->pipe(); if (!child_pipe) throw( ({ "Crypto.random->popen: couldn't create pipe\n", backtrace() }) );
ddab201998-01-19Fredrik Hübinette (Hubbe)  object null=Stdio.File("/dev/null","rw"); env["PATH"]=PATH; 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); return parent_pipe->read();
7f26571999-12-01Marcus Comstedt #endif
6d00f01997-03-15Niels Möller }
ddab201998-01-19Fredrik Hübinette (Hubbe) 
214bd21999-08-25Henrik Grubbström (Grubba) //! A pseudo random generator based on the ordinary random() function.
6d00f01997-03-15Niels Möller class pike_random {
7dc3162001-04-27Henrik Grubbström (Grubba) 
214bd21999-08-25Henrik Grubbström (Grubba)  //! Returns a string of length len with pseudo random values.
6d00f01997-03-15Niels Möller  string read(int len) {
283ec72000-04-15Fredrik Hübinette (Hubbe) #if 1 // major optimization /Hubbe return random_string(len); #else
103d891999-09-13Fredrik Hübinette (Hubbe) #if 1 // 30% optimization /Hubbe string ret=""; if(len>=16384) { array x=allocate(16384,random); for(int e=0;e<(len/16384);e++) ret+=(string)x(256); } ret+=(string)allocate(len % 16384, random)(256); return ret; #else
8177c41999-06-16David Hedbor  if (len > 16384) return read(len/2)+read(len-len/2); return (string)allocate(len, random)(256);
103d891999-09-13Fredrik Hübinette (Hubbe) #endif
283ec72000-04-15Fredrik Hübinette (Hubbe) #endif
6d00f01997-03-15Niels Möller  } }
dd4d5d2000-03-28Henrik Grubbström (Grubba) #if constant(Crypto.arcfour) //! A pseudo random generator based on the arcfour crypto. class arcfour_random {
7dc3162001-04-27Henrik Grubbström (Grubba) 
dd4d5d2000-03-28Henrik Grubbström (Grubba)  inherit Crypto.arcfour : arcfour;
6d00f01997-03-15Niels Möller 
dd4d5d2000-03-28Henrik Grubbström (Grubba)  //! Initialize and seed the arcfour random generator.
6d00f01997-03-15Niels Möller  void create(string secret) { object hash = Crypto.sha(); hash->update(secret);
dd4d5d2000-03-28Henrik Grubbström (Grubba)  arcfour::set_encrypt_key(hash->digest());
6d00f01997-03-15Niels Möller  }
214bd21999-08-25Henrik Grubbström (Grubba)  //! Return a string of the next len random characters from the
dd4d5d2000-03-28Henrik Grubbström (Grubba)  //! 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) 
6d00f01997-03-15Niels Möller object reasonably_random() { if (file_stat(PRANDOM_DEVICE)) { object res = Stdio.File(); 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) 
dd4d5d2000-03-28Henrik Grubbström (Grubba) #if constant(Crypto.arcfour)
6d00f01997-03-15Niels Möller  string seed = some_entropy(); if (strlen(seed) > 2000)
dd4d5d2000-03-28Henrik Grubbström (Grubba)  return (global_arcfour = arcfour_random(sprintf("%4c%O%s", time(), _memory_usage(), seed))); #else /* !constant(Crypto.arcfour) */
986d8e1999-11-26Henrik Grubbström (Grubba)  /* Not very random, but at least a fallback... */
dd4d5d2000-03-28Henrik Grubbström (Grubba)  return global_arcfour = pike_random(); #endif /* constant(Crypto.arcfour) */
6d00f01997-03-15Niels Möller  throw( ({ "Crypto.randomness.reasonably_random: No source found\n", backtrace() }) ); } object really_random(int|void may_block) {
e106c71997-04-10Niels Möller  object 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; } throw( ({ "Crypto.randomness.really_random: No source found\n", backtrace() }) ); }
ddab201998-01-19Fredrik Hübinette (Hubbe)