File Coverage

blib/lib/BSD/arc4random.pm
Criterion Covered Total %
statement 45 79 56.9
branch 9 28 32.1
condition 3 9 33.3
subroutine 11 15 73.3
pod 7 7 100.0
total 75 138 54.3


line stmt bran cond sub pod time code
1             # $MirOS: contrib/hosted/tg/code/BSD::arc4random/lib/BSD/arc4random.pm,v 1.10 2011/06/05 23:19:04 tg Exp $
2             #-
3             # Copyright (c) 2008, 2009, 2010, 2011
4             # Thorsten Glaser
5             # Copyright (c) 2009
6             # Benny Siegert
7             #
8             # Provided that these terms and disclaimer and all copyright notices
9             # are retained or reproduced in an accompanying document, permission
10             # is granted to deal in this work without restriction, including un-
11             # limited rights to use, publicly perform, distribute, sell, modify,
12             # merge, give away, or sublicence.
13             #
14             # This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15             # the utmost extent permitted by applicable law, neither express nor
16             # implied; without malicious intent or gross negligence. In no event
17             # may a licensor, author or contributor be held liable for indirect,
18             # direct, other damage, loss, or other issues arising in any way out
19             # of dealing in the work, even if advised of the possibility of such
20             # damage or existence of a defect, except proven that it results out
21             # of said person's immediate fault when using the work as intended.
22              
23             package BSD::arc4random;
24              
25 1     1   491 use strict;
  1         1  
  1         27  
26 1     1   5 use warnings;
  1         1  
  1         37  
27              
28             BEGIN {
29 1     1   4 require Exporter;
30 1         3 require DynaLoader;
31 1     1   4 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  1         4  
  1         118  
32 1         2 $VERSION = "1.50";
33 1         13 @ISA = qw(Exporter DynaLoader);
34 1         2 @EXPORT = qw();
35 1         3 @EXPORT_OK = qw(
36             $RANDOM
37             &arc4random
38             &arc4random_addrandom
39             &arc4random_bytes
40             &arc4random_pushb
41             &arc4random_pushk
42             &arc4random_stir
43             &arc4random_uniform
44             );
45 1         22 %EXPORT_TAGS = (
46             all => [ @EXPORT_OK ],
47             );
48             }
49              
50 1     1   4 use vars qw($RANDOM); # public tied integer variable
  1         1  
  1         702  
51             sub have_kintf() {} # public constant function, prototyped
52              
53             my $have_threadlock = 1;
54             my $arcfour_lock;
55             eval { require threads::shared; };
56             if ($@) {
57             $have_threadlock = 0; # module not available
58             } else {
59             # private thread lock
60             threads::shared::share($arcfour_lock);
61             };
62              
63             bootstrap BSD::arc4random $BSD::arc4random::VERSION;
64              
65             # public thread-safe functions
66             sub
67             arc4random()
68             {
69 8 50   8 1 16 lock($arcfour_lock) if $have_threadlock;
70 8         21 return &arc4random_xs();
71             }
72              
73             sub
74             arc4random_addrandom($)
75             {
76 0     0 1 0 my $buf = shift;
77              
78 0 0       0 lock($arcfour_lock) if $have_threadlock;
79 0         0 return &arc4random_addrandom_xs($buf);
80             }
81              
82             sub
83             arc4random_pushb($)
84             {
85 3     3 1 5 my $buf = shift;
86              
87 3 50       23 lock($arcfour_lock) if $have_threadlock;
88 3         88 return &arc4random_pushb_xs($buf);
89             }
90              
91             sub
92             arc4random_pushk($)
93             {
94 0     0 1 0 my $buf = shift;
95              
96 0 0       0 lock($arcfour_lock) if $have_threadlock;
97 0         0 return &arc4random_pushk_xs($buf);
98             }
99              
100             sub
101             arc4random_stir()
102             {
103 0 0   0 1 0 lock($arcfour_lock) if $have_threadlock;
104 0         0 &arc4random_stir_xs();
105 0         0 return;
106             }
107              
108             sub
109             arc4random_bytes($;$)
110             {
111 0     0 1 0 my ($len, $buf) = @_;
112 0         0 my $val;
113 0         0 my $vleft = 0;
114 0         0 my $rv = '';
115 0         0 my $idx = 0;
116              
117 0 0       0 if (defined($buf)) {
118 0         0 $val = arc4random_pushb($buf);
119 0         0 $vleft = 4;
120             }
121 0         0 while (($len - $idx) >= 4) {
122 0 0       0 if ($vleft < 4) {
123 0         0 $val = arc4random();
124 0         0 $vleft = 4;
125             }
126 0         0 vec($rv, $idx / 4, 32) = $val;
127 0         0 $idx += 4;
128 0         0 $vleft = 0;
129             }
130 0         0 while ($idx < $len) {
131 0 0       0 if ($vleft == 0) {
132 0         0 $val = arc4random();
133 0         0 $vleft = 4;
134             }
135 0         0 vec($rv, $idx, 8) = $val & 0xFF;
136 0         0 $idx++;
137 0         0 $val >>= 8;
138 0         0 $vleft--;
139             }
140 0         0 return $rv;
141             }
142              
143             # Perl implementation of arc4random_uniform(3)
144             # C implementation contributed by djm@openbsd.org, Jinmei_Tatuya@isc.org
145             #
146             # Calculate a uniformly distributed random number less than upper_bound
147             # avoiding "modulo bias".
148             #
149             # Uniformity is achieved by generating new random numbers until the one
150             # returned is outside the range [0, 2**32 % upper_bound). This
151             # guarantees the selected random number will be inside
152             # [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
153             # after reduction modulo upper_bound.
154              
155             sub
156             arc4random_uniform($)
157             {
158 8     8 1 82 my $upper_bound = shift;
159 8         9 my $r;
160             my $min;
161              
162 8 50       15 return 0 unless defined($upper_bound);
163             # convert upper_bound to 32-bit UV (unsigned integer value)
164 8         8 $upper_bound &= 0xFFFFFFFF;
165 8 50 33     35 return 0 if $upper_bound < 2 || $upper_bound > 0xFFFFFFFF;
166              
167             # Calculate (2**32 % upper_bound) avoiding 64-bit math
168 8 100       20 if ($upper_bound > 0x80000000) {
169             # 2**32 - upper_bound (only one "value area")
170 2         4 $min = 1 + (~$upper_bound & 0xFFFFFFFF);
171             } else {
172             # (2**32 - x) % x == 2**32 % x when x <= 2**31
173 6         8 $min = (0xFFFFFFFF - $upper_bound + 1) % $upper_bound;
174             }
175              
176             # This could theoretically loop forever but each retry has
177             # p > 0.5 (worst case, usually far better) of selecting a
178             # number inside the range we need, so it should rarely need
179             # to re-roll.
180 8         8 while (1) {
181 8         14 $r = arc4random();
182 8 50       18 last if $r >= $min;
183             }
184              
185 8         21 return ($r % $upper_bound);
186             }
187              
188             # private implementation for a tied $RANDOM variable
189             sub
190             TIESCALAR
191             {
192 1     1   3 my $class = shift;
193 1         2 my $max = shift;
194              
195 1 50 33     15 if (!defined($max) || ($max = int($max)) > 0xFFFFFFFE || $max < 0) {
      33        
196 0         0 $max = 0;
197             }
198              
199 1         5 return bless \$max, $class;
200             }
201              
202             sub
203             FETCH
204             {
205 4     4   26 my $self = shift;
206              
207 4 50       25 return ($$self == 0 ? arc4random() : arc4random_uniform($$self + 1));
208             }
209              
210             sub
211             STORE
212             {
213 2     2   89 my $self = shift;
214 2         4 my $value = shift;
215              
216 2         6 arc4random_pushb($value);
217             }
218              
219             # tie the public $RANDOM variable to an mksh-style implementation
220             tie $RANDOM, 'BSD::arc4random', 0x7FFF;
221              
222             # we are nice and re-seed perl's internal PRNG as well
223             srand(arc4random_pushb(pack("F*", rand(), rand(), rand(), rand())));
224              
225             1;
226             __END__