Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 29 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
Random | |
0.00% |
0 / 29 |
|
0.00% |
0 / 4 |
156 | |
0.00% |
0 / 1 |
open | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
close | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
getInt | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
20 | |||
shuffle | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\SecurePoll\Crypt; |
4 | |
5 | use MediaWiki\Status\Status; |
6 | use RuntimeException; |
7 | |
8 | class Random { |
9 | /** @var resource|null */ |
10 | public $urandom; |
11 | |
12 | /** |
13 | * Open a /dev/urandom file handle |
14 | * @return Status |
15 | */ |
16 | public function open() { |
17 | if ( $this->urandom ) { |
18 | return Status::newGood(); |
19 | } |
20 | |
21 | if ( wfIsWindows() ) { |
22 | return Status::newFatal( 'securepoll-urandom-not-supported' ); |
23 | } |
24 | $this->urandom = fopen( '/dev/urandom', 'rb' ); |
25 | if ( !$this->urandom ) { |
26 | return Status::newFatal( 'securepoll-dump-no-urandom' ); |
27 | } |
28 | |
29 | return Status::newGood(); |
30 | } |
31 | |
32 | /** |
33 | * Close any open file handles |
34 | */ |
35 | public function close() { |
36 | if ( $this->urandom ) { |
37 | fclose( $this->urandom ); |
38 | $this->urandom = null; |
39 | } |
40 | } |
41 | |
42 | /** |
43 | * Get a random integer between 0 and ($maxp1 - 1). |
44 | * Should only be called after open() succeeds. |
45 | * @param int $maxp1 |
46 | * @return int |
47 | */ |
48 | public function getInt( $maxp1 ) { |
49 | $numBytes = ceil( strlen( base_convert( (string)$maxp1, 10, 16 ) ) / 2 ); |
50 | if ( $numBytes == 0 ) { |
51 | return 0; |
52 | } |
53 | $data = fread( $this->urandom, $numBytes ); |
54 | if ( strlen( $data ) != $numBytes ) { |
55 | throw new RuntimeException( __METHOD__ . ': not enough bytes' ); |
56 | } |
57 | $x = 0; |
58 | for ( $i = 0; $i < $numBytes; $i++ ) { |
59 | $x *= 256; |
60 | $x += ord( substr( $data, $i, 1 ) ); |
61 | } |
62 | |
63 | return $x % $maxp1; |
64 | } |
65 | |
66 | /** |
67 | * Works like shuffle() except more secure. Returns the new array instead |
68 | * of modifying it. The algorithm is the Knuth/Durstenfeld kind. |
69 | * @param array $a |
70 | * @return array |
71 | */ |
72 | public function shuffle( $a ) { |
73 | $a = array_values( $a ); |
74 | for ( $i = count( $a ) - 1; $i >= 0; $i-- ) { |
75 | $target = $this->getInt( $i + 1 ); |
76 | $tmp = $a[$i]; |
77 | $a[$i] = $a[$target]; |
78 | $a[$target] = $tmp; |
79 | } |
80 | |
81 | return $a; |
82 | } |
83 | } |