File Coverage

blib/lib/Crypt/OpenPGP/Ciphertext.pm
Criterion Covered Total %
statement 79 84 94.0
branch 20 26 76.9
condition 6 11 54.5
subroutine 14 15 93.3
pod 4 7 57.1
total 123 143 86.0


line stmt bran cond sub pod time code
1             package Crypt::OpenPGP::Ciphertext;
2 3     3   19 use strict;
  3         6  
  3         118  
3 3     3   14 use warnings;
  3         6  
  3         229  
4              
5             our $VERSION = '1.19'; # VERSION
6              
7 3     3   18 use Crypt::OpenPGP::Util;
  3         5  
  3         190  
8 3     3   446 use Crypt::OpenPGP::Cipher;
  3         8  
  3         149  
9 3         39 use Crypt::OpenPGP::Constants qw( DEFAULT_CIPHER
10             PGP_PKT_ENCRYPTED
11 3     3   35 PGP_PKT_ENCRYPTED_MDC );
  3         6  
12 3     3   18 use Crypt::OpenPGP::ErrorHandler;
  3         5  
  3         112  
13 3     3   15 use base qw( Crypt::OpenPGP::ErrorHandler );
  3         5  
  3         385  
14              
15 3     3   19 use constant MDC_TRAILER => chr(0xd3) . chr(0x14);
  3         6  
  3         7439  
16              
17 23 100   23 0 206 sub pkt_type { $_[0]->{is_mdc} ? PGP_PKT_ENCRYPTED_MDC : PGP_PKT_ENCRYPTED }
18              
19             sub new {
20 48     48 1 226 my $class = shift;
21 48         140 my $enc = bless { }, $class;
22 48         206 $enc->init(@_);
23             }
24              
25             sub init {
26 48     48 0 127 my $enc = shift;
27 48         287 my %param = @_;
28 48 100 66     408 if ((my $key = $param{SymKey}) && (my $data = $param{Data})) {
29 23   100     149 $enc->{is_mdc} = $param{MDC} || 0;
30 23         95 $enc->{version} = 1;
31 23   33     96 my $alg = $param{Cipher} || DEFAULT_CIPHER;
32 23         158 my $cipher = Crypt::OpenPGP::Cipher->new($alg, $key);
33 23         79 my $bs = $cipher->blocksize;
34 23         149 my $pad = Crypt::OpenPGP::Util::get_random_bytes($bs);
35 23         1873 $pad .= substr $pad, -2, 2;
36 23         168 $enc->{ciphertext} = $cipher->encrypt($pad);
37 23 100       186 $cipher->sync unless $enc->{is_mdc};
38 23         71 $enc->{ciphertext} .= $cipher->encrypt($data);
39              
40 23 100       450 if ($enc->{is_mdc}) {
41 1         938 require Crypt::OpenPGP::MDC;
42 1         10 my $mdc = Crypt::OpenPGP::MDC->new(
43             Data => $pad . $data . MDC_TRAILER );
44 1         12 my $mdc_buf = Crypt::OpenPGP::PacketFactory->save($mdc);
45 1         5 $enc->{ciphertext} .= $cipher->encrypt($mdc_buf);
46             }
47             }
48 48         354 $enc;
49             }
50              
51             sub parse {
52 25     25 1 67 my $class = shift;
53 25         84 my($buf, $is_mdc) = @_;
54 25         128 my $enc = $class->new;
55 25         94 $enc->{is_mdc} = $is_mdc;
56 25 100       99 if ($is_mdc) {
57 3         15 $enc->{version} = $buf->get_int8;
58             }
59 25         156 $enc->{ciphertext} = $buf->get_bytes($buf->length - $buf->offset);
60 25         695 $enc;
61             }
62              
63             sub save {
64 23     23 1 55 my $enc = shift;
65 23         81 my $buf = Crypt::OpenPGP::Buffer->new;
66 23 100       270 if ($enc->{is_mdc}) {
67 1         5 $buf->put_int8($enc->{version});
68             }
69 23         88 $buf->put_bytes($enc->{ciphertext});
70 23         320 $buf->bytes;
71             }
72              
73             sub display {
74 0     0 0 0 my $enc = shift;
75             my $str = ":encrypted data packet:\n" .
76 0         0 " length: " . length($enc->{ciphertext}) . "\n";
77 0 0       0 if ($enc->{is_mdc}) {
78 0         0 $str .= " is_mdc: $enc->{version}\n";
79             }
80 0         0 $str;
81             }
82              
83             sub decrypt {
84 24     24 1 59 my $enc = shift;
85 24         73 my($key, $sym_alg) = @_;
86 24 50       227 my $cipher = Crypt::OpenPGP::Cipher->new($sym_alg, $key) or
87             return $enc->error( Crypt::OpenPGP::Cipher->errstr );
88 24         92 my $padlen = $cipher->blocksize + 2;
89             my $pt = $enc->{prefix} =
90 24         196 $cipher->decrypt(substr $enc->{ciphertext}, 0, $padlen);
91 24 50       174 return $enc->error("Bad checksum")
92             unless substr($pt, -4, 2) eq substr($pt, -2, 2);
93 24 100       1249 $cipher->sync unless $enc->{is_mdc};
94 24         98 $pt = $cipher->decrypt(substr $enc->{ciphertext}, $padlen);
95 24 100       108 if ($enc->{is_mdc}) {
96 2         54 my $mdc_buf = Crypt::OpenPGP::Buffer->new_with_init(substr $pt,-22,22);
97 2         105 $pt = substr $pt, 0, -22;
98 2         34 my $mdc = Crypt::OpenPGP::PacketFactory->parse($mdc_buf);
99 2 50 33     41 return $enc->error("Encrypted MDC packet without MDC")
100             unless $mdc && ref($mdc) eq 'Crypt::OpenPGP::MDC';
101 2         17 require Crypt::OpenPGP::Digest;
102 2         16 my $dgst = Crypt::OpenPGP::Digest->new('SHA1');
103 2         14 my $hash = $dgst->hash($enc->{prefix} . $pt . chr(0xd3) . chr(0x14));
104 2 50       13 return $enc->error("SHA-1 hash of plaintext does not match MDC body")
105             unless $mdc->digest eq $hash;
106             }
107 24         402 $pt;
108             }
109              
110             1;
111             __END__