Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
| Download
Views: 549
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <assert.h>
5
#include "des.h"
6
#include "hex.h"
7
8
// This does not return a 1 for a 1 bit; it just returns non-zero
9
#define GET_BIT( array, bit ) \
10
( array[ ( int ) ( bit / 8 ) ] & ( 0x80 >> ( bit % 8 ) ) )
11
#define SET_BIT( array, bit ) \
12
( array[ ( int ) ( bit / 8 ) ] |= ( 0x80 >> ( bit % 8 ) ) )
13
#define CLEAR_BIT( array, bit ) \
14
( array[ ( int ) ( bit / 8 ) ] &= ~( 0x80 >> ( bit % 8 ) ) )
15
16
static void xor( unsigned char *target, const unsigned char *src, int len )
17
{
18
while ( len-- )
19
{
20
*target++ ^= *src++;
21
}
22
}
23
24
/**
25
* Implement the initial and final permutation functions. permute_table
26
* and target must have exactly len and len * 8 number of entries,
27
* respectively, but src can be shorter (expansion function depends on this).
28
* NOTE: this assumes that the permutation tables are defined as one-based
29
* rather than 0-based arrays, since they're given that way in the
30
* specification.
31
*/
32
static void permute( unsigned char target[],
33
const unsigned char src[],
34
const int permute_table[],
35
int len )
36
{
37
int i;
38
for ( i = 0; i < len * 8; i++ )
39
{
40
if ( GET_BIT( src, ( permute_table[ i ] - 1 ) ) )
41
{
42
SET_BIT( target, i );
43
}
44
else
45
{
46
CLEAR_BIT( target, i );
47
}
48
}
49
}
50
51
static const int ip_table[] = {
52
58, 50, 42, 34, 26, 18, 10, 2,
53
60, 52, 44, 36, 28, 20, 12, 4,
54
62, 54, 46, 38, 30, 22, 14, 6,
55
64, 56, 48, 40, 32, 24, 16, 8,
56
57, 49, 41, 33, 25, 17, 9, 1,
57
59, 51, 43, 35, 27, 19, 11, 3,
58
61, 53, 45, 37, 29, 21, 13, 5,
59
63, 55, 47, 39, 31, 23, 15, 7 };
60
61
/**
62
* This just inverts ip_table.
63
*/
64
static const int fp_table[] = { 40, 8, 48, 16, 56, 24, 64, 32,
65
39, 7, 47, 15, 55, 23, 63, 31,
66
38, 6, 46, 14, 54, 22, 62, 30,
67
37, 5, 45, 13, 53, 21, 61, 29,
68
36, 4, 44, 12, 52, 20, 60, 28,
69
35, 3, 43, 11, 51, 19, 59, 27,
70
34, 2, 42, 10, 50, 18, 58, 26,
71
33, 1, 41, 9, 49, 17, 57, 25 };
72
73
static const int pc1_table[] = { 57, 49, 41, 33, 25, 17, 9, 1,
74
58, 50, 42, 34, 26, 18, 10, 2,
75
59, 51, 43, 35, 27, 19, 11, 3,
76
60, 52, 44, 36,
77
63, 55, 47, 39, 31, 23, 15, 7,
78
62, 54, 46, 38, 30, 22, 14, 6,
79
61, 53, 45, 37, 29, 21, 13, 5,
80
28, 20, 12, 4 };
81
82
static const int pc2_table[] = { 14, 17, 11, 24, 1, 5,
83
3, 28, 15, 6, 21, 10,
84
23, 19, 12, 4, 26, 8,
85
16, 7, 27, 20, 13, 2,
86
41, 52, 31, 37, 47, 55,
87
30, 40, 51, 45, 33, 48,
88
44, 49, 39, 56, 34, 53,
89
46, 42, 50, 36, 29, 32 };
90
91
/**
92
* Perform the left rotation operation on the key. This is made fairly
93
* complex by the fact that the key is split into two 28-bit halves, each
94
* of which has to be rotated independently (so the second rotation operation
95
* starts in the middle of byte 3).
96
*/
97
static void rol( unsigned char *target )
98
{
99
int carry_left, carry_right;
100
101
carry_left = ( target[ 0 ] & 0x80 ) >> 3;
102
103
target[ 0 ] = ( target[ 0 ] << 1 ) | ( ( target[ 1 ] & 0x80 ) >> 7 );
104
target[ 1 ] = ( target[ 1 ] << 1 ) | ( ( target[ 2 ] & 0x80 ) >> 7 );
105
target[ 2 ] = ( target[ 2 ] << 1 ) | ( ( target[ 3 ] & 0x80 ) >> 7 );
106
107
// special handling for byte 3
108
carry_right = ( target[ 3 ] & 0x08 ) >> 3;
109
target[ 3 ] = ( ( ( target[ 3 ] << 1 ) |
110
( ( target[ 4 ] & 0x80 ) >> 7 ) ) & ~0x10 ) | carry_left;
111
112
target[ 4 ] = ( target[ 4 ] << 1 ) | ( ( target[ 5 ] & 0x80 ) >> 7 );
113
target[ 5 ] = ( target[ 5 ] << 1 ) | ( ( target[ 6 ] & 0x80 ) >> 7 );
114
target[ 6 ] = ( target[ 6 ] << 1 ) | carry_right;
115
}
116
117
static void ror(unsigned char *target )
118
{
119
int carry_left, carry_right;
120
121
carry_right = ( target[ 6 ] & 0x01 ) << 3;
122
123
target[ 6 ] = ( target[ 6 ] >> 1 ) | ( ( target[ 5 ] & 0x01 ) << 7 );
124
target[ 5 ] = ( target[ 5 ] >> 1 ) | ( ( target[ 4 ] & 0x01 ) << 7 );
125
target[ 4 ] = ( target[ 4 ] >> 1 ) | ( ( target[ 3 ] & 0x01 ) << 7 );
126
127
carry_left = ( target[ 3 ] & 0x10 ) << 3;
128
target[ 3 ] = ( ( ( target[ 3 ] >> 1 ) |
129
( ( target[ 2 ] & 0x01 ) << 7 ) ) & ~0x08 ) | carry_right;
130
131
target[ 2 ] = ( target[ 2 ] >> 1 ) | ( ( target[ 1 ] & 0x01 ) << 7 );
132
target[ 1 ] = ( target[ 1 ] >> 1 ) | ( ( target[ 0 ] & 0x01 ) << 7 );
133
target[ 0 ] = ( target[ 0 ] >> 1 ) | carry_left;
134
}
135
136
static const int expansion_table[] = {
137
32, 1, 2, 3, 4, 5,
138
4, 5, 6, 7, 8, 9,
139
8, 9, 10, 11, 12, 13,
140
12, 13, 14, 15, 16, 17,
141
16, 17, 18, 19, 20, 21,
142
20, 21, 22, 23, 24, 25,
143
24, 25, 26, 27, 28, 29,
144
28, 29, 30, 31, 32, 1 };
145
146
static const int sbox[8][64] = {
147
{ 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
148
3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
149
4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
150
15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 },
151
{ 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
152
9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
153
0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
154
5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 },
155
{ 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
156
1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
157
13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
158
11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 },
159
{ 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
160
1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
161
10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
162
15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14 },
163
{ 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
164
8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
165
4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
166
15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3 },
167
{ 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
168
0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
169
9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
170
7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13 },
171
{ 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
172
3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
173
1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
174
10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12 },
175
{ 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
176
10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
177
7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
178
0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 }
179
};
180
181
static const int p_table[] = { 16, 7, 20, 21,
182
29, 12, 28, 17,
183
1, 15, 23, 26,
184
5, 18, 31, 10,
185
2, 8, 24, 14,
186
32, 27, 3, 9,
187
19, 13, 30, 6,
188
22, 11, 4, 25 };
189
190
#define DES_BLOCK_SIZE 8 // 64 bits, defined in the standard
191
#define EXPANSION_BLOCK_SIZE 6
192
#define PC1_KEY_SIZE 7
193
#define SUBKEY_SIZE 6
194
195
typedef enum { OP_ENCRYPT, OP_DECRYPT } op_type;
196
197
void print_subkey(unsigned char sk[])
198
{
199
int i = 0;
200
for(i=0;i<SUBKEY_SIZE;i++)
201
printf("%02x",sk[i]);
202
puts("");
203
}
204
205
static void des_block_operate( const unsigned char plaintext[ DES_BLOCK_SIZE ],
206
unsigned char ciphertext[ DES_BLOCK_SIZE ],
207
const unsigned char key[ DES_KEY_SIZE ],
208
op_type operation )
209
{
210
// Holding areas; result flows from plaintext, down through these,
211
// finally into ciphertext. This could be made more memory efficient
212
// by reusing these.
213
unsigned char ip_block[ DES_BLOCK_SIZE ];
214
unsigned char expansion_block[ EXPANSION_BLOCK_SIZE ];
215
unsigned char substitution_block[ DES_BLOCK_SIZE / 2 ];
216
unsigned char pbox_target[ DES_BLOCK_SIZE / 2 ];
217
unsigned char recomb_box[ DES_BLOCK_SIZE / 2 ];
218
219
unsigned char pc1key[ PC1_KEY_SIZE ];
220
unsigned char subkey[ SUBKEY_SIZE ];
221
int round;
222
// Initial permutation
223
permute( ip_block, plaintext, ip_table, DES_BLOCK_SIZE );
224
225
// Key schedule computation
226
permute( pc1key, key, pc1_table, PC1_KEY_SIZE );
227
for ( round = 0; round < 16; round++ )
228
{
229
// "Feistel function" on the first half of the block in 'ip_block'
230
231
// "Expansion". This permutation only looks at the first
232
// four bytes (32 bits of ip_block); 16 of these are repeated
233
// in "expansion_table".
234
permute( expansion_block, ip_block + 4, expansion_table, 6 );
235
236
// "Key mixing"
237
// rotate both halves of the initial key
238
if ( operation == OP_ENCRYPT )
239
{
240
rol( pc1key );
241
if ( !( round <= 1 || round == 8 || round == 15 ) )
242
{
243
// Rotate twice except in rounds 1, 2, 9 & 16
244
rol( pc1key );
245
}
246
}
247
248
permute( subkey, pc1key, pc2_table, SUBKEY_SIZE );
249
print_subkey(subkey);
250
if ( operation == OP_DECRYPT )
251
{
252
ror( pc1key );
253
if ( !( round >= 14 || round == 7 || round == 0 ) )
254
{
255
// Rotate twice except in rounds 1, 2, 9 & 16
256
ror( pc1key );
257
}
258
}
259
260
xor( expansion_block, subkey, 6 );
261
262
// Substitution; "copy" from updated expansion block to ciphertext block
263
memset( ( void * ) substitution_block, 0, DES_BLOCK_SIZE / 2 );
264
substitution_block[ 0 ] =
265
sbox[ 0 ][ ( expansion_block[ 0 ] & 0xFC ) >> 2 ] << 4;
266
substitution_block[ 0 ] |=
267
sbox[ 1 ][ ( expansion_block[ 0 ] & 0x03 ) << 4 |
268
( expansion_block[ 1 ] & 0xF0 ) >> 4 ];
269
substitution_block[ 1 ] =
270
sbox[ 2 ][ ( expansion_block[ 1 ] & 0x0F ) << 2 |
271
( expansion_block[ 2 ] & 0xC0 ) >> 6 ] << 4;
272
substitution_block[ 1 ] |=
273
sbox[ 3 ][ ( expansion_block[ 2 ] & 0x3F ) ];
274
substitution_block[ 2 ] =
275
sbox[ 4 ][ ( expansion_block[ 3 ] & 0xFC ) >> 2 ] << 4;
276
substitution_block[ 2 ] |=
277
sbox[ 5 ][ ( expansion_block[ 3 ] & 0x03 ) << 4 |
278
( expansion_block[ 4 ] & 0xF0 ) >> 4 ];
279
substitution_block[ 3 ] =
280
sbox[ 6 ][ ( expansion_block[ 4 ] & 0x0F ) << 2 |
281
( expansion_block[ 5 ] & 0xC0 ) >> 6 ] << 4;
282
substitution_block[ 3 ] |=
283
sbox[ 7 ][ ( expansion_block[ 5 ] & 0x3F ) ];
284
285
// Permutation
286
permute( pbox_target, substitution_block, p_table, DES_BLOCK_SIZE / 2 );
287
288
// Recombination. XOR the pbox with left half and then switch sides.
289
memcpy( ( void * ) recomb_box, ( void * ) ip_block, DES_BLOCK_SIZE / 2 );
290
memcpy( ( void * ) ip_block, ( void * ) ( ip_block + 4 ),
291
DES_BLOCK_SIZE / 2 );
292
xor( recomb_box, pbox_target, DES_BLOCK_SIZE / 2 );
293
memcpy( ( void * ) ( ip_block + 4 ), ( void * ) recomb_box,
294
DES_BLOCK_SIZE / 2 );
295
}
296
297
// Swap one last time
298
memcpy( ( void * ) recomb_box, ( void * ) ip_block, DES_BLOCK_SIZE / 2 );
299
memcpy( ( void * ) ip_block, ( void * ) ( ip_block + 4 ), DES_BLOCK_SIZE / 2 );
300
memcpy( ( void * ) ( ip_block + 4 ), ( void * ) recomb_box,
301
DES_BLOCK_SIZE / 2 );
302
303
// Final permutation (undo initial permutation)
304
permute( ciphertext, ip_block, fp_table, DES_BLOCK_SIZE );
305
}
306
307
static void des_operate( const unsigned char *input,
308
int input_len,
309
unsigned char *output,
310
const unsigned char *iv,
311
const unsigned char *key,
312
op_type operation,
313
int triplicate )
314
{
315
unsigned char input_block[ DES_BLOCK_SIZE ];
316
317
assert( !( input_len % DES_BLOCK_SIZE ) );
318
319
while ( input_len )
320
{
321
memcpy( ( void * ) input_block, ( void * ) input, DES_BLOCK_SIZE );
322
if ( operation == OP_ENCRYPT )
323
{
324
xor( input_block, iv, DES_BLOCK_SIZE ); // implement CBC
325
des_block_operate( input_block, output, key, operation );
326
if ( triplicate )
327
{
328
memcpy( input_block, output, DES_BLOCK_SIZE );
329
des_block_operate( input_block, output, key + DES_KEY_SIZE,
330
OP_DECRYPT );
331
memcpy( input_block, output, DES_BLOCK_SIZE );
332
des_block_operate( input_block, output, key + ( DES_KEY_SIZE * 2 ),
333
operation );
334
}
335
memcpy( ( void * ) iv, ( void * ) output, DES_BLOCK_SIZE ); // CBC
336
}
337
338
if ( operation == OP_DECRYPT )
339
{
340
if ( triplicate )
341
{
342
des_block_operate( input_block, output, key + ( DES_KEY_SIZE * 2 ),
343
operation );
344
memcpy( input_block, output, DES_BLOCK_SIZE );
345
des_block_operate( input_block, output, key + DES_KEY_SIZE,
346
OP_ENCRYPT );
347
memcpy( input_block, output, DES_BLOCK_SIZE );
348
des_block_operate( input_block, output, key, operation );
349
}
350
else
351
{
352
des_block_operate( input_block, output, key, operation );
353
}
354
xor( output, iv, DES_BLOCK_SIZE );
355
memcpy( ( void * ) iv, ( void * ) input, DES_BLOCK_SIZE ); // CBC
356
}
357
358
input += DES_BLOCK_SIZE;
359
output += DES_BLOCK_SIZE;
360
input_len -= DES_BLOCK_SIZE;
361
}
362
}
363
364
void des_encrypt( const unsigned char *plaintext,
365
const int plaintext_len,
366
unsigned char *ciphertext,
367
void *iv,
368
const unsigned char *key )
369
{
370
des_operate( plaintext, plaintext_len, ciphertext,
371
( const unsigned char * ) iv, key, OP_ENCRYPT, 0 );
372
}
373
374
void des3_encrypt( const unsigned char *plaintext,
375
const int plaintext_len,
376
unsigned char *ciphertext,
377
void *iv,
378
const unsigned char *key )
379
{
380
des_operate( plaintext, plaintext_len, ciphertext,
381
( const unsigned char * ) iv, key, OP_ENCRYPT, 1 );
382
}
383
384
void des_decrypt( const unsigned char *ciphertext,
385
const int ciphertext_len,
386
unsigned char *plaintext,
387
void *iv,
388
const unsigned char *key )
389
{
390
des_operate( ciphertext, ciphertext_len, plaintext,
391
( const unsigned char * ) iv, key, OP_DECRYPT, 0 );
392
// Remove any padding on the end of the input
393
//plaintext[ ciphertext_len - plaintext[ ciphertext_len - 1 ] ] = 0x0;
394
}
395
396
void des3_decrypt( const unsigned char *ciphertext,
397
const int ciphertext_len,
398
unsigned char *plaintext,
399
void *iv,
400
const unsigned char *key )
401
{
402
des_operate( ciphertext, ciphertext_len, plaintext,
403
( const unsigned char * ) iv, key, OP_DECRYPT, 1 );
404
// Remove any padding on the end of the input
405
//plaintext[ ciphertext_len - plaintext[ ciphertext_len - 1 ] ] = 0x0;
406
}
407
408
//#ifdef TEST_DES
409
int main( int argc, char *argv[ ] )
410
{
411
unsigned char *key;
412
unsigned char *iv;
413
unsigned char *input;
414
int key_len;
415
int iv_len;
416
unsigned char *output;
417
int out_len, input_len;
418
419
if ( argc < 4 )
420
{
421
fprintf( stderr, "Usage: %s [-e|-d] <key> <iv> <input>\n", argv[ 0 ] );
422
exit( 0 );
423
}
424
425
key_len = hex_decode( argv[ 2 ], &key );
426
iv_len = hex_decode( argv[ 3 ], &iv );
427
input_len = hex_decode( argv[ 4 ], &input );
428
429
out_len = input_len = strlen( input );
430
output = ( unsigned char * ) malloc( out_len + 1 );
431
if ( !( strcmp( argv[ 1 ], "-e" ) ) )
432
{
433
if ( key_len == 24 )
434
{
435
des3_encrypt( input, input_len, output, iv, key );
436
}
437
else
438
{
439
des_encrypt( input, input_len, output, iv, key );
440
}
441
show_hex( output, out_len );
442
}
443
else if ( !( strcmp( argv[ 1 ], "-d" ) ) )
444
{
445
if ( key_len == 24 )
446
{
447
des3_decrypt( input, input_len, output, iv, key );
448
}
449
else
450
{
451
des_decrypt( input, input_len, output, iv, key );
452
}
453
show_hex( output, out_len );
454
}
455
else
456
{
457
fprintf( stderr, "Usage: %s [-e|-d] <key> <iv> <input>\n", argv[ 0 ] );
458
}
459
460
free( input );
461
free( iv );
462
free( key );
463
free( output );
464
465
return 0;
466
}
467
468
//#endif
469
470
/*
471
[jdavies@localhost ssl]$ ./des password initialz abcdefgh
472
71828547387b18e5
473
[jdavies@localhost ssl]$ ./des -d password initialz \
474
0x71828547387b18e5
475
6162636465666768
476
[jdavies@localhost ssl]$ ./des -e twentyfourcharacterinput initialz abcdefgh
477
c0c48bc47e87ce17
478
[jdavies@localhost ssl]$ ./des -d twentyfourcharacterinput initialz \
479
0xc0c48bc47e87ce17
480
6162636465666768
481
*/
482
483