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