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 }