-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtestfile1.c
4029 lines (3466 loc) · 127 KB
/
testfile1.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/*
* des takes two arguments on the command line:
* des -enc -ecb -- encrypt in ECB mode
* des -enc -ctr -- encrypt in CTR mode
* des -dec -ecb -- decrypt in ECB mode
* des -dec -ctr -- decrypt in CTR mode
* des also reads some hardcoded files:
* message.txt -- the ASCII text message to be encrypted,
* read by "des -enc"
* encrypted_msg.bin -- the encrypted message, a binary file,
* written by "des -enc"
* decrypted_message.txt -- the decrypted ASCII text message
* key.txt -- just contains the key, on a line by itself, as an ASCII
* hex number, such as: 0x34FA879B
*/
uint64_t
u8tou64(uint8_t const u8[static 8]){
uint64_t u64;
memcpy(&u64, u8, sizeof u64);
return u64;
}
unsigned createMask(unsigned a, unsigned b)
{
unsigned r = 0;
for (unsigned i=a; i<=b; i++)
r |= 1 << i;
return r;
}
/////////////////////////////////////////////////////////////////////////////
// Type definitions
/////////////////////////////////////////////////////////////////////////////
typedef uint64_t KEYTYPE;
typedef uint32_t SUBKEYTYPE;
typedef uint64_t BLOCKTYPE;
typedef uint32_t HALFBLOCKTYPE;
struct BLOCK {
BLOCKTYPE block; // the block read
int size; // number of "real" bytes in the block, should be 8, unless it's the last block
struct BLOCK *next; // pointer to the next block
};
struct BLOCKHEAD {
struct BLOCK *first; // first block
struct BLOCK *last; // last block
};
typedef struct BLOCK* BLOCKNODE;
typedef struct BLOCKHEAD* BLOCKLIST;
BLOCKLIST newBlockList() {
BLOCKLIST blocks = (BLOCKLIST)malloc(sizeof(struct BLOCKHEAD));
blocks->first = NULL;
blocks->last = NULL;
return blocks;
}
BLOCKNODE newBlock(uint64_t block, int size){
BLOCKNODE new_node = (BLOCKNODE) malloc(sizeof(struct BLOCK));
new_node->block = block;
new_node->size = size;
new_node->next = NULL;
return new_node;
}
void addBlockLast(BLOCKLIST list, BLOCKTYPE block, int size) {
BLOCKNODE currBlock = newBlock(block, size);
if (list->first == NULL) {
list->first = currBlock;
list->last = currBlock;
} else {
list->last->next = currBlock;
list->last = currBlock;
}
}
/////////////////////////////////////////////////////////////////////////////
// Debugging
/////////////////////////////////////////////////////////////////////////////
int debug = 1;
void print_blocklist(BLOCKLIST head) {
BLOCKNODE curr = head->first;
int x = 0;
assert(curr != NULL);
while (curr != NULL) {
printf("\tBLOCK [%d]: 0x%lx, size=%d\n", x, curr->block,curr->size);
x++;
curr = curr->next;
}
}
void print_block(struct BLOCK* head) {
printf("\tBLOCK : 0x%lx, size=%d\n", head->block,head->size);
}
/////////////////////////////////////////////////////////////////////////////
// Initial and final permutation
/////////////////////////////////////////////////////////////////////////////
uint64_t init_perm[] = {
58,50,42,34,26,18,10,2,
60,52,44,36,28,20,12,4,
62,54,46,38,30,22,14,6,
64,56,48,40,32,24,16,8,
57,49,41,33,25,17,9,1,
59,51,43,35,27,19,11,3,
61,53,45,37,29,21,13,5,
63,55,47,39,31,23,15,7
};
int final_perm[] = {
40,8,48,16,56,24,64,32,
39,7,47,15,55,23,63,31,
38,6,46,14,54,22,62,30,
37,5,45,13,53,21,61,29,
36,4,44,12,52,20,60,28,
35,3,43,11,51,19,59,27,
34,2,42,10,50,18,58,26,
33,1,41,9, 49,17,57,25
};
/////////////////////////////////////////////////////////////////////////////
// Subkey generation
/////////////////////////////////////////////////////////////////////////////
//SUBKEYTYPE subkeys[16];
KEYTYPE key = 0; // Global variable key
// This function returns the i:th subkey, 48 bits long. To simplify the assignment
// you can use a trivial implementation: just take the input key and xor it with i.
uint64_t getSubKey(int i) {
// TODO: return the first 48 bits of the 56 bit DES key, xor:ed with i.
return ((key ^ i) & 0xffffffffffff);
//return subkeys[i];
}
// For extra credit, write the real DES key expansion routine!
//SUBKEYTYPE* generateSubKeys(KEYTYPE key) {
// // TODO for extra credit
// for( int i = 0; i<16; i++){
// unsigned r = createMask(0,47);
// unsigned result = r & (key^i);
// subkeys[i] = result;
// }
// return subkeys;
//}
/////////////////////////////////////////////////////////////////////////////
// P-boxes
/////////////////////////////////////////////////////////////////////////////
uint64_t expand_box[] = {
32,1,2,3,4,5,4,5,6,7,8,9,
8,9,10,11,12,13,12,13,14,15,16,17,
16,17,18,19,20,21,20,21,22,23,24,25,
24,25,26,27,28,29,28,29,30,31,32,1
};
uint32_t Pbox[] =
{
16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,
2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25,
};
/////////////////////////////////////////////////////////////////////////////
// S-boxes
/////////////////////////////////////////////////////////////////////////////
uint64_t sbox_1[4][16] = {
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10 , 6, 12, 5, 9, 0, 7},
{ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}};
uint64_t sbox_2[4][16] = {
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5 ,10},
{ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
{ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}};
uint64_t sbox_3[4][16] = {
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
{ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}};
uint64_t sbox_4[4][16] = {
{ 7, 13, 14, 3, 0 , 6, 9, 10, 1 , 2 , 8, 5, 11, 12, 4 ,15},
{13, 8, 11, 5, 6, 15, 0, 3, 4 , 7 , 2, 12, 1, 10, 14, 9},
{10, 6, 9 , 0, 12, 11, 7, 13 ,15 , 1 , 3, 14 , 5 , 2, 8, 4},
{ 3, 15, 0, 6, 10, 1, 13, 8, 9 , 4 , 5, 11 ,12 , 7, 2, 14}};
uint64_t sbox_5[4][16] = {
{ 2, 12, 4, 1 , 7 ,10, 11, 6 , 8 , 5 , 3, 15, 13, 0, 14, 9},
{14, 11 , 2 ,12 , 4, 7, 13 , 1 , 5 , 0, 15, 10, 3, 9, 8, 6},
{ 4, 2 , 1, 11, 10, 13, 7 , 8 ,15 , 9, 12, 5, 6 , 3, 0, 14},
{11, 8 ,12 , 7 , 1, 14 , 2 ,13 , 6 ,15, 0, 9, 10 , 4, 5, 3}};
uint64_t sbox_6[4][16] = {
{12, 1, 10, 15 , 9 , 2 , 6 , 8 , 0, 13 , 3 , 4 ,14 , 7 ,5 ,11},
{10, 15, 4, 2, 7, 12 , 9 , 5 , 6, 1 ,13 ,14 , 0 ,11 , 3 , 8},
{ 9, 14 ,15, 5, 2, 8 ,12 , 3 , 7 , 0, 4 ,10 ,1 ,13 ,11 , 6},
{ 4, 3, 2, 12 , 9, 5 ,15 ,10, 11 ,14, 1 , 7 ,6 , 0 , 8 ,13}};
uint64_t sbox_7[4][16] = {
{ 4, 11, 2, 14, 15, 0 , 8, 13, 3, 12 , 9 , 7, 6 ,10 , 6 , 1},
{13, 0, 11, 7, 4 , 9, 1, 10, 14 , 3 , 5, 12, 2, 15 , 8 , 6},
{ 1 , 4, 11, 13, 12, 3, 7, 14, 10, 15 , 6, 8, 0, 5 , 9 , 2},
{ 6, 11, 13 , 8, 1 , 4, 10, 7, 9 , 5 , 0, 15, 14, 2 , 3 ,12}};
uint64_t sbox_8[4][16] = {
{13, 2, 8, 4, 6 ,15 ,11, 1, 10, 9 , 3, 14, 5, 0, 12, 7},
{ 1, 15, 13, 8 ,10 , 3 ,7 , 4, 12 , 5, 6 ,11, 0 ,14 , 9 , 2},
{ 7, 11, 4, 1, 9, 12, 14 , 2, 0 ,6, 10 ,13 ,15 , 3 ,5 ,8},
{ 2, 1, 14 , 7 , 4, 10, 8, 13, 15, 12, 9, 0 , 3, 5 , 6 ,11}};
/////////////////////////////////////////////////////////////////////////////
// I/O
/////////////////////////////////////////////////////////////////////////////
// Pad the list of blocks, so that every block is 64 bits, even if the
// file isn't a perfect multiple of 8 bytes long. In the input list of blocks,
// the last block may have "size" < 8. In this case, it needs to be padded. See
// the slides for how to do this (the last byte of the last block
// should contain the number if real bytes in the block, add an extra block if
// the file is an exact multiple of 8 bytes long.) The returned
// list of blocks will always have the "size"-field=8.
// Example:
// 1) The last block is 5 bytes long: [10,20,30,40,50]. We pad it with 2 bytes,
// and set the length to 5: [10,20,30,40,50,0,0,5]. This means that the
// first 5 bytes of the block are "real", the last 3 should be discarded.
// 2) The last block is 8 bytes long: [10,20,30,40,50,60,70,80]. We keep this
// block as is, and add a new final block: [0,0,0,0,0,0,0,0]. When we decrypt,
// the entire last block will be discarded since the last byte is 0
BLOCKLIST pad_last_block(BLOCKLIST blocks) {
// TODO
struct BLOCK* lastblock = blocks->last;
if(debug)
printf("Printing blocklist before padding\n");
print_blocklist(blocks);
uint8_t *p = (uint8_t *)&lastblock->block;
//if you need a copy
uint8_t result[8];
for(int i = 0; i < 8; i++) {
result[i] = p[i];
if(debug)
{
printf("%x ", result[i]);
printf("\n");
}
}
int blocksize = lastblock->size;
if( blocksize == 8)
{
// create a new empty block
BLOCKTYPE emptyBlock = 0;
BLOCKNODE paddedblock = newBlock(emptyBlock, 8);
lastblock->next = paddedblock;
lastblock = paddedblock;
}
else {
result[7] = blocksize;
uint64_t paddedblock = u8tou64(result);
if(debug){
printf("%lx\n", paddedblock);
}
lastblock->block = paddedblock;
if(debug) {
p = (uint8_t *)&paddedblock;
//if you need a copy
result[8];
for(int i = 0; i < 8; i++) {
result[i] = p[i];
if (debug) {
printf("%x ", result[i]);
printf("\n");
}
}
}
}
if(debug)
printf("Printing blocklist after padding\n");
print_blocklist(blocks);
return blocks;
}
// Reads the message to be encrypted, an ASCII text file, and returns a linked list
// of BLOCKs, each representing a 64 bit block. In other words, read the first 8 characters
// from the input file, and convert them (just a C cast) to 64 bits; this is your first block.
// Continue to the end of the file.
BLOCKLIST read_cleartext_message(FILE *msg_fp) {
BLOCKLIST blocks = newBlockList();
unsigned char byte = 0;
int retVal = fscanf(msg_fp, "%c", &byte);
BLOCKTYPE block = 0;
int counter = 0;
while (retVal > 0) {
if (counter == 8) {
addBlockLast(blocks, block, counter);
counter = 0;
block = 0;
}
block = (block << 8) | byte;
counter++;
retVal = fscanf(msg_fp, "%c", &byte);
}
if (counter > 0) {
addBlockLast(blocks, block, counter);
}
blocks = pad_last_block(blocks);
if (debug) {
printf("Cleartext Blocks Read\n");
print_blocklist(blocks);
}
return blocks;
}
// Reads the encrypted message, and returns a linked list of blocks, each 64 bits.
// Note that, because of the padding that was done by the encryption, the length of
// this file should always be a multiple of 8 bytes. The output is a linked list of
// 64-bit blocks.
BLOCKLIST read_encrypted_file(FILE *msg_fp) {
BLOCKLIST blocks = newBlockList();
uint64_t block;
while(fread(&block, sizeof(block), 1, msg_fp) > 0){
addBlockLast(blocks, block, 8);
block = 0;
}
return blocks;
}
// Reads 56-bit key into a 64 bit unsigned int. We will ignore the most significant byte,
// i.e. we'll assume that the top 8 bits are all 0. In real DES, these are used to check
// that the key hasn't been corrupted in transit. The key file is ASCII, consisting of
// exactly one line. That line has a single hex number on it, the key, such as 0x08AB674D9.
KEYTYPE read_key(FILE *key_fp) {
char buff[17];
fgets(buff, 17, key_fp);
KEYTYPE key = strtol(buff, 0, 16);
return key;
}
// Write the encrypted blocks to file. The encrypted file is in binary, i.e., you can
// just write each 64-bit block directly to the file, without any conversion.
void write_encrypted_message(FILE *msg_fp, BLOCKLIST msg) {
assert(msg != NULL);
BLOCKNODE curr = msg->first;
char buffer[8];
while(curr != NULL){
memcpy(&buffer,&(curr->block),curr->size);
fwrite(buffer, sizeof(char), 8, msg_fp);
curr = curr->next;
}
return;
}
// Write the encrypted blocks to file. This is called by the decryption routine.
// The output file is a plain ASCII file, containing the decrypted text message.
void write_decrypted_message(FILE *msg_fp, BLOCKLIST msg) {
assert(msg != NULL);
BLOCKNODE cur = msg->first;
int size;
unsigned int charac;
while(cur != NULL){
for(int i=8; i>=1; i--){
charac = (unsigned int) (((cur->block) >> ((i-1)*8)) & 0xFF);
fprintf(msg_fp,"%c",charac);
}
cur = cur->next;
}
}
/////////////////////////////////////////////////////////////////////////////
// Encryption
/////////////////////////////////////////////////////////////////////////////
BLOCKTYPE perm_64_64(BLOCKTYPE M, uint64_t *PERM_TABLE){
BLOCKTYPE M_IP = 0;
for (int i=0; i<64; i++){
M_IP = M_IP | ((M>>(PERM_TABLE[i] - 1)) & (1)) << i;
}
return M_IP;
}
BLOCKTYPE perm_64_64_final(BLOCKTYPE M, int *FINAL_PERMTABLE){
BLOCKTYPE FP = 0;
for (int i=0; i<64; i++){
FP = FP | ((M>>( (BLOCKTYPE)FINAL_PERMTABLE[i] - 1)) & (1)) << i;
}
return FP;
}
BLOCKTYPE perm_32_48(HALFBLOCKTYPE R, uint64_t *EXPAND_BOX){
BLOCKTYPE EX_M = 0;
for (int i=0; i<48; i++){
EX_M = EX_M | ((R>>(EXPAND_BOX[i] - 1)) & (1)) << i;
}
return EX_M;
}
HALFBLOCKTYPE perm_32_32(HALFBLOCKTYPE substitutedMessage, uint32_t *PBOX){
HALFBLOCKTYPE P_M = 0;
for (int i=0; i<32; i++){
P_M = P_M | ( (substitutedMessage >> (PBOX[i] - 1)) & (1)) << i;
}
return P_M;
}
HALFBLOCKTYPE unitSubstitute(HALFBLOCKTYPE input_6, uint64_t sbox[][16]){
//printf("[DEBUG: unitSubstitute] Entered unitSubstitute function\n");
//printf("[DEBUG: unitSubstitute] Value of 6 bit input is 0x%x\n", input_6);
HALFBLOCKTYPE output_4;
int row = (2* ((input_6>>5) & 1)) + (input_6 & 1);
//printf("[DEBUG: unitSubstitute] Row value is %d\n", row);
int column = (input_6 >> 1) & 0xf;
//printf("[DEBUG: unitSubstitute] Column value is %d\n", column);
output_4 = (HALFBLOCKTYPE) sbox[row][column];
//printf("[DEBUG: unitSubstitute] Value of calculated 4-bit output is 0x%x\n", output_4);
return output_4;
}
HALFBLOCKTYPE substitute(BLOCKTYPE exp_message_48){
HALFBLOCKTYPE substituted_message = 0;
HALFBLOCKTYPE intermediate_input_6 = 0;
HALFBLOCKTYPE intermediate_output_4 = 0;
//printf("[DEBUG: substitute] Starting sbox substitution of 6 bit units\n");
// Running S1 box
intermediate_input_6 = (exp_message_48 & 0x3f);
intermediate_output_4 = unitSubstitute(intermediate_input_6, sbox_1);
substituted_message = substituted_message | intermediate_output_4;
// Running S2 box
intermediate_input_6 = ((exp_message_48 >> 6) & 0x3f);
intermediate_output_4 = unitSubstitute(intermediate_input_6, sbox_2);
substituted_message = (substituted_message << 4) | intermediate_output_4;
// Running S3 box
intermediate_input_6 = ((exp_message_48 >> 12) & 0x3f);
intermediate_output_4 = unitSubstitute(intermediate_input_6, sbox_3);
substituted_message = (substituted_message << 4) | intermediate_output_4;
// Running S4 box
intermediate_input_6 = ((exp_message_48 >> 18) & 0x3f);
intermediate_output_4 = unitSubstitute(intermediate_input_6, sbox_4);
substituted_message = (substituted_message << 4) | intermediate_output_4;
// Running S5 box
intermediate_input_6 = ((exp_message_48 >> 24) & 0x3f);
intermediate_output_4 = unitSubstitute(intermediate_input_6, sbox_5);
substituted_message = (substituted_message << 4) | intermediate_output_4;
// Running S6 box
intermediate_input_6 = ((exp_message_48 >> 30) & 0x3f);
intermediate_output_4 = unitSubstitute(intermediate_input_6, sbox_6);
substituted_message = (substituted_message << 4) | intermediate_output_4;
// Running S7 box
intermediate_input_6 = ((exp_message_48 >> 36) & 0x3f);
intermediate_output_4 = unitSubstitute(intermediate_input_6, sbox_7);
substituted_message = (substituted_message << 4) | intermediate_output_4;
// Running S8 box
intermediate_input_6 = ((exp_message_48 >> 42) & 0x3f);
intermediate_output_4 = unitSubstitute(intermediate_input_6, sbox_8);
substituted_message = (substituted_message << 4) | intermediate_output_4;
//printf("[DEBUG: substitute] Finished sbox substitution of 6 bit units\n");
return substituted_message;
}
HALFBLOCKTYPE fiestel(HALFBLOCKTYPE righthalf, int i){
// Expansion permutation 32 -> 48
BLOCKTYPE exp_message = perm_32_48(righthalf, expand_box);
// XOR with subkey[i]
exp_message = exp_message ^ (getSubKey(i));
// 8 S-box substitution 48 -> 32
HALFBLOCKTYPE substituted_message = substitute(exp_message);
// P-box permutation 32 -> 32 (return)
HALFBLOCKTYPE fiestelOutput = perm_32_32(substituted_message, Pbox);
return fiestelOutput;
}
// Encrypt one block. This is where the main computation takes place. It takes
// one 64-bit block as input, and returns the encrypted 64-bit block. The
// subkeys needed by the Feistel Network is given by the function getSubKey(i).
BLOCKTYPE des_enc(BLOCKTYPE v){
// TODO
HALFBLOCKTYPE L;
HALFBLOCKTYPE R;
HALFBLOCKTYPE temp_R = 0;
// Initial permutation on the Plaintext
BLOCKTYPE IP = perm_64_64(v, init_perm);
/*
if (debug) {
// print v in binary
printf("[DEBUG] Printing Message Block\n");
for(int i=63; i>=0; i--){
printf("%ld [%d], ", (v>>i)&1, i+1); // Indexed from 1-64
}
printf("\n");
// print IP
printf("[DEBUG] Printing Message after Initial Permutation\n");
for (int i=63; i>=0; i--){
printf("%ld [%ld], ", (IP>>i)&1, init_perm[i]); // Indexed from 1-64
}
printf("\n");
}
*/
L = (HALFBLOCKTYPE)(IP >> 32);
R = (HALFBLOCKTYPE)(IP);
for (int i = 0; i < 16; i++){
temp_R = R;
R = L ^ (fiestel(R, i));
L = temp_R;
}
// Final switching between L and R
temp_R = R;
R = L;
L = temp_R;
// Final permutation on L and R
BLOCKTYPE FP = ( ((BLOCKTYPE)L) << 32 ) | (BLOCKTYPE)R;
FP = perm_64_64_final(FP, final_perm);
return FP;
}
// Encrypt the blocks in ECB mode. The blocks have already been padded
// by the input routine. The output is an encrypted list of blocks.
BLOCKLIST des_enc_ECB(BLOCKLIST msg) {
assert(msg != NULL);
BLOCKLIST encryptedBlockList = newBlockList();
// Calls des_enc in here repeatedly
BLOCKNODE start = msg->first;
int i = 0; // Used for debugging only
while(start!=NULL)
{
BLOCKTYPE block = start->block;
BLOCKTYPE encryptedblock = des_enc(block);
if(debug){
printf("Encrypted Block[%d] 0x%lx\n", i, encryptedblock);
i++;
}
addBlockLast(encryptedBlockList, encryptedblock, start->size);
start = start->next;
}
return encryptedBlockList;
}
// Same as des_enc_ECB, but encrypt the blocks in Counter mode.
// SEE: https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_(CTR)
// Start the counter at 0.
BLOCKLIST des_enc_CTR(BLOCKLIST msg) {
assert(msg != NULL);
// TODO
// Should call des_enc in here repeatedly
BLOCKLIST encryptedBlockList = newBlockList();
BLOCKNODE start = msg->first;
int ctr = 0;
KEYTYPE original_key = key;
int i = 0; // Used for debugging only
while(start!=NULL) {
key = original_key ^ ctr;
BLOCKTYPE block = start->block;
BLOCKTYPE encryptedblock = des_enc(block);
if(debug) {
printf("Encrypted Block[%d] 0x%lx\n", i, encryptedblock);
i++;
}
addBlockLast(encryptedBlockList, encryptedblock, 8);
start = start->next;
key = original_key;
ctr += 1;
}
return encryptedBlockList;
}
/////////////////////////////////////////////////////////////////////////////
// Decryption
/////////////////////////////////////////////////////////////////////////////
// Decrypt one block.
BLOCKTYPE des_dec(BLOCKTYPE v){
// TODO
HALFBLOCKTYPE L;
HALFBLOCKTYPE R;
HALFBLOCKTYPE temp_R = 0;
// Initial permutation on the Plaintext
BLOCKTYPE IP = perm_64_64(v, init_perm);
/*
if (debug) {
// print v in binary
printf("[DEBUG] Printing Message Block\n");
for(int i=63; i>=0; i--){
printf("%ld [%d], ", (v>>i)&1, i+1); // Indexed from 1-64
}
printf("\n");
// print IP
printf("[DEBUG] Printing Message after Initial Permutation\n");
for (int i=63; i>=0; i--){
printf("%ld [%ld], ", (IP>>i)&1, init_perm[i]); // Indexed from 1-64
}
printf("\n");
}
*/
L = (HALFBLOCKTYPE)(IP >> 32);
R = (HALFBLOCKTYPE)(IP);
for (int i = 15; i >= 0; i--){
temp_R = R;
R = L ^ (fiestel(R, i));
L = temp_R;
}
// Final switching between L and R
temp_R = R;
R = L;
L = temp_R;
// Final permutation on L and R
BLOCKTYPE FP = ( ((BLOCKTYPE)L) << 32 ) | (BLOCKTYPE)R;
FP = perm_64_64_final(FP, final_perm);
return FP;
}
// Decrypt the blocks in ECB mode. The input is a list of encrypted blocks,
// the output a list of plaintext blocks.
BLOCKLIST des_dec_ECB(BLOCKLIST msg) {
assert(msg != NULL);
// Should call des_dec in here repeatedly
BLOCKLIST decryptedBlockList = newBlockList();
// Calls des_enc in here repeatedly
BLOCKNODE start = msg->first;
int i = 0; // Used for debugging only
while(start!=NULL)
{
BLOCKTYPE block = start->block;
BLOCKTYPE decryptedblock = des_dec(block);
if(debug){
printf("Decrypted Block[%d] 0x%lx\n", i, decryptedblock);
i++;
}
addBlockLast(decryptedBlockList, decryptedblock, start->size);
start = start->next;
}
return decryptedBlockList;
}
// Decrypt the blocks in Counter mode
BLOCKLIST des_dec_CTR(BLOCKLIST msg) {
assert(msg != NULL);
// Should call des_dec in here repeatedly
BLOCKLIST decryptedBlockList = newBlockList();
// Calls des_enc in here repeatedly
BLOCKNODE start = msg->first;
int i = 0; // Used for debugging only
int ctr = 0;
KEYTYPE original_key = key;
while(start!=NULL)
{
key = original_key ^ ctr;
BLOCKTYPE block = start->block;
BLOCKTYPE decryptedblock = des_dec(block);
if(debug){
printf("Decrypted Block[%d] 0x%lx\n", i, decryptedblock);
i++;
}
addBlockLast(decryptedBlockList, decryptedblock, start->size);
start = start->next;
key = original_key;
ctr += 1;
}
return decryptedBlockList;
}
/////////////////////////////////////////////////////////////////////////////
// Main routine
/////////////////////////////////////////////////////////////////////////////
void encrypt (int argc, char **argv) {
FILE *msg_fp = fopen("message.txt", "r");
BLOCKLIST msg = read_cleartext_message(msg_fp);
fclose(msg_fp);
BLOCKLIST encrypted_message;
if (strncmp(argv[2], "-ecb", 4) == 0) {
encrypted_message = des_enc_ECB(msg);
} else if (strncmp(argv[2], "-ctr", 4) == 0) {
encrypted_message = des_enc_CTR(msg);
} else {
printf("No such mode.\n");
exit(-1);
};
FILE *encrypted_msg_fp = fopen("encrypted_msg.bin", "wb");
write_encrypted_message(encrypted_msg_fp, encrypted_message);
fclose(encrypted_msg_fp);
}
void decrypt (int argc, char **argv) {
FILE *encrypted_msg_fp = fopen("encrypted_msg.bin", "rb");
assert(encrypted_msg_fp != NULL);
BLOCKLIST encrypted_message = read_encrypted_file(encrypted_msg_fp);
fclose(encrypted_msg_fp);
assert(encrypted_message != NULL);
if(debug) {
printf("[DEBUG: decrypt] Printing encrypted message block from encrypted binary file\n");
print_blocklist(encrypted_message);
}
BLOCKLIST decrypted_message;
if (strncmp(argv[2], "-ecb", 4) == 0) {
decrypted_message = des_dec_ECB(encrypted_message);
} else if (strncmp(argv[2], "-ctr", 4) == 0) {
decrypted_message = des_dec_CTR(encrypted_message);
} else {
printf("No such mode.\n");
exit(-1);
};
if (debug){
print_blocklist(decrypted_message);
}
FILE *decrypted_msg_fp = fopen("decrypted_message.txt", "w");
write_decrypted_message(decrypted_msg_fp, decrypted_message);
fclose(decrypted_msg_fp);
}
int main(int argc, char **argv){
FILE *key_fp = fopen("key.txt","r");
key = read_key(key_fp);
//generateSubKeys(key); // This does nothing right now.
fclose(key_fp);
if (argc != 3) {
printf("Two arguments expected.\n");
exit(-1);
}
if (strncmp(argv[1],"-enc",4) == 0) {
encrypt(argc, argv);
} else if (strncmp(argv[1],"-dec",4) == 0) {
decrypt(argc, argv);
} else {
printf("First argument should be -enc or -dec\n");
}
return 0;
}#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
/*
* des takes two arguments on the command line:
* des -enc -ecb -- encrypt in ECB mode
* des -enc -ctr -- encrypt in CTR mode
* des -dec -ecb -- decrypt in ECB mode
* des -dec -ctr -- decrypt in CTR mode
* des also reads some hardcoded files:
* message.txt -- the ASCII text message to be encrypted,
* read by "des -enc"
* encrypted_msg.bin -- the encrypted message, a binary file,
* written by "des -enc"
* decrypted_message.txt -- the decrypted ASCII text message
* key.txt -- just contains the key, on a line by itself, as an ASCII
* hex number, such as: 0x34FA879B
*/
uint64_t
u8tou64(uint8_t const u8[static 8]){
uint64_t u64;
memcpy(&u64, u8, sizeof u64);
return u64;
}
unsigned createMask(unsigned a, unsigned b)
{
unsigned r = 0;
for (unsigned i=a; i<=b; i++)
r |= 1 << i;
return r;
}
/////////////////////////////////////////////////////////////////////////////
// Type definitions
/////////////////////////////////////////////////////////////////////////////
typedef uint64_t KEYTYPE;
typedef uint32_t SUBKEYTYPE;
typedef uint64_t BLOCKTYPE;
typedef uint32_t HALFBLOCKTYPE;
struct BLOCK {
BLOCKTYPE block; // the block read
int size; // number of "real" bytes in the block, should be 8, unless it's the last block
struct BLOCK *next; // pointer to the next block
};
struct BLOCKHEAD {
struct BLOCK *first; // first block
struct BLOCK *last; // last block
};
typedef struct BLOCK* BLOCKNODE;
typedef struct BLOCKHEAD* BLOCKLIST;
BLOCKLIST newBlockList() {
BLOCKLIST blocks = (BLOCKLIST)malloc(sizeof(struct BLOCKHEAD));
blocks->first = NULL;
blocks->last = NULL;
return blocks;
}
BLOCKNODE newBlock(uint64_t block, int size){
BLOCKNODE new_node = (BLOCKNODE) malloc(sizeof(struct BLOCK));
new_node->block = block;
new_node->size = size;
new_node->next = NULL;
return new_node;
}
void addBlockLast(BLOCKLIST list, BLOCKTYPE block, int size) {
BLOCKNODE currBlock = newBlock(block, size);
if (list->first == NULL) {
list->first = currBlock;
list->last = currBlock;
} else {
list->last->next = currBlock;
list->last = currBlock;
}
}
/////////////////////////////////////////////////////////////////////////////
// Debugging
/////////////////////////////////////////////////////////////////////////////
int debug = 1;
void print_blocklist(BLOCKLIST head) {
BLOCKNODE curr = head->first;
int x = 0;
assert(curr != NULL);
while (curr != NULL) {
printf("\tBLOCK [%d]: 0x%lx, size=%d\n", x, curr->block,curr->size);
x++;
curr = curr->next;
}
}
void print_block(struct BLOCK* head) {
printf("\tBLOCK : 0x%lx, size=%d\n", head->block,head->size);
}
/////////////////////////////////////////////////////////////////////////////
// Initial and final permutation
/////////////////////////////////////////////////////////////////////////////
uint64_t init_perm[] = {
58,50,42,34,26,18,10,2,
60,52,44,36,28,20,12,4,
62,54,46,38,30,22,14,6,
64,56,48,40,32,24,16,8,
57,49,41,33,25,17,9,1,
59,51,43,35,27,19,11,3,
61,53,45,37,29,21,13,5,
63,55,47,39,31,23,15,7
};
int final_perm[] = {
40,8,48,16,56,24,64,32,
39,7,47,15,55,23,63,31,
38,6,46,14,54,22,62,30,
37,5,45,13,53,21,61,29,
36,4,44,12,52,20,60,28,
35,3,43,11,51,19,59,27,
34,2,42,10,50,18,58,26,
33,1,41,9, 49,17,57,25
};
/////////////////////////////////////////////////////////////////////////////
// Subkey generation
/////////////////////////////////////////////////////////////////////////////
//SUBKEYTYPE subkeys[16];
KEYTYPE key = 0; // Global variable key
// This function returns the i:th subkey, 48 bits long. To simplify the assignment
// you can use a trivial implementation: just take the input key and xor it with i.
uint64_t getSubKey(int i) {
// TODO: return the first 48 bits of the 56 bit DES key, xor:ed with i.
return ((key ^ i) & 0xffffffffffff);
//return subkeys[i];
}
// For extra credit, write the real DES key expansion routine!
//SUBKEYTYPE* generateSubKeys(KEYTYPE key) {
// // TODO for extra credit
// for( int i = 0; i<16; i++){
// unsigned r = createMask(0,47);
// unsigned result = r & (key^i);
// subkeys[i] = result;
// }
// return subkeys;
//}
/////////////////////////////////////////////////////////////////////////////
// P-boxes
/////////////////////////////////////////////////////////////////////////////
uint64_t expand_box[] = {
32,1,2,3,4,5,4,5,6,7,8,9,
8,9,10,11,12,13,12,13,14,15,16,17,
16,17,18,19,20,21,20,21,22,23,24,25,
24,25,26,27,28,29,28,29,30,31,32,1
};
uint32_t Pbox[] =
{
16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,
2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25,
};
/////////////////////////////////////////////////////////////////////////////
// S-boxes
/////////////////////////////////////////////////////////////////////////////
uint64_t sbox_1[4][16] = {
{14, 4, 13, 1, 2, 15, 11, 8, 3, 10 , 6, 12, 5, 9, 0, 7},
{ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
{ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
{15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}};
uint64_t sbox_2[4][16] = {
{15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5 ,10},
{ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
{ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
{13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}};
uint64_t sbox_3[4][16] = {
{10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
{13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
{13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
{ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}};
uint64_t sbox_4[4][16] = {