File Coverage

blib/lib/Crypt/Skip32.pm
Criterion Covered Total %
statement 66 66 100.0
branch 8 8 100.0
condition n/a
subroutine 12 12 100.0
pod 5 5 100.0
total 91 91 100.0


line stmt bran cond sub pod time code
1             package Crypt::Skip32;
2              
3 5     5   209132 use 5.008000;
  5         32  
4 5     5   22 use strict;
  5         9  
  5         84  
5 5     5   18 use warnings;
  5         8  
  5         143  
6 5     5   22 use Carp qw(croak);
  5         7  
  5         745  
7              
8 3     3   1121 if (not $ENV{CRYPT_SKIP32_PP} and eval 'use Crypt::Skip32::XS; 1') {
  3         1203  
  3         42  
9             *new = *Crypt::Skip32::XS::new;
10             }
11              
12             our $VERSION = '0.19';
13              
14 864 100   864 1 1020 eval <<'EOP' if not defined &new;
  864 100   36 1 1169  
  864 100   2 1 920  
  864 100   20 1 870  
  864     20 1 1102  
  864     2   1084  
  864     7   1075  
  864         1058  
  864         1281  
  36         50  
  36         59  
  36         106  
  36         0  
  36         0  
  36         0  
  36         61  
  18         21  
  18         33  
  18         22  
  18         31  
  36         51  
  36         41  
  36         72  
  432         521  
  432         479  
  432         515  
  432         651  
  36         48  
  36         40  
  36         42  
  36         38  
  36         62  
  2         548  
  20         1292  
  20         46  
  20         154  
  18         34  
  18         39  
  18         72  
  20         1624  
  20         48  
  20         195  
  18         45  
  18         54  
  18         49  
  2         40  
  7         4087  
  7         30  
  7         281  
  5         16  
  5         12  
  5         18  
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__