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 }