File Coverage

blib/lib/Crypt/PK/DSA.pm
Criterion Covered Total %
statement 95 100 95.0
branch 57 84 67.8
condition 14 37 37.8
subroutine 16 17 94.1
pod 4 10 40.0
total 186 248 75.0


line stmt bran cond sub pod time code
1             package Crypt::PK::DSA;
2              
3 6     6   238661 use strict;
  6         12  
  6         234  
4 6     6   41 use warnings;
  6         11  
  6         920  
5             our $VERSION = '0.089';
6              
7             require Exporter; our @ISA = qw(Exporter); ### use Exporter 5.57 'import';
8             our %EXPORT_TAGS = ( all => [qw( dsa_encrypt dsa_decrypt dsa_sign_message dsa_verify_message dsa_sign_hash dsa_verify_hash )] );
9             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
10             our @EXPORT = qw();
11              
12 6     6   38 use Carp;
  6         8  
  6         500  
13             $Carp::Internal{(__PACKAGE__)}++;
14 6     6   1036 use CryptX;
  6         14  
  6         240  
15 6     6   1182 use Crypt::Misc qw(read_rawfile encode_b64 decode_b64 pem_to_der der_to_pem);
  6         17  
  6         511  
16 6     6   2016 use Crypt::PK;
  6         15  
  6         10685  
17              
18             sub new {
19 82     82 1 647301 my $self = shift->_new();
20 82 100       1290 return @_ > 0 ? $self->import_key(@_) : $self;
21             }
22              
23             sub generate_key {
24 8     8 1 2037 my $self = shift;
25 8 100       1470447 return $self->_generate_key_size(@_) if @_ == 2;
26 3 100 66     34 if (@_ == 1 && ref $_[0] eq 'HASH') {
    50 33        
27 1         4 my $param = shift;
28 1 50       5 my $p = $param->{p} or croak "FATAL: 'p' param not specified";
29 1 50       4 my $q = $param->{q} or croak "FATAL: 'q' param not specified";
30 1 50       3 my $g = $param->{g} or croak "FATAL: 'g' param not specified";
31 1         3 $p =~ s/^0x//;
32 1         3 $q =~ s/^0x//;
33 1         2 $g =~ s/^0x//;
34 1 50       3 croak "FATAL: 'p' param is empty after stripping '0x' prefix" unless length $p;
35 1 50       2 croak "FATAL: 'q' param is empty after stripping '0x' prefix" unless length $q;
36 1 50       3 croak "FATAL: 'g' param is empty after stripping '0x' prefix" unless length $g;
37 1         764 return $self->_generate_key_pqg_hex($p, $q, $g);
38             }
39             elsif (@_ == 1 && ref $_[0] eq 'SCALAR') {
40 2         2 my $data = ${$_[0]};
  2         5  
41 2 100       20 if ($data =~ /-----BEGIN DSA PARAMETERS-----\s*(.+)\s*-----END DSA PARAMETERS-----/s) {
42 1 50       5 $data = pem_to_der($data) or croak "FATAL: PEM/params decode failed";
43             }
44 2         7001 return $self->_generate_key_dsaparam($data);
45             }
46 0         0 croak "FATAL: DSA generate_key - invalid args";
47             }
48              
49             sub export_key_pem {
50 11     11 1 3071 my ($self, $type, $password, $cipher) = @_;
51             # public_x509 uses the same DER as public, just different PEM header
52 11 100 50     51 my $der_type = ($type || '') eq 'public_x509' ? 'public' : ($type || '');
      50        
53 11         577 my $key = $self->export_key_der($der_type);
54 11 50       26 return unless $key;
55 11 100       41 return der_to_pem($key, "DSA PRIVATE KEY", $password, $cipher) if $type eq 'private';
56 6 100       27 return der_to_pem($key, "DSA PUBLIC KEY") if $type eq 'public';
57 1 50       11 return der_to_pem($key, "PUBLIC KEY") if $type eq 'public_x509';
58             }
59              
60             sub import_key {
61 83     83 1 35918 my ($self, $key, $password) = @_;
62 83 50       261 croak "FATAL: undefined key" unless $key;
63              
64             # special case
65 83 100       276 if (ref($key) eq 'HASH') {
66 2 50 33     28 if ($key->{p} && $key->{q} && $key->{g} && $key->{y}) {
      33        
      33        
67             # hash exported via key2hash
68 2         18289 return $self->_import_hex($key->{p}, $key->{q}, $key->{g}, $key->{x}, $key->{y});
69             }
70             }
71              
72 81         186 my $data;
73 81 100       1238 if (ref($key) eq 'SCALAR') {
    50          
74 36         69 $data = $$key;
75             }
76             elsif (-f $key) {
77 45         269 $data = read_rawfile($key);
78             }
79             else {
80 0         0 croak "FATAL: non-existing file '$key'";
81             }
82 81 50       272 croak "FATAL: invalid key data" unless $data;
83              
84 81 100       900 if ($data =~ /-----BEGIN (DSA PRIVATE|DSA PUBLIC|PRIVATE|ENCRYPTED PRIVATE|PUBLIC) KEY-----(.+?)-----END (DSA PRIVATE|DSA PUBLIC|PRIVATE|ENCRYPTED PRIVATE|PUBLIC) KEY-----/s) {
    50          
    100          
    100          
    100          
85 20         50304 return $self->_import_pem($data, $password);
86             }
87             elsif ($data =~ /-----BEGIN CERTIFICATE-----(.+?)-----END CERTIFICATE-----/s) {
88 0         0 return $self->_import_pem($data, undef);
89             }
90             elsif ($data =~ /-----BEGIN OPENSSH PRIVATE KEY-----(.+?)-----END OPENSSH PRIVATE KEY-----/s) {
91 2         225976 return $self->_import_openssh($data, $password);
92             }
93             elsif ($data =~ /---- BEGIN SSH2 PUBLIC KEY ----(.+?)---- END SSH2 PUBLIC KEY ----/s) {
94 1         697 return $self->_import_openssh($data, undef);
95             }
96             elsif ($data =~ /ssh-dss\s+(\S+)/) {
97 1         13 $data = decode_b64("$1");
98 1         7 my ($typ, $p, $q, $g, $y) = Crypt::PK::_ssh_parse($data);
99 1 50 33     1597 return $self->_import_hex(unpack('H*',$p), unpack('H*',$q), unpack('H*',$g), undef, unpack('H*',$y)) if $typ && $p && $q && $g && $y && $typ eq 'ssh-dss';
      33        
      33        
      33        
      33        
100             }
101             else {
102 57   33     116 my $rv = eval { $self->_import($data) } || eval { $self->_import_pkcs8($data, $password) };
103 57 50       623 return $rv if $rv;
104             }
105 0         0 croak "FATAL: invalid or unsupported DSA key format";
106             }
107              
108             ### FUNCTIONS
109              
110             sub dsa_encrypt { # legacy/obsolete
111 2     2 0 996 my $key = shift;
112 2         15 local $SIG{__DIE__} = \&CryptX::_croak;
113 2 100       13 $key = __PACKAGE__->new($key) unless ref $key;
114 2 100       297 croak "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
115 1         6037 return $key->encrypt(@_);
116             }
117              
118             sub dsa_decrypt { # legacy/obsolete
119 1     1 0 437 my $key = shift;
120 1         8 local $SIG{__DIE__} = \&CryptX::_croak;
121 1 50       16 $key = __PACKAGE__->new($key) unless ref $key;
122 1 50       7 croak "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
123 1         3130 return $key->decrypt(@_);
124             }
125              
126             sub dsa_sign_message { # legacy/obsolete
127 1     1 0 427 my $key = shift;
128 1         8 local $SIG{__DIE__} = \&CryptX::_croak;
129 1 50       11 $key = __PACKAGE__->new($key) unless ref $key;
130 1 50       8 croak "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
131 1         3199 return $key->sign_message(@_);
132             }
133              
134             sub dsa_verify_message { # legacy/obsolete
135 1     1 0 440 my $key = shift;
136 1         6 local $SIG{__DIE__} = \&CryptX::_croak;
137 1 50       12 $key = __PACKAGE__->new($key) unless ref $key;
138 1 50       13 croak "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
139 1         6103 return $key->verify_message(@_);
140             }
141              
142             sub dsa_sign_hash { # legacy/obsolete
143 1     1 0 478 my $key = shift;
144 1         7 local $SIG{__DIE__} = \&CryptX::_croak;
145 1 50       12 $key = __PACKAGE__->new($key) unless ref $key;
146 1 50       8 croak "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
147 1         3257 return $key->sign_hash(@_);
148             }
149              
150             sub dsa_verify_hash { # legacy/obsolete
151 1     1 0 438 my $key = shift;
152 1         8 local $SIG{__DIE__} = \&CryptX::_croak;
153 1 50       10 $key = __PACKAGE__->new($key) unless ref $key;
154 1 50       8 croak "FATAL: invalid 'key' param" unless ref($key) eq __PACKAGE__;
155 1         6955 return $key->verify_hash(@_);
156             }
157              
158 0     0     sub CLONE_SKIP { 1 } # prevent cloning
159              
160             1;
161              
162             =pod
163              
164             =head1 NAME
165              
166             Crypt::PK::DSA - Public key cryptography based on DSA
167              
168             =head1 SYNOPSIS
169              
170             ### OO interface
171              
172             my $message = 'hello world';
173             my $signer = Crypt::PK::DSA->new();
174             $signer->generate_key(30, 256);
175              
176             my $signature = $signer->sign_message($message);
177             my $public_der = $signer->export_key_der('public');
178             my $verifier = Crypt::PK::DSA->new(\$public_der);
179             $verifier->verify_message($signature, $message) or die "ERROR";
180              
181             my $ciphertext = $verifier->encrypt("secret message");
182             my $plaintext = $signer->decrypt($ciphertext);
183              
184             my $private_der = $signer->export_key_der('private');
185             my $private_pem = $signer->export_key_pem('private');
186             my $public_pem = $verifier->export_key_pem('public');
187              
188             =head1 DESCRIPTION
189              
190             DSA is primarily a digital signature scheme. In this module, signing and
191             verification are the most common operations and therefore the primary examples.
192              
193             Legacy function-style wrappers still exist in code for backwards compatibility,
194             but they are intentionally undocumented.
195              
196             =head1 METHODS
197              
198             =head2 new
199              
200             my $source = Crypt::PK::DSA->new();
201             $source->generate_key(20, 128);
202              
203             my $public_der = $source->export_key_der('public');
204             my $pub = Crypt::PK::DSA->new(\$public_der);
205              
206             my $private_pem = $source->export_key_pem('private', 'secret', 'AES-256-CBC');
207             my $priv = Crypt::PK::DSA->new(\$private_pem, 'secret');
208              
209             Passing C<$filename> or C<\$buffer> to C is equivalent: both forms
210             immediately import the key material into the new object.
211              
212             =head2 generate_key
213              
214             Uses the bundled C PRNG via libtomcrypt's C.
215             Returns the object itself (for chaining).
216              
217             $pk->generate_key($group_size, $modulus_size);
218             # $group_size ... [integer] size of the subgroup (q) in bytes; must satisfy: 15 < $group_size < 1024
219             # $modulus_size .. [integer] size of the prime (p) in bytes; must satisfy: ($modulus_size - $group_size) < 512
220             # $modulus_size must be >= $group_size
221             #
222             # The two-integer form uses Perl's usual numeric-to-integer coercion before
223             # the XS call. Callers should therefore pass exact integers; values like
224             # C<10.9> or C<"1e1"> will be coerced according to Perl's integer conversion.
225              
226             ### Common parameter pairs (group_size, modulus_size) => security level:
227             # generate_key(20, 128) => 80-bit security (1024-bit p, 160-bit q)
228             # generate_key(30, 256) => 120-bit security (2048-bit p, 240-bit q)
229             # generate_key(32, 256) => 128-bit security (2048-bit p, 256-bit q)
230             # generate_key(35, 384) => ~140-bit security (3072-bit p, 280-bit q)
231             # 140 bits => generate_key(35, 384)
232             # 160 bits => generate_key(40, 512)
233              
234             ### Sizes according section 4.2 of FIPS 186-4
235             # (L and N are the bit lengths of p and q respectively)
236             # L = 1024, N = 160 => generate_key(20, 128)
237             # L = 2048, N = 224 => generate_key(28, 256)
238             # L = 2048, N = 256 => generate_key(32, 256)
239             # L = 3072, N = 256 => generate_key(32, 384)
240              
241             $pk->generate_key($param_hash)
242             # $param_hash is { p => $p, q => $q, g => $g }
243             # where $p, $q, $g are hex strings
244              
245             $pk->generate_key(\$dsa_param)
246             # $dsa_param is the content of DER or PEM file with DSA params
247             # e.g. openssl dsaparam 2048
248              
249             =head2 import_key
250              
251             Loads private or public key in DER or PEM format.
252              
253             my $source = Crypt::PK::DSA->new();
254             $source->generate_key(20, 128);
255              
256             my $public_der = $source->export_key_der('public');
257             my $pub = Crypt::PK::DSA->new();
258             $pub->import_key(\$public_der);
259              
260             my $private_pem = $source->export_key_pem('private', 'secret', 'AES-256-CBC');
261             my $priv = Crypt::PK::DSA->new();
262             $priv->import_key(\$private_pem, 'secret');
263              
264             The same method also accepts filenames instead of buffers.
265              
266             Loading private or public keys from a Perl HASH:
267              
268             $pk->import_key($hashref);
269              
270             # where $hashref is a key exported via key2hash
271             $pk->import_key({
272             p => "AAF839A764E04D80824B79FA1F0496C093...", #prime modulus
273             q => "D05C4CB45F29D353442F1FEC43A6BE2BE8...", #prime divisor
274             g => "847E8896D12C9BF18FE283AE7AD58ED7F3...", #generator of a subgroup of order q in GF(p)
275             x => "6C801901AC74E2DC714D75A9F6969483CF...", #private key, random 0 < x < q
276             y => "8F7604D77FA62C7539562458A63C7611B7...", #public key, where y = g^x mod p
277             });
278              
279             Supported key formats:
280              
281             =over
282              
283             =item * DSA public keys
284              
285             -----BEGIN PUBLIC KEY-----
286             MIIBtjCCASsGByqGSM44BAEwggEeAoGBAJKyu+puNMGLpGIhbD1IatnwlI79ePr4
287             YHe2KBhRkheKxWUZRpN1Vd/+usS2IHSJ9op5cSWETiP05d7PMtJaitklw7jhudq3
288             GxNvV/GRdCQm3H6d76FHP88dms4vcDYc6ry6wKERGfNEtZ+4BAKrMZK+gDYsF4Aw
289             U6WVR969kYZhAhUA6w25FgSRmJ8W4XkvC60n8Wv3DpMCgYA4ZFE+3tLOM24PZj9Z
290             rxuqUzZZdR+kIzrsIYpWN9ustbmdKLKwsqIaUIxc5zxHEhbAjAIf8toPD+VEQIpY
291             7vgJgDhXuPq45BgN19iLTzOJwIhAFXPZvnAdIo9D/AnMw688gT6g6U8QCZwX2XYg
292             ICiVcriYVNcjVKHSFY/X0Oi7CgOBhAACgYB4ZTn4OYT/pjUd6tNhGPtOS3CE1oaj
293             5ScbetXg4ZDpceEyQi8VG+/ZTbs8var8X77JdEdeQA686cAxpOaVgW8V4odvcmfA
294             BfueiGnPXjqGfppiHAyL1Ngyd+EsXKmKVXZYAVFVI0WuJKiZBSVURU7+ByxOfpGa
295             fZhibr0SggWixQ==
296             -----END PUBLIC KEY-----
297              
298             =item * DSA private keys
299              
300             -----BEGIN DSA PRIVATE KEY-----
301             MIIBuwIBAAKBgQCSsrvqbjTBi6RiIWw9SGrZ8JSO/Xj6+GB3tigYUZIXisVlGUaT
302             dVXf/rrEtiB0ifaKeXElhE4j9OXezzLSWorZJcO44bnatxsTb1fxkXQkJtx+ne+h
303             Rz/PHZrOL3A2HOq8usChERnzRLWfuAQCqzGSvoA2LBeAMFOllUfevZGGYQIVAOsN
304             uRYEkZifFuF5LwutJ/Fr9w6TAoGAOGRRPt7SzjNuD2Y/Wa8bqlM2WXUfpCM67CGK
305             VjfbrLW5nSiysLKiGlCMXOc8RxIWwIwCH/LaDw/lRECKWO74CYA4V7j6uOQYDdfY
306             i08zicCIQBVz2b5wHSKPQ/wJzMOvPIE+oOlPEAmcF9l2ICAolXK4mFTXI1Sh0hWP
307             19DouwoCgYB4ZTn4OYT/pjUd6tNhGPtOS3CE1oaj5ScbetXg4ZDpceEyQi8VG+/Z
308             Tbs8var8X77JdEdeQA686cAxpOaVgW8V4odvcmfABfueiGnPXjqGfppiHAyL1Ngy
309             d+EsXKmKVXZYAVFVI0WuJKiZBSVURU7+ByxOfpGafZhibr0SggWixQIVAL7Sia03
310             8bvANjjL9Sitk8slrM6P
311             -----END DSA PRIVATE KEY-----
312              
313             =item * DSA private keys in password protected PEM format:
314              
315             -----BEGIN DSA PRIVATE KEY-----
316             Proc-Type: 4,ENCRYPTED
317             DEK-Info: DES-CBC,227ADC3AA0299491
318              
319             UISxBYAxPQMl2eK9LMAeHsssF6IxO+4G2ta2Jn8VE+boJrrH3iSTKeMXGjGaXl0z
320             DwcLGV+KMR70y+cxtTb34rFy+uSpBy10dOQJhxALDbe1XfCDQIUfaXRfMNA3um2I
321             JdZixUD/zcxBOUzao+MCr0V9XlJDgqBhJ5EEr53XHH07Eo5fhiBfbbR9NzdUPFrQ
322             p2ASyZtFh7RXoIBUCQgg21oeLddcNWV7gd/Y46kghO9s0JbJ8C+IsuWEPRSq502h
323             tSoDN6B0sxbVvOUICLLbQaxt7yduTAhRxVIJZ1PWATTVD7CZBVz9uIDZ7LOv+er2
324             1q3vkwb8E9spPsA240+BnfD571XEop4jrawxC0VKQZ+3cPVLc6jhIsxvzzFQUt67
325             g66v8GUgt7KF3KhVV7qEtntybQWDWb+K/uTIH9Ra8nP820d3Rnl61pPXDPlluteT
326             WSLOvEMN2zRmkaxQNv/tLdT0SYpQtdjw74G3A6T7+KnvinKrjtp1a/AXkCF9hNEx
327             DGbxOYo1UOmk8qdxWCrab34nO+Q8oQc9wjXHG+ZtRYIMoGMKREK8DeL4H1RPNkMf
328             rwXWk8scd8QFmJAb8De1VQ==
329             -----END DSA PRIVATE KEY-----
330              
331             =item * SSH public DSA keys
332              
333             ssh-dss AAAAB3NzaC1kc3MAAACBAKU8/avmk...4XOwuEssAVhmwA==
334              
335             =item * SSH public DSA keys (RFC-4716 format)
336              
337             ---- BEGIN SSH2 PUBLIC KEY ----
338             Comment: "1024-bit DSA, converted from OpenSSH"
339             AAAAB3NzaC1kc3MAAACBAKU8/avmkFeGnSqwYG7dZnQlG+01QNaxu3F5v0NcL/SRUW7Idp
340             Uq8t14siK0mA6yjphLhOf5t8gugTEVBllP86ANSbFigH7WN3v6ydJWqm60pNhNHN//50cn
341             NtIsXbxeq3VtsI64pkH1OJqeZDHLmu73k4T0EKOzsylSfF/wtVBJAAAAFQChpubLHViwPB
342             +jSvUb8e4THS7PBQAAAIAJD1PMCiTCQa1xyD/NCWOajCufTOIzKAhm6l+nlBVPiKI+262X
343             pYt127Ke4mPL8XJBizoTjSQN08uHMg/8L6W/cdO2aZ+mhkBnS1xAm83DAwqLrDraR1w/4Q
344             RFxr5Vbyy8qnejrPjTJobBN1BGsv84wHkjmoCn6pFIfkGYeATlJgAAAIAHYPU1zMVBTDWr
345             u7SNC4G2UyWGWYYLjLytBVHfQmBa51CmqrSs2kCfGLGA1ynfYENsxcJq9nsXrb4i17H5BH
346             JFkH0g7BUDpeBeLr8gsK3WgfqWwtZsDkltObw9chUD/siK6q/dk/fSIB2Ho0inev7k68Z5
347             ZkNI4XOwuEssAVhmwA==
348             ---- END SSH2 PUBLIC KEY ----
349              
350             =back
351              
352             =head2 export_key_der
353              
354             Returns the key as a binary DER-encoded string.
355              
356             my $private_der = $pk->export_key_der('private');
357             #or
358             my $public_der = $pk->export_key_der('public');
359              
360             =head2 export_key_pem
361              
362             Returns the key as a PEM-encoded string (ASCII).
363              
364             my $private_pem = $pk->export_key_pem('private');
365             #or
366             my $public_pem = $pk->export_key_pem('public');
367             #or
368             my $public_pem = $pk->export_key_pem('public_x509');
369              
370             With parameter C<'public'> uses header and footer lines:
371              
372             -----BEGIN DSA PUBLIC KEY------
373             -----END DSA PUBLIC KEY------
374              
375             With parameter C<'public_x509'> uses header and footer lines:
376              
377             -----BEGIN PUBLIC KEY------
378             -----END PUBLIC KEY------
379              
380             Support for password protected PEM keys
381              
382             my $private_pem = $pk->export_key_pem('private', $password);
383             #or
384             my $private_pem = $pk->export_key_pem('private', $password, $cipher);
385              
386             # supported ciphers: 'DES-CBC'
387             # 'DES-EDE3-CBC'
388             # 'SEED-CBC'
389             # 'CAMELLIA-128-CBC'
390             # 'CAMELLIA-192-CBC'
391             # 'CAMELLIA-256-CBC'
392             # 'AES-128-CBC'
393             # 'AES-192-CBC'
394             # 'AES-256-CBC' (DEFAULT)
395              
396             =head2 encrypt
397              
398             Returns the ciphertext as a binary string.
399              
400             DSA is usually used for signatures. This helper is available because the
401             underlying library exposes a DSA-based encryption primitive.
402              
403             my $pk = Crypt::PK::DSA->new($pub_key_filename);
404             my $ct = $pk->encrypt($message);
405             #or
406             my $ct = $pk->encrypt($message, $hash_name);
407              
408             # $hash_name .. [string] 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
409              
410             =head2 decrypt
411              
412             Returns the plaintext as a binary string.
413              
414             my $pk = Crypt::PK::DSA->new($priv_key_filename);
415             my $pt = $pk->decrypt($ciphertext);
416              
417             =head2 sign_message
418              
419             Returns the signature as a binary string.
420              
421             my $pk = Crypt::PK::DSA->new($priv_key_filename);
422             my $signature = $pk->sign_message($message);
423             #or
424             my $signature = $pk->sign_message($message, $hash_name);
425              
426             # $hash_name .. [string] 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
427              
428             =head2 verify_message
429              
430             Returns C<1> if the signature is valid, C<0> otherwise.
431              
432             my $pk = Crypt::PK::DSA->new($pub_key_filename);
433             my $valid = $pk->verify_message($signature, $message);
434             #or
435             my $valid = $pk->verify_message($signature, $message, $hash_name);
436              
437             # $hash_name .. [string] 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest
438              
439             =head2 sign_hash
440              
441             Returns the signature as a binary string.
442              
443             my $pk = Crypt::PK::DSA->new($priv_key_filename);
444             my $signature = $pk->sign_hash($message_hash);
445              
446             =head2 verify_hash
447              
448             Returns C<1> if the signature is valid, C<0> otherwise.
449              
450             my $pk = Crypt::PK::DSA->new($pub_key_filename);
451             my $valid = $pk->verify_hash($signature, $message_hash);
452              
453             =head2 is_private
454              
455             my $rv = $pk->is_private;
456             # 1 .. private key loaded
457             # 0 .. public key loaded
458             # undef .. no key loaded
459              
460             =head2 size
461              
462             my $size = $pk->size;
463             # returns key size (length of the prime p) in bytes or undef if key not loaded
464              
465             =head2 size_q
466              
467             my $size = $pk->size_q;
468             # returns length of the prime q in bytes or undef if key not loaded
469              
470             =head2 key2hash
471              
472             Returns a hashref with the key components, or C if no key is loaded.
473              
474             my $hash = $pk->key2hash;
475              
476             # returns hash like this (or undef if no key loaded):
477             {
478             type => 1, # integer: 1 .. private, 0 .. public
479             size => 256, # integer: key size in bytes
480             # all the rest are hex strings
481             p => "AAF839A764E04D80824B79FA1F0496C093...", #prime modulus
482             q => "D05C4CB45F29D353442F1FEC43A6BE2BE8...", #prime divisor
483             g => "847E8896D12C9BF18FE283AE7AD58ED7F3...", #generator of a subgroup of order q in GF(p)
484             x => "6C801901AC74E2DC714D75A9F6969483CF...", #private key, random 0 < x < q
485             y => "8F7604D77FA62C7539562458A63C7611B7...", #public key, where y = g^x mod p
486             }
487              
488             =head1 OpenSSL interoperability
489              
490             ### let's have:
491             # DSA private key in PEM format - dsakey.priv.pem
492             # DSA public key in PEM format - dsakey.pub.pem
493             # data file to be signed - input.data
494              
495             =head2 Sign by OpenSSL, verify by Crypt::PK::DSA
496              
497             Create signature (from commandline):
498              
499             openssl dgst -sha1 -sign dsakey.priv.pem -out input.sha1-dsa.sig input.data
500              
501             Verify signature (Perl code):
502              
503             use Crypt::PK::DSA;
504             use Crypt::Digest 'digest_file';
505             use Crypt::Misc 'read_rawfile';
506              
507             my $pkdsa = Crypt::PK::DSA->new("dsakey.pub.pem");
508             my $signature = read_rawfile("input.sha1-dsa.sig");
509             my $valid = $pkdsa->verify_hash($signature, digest_file("SHA1", "input.data"));
510             print $valid ? "SUCCESS" : "FAILURE";
511              
512             =head2 Sign by Crypt::PK::DSA, verify by OpenSSL
513              
514             Create signature (Perl code):
515              
516             use Crypt::PK::DSA;
517             use Crypt::Digest 'digest_file';
518             use Crypt::Misc 'write_rawfile';
519              
520             my $pkdsa = Crypt::PK::DSA->new("dsakey.priv.pem");
521             my $signature = $pkdsa->sign_hash(digest_file("SHA1", "input.data"));
522             write_rawfile("input.sha1-dsa.sig", $signature);
523              
524             Verify signature (from commandline):
525              
526             openssl dgst -sha1 -verify dsakey.pub.pem -signature input.sha1-dsa.sig input.data
527              
528             =head2 Keys generated by Crypt::PK::DSA
529              
530             Generate keys (Perl code):
531              
532             use Crypt::PK::DSA;
533             use Crypt::Misc 'write_rawfile';
534              
535             my $pkdsa = Crypt::PK::DSA->new;
536             $pkdsa->generate_key(20, 128);
537             write_rawfile("dsakey.pub.der", $pkdsa->export_key_der('public'));
538             write_rawfile("dsakey.priv.der", $pkdsa->export_key_der('private'));
539             write_rawfile("dsakey.pub.pem", $pkdsa->export_key_pem('public_x509'));
540             write_rawfile("dsakey.priv.pem", $pkdsa->export_key_pem('private'));
541             write_rawfile("dsakey-passwd.priv.pem", $pkdsa->export_key_pem('private', 'secret'));
542              
543             Use keys by OpenSSL:
544              
545             openssl dsa -in dsakey.priv.der -text -inform der
546             openssl dsa -in dsakey.priv.pem -text
547             openssl dsa -in dsakey-passwd.priv.pem -text -inform pem -passin pass:secret
548             openssl dsa -in dsakey.pub.der -pubin -text -inform der
549             openssl dsa -in dsakey.pub.pem -pubin -text
550              
551             =head2 Keys generated by OpenSSL
552              
553             Generate keys:
554              
555             openssl dsaparam -genkey -out dsakey.priv.pem 1024
556             openssl dsa -in dsakey.priv.pem -out dsakey.priv.der -outform der
557             openssl dsa -in dsakey.priv.pem -out dsakey.pub.pem -pubout
558             openssl dsa -in dsakey.priv.pem -out dsakey.pub.der -outform der -pubout
559             openssl dsa -in dsakey.priv.pem -passout pass:secret -des3 -out dsakey-passwd.priv.pem
560              
561             Load keys (Perl code):
562              
563             use Crypt::PK::DSA;
564              
565             my $pkdsa = Crypt::PK::DSA->new;
566             $pkdsa->import_key("dsakey.pub.der");
567             $pkdsa->import_key("dsakey.priv.der");
568             $pkdsa->import_key("dsakey.pub.pem");
569             $pkdsa->import_key("dsakey.priv.pem");
570             $pkdsa->import_key("dsakey-passwd.priv.pem", "secret");
571              
572             =head1 SEE ALSO
573              
574             =over
575              
576             =item * L
577              
578             =back
579              
580             =cut