File Coverage

blib/lib/Crypt/DH.pm
Criterion Covered Total %
statement 53 57 92.9
branch 17 30 56.6
condition 3 8 37.5
subroutine 12 12 100.0
pod 2 3 66.6
total 87 110 79.0


line stmt bran cond sub pod time code
1             package Crypt::DH;
2 2     2   887 use strict;
  2         3  
  2         87  
3              
4 2     2   236756 use Math::BigInt lib => "GMP,Pari";
  2         48944  
  2         15  
5             our $VERSION = '0.07';
6              
7             sub new {
8 8     8 1 3395 my $class = shift;
9 8         22 my $dh = bless {}, $class;
10              
11 8         28 my %param = @_;
12 8         17 for my $w (qw( p g priv_key )) {
13 24 100       74 next unless exists $param{$w};
14 16         61 $dh->$w(delete $param{$w});
15             }
16 8 50       23 die "Unknown parameters to constructor: " . join(", ", keys %param) if %param;
17              
18 8         27 $dh;
19             }
20              
21             BEGIN {
22 2     2   101781 no strict 'refs';
  2         6  
  2         224  
23 2     2   6 for my $meth (qw( p g pub_key priv_key )) {
24             *$meth = sub {
25 32     32   438792591 my $key = shift;
26 32 100       73 if (@_) {
27 16         37 $key->{$meth} = _any2bigint(shift);
28             }
29 32   50     113636 my $ret = $key->{$meth} || "";
30 32         906 $ret;
31 8         1238 };
32             }
33             }
34              
35             sub _any2bigint {
36 26     26   1717 my($value) = @_;
37 26 100 33     201 if (ref $value eq 'Math::BigInt') {
    50          
    50          
    0          
38 9         25 return $value;
39             }
40             elsif (ref $value eq 'Math::Pari') {
41 0         0 return Math::BigInt->new(Math::Pari::pari2pv($value));
42             }
43             elsif (defined $value && !(ref $value)) {
44 17         82 return Math::BigInt->new($value);
45             }
46             elsif (defined $value) {
47 0         0 die "Unknown parameter type: $value\n";
48             }
49             }
50              
51             sub generate_keys {
52 8     8 1 449504222 my $dh = shift;
53              
54 8 50       38 unless (defined $dh->{priv_key}) {
55 8         31 my $i = _bitsize($dh->{p}) - 1;
56 8 50       128888 $dh->{priv_key} =
57             $Crypt::Random::VERSION ?
58             Crypt::Random::makerandom_itv(Strength => 0, Uniform => 1,
59             Lower => 1, Upper => $dh->{p} - 1) :
60             _makerandom_itv($i, 1, $dh->{p} - 1);
61             }
62              
63 8         1355 $dh->{pub_key} = $dh->{g}->copy->bmodpow($dh->{priv_key}, $dh->{p});
64             }
65              
66             sub compute_key {
67 8     8 0 425797237 my $dh = shift;
68 8         29 my $pub_key = _any2bigint(shift);
69 8         35 $pub_key->copy->bmodpow($dh->{priv_key}, $dh->{p});
70             }
71             *compute_secret = \&compute_key;
72              
73             sub _bitsize {
74 8     8   41 return length($_[0]->as_bin) - 2;
75             }
76              
77             sub _makerandom_itv {
78 8     8   1986 my ($size, $min_inc, $max_exc) = @_;
79              
80 8         17 while (1) {
81 8         32 my $r = _makerandom($size);
82 8 50 33     116584 return $r if $r >= $min_inc && $r < $max_exc;
83             }
84             }
85              
86             sub _makerandom {
87 8     8   19 my $size = shift;
88              
89 8 50       37 my $bytes = int($size / 8) + ($size % 8 ? 1 : 0);
90              
91 8         24 my $rand;
92 8 50       220 if (-e "/dev/urandom") {
93 8         13 my $fh;
94 8 50       275 open($fh, '/dev/urandom')
95             or die "Couldn't open /dev/urandom";
96 8         269 my $got = sysread $fh, $rand, $bytes;
97 8 50       26 die "Didn't read all bytes from urandom" unless $got == $bytes;
98 8         160 close $fh;
99             } else {
100 0         0 for (1..$bytes) {
101 0         0 $rand .= chr(int(rand(256)));
102             }
103             }
104              
105 8         92 my $bits = unpack("b*", $rand);
106 8 50       31 die unless length($bits) >= $size;
107              
108 8         94 Math::BigInt->new('0b' . substr($bits, 0, $size));
109             }
110              
111             1;
112             __END__