File Coverage

blib/lib/Crypt/DSA.pm
Criterion Covered Total %
statement 86 86 100.0
branch 13 22 59.0
condition 1 3 33.3
subroutine 15 15 100.0
pod 4 4 100.0
total 119 130 91.5


line stmt bran cond sub pod time code
1             package Crypt::DSA;
2              
3 6     6   768086 use 5.006;
  6         21  
4 6     6   46 use strict;
  6         38  
  6         137  
5 6     6   48 use warnings;
  6         14  
  6         343  
6 6     6   4337 use Digest::SHA qw( sha1 );
  6         18295  
  6         601  
7 6     6   64 use Carp qw( croak );
  6         11  
  6         249  
8 6     6   2532 use Crypt::DSA::KeyChain;
  6         17  
  6         203  
9 6     6   29 use Crypt::DSA::Key;
  6         11  
  6         96  
10 6     6   2324 use Crypt::DSA::Signature;
  6         15  
  6         242  
11 6     6   32 use Crypt::DSA::Util qw( bitsize bin2mp mod_inverse mod_exp makerandom );
  6         8  
  6         381  
12              
13             our $VERSION = '1.21'; #VERSION
14              
15 6     6   23 use vars qw( $VERSION );
  6         8  
  6         3602  
16              
17             sub new {
18 3     3 1 488484 my $class = shift;
19 3         9 my $dsa = bless { @_ }, $class;
20 3         24 $dsa->{_keychain} = Crypt::DSA::KeyChain->new(@_);
21 3         7 $dsa;
22             }
23              
24             sub keygen {
25 2     2 1 559 my $dsa = shift;
26 2         10 my $key = $dsa->{_keychain}->generate_params(@_);
27 2         52 $dsa->{_keychain}->generate_keys($key);
28 2         1587 $key;
29             }
30              
31             sub sign {
32 3     3 1 87 my $dsa = shift;
33 3         40 my %param = @_;
34 3         6 my($key, $dgst);
35 3 50       18 croak __PACKAGE__, "->sign: Need a Key" unless $key = $param{Key};
36 3 50       26 unless ($dgst = $param{Digest}) {
37             croak __PACKAGE__, "->sign: Need either Message or Digest"
38 3 50       19 unless $param{Message};
39 3         40 $dgst = sha1($param{Message});
40             }
41 3         5 my $dlen = length $dgst;
42              
43 3         11 my $i = bitsize($key->q) / 8;
44 3 50 33     1393 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 3         23 $dsa->_sign_setup($key);
52              
53 3         31 my $m = bin2mp($dgst);
54 3         2149 my $xr = ($key->priv_key * $key->r) % $key->q;
55 3         1079 my $s = $xr + $m;
56 3 100       307 $s -= $key->q if $s > $key->q;
57 3         296 $s = ($s * $key->kinv) % $key->q;
58              
59 3         1045 my $sig = Crypt::DSA::Signature->new;
60 3         38 $sig->r($key->r);
61 3         24 $sig->s($s);
62 3         31 $sig;
63             }
64              
65             sub _sign_setup {
66 3     3   11 my $dsa = shift;
67 3         4 my $key = shift;
68 3         5 my($k, $r);
69             {
70 3         10 $k = makerandom(Size => bitsize($key->q));
  3         7  
71 3 100       1615 $k -= $key->q if $k >= $key->q;
72 3 50       316 redo if $k == 0;
73             }
74 3         506 $r = mod_exp($key->g, $k, $key->p);
75 3         1313467 $r %= $key->q;
76 3         1623 my $kinv = mod_inverse($k, $key->q);
77 3         28703 $key->r($r);
78 3         19 $key->kinv($kinv);
79             }
80              
81             sub verify {
82 1     1 1 1 my $dsa = shift;
83 1         5 my %param = @_;
84 1         1 my($key, $dgst, $sig);
85 1 50       4 croak __PACKAGE__, "->verify: Need a Key" unless $key = $param{Key};
86 1 50       5 unless ($dgst = $param{Digest}) {
87             croak __PACKAGE__, "->verify: Need either Message or Digest"
88 1 50       3 unless $param{Message};
89 1         7 $dgst = sha1($param{Message});
90             }
91             croak __PACKAGE__, "->verify: Need a Signature"
92 1 50       4 unless $sig = $param{Signature};
93 1         3 my $u2 = mod_inverse($sig->s, $key->q);
94 1         9130 my $u1 = bin2mp($dgst);
95 1         709 $u1 = ($u1 * $u2) % $key->q;
96 1         319 $u2 = ($sig->r * $u2) % $key->q;
97 1         308 my $t1 = mod_exp($key->g, $u1, $key->p);
98 1         1351107 my $t2 = mod_exp($key->pub_key, $u2, $key->p);
99 1         1495680 $u1 = ($t1 * $t2) % $key->p;
100 1         3567 $u1 %= $key->q;
101 1         932 $u1 == $sig->r;
102             }
103              
104             1;
105              
106             __END__