1 /*
2  * -------------------------------------------------------------------------
3  * Run SHA-3 (NIST FIPS 202) on the given file.
4  *
5  * Call as
6  *
7  * sha3sum 256|384|512 file_path
8  *
9  * See sha3.c for additional details.
10  *
11  * Jun 2018. Andrey Jivsov. crypto@brainhub.org
12  * ----------------------------------------------------------------------
13  */
14 module sha3sum;
15 
16 
17 private static import core.stdc.stdio;
18 private static import core.stdc.stdlib;
19 private static import core.stdc.string;
20 private static import core.stdc.wchar_;
21 private static import core.sys.posix.fcntl;
22 private static import core.sys.posix.sys.mman;
23 private static import core.sys.posix.sys.stat;
24 private static import core.sys.posix.unistd;
25 private static import sha3iuf_d;
26 
27 nothrow @nogc @live
28 private void help(scope const char* argv0)
29 
30 	do
31 	{
32 		core.stdc.stdio.printf("To call: %s 256|384|512 [-k] file_path.\n", argv0);
33 	}
34 
35 pure nothrow @nogc @live
36 private void byte_to_hex(ubyte b, ref char[3] s)
37 
38 	do
39 	{
40 		s[0] = '0';
41 		s[1] = '0';
42 		s[2] = '\0';
43 		uint i = 1;
44 
45 		while (b != 0) {
46 			uint t = b & 0x0F;
47 			assert(i < 2);
48 
49 			if (t < 10) {
50 				s[i] = cast(char)('0' + t);
51 			} else {
52 				s[i] = cast(char)('a' + t - 10);
53 			}
54 
55 			i--;
56 			b >>= 4;
57 		}
58 	}
59 
60 version (Posix)
61 extern (C)
62 nothrow @nogc @live
63 int main(int argc, char** argv)
64 
65 	do
66 	{
67 		if ((argc != 3) && (argc != 4)) {
68 			.help(argv[0]);
69 
70 			return 1;
71 		}
72 
73 		int image_size = core.stdc.stdlib.atoi(argv[1]);
74 
75 		switch (image_size) {
76 			case 256:
77 			case 384:
78 			case 512:
79 				break;
80 
81 			default:
82 				.help(argv[0]);
83 
84 				return 1;
85 		}
86 
87 		const (char)* file_path = argv[2];
88 		bool use_keccak = false;
89 
90 		if ((argc == 4) && (file_path[0] == '-') && (file_path[1] == 'k')) {
91 			use_keccak = true;
92 			file_path = argv[3];
93 		}
94 
95 		if (core.sys.posix.unistd.access(file_path, core.sys.posix.unistd.R_OK) != 0) {
96 			core.stdc.stdio.printf("Cannot read file '%s'", file_path);
97 
98 			return 2;
99 		}
100 
101 		int fd = core.sys.posix.fcntl.open(file_path, core.sys.posix.fcntl.O_RDONLY);
102 
103 		if (fd == -1) {
104 			core.stdc.stdio.printf("Cannot open file '%s' for reading", file_path);
105 
106 			return 2;
107 		}
108 
109 		core.sys.posix.sys.stat.stat_t st = void;
110 		uint i = core.sys.posix.sys.stat.fstat(fd, &st);
111 
112 		if (i != 0) {
113 			core.sys.posix.unistd.close(fd);
114 			core.stdc.stdio.printf("Cannot determine the size of file '%s'", file_path);
115 
116 			return 2;
117 		}
118 
119 		void* p = core.sys.posix.sys.mman.mmap(null, st.st_size, core.sys.posix.sys.mman.PROT_READ, core.sys.posix.sys.mman.MAP_SHARED, fd, 0);
120 		core.sys.posix.unistd.close(fd);
121 
122 		if (p == null) {
123 			core.stdc.stdio.printf("Cannot memory-map file '%s'", file_path);
124 
125 			return 2;
126 		}
127 
128 		sha3iuf_d.sha3_context c = void;
129 
130 		switch (image_size) {
131 			case 256:
132 				sha3iuf_d.sha3_Init256(&c);
133 
134 				break;
135 
136 			case 384:
137 				sha3iuf_d.sha3_Init384(&c);
138 
139 				break;
140 
141 			case 512:
142 				sha3iuf_d.sha3_Init512(&c);
143 
144 				break;
145 
146 			default:
147 				assert(false);
148 		}
149 
150 		if (use_keccak) {
151 			sha3iuf_d.SHA3_FLAGS flags2 = sha3iuf_d.sha3_SetFlags(&c, sha3iuf_d.SHA3_FLAGS.SHA3_FLAGS_KECCAK);
152 
153 			if (flags2 != sha3iuf_d.SHA3_FLAGS.SHA3_FLAGS_KECCAK) {
154 				core.stdc.stdio.printf("Failed to set Keccak mode");
155 
156 				return 2;
157 			}
158 		}
159 
160 		sha3iuf_d.sha3_Update(&c, p, st.st_size);
161 		const ubyte* hash = cast(const ubyte*)(sha3iuf_d.sha3_Finalize(&c));
162 
163 		core.sys.posix.sys.mman.munmap(p, st.st_size);
164 
165 		for (i = 0; i < (image_size / 8); i++) {
166 			char[3] s = void;
167 			.byte_to_hex(hash[i], s);
168 			core.stdc.stdio.printf("%s", &(s[0]));
169 		}
170 
171 		core.stdc.stdio.printf("  %s\n", file_path);
172 
173 		return 0;
174 	}