-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathot7test.c
2179 lines (1843 loc) · 80.4 KB
/
ot7test.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
/* https://github.com/otseven/OT7
--------------------------------------------------------------------------------
ot7test.c - TEST PROGRAM FOR OT7 ENCRYPTION TOOL January 2, 2015
--------------------------------------------------------------------------------
PURPOSE: To test the OT7 encryption tool.
DESCRIPTION: This is a separate program that calls the OT7 application to make
sure it's working properly.
Test encryption keys and plaintext files are pseudo-randomly generated during
this test. Many different ways of using OT7 are tested with this generated data.
21MB of disk space is required for this test.
This test can take an hour or more to run depending on the speed of the
computer.
The test ends early with an error message if any error is detected.
------------------------------------------------------------------------------*/
#define APPLICATION_NAME_STRING "ot7test"
// Name of this application.
#define _LARGEFILE64_SOURCE
// Enable the use of large files with sizes up to 2^64.
#define _FILE_OFFSET_BITS 64
// Enable the use of 64-bit file offsets.
#define _LARGEFILE_SOURCE
// Enable the use of fseeko and ftello.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
// For MacOS X, 64-bit file access is standard. Define the symbols needed to
// link to the library routines.
#if defined( __MWERKS__ ) || defined( __APPLE_CC__ )
#define off64_t off_t
#define fopen64 fopen
#define fseeko64 fseeko
#define ftello64 ftello
#endif // __MWERKS__ || __APPLE_CC__
//------------------------------------------------------------------------------
// Abbreviated integer types.
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef char s8;
typedef short s16;
typedef long s32;
// For 64-bit integers...
//
// ... for GCC on Linux.
#if defined( __GNUC__ ) && defined( __linux__ )
typedef unsigned long long u64;
typedef long long s64;
#endif // __GNUC__
// ... for Metrowerks or Apple compilers.
#if defined( __MWERKS__ ) || defined( __APPLE_CC__ )
typedef unsigned long long u64;
typedef long long s64;
#endif // __MWERKS__ || __APPLE_CC__
// ...for Microsoft Visual C++.
#if defined( _MSC_VER ) && !defined( __MWERKS__ ) && defined( _INTEGRAL_MAX_BITS ) && ( _INTEGRAL_MAX_BITS >= 64 )
typedef unsigned __int64 u64; // VC++ doesn't fully support this type: use s64 instead.
typedef __int64 s64;
#endif // _MSC_VER
#define MAX_VALUE_32BIT 0xFFFFFFFFL
// The maximum value that can be held in a 32-bit field.
#define MAX_VALUE_64BIT 0xFFFFFFFFFFFFFFFFLL
// The maximum value that can be held in a 64-bit field.
//------------------------------------------------------------------------------
// SKEIN1024 HASH FUNCTION - VERSION 1.3
//------------------------------------------------------------------------------
/* tweak word T[1]: bit field starting positions */
#define SKEIN_T1_BIT(BIT) ((BIT) - 64) /* offset 64 because it's the second word */
#define SKEIN_T1_POS_TREE_LVL SKEIN_T1_BIT(112) /* bits 112..118: level in hash tree */
#define SKEIN_T1_POS_BIT_PAD SKEIN_T1_BIT(119) /* bit 119 : partial final input byte */
#define SKEIN_T1_POS_BLK_TYPE SKEIN_T1_BIT(120) /* bits 120..125: type field */
#define SKEIN_T1_POS_FIRST SKEIN_T1_BIT(126) /* bits 126 : first block flag */
#define SKEIN_T1_POS_FINAL SKEIN_T1_BIT(127) /* bit 127 : final block flag */
/* tweak word T[1]: flag bit definition(s) */
#define SKEIN_T1_FLAG_FIRST (((u64) 1 ) << SKEIN_T1_POS_FIRST)
#define SKEIN_T1_FLAG_FINAL (((u64) 1 ) << SKEIN_T1_POS_FINAL)
#define SKEIN_T1_FLAG_BIT_PAD (((u64) 1 ) << SKEIN_T1_POS_BIT_PAD)
/* tweak word T[1]: tree level bit field mask */
#define SKEIN_T1_TREE_LVL_MASK (((u64)0x7F) << SKEIN_T1_POS_TREE_LVL)
#define SKEIN_T1_TREE_LEVEL(n) (((u64) (n)) << SKEIN_T1_POS_TREE_LVL)
/* tweak word T[1]: block type field */
#define SKEIN_BLK_TYPE_KEY ( 0) /* key, for MAC and KDF */
#define SKEIN_BLK_TYPE_CFG ( 4) /* configuration block */
#define SKEIN_BLK_TYPE_PERS ( 8) /* personalization string */
#define SKEIN_BLK_TYPE_PK (12) /* public key (for digital signature hashing) */
#define SKEIN_BLK_TYPE_KDF (16) /* key identifier for KDF */
#define SKEIN_BLK_TYPE_NONCE (20) /* nonce for PRNG */
#define SKEIN_BLK_TYPE_MSG (48) /* message processing */
#define SKEIN_BLK_TYPE_OUT (63) /* output stage */
#define SKEIN_BLK_TYPE_MASK (63) /* bit field mask */
#define SKEIN_T1_BLK_TYPE(T) (((u64) (SKEIN_BLK_TYPE_##T)) << SKEIN_T1_POS_BLK_TYPE)
#define SKEIN_T1_BLK_TYPE_KEY SKEIN_T1_BLK_TYPE(KEY) /* key, for MAC and KDF */
#define SKEIN_T1_BLK_TYPE_CFG SKEIN_T1_BLK_TYPE(CFG) /* configuration block */
#define SKEIN_T1_BLK_TYPE_PERS SKEIN_T1_BLK_TYPE(PERS) /* personalization string */
#define SKEIN_T1_BLK_TYPE_PK SKEIN_T1_BLK_TYPE(PK) /* public key (for digital signature hashing) */
#define SKEIN_T1_BLK_TYPE_KDF SKEIN_T1_BLK_TYPE(KDF) /* key identifier for KDF */
#define SKEIN_T1_BLK_TYPE_NONCE SKEIN_T1_BLK_TYPE(NONCE)/* nonce for PRNG */
#define SKEIN_T1_BLK_TYPE_MSG SKEIN_T1_BLK_TYPE(MSG) /* message processing */
#define SKEIN_T1_BLK_TYPE_OUT SKEIN_T1_BLK_TYPE(OUT) /* output stage */
#define SKEIN_T1_BLK_TYPE_MASK SKEIN_T1_BLK_TYPE(MASK) /* field bit mask */
#define SKEIN_T1_BLK_TYPE_CFG_FINAL (SKEIN_T1_BLK_TYPE_CFG | SKEIN_T1_FLAG_FINAL)
#define SKEIN_T1_BLK_TYPE_OUT_FINAL (SKEIN_T1_BLK_TYPE_OUT | SKEIN_T1_FLAG_FINAL)
#define SKEIN_VERSION (1)
#ifndef SKEIN_ID_STRING_LE /* allow compile-time personalization */
#define SKEIN_ID_STRING_LE (0x33414853) /* "SHA3" (little-endian)*/
#endif
enum
{
// Skein1024 round rotation constants from "Table 4: Rotation constants
// R(d,j) for each Nw" of skein1.3.pdf.
R_0_0=24, R_0_1=13, R_0_2= 8, R_0_3=47, R_0_4= 8, R_0_5=17, R_0_6=22, R_0_7=37,
R_1_0=38, R_1_1=19, R_1_2=10, R_1_3=55, R_1_4=49, R_1_5=18, R_1_6=23, R_1_7=52,
R_2_0=33, R_2_1= 4, R_2_2=51, R_2_3=13, R_2_4=34, R_2_5=41, R_2_6=59, R_2_7=17,
R_3_0= 5, R_3_1=20, R_3_2=48, R_3_3=41, R_3_4=47, R_3_5=28, R_3_6=16, R_3_7=25,
R_4_0=41, R_4_1= 9, R_4_2=37, R_4_3=31, R_4_4=12, R_4_5=47, R_4_6=44, R_4_7=30,
R_5_0=16, R_5_1=34, R_5_2=56, R_5_3=51, R_5_4= 4, R_5_5=53, R_5_6=42, R_5_7=41,
R_6_0=31, R_6_1=44, R_6_2=47, R_6_3=46, R_6_4=19, R_6_5=42, R_6_6=44, R_6_7=25,
R_7_0= 9, R_7_1=48, R_7_2=35, R_7_3=52, R_7_4=23, R_7_5=31, R_7_6=37, R_7_7=20
};
#define SKEIN_MK_64(hi32,lo32) ((lo32) + (((u64) (hi32)) << 32))
#define SKEIN_SCHEMA_VER SKEIN_MK_64(SKEIN_VERSION,SKEIN_ID_STRING_LE)
#define SKEIN_KS_PARITY SKEIN_MK_64(0x1BD11BDA,0xA9FC1A22)
#define SKEIN_MODIFIER_WORDS (2) // Number of modifier (tweak) words.
#define SKEIN1024_STATE_WORDS (16)
#define SKEIN1024_BLOCK_BYTES (8*SKEIN1024_STATE_WORDS)
// 1024-bit Skein hash context structure.
typedef struct
{
u32 hashBitLen; // Size of hash result, in bits.
u32 bCnt; // Current byte count in buffer b[].
u64 T[SKEIN_MODIFIER_WORDS]; // Tweak words: T[0]=byte cnt, T[1]=flags.
u64 X[SKEIN1024_STATE_WORDS]; // Chaining variables.
u8 b[SKEIN1024_BLOCK_BYTES]; // Partial block buffer (8-byte aligned).
} Skein1024Context;
#define SKEIN1024_ROUNDS_TOTAL (80)
#define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N))))
#define SKEIN_CFG_STR_LEN (4*8)
// bit field definitions in config block treeInfo word.
#define SKEIN_CFG_TREE_LEAF_SIZE_POS ( 0)
#define SKEIN_CFG_TREE_NODE_SIZE_POS ( 8)
#define SKEIN_CFG_TREE_MAX_LEVEL_POS (16)
#define SKEIN_CFG_TREE_LEAF_SIZE_MSK (((u64) 0xFF) << SKEIN_CFG_TREE_LEAF_SIZE_POS)
#define SKEIN_CFG_TREE_NODE_SIZE_MSK (((u64) 0xFF) << SKEIN_CFG_TREE_NODE_SIZE_POS)
#define SKEIN_CFG_TREE_MAX_LEVEL_MSK (((u64) 0xFF) << SKEIN_CFG_TREE_MAX_LEVEL_POS)
#define SKEIN_CFG_TREE_INFO(leaf,node,maxLvl) \
( (((u64)(leaf )) << SKEIN_CFG_TREE_LEAF_SIZE_POS) | \
(((u64)(node )) << SKEIN_CFG_TREE_NODE_SIZE_POS) | \
(((u64)(maxLvl)) << SKEIN_CFG_TREE_MAX_LEVEL_POS) )
#define SKEIN_CFG_TREE_INFO_SEQUENTIAL SKEIN_CFG_TREE_INFO(0,0,0)
// Use as treeInfo in InitExt() call for sequential processing.
// Skein macros for getting/setting tweak words, etc.
// These are useful for partial input bytes, hash tree init/update, etc.
#define Skein_Get_Tweak(ctxPtr,TWK_NUM) ((ctxPtr)->T[TWK_NUM])
#define Skein_Set_Tweak(ctxPtr,TWK_NUM,tVal) {(ctxPtr)->T[TWK_NUM] = (tVal);}
#define Skein_Set_T0(ctxPtr,T0) Skein_Set_Tweak(ctxPtr,0,T0)
#define Skein_Set_T1(ctxPtr,T1) Skein_Set_Tweak(ctxPtr,1,T1)
// Set both tweak words at once.
#define Skein_Set_T0_T1(ctxPtr,T0,T1) \
{ \
Skein_Set_T0(ctxPtr,(T0)); \
Skein_Set_T1(ctxPtr,(T1)); \
}
// set up for starting with a new type: h.T[0]=0; h.T[1] = NEW_TYPE; h.bCnt=0;
#define Skein_Start_New_Type(ctxPtr,BLK_TYPE) \
{ Skein_Set_T0_T1(ctxPtr,0,SKEIN_T1_FLAG_FIRST | BLK_TYPE); (ctxPtr)->bCnt=0; }
// Macro to perform a key injection.
#define InjectKey(r) \
for (i=0;i < SKEIN1024_STATE_WORDS;i++) \
X[i] += ks[((r)+i) % (SKEIN1024_STATE_WORDS+1)]; \
X[SKEIN1024_STATE_WORDS-3] += ts[((r)+0) % 3]; \
X[SKEIN1024_STATE_WORDS-2] += ts[((r)+1) % 3]; \
X[SKEIN1024_STATE_WORDS-1] += (r);
//------------------------------------------------------------------------------
// PSEUDO-RANDOM NUMBER GENERATOR
//------------------------------------------------------------------------------
#define PSEUDO_RANDOM_DATA_BUFFER_SIZE 1024
// Size in bytes of the pseudo-random number data buffer.
#define PSEUDO_RANDOM_BUFFER_BIT_COUNT (PSEUDO_RANDOM_DATA_BUFFER_SIZE << 3)
// Size in bits of the pseudo-random number data buffer.
u8 PseudoRandomDataBuffer[PSEUDO_RANDOM_DATA_BUFFER_SIZE]; // 1024 bytes
// Buffer for bytes produced by the pseudo-random number generator. Data
// is generated in blocks of 1024 bytes and then used one at a time.
u32 PseudoRandomDataBufferByteCount;
// Number of data bytes in the PseudoRandomDataBuffer. Bytes are removed in
// order from the start of the buffer to the end.
Skein1024Context PseudoRandomHashContext;
// Hash context for generating pseudo-random test data such as plaintext
// files and encryption key files.
//------------------------------------------------------------------------------
// RESULT CODES
//------------------------------------------------------------------------------
int Result;
// Result code returned when the application exits, one of the following
// values. Applications calling the ot7 command line tool can use these
// result codes in error handling routines.
//
// Zero is reserved to mean successful completion. Error numbers start at
// 1 to fit into a byte and avoid collision with the range used by
// sysexits.h which starts at 64.
#define RESULT_OK 0
// Use 0 for no error result for compatibility with other
// applications.
#define RESULT_CANT_CLOSE_ENCRYPTED_FILE 1
#define RESULT_CANT_CLOSE_FILE 2
#define RESULT_CANT_CLOSE_KEY_FILE 3
#define RESULT_CANT_CLOSE_PLAINTEXT_FILE 4
#define RESULT_CANT_IDENTIFY_KEYADDRESS_FOR_DECRYPTION 5
#define RESULT_CANT_IDENTIFY_KEYID_FOR_DECRYPTION 6
#define RESULT_CANT_IDENTIFY_KEYID_FOR_ENCRYPTION 7
#define RESULT_CANT_OPEN_ENCRYPTED_FILE_FOR_READING 8
#define RESULT_CANT_OPEN_ENCRYPTED_FILE_FOR_WRITING 9
#define RESULT_CANT_OPEN_FILE_FOR_WRITING 10
#define RESULT_CANT_OPEN_KEY_FILE_FOR_READING 11
#define RESULT_CANT_OPEN_KEY_FILE_FOR_WRITING 12
#define RESULT_CANT_OPEN_PLAINTEXT_FILE_FOR_READING 13
#define RESULT_CANT_OPEN_PLAINTEXT_FILE_FOR_WRITING 14
#define RESULT_CANT_READ_ENCRYPTED_FILE 15
#define RESULT_CANT_READ_KEY_FILE 16
#define RESULT_CANT_READ_KEY_MAP_FILE 17
#define RESULT_CANT_READ_PLAINTEXT_FILE 18
#define RESULT_CANT_SEEK_IN_ENCRYPTED_FILE 19
#define RESULT_CANT_SEEK_IN_KEY_FILE 20
#define RESULT_CANT_SEEK_IN_PLAINTEXT_FILE 21
#define RESULT_CANT_WRITE_ENCRYPTED_FILE 22
#define RESULT_CANT_WRITE_FILE 23
#define RESULT_CANT_WRITE_KEY_FILE 24
#define RESULT_CANT_WRITE_PLAINTEXT_FILE 25
#define RESULT_CANT_ERASE_USED_KEY_BYTES 26
#define RESULT_INVALID_CHECKSUM_DECRYPTED 27
#define RESULT_INVALID_COMMAND_LINE_PARAMETER 28
#define RESULT_INVALID_COMPUTED_HEADER_KEY 29
#define RESULT_INVALID_DECRYPTION_OUTPUT 30
#define RESULT_INVALID_ENCRYPTED_FILE_FORMAT 31
#define RESULT_INVALID_KEY_FILE_NAME 32
#define RESULT_INVALID_KEY_FILE_POINTER 33
#define RESULT_INVALID_KEY_MAP_FILE_NAME 34
#define RESULT_INVALID_LOG_FILE_NAME 35
#define RESULT_INVALID_NAME_OF_FILE_TO_DECRYPT 36
#define RESULT_INVALID_NAME_OF_PLAINTEXT_FILE 37
#define RESULT_INVALID_OUTPUT_FILE_NAME 38
#define RESULT_KEY_FILE_IS_TOO_SMALL 39
#define RESULT_MISSING_COMMAND_LINE_PARAMETER 40
#define RESULT_MISSING_KEYID_IN_KEYDEF_STRING 41
#define RESULT_NO_COMMAND_LINE_PARAMETERS_GIVEN 42
#define RESULT_OUT_OF_MEMORY 43
#define RESULT_RAN_OUT_OF_KEY_IN_ONE_TIME_PAD 44
#define RESULT_SKEIN_TEST_FINAL_RESULT_IS_INVALID 45
#define RESULT_SKEIN_TEST_INITIALIZATION_FAILED 46
#define RESULT_TEXT_LINE_TOO_LONG_FOR_BUFFER 47
/*------------------------------------------------------------------------------
| ResultCodeAndString
|-------------------------------------------------------------------------------
|
| PURPOSE: To associate a result code with a name string.
|
| DESCRIPTION:
|
| HISTORY:
| 25Dec14
------------------------------------------------------------------------------*/
typedef struct
{
u32 ResultCode;
// A 32-bit result code.
s8* ResultCodeString;
// The name of the result code an ASCIIZ string.
} ResultCodeAndString;
/*------------------------------------------------------------------------------
| ResultCodesOT7
|-------------------------------------------------------------------------------
|
| PURPOSE: To associate OT7 result codes with name strings.
|
| DESCRIPTION: OT7 passes a result code to the calling application or shell
| when it exits. This table is used to convert that number to a human readable
| string.
|
| HISTORY:
| 25Dec14
------------------------------------------------------------------------------*/
ResultCodeAndString
ResultCodesOT7[] =
{
{ RESULT_OK,
"RESULT_OK" },
{ RESULT_CANT_CLOSE_ENCRYPTED_FILE,
"RESULT_CANT_CLOSE_ENCRYPTED_FILE" },
{ RESULT_CANT_CLOSE_FILE,
"RESULT_CANT_CLOSE_FILE" },
{ RESULT_CANT_CLOSE_KEY_FILE,
"RESULT_CANT_CLOSE_KEY_FILE" },
{ RESULT_CANT_CLOSE_PLAINTEXT_FILE,
"RESULT_CANT_CLOSE_PLAINTEXT_FILE" },
{ RESULT_CANT_IDENTIFY_KEYADDRESS_FOR_DECRYPTION,
"RESULT_CANT_IDENTIFY_KEYADDRESS_FOR_DECRYPTION" },
{ RESULT_CANT_IDENTIFY_KEYID_FOR_DECRYPTION,
"RESULT_CANT_IDENTIFY_KEYID_FOR_DECRYPTION" },
{ RESULT_CANT_IDENTIFY_KEYID_FOR_ENCRYPTION,
"RESULT_CANT_IDENTIFY_KEYID_FOR_ENCRYPTION" },
{ RESULT_CANT_OPEN_ENCRYPTED_FILE_FOR_READING,
"RESULT_CANT_OPEN_ENCRYPTED_FILE_FOR_READING" },
{ RESULT_CANT_OPEN_ENCRYPTED_FILE_FOR_WRITING,
"RESULT_CANT_OPEN_ENCRYPTED_FILE_FOR_WRITING" },
{ RESULT_CANT_OPEN_FILE_FOR_WRITING,
"RESULT_CANT_OPEN_FILE_FOR_WRITING" },
{ RESULT_CANT_OPEN_KEY_FILE_FOR_READING,
"RESULT_CANT_OPEN_KEY_FILE_FOR_READING" },
{ RESULT_CANT_OPEN_KEY_FILE_FOR_WRITING,
"RESULT_CANT_OPEN_KEY_FILE_FOR_WRITING" },
{ RESULT_CANT_OPEN_PLAINTEXT_FILE_FOR_READING,
"RESULT_CANT_OPEN_PLAINTEXT_FILE_FOR_READING" },
{ RESULT_CANT_OPEN_PLAINTEXT_FILE_FOR_WRITING,
"RESULT_CANT_OPEN_PLAINTEXT_FILE_FOR_WRITING" },
{ RESULT_CANT_READ_ENCRYPTED_FILE,
"RESULT_CANT_READ_ENCRYPTED_FILE" },
{ RESULT_CANT_READ_KEY_FILE,
"RESULT_CANT_READ_KEY_FILE" },
{ RESULT_CANT_READ_KEY_MAP_FILE,
"RESULT_CANT_READ_KEY_MAP_FILE" },
{ RESULT_CANT_READ_PLAINTEXT_FILE,
"RESULT_CANT_READ_PLAINTEXT_FILE" },
{ RESULT_CANT_SEEK_IN_ENCRYPTED_FILE,
"RESULT_CANT_SEEK_IN_ENCRYPTED_FILE" },
{ RESULT_CANT_SEEK_IN_KEY_FILE,
"RESULT_CANT_SEEK_IN_KEY_FILE" },
{ RESULT_CANT_SEEK_IN_PLAINTEXT_FILE,
"RESULT_CANT_SEEK_IN_PLAINTEXT_FILE" },
{ RESULT_CANT_WRITE_ENCRYPTED_FILE,
"RESULT_CANT_WRITE_ENCRYPTED_FILE" },
{ RESULT_CANT_WRITE_FILE,
"RESULT_CANT_WRITE_FILE" },
{ RESULT_CANT_WRITE_KEY_FILE,
"RESULT_CANT_WRITE_KEY_FILE" },
{ RESULT_CANT_WRITE_PLAINTEXT_FILE,
"RESULT_CANT_WRITE_PLAINTEXT_FILE" },
{ RESULT_CANT_ERASE_USED_KEY_BYTES,
"RESULT_CANT_ERASE_USED_KEY_BYTES" },
{ RESULT_INVALID_CHECKSUM_DECRYPTED,
"RESULT_INVALID_CHECKSUM_DECRYPTED" },
{ RESULT_INVALID_COMMAND_LINE_PARAMETER,
"RESULT_INVALID_COMMAND_LINE_PARAMETER" },
{ RESULT_INVALID_COMPUTED_HEADER_KEY,
"RESULT_INVALID_COMPUTED_HEADER_KEY" },
{ RESULT_INVALID_DECRYPTION_OUTPUT,
"RESULT_INVALID_DECRYPTION_OUTPUT" },
{ RESULT_INVALID_ENCRYPTED_FILE_FORMAT,
"RESULT_INVALID_ENCRYPTED_FILE_FORMAT" },
{ RESULT_INVALID_KEY_FILE_NAME,
"RESULT_INVALID_KEY_FILE_NAME" },
{ RESULT_INVALID_KEY_FILE_POINTER,
"RESULT_INVALID_KEY_FILE_POINTER" },
{ RESULT_INVALID_KEY_MAP_FILE_NAME,
"RESULT_INVALID_KEY_MAP_FILE_NAME" },
{ RESULT_INVALID_LOG_FILE_NAME,
"RESULT_INVALID_LOG_FILE_NAME" },
{ RESULT_INVALID_NAME_OF_FILE_TO_DECRYPT,
"RESULT_INVALID_NAME_OF_FILE_TO_DECRYPT" },
{ RESULT_INVALID_NAME_OF_PLAINTEXT_FILE,
"RESULT_INVALID_NAME_OF_PLAINTEXT_FILE" },
{ RESULT_INVALID_OUTPUT_FILE_NAME,
"RESULT_INVALID_OUTPUT_FILE_NAME" },
{ RESULT_KEY_FILE_IS_TOO_SMALL,
"RESULT_KEY_FILE_IS_TOO_SMALL" },
{ RESULT_MISSING_COMMAND_LINE_PARAMETER,
"RESULT_MISSING_COMMAND_LINE_PARAMETER" },
{ RESULT_MISSING_KEYID_IN_KEYDEF_STRING,
"RESULT_MISSING_KEYID_IN_KEYDEF_STRING" },
{ RESULT_NO_COMMAND_LINE_PARAMETERS_GIVEN,
"RESULT_NO_COMMAND_LINE_PARAMETERS_GIVEN" },
{ RESULT_OUT_OF_MEMORY,
"RESULT_OUT_OF_MEMORY" },
{ RESULT_RAN_OUT_OF_KEY_IN_ONE_TIME_PAD,
"RESULT_RAN_OUT_OF_KEY_IN_ONE_TIME_PAD" },
{ RESULT_SKEIN_TEST_FINAL_RESULT_IS_INVALID,
"RESULT_SKEIN_TEST_FINAL_RESULT_IS_INVALID" },
{ RESULT_SKEIN_TEST_INITIALIZATION_FAILED,
"RESULT_SKEIN_TEST_INITIALIZATION_FAILED" },
{ RESULT_TEXT_LINE_TOO_LONG_FOR_BUFFER,
"RESULT_TEXT_LINE_TOO_LONG_FOR_BUFFER" },
{ 0, 0 } // This record marks the end of the list.
};
s8* ConvertIntegerToString64( u64 n );
u8 GeneratePseudoRandomByte();
u32 GenerateRandomFile( s8* FileName, u64 FileSize );
u64 Get_u64_LSB_to_MSB( u8* Buffer );
u64 GetFileSize64( FILE* F );
void InitPseudoRandomGenerator( u8* Seed, u32 ByteCount );
u32 IsFilesIdentical( s8* AFileName, s8* BFileName );
s8* LookUpResultCodeString( int ResultCode );
int main( int argc, char* argv[] );
void Put_u64_LSB_to_MSB( u64 n, u8* Buffer );
u32 ReadByte( FILE* FileHandle, u8* BufferAddress );
u32 ReadBytes( FILE* FileHandle, u8* BufferAddress, u32 NumberOfBytes );
void ReverseString( s8* A );
void Skein_Get64_LSB_First( u64* dst, u8* src, u32 WordCount );
void Skein_Put64_LSB_First( u8* dst, u64* src, u32 ByteCount );
void Skein1024_Final( Skein1024Context* ctx, u8* hashVal );
void Skein1024_Init( Skein1024Context* ctx, u32 hashBitLen );
void Skein1024_Print( Skein1024Context* ctx );
void Skein1024_Process_Block(
Skein1024Context* ctx,
u8* blkPtr,
u32 blkCnt,
u32 byteCntAdd );
u32 Skein1024_Test();
u32 Skein1024_TestCase( u8* MessageData, u32 MessageSize, u8* ExpectedResult );
void Skein1024_Update( Skein1024Context* ctx, u8* msg, u32 msgByteCnt );
int Test( s8* CommandLineString, int ExpectedResultCode );
int TestEncryptDecryptFile(
u64 FileSize,
s8* EncryptionCommandString,
s8* DecryptionCommandString );
void TestEncryptDecryptFiles_DefaultOptions(
u64 StartFileSize,
u64 EndFileSize,
u64 SizeIncrement );
void TestEncryptDecryptFiles_EncryptedFileFormatBinary(
u64 StartFileSize,
u64 EndFileSize,
u64 SizeIncrement );
void TestEncryptDecryptFiles_EncryptedFileFormatBase64(
u64 StartFileSize,
u64 EndFileSize,
u64 SizeIncrement );
void TestEncryptDecryptFiles_NoFileName(
u64 StartFileSize,
u64 EndFileSize,
u64 SizeIncrement );
u32 WriteByte( FILE* FileHandle, u8 AByte );
u32 WriteBytes( FILE* FileHandle, u8* BufferAddress, u32 AByteCount );
void ZeroBytes( u8* Destination, u32 AByteCount );
/*------------------------------------------------------------------------------
| main
|-------------------------------------------------------------------------------
|
| PURPOSE: Main routine for OT7 test program.
|
| DESCRIPTION: This is a separate program that calls the OT7 application to
| make sure it's working properly.
|
| Test encryption keys and plaintext files are pseudo-randomly generated during
| this test.
|
| Many different ways of using OT7 are tested with this generated data and test
| results are printed to standard output.
|
| 21MB of disk space are required for this test.
|
| This test can take an hour or more to run depending on the speed of the
| computer.
|
| The test ends early if any error is detected.
|
| HISTORY:
| 26Dec14
------------------------------------------------------------------------------*/
// OUT: Result code from interpreting the command line function.
int //
main( int argc, char* argv[] )
{
(void) argc;
(void) argv;
// Run OT7 with no command line parameters, expecting an error as a result.
Test( "./ot7", RESULT_NO_COMMAND_LINE_PARAMETERS_GIVEN );
// Test the option that suppresses all output.
Test( "./ot7 -silent", RESULT_OK );
// Test the hash function used by the crypto routines.
Test( "./ot7 -testhash", RESULT_OK );
// Test help request option, expecting no error as a result.
Test( "./ot7 -h", RESULT_OK );
// Initialize the pseudo-random number generator using "Seed" as the
// initialization vector.
InitPseudoRandomGenerator( (u8*) "Seed", 4 );
printf( "Generating a 30,000 byte encryption key file named '123.key'.\n" );
// Generate a 30,000,000 byte key file named '123.key' for use by
// TestEncryptDecryptFile_BinaryFormat() below.
GenerateRandomFile( "123.key", 30000LL );
printf( "Range across OT7 crypto options using a series of small \n" );
printf( "plaintext files.\n" );
TestEncryptDecryptFiles_DefaultOptions( 1LL, 10LL, 1LL );
TestEncryptDecryptFiles_NoFileName( 1LL, 10LL, 1LL );
TestEncryptDecryptFiles_EncryptedFileFormatBinary( 1LL, 10LL, 1LL );
TestEncryptDecryptFiles_EncryptedFileFormatBase64( 1LL, 10LL, 1LL );
printf( "Generating a 20,000,000 byte encryption key file named '123.key'.\n" );
// Generate a 20,000,000 key file named '123.key' for use by
// TestEncryptDecryptFile_BinaryFormat() below.
GenerateRandomFile( "123.key", 20000000LL );
printf( "Test encryption of every plaintext file size from 11 to 2100.\n" );
printf( "This test is looking for any special case failures associated\n" );
printf( "with sizes of the working buffers used in OT7.\n" );
TestEncryptDecryptFiles_DefaultOptions( 11LL, 2100LL, 1LL );
TestEncryptDecryptFiles_NoFileName( 11LL, 2100LL, 1LL );
TestEncryptDecryptFiles_EncryptedFileFormatBinary( 11LL, 2100LL, 1LL );
TestEncryptDecryptFiles_EncryptedFileFormatBase64( 11LL, 2100LL, 1LL );
printf( "Generating a 10,000,000 byte encryption key file named '123.key'.\n" );
// Generate a 10,000,000 key file named '123.key' for use by
// TestEncryptDecryptFile_BinaryFormat() below.
GenerateRandomFile( "123.key", 10000000LL );
printf( "Test encryption of plaintext file sizes spanning the 64K boundary.\n" );
TestEncryptDecryptFiles_DefaultOptions( 0xFFF0LL, 0x10005LL, 1LL );
TestEncryptDecryptFiles_NoFileName( 0xFFF0LL, 0x10005LL, 1LL );
TestEncryptDecryptFiles_EncryptedFileFormatBinary( 0xFFF0LL, 0x10005LL, 1LL );
TestEncryptDecryptFiles_EncryptedFileFormatBase64( 0xFFF0LL, 0x10005LL, 1LL );
// Getting to this point implies success with Result = RESULT_OK (0).
printf( "All tests passed OK.\n" );
printf( "Exiting OT7 test program with result code %d = %s.\n",
Result,
LookUpResultCodeString( Result ) );
// Return result code to the calling application.
return( Result );
}
/*------------------------------------------------------------------------------
| ConvertIntegerToString64
|-------------------------------------------------------------------------------
|
| PURPOSE: To produce a decimal ASCII string equivalent to an unsigned 64-bit
| integer.
|
| DESCRIPTION: Makes an ASCII number in a static buffer and returns the address
| of the buffer.
|
| EXAMPLE: MyString = ConvertIntegerToString( 123 );
|
| HISTORY:
| 09Nov13 Changed to support 64-bit integers with static buffer.
| 26Jan13 Revised to be unsigned rather than signed.
------------------------------------------------------------------------------*/
// OUT: Address of the string corresponding to n, in a static buffer.
s8* //
ConvertIntegerToString64( u64 n )
{
static s8 s[22];
s32 i;
// Start the byte counter at 0.
i = 0;
////////////
NextDigit://
////////////
// Divide n by 10, converting the remainder to an ASCII digit.
s[i++] = (s8) (n % 10 + '0');
// Move the decimal point over by one digit.
n /= 10;
// If more significant figures exist, go convert the next digit.
if( n > 0 )
{
goto NextDigit;
}
// Add zero end-of-string byte.
s[i] = 0;
// Reverse the order of the digits.
ReverseString( s );
// Return the string address.
return( (s8*) &s[0] );
}
/*------------------------------------------------------------------------------
| GeneratePseudoRandomByte
|-------------------------------------------------------------------------------
|
| PURPOSE: To generate a pseudo-random byte from the range 0 to 255 inclusive.
|
| DESCRIPTION: This implementation uses a Skein1024 hash function as a pseudo-
| random number generator. Any other method could be used here to produce test
| data, but the Skein routines are handy since they have already been tested
| using the test in OT7.c.
|
| Before using this routine, call InitPseudoRandomGenerator() to initialize
| the hash context and buffer pointer.
|
| HISTORY:
| 27Dec14 From GetNextByteFromPasswordHashStream() in OT7.c.
------------------------------------------------------------------------------*/
// OUT: The next pseudo-random byte.
u8 //
GeneratePseudoRandomByte()
{
u8 AByte;
// If there are no bytes in the pseudo-random data buffer, then generate a
// block from the pseudo-random hash context.
if( PseudoRandomDataBufferByteCount == 0 )
{
// Generate pseudo-random bytes to the PseudoRandomDataBuffer.
Skein1024_Final( &PseudoRandomHashContext,
(u8*) &PseudoRandomDataBuffer );
// Reset the content counter for the PseudoRandomDataBuffer to indicate
// that the buffer is full of data.
PseudoRandomDataBufferByteCount = PSEUDO_RANDOM_DATA_BUFFER_SIZE;
}
// Fetch the next byte from the pseudo-random data buffer.
AByte = PseudoRandomDataBuffer[PSEUDO_RANDOM_DATA_BUFFER_SIZE -
PseudoRandomDataBufferByteCount];
// Account for using one of the pseudo-random data bytes.
PseudoRandomDataBufferByteCount--;
// Return the byte.
return( AByte );
}
/*------------------------------------------------------------------------------
| GenerateRandomFile
|-------------------------------------------------------------------------------
|
| PURPOSE: To generate a file filled with pseudo-random bytes.
|
| DESCRIPTION: The data written to the file is unformatted binary values in the
| full range from 0 to 255 inclusive.
|
| This generator is intended for testing purposes only. It is not safe for
| making actual OT7 encryption keys, so use a true random number generator for
| that.
|
| HISTORY:
| 28Dec14
------------------------------------------------------------------------------*/
// OUT: Result code RESULT_OK if successful, or an error code if not.
u32 //
GenerateRandomFile( s8* FileName, u64 FileSize )
{
FILE* F;
u64 i;
u32 BytesWritten;
// Open an output file to write binary data.
F = fopen64( FileName, "wb" );
// If file was opened OK, write pseudo-random data to the file.
if( F )
{
// Write enough bytes to make a file of the given size.
for( i = 0; i < FileSize; i++ )
{
// Write one byte to the file.
BytesWritten = WriteByte( F, GeneratePseudoRandomByte() );
// If the byte was not written, then close the file and return
// an error result code.
if( BytesWritten != 1 )
{
// Close the file, leaving any partially written file on disk.
fclose( F );
// Return an error code that means the file could not be
// written.
return( RESULT_CANT_WRITE_FILE );
}
}
// Close the file after having written the whole file to disk.
fclose( F );
// Return a result code meaning successful completion.
return( RESULT_OK );
}
else // Unable to open the file for writing, so return an error code.
{
// Return an error code that means the file could not be opened
// for writing.
return( RESULT_CANT_OPEN_FILE_FOR_WRITING );
}
}
/*------------------------------------------------------------------------------
| Get_u64_LSB_to_MSB
|-------------------------------------------------------------------------------
|
| PURPOSE: To fetch a 64-bit integer from a buffer where it is stored in
| LSB-to-MSB order.
|
| DESCRIPTION: This makes integers for the kind of CPU that is running this
| code, unpacking it from a standard byte order used for data interchange.
|
| HISTORY:
| 09Nov13 From Get_u32_LSB_to_MSB().
------------------------------------------------------------------------------*/
// OUT: The 64-bit integer unpacked from the buffer.
u64 //
Get_u64_LSB_to_MSB( u8* Buffer )
{
u64 n;
// Assemble the 64-bit result from the first 8 bytes in the buffer which
// are stored in LSB-to-MSB order.
n = (u64) Buffer[7]; n <<= 8;
n |= (u64) Buffer[6]; n <<= 8;
n |= (u64) Buffer[5]; n <<= 8;
n |= (u64) Buffer[4]; n <<= 8;
n |= (u64) Buffer[3]; n <<= 8;
n |= (u64) Buffer[2]; n <<= 8;
n |= (u64) Buffer[1]; n <<= 8;
n |= (u64) Buffer[0];
// Return the integer.
return( n );
}
/*------------------------------------------------------------------------------
| GetFileSize64
|-------------------------------------------------------------------------------
|
| PURPOSE: To return the size of a given file in bytes.
|
| DESCRIPTION: Returns the number of data bytes in the file. Supports large
| files requiring 64-bit integers to represent the size.
|
| HISTORY:
| 06Oct13 Revised comments.
| 09Nov13 Change to support larger files needing 64-bit integers.
| 29Dec13 Added error handling.
------------------------------------------------------------------------------*/
// OUT: The number of bytes in the file, or MAX_VALUE_64BIT if there was
// an error.
u64 //
GetFileSize64( FILE* F )
{
s32 Status;
u64 EndPosition;
u64 CurrentPosition;
// Preserve the current file position.
CurrentPosition = (u64) ftello64( F );
// Set the file position to the end of the file.
// Returns 0 on success, or -1 if an error.
Status = (s32) fseeko64( F, (s64) 0, SEEK_END );
// If there was a seek error, then return MAX_VALUE_64BIT as an error code.
if( Status )
{
return( MAX_VALUE_64BIT );
}
// Get the position of the file pointer at the end of the file which is also
// the number of data bytes in the file.
EndPosition = (u64) ftello64( F );
// Restore original file position, set relative to the beginning of the
// file. Returns 0 on success, or -1 if an error.
Status = (s32) fseeko64( F, (s64) CurrentPosition, SEEK_SET );
// If there was a seek error, then return MAX_VALUE_64BIT as an error code.
if( Status )
{
return( MAX_VALUE_64BIT );
}
// Return the number of bytes in the file.
return( EndPosition );
}
/*------------------------------------------------------------------------------
| InitPseudoRandomGenerator
|-------------------------------------------------------------------------------
|
| PURPOSE: To initialize the pseudo-random number generator.
|
| DESCRIPTION: This implementation uses a Skein1024 hash function as a pseudo-
| random number generator.
|
| The input parameters specify a seed value for the generator. The seed defines
| which of many possible pseudo-random streams will be produced by the
| generator.
|
| HISTORY:
| 27Dec14 From GetNextByteFromPasswordHashStream() in OT7.c.
------------------------------------------------------------------------------*/
void
InitPseudoRandomGenerator( u8* Seed, u32 ByteCount )
{
// Zero the count of pseudo-random data bytes available in the
// PseudoRandomDataBuffer.
PseudoRandomDataBufferByteCount = 0;
// Initialize the pseudo-random hash context for producing a 1024-byte hash
// value.
Skein1024_Init( &PseudoRandomHashContext, PSEUDO_RANDOM_BUFFER_BIT_COUNT );
// Feed the seed value into the hash context to prepare for generating a
// stream of values that depends on the seed.
Skein1024_Update(
&PseudoRandomHashContext,
Seed,
ByteCount );
}
/*------------------------------------------------------------------------------
| IsFilesIdentical
|-------------------------------------------------------------------------------
|
| PURPOSE: To test if two files are identical in size and content.
|
| DESCRIPTION: Given the names of two files, this routine compares them to
| determine if they match.
|
| HISTORY:
| 29Dec14 From IsMatchingFiles().
------------------------------------------------------------------------------*/
// OUT: 1 if the files match, or 0 if they don't or there was an error.
u32 //
IsFilesIdentical( s8* AFileName, s8* BFileName )
{
FILE* fA;
FILE* fB;
u64 ASize, BSize, i;
u32 NumberOfBytesReadA;
u32 NumberOfBytesReadB;
u8 cA, cB;
// Open the first file for reading binary data.
fA = fopen64( AFileName, "rb" );
// If unable to open the file, then return 0.
if( fA == 0 )
{
// Return 0 to mean there was an error and so the files can't be
// identical.
return( 0 );
}
// Open the second file for reading binary data.
fB = fopen64( BFileName, "rb" );
// If unable to open the file, then return 0.
if( fB == 0 )
{
// Return 0 to mean there was an error and so the files can't be
// identical.
return( 0 );
}
// Get the file size in bytes of the first file, or MAX_VALUE_64BIT if there
// was an error.
ASize = GetFileSize64( fA );
// Get the file size in bytes of the second file, or MAX_VALUE_64BIT if
// there was an error.
BSize = GetFileSize64( fB );
// If the file sizes differ or if there was an error when determining the
// file sizes, then return 0.
if( (ASize != BSize) ||
(ASize == MAX_VALUE_64BIT) )
{
// Close the first file.
fclose( fA );
// Close the second file.
fclose( fB );