File Coverage

blib/lib/Crypt/Present.pm
Criterion Covered Total %
statement 65 73 89.0
branch 7 12 58.3
condition n/a
subroutine 7 12 58.3
pod 4 8 50.0
total 83 105 79.0


line stmt bran cond sub pod time code
1             package Crypt::Present;
2              
3 1     1   27157 use strict;
  1         2  
  1         42  
4 1     1   6 use warnings;
  1         2  
  1         61  
5              
6             our @ISA = qw();
7              
8             our $VERSION = '0.02';
9              
10              
11 1     1   5 use Carp;
  1         13  
  1         612  
12              
13             my @SBoxBits;
14             my @SBoxByte;
15             my @SBoxByteRev;
16             my @V5Bits;
17             my @pLVec;
18             BEGIN {
19 1     1   4 my @SBox = ( 0xC, 0x5, 0x6, 0xB, 0x9, 0x0, 0xA, 0xD, 0x3, 0xE, 0xF, 0x8, 0x4, 0x7, 0x1, 0x2 );
20 1         42 @SBoxBits = map unpack('B4',chr($_<<4)), @SBox;
21 1         5 @SBoxByte = map { my $h = ( $_ & 0xF0 ) >> 4;
  256         338  
22 256         237 my $l = ( $_ & 0x0F );
23 256         559 chr( ( $SBox[$h] << 4 ) | $SBox[$l] );
24             } ( 0 .. 255 );
25 1         12 foreach ( 0 .. 255 ) { $SBoxByteRev[ord($SBoxByte[$_])] = chr $_; }
  256         396  
26              
27 1         43 push @V5Bits, unpack('B5',chr($_<<3)) foreach (0..31);
28              
29 1         2 my @pLayer; # ( 0, 16, 32, 48, ... );
30 1         6 for ( my $i = 0; $i < 16; $i++ ) {
31 16         20 $pLayer[$i*4+0] = $i;
32 16         19 $pLayer[$i*4+1] = $i + 16;
33 16         20 $pLayer[$i*4+2] = $i + 32;
34 16         37 $pLayer[$i*4+3] = $i + 48;
35             }
36 1         2 for my $i ( 0 .. 63 ) {
37 64         59 my $p = $pLayer[$i];
38 64         81 my $iv = int($i/8)*8+(7-($i%8));
39 64         76 my $pv = int($p/8)*8+(7-($p%8));
40 64         1325 $pLVec[$iv] = $pv;
41             }
42             }
43              
44              
45             sub usage
46             {
47 0     0 0 0 my ($package, $filename, $line, $subr) = caller(1);
48 0         0 $Carp::CarpLevel = 2;
49 0         0 croak "Usage: $subr(@_)";
50             }
51              
52              
53 0     0 1 0 sub blocksize { 8; }
54 0 0   0 0 0 sub keysize { my $k = $_[0]->{KEY}; return defined($k) ? length($k) : [ 80, 128 ]; }
  0         0  
55 0     0 0 0 sub min_keysize { 80; }
56 0     0 0 0 sub max_keysize { 128; }
57              
58             my $genRoundKeys = sub ($) {
59             my $self = shift;
60              
61             my $key = $self->{KEY};
62              
63             my @roundKeys;
64              
65             if ( length($key) == 10 ) {
66              
67             push @roundKeys, substr( $key, 0, 8 );
68             $key = unpack('B*',$key);
69             for ( my $i = 1; $i <= 31; $i++ ) {
70             $key = $SBoxBits[ord(pack('B8','0000'.substr( $key, 61, 4 )))] . substr( $key, 65, 15 ) . substr( $key, 0, 61 );
71             $key = substr( $key, 0, 60 ) . $V5Bits[(ord(pack("B5",substr( $key, 60, 5 )))>>3)^$i] . substr( $key, 65, 15 );
72             push @roundKeys, substr( pack('B*',$key), 0, 8 );
73             }
74              
75             } elsif ( length($key) == 16 ) {
76              
77             push @roundKeys, substr( $key, 0, 8 );
78             $key = unpack('B*',$key);
79             for ( my $i = 1; $i <= 31; $i++ ) {
80             $key = $SBoxBits[ord(pack('B8','0000'.substr( $key, 61, 4 )))] . $SBoxBits[ord(pack('B8','0000'.substr( $key, 65, 4 )))] . substr( $key, 69, 59 ) . substr( $key, 0, 61 );
81             $key = substr( $key, 0, 61 ) . $V5Bits[(ord(pack("B5",substr( $key, 61, 5 )))>>3)^$i] . substr( $key, 66, 62 );
82             push @roundKeys, substr( pack('B*',$key), 0, 8 );
83             }
84              
85             } else {
86             die 'key size must be 80 or 128 but not '.(8 * length $key);
87             }
88              
89             return $self->{ROUND_KEYS} = \@roundKeys;
90             };
91              
92              
93             sub new ($;$) {
94 8 50   8 1 8428 usage("new Present key") unless @_ == 2;
95 8         17 my $class = shift;
96 8         17 my $key = shift;
97              
98 8         40 my $self = bless { KEY => $key }, $class;
99 8         27 &$genRoundKeys($self);
100 8         22 return $self;
101             }
102              
103              
104             my $null64 = "\x00" x 8; # 64 bit null value
105              
106              
107             sub encrypt ($$) {
108 8 50   8 1 63 usage("encrypt data[8 bytes]") unless @_ == 2;
109 8         13 my $self = shift;
110 8         12 my $data = shift; # plaintext
111              
112 8         15 my $roundKeys = $self->{ROUND_KEYS}; # $roundKeys = &$genRoundKeys($self) if !defined $roundKeys;
113              
114 8         28 for ( my $i = 0; $i <= 30; $i++ ) {
115 248         427 $data = $data ^ $roundKeys->[$i];
116 248         768 $data = join '', map { $SBoxByte[ord($_)]; } split //, $data;
  1984         3221  
117             { # permutate
118 248         545 my $c = $null64;
  248         278  
119             #foreach ( 0 .. 63 ) { vec( $c, $pLVec[$_], 1 ) = 1 if vec( $b, $_, 1 ); }
120 248 100       529 for ( my $j = 64; $j--; ) { vec( $c, $pLVec[$j], 1 ) = 1 if vec( $data, $j, 1 ); }
  15872         45164  
121 248         687 $data = $c;
122             }
123             }
124 8         25 $data = $data ^ $roundKeys->[31];
125              
126 8         45 return $data;
127             }
128              
129              
130             sub decrypt ($$) {
131 8 50   8 1 77 usage("decrypt data[8 bytes]") unless @_ == 2;
132 8         16 my $self = shift;
133 8         15 my $data = shift; # ciphertext
134              
135 8         53 my $roundKeys = $self->{ROUND_KEYS}; # $roundKeys = &$genRoundKeys($self) if !defined $roundKeys;
136              
137 8         25 $data = $data ^ $roundKeys->[31];
138 8         32 for ( my $i = 30; $i >= 0; $i-- ) {
139             { # permutate
140 248         232 my $c = $null64;
  248         309  
141             #foreach ( 0 .. 63 ) { vec( $c, $_, 1 ) = 1 if vec( $data, $pLVec[$_], 1 ); }
142 248 100       536 for ( my $j = 64; $j--; ) { vec( $c, $j, 1 ) = 1 if vec( $data, $pLVec[$j], 1 ); }
  15872         46103  
143 248         352 $data = $c;
144             }
145 248         700 $data = join '', map { $SBoxByteRev[ord($_)]; } split //, $data;
  1984         3255  
146 248         1059 $data = $data ^ $roundKeys->[$i];
147             }
148              
149 8         46 return $data;
150             }
151              
152              
153             1;
154              
155             __END__