File Coverage

blib/lib/Crypt/DSA.pm
Criterion Covered Total %
statement 85 85 100.0
branch 10 20 50.0
condition 1 3 33.3
subroutine 15 15 100.0
pod 4 4 100.0
total 115 127 90.5


line stmt bran cond sub pod time code
1             package Crypt::DSA;
2              
3 7     7   869454 use 5.006;
  7         21  
4 7     7   45 use strict;
  7         47  
  7         193  
5 7     7   33 use warnings;
  7         9  
  7         303  
6 7     7   3526 use Digest::SHA qw( sha1 );
  7         20329  
  7         679  
7 7     7   64 use Carp qw( croak );
  7         11  
  7         268  
8 7     7   3204 use Crypt::DSA::KeyChain;
  7         21  
  7         230  
9 7     7   32 use Crypt::DSA::Key;
  7         7  
  7         103  
10 7     7   2613 use Crypt::DSA::Signature;
  7         17  
  7         282  
11 7     7   32 use Crypt::DSA::Util qw( bitsize bin2mp mod_inverse mod_exp makerandom randombelow );
  7         9  
  7         431  
12              
13             our $VERSION = '1.24'; #VERSION
14              
15 7     7   26 use vars qw( $VERSION );
  7         24  
  7         3938  
16              
17             sub new {
18 2     2 1 285961 my $class = shift;
19 2         7 my $dsa = bless { @_ }, $class;
20 2         18 $dsa->{_keychain} = Crypt::DSA::KeyChain->new(@_);
21 2         6 $dsa;
22             }
23              
24             sub keygen {
25 1     1 1 4 my $dsa = shift;
26 1         4 my $key = $dsa->{_keychain}->generate_params(@_);
27 1         43 $dsa->{_keychain}->generate_keys($key);
28 1         44 $key;
29             }
30              
31             sub sign {
32 1     1 1 28 my $dsa = shift;
33 1         24 my %param = @_;
34 1         2 my($key, $dgst);
35 1 50       10 croak __PACKAGE__, "->sign: Need a Key" unless $key = $param{Key};
36 1 50       9 unless ($dgst = $param{Digest}) {
37             croak __PACKAGE__, "->sign: Need either Message or Digest"
38 1 50       3 unless $param{Message};
39 1         20 $dgst = sha1($param{Message});
40             }
41 1         18 my $dlen = length $dgst;
42              
43 1         15 my $i = bitsize($key->q) / 8;
44 1 50 33     459 croak "Data too large for key size"
45             if $dlen > $i || $dlen > 50;
46              
47             # SECURITY: a DSA nonce (k) must NEVER be reused across signatures;
48             # two signatures sharing k disclose the private key. Always generate
49             # fresh r/kinv per signature -- do NOT reuse any values cached on the
50             # Key object from a previous sign().
51 1         14 $dsa->_sign_setup($key);
52              
53 1         12 my $m = bin2mp($dgst);
54 1         581 my $xr = ($key->priv_key * $key->r) % $key->q;
55 1         353 my $s = $xr + $m;
56 1 50       120 $s -= $key->q if $s > $key->q;
57 1         66 $s = ($s * $key->kinv) % $key->q;
58              
59 1         373 my $sig = Crypt::DSA::Signature->new;
60 1         10 $sig->r($key->r);
61 1         13 $sig->s($s);
62 1         14 $sig;
63             }
64              
65             sub _sign_setup {
66 1     1   14 my $dsa = shift;
67 1         7 my $key = shift;
68 1         2 my($k, $r);
69             {
70             # Nonce must be uniform in [1, q-1]. Do NOT use makerandom()
71             # (it forces the high bit, which biases the nonce after folding).
72 1         6 $k = randombelow($key->q);
  1         18  
73 1 50       207 redo if $k == 0;
74             }
75 1         148 $r = mod_exp($key->g, $k, $key->p);
76 1         387749 $r %= $key->q;
77 1         529 my $kinv = mod_inverse($k, $key->q);
78 1         8138 $key->r($r);
79 1         47 $key->kinv($kinv);
80             }
81              
82             sub verify {
83 1     1 1 2 my $dsa = shift;
84 1         6 my %param = @_;
85 1         1 my($key, $dgst, $sig);
86 1 50       4 croak __PACKAGE__, "->verify: Need a Key" unless $key = $param{Key};
87 1 50       6 unless ($dgst = $param{Digest}) {
88             croak __PACKAGE__, "->verify: Need either Message or Digest"
89 1 50       3 unless $param{Message};
90 1         8 $dgst = sha1($param{Message});
91             }
92             croak __PACKAGE__, "->verify: Need a Signature"
93 1 50       4 unless $sig = $param{Signature};
94 1         3 my $u2 = mod_inverse($sig->s, $key->q);
95 1         9175 my $u1 = bin2mp($dgst);
96 1         716 $u1 = ($u1 * $u2) % $key->q;
97 1         348 $u2 = ($sig->r * $u2) % $key->q;
98 1         313 my $t1 = mod_exp($key->g, $u1, $key->p);
99 1         1332244 my $t2 = mod_exp($key->pub_key, $u2, $key->p);
100 1         1418861 $u1 = ($t1 * $t2) % $key->p;
101 1         3719 $u1 %= $key->q;
102 1         909 $u1 == $sig->r;
103             }
104              
105             1;
106              
107             __END__