File Coverage

blib/lib/Convert/PEM/CBC.pm
Criterion Covered Total %
statement 79 83 95.1
branch 16 26 61.5
condition 3 6 50.0
subroutine 13 13 100.0
pod 4 6 66.6
total 115 134 85.8


line stmt bran cond sub pod time code
1             package Convert::PEM::CBC;
2 5     5   654 use strict;
  5         9  
  5         209  
3              
4 5     5   25 use Carp qw( croak );
  5         9  
  5         258  
5 5     5   29 use Digest::MD5 qw( md5 );
  5         7  
  5         212  
6 5     5   25 use base qw( Class::ErrorHandler );
  5         12  
  5         4801  
7              
8             sub new {
9 8     8 1 40 my $class = shift;
10 8         26 my $cbc = bless { }, $class;
11 8         33 $cbc->init(@_);
12             }
13              
14             sub init {
15 8     8 0 14 my $cbc = shift;
16 8         36 my %param = @_;
17 16         336 $cbc->{iv} = exists $param{IV} ? $param{IV} :
18 8 100       46 pack("C*", map { rand 255 } 1..8);
19 8 50       30 croak "init: Cipher is required"
20             unless my $cipher = $param{Cipher};
21 8 50       30 if (ref($cipher)) {
22 0         0 $cbc->{cipher} = $cipher;
23             }
24             else {
25 8     3   944 eval "use $cipher;";
  3     3   3726  
  3     2   8382  
  3         61  
  3         20  
  3         6  
  3         115  
  2         14  
  2         4  
  2         37  
26 8 50       34 croak "Loading '$cipher' failed: $@" if $@;
27 8         19 my $key = $param{Key};
28 8 100 66     52 if (!$key && exists $param{Passphrase}) {
29 6         69 $key = bytes_to_key($param{Passphrase}, $cbc->{iv},
30             \&md5, $cipher->keysize);
31             }
32 8 50       28 croak "init: either Key or Passphrase required"
33             unless $key;
34 8         35 $cbc->{cipher} = $cipher->new($key);
35             }
36 8         540 $cbc;
37             }
38              
39 2     2 1 19 sub iv { $_[0]->{iv} }
40              
41             sub encrypt {
42 3     3 1 67 my $cbc = shift;
43 3         9 my($text) = @_;
44 3         9 my $cipher = $cbc->{cipher};
45 3         24 my $bs = $cipher->blocksize;
46 3         80 my @blocks = $text =~ /(.{1,$bs})/ogs;
47 3 50       16 my $last = pop @blocks if length($blocks[-1]) < $bs;
48 3         9 my $iv = $cbc->{iv};
49 3         7 my $buf = '';
50 3         11 for my $block (@blocks) {
51 0         0 $buf .= $iv = $cipher->encrypt($iv ^ $block);
52             }
53 3 50 33     27 $last = pack("C*", ($bs) x $bs) unless $last && length $last;
54 3 50       15 if (length $last) {
55 3 50       33 $last .= pack("C*", ($bs-length($last)) x ($bs-length($last)))
56             if length($last) < $bs;
57 3         18 $buf .= $iv = $cipher->encrypt($iv ^ $last);
58             }
59 3         80 $cbc->{iv} = $iv;
60 3         106 $buf;
61             }
62              
63             sub decrypt {
64 5     5 1 15 my $cbc = shift;
65 5         17 my($text) = @_;
66 5         12 my $cipher = $cbc->{cipher};
67 5         19 my $bs = $cipher->blocksize;
68 5         74 my @blocks = $text =~ /(.{1,$bs})/ogs;
69 5 50       21 my $last = length($blocks[-1]) < $bs ?
70             join '', splice(@blocks, -2) : pop @blocks;
71 5         12 my $iv = $cbc->{iv};
72 5         9 my $buf = '';
73 5         13 for my $block (@blocks) {
74 0         0 $buf .= $iv ^ $cipher->decrypt($block);
75 0         0 $iv = $block;
76             }
77 5         21 $last = pack "a$bs", $last;
78 5 50       20 if (length($last)) {
79 5         18 my $tmp = $iv ^ $cipher->decrypt($last);
80 5         120 $iv = $last;
81 5         23 $last = $tmp;
82 5         11 my $cut = ord substr $last, -1;
83 5 100       43 return $cbc->error("Bad key/passphrase")
84             if $cut > $bs;
85 3         10 substr($last, -$cut) = '';
86 3         7 $buf .= $last;
87             }
88 3         9 $cbc->{iv} = $iv;
89 3         15 $buf;
90             }
91              
92             sub bytes_to_key {
93 6     6 0 35 my($key, $salt, $md, $ks) = @_;
94 6         45 my $ckey = $md->($key, $salt);
95 6         26 while (length($ckey) < $ks) {
96 6         33 $ckey .= $md->($ckey, $key, $salt);
97             }
98 6         20 substr $ckey, 0, $ks;
99             }
100              
101             1;
102             __END__