File Coverage

blib/lib/Crypt/OpenPGP/SKSessionKey.pm
Criterion Covered Total %
statement 59 63 93.6
branch 5 8 62.5
condition 4 9 44.4
subroutine 11 11 100.0
pod 4 5 80.0
total 83 96 86.4


line stmt bran cond sub pod time code
1             package Crypt::OpenPGP::SKSessionKey;
2 2     2   11 use strict;
  2         4  
  2         102  
3              
4 2     2   13 use Crypt::OpenPGP::Constants qw( DEFAULT_CIPHER );
  2         3  
  2         16  
5 2     2   11 use Crypt::OpenPGP::Buffer;
  2         3  
  2         51  
6 2     2   552 use Crypt::OpenPGP::S2k;
  2         3  
  2         58  
7 2     2   10 use Crypt::OpenPGP::ErrorHandler;
  2         3  
  2         50  
8 2     2   9 use base qw( Crypt::OpenPGP::ErrorHandler );
  2         3  
  2         1364  
9              
10             sub new {
11 23     23 1 37 my $class = shift;
12 23         62 my $key = bless { }, $class;
13 23         82 $key->init(@_);
14             }
15              
16             sub init {
17 23     23 0 35 my $key = shift;
18 23         74 my %param = @_;
19 23         77 $key->{version} = 4;
20 23 100 66     137 if ((my $sym_key = $param{SymKey}) && (my $pass = $param{Passphrase})) {
21 11   33     35 my $alg = $param{Cipher} || DEFAULT_CIPHER;
22 11         56 my $cipher = Crypt::OpenPGP::Cipher->new($alg);
23 11         37 my $keysize = $cipher->keysize;
24 11         56 $key->{s2k_ciph} = $cipher->alg_id;
25 11   33     42 $key->{s2k} = $param{S2k} || Crypt::OpenPGP::S2k->new('Salt_Iter');
26 11         42 $sym_key = substr $sym_key, 0, $keysize;
27 11         37 my $s2k_key = $key->{s2k}->generate($pass, $keysize);
28 11         67 $cipher->init($s2k_key);
29             }
30 23         113 $key;
31             }
32              
33             sub parse {
34 12     12 1 20 my $class = shift;
35 12         21 my($buf) = @_;
36 12         30 my $key = $class->new;
37 12         35 $key->{version} = $buf->get_int8;
38             return $class->error("Unsupported version ($key->{version})")
39 12 50       146 unless $key->{version} == 4;
40 12         30 $key->{s2k_ciph} = $buf->get_int8;
41 12         134 $key->{s2k} = Crypt::OpenPGP::S2k->parse($buf);
42 12 50       34 if ($buf->offset < $buf->length) {
43 0         0 $key->{encrypted} = $buf->get_bytes( $buf->length - $buf->offset );
44             }
45 12         76 $key;
46             }
47              
48             sub save {
49 11     11 1 20 my $key = shift;
50 11         57 my $buf = Crypt::OpenPGP::Buffer->new;
51 11         133 $buf->put_int8($key->{version});
52 11         87 $buf->put_int8($key->{s2k_ciph});
53 11         87 $buf->put_bytes( $key->{s2k}->save );
54 11         157 $buf->bytes;
55             }
56              
57             sub decrypt {
58 11     11 1 13 my $key = shift;
59 11         21 my($passphrase) = @_;
60 11         32 my $cipher = Crypt::OpenPGP::Cipher->new($key->{s2k_ciph});
61 11         54 my $keysize = $cipher->keysize;
62 11         35 my $s2k_key = $key->{s2k}->generate($passphrase, $keysize);
63 11         20 my($sym_key, $alg);
64 11 50       359 if ($key->{encrypted}) {
65 0         0 $cipher->init($s2k_key);
66 0         0 $sym_key = $cipher->decrypt($key->{encrypted});
67 0         0 $alg = ord substr $sym_key, 0, 1, '';
68             } else {
69 11         18 $sym_key = $s2k_key;
70 11         88 $alg = $cipher->alg_id;
71             }
72 11         138 ($sym_key, $alg);
73             }
74              
75             1;
76             __END__
77              
78             =head1 NAME
79              
80             Crypt::OpenPGP::SKSessionKey - Symmetric-Key Encrypted Session Key
81              
82             =head1 SYNOPSIS
83              
84             use Crypt::OpenPGP::SKSessionKey;
85              
86             my $passphrase = 'foobar'; # Not a very good passphrase
87             my $key_data = 'f' x 64; # Not a very good key
88              
89             my $skey = Crypt::OpenPGP::SKSessionKey->new(
90             Passphrase => $passphrase,
91             SymKey => $key_data,
92             );
93             my $serialized = $skey->save;
94              
95             =head1 DESCRIPTION
96              
97             I<Crypt::OpenPGP::SKSessionKey> implements symmetric-key encrypted
98             session key packets; these packets store symmetric-key-encrypted key data
99             that, when decrypted using the proper passphrase, can be used to decrypt a
100             block of ciphertext--that is, a I<Crypt::OpenPGP::Ciphertext> object.
101              
102             Symmetric-key encrypted session key packets can work in two different
103             ways: in one scenario the passphrase you provide is used to encrypt
104             a randomly chosen string of key material; the key material is the key
105             that is actually used to encrypt the data packet, and the passphrase
106             just serves to encrypt the key material. This encrypted key material
107             is then serialized into the symmetric-key encrypted session key packet.
108              
109             The other method of using this encryption form is to use the passphrase
110             directly to encrypt the data packet. In this scenario the need for any
111             additional key material goes away, because all the receiver needs is
112             the same passphrase that you have entered to encrypt the data.
113              
114             At the moment I<Crypt::OpenPGP> really only supports the first
115             scenario; note also that the interface to I<new> may change in the
116             future when support for the second scenario is added.
117              
118             =head1 USAGE
119              
120             =head2 Crypt::OpenPGP::SKSessionKey->new( %arg )
121              
122             Creates a new encrypted session key packet object and returns that
123             object. If there are no arguments in I<%arg>, the object is created
124             empty; this is used, for example in I<parse> (below), to create an
125             empty packet which is then filled from the data in the buffer.
126              
127             If you wish to initialize a non-empty object, I<%arg> can contain:
128              
129             =over 4
130              
131             =item * Passphrase
132              
133             An arbitrary-length passphrase; that is, a string of octets. The
134             passphrase is used to encrypt the actual session key such that it can
135             only be decrypted by supplying the correct passphrase.
136              
137             This argument is required (for a non-empty object).
138              
139             =item * SymKey
140              
141             The symmetric cipher key: a string of octets that make up the key data
142             of the symmetric cipher key. This should be at least long enough for
143             the key length of your chosen cipher (see I<Cipher>, below), or, if
144             you have not specified a cipher, at least 64 bytes (to allow for long
145             cipher key sizes).
146              
147             This argument is required (for a non-empty object).
148              
149             =item * S2k
150              
151             An object of type I<Crypt::OpenPGP::S2k> (or rather, of one of its
152             subclasses). If you use the passphrase directly to encrypt the data
153             packet (scenario one, above), you will probably be generating the
154             key material outside of this class, meaning that you will need to pass
155             in the I<S2k> object that was used to generate that key material from
156             the passphrase. This is the way to do that.
157              
158             =item * Cipher
159              
160             The name (or ID) of a supported PGP cipher. See I<Crypt::OpenPGP::Cipher>
161             for a list of valid cipher names.
162              
163             This argument is optional; by default I<Crypt::OpenPGP::Cipher> will
164             use C<DES3>.
165              
166             =back
167              
168             =head2 $skey->save
169              
170             Serializes the session key packet and returns the string of octets.
171              
172             =head2 Crypt::OpenPGP::SKSessionKey->parse($buffer)
173              
174             Given I<$buffer>, a I<Crypt::OpenPGP::Buffer> object holding (or
175             with offset pointing to) an encrypted session key packet, returns
176             a new I<Crypt::OpenPGP::Ciphertext> object, initialized with the
177             data in the buffer.
178              
179             =head2 $skey->decrypt($passphrase)
180              
181             Given a passphrase I<$passphrase>, decrypts the encrypted session key
182             data. The key data includes the symmetric key itself, along with a
183             one-octet ID of the symmetric cipher used to encrypt the message.
184              
185             Returns a list containing two items: the symmetric key and the cipher
186             algorithm ID. These are suitable for passing off to the I<decrypt>
187             method of a I<Crypt::OpenPGP::Ciphertext> object to decrypt a block
188             of encrypted data.
189              
190             =head1 AUTHOR & COPYRIGHTS
191              
192             Please see the Crypt::OpenPGP manpage for author, copyright, and
193             license information.
194              
195             =cut