File Coverage

blib/lib/Convert/PEM/CBC.pm
Criterion Covered Total %
statement 83 84 98.8
branch 25 42 59.5
condition 3 6 50.0
subroutine 13 13 100.0
pod 4 6 66.6
total 128 151 84.7


line stmt bran cond sub pod time code
1             package Convert::PEM::CBC;
2 16     16   100990 use strict;
  16         41  
  16         1035  
3              
4             our $VERSION = '0.13'; # VERSION
5 16     16   101 use Carp qw( croak );
  16         26  
  16         993  
6 16     16   97 use Digest::MD5 qw( md5 );
  16         28  
  16         953  
7 16     16   97 use base qw( Class::ErrorHandler );
  16         26  
  16         2786  
8 16     16   8637 use Crypt::PRNG qw( random_bytes );
  16         72259  
  16         22785  
9              
10              
11             sub new {
12 66     66 1 211711 my $class = shift;
13 66         208 my $cbc = bless { }, $class;
14 66         307 $cbc->init(@_);
15             }
16              
17             sub init {
18 66     66 0 125 my $cbc = shift;
19 66         321 my %param = @_;
20 66 50       377 $cbc->{iv} = exists $param{IV} ? $param{IV} : random_bytes(8);
21             croak "init: Cipher is required"
22 66 50       256 unless my $cipher = $param{Cipher};
23 66 100       184 if (ref($cipher)) {
24 64         208 $cbc->{cipher} = $cipher;
25             }
26             else {
27 2     1   176 eval "use $cipher;";
  1     1   775  
  1         2076  
  1         24  
  1         6  
  1         2  
  1         13  
28 2 50       7 croak "Loading '$cipher' failed: $@" if $@;
29 2         6 my $key = $param{Key};
30 2 0 33     4 if (!$key && exists $param{Passphrase}) {
31             $key = bytes_to_key($param{Passphrase}, $cbc->{iv},
32 0         0 \&md5, $cipher->keysize);
33             }
34 2 50       4 croak "init: either Key or Passphrase required"
35             unless $key;
36 2         8 $cbc->{cipher} = $cipher->new($key);
37             }
38 66         370 $cbc;
39             }
40              
41 21     21 1 164 sub iv { $_[0]->{iv} }
42              
43             sub encrypt {
44 22     22 1 393 my $cbc = shift;
45 22         54 my ($text) = @_;
46 22         59 my $cipher = $cbc->{cipher};
47             ## special stuff for the old SEED package
48 22         78 my $seed = ref($cipher) eq "Crypt::SEED";
49 22 50       156 my $bs = ($seed ? 16 : $cipher->blocksize())
    50          
50             or return $cbc->error("This cipher does not support the blocksize method");
51 22         742 my @blocks = $text =~ /(.{1,$bs})/gs;
52 22 100       102 my $last = pop @blocks if length($blocks[-1]) < $bs;
53 22         58 my $iv = $cbc->{iv};
54 22         44 my $buf = '';
55 22         75 for my $block (@blocks) {
56 471 50       3882 $buf .= $iv = $seed
57             ? $cipher->encrypt($iv ^ $block,0)
58             : $cipher->encrypt($iv ^ $block);
59             }
60 22 100 66     240 $last = pack("C*", ($bs) x $bs) unless $last && length $last;
61 22 50       118 if (length $last) {
62 22 100       111 $last .= pack("C*", ($bs-length($last)) x ($bs-length($last)))
63             if length($last) < $bs;
64 22 50       115 $buf .= $iv = $seed
65             ? $cipher->encrypt($iv ^ $last,0)
66             : $cipher->encrypt($iv ^ $last);
67             }
68 22         368 $cbc->{iv} = $iv;
69 22         180 $buf;
70             }
71              
72             sub decrypt {
73 44     44 1 387 my $cbc = shift;
74 44         115 my ($text) = @_;
75 44         115 my $cipher = $cbc->{cipher};
76             ## special stuff for the old SEED package
77 44         126 my $seed = ref($cipher) eq "Crypt::SEED";
78 44 50       270 my $bs = ($seed ? 16 : $cipher->blocksize())
    50          
79             or return $cbc->error("This cipher does not support the blocksize method");
80 44         1383 my @blocks = $text =~ /(.{1,$bs})/gs;
81 44 50       258 my $last = length($blocks[-1]) < $bs ?
82             join '', splice(@blocks, -2) : pop @blocks;
83 44         110 my $iv = $cbc->{iv};
84 44         104 my $buf = '';
85             ## more special stuff for the old SEED package
86 44         130 for my $block (@blocks) {
87 999 50       2527 $buf .= $iv ^ ($seed
88             ? $cipher->decrypt($block,0)
89             : $cipher->decrypt($block));
90 999         6971 $iv = $block;
91             }
92 44         200 $last = pack "a$bs", $last;
93 44 50       195 if (length($last)) {
94 44 50       241 my $tmp = $iv ^ ($seed
95             ? $cipher->decrypt($last,0)
96             : $cipher->decrypt($last));
97 44         376 $iv = $last;
98 44         77 $last = $tmp;
99 44         122 my $cut = ord substr $last, -1;
100 44 100       216 return $cbc->error("Bad key/passphrase")
101             if $cut > $bs;
102 40         106 substr($last, -$cut) = '';
103 40         111 $buf .= $last;
104             }
105 40         93 $cbc->{iv} = $iv;
106 40         303 $buf;
107             }
108              
109             sub bytes_to_key {
110 64     64 0 226 my ($key, $salt, $md, $ks) = @_;
111 64         430 my $ckey = $md->($key . substr($salt,0,8));
112 64         246 while (length($ckey) < $ks) {
113 39         355 $ckey .= $md->($ckey, $key, substr($salt,0,8));
114             }
115 64         265 substr $ckey, 0, $ks;
116             }
117              
118             1;
119             __END__