File Coverage

blib/lib/Crypt/OpenPGP/Cipher.pm
Criterion Covered Total %
statement 191 198 96.4
branch 9 18 50.0
condition 1 3 33.3
subroutine 77 78 98.7
pod 5 8 62.5
total 283 305 92.7


line stmt bran cond sub pod time code
1             package Crypt::OpenPGP::Cipher;
2 8     8   22957 use strict;
  8         18  
  8         246  
3              
4 8     8   2969 use Crypt::OpenPGP::CFB;
  8         17  
  8         231  
5 8     8   511 use Crypt::OpenPGP::ErrorHandler;
  8         13  
  8         246  
6 8     8   46 use base qw( Crypt::OpenPGP::ErrorHandler );
  8         14  
  8         638  
7              
8 8     8   47 use vars qw( %ALG %ALG_BY_NAME );
  8         12  
  8         4329  
9             %ALG = (
10             1 => 'IDEA',
11             2 => 'DES3',
12             3 => 'CAST5',
13             4 => 'Blowfish',
14             7 => 'Rijndael',
15             8 => 'Rijndael192',
16             9 => 'Rijndael256',
17             10 => 'Twofish',
18             );
19             %ALG_BY_NAME = map { $ALG{$_} => $_ } keys %ALG;
20              
21             sub new {
22 128     128 1 5757 my $class = shift;
23 128         171 my $alg = shift;
24 128   33     462 $alg = $ALG{$alg} || $alg;
25 128 50       678 return $class->error("Unsupported cipher algorithm '$alg'")
26             unless $alg =~ /^\D/;
27 128         340 my $pkg = join '::', $class, $alg;
28             my $ciph = bless { __alg => $alg,
29 128         688 __alg_id => $ALG_BY_NAME{$alg} }, $pkg;
30 128         391 my $impl_class = $ciph->crypt_class;
31 128 50       497 my @classes = ref($impl_class) eq 'ARRAY' ? @$impl_class : ($impl_class);
32 128         260 for my $c (@classes) {
33 7     7   4074 eval "use $c;";
  7     6   8497  
  7     4   238  
  6     4   581  
  6     4   1091  
  6     4   154  
  4     4   1082  
  4     4   4218  
  4     4   74  
  4     4   26  
  4     4   6  
  4     4   56  
  4     4   23  
  4     4   6  
  4     3   60  
  4     3   378  
  4     3   700  
  4     3   104  
  4     3   423  
  4     3   554  
  4     3   94  
  4     3   365  
  4     3   1167  
  4     3   69  
  4         26  
  4         8  
  4         68  
  4         26  
  4         8  
  4         68  
  4         19  
  4         7  
  4         76  
  4         26  
  4         5  
  4         63  
  4         30  
  4         8  
  4         71  
  4         26  
  4         121  
  4         65  
  3         22  
  3         4  
  3         46  
  3         15  
  3         4  
  3         40  
  3         21  
  3         6  
  3         51  
  3         17  
  3         6  
  3         46  
  3         16  
  3         4  
  3         77  
  3         18  
  3         5  
  3         56  
  3         15  
  3         6  
  3         61  
  3         22  
  3         4  
  3         68  
  3         17  
  3         3  
  3         41  
  3         15  
  3         4  
  3         38  
  128         11679  
34 128 50       770 $ciph->{__impl} = $c, last unless $@;
35             }
36             return $class->error("Error loading cipher implementation for " .
37             "'$alg': no implementations installed.")
38 128 50       342 unless $ciph->{__impl};
39 128         585 $ciph->init(@_);
40             }
41              
42             sub init {
43 146     146 0 232 my $ciph = shift;
44 146         245 my($key, $iv) = @_;
45 146 100       333 if ($key) {
46 81         182 my $class = $ciph->{__impl};
47             ## Make temp variable, because Rijndael checks SvPOK, which
48             ## doesn't seem to like a value that isn't a variable?
49 81         251 my $tmp = substr $key, 0, $ciph->keysize;
50 81         450 my $c = $class->new($tmp);
51 81         9114 $ciph->{cipher} = Crypt::OpenPGP::CFB->new($c, $iv);
52             }
53 146         660 $ciph;
54             }
55              
56 68     68 1 7319 sub encrypt { $_[0]->{cipher}->encrypt($_[1]) }
57 70     70 1 275 sub decrypt { $_[0]->{cipher}->decrypt($_[1]) }
58              
59 44     44 0 153 sub sync { $_[0]->{cipher}->sync }
60              
61 8     8 1 3946 sub alg { $_[0]->{__alg} }
62             sub alg_id {
63 30 50   30 1 151 return $_[0]->{__alg_id} if ref($_[0]);
64 0 0       0 $ALG_BY_NAME{$_[1]} || $_[1];
65             }
66             sub supported {
67 0     0 0 0 my $class = shift;
68 0         0 my %s;
69 0         0 for my $cid (keys %ALG) {
70 0         0 my $cipher = $class->new($cid);
71 0 0       0 $s{$cid} = $cipher->alg if $cipher;
72             }
73 0         0 \%s;
74             }
75              
76             package Crypt::OpenPGP::Cipher::IDEA;
77 8     8   53 use strict;
  8         32  
  8         227  
78 8     8   42 use base qw( Crypt::OpenPGP::Cipher );
  8         129  
  8         1341  
79              
80             sub init {
81 3     3   5 my $ciph = shift;
82 3         6 my($key, $iv) = @_;
83 3 100       8 if ($key) {
84 2         8 my $c = IDEA->new(substr($key, 0, $ciph->keysize));
85 2         42 $ciph->{cipher} = Crypt::OpenPGP::CFB->new($c, $iv);
86             }
87 3         8 $ciph;
88             }
89              
90 3     3   4 sub crypt_class { 'Crypt::IDEA' }
91 2     2   13 sub keysize { 16 }
92 1     1   5 sub blocksize { 8 }
93              
94             package Crypt::OpenPGP::Cipher::Blowfish;
95 8     8   45 use strict;
  8         10  
  8         214  
96 8     8   44 use base qw( Crypt::OpenPGP::Cipher );
  8         14  
  8         780  
97              
98 11     11   27 sub crypt_class { 'Crypt::Blowfish' }
99 18     18   98 sub keysize { 16 }
100 1     1   5 sub blocksize { 8 }
101              
102             package Crypt::OpenPGP::Cipher::DES3;
103 8     8   46 use strict;
  8         17  
  8         213  
104 8     8   47 use base qw( Crypt::OpenPGP::Cipher );
  8         18  
  8         764  
105              
106 99     99   175 sub crypt_class { 'Crypt::DES_EDE3' }
107 111     111   264 sub keysize { 24 }
108 47     47   97 sub blocksize { 8 }
109              
110             package Crypt::OpenPGP::Cipher::CAST5;
111 8     8   59 use strict;
  8         10  
  8         201  
112 8     8   41 use base qw( Crypt::OpenPGP::Cipher );
  8         12  
  8         791  
113              
114 3     3   5 sub crypt_class { 'Crypt::CAST5_PP' }
115 2     2   7 sub keysize { 16 }
116 1     1   6 sub blocksize { 8 }
117              
118             package Crypt::OpenPGP::Cipher::Twofish;
119 8     8   51 use strict;
  8         15  
  8         243  
120 8     8   44 use base qw( Crypt::OpenPGP::Cipher );
  8         15  
  8         779  
121              
122 3     3   5 sub crypt_class { 'Crypt::Twofish' }
123 2     2   3 sub keysize { 32 }
124 1     1   4 sub blocksize { 16 }
125              
126             package Crypt::OpenPGP::Cipher::Rijndael;
127 8     8   49 use strict;
  8         19  
  8         203  
128 7     7   35 use base qw( Crypt::OpenPGP::Cipher );
  7         10  
  7         757  
129              
130 3     3   5 sub crypt_class { 'Crypt::Rijndael' }
131 2     2   6 sub keysize { 16 }
132 1     1   6 sub blocksize { 16 }
133              
134             package Crypt::OpenPGP::Cipher::Rijndael192;
135 7     7   42 use strict;
  7         16  
  7         228  
136 7     7   89 use base qw( Crypt::OpenPGP::Cipher );
  7         14  
  7         859  
137              
138 3     3   6 sub crypt_class { 'Crypt::Rijndael' }
139 2     2   6 sub keysize { 24 }
140 1     1   7 sub blocksize { 16 }
141              
142             package Crypt::OpenPGP::Cipher::Rijndael256;
143 7     7   47 use strict;
  7         12  
  7         214  
144 7     7   36 use base qw( Crypt::OpenPGP::Cipher );
  7         8  
  7         739  
145              
146 3     3   5 sub crypt_class { 'Crypt::Rijndael' }
147 2     2   3 sub keysize { 32 }
148 1     1   6 sub blocksize { 16 }
149              
150             1;
151             __END__
152              
153             =head1 NAME
154              
155             Crypt::OpenPGP::Cipher - PGP symmetric cipher factory
156              
157             =head1 SYNOPSIS
158              
159             use Crypt::OpenPGP::Cipher;
160              
161             my $alg = 'Rijndael';
162             my $cipher = Crypt::OpenPGP::Cipher->new( $alg );
163              
164             my $plaintext = 'foo bar';
165             my $ct = $cipher->encrypt($plaintext);
166             my $pt = $cipher->decrypt($ct);
167              
168             =head1 DESCRIPTION
169              
170             I<Crypt::OpenPGP::Cipher> is a factory class for PGP symmetric ciphers.
171             All cipher objects are subclasses of this class and share a common
172             interface; when creating a new cipher object, the object is blessed
173             into the subclass to take on algorithm-specific functionality.
174              
175             A I<Crypt::OpenPGP::Cipher> object is a wrapper around a
176             I<Crypt::OpenPGP::CFB> object, which in turn wraps around the actual
177             cipher implementation (eg. I<Crypt::Blowfish> for a Blowfish cipher).
178             This allows all ciphers to share a common interface and a simple
179             instantiation method.
180              
181             =head1 USAGE
182              
183             =head2 Crypt::OpenPGP::Cipher->new($cipher)
184              
185             Creates a new symmetric cipher object of type I<$cipher>; I<$cipher>
186             can be either the name of a cipher (in I<Crypt::OpenPGP> parlance) or
187             the numeric ID of the cipher (as defined in the OpenPGP RFC). Using
188             a cipher name is recommended, for the simple reason that it is easier
189             to understand quickly (not everyone knows the cipher IDs).
190              
191             Valid cipher names are: C<IDEA>, C<DES3>, C<Blowfish>, C<Rijndael>,
192             C<Rijndael192>, C<Rijndael256>, C<Twofish>, and C<CAST5>.
193              
194             Returns the new cipher object on success. On failure returns C<undef>;
195             the caller should check for failure and call the class method I<errstr>
196             if a failure occurs. A typical reason this might happen is an
197             unsupported cipher name or ID.
198              
199             =head2 $cipher->encrypt($plaintext)
200              
201             Encrypts the plaintext I<$plaintext> and returns the encrypted text
202             (ie. ciphertext). The encryption is done in CFB mode using the
203             underlying cipher implementation.
204              
205             =head2 $cipher->decrypt($ciphertext)
206              
207             Decrypts the ciphertext I<$ciphertext> and returns the plaintext. The
208             decryption is done in CFB mode using the underlying cipher
209             implementation.
210              
211             =head2 $cipher->alg
212              
213             Returns the name of the cipher algorithm (as listed above in I<new>).
214              
215             =head2 $cipher->alg_id
216              
217             Returns the numeric ID of the cipher algorithm.
218              
219             =head2 $cipher->blocksize
220              
221             Returns the blocksize of the cipher algorithm (in bytes).
222              
223             =head2 $cipher->keysize
224              
225             Returns the keysize of the cipher algorithm (in bytes).
226              
227             =head1 AUTHOR & COPYRIGHTS
228              
229             Please see the Crypt::OpenPGP manpage for author, copyright, and
230             license information.
231              
232             =cut