1 /**
2  * Main module that handles various hashing algorithms at run-time.
3  *
4  * Authors: dd86k <dd@dax.moe>
5  * Copyright: None
6  * License: Public domain
7  */
8 module ddh;
9 
10 private import std.digest.sha, std.digest.md, std.digest.ripemd, std.digest.crc;
11 private import sha3d.sha3;
12 
13 version (PrintInfo)
14 {
15 	pragma(msg, "CRC32.sizeof\t",	CRC32.sizeof);
16 	pragma(msg, "CRC64ISO.sizeof\t",	CRC64ISO.sizeof);
17 	pragma(msg, "CRC64ECMA.sizeof\t",	CRC64ECMA.sizeof);
18 	pragma(msg, "MD5.sizeof\t",	MD5.sizeof);
19 	pragma(msg, "RIPEMD160.sizeof\t",	RIPEMD160.sizeof);
20 	pragma(msg, "SHA1.sizeof\t",	SHA1.sizeof);
21 	pragma(msg, "SHA224.sizeof\t",	SHA224.sizeof);
22 	pragma(msg, "SHA256.sizeof\t",	SHA256.sizeof);
23 	pragma(msg, "SHA384.sizeof\t",	SHA384.sizeof);
24 	pragma(msg, "SHA512.sizeof\t",	SHA512.sizeof);
25 	pragma(msg, "SHA3_224.sizeof\t",	SHA3_224.sizeof);
26 	pragma(msg, "SHA3_256.sizeof\t",	SHA3_256.sizeof);
27 	pragma(msg, "SHA3_384.sizeof\t",	SHA3_384.sizeof);
28 	pragma(msg, "SHA3_512.sizeof\t",	SHA3_512.sizeof);
29 	pragma(msg, "SHAKE128.sizeof\t",	SHAKE128.sizeof);
30 	pragma(msg, "SHAKE256.sizeof\t",	SHAKE256.sizeof);
31 	pragma(msg, "BLAKE2.sizeof\t",	BLAKE2.sizeof);
32 	pragma(msg, "BLAKE2b.sizeof\t",	BLAKE2b.sizeof);
33 	pragma(msg, "BLAKE2s.sizeof\t",	BLAKE2s.sizeof);
34 }
35 
36 /// Choose which checksum or hash will be used
37 enum DDHType
38 {
39 	CRC32,
40 	CRC64ISO,
41 	CRC64ECMA,
42 	MD5,
43 	RIPEMD160,
44 	SHA1,
45 	SHA224,
46 	SHA256,
47 	SHA384,
48 	SHA512,
49 	SHA3_224,
50 	SHA3_256,
51 	SHA3_384,
52 	SHA3_512,
53 	SHAKE128,
54 	SHAKE256,
55 }
56 
57 template DGSTSZ(DDHType type)
58 {
59 	static if (type == DDHType.CRC32)
60 	{
61 		enum DGSTSZ = BITS!(32);
62 	}
63 	else static if (type == DDHType.CRC64ISO)
64 	{
65 		enum DGSTSZ = BITS!(64);
66 	}
67 	else static if (type == DDHType.CRC64ECMA)
68 	{
69 		enum DGSTSZ = BITS!(64);
70 	}
71 	else static if (type == DDHType.MD5)
72 	{
73 		enum DGSTSZ = BITS!(128);
74 	}
75 	else static if (type == DDHType.RIPEMD160)
76 	{
77 		enum DGSTSZ = BITS!(160);
78 	}
79 	else static if (type == DDHType.SHA1)
80 	{
81 		enum DGSTSZ = BITS!(160);
82 	}
83 	else static if (type == DDHType.SHA224)
84 	{
85 		enum DGSTSZ = BITS!(224);
86 	}
87 	else static if (type == DDHType.SHA256)
88 	{
89 		enum DGSTSZ = BITS!(256);
90 	}
91 	else static if (type == DDHType.SHA384)
92 	{
93 		enum DGSTSZ = BITS!(384);
94 	}
95 	else static if (type == DDHType.SHA512)
96 	{
97 		enum DGSTSZ = BITS!(512);
98 	}
99 	else static if (type == DDHType.SHA3_224)
100 	{
101 		enum DGSTSZ = BITS!(224);
102 	}
103 	else static if (type == DDHType.SHA3_256)
104 	{
105 		enum DGSTSZ = BITS!(256);
106 	}
107 	else static if (type == DDHType.SHA3_384)
108 	{
109 		enum DGSTSZ = BITS!(384);
110 	}
111 	else static if (type == DDHType.SHA3_512)
112 	{
113 		enum DGSTSZ = BITS!(512);
114 	}
115 	else static if (type == DDHType.SHAKE128)
116 	{
117 		enum DGSTSZ = BITS!(128);
118 	}
119 	else static if (type == DDHType.SHAKE256)
120 	{
121 		enum DGSTSZ = BITS!(256);
122 	}
123 	else static assert(0, "Implement DGSTSZ");
124 }
125 
126 private alias func_compute = extern (C) void function(DDH_INTERNALS_T*, ubyte[]);
127 private alias func_finish  = extern (C) ubyte[] function(DDH_INTERNALS_T*);
128 private alias func_reset   = extern (C) void function(DDH_INTERNALS_T*);
129 
130 /// Main structure
131 struct DDH_T
132 {
133 	DDHType type;	/// Checksum or hash type
134 	func_compute compute;	/// compute function ptr
135 	func_finish finish;	/// finish function ptr
136 	func_reset reset;	/// reset function ptr
137 	union
138 	{
139 		void *voidptr;	/// Void pointer for allocation
140 		DDH_INTERNALS_T *inptr;	/// Internal pointer for allocation
141 	}
142 	bool internalInit;
143 }
144 
145 /// Internals for DDH_T
146 private struct DDH_INTERNALS_T
147 {
148 	enum BIGGEST = BITS!(512);
149 	union
150 	{
151 		CRC32 crc32;	/// CRC-32
152 		CRC64ISO crc64iso;	/// CRC-64-ISO
153 		CRC64ECMA crc64ecma;	/// CRC-64-ECMA
154 		MD5 md5;	/// MD-5
155 		RIPEMD160 ripemd160;	/// RIPEMD-160
156 		SHA1 sha1;	/// SHA-1
157 		SHA224 sha224;	/// SHA-2-224
158 		SHA256 sha256;	/// SHA-2-256
159 		SHA384 sha384;	/// SHA-2-384
160 		SHA512 sha512;	/// SHA-2-512
161 		SHA3_224 sha3_224;	/// SHA-3-256
162 		SHA3_256 sha3_256;	/// SHA-3-256
163 		SHA3_384 sha3_384;	/// SHA-3-256
164 		SHA3_512 sha3_512;	/// SHA-3-256
165 		SHAKE128 shake128;	/// SHAKE-128
166 		SHAKE256 shake256;	/// SHAKE-256
167 	}
168 	union
169 	{
170 		ubyte[BIGGEST] buffer;	/// Internal buffer for raw result
171 		ulong bufferu64;	/// Internal union type
172 		uint bufferu32;	/// Internal union type
173 	}
174 	size_t bufferlen;	/// Internal buffer raw result size
175 	char[BIGGEST * 2] result;	/// Internal buffer for formatted result
176 }
177 
178 //TODO: Template that lets me initiate structure
179 //      In a cute way
180 
181 /// 
182 struct DDHInfo
183 {
184 	DDHType type;	/// static action
185 	uint size;	/// static digest_size
186 	string name;	/// static name
187 	string basename;	/// static basename
188 	string tagname;	/// BSD-style tag name
189 	func_compute fcomp;	/// static fcomp
190 	func_finish fdone;	/// static fdone
191 	func_reset freset;	/// static freset
192 }
193 
194 /// Structure information
195 immutable DDHInfo[] meta_info = [
196 	{
197 		DDHType.CRC32, DGSTSZ!(DDHType.CRC32),
198 		"CRC-32", "crc32", "CRC32",
199 		&ddh_compute!(DDHType.CRC32),
200 		&ddh_finish!(DDHType.CRC32),
201 		&ddh_reset!(DDHType.CRC32),
202 	},
203 	{
204 		DDHType.CRC64ISO, DGSTSZ!(DDHType.CRC64ISO),
205 		"CRC-64-ISO", "crc64iso", "CRC64ISO",
206 		&ddh_compute!(DDHType.CRC64ISO),
207 		&ddh_finish!(DDHType.CRC64ISO),
208 		&ddh_reset!(DDHType.CRC64ISO),
209 	},
210 	{
211 		DDHType.CRC64ECMA, DGSTSZ!(DDHType.CRC64ECMA),
212 		"CRC-64-ECMA", "crc64ecma", "CRC64ECMA",
213 		&ddh_compute!(DDHType.CRC64ECMA),
214 		&ddh_finish!(DDHType.CRC64ECMA),
215 		&ddh_reset!(DDHType.CRC64ECMA),
216 	},
217 	{
218 		DDHType.MD5, DGSTSZ!(DDHType.MD5),
219 		"MD5-128", "md5", "MD5",
220 		&ddh_compute!(DDHType.MD5),
221 		&ddh_finish!(DDHType.MD5),
222 		&ddh_reset!(DDHType.MD5)
223 	},
224 	{
225 		DDHType.RIPEMD160, DGSTSZ!(DDHType.RIPEMD160),
226 		"RIPEMD-160", "ripemd160", "RIPEMD160",
227 		&ddh_compute!(DDHType.RIPEMD160),
228 		&ddh_finish!(DDHType.RIPEMD160),
229 		&ddh_reset!(DDHType.RIPEMD160)
230 	},
231 	{
232 		DDHType.SHA1, DGSTSZ!(DDHType.SHA1),
233 		"SHA-1-160", "sha1", "SHA1",
234 		&ddh_compute!(DDHType.SHA1),
235 		&ddh_finish!(DDHType.SHA1),
236 		&ddh_reset!(DDHType.SHA1)
237 	},
238 	{
239 		DDHType.SHA224, DGSTSZ!(DDHType.SHA224),
240 		"SHA-2-224", "sha224", "SHA224",
241 		&ddh_compute!(DDHType.SHA224),
242 		&ddh_finish!(DDHType.SHA224),
243 		&ddh_reset!(DDHType.SHA224)
244 	},
245 	{
246 		DDHType.SHA256, DGSTSZ!(DDHType.SHA256),
247 		"SHA-2-256", "sha256", "SHA256",
248 		&ddh_compute!(DDHType.SHA256),
249 		&ddh_finish!(DDHType.SHA256),
250 		&ddh_reset!(DDHType.SHA256)
251 	},
252 	{
253 		DDHType.SHA384, DGSTSZ!(DDHType.SHA384),
254 		"SHA-2-384", "sha384", "SHA384",
255 		&ddh_compute!(DDHType.SHA384),
256 		&ddh_finish!(DDHType.SHA384),
257 		&ddh_reset!(DDHType.SHA384)
258 	},
259 	{
260 		DDHType.SHA512, DGSTSZ!(DDHType.SHA512),
261 		"SHA-2-512", "sha512", "SHA512",
262 		&ddh_compute!(DDHType.SHA512),
263 		&ddh_finish!(DDHType.SHA512),
264 		&ddh_reset!(DDHType.SHA512)
265 	},
266 	{
267 		DDHType.SHA3_224, DGSTSZ!(DDHType.SHA3_224),
268 		"SHA-3-224", "sha3-224", "SHA3_224",
269 		&ddh_compute!(DDHType.SHA3_224),
270 		&ddh_finish!(DDHType.SHA3_224),
271 		&ddh_reset!(DDHType.SHA3_224)
272 	},
273 	{
274 		DDHType.SHA3_256, DGSTSZ!(DDHType.SHA3_256),
275 		"SHA-3-256", "sha3-256", "SHA3_256",
276 		&ddh_compute!(DDHType.SHA3_256),
277 		&ddh_finish!(DDHType.SHA3_256),
278 		&ddh_reset!(DDHType.SHA3_256)
279 	},
280 	{
281 		DDHType.SHA3_384, DGSTSZ!(DDHType.SHA3_384),
282 		"SHA-3-384", "sha3-384", "SHA3_384",
283 		&ddh_compute!(DDHType.SHA3_384),
284 		&ddh_finish!(DDHType.SHA3_384),
285 		&ddh_reset!(DDHType.SHA3_384)
286 	},
287 	{
288 		DDHType.SHA3_512, DGSTSZ!(DDHType.SHA3_512),
289 		"SHA-3-512", "sha3-512", "SHA3_512",
290 		&ddh_compute!(DDHType.SHA3_512),
291 		&ddh_finish!(DDHType.SHA3_512),
292 		&ddh_reset!(DDHType.SHA3_512)
293 	},
294 	{
295 		DDHType.SHAKE128, DGSTSZ!(DDHType.SHAKE128),
296 		"SHAKE-128", "shake128", "SHAKE128",
297 		&ddh_compute!(DDHType.SHAKE128),
298 		&ddh_finish!(DDHType.SHAKE128),
299 		&ddh_reset!(DDHType.SHAKE128)
300 	},
301 	{
302 		DDHType.SHAKE256, DGSTSZ!(DDHType.SHAKE128),
303 		"SHAKE-256", "shake256", "SHAKE256",
304 		&ddh_compute!(DDHType.SHAKE256),
305 		&ddh_finish!(DDHType.SHAKE256),
306 		&ddh_reset!(DDHType.SHAKE256)
307 	}
308 ];
309 static assert(meta_info.length == DDHType.max + 1);
310 // GDC 10.0 supports static foreach, GDC 9.3 does not
311 unittest
312 {
313 	foreach (i, DDHInfo info; meta_info)
314 	{
315 		assert(info.type == cast(DDHType)i);
316 	}
317 }
318 
319 // Helps converting bits to byte sizes, avoids errors
320 private template BITS(int n) if (n % 8 == 0) { enum { BITS = n >> 3 } }
321 /// BITS test
322 unittest { static assert(BITS!(32) == 4); }
323 
324 /// Initiates a DDH_T structure with an DDHType value.
325 /// Params:
326 /// 	ddh = DDH_T structure
327 /// 	type = DDHType value
328 /// Returns: True on error
329 bool ddh_init(ref DDH_T ddh, DDHType type)
330 {
331 	import core.stdc.stdlib : malloc;
332 	
333 	if (ddh.internalInit == false)
334 	{
335 		ddh.voidptr = malloc(DDH_INTERNALS_T.sizeof);
336 		if (ddh.voidptr == null)
337 			return true;
338 		ddh.internalInit = true;
339 	}
340 	
341 	size_t i = ddh.type = type;
342 	ddh.compute = meta_info[i].fcomp;
343 	ddh.finish  = meta_info[i].fdone;
344 	ddh.reset   = meta_info[i].freset;
345 	ddh.inptr.bufferlen = meta_info[i].size;
346 	
347 	ddh_reset(ddh);
348 	
349 	return false;
350 }
351 
352 /// Get the digest size in bytes
353 /// Returns: Digest size
354 uint ddh_digest_size(ref DDH_T ddh)
355 {
356 	return meta_info[ddh.type].size;
357 }
358 
359 /// Compute a block of data
360 /// Params:
361 /// 	ddh = DDH_T structure
362 /// 	data = Byte array
363 void ddh_compute(ref DDH_T ddh, ubyte[] data)
364 {
365 	ddh.compute(ddh.inptr, data);
366 }
367 
368 /// Finalize digest or checksum
369 /// Params: ddh = DDH_T structure
370 /// Returns: Raw digest slice
371 ubyte[] ddh_finish(ref DDH_T ddh)
372 {
373 	return ddh.finish(ddh.inptr);
374 }
375 
376 /// Re-initiates the DDH session.
377 /// Params: ddh = DDH_T structure
378 void ddh_reset(ref DDH_T ddh)
379 {
380 	ddh.reset(ddh.inptr);
381 }
382 
383 /// Finalize digest or checksum and return formatted 
384 /// Finalize and return formatted diggest
385 /// Params: ddh = DDH_T structure
386 /// Returns: Formatted digest
387 char[] ddh_string(ref DDH_T ddh)
388 {
389 	import std.format : sformat;
390 	
391 	ddh_finish(ddh);
392 	
393 	switch (ddh.type)
394 	{
395 	case DDHType.CRC64ISO, DDHType.CRC64ECMA:	// 64 bits
396 		return sformat(ddh.inptr.result, "%016x", ddh.inptr.bufferu64);
397 	case DDHType.CRC32:	// 32 bits
398 		return sformat(ddh.inptr.result, "%08x", ddh.inptr.bufferu32);
399 	default:	// Of any length
400 		const size_t len = ddh.inptr.bufferlen;
401 		ubyte *tbuf = ddh.inptr.buffer.ptr;
402 		char  *rbuf = ddh.inptr.result.ptr;
403 		for (size_t i; i < len; ++i) {
404 			ubyte v = tbuf[i];
405 			rbuf[1] = fasthexchar(v & 0xF);
406 			rbuf[0] = fasthexchar(v >> 4);
407 			rbuf += 2;
408 		}
409 		return ddh.inptr.result[0..len << 1];
410 	}
411 }
412 
413 private:
414 extern (C):
415 
416 pragma(inline, true)
417 char fasthexchar(ubyte v) nothrow pure @nogc @safe
418 {
419 	return cast(char)(v <= 9 ? v + 48 : v + 87);
420 }
421 
422 void ddh_compute(DDHType type)(DDH_INTERNALS_T *v, ubyte[] data)
423 {
424 	static if (type == DDHType.CRC32)
425 	{
426 		v.crc32.put(data);
427 	}
428 	else static if (type == DDHType.CRC64ISO)
429 	{
430 		v.crc64iso.put(data);
431 	}
432 	else static if (type == DDHType.CRC64ECMA)
433 	{
434 		v.crc64ecma.put(data);
435 	}
436 	else static if (type == DDHType.MD5)
437 	{
438 		v.md5.put(data);
439 	}
440 	else static if (type == DDHType.RIPEMD160)
441 	{
442 		v.ripemd160.put(data);
443 	}
444 	else static if (type == DDHType.SHA1)
445 	{
446 		v.sha1.put(data);
447 	}
448 	else static if (type == DDHType.SHA224)
449 	{
450 		v.sha224.put(data);
451 	}
452 	else static if (type == DDHType.SHA256)
453 	{
454 		v.sha256.put(data);
455 	}
456 	else static if (type == DDHType.SHA384)
457 	{
458 		v.sha384.put(data);
459 	}
460 	else static if (type == DDHType.SHA512)
461 	{
462 		v.sha512.put(data);
463 	}
464 	else static if (type == DDHType.SHA3_224)
465 	{
466 		v.sha3_224.put(data);
467 	}
468 	else static if (type == DDHType.SHA3_256)
469 	{
470 		v.sha3_256.put(data);
471 	}
472 	else static if (type == DDHType.SHA3_384)
473 	{
474 		v.sha3_384.put(data);
475 	}
476 	else static if (type == DDHType.SHA3_512)
477 	{
478 		v.sha3_512.put(data);
479 	}
480 	else static if (type == DDHType.SHAKE128)
481 	{
482 		v.shake128.put(data);
483 	}
484 	else static if (type == DDHType.SHAKE256)
485 	{
486 		v.shake256.put(data);
487 	}
488 	else static assert(0, "Implement ddh_compute");
489 }
490 
491 ubyte[] ddh_finish(DDHType type)(DDH_INTERNALS_T *v)
492 {
493 	static if (type == DDHType.CRC32)
494 	{
495 		return v.buffer[0..DGSTSZ!(DDHType.CRC32)] = v.crc32.finish()[];
496 	}
497 	else static if (type == DDHType.CRC64ISO)
498 	{
499 		return v.buffer[0..DGSTSZ!(DDHType.CRC64ISO)] = v.crc64iso.finish()[];
500 	}
501 	else static if (type == DDHType.CRC64ECMA)
502 	{
503 		return v.buffer[0..DGSTSZ!(DDHType.CRC64ECMA)] = v.crc64ecma.finish()[];
504 	}
505 	else static if (type == DDHType.MD5)
506 	{
507 		return v.buffer[0..DGSTSZ!(DDHType.MD5)] = v.md5.finish()[];
508 	}
509 	else static if (type == DDHType.RIPEMD160)
510 	{
511 		return v.buffer[0..DGSTSZ!(DDHType.RIPEMD160)] = v.ripemd160.finish()[];
512 	}
513 	else static if (type == DDHType.SHA1)
514 	{
515 		return v.buffer[0..DGSTSZ!(DDHType.SHA1)] = v.sha1.finish()[];
516 	}
517 	else static if (type == DDHType.SHA224)
518 	{
519 		return v.buffer[0..DGSTSZ!(DDHType.SHA224)] = v.sha224.finish()[];
520 	}
521 	else static if (type == DDHType.SHA256)
522 	{
523 		return v.buffer[0..DGSTSZ!(DDHType.SHA256)] = v.sha256.finish()[];
524 	}
525 	else static if (type == DDHType.SHA384)
526 	{
527 		return v.buffer[0..DGSTSZ!(DDHType.SHA384)] = v.sha384.finish()[];
528 	}
529 	else static if (type == DDHType.SHA512)
530 	{
531 		return v.buffer[0..DGSTSZ!(DDHType.SHA512)] = v.sha512.finish()[];
532 	}
533 	else static if (type == DDHType.SHA3_224)
534 	{
535 		return v.buffer[0..DGSTSZ!(DDHType.SHA3_224)] = v.sha3_224.finish()[];
536 	}
537 	else static if (type == DDHType.SHA3_256)
538 	{
539 		return v.buffer[0..DGSTSZ!(DDHType.SHA3_256)] = v.sha3_256.finish()[];
540 	}
541 	else static if (type == DDHType.SHA3_384)
542 	{
543 		return v.buffer[0..DGSTSZ!(DDHType.SHA3_384)] = v.sha3_384.finish()[];
544 	}
545 	else static if (type == DDHType.SHA3_512)
546 	{
547 		return v.buffer[0..DGSTSZ!(DDHType.SHA3_512)] = v.sha3_512.finish()[];
548 	}
549 	else static if (type == DDHType.SHAKE128)
550 	{
551 		return v.buffer[0..DGSTSZ!(DDHType.SHAKE128)] = v.shake128.finish()[];
552 	}
553 	else static if (type == DDHType.SHAKE256)
554 	{
555 		return v.buffer[0..DGSTSZ!(DDHType.SHAKE256)] = v.shake256.finish()[];
556 	}
557 	else static assert(0, "Implement ddh_compute");
558 }
559 
560 void ddh_reset(DDHType type)(DDH_INTERNALS_T *v)
561 {
562 	static if (type == DDHType.CRC32)
563 	{
564 		v.crc32.start();
565 	}
566 	else static if (type == DDHType.CRC64ISO)
567 	{
568 		v.crc64iso.start();
569 	}
570 	else static if (type == DDHType.CRC64ECMA)
571 	{
572 		v.crc64ecma.start();
573 	}
574 	else static if (type == DDHType.MD5)
575 	{
576 		v.md5.start();
577 	}
578 	else static if (type == DDHType.RIPEMD160)
579 	{
580 		v.ripemd160.start();
581 	}
582 	else static if (type == DDHType.SHA1)
583 	{
584 		v.sha1.start();
585 	}
586 	else static if (type == DDHType.SHA224)
587 	{
588 		v.sha224.start();
589 	}
590 	else static if (type == DDHType.SHA256)
591 	{
592 		v.sha256.start();
593 	}
594 	else static if (type == DDHType.SHA384)
595 	{
596 		v.sha384.start();
597 	}
598 	else static if (type == DDHType.SHA512)
599 	{
600 		v.sha512.start();
601 	}
602 	else static if (type == DDHType.SHA3_224)
603 	{
604 		v.sha3_224.start();
605 	}
606 	else static if (type == DDHType.SHA3_256)
607 	{
608 		v.sha3_256.start();
609 	}
610 	else static if (type == DDHType.SHA3_384)
611 	{
612 		v.sha3_384.start();
613 	}
614 	else static if (type == DDHType.SHA3_512)
615 	{
616 		v.sha3_512.start();
617 	}
618 	else static if (type == DDHType.SHAKE128)
619 	{
620 		v.shake128.start();
621 	}
622 	else static if (type == DDHType.SHAKE256)
623 	{
624 		v.shake256.start();
625 	}
626 	else static assert(0, "Implement ddh_compute");
627 }