File Coverage

blib/lib/Crypt/Skip32.pm
Criterion Covered Total %
statement 64 67 95.5
branch 8 8 100.0
condition n/a
subroutine 12 12 100.0
pod 5 5 100.0
total 89 92 96.7


line stmt bran cond sub pod time code
1             package Crypt::Skip32;
2              
3 4     4   126428 use 5.008000;
  4         17  
  4         183  
4 4     4   24 use strict;
  4         9  
  4         148  
5 4     4   22 use warnings;
  4         11  
  4         163  
6 4     4   20 use Carp qw(croak);
  4         7  
  4         857  
7              
8 2     2   1844 if (not $ENV{CRYPT_SKIP32_PP} and eval 'use Crypt::Skip32::XS; 1') {
  2         1448  
  2         37  
9             eval q(sub Crypt::Skip32 () { 'Crypt::Skip32::XS' });
10             }
11              
12             our $VERSION = '0.18';
13              
14 864 100   864 1 1007 eval <<'EOP' if not defined &new;
  864 100   36 1 1611  
  864 100   2 1 957  
  864 100   20 1 854  
  864     20 1 1215  
  864     2   1223  
  864     7   1139  
  864         1090  
  864         1683  
  36         50  
  36         66  
  36         49  
  0         0  
  0         0  
  0         0  
  36         64  
  18         19  
  18         576  
  18         22  
  18         21  
  36         49  
  36         42  
  36         82  
  432         644  
  432         471  
  432         646  
  432         947  
  36         50  
  36         60  
  36         54  
  36         38  
  36         99  
  2         496  
  20         1326  
  20         53  
  20         803  
  18         60  
  18         48  
  18         59  
  20         2389  
  20         61  
  20         214  
  18         56  
  18         54  
  18         61  
  2         50  
  7         3525  
  7         33  
  7         332  
  5         17  
  5         15  
  5         15  
15              
16             # Number of bytes in the 4 byte (32-bit) block.
17             sub blocksize {
18             return 4;
19             }
20              
21             # Number of bytes in the 10 byte (80-bit) key.
22             sub keysize {
23             return 10;
24             }
25              
26             # New cipher constructor
27             sub new {
28             my ($class, $key) = @_;
29              
30             my @key_bytes = unpack('C*', $key);
31             croak "key must be 10 bytes long"
32             unless scalar @key_bytes == 10;
33              
34             my $self = {
35             key => $key,
36             key_bytes => \@key_bytes,
37             };
38             bless $self, $class;
39              
40             return $self;
41             }
42              
43             # Encrypt a 4 byte (32-bit) block
44             sub encrypt {
45             my ($self, $plaintext) = @_;
46              
47             my @input_bytes = unpack('C*', $plaintext);
48             croak "plaintext must be 4 bytes long"
49             unless scalar @input_bytes == 4;
50             my @output_bytes = _skip32($self->{key_bytes}, \@input_bytes, 1);
51             my $cipher_text = pack('C*', @output_bytes);
52              
53             return $cipher_text;
54             }
55              
56             # Decrypt a 4 byte (32-bit) block
57             sub decrypt {
58             my ($self, $ciphertext) = @_;
59              
60             my @input_bytes = unpack('C*', $ciphertext);
61             croak "ciphertext must be 4 bytes long"
62             unless scalar @input_bytes == 4;
63             my @output_bytes = _skip32($self->{key_bytes}, \@input_bytes, 0);
64             my $plain_text = pack('C*', @output_bytes);
65              
66             return $plain_text;
67             }
68              
69             # Remaining Perl code is a direct translation of the SKIP32 C implementation
70              
71             my @FTABLE =
72             (
73             0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf,0xf9,
74             0xe7,0x2d,0x4d,0x8a,0xce,0x4c,0xca,0x2e,0x52,0x95,0xd9,0x1e,0x4e,0x38,0x44,0x28,
75             0x0a,0xdf,0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a,0xc3,0xe9,0xfa,0x3d,0x53,
76             0x96,0x84,0x6b,0xba,0xf2,0x63,0x9a,0x19,0x7c,0xae,0xe5,0xf5,0xf7,0x16,0x6a,0xa2,
77             0x39,0xb6,0x7b,0x0f,0xc1,0x93,0x81,0x1b,0xee,0xb4,0x1a,0xea,0xd0,0x91,0x2f,0xb8,
78             0x55,0xb9,0xda,0x85,0x3f,0x41,0xbf,0xe0,0x5a,0x58,0x80,0x5f,0x66,0x0b,0xd8,0x90,
79             0x35,0xd5,0xc0,0xa7,0x33,0x06,0x65,0x69,0x45,0x00,0x94,0x56,0x6d,0x98,0x9b,0x76,
80             0x97,0xfc,0xb2,0xc2,0xb0,0xfe,0xdb,0x20,0xe1,0xeb,0xd6,0xe4,0xdd,0x47,0x4a,0x1d,
81             0x42,0xed,0x9e,0x6e,0x49,0x3c,0xcd,0x43,0x27,0xd2,0x07,0xd4,0xde,0xc7,0x67,0x18,
82             0x89,0xcb,0x30,0x1f,0x8d,0xc6,0x8f,0xaa,0xc8,0x74,0xdc,0xc9,0x5d,0x5c,0x31,0xa4,
83             0x70,0x88,0x61,0x2c,0x9f,0x0d,0x2b,0x87,0x50,0x82,0x54,0x64,0x26,0x7d,0x03,0x40,
84             0x34,0x4b,0x1c,0x73,0xd1,0xc4,0xfd,0x3b,0xcc,0xfb,0x7f,0xab,0xe6,0x3e,0x5b,0xa5,
85             0xad,0x04,0x23,0x9c,0x14,0x51,0x22,0xf0,0x29,0x79,0x71,0x7e,0xff,0x8c,0x0e,0xe2,
86             0x0c,0xef,0xbc,0x72,0x75,0x6f,0x37,0xa1,0xec,0xd3,0x8e,0x62,0x8b,0x86,0x10,0xe8,
87             0x08,0x77,0x11,0xbe,0x92,0x4f,0x24,0xc5,0x32,0x36,0x9d,0xcf,0xf3,0xa6,0xbb,0xac,
88             0x5e,0x6c,0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd,0xa8,0x3a,0x01,0x05,0x59,0x2a,0x46
89             );
90              
91             sub _g {
92             my ($rkey, $k, $w) = @_;
93             my @key = @$rkey;
94              
95             my $g1 = ($w>>8)&0xff;
96             my $g2 = $w&0xff;
97             my $g3 = $FTABLE[$g2 ^ $key[(4*$k)%10]] ^ $g1;
98             my $g4 = $FTABLE[$g3 ^ $key[(4*$k+1)%10]] ^ $g2;
99             my $g5 = $FTABLE[$g4 ^ $key[(4*$k+2)%10]] ^ $g3;
100             my $g6 = $FTABLE[$g5 ^ $key[(4*$k+3)%10]] ^ $g4;
101              
102             return (($g5<<8) + $g6);
103             }
104              
105             sub _skip32 {
106             my ($rkey, $rbuf, $encrypt) = @_;
107             my @buf = @$rbuf;
108              
109             my $k; # round number
110             my $i; # round counter
111             my $kstep;
112             my $wl;
113             my $wr;
114              
115             # sort out direction
116             if ($encrypt) {
117             $kstep = 1;
118             $k = 0;
119             }
120             else {
121             $kstep = -1;
122             $k = 23;
123             }
124              
125             # pack into words
126             $wl = ($buf[0] << 8) + $buf[1];
127             $wr = ($buf[2] << 8) + $buf[3];
128              
129             # 24 feistel rounds, doubled up
130             for ($i = 0; $i < 24/2; ++$i) {
131             $wr ^= _g($rkey, $k, $wl) ^ $k;
132             $k += $kstep;
133             $wl ^= _g($rkey, $k, $wr) ^ $k;
134             $k += $kstep;
135             }
136              
137             # implicitly swap halves while unpacking
138             $buf[0] = $wr >> 8;
139             $buf[1] = $wr & 0xFF;
140             $buf[2] = $wl >> 8;
141             $buf[3] = $wl & 0xFF;
142              
143             return @buf;
144             }
145              
146             EOP
147              
148             1;
149              
150             __END__