File Coverage

blib/lib/Crypt/Rijndael/PP.pm
Criterion Covered Total %
statement 347 355 97.7
branch 29 34 85.2
condition 3 3 100.0
subroutine 49 52 94.2
pod 9 14 64.2
total 437 458 95.4


line stmt bran cond sub pod time code
1             package Crypt::Rijndael::PP;
2              
3 17     17   5581291 use strict;
  17         42  
  17         761  
4 17     17   90 use warnings;
  17         28  
  17         563  
5              
6 17     17   7080 use bytes;
  17         117  
  17         87  
7              
8 17     17   10558 use Smart::Comments -ENV;
  17         799046  
  17         148  
9 17     17   82229 use Data::Dumper;
  17         55  
  17         1362  
10 17     17   108 use Carp;
  17         31  
  17         1182  
11              
12 17     17   10349 use Crypt::Rijndael::PP::GF qw( gf_multiply );
  17         69  
  17         1318  
13 17     17   8980 use Crypt::Rijndael::PP::Debug qw( generate_printable_state );
  17         43  
  17         1230  
14              
15 17     17   10090 use Crypt::Random::Source qw(get_weak);
  17         1326435  
  17         166  
16              
17             our $VERSION = '0.3.0'; # VERSION
18             # ABSTRACT: Pure Perl Implementation of the Rijndael Cipher
19              
20 17     17   6436 use Readonly;
  17         27  
  17         62053  
21             #<<< Don't Tidy S Boxes
22             Readonly my @SBOX => (
23             0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
24             0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
25             0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
26             0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
27             0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
28             0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
29             0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
30             0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
31             0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
32             0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
33             0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
34             0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
35             0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
36             0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
37             0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
38             0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
39             );
40              
41             Readonly my @INVSBOX => (
42             0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
43             0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
44             0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
45             0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
46             0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
47             0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
48             0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
49             0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
50             0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
51             0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
52             0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
53             0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
54             0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
55             0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
56             0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
57             0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
58             );
59             #>>>
60              
61             #<<< Don't Tidy the Round Constansts
62             Readonly my @RCONST => (
63             0x8d000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000,
64             0x80000000, 0x1b000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000,
65             0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
66             0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
67             0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
68             0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
69             0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
70             0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
71             0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
72             0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
73             0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
74             0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
75             0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
76             0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
77             0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
78             0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
79             0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d
80             );
81             #>>>
82              
83             Readonly my $NUM_ROUNDS => {
84             128 => 10,
85             192 => 12,
86             256 => 14,
87             };
88              
89             sub new {
90 90     90 1 4824 my $class = shift;
91 90         242 my $key = shift;
92 90         162 my $mode = shift;
93              
94 90 50       368 if( !$mode ) {
95 0         0 $mode = MODE_ECB();
96             }
97              
98 90         635 my $self = {
99             key => $key,
100             mode => $mode,
101             iv => get_weak(16),
102             };
103              
104 90         627361 bless $self, $class;
105              
106 90         349 return $self;
107             }
108              
109             sub MODE_ECB {
110 108     108 1 56045 return 1;
111             }
112              
113             sub MODE_CBC {
114 90     90 1 83527 return 2;
115             }
116              
117             sub MODE_CTR {
118 72     72 1 92212 return 3;
119             }
120              
121             sub MODE_CFB {
122 54     54 1 84716 return 4;
123             }
124              
125             sub MODE_OFB {
126 36     36 1 98129 return 5;
127             }
128              
129             sub blocksize {
130 0     0 0 0 return 16;
131             }
132              
133             sub keysize {
134 0     0 0 0 return 32;
135             }
136              
137             sub set_iv {
138 72     72 1 601 my $self = shift;
139 72         177 my $iv = shift;
140              
141 72 50       477 if( length( $iv ) != 16 ) {
142 0         0 croak 'set_iv: initial value must be the blocksize (16 bytes), but was '
143             . length( $iv ) . ' bytes';
144             }
145              
146 72         270 $self->{iv} = $iv;
147              
148 72         417 return $self;
149             }
150              
151             sub get_iv {
152 0     0 1 0 my $self = shift;
153              
154 0         0 return $self->{iv};
155             }
156              
157             sub _increment_nonce {
158 36     36   73 my $self = shift;
159 36         74 my $packed_nonce = shift;
160              
161 36         171 my @nonce_parts = unpack( 'N4', $packed_nonce );
162              
163             ### Nonce Part 0 : unpack( 'A4', $nonce_parts[0] ) . ' - ' . unpack( 'B32', $nonce_parts[0] )
164             ### Nonce Part 1 : unpack( 'A4', $nonce_parts[1] ) . ' - ' . unpack( 'B32', $nonce_parts[1] )
165             ### Nonce Part 2 : unpack( 'A4', $nonce_parts[2] ) . ' - ' . unpack( 'B32', $nonce_parts[2] )
166             ### Nonce Part 3 : unpack( 'A4', $nonce_parts[3] ) . ' - ' . unpack( 'B32', $nonce_parts[3] )
167              
168 36         162 for my $nonce_part_index ( 0 .. 3 ) {
169 36         119 my $original_nonce_part = $nonce_parts[ 3 - $nonce_part_index ];
170 36         88 $nonce_parts[ 3 - $nonce_part_index ]++;
171              
172             ### Nonce Part Index : ( $nonce_part_index )
173             ### Original Nonce Part : unpack( 'A4', $original_nonce_part ) . ' - ' . unpack( 'B32', $original_nonce_part )
174             ### Incremented Nonce Part : unpack( 'A4', $nonce_parts[ 3 - $nonce_part_index ] ) . ' - ' . unpack( 'B32', $nonce_parts[ 3 - $nonce_part_index ] )
175              
176 36 50       106 if( $original_nonce_part < $nonce_parts[ 3 - $nonce_part_index ] ) {
177 36         115 last;
178             }
179             }
180              
181 36         204 return pack( 'N4', @nonce_parts );
182             }
183              
184             sub encrypt {
185 45     45 0 19564 my $self = shift;
186 45         120 my $input = shift;
187              
188             ## no critic (ControlStructures::ProhibitCascadingIfElse)
189 45 100       194 if( $self->{mode} == MODE_ECB() ) {
    100          
    100          
    100          
    50          
190 9         29 return $self->_encrypt_mode_ecb( $input );
191             }
192             elsif( $self->{mode} == MODE_CBC() ) {
193 9         50 return $self->_encrypt_mode_cbc( $input );
194             }
195             elsif( $self->{mode} == MODE_CTR() ) {
196 9         49 return $self->_encrypt_mode_ctr( $input );
197             }
198             elsif( $self->{mode} == MODE_CFB() ) {
199 9         45 return $self->_encrypt_mode_cfb( $input );
200             }
201             elsif( $self->{mode} == MODE_OFB() ) {
202 9         48 return $self->_encrypt_mode_ofb( $input );
203             }
204             else {
205 0         0 croak "Invalid Mode specified";
206             }
207             ## use critic
208             }
209              
210             sub _encrypt_mode_ecb {
211 9     9   15 my $self = shift;
212 9         48 my $input = shift;
213              
214 9         15 my $cipher_text = '';
215 9         46 for( my $block_index = 0; $block_index < ( length($input) / 16 ); $block_index++ ) {
216 18         47 my $block = substr( $input, $block_index * 16, 16 );
217              
218 18         61 $cipher_text .= $self->encrypt_block( $block, $self->{key} );
219             }
220              
221 9         99 return $cipher_text;
222             }
223              
224             sub _encrypt_mode_cbc {
225 9     9   33 my $self = shift;
226 9         13 my $input = shift;
227              
228 9         29 my $last_block = $self->{iv};
229              
230 9         24 my $cipher_text = '';
231 9         67 for( my $block_index = 0; $block_index < ( length($input) / 16 ); $block_index++ ) {
232 18         70 my $block = substr( $input, $block_index * 16, 16 );
233              
234 18         46 $block = $block ^ $last_block;
235              
236 18         153 $last_block = $self->encrypt_block( $block, $self->{key} );
237              
238 18         167 $cipher_text .= $last_block;
239             }
240              
241 9         172 return $cipher_text;
242             }
243              
244             sub _encrypt_mode_ctr {
245 18     18   36 my $self = shift;
246 18         43 my $input = shift;
247              
248 18         70 my $nonce = $self->{iv};
249              
250 18         36 my $cipher_text = '';
251 18         135 for( my $block_index = 0; $block_index < ( length($input) / 16 ); $block_index++ ) {
252 36         139 my $block = substr( $input, $block_index * 16, 16 );
253              
254 36         186 my $packed_nonce = pack( 'A16', $nonce );
255              
256             ### Nonce : ( $nonce )
257             ### Nonce Bit String : ( unpack( 'B128', $packed_nonce ) )
258              
259 36         296 my $ctr_block = $self->encrypt_block( unpack( 'A16', $packed_nonce ), $self->{key} );
260              
261 36         149 $cipher_text .= $ctr_block ^ $block;
262 36         238 $packed_nonce = $self->_increment_nonce( $packed_nonce );
263              
264             ### Nonce + 1 Bit String: ( unpack( 'B128', $packed_nonce ) )
265 36         433 $nonce = unpack('A16', $packed_nonce );
266             }
267              
268 18         314 return $cipher_text;
269             }
270              
271             sub _encrypt_mode_cfb {
272 9     9   20 my $self = shift;
273 9         20 my $input = shift;
274              
275 9         21 my $last_block = $self->{iv};
276              
277 9         17 my $cipher_text = '';
278 9         73 for( my $block_index = 0; $block_index < ( length($input) / 16 ); $block_index++ ) {
279 18         69 my $block = substr( $input, $block_index * 16, 16 );
280              
281 18         85 my $cfb_block = $self->encrypt_block( $last_block, $self->{key} );
282              
283 18         64 $last_block = $block ^ $cfb_block;
284 18         138 $cipher_text .= $last_block;
285             }
286              
287 9         220 return $cipher_text;
288             }
289              
290             sub _encrypt_mode_ofb {
291 18     18   41 my $self = shift;
292 18         27 my $input = shift;
293              
294 18         47 my $last_block = $self->{iv};
295              
296 18         31 my $cipher_text = '';
297 18         135 for( my $block_index = 0; $block_index < ( length($input) / 16 ); $block_index++ ) {
298 36         147 my $block = substr( $input, $block_index * 16, 16 );
299              
300 36         177 my $ofb_block = $self->encrypt_block( $last_block, $self->{key} );
301              
302 36         149 $cipher_text .= $block ^ $ofb_block;
303 36         316 $last_block = $ofb_block;
304             }
305              
306 18         319 return $cipher_text;
307             }
308              
309             sub decrypt {
310 45     45 1 19421 my $self = shift;
311 45         105 my $input = shift;
312              
313             ## no critic (ControlStructures::ProhibitCascadingIfElse)
314 45 100       186 if( $self->{mode} == MODE_ECB() ) {
    100          
    100          
    100          
    50          
315 9         28 return $self->_decrypt_mode_ecb( $input );
316             }
317             elsif( $self->{mode} == MODE_CBC() ) {
318 9         43 return $self->_decrypt_mode_cbc( $input );
319             }
320             elsif( $self->{mode} == MODE_CTR() ) {
321 9         45 return $self->_decrypt_mode_ctr( $input );
322             }
323             elsif( $self->{mode} == MODE_CFB() ) {
324 9         35 return $self->_decrypt_mode_cfb( $input );
325             }
326             elsif( $self->{mode} == MODE_OFB() ) {
327 9         35 return $self->_decrypt_mode_ofb( $input );
328             }
329             else {
330 0         0 croak "Invalid Mode specified";
331             }
332             ## use critic
333             }
334              
335             sub _decrypt_mode_ecb {
336 9     9   13 my $self = shift;
337 9         9 my $input = shift;
338              
339 9         12 my $plain_text = '';
340 9         41 for( my $block_index = 0; $block_index < ( length($input) / 16 ); $block_index++ ) {
341 18         60 my $cipher_block = substr( $input, $block_index * 16, 16 );
342              
343 18         57 $plain_text .= $self->decrypt_block( $cipher_block, $self->{key} );
344             }
345              
346 9         102 return $plain_text;
347             }
348              
349             sub _decrypt_mode_cbc {
350 9     9   17 my $self = shift;
351 9         19 my $input = shift;
352              
353 9         13 my $last_cipher_block;
354              
355 9         20 my $plain_text = '';
356 9         60 for( my $block_index = 0; $block_index < ( length($input) / 16 ); $block_index++ ) {
357 18         122 my $cipher_block = substr( $input, $block_index * 16, 16 );
358              
359 18         80 my $plain_block = $self->decrypt_block( $cipher_block, $self->{key} );
360              
361 18 100       89 if( $block_index == 0 ) {
362 9         38 $plain_block = $plain_block ^ $self->{iv};
363             }
364             else {
365 9         37 $plain_block = $plain_block ^ $last_cipher_block;
366             }
367              
368 18         47 $last_cipher_block = $cipher_block;
369 18         139 $plain_text .= $plain_block;
370             }
371              
372 9         151 return $plain_text;
373             }
374              
375             sub _decrypt_mode_ctr {
376 9     9   17 my $self = shift;
377 9         17 my $input = shift;
378              
379 9         44 return $self->_encrypt_mode_ctr( $input );
380             }
381              
382             sub _decrypt_mode_cfb {
383 9     9   17 my $self = shift;
384 9         19 my $input = shift;
385              
386 9         18 my $last_block = $self->{iv};
387              
388 9         22 my $plain_text = '';
389 9         57 for( my $block_index = 0; $block_index < ( length($input) / 16 ); $block_index++ ) {
390 18         59 my $cipher_block = substr( $input, $block_index * 16, 16 );
391              
392 18         79 my $cfb_block = $self->encrypt_block( $last_block, $self->{key} );
393              
394 18         58 $last_block = $cipher_block;
395 18         148 $plain_text .= $cfb_block ^ $cipher_block;
396             }
397              
398 9         142 return $plain_text;
399             }
400              
401             sub _decrypt_mode_ofb {
402 9     9   17 my $self = shift;
403 9         18 my $input = shift;
404              
405 9         41 return $self->_encrypt_mode_ofb( $input );
406             }
407              
408             sub encrypt_block {
409 150     150 0 16170 my $self = shift;
410 150         275 my $input = shift;
411 150         267 my $key = shift;
412              
413 150         843 my $bits_in_initial_key = length( unpack("H*", $key ) ) * 4;
414 150         990 my $number_of_rounds = $NUM_ROUNDS->{ $bits_in_initial_key };
415             ##### Number of Bits in Initial Key : ( $bits_in_initial_key )
416             ##### Words In Initial Key : ( $bits_in_initial_key / ( 8 * 4 ) )
417             ##### Number of Rounds : ( $number_of_rounds )
418              
419 150         1326 my $state = $self->_input_to_state( $input );
420             #### Inital State: ( generate_printable_state( $state ) )
421              
422 150         776 my $key_schedule = $self->_ExpandKey( $key );
423             #### Key Schedule: ( unpack("H*", $key_schedule ) )
424              
425 150         594 $self->_AddRoundKey($state, $key_schedule, 0);
426             #### State After Round 0 AddRoundKey: ( generate_printable_state( $state ) )
427              
428 150         472 for( my $round = 1; $round < $number_of_rounds; $round++ ) {
429             #### Processing Round Number: ( $round )
430              
431 1650         3716 $self->_SubBytes( $state );
432             #### State after SubBytes: ( generate_printable_state( $state ) )
433              
434 1650         3589 $self->_ShiftRows( $state );
435             #### State after ShiftRows: ( generate_printable_state( $state ) )
436              
437 1650         3110 $self->_MixColumns( $state );
438             #### State after MixColumns: ( generate_printable_state( $state ) )
439              
440 1650         3686 $self->_AddRoundKey( $state, $key_schedule, $round );
441             #### State after AddRoundKey: ( generate_printable_state( $state ) )
442             }
443              
444             #### Performing final transforms...
445              
446 150         429 $self->_SubBytes( $state );
447             #### State after SubBytes: ( generate_printable_state( $state ) )
448              
449 150         441 $self->_ShiftRows( $state );
450             #### State after ShiftRows: ( generate_printable_state( $state ) )
451              
452 150         678 $self->_AddRoundKey( $state, $key_schedule, $number_of_rounds );
453             #### State after AddRoundKey: ( generate_printable_state( $state ) )
454              
455 150         629 return $self->_state_to_output( $state );
456             }
457              
458             sub decrypt_block {
459 42     42 0 7670 my $self = shift;
460 42         61 my $input = shift;
461 42         59 my $key = shift;
462              
463 42         202 my $bits_in_initial_key = length( unpack("H*", $key ) ) * 4;
464 42         211 my $number_of_rounds = $NUM_ROUNDS->{ $bits_in_initial_key };
465             ##### Number of Bits in Initial Key : ( $bits_in_initial_key )
466             ##### Words In Initial Key : ( $bits_in_initial_key / ( 8 * 4 ) )
467             ##### Number of Rounds : ( $number_of_rounds )
468              
469 42         323 my $state = $self->_input_to_state( $input );
470             #### Inital State: ( generate_printable_state( $state ) )
471              
472 42         133 my $key_schedule = $self->_ExpandKey( $key );
473             #### Key Schedule: ( unpack("H*", $key_schedule ) )
474              
475 42         137 $self->_AddRoundKey($state, $key_schedule, $number_of_rounds);
476             #### State After Round 0 AddRoundKey: ( generate_printable_state( $state ) )
477              
478 42         121 for( my $round = $number_of_rounds - 1; $round > 0; $round-- ) {
479             #### Processing Round Number: ( $round )
480              
481 462         968 $self->_InvShiftRows( $state );
482             #### State After InvShiftRows: ( generate_printable_state( $state ) )
483              
484 462         947 $self->_InvSubBytes( $state );
485             #### State After InvSubBytes: ( generate_printable_state( $state ) )
486              
487 462         922 $self->_AddRoundKey( $state, $key_schedule, $round );
488             #### State After AddRoundKey: ( generate_printable_state( $state ) )
489              
490 462         909 $self->_InvMixColumns( $state );
491             #### State After InvMixColumns: ( generate_printable_state( $state ) )
492             }
493              
494             #### Performing final transforms...
495              
496 42         150 $self->_InvShiftRows( $state );
497             #### State After InvShiftRows: ( generate_printable_state( $state ) )
498              
499 42         96 $self->_InvSubBytes( $state );
500             #### State After InvSubBytes: ( generate_printable_state( $state ) )
501              
502 42         115 $self->_AddRoundKey( $state, $key_schedule, 0 );
503             #### State After AddRoundKey: ( generate_printable_state( $state ) )
504              
505 42         137 return $self->_state_to_output( $state );
506             }
507              
508             sub _SubBytes {
509 1801     1801   1956 my $self = shift;
510 1801         1611 my $state = shift;
511              
512 1801         4301 return $self->_sub_bytes( $state, \@SBOX );
513             }
514              
515             sub _InvSubBytes {
516 505     505   507 my $self = shift;
517 505         455 my $state = shift;
518              
519 505         1112 return $self->_sub_bytes( $state, \@INVSBOX );
520             }
521              
522             sub _sub_bytes {
523 2306     2306   2521 my $self = shift;
524 2306         2142 my $state = shift;
525 2306         2276 my $sbox = shift;
526              
527 2306         4582 for( my $column_index = 0; $column_index < 4; $column_index++ ) {
528 9224         15495 for( my $row_index = 0; $row_index < 4; $row_index++ ) {
529 36896         39183 my $original_byte = $state->[$row_index][$column_index];
530              
531 36896         53546 my $xy = unpack( "H2", $original_byte );
532 36896         40309 my $x = substr( $xy, 0, 1 );
533 36896         32824 my $y = substr( $xy, 1, 1 );
534              
535 36896         108357 my $substituted_byte = pack( "C", $sbox->[
536             ( hex($x) * 16 ) + hex($y)
537             ]);
538              
539             ##### Row Index : ( $row_index )
540             ##### Column Index : ( $column_index )
541             ##### X Coordinate : ( $x )
542             ##### Y Coordinate : ( $y )
543             ##### Original Byte : ( unpack "H2", $original_byte )
544             ##### Substituted Byte : ( unpack "H2", $substituted_byte )
545              
546 36896         211067 $state->[$row_index][$column_index] = $substituted_byte;
547             }
548             }
549              
550 2306         3386 return $state;
551             }
552              
553             sub _ShiftRows {
554 1801     1801   2026 my $self = shift;
555 1801         1831 my $state = shift;
556              
557             # Row 0 does not shift
558 1801         3587 for( my $row_index = 1; $row_index < 4; $row_index++ ) {
559 5403         8358 $self->_shift_row( $state->[$row_index], $row_index );
560             }
561              
562 1801         2918 return $state;
563             }
564              
565             sub _shift_row {
566 5407     5407   12650 my $self = shift;
567 5407         4358 my $row = shift;
568 5407         4340 my $num_bytes = shift;
569              
570 5407         8699 for( my $shift_round = 0; $shift_round < $num_bytes; $shift_round++ ) {
571 10812         8535 push ( @{ $row }, shift @{ $row });
  10812         11030  
  10812         24446  
572             }
573              
574 5407         10389 return $row;
575             }
576              
577             sub _MixColumns {
578 1651     1651   1719 my $self = shift;
579 1651         1520 my $state = shift;
580              
581 1651         3141 for( my $column = 0; $column < 4; $column++ ) {
582 6604         28777 my $mixed_column = $self->_mix_column([
583             unpack( "C", $state->[0][$column] ),
584             unpack( "C", $state->[1][$column] ),
585             unpack( "C", $state->[2][$column] ),
586             unpack( "C", $state->[3][$column] ),
587             ]);
588              
589 6604         13337 $state->[0][$column] = $mixed_column->[0];
590 6604         7721 $state->[1][$column] = $mixed_column->[1];
591 6604         7331 $state->[2][$column] = $mixed_column->[2];
592 6604         18425 $state->[3][$column] = $mixed_column->[3];
593             }
594              
595 1651         1985 return $state;
596             }
597              
598             sub _mix_column {
599 6605     6605   7888 my $self = shift;
600 6605         5599 my $column = shift;
601              
602 6605         6608 my $s0 = $column->[0];
603 6605         6873 my $s1 = $column->[1];
604 6605         6006 my $s2 = $column->[2];
605 6605         6004 my $s3 = $column->[3];
606              
607 6605         14625 my $s0_prime =
608             pack( "C", gf_multiply( 0x02, $s0 ) )
609             ^ pack( "C", gf_multiply( 0x03, $s1 ) )
610             ^ pack( "C", $s2 )
611             ^ pack( "C", $s3 );
612              
613             ##### S0 => S0_Prime : ( unpack( "H2", $s0 ) . " => " . unpack( "H2", $s0_prime ) )
614              
615 6605         42541 my $s1_prime =
616             pack( "C", $s0 )
617             ^ pack( "C", gf_multiply( 0x02, $s1 ) )
618             ^ pack( "C", gf_multiply( 0x03, $s2 ) )
619             ^ pack( "C", $s3 );
620              
621             ##### S1 => S1_Prime : ( unpack( "H2", $s1 ) . " => " . unpack( "H2", $s1_prime ) )
622              
623 6605         40631 my $s2_prime =
624             pack( "C", $s0 )
625             ^ pack( "C", $s1 )
626             ^ pack( "C", gf_multiply( 0x02, $s2 ) )
627             ^ pack( "C", gf_multiply( 0x03, $s3 ) );
628              
629             ##### S2 => S2_Prime : ( unpack( "H2", $s2 ) . " => " . unpack( "H2", $s2_prime ) )
630              
631 6605         33492 my $s3_prime =
632             pack( "C", gf_multiply( 0x03, $s0 ) )
633             ^ pack( "C", $s1 )
634             ^ pack( "C", $s2 )
635             ^ pack( "C", gf_multiply( 0x02, $s3 ) );
636              
637             ##### S3 => S3_Prime : ( unpack( "H2", $s3 ) . " => " . unpack( "H2", $s3_prime ) )
638              
639 6605         40187 return [ $s0_prime, $s1_prime, $s2_prime, $s3_prime ];
640             }
641              
642             sub _InvMixColumns {
643 463     463   506 my $self = shift;
644 463         408 my $state = shift;
645              
646 463         965 for( my $column = 0; $column < 4; $column++ ) {
647 1852         7512 my $mixed_column = $self->_inv_mix_column([
648             unpack( "C", $state->[0][$column] ),
649             unpack( "C", $state->[1][$column] ),
650             unpack( "C", $state->[2][$column] ),
651             unpack( "C", $state->[3][$column] ),
652             ]);
653              
654 1852         3671 $state->[0][$column] = $mixed_column->[0];
655 1852         2059 $state->[1][$column] = $mixed_column->[1];
656 1852         2055 $state->[2][$column] = $mixed_column->[2];
657 1852         5207 $state->[3][$column] = $mixed_column->[3];
658             }
659              
660 463         1170 return $state;
661             }
662              
663             sub _inv_mix_column {
664 1853     1853   2786 my $self = shift;
665 1853         1525 my $column = shift;
666              
667 1853         1759 my $s0 = $column->[0];
668 1853         1666 my $s1 = $column->[1];
669 1853         1576 my $s2 = $column->[2];
670 1853         1510 my $s3 = $column->[3];
671              
672 1853         3895 my $s0_prime =
673             pack( "C", gf_multiply( 0x0e, $s0 ) )
674             ^ pack( "C", gf_multiply( 0x0b, $s1 ) )
675             ^ pack( "C", gf_multiply( 0x0d, $s2 ) )
676             ^ pack( "C", gf_multiply( 0x09, $s3 ) );
677              
678             ##### S0 => S0_Prime : ( unpack( "H2", $s0 ) . " => " . unpack( "H2", $s0_prime ) )
679              
680 1853         10117 my $s1_prime =
681             pack( "C", gf_multiply( 0x09, $s0 ) )
682             ^ pack( "C", gf_multiply( 0x0e, $s1 ) )
683             ^ pack( "C", gf_multiply( 0x0b, $s2 ) )
684             ^ pack( "C", gf_multiply( 0x0d, $s3 ) );
685              
686             ##### S1 => S1_Prime : ( unpack( "H2", $s1 ) . " => " . unpack( "H2", $s1_prime ) )
687              
688 1853         9720 my $s2_prime =
689             pack( "C", gf_multiply( 0x0d, $s0 ) )
690             ^ pack( "C", gf_multiply( 0x09, $s1 ) )
691             ^ pack( "C", gf_multiply( 0x0e, $s2 ) )
692             ^ pack( "C", gf_multiply( 0x0b, $s3 ) );
693              
694             ##### S2 => S2_Prime : ( unpack( "H2", $s2 ) . " => " . unpack( "H2", $s2_prime ) )
695              
696 1853         9453 my $s3_prime =
697             pack( "C", gf_multiply( 0x0b, $s0 ) )
698             ^ pack( "C", gf_multiply( 0x0d, $s1 ) )
699             ^ pack( "C", gf_multiply( 0x09, $s2 ) )
700             ^ pack( "C", gf_multiply( 0x0e, $s3 ) );
701              
702             ##### S3 => S3_Prime : ( unpack( "H2", $s3 ) . " => " . unpack( "H2", $s3_prime ) )
703              
704 1853         10724 return [ $s0_prime, $s1_prime, $s2_prime, $s3_prime ];
705             }
706              
707             sub _AddRoundKey {
708 2498     2498   3035 my $self = shift;
709 2498         2238 my $state = shift;
710 2498         3109 my $key_schedule = shift;
711 2498         2389 my $round = shift;
712              
713 2498         4786 my $relevant_key_schedule = substr( $key_schedule, ($round * 16), 16 );
714             ##### Full Key Schedule : ( unpack("H*", $key_schedule ) )
715             ##### Relevant Portion of Key Schedule : ( unpack("H*", $relevant_key_schedule ) )
716              
717 2498         5166 for( my $column = 0; $column < 4; $column++ ) {
718             ##### Processing Column : ( $column )
719              
720 9992         11625 my $key_word = substr( $relevant_key_schedule, ($column * 4 ), 4 );
721 9992         28577 my $state_column = pack( "C4", (
722             unpack( "C", $state->[0][$column] ),
723             unpack( "C", $state->[1][$column] ),
724             unpack( "C", $state->[2][$column] ),
725             unpack( "C", $state->[3][$column] ),
726             ) );
727             ##### Key Word : ( unpack("B*", $key_word ) . " - " . unpack("H*", $key_word ) )
728             ##### State Column : ( unpack("B*", $state_column ) . " - " . unpack("H*", $state_column ) )
729              
730 9992         13048 my $int_key_word = unpack( "N1", $key_word );
731 9992         10440 my $int_state_column = unpack( "N1", $state_column );
732 9992         9364 my $xored_column = $int_key_word ^ $int_state_column;
733             ##### Int Key Word : ( unpack("B*", pack( "N", $int_key_word ) ) . " - " . unpack("H*", pack( "N", $int_key_word ) ) )
734             ##### Int State Column : ( unpack("B*", pack( "N", $int_state_column ) ) . " - " . unpack("H*", pack( "N", $int_state_column ) ) )
735             ##### XOR'ed Column : ( unpack("B*", pack( "N", $xored_column ) ) . " - " . unpack("H*", pack( "N", $xored_column ) ) )
736              
737 9992         19478 $state->[0][$column] = pack("C", unpack( "x0C", pack( "N1", $xored_column ) ) );
738 9992         17404 $state->[1][$column] = pack("C", unpack( "x1C", pack( "N1", $xored_column ) ) );
739 9992         25046 $state->[2][$column] = pack("C", unpack( "x2C", pack( "N1", $xored_column ) ) );
740 9992         28685 $state->[3][$column] = pack("C", unpack( "x3C", pack( "N1", $xored_column ) ) );
741             ##### Value of State Row 0 : ( unpack("H*", $state->[0][$column] ) )
742             ##### Value of State Row 1 : ( unpack("H*", $state->[1][$column] ) )
743             ##### Value of State Row 2 : ( unpack("H*", $state->[2][$column] ) )
744             ##### Value of State Row 3 : ( unpack("H*", $state->[3][$column] ) )
745             }
746              
747 2498         5505 return $state;
748             }
749              
750             sub _ExpandKey {
751 196     196   208203 my $self = shift;
752 196         319 my $key = shift;
753              
754             ##### Initial Key: ( unpack("H*", $key ) )
755              
756 196         343 my $expanded_key = $key;
757              
758             # Nb * (Nr + 1)
759 196         714 my $bits_in_initial_key = length( unpack("H*", $key ) ) * 4;
760 196         499 my $words_in_key = $bits_in_initial_key / ( 8 * 4 );
761 196         626 my $number_of_rounds = 4 * ( $NUM_ROUNDS->{ $bits_in_initial_key } + 1);
762             ##### Number of Bits in Initial Key : ( $bits_in_initial_key )
763             ##### Words In Initial Key : ( $words_in_key )
764             ##### Number of Rounds : ( $number_of_rounds )
765              
766 196         1637 for( my $expansion_round = $words_in_key; $expansion_round < $number_of_rounds; $expansion_round++ ) {
767             ##### Expansion Round: ( $expansion_round )
768              
769 9010         11026 my $temp = substr( $expanded_key, ($expansion_round * 4) - 4, 4 );
770             ##### Temp : ( unpack("B*", $temp ) . " - " . unpack("H*", $temp ) )
771              
772 9010 100 100     28820 if( $expansion_round % $words_in_key == 0 ) {
    100          
773             ##### Performing Transformation...
774              
775 1635         3344 my $rotted_word = $self->_RotWord( $temp );
776             ##### Rotted Word : ( unpack("B*", $rotted_word ) . " - " . unpack("H*", $rotted_word ) )
777              
778 1635         3016 my $subbed_word = $self->_SubWord( $rotted_word );
779             ##### Subbed Word : ( unpack("B*", $subbed_word ) . " - " . unpack("H*", $subbed_word ) )
780              
781 1635         2613 my $int_subbed_word = unpack( "N1", $subbed_word );
782 1635         4922 $temp = $int_subbed_word ^ $RCONST[ $expansion_round / $words_in_key ];
783             ##### Int Subbed Word : ( unpack("B*", pack( "N", $int_subbed_word ) ) . " - " . unpack("H*", pack( "N", $int_subbed_word ) ) )
784             ##### Index into RCON : ( $expansion_round / $words_in_key )
785             ##### RCON : ( unpack("B*", pack( "N", $RCONST[$expansion_round / $words_in_key] ) ) . " - " . unpack("H*", pack( "N", $RCONST[$expansion_round / $words_in_key] ) ) )
786             ##### Xored Result : ( unpack("B*", pack( "N", $temp ) ) . " - " . unpack("H*", pack("N", $temp ) ) )
787              
788 1635         8457 $temp = pack("N1", $temp );
789             ##### Temp : ( unpack("B*", $temp ) . " - " . unpack("H*", $temp ) )
790             }
791             elsif( $words_in_key > 6 && $expansion_round % $words_in_key == 4 ) {
792             ##### Performing 256 Bit Transform...
793              
794 390         727 $temp = $self->_SubWord( $temp );
795             ##### Subbed Word : ( unpack("B*", $temp ) . " - " . unpack("H*", $temp ) )
796             }
797              
798 9010         11168 my $previous_word = substr( $expanded_key, ($expansion_round * 4) - ( $words_in_key * 4 ), 4 );
799 9010         11160 my $int_previous_word = unpack( "N1", $previous_word );
800 9010         10392 my $new_word = $int_previous_word ^ unpack("N1", $temp);
801             ##### Previous Word : ( unpack("B*", $previous_word) . " - " . unpack("H*", $previous_word ) )
802             ##### Int Previous Word : ( unpack("B*", pack("N", $int_previous_word)) . " - " . unpack("H*", pack("N", $int_previous_word ) ) )
803             ##### New Word : ( unpack("B*", pack("N", $new_word ) ) . " - " . unpack("H*", pack("N", $new_word ) ) )
804              
805 9010         21283 $expanded_key .= pack("N1", $new_word);
806             ##### Expanded Key : ( unpack("H*", $expanded_key ) )
807             }
808              
809 196         583 return $expanded_key;
810             }
811              
812             sub _SubWord {
813 2026     2026   3374 my $self = shift;
814 2026         2053 my $word = shift;
815              
816 2026         2073 my $subbed_word = "";
817 2026         3939 for( my $byte_index = 0; $byte_index < 4; $byte_index++ ) {
818 8104         8624 my $original_byte = substr( $word, $byte_index, 1 );
819              
820 8104         11919 my $xy = unpack( "H2", $original_byte );
821 8104         8364 my $x = substr( $xy, 0, 1 );
822 8104         7137 my $y = substr( $xy, 1, 1 );
823              
824 8104         24445 my $substituted_byte = pack( "C", $SBOX[
825             ( 16 * hex($x) ) + hex($y)
826             ]);
827              
828             ##### Byte Index : ( $byte_index )
829             ##### X Coordinate : ( $x )
830             ##### Y Coordinate : ( $y )
831             ##### Original Byte : ( unpack "H2", $original_byte )
832             ##### Substituted Byte : ( unpack "H2", $substituted_byte )
833              
834 8104         45198 $subbed_word .= $substituted_byte;
835             }
836              
837 2026         3290 return $subbed_word;
838             }
839              
840             sub _RotWord {
841 1636     1636   4869 my $self = shift;
842 1636         1698 my $word = shift;
843              
844 1636         1504 my @byte_array;
845 1636         3417 for( my $byte_index = 0; $byte_index < 4; $byte_index++ ) {
846 6544         13343 push @byte_array, substr( $word, $byte_index, 1 );
847             }
848              
849 1636         2008 push (@byte_array, shift @byte_array);
850              
851 1636         4646 return join('', @byte_array );
852             }
853              
854             sub _input_to_state {
855 211     211   33680 my $self = shift;
856 211         363 my $input = shift;
857              
858             ##### Input : ( unpack( "H*", $input ) )
859             ##### Length of Input : ( length $input )
860              
861 211 100       810 if( length $input != 16 ) {
862 2         43 croak "Invalid Input Length, Must be 128 Bits";
863             }
864              
865 209         299 my $state;
866              
867 209         311 my $byte_index = 0;
868 209         854 for( my $column_index = 0; $column_index < 4; $column_index++ ) {
869 836         1653 for( my $row_index = 0; $row_index < 4; $row_index++ ) {
870 3344         6248 my $byte = unpack("x" . ( $byte_index++ ) . "a", $input );
871              
872             ##### Row Index : ( $row_index )
873             ##### Column Index : ( $column_index )
874             ##### Byte Index : ( $byte_index )
875             ##### Raw Byte : ( $byte )
876             ##### Byte : ( unpack "H2", $byte )
877              
878 3344         8141 $state->[$row_index][$column_index] = $byte;
879             }
880             }
881              
882 209         486 return $state;
883             }
884              
885             sub _state_to_output {
886 192     192   347 my $self = shift;
887 192         275 my $state = shift;
888              
889 192         308 my $output = "";
890              
891 192         734 for( my $column_index = 0; $column_index < 4; $column_index++ ) {
892 768         1442 for( my $row_index = 0; $row_index < 4; $row_index++ ) {
893 3072         6420 $output .= $state->[$row_index][$column_index];
894             }
895             }
896              
897 192         1617 return $output;
898             }
899              
900             sub _InvShiftRows {
901 505     505   553 my $self = shift;
902 505         466 my $state = shift;
903              
904             # Row 0 does not shift
905 505         989 for( my $row_index = 1; $row_index < 4; $row_index++ ) {
906 1515         2422 $self->_inv_shift_row( $state->[$row_index], $row_index );
907             }
908              
909 505         586 return $state;
910             }
911             sub _inv_shift_row {
912 1519     1519   6998 my $self = shift;
913 1519         1180 my $row = shift;
914 1519         1207 my $num_bytes = shift;
915              
916 1519         2452 for( my $shift_round = 0; $shift_round < $num_bytes; $shift_round++ ) {
917 3036         2177 unshift ( @{ $row }, pop @{ $row });
  3036         2779  
  3036         6876  
918             }
919              
920 1519         2974 return $row;
921             }
922              
923             1;