1
  
2
  
3
  
4
  
5
  
6
  
7
  
8
  
9
  
10
  
11
  
12
  
13
  
14
  
15
  
16
  
17
  
18
  
19
  
20
  
21
  
22
  
23
  
24
  
25
  
26
  
27
  
28
  
29
  
30
  
31
  
32
  
33
  
34
  
35
  
36
  
37
  
38
  
39
  
40
  
41
  
42
  
43
  
44
  
45
  
46
  
47
  
48
  
49
  
50
  
51
  
52
  
53
  
54
  
55
  
56
  
57
  
58
  
59
  
60
  
61
  
62
  
63
  
64
  
65
  
66
  
67
  
68
  
69
  
70
  
71
  
72
  
73
  
74
  
75
  
76
  
77
  
78
  
79
  
80
  
81
  
82
  
83
  
84
  
85
  
86
  
87
  
88
  
89
  
90
  
91
  
92
  
93
  
94
  
95
  
96
  
97
  
98
  
99
  
100
  
101
  
102
  
103
  
104
  
105
  
106
  
107
  
108
  
109
  
110
  
111
  
112
  
113
  
114
  
115
  
116
  
117
  
118
  
119
  
120
  
121
  
122
  
123
  
124
  
/* randomness.pmod 
 * 
 * Assorted stronger or weaker randomnumber generators. 
 */ 
 
/* These devices tries 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 */ 
 
#define RANDOM_DEVICE "/dev/random" 
#define PRANDOM_DEVICE "/dev/urandom" 
 
/* Collect somewhat random data from the environment. Unfortunately, 
 * this is quite system dependent */ 
#define PATH  "/usr/sbin:/usr/etc:/usr/bin/:/sbin/:/etc:/bin" 
#define SYSTEM_COMMANDS "rup & ping -s 255.255.255.255 256 30 &" \ 
                        "uptime & ps -fel & vmstat -s & iostat -cdDItx &" 
                       
#define PRIVATE 
                       
PRIVATE object global_rc4; 
 
PRIVATE string some_entropy() 
{ 
  object parent_pipe, child_pipe; 
 
  parent_pipe = Stdio.File(); 
  child_pipe = parent_pipe->pipe(); 
  if (!child_pipe) 
    throw( ({ "Crypto.random->popen: couldn't create pipe\n", backtrace() }) ); 
 
  if (!fork()) 
  { /* Child */ 
    catch { 
      object stderr = Stdio.File(); 
      object stdin = Stdio.File(); 
       
      destruct(parent_pipe); 
       
      stderr->open("/dev/null", "w"); 
      stderr->dup2(Stdio.File("stderr")); 
       
      stdin->open("/dev/null", "r"); 
      stdin->dup2(Stdio.File("stdin")); 
     
      child_pipe->dup2(Stdio.File("stdout")); 
      catch(exece("/bin/sh", ({ "-c", SYSTEM_COMMANDS }), ([ "PATH" : PATH ]) )); 
    }; 
    exit(17); 
  } else { 
    /* Parent */ 
    string res; 
    destruct(child_pipe); 
    res = parent_pipe->read(0x7fffffff); 
    return res; 
  } 
} 
 
class pike_random { 
  string read(int len) 
  { 
    return sprintf("%@c", Array.map(allocate(len), lambda(int dummy) 
                                    { 
                                      return random(256); 
                                    } )); 
  } 
} 
 
class rc4_random { 
  inherit Crypto.rc4 : rc4; 
 
  void create(string secret) 
  { 
    object hash = Crypto.sha(); 
    hash->update(secret); 
     
    rc4::set_encrypt_key(hash->digest()); 
  } 
 
  string read(int len) 
  { 
    return rc4::crypt(replace(allocate(len), 0, "\47") * ""); 
  } 
} 
 
object reasonably_random() 
{ 
  if (file_stat(PRANDOM_DEVICE)) 
  { 
    object res = Stdio.File(); 
    if (res->open(PRANDOM_DEVICE, "r")) 
      return res; 
  } 
 
  if (global_rc4) 
    return global_rc4; 
   
  string seed = some_entropy(); 
  if (strlen(seed) > 2000) 
    return (global_rc4 = rc4_random(sprintf("%4c%O%s", time(), _memory_usage(), seed))); 
   
  throw( ({ "Crypto.randomness.reasonably_random: No source found\n", backtrace() }) ); 
} 
 
object really_random(int|void may_block) 
{ 
  object res = Stdio.File(); 
  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() }) ); 
}