Elgg  Version 1.9
ElggCrypto.php
Go to the documentation of this file.
1 <?php
10 class ElggCrypto {
11 
15  const CHARS_PASSWORD = 'bcdfghjklmnpqrstvwxyz2346789';
16 
20  const CHARS_HEX = '0123456789abcdef';
21 
55  public function getRandomBytes($length) {
60  $SSLstr = '4'; // http://xkcd.com/221/
61  if (function_exists('openssl_random_pseudo_bytes')
62  && (version_compare(PHP_VERSION, '5.3.4') >= 0 || substr(PHP_OS, 0, 3) !== 'WIN')) {
63  $SSLstr = openssl_random_pseudo_bytes($length, $strong);
64  if ($strong) {
65  return $SSLstr;
66  }
67  }
68 
77  if (function_exists('mcrypt_create_iv')
78  && (version_compare(PHP_VERSION, '5.3.7') >= 0 || substr(PHP_OS, 0, 3) !== 'WIN')) {
79  $str = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
80  if ($str !== false) {
81  return $str;
82  }
83  }
84 
92  $str = '';
93  $bits_per_round = 2; // bits of entropy collected in each clock drift round
94  $msec_per_round = 400; // expected running time of each round in microseconds
95  $hash_len = 20; // SHA-1 Hash length
96  $total = $length; // total bytes of entropy to collect
97 
98  $handle = @fopen('/dev/urandom', 'rb');
99  if ($handle && function_exists('stream_set_read_buffer')) {
100  @stream_set_read_buffer($handle, 0);
101  }
102 
103  do {
104  $bytes = ($total > $hash_len) ? $hash_len : $total;
105  $total -= $bytes;
106 
107  //collect any entropy available from the PHP system and filesystem
108  $entropy = rand() . uniqid(mt_rand(), true) . $SSLstr;
109  $entropy .= implode('', @fstat(@fopen(__FILE__, 'r')));
110  $entropy .= memory_get_usage() . getmypid();
111  $entropy .= serialize($_ENV) . serialize($_SERVER);
112  if (function_exists('posix_times')) {
113  $entropy .= serialize(posix_times());
114  }
115  if (function_exists('zend_thread_id')) {
116  $entropy .= zend_thread_id();
117  }
118 
119  if ($handle) {
120  $entropy .= @fread($handle, $bytes);
121  } else {
122  // Measure the time that the operations will take on average
123  for ($i = 0; $i < 3; $i++) {
124  $c1 = microtime(true);
125  $var = sha1(mt_rand());
126  for ($j = 0; $j < 50; $j++) {
127  $var = sha1($var);
128  }
129  $c2 = microtime(true);
130  $entropy .= $c1 . $c2;
131  }
132 
133  // Based on the above measurement determine the total rounds
134  // in order to bound the total running time.
135  $rounds = (int) ($msec_per_round * 50 / (int) (($c2 - $c1) * 1000000));
136 
137  // Take the additional measurements. On average we can expect
138  // at least $bits_per_round bits of entropy from each measurement.
139  $iter = $bytes * (int) (ceil(8 / $bits_per_round));
140 
141  for ($i = 0; $i < $iter; $i++) {
142  $c1 = microtime();
143  $var = sha1(mt_rand());
144  for ($j = 0; $j < $rounds; $j++) {
145  $var = sha1($var);
146  }
147  $c2 = microtime();
148  $entropy .= $c1 . $c2;
149  }
150  }
151 
152  // We assume sha1 is a deterministic extractor for the $entropy variable.
153  $str .= sha1($entropy, true);
154 
155  } while ($length > strlen($str));
156 
157  if ($handle) {
158  @fclose($handle);
159  }
160 
161  return substr($str, 0, $length);
162  }
163 
183  public function getRandomString($length, $chars = null) {
184  if ($length < 1) {
185  throw new InvalidArgumentException('Length should be >= 1');
186  }
187 
188  if (empty($chars)) {
189  $numBytes = ceil($length * 0.75);
190  $bytes = $this->getRandomBytes($numBytes);
191  $string = substr(rtrim(base64_encode($bytes), '='), 0, $length);
192 
193  // Base64 URL
194  return strtr($string, '+/', '-_');
195  }
196 
197  if ($chars == self::CHARS_HEX) {
198  // hex is easy
199  $bytes = $this->getRandomBytes(ceil($length / 2));
200  return substr(bin2hex($bytes), 0, $length);
201  }
202 
203  $listLen = strlen($chars);
204 
205  if ($listLen == 1) {
206  return str_repeat($chars, $length);
207  }
208 
209  $bytes = $this->getRandomBytes($length);
210  $pos = 0;
211  $result = '';
212  for ($i = 0; $i < $length; $i++) {
213  $pos = ($pos + ord($bytes[$i])) % $listLen;
214  $result .= $chars[$pos];
215  }
216 
217  return $result;
218  }
219 }
const CHARS_PASSWORD
Character set for temp passwords (no risk of embedded profanity/glyphs that look similar) ...
Definition: ElggCrypto.php:15
getRandomBytes($length)
Generate a string of highly randomized bytes (over the full 8-bit range).
Definition: ElggCrypto.php:55
$string
const CHARS_HEX
Character set for hexadecimal.
Definition: ElggCrypto.php:20
getRandomString($length, $chars=null)
Generate a random string of specified length.
Definition: ElggCrypto.php:183