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   803465 use 5.006;
  7         19  
4 7     7   53 use strict;
  7         32  
  7         187  
5 7     7   22 use warnings;
  7         14  
  7         309  
6 7     7   3150 use Digest::SHA qw( sha1 );
  7         19048  
  7         602  
7 7     7   42 use Carp qw( croak );
  7         10  
  7         295  
8 7     7   2914 use Crypt::DSA::KeyChain;
  7         20  
  7         211  
9 7     7   33 use Crypt::DSA::Key;
  7         8  
  7         94  
10 7     7   2617 use Crypt::DSA::Signature;
  7         15  
  7         223  
11 7     7   30 use Crypt::DSA::Util qw( bitsize bin2mp mod_inverse mod_exp makerandom randombelow );
  7         10  
  7         421  
12              
13             our $VERSION = '1.23'; #VERSION
14              
15 7     7   29 use vars qw( $VERSION );
  7         7  
  7         4086  
16              
17             sub new {
18 2     2 1 272953 my $class = shift;
19 2         5 my $dsa = bless { @_ }, $class;
20 2         16 $dsa->{_keychain} = Crypt::DSA::KeyChain->new(@_);
21 2         5 $dsa;
22             }
23              
24             sub keygen {
25 1     1 1 4 my $dsa = shift;
26 1         5 my $key = $dsa->{_keychain}->generate_params(@_);
27 1         12 $dsa->{_keychain}->generate_keys($key);
28 1         23 $key;
29             }
30              
31             sub sign {
32 1     1 1 11 my $dsa = shift;
33 1         19 my %param = @_;
34 1         2 my($key, $dgst);
35 1 50       6 croak __PACKAGE__, "->sign: Need a Key" unless $key = $param{Key};
36 1 50       3 unless ($dgst = $param{Digest}) {
37             croak __PACKAGE__, "->sign: Need either Message or Digest"
38 1 50       23 unless $param{Message};
39 1         19 $dgst = sha1($param{Message});
40             }
41 1         3 my $dlen = length $dgst;
42              
43 1         4 my $i = bitsize($key->q) / 8;
44 1 50 33     495 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         17 $dsa->_sign_setup($key);
52              
53 1         4 my $m = bin2mp($dgst);
54 1         567 my $xr = ($key->priv_key * $key->r) % $key->q;
55 1         320 my $s = $xr + $m;
56 1 50       104 $s -= $key->q if $s > $key->q;
57 1         50 $s = ($s * $key->kinv) % $key->q;
58              
59 1         344 my $sig = Crypt::DSA::Signature->new;
60 1         16 $sig->r($key->r);
61 1         4 $sig->s($s);
62 1         8 $sig;
63             }
64              
65             sub _sign_setup {
66 1     1   3 my $dsa = shift;
67 1         1 my $key = shift;
68 1         1 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         2 $k = randombelow($key->q);
  1         9  
73 1 50       194 redo if $k == 0;
74             }
75 1         164 $r = mod_exp($key->g, $k, $key->p);
76 1         397052 $r %= $key->q;
77 1         487 my $kinv = mod_inverse($k, $key->q);
78 1         7901 $key->r($r);
79 1         4 $key->kinv($kinv);
80             }
81              
82             sub verify {
83 1     1 1 2 my $dsa = shift;
84 1         5 my %param = @_;
85 1         2 my($key, $dgst, $sig);
86 1 50       4 croak __PACKAGE__, "->verify: Need a Key" unless $key = $param{Key};
87 1 50       5 unless ($dgst = $param{Digest}) {
88             croak __PACKAGE__, "->verify: Need either Message or Digest"
89 1 50       2 unless $param{Message};
90 1         9 $dgst = sha1($param{Message});
91             }
92             croak __PACKAGE__, "->verify: Need a Signature"
93 1 50       3 unless $sig = $param{Signature};
94 1         3 my $u2 = mod_inverse($sig->s, $key->q);
95 1         9059 my $u1 = bin2mp($dgst);
96 1         707 $u1 = ($u1 * $u2) % $key->q;
97 1         337 $u2 = ($sig->r * $u2) % $key->q;
98 1         313 my $t1 = mod_exp($key->g, $u1, $key->p);
99 1         1350599 my $t2 = mod_exp($key->pub_key, $u2, $key->p);
100 1         1318819 $u1 = ($t1 * $t2) % $key->p;
101 1         3567 $u1 %= $key->q;
102 1         908 $u1 == $sig->r;
103             }
104              
105             1;
106              
107             __END__