>From 19474b1ba1da612b9852074222c8017b5f6bbb19 Mon Sep 17 00:00:00 2001 From: apache2 Date: Sun, 10 Apr 2022 06:52:47 +0200 Subject: [PATCH] add md5.pk pickle --- pickles/md5.pk | 160 +++++++++++++++++++++++++++++ testsuite/Makefile.am | 1 + testsuite/poke.pickles/md5-test.pk | 58 +++++++++++ 3 files changed, 219 insertions(+) create mode 100644 pickles/md5.pk create mode 100644 testsuite/poke.pickles/md5-test.pk diff --git a/pickles/md5.pk b/pickles/md5.pk new file mode 100644 index 00000000..eaa94749 --- /dev/null +++ b/pickles/md5.pk @@ -0,0 +1,160 @@ +// +// MD5_Single(byte[])byte[16] is probably what you are looking for :-) +// if you want hash something without keeping it in memory, +// see the function body for details on how to do streaming hashing. +// To get the result, call .bytes() on the MD5_Context +// + +var MD5_s = [7U, 12U, 17U, 22U, 7U, 12U, 17U, 22U, 7U, 12U, 17U, 22U, 7U, 12U, 17U, 22U, + 5U, 9U, 14U, 20U, 5U, 9U, 14U, 20U, 5U, 9U, 14U, 20U, 5U, 9U, 14U, 20U, + 4U, 11U, 16U, 23U, 4U, 11U, 16U, 23U, 4U, 11U, 16U, 23U, 4U, 11U, 16U, 23U, + 6U, 10U, 15U, 21U, 6U, 10U, 15U, 21U, 6U, 10U, 15U, 21U, 6U, 10U, 15U, 21U]; + +var MD5_K = [0xd76aa478U, 0xe8c7b756U, 0x242070dbU, 0xc1bdceeeU, 0xf57c0fafU, + 0x4787c62aU, 0xa8304613U, 0xfd469501U, 0x698098d8U, 0x8b44f7afU, 0xffff5bb1U, + 0x895cd7beU, 0x6b901122U, 0xfd987193U, 0xa679438eU, 0x49b40821U, 0xf61e2562U, + 0xc040b340U, 0x265e5a51U, 0xe9b6c7aaU, 0xd62f105dU, 0x02441453U, 0xd8a1e681U, + 0xe7d3fbc8U, 0x21e1cde6U, 0xc33707d6U, 0xf4d50d87U, 0x455a14edU, 0xa9e3e905U, + 0xfcefa3f8U, 0x676f02d9U, 0x8d2a4c8aU, 0xfffa3942U, 0x8771f681U, 0x6d9d6122U, + 0xfde5380cU, 0xa4beea44U, 0x4bdecfa9U, 0xf6bb4b60U, 0xbebfbc70U, 0x289b7ec6U, + 0xeaa127faU, 0xd4ef3085U, 0x04881d05U, 0xd9d4d039U, 0xe6db99e5U, 0x1fa27cf8U, + 0xc4ac5665U, 0xf4292244U, 0x432aff97U, 0xab9423a7U, 0xfc93a039U, 0x655b59c3U, + 0x8f0ccc92U, 0xffeff47dU, 0x85845dd1U, 0x6fa87e4fU, 0xfe2ce6e0U, 0xa3014314U, + 0x4e0811a1U, 0xf7537e82U, 0xbd3af235U, 0x2ad7d2bbU, 0xeb86d391U]; // 64 elements + +var MD5_A = 0x67452301u; +var MD5_B = 0xefcdab89u; +var MD5_C = 0x98badcfeu; +var MD5_D = 0x10325476u; + +type MD5_Context = struct { + little uint32 a0 = MD5_A; + little uint32 b0 = MD5_B; + little uint32 c0 = MD5_C; + little uint32 d0 = MD5_D; + little uint64 bits_hashed = 0; + method bytes = byte[16]: + { + // TODO ugly + var out = byte[](); + var xyz = open("*data*"); + var f = uint32[4] @ xyz : 0#b; + f[0] = a0; + f[1] = b0; + f[2] = c0; + f[3] = d0; + for (var i = 0; i < 4 ; i++) { + var w = byte[4] @ xyz : (i*4)#B; + reverse(w); + out += w; + } + close(xyz); + return out; + } + method hexdigest = string: + { + var out = bytes(); + var p = ""; + for(b in out) + p += format("%u8x", b); + return p; + } + method _print = void: { + printf("%s", hexdigest()); + } +}; + +fun MD5_rotateLeft = (uint32 x, uint32 c)int:{ + return (x <<. c) | (x .>> (32-c)); +}; + +fun MD5_Round = (MD5_Context ctx, byte[] byte_M)void: + { + var M = uint32[16](); + for (var Mi = 0; Mi < 16; Mi++) { + M[Mi] |= (byte_M[Mi*4 + 0] as uint32 <<. 0); + M[Mi] |= (byte_M[Mi*4 + 1] as uint32 <<. 8); + M[Mi] |= (byte_M[Mi*4 + 2] as uint32 <<. 16); + M[Mi] |= (byte_M[Mi*4 + 3] as uint32 <<. 24); + } + var A = ctx.a0; + var B = ctx.b0; + var C = ctx.c0; + var D = ctx.d0; + for (var i = 0u; i < 64; i++) { + var F = 0u; var g = 0u; + if ( 0 <= i && i <= 15) { + F = (B & C) | ((~B) & D); + g = i; + } else if (16 <= i && i <= 31) { + F = (D & B) | ((~D) & C); + g = (5*i + 1) & 0xf; // mod 16 + } else if (32 <= i && i <= 47) { + F = B ^ C ^ D; + g = (3*i + 5) & 0xf; + } else if (48 <= i && i <= 63) { + F = C ^ (B | (~D)); + g = (7*i) & 0xf; + } + F += A + MD5_K[i] + M[g]; + A = D; + D = C; + C = B; + B += MD5_rotateLeft(F, MD5_s[i]); + } + ctx.a0 += A; + ctx.b0 += B; + ctx.c0 += C; + ctx.d0 += D; + ctx.bits_hashed += 512; + } + +fun MD5_Finalize = (MD5_Context ctx, byte[] leftover)void: + { + ctx.bits_hashed += leftover'size'magnitude * leftover'size'unit; + leftover += [0x80uB]; // append "1" bit to message + var actual_bitlen = ctx.bits_hashed; + if (leftover'length > 56) { + // this last block is too small to also contain the 64-bit + // "total message length" suffix, so we finish this round + // and do an all-zeroes one next. + for (var i = leftover'length; i < 64; i++) { + leftover += [0uB]; + } + MD5_Round(ctx, leftover); + leftover = byte[56](); + } + + for (var i = leftover'length; i < 64-8; i++) { + // append 0 bit until message length in bits is congruent to 448 (mod 512) + leftover += [0uB]; + } + assert(leftover'length == 56, format("%u32d", leftover'length)); + // append original length in bits mod 2**64 to message little endian: + leftover += [(actual_bitlen & 0xff) as byte]; + leftover += [((actual_bitlen .>> 8) & 0xff) as byte]; + leftover += [((actual_bitlen .>> 16) & 0xff) as byte]; + leftover += [((actual_bitlen .>> 24) & 0xff) as byte]; + leftover += [((actual_bitlen .>> 32) & 0xff) as byte]; + leftover += [((actual_bitlen .>> 40) & 0xff) as byte]; + leftover += [((actual_bitlen .>> 48) & 0xff) as byte]; + leftover += [((actual_bitlen .>> 56) & 0xff) as byte]; + assert(leftover'length == 64); + MD5_Round(ctx, leftover); + } + +fun MD5_Single = (byte[] buf) MD5_Context: + { + var ctx = MD5_Context{}; + var chunk = 0u; + for( ; chunk < buf'length / 64; chunk++) + { + MD5_Round(ctx, buf[chunk*64:(1+chunk)*64]); + } + if (buf'length - chunk*64 == 0) { // TODO ugly + MD5_Finalize(ctx, byte[]()); + } else { + MD5_Finalize(ctx, buf[chunk*64:]); + } + return ctx; + } \ No newline at end of file diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index 3bfd3d4e..e4a08075 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -560,6 +560,7 @@ EXTRA_DIST = \ poke.pickles/mbr-test.pk \ poke.pickles/id3v1-test.pk \ poke.pickles/rgb24-test.pk \ + poke.pickles/md5-test.pk \ poke.pkl/pkl.exp \ poke.pkl/postincr-1.pk \ poke.pkl/postincr-2.pk \ diff --git a/testsuite/poke.pickles/md5-test.pk b/testsuite/poke.pickles/md5-test.pk new file mode 100644 index 00000000..f0cfeba6 --- /dev/null +++ b/testsuite/poke.pickles/md5-test.pk @@ -0,0 +1,58 @@ +load pktest; +load md5; + +var vec_a_300 = byte[300](); +stoca("a"*300, vec_a_300); +var vec_a64_b64_c32 = byte[64+64+32](); +stoca("A"*64 + "B"*64+"C"*32, vec_a64_b64_c32); +// all bytes from 0x00..0xff +var vec_123 = byte[256](); +for(var i = 0; i