1cbb892011-04-25Martin Stjernholm /* $Id$
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__
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)
484a742002-03-09Martin Nilsson  error( "Crypto.random: couldn't create crypto context.\n" );
7f26571999-12-01Marcus Comstedt  string res = ctx->CryptGenRandom(8192); if(!res)
484a742002-03-09Martin Nilsson  error( "Crypto.random: couldn't generate randomness.\n" );
7f26571999-12-01Marcus Comstedt  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)
484a742002-03-09Martin Nilsson  error( "Crypto.random->popen: couldn't create pipe.\n" );
6d00f01997-03-15Niels Möller 
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) 
ed4d752001-11-08Martin Nilsson //! A pseudo random generator based on the ordinary random() function.
6d00f01997-03-15Niels Möller class pike_random {
7dc3162001-04-27Henrik Grubbström (Grubba) 
ed4d752001-11-08Martin Nilsson  //! 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)
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) { object hash = Crypto.sha(); hash->update(secret);
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) 
ed4d752001-11-08Martin Nilsson //!
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) */
484a742002-03-09Martin Nilsson  error( "Crypto.randomness.reasonably_random: No source found.\n" );
6d00f01997-03-15Niels Möller }
ed4d752001-11-08Martin Nilsson //!
6d00f01997-03-15Niels Möller 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; }
484a742002-03-09Martin Nilsson  error( "Crypto.randomness.really_random: No source found.\n" );
6d00f01997-03-15Niels Möller }
ddab201998-01-19Fredrik Hübinette (Hubbe)