diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-08-23 19:32:15 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-08-23 19:32:15 -0700 |
commit | 10fd98a804097002f9331e48fc6f84f3f3d8f3e2 (patch) | |
tree | df74904a86469a4d2dcde22a890053d0fba6d073 /chksums | |
parent | 0dd1d1a586fcfcf11e0b1c926c8be9c4c8d525be (diff) | |
download | txr-10fd98a804097002f9331e48fc6f84f3f3d8f3e2.tar.gz txr-10fd98a804097002f9331e48fc6f84f3f3d8f3e2.tar.bz2 txr-10fd98a804097002f9331e48fc6f84f3f3d8f3e2.zip |
New: MD5 digest functions.
* Makefile (OBJS): New object file, chksums/md5.o.
* chksum.c (sha256_ensure_buf): Renamed to chksum_ensure_buf
and made generic so MD5 code can borrow it.
(sha256_stream, sha256): Call chksum_ensure_buf instead of
sha256_ensure_buf, passing in new length and hash name
parameters.
(md5_stream_impl, md5_buf, md5_str): New static functions.
(md5_stream, md5): New functions.
(chksum_init): Register md5-stream and md5 intrinsics.
* chksum.h (md5_stream, md5): Declared.
* chksums/md5.c, chksums/md5.h: New files.
Diffstat (limited to 'chksums')
-rw-r--r-- | chksums/md5.c | 320 | ||||
-rw-r--r-- | chksums/md5.h | 41 |
2 files changed, 361 insertions, 0 deletions
diff --git a/chksums/md5.c b/chksums/md5.c new file mode 100644 index 00000000..b52c9e48 --- /dev/null +++ b/chksums/md5.c @@ -0,0 +1,320 @@ +/* + * RSA Data Security, Inc., MD5 message-digest algorithm + * + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * Implementations of these message-digest algorithms, including + * implementations derived from the reference C code in RFC-1319, RFC-1320, and + * RFC-1321, may be made, used, and sold without license from RSA for any + * purpose. [https://www.ietf.org/ietf-ftp/ietf/IPR/RSA-MD-all] + * + * DISCLAIMER: RSA MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY + * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, VALIDITY OF INTELLECTUAL + * PROPERTY RIGHTS, ISSUED OR PENDING, OR THE ABSENCE OF LATENT OR OTHER + * DEFECTS, WHETHER OR NOT DISCOVERABLE, IN CONNECTION WITH THE MD2, MD4, OR + * MD5 ALGORITHMS. NOTHING IN THIS GRANT OF RIGHTS SHALL BE CONSTRUED AS A + * REPRESENTATION OR WARRANTY GIVEN BY RSA THAT THE IMPLEMENTATION OF THE + * ALGORITHM WILL NOT INFRINGE THE INTELLECTUAL PROPERTY RIGHTS OF ANY THIRD + * PARTY. IN NO EVENT SHALL RSA, ITS TRUSTEES, DIRECTORS, OFFICERS, EMPLOYEES, + * PARENTS AND AFFILIATES BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES OF + * ANY KIND RESULTING FROM IMPLEMENTATION OF THIS ALGORITHM, INCLUDING ECONOMIC + * DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER RSA + * SHALL BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF + * THE POSSIBILITY OF SUCH INJURY OR DAMAGE. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#include <string.h> +#include <limits.h> +#include <wchar.h> +#include "config.h" +#include "lib.h" +#include "itypes.h" +#include "md5.h" + +static void MD5_transform(u32_t [4], const unsigned char [64]); + +#if HAVE_LITTLE_ENDIAN + +#define encode memcpy +#define decode memcpy + +#else + +/* + * Encodes input (u32_t) into output (unsigned char). Assumes len is + * a multiple of 4. + */ +static void encode(unsigned char *output, u32_t *input, unsigned int len) +{ + unsigned int i; + u32_t *op = (u32_t *)output; + + for (i = 0; i < len; i += 4) { + u32_t iw = input[i/4]; + + output[i] = (iw >> 24) & 0xff; + output[i+1] = (iw >> 16) & 0xff; + output[i+2] = (iw >> 8) & 0xff; + output[i+3] = iw & 0xff; + } +} + +/* + * Decodes input (unsigned char) into output (u32_t). Assumes len is + * a multiple of 4. + */ +static void decode(u32_t *output, const unsigned char *input, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i += 4) { + u32_t ow = convert(u32_t, input[i]) << 24; + ow |= convert(u32_t, input[i+1]) << 16; + ow |= convert(u32_t, input[i+2]) << 8; + ow |= convert(u32_t, input[i+3]); + output[i/4] = ow; + } +} + +#endif + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* + * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + * Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F((b), (c), (d)) + (x) + convert(u32_t, ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G((b), (c), (d)) + (x) + convert(u32_t, ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H((b), (c), (d)) + (x) + convert(u32_t, ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +#define II(a, b, c, d, x, s, ac) { \ + (a) += I((b), (c), (d)) + (x) + convert(u32_t, ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +/* MD5 initialization. Begins an MD5 operation, writing a new context. */ + +void MD5_init(MD5_t *context) +{ + + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* + * MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ +void MD5_update(MD5_t *context, const unsigned char *input, size_t inputLen) +{ + u32_t i, idx, partLen; + + /* Compute number of bytes mod 64 */ + idx = (context->count[0] >> 3) & 0x3F; + + /* Update number of bits */ + if ((context->count[0] += (inputLen << 3)) < (inputLen << 3)) + context->count[1]++; + context->count[1] += (inputLen >> 29); + + partLen = 64 - idx; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + memcpy(&context->buffer[idx], input, partLen); + MD5_transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5_transform(context->state, &input[i]); + + idx = 0; + } else { + i = 0; + } + + /* Buffer remaining input */ + memcpy(&context->buffer[idx], &input[i], inputLen - i); +} + +/* + * MD5 padding. Adds padding followed by original length. + */ + +static void MD5_pad(MD5_t *context) +{ + unsigned char bits[8]; + u32_t idx, padLen; + + /* Save number of bits */ + encode(bits, context->count, 8); + + /* Pad out to 56 mod 64. */ + idx = (context->count[0] >> 3) & 0x3f; + padLen = (idx < 56) ? (56 - idx) : (120 - idx); + MD5_update(context, PADDING, padLen); + + /* Append length (before padding) */ + MD5_update(context, bits, 8); +} + +/* + * MD5 finalization. Ends an MD5 message-digest operation, writing the + * the message digest and zeroizing the context. + */ + +void MD5_final(MD5_t *context, unsigned char digest[16]) +{ + /* Do padding. */ + MD5_pad(context); + + /* Store state in digest */ + encode(digest, context->state, 16); + + /* Zeroize sensitive information. */ + memset(context, 0, sizeof *context); +} + +/* MD5 basic transformation. Transforms state based on block. */ + +static void MD5_transform(u32_t state[4], const unsigned char block[64]) +{ + u32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + decode(x, block, 64); + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + memset(x, 0, sizeof x); +} diff --git a/chksums/md5.h b/chksums/md5.h new file mode 100644 index 00000000..10d28d73 --- /dev/null +++ b/chksums/md5.h @@ -0,0 +1,41 @@ +/* + * RSA Data Security, Inc., MD5 message-digest algorithm + * + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * Implementations of these message-digest algorithms, including + * implementations derived from the reference C code in RFC-1319, RFC-1320, and + * RFC-1321, may be made, used, and sold without license from RSA for any + * purpose. [https://www.ietf.org/ietf-ftp/ietf/IPR/RSA-MD-all] + * + * DISCLAIMER: RSA MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY + * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, VALIDITY OF INTELLECTUAL + * PROPERTY RIGHTS, ISSUED OR PENDING, OR THE ABSENCE OF LATENT OR OTHER + * DEFECTS, WHETHER OR NOT DISCOVERABLE, IN CONNECTION WITH THE MD2, MD4, OR + * MD5 ALGORITHMS. NOTHING IN THIS GRANT OF RIGHTS SHALL BE CONSTRUED AS A + * REPRESENTATION OR WARRANTY GIVEN BY RSA THAT THE IMPLEMENTATION OF THE + * ALGORITHM WILL NOT INFRINGE THE INTELLECTUAL PROPERTY RIGHTS OF ANY THIRD + * PARTY. IN NO EVENT SHALL RSA, ITS TRUSTEES, DIRECTORS, OFFICERS, EMPLOYEES, + * PARENTS AND AFFILIATES BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES OF + * ANY KIND RESULTING FROM IMPLEMENTATION OF THIS ALGORITHM, INCLUDING ECONOMIC + * DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER RSA + * SHALL BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF + * THE POSSIBILITY OF SUCH INJURY OR DAMAGE. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#define MD5_DIGEST_LENGTH 16 + +typedef struct { + u32_t state[4]; /* state (ABCD) */ + u32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_t; + +void MD5_init(MD5_t *); +void MD5_update(MD5_t *, const unsigned char *, size_t); +void MD5_final(MD5_t *, unsigned char digest[16]); |