File Coverage

blib/lib/Crypt/DSA/GMP.pm
Criterion Covered Total %
statement 21 23 91.3
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 29 31 93.5


line stmt bran cond sub pod time code
1             package Crypt::DSA::GMP;
2 6     6   156516 use 5.006;
  6         25  
  6         264  
3 6     6   45 use strict;
  6         12  
  6         229  
4 6     6   41 use warnings;
  6         13  
  6         360  
5              
6             BEGIN {
7 6     6   13 $Crypt::DSA::GMP::AUTHORITY = 'cpan:DANAJ';
8 6         202 $Crypt::DSA::GMP::VERSION = '0.02';
9             }
10              
11 6     6   40 use Carp qw( croak );
  6         22  
  6         525  
12 6     6   18702 use Math::BigInt lib => "GMP";
  6         280041  
  6         43  
13 6     6   154349 use Digest::SHA qw( sha1 sha256 sha512 );
  6         37501  
  6         767  
14 6     6   11356 use Crypt::DSA::GMP::KeyChain;
  0            
  0            
15             use Crypt::DSA::GMP::Key;
16             use Crypt::DSA::GMP::Signature;
17             use Crypt::DSA::GMP::Util qw( bitsize bin2mp mod_inverse mod_exp makerandomrange );
18              
19             sub new {
20             my $class = shift;
21             my $dsa = bless { @_ }, $class;
22             $dsa->{_keychain} = Crypt::DSA::GMP::KeyChain->new(@_);
23             $dsa;
24             }
25              
26             sub keygen {
27             my ($dsa, %params) = @_;
28             my $key = $dsa->{_keychain}->generate_params(%params);
29             my $nonblock = $params{NonBlockingKeyGeneration};
30             $dsa->{_keychain}->generate_keys($key, $nonblock);
31             croak "Invalid key" unless $key->validate();
32             $key;
33             }
34             sub keyset {
35             my ($dsa, %param) = @_;
36             my $key = Crypt::DSA::GMP::Key->new;
37             croak "Key missing p" unless defined $param{p}; $key->p($param{p});
38             croak "Key missing q" unless defined $param{q}; $key->q($param{q});
39             croak "Key missing g" unless defined $param{g}; $key->g($param{g});
40             $key->priv_key($param{priv_key}) if defined $param{priv_key};
41             $key->priv_key($param{x} ) if defined $param{x};
42             $key->pub_key($param{pub_key}) if defined $param{pub_key};
43             $key->pub_key($param{y} ) if defined $param{y};
44             $key->pub_key(mod_exp($key->g, $key->priv_key, $key->p))
45             if !defined $key->pub_key && defined $key->priv_key;
46             croak "Key missing both private and public keys"
47             unless defined $key->pub_key || defined $key->priv_key;
48             croak "Invalid key" unless $key->validate();
49             $key;
50             }
51              
52             sub sign {
53             my ($dsa, %param) = @_;
54             my ($key, $dgst) = ($param{Key}, $param{Digest});
55              
56             croak __PACKAGE__, "->sign: Need a Key" unless defined $key && ref($key);
57             croak __PACKAGE__, "->sign: Invalid key" unless $key->validate();
58             my ($p, $q, $g) = ($key->p, $key->q, $key->g);
59             my $N = bitsize($q);
60              
61             if (!defined $dgst) {
62             my $message = $param{Message};
63             croak __PACKAGE__, "->sign: Need either Message or Digest"
64             unless defined $message;
65             # Determine which standard we're following.
66             $param{Standard} = $dsa->{Standard}
67             if defined $dsa->{Standard} && !defined $param{Standard};
68             if (defined $param{Standard} && $param{Standard} =~ /186-[34]/) {
69             # See NIST SP 800-57 revision 3, section 5.6.1
70             $dgst = ($N > 256) ? sha512($message) : sha256($message);
71             } else {
72             $dgst = sha1($message);
73             }
74             }
75              
76             # FIPS 186-4, section 4.6 "DSA Signature Generation"
77              
78             # compute z as the leftmost MIN(N, outlen) bits of the digest
79             my $z = bin2mp($dgst);
80             $z->brsft(8*length($dgst) - $N) if $N < 8*length($dgst);
81              
82             # Generate r and s, ensuring neither are zero.
83             my ($r, $s);
84             do {
85             my ($k, $kinv);
86             do {
87             # Using FIPS 186-4 B.2.2 approved method
88             # k is per-message random number 0 < k < q
89             $k = makerandomrange( Max => $q-2 ) + 1;
90             $r = mod_exp($g, $k, $p)->bmod($q);
91             } while $r == 0;
92             $kinv = mod_inverse($k, $q);
93             $s = ($kinv * ($z + $key->priv_key * $r)) % $q;
94             } while $s == 0;
95             croak "Internal error in signing" if $r == 0 || $s == 0;
96              
97             my $sig = Crypt::DSA::GMP::Signature->new;
98             $sig->r($r);
99             $sig->s($s);
100             $sig;
101             }
102              
103             sub verify {
104             my ($dsa, %param) = @_;
105             my ($key, $dgst, $sig) = ($param{Key}, $param{Digest}, $param{Signature});
106              
107             croak __PACKAGE__, "->verify: Need a Key"
108             unless defined $key && ref($key);
109             croak __PACKAGE__, "->verify: Need a Signature"
110             unless defined $sig && ref($sig);
111             croak __PACKAGE__, "->verify: Invalid key" unless $key->validate();
112             my ($p, $q, $g, $r, $s) = ($key->p, $key->q, $key->g, $sig->r, $sig->s);
113             return 0 unless $r > 0 && $r < $q && $s > 0 && $s < $q;
114             my $N = bitsize($q);
115              
116             if (!defined $dgst) {
117             my $message = $param{Message};
118             croak __PACKAGE__, "->verify: Need either Message or Digest"
119             unless defined $message;
120             # Determine which standard we're following.
121             $param{Standard} = $dsa->{Standard}
122             if defined $dsa->{Standard} && !defined $param{Standard};
123             if (defined $param{Standard} && $param{Standard} =~ /186-[34]/) {
124             # See NIST SP 800-57 revision 3, section 5.6.1
125             $dgst = ($N > 256) ? sha512($message) : sha256($message);
126             } else {
127             $dgst = sha1($message);
128             }
129             }
130              
131             my $w = mod_inverse($s, $q);
132             my $z = bin2mp($dgst);
133             $z->brsft(8*length($dgst) - $N) if $N < 8*length($dgst);
134             my $u1 = $w->copy->bmul($z)->bmod($q);
135             my $u2 = $w->copy->bmul($r)->bmod($q);
136             my $v = mod_exp($g, $u1, $p)
137             ->bmul(mod_exp($key->pub_key, $u2, $p))
138             ->bmod($p)
139             ->bmod($q);
140             $v == $r;
141             }
142              
143             1;
144              
145             __END__