dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The code is modified for use in fossil. The original header dbda8d6ce9 2007-07-21 drh: ** comment follows: dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * This code implements the MD5 message-digest algorithm. dbda8d6ce9 2007-07-21 drh: * The algorithm is due to Ron Rivest. This code was dbda8d6ce9 2007-07-21 drh: * written by Colin Plumb in 1993, no copyright is claimed. dbda8d6ce9 2007-07-21 drh: * This code is in the public domain; do with it what you wish. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * Equivalent code is available from RSA Data Security, Inc. dbda8d6ce9 2007-07-21 drh: * This code has been tested against that, and is equivalent, dbda8d6ce9 2007-07-21 drh: * except that you don't need to include two pages of legalese dbda8d6ce9 2007-07-21 drh: * with every copy. dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * To compute the message digest of a chunk of bytes, declare an dbda8d6ce9 2007-07-21 drh: * MD5Context structure, pass it to MD5Init, call MD5Update as dbda8d6ce9 2007-07-21 drh: * needed on buffers full of bytes, and then call MD5Final, which dbda8d6ce9 2007-07-21 drh: * will fill a supplied 16-byte array with the digest. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #include <string.h> dbda8d6ce9 2007-07-21 drh: #include <stdio.h> dbda8d6ce9 2007-07-21 drh: #include <sqlite3.h> dbda8d6ce9 2007-07-21 drh: #include "md5.h" dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * If compiled on a machine that doesn't have a 32-bit integer, dbda8d6ce9 2007-07-21 drh: * you just set "uint32" to the appropriate datatype for an dbda8d6ce9 2007-07-21 drh: * unsigned 32-bit integer. For example: dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: * cc -Duint32='unsigned long' md5.c dbda8d6ce9 2007-07-21 drh: * dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: #ifndef uint32 dbda8d6ce9 2007-07-21 drh: # define uint32 unsigned int dbda8d6ce9 2007-07-21 drh: #endif dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: struct Context { dbda8d6ce9 2007-07-21 drh: int isInit; dbda8d6ce9 2007-07-21 drh: uint32 buf[4]; dbda8d6ce9 2007-07-21 drh: uint32 bits[2]; dbda8d6ce9 2007-07-21 drh: unsigned char in[64]; dbda8d6ce9 2007-07-21 drh: }; dbda8d6ce9 2007-07-21 drh: typedef struct Context MD5Context; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * Note: this code is harmless on little-endian machines. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void byteReverse (unsigned char *buf, unsigned longs){ dbda8d6ce9 2007-07-21 drh: uint32 t; dbda8d6ce9 2007-07-21 drh: do { dbda8d6ce9 2007-07-21 drh: t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | dbda8d6ce9 2007-07-21 drh: ((unsigned)buf[1]<<8 | buf[0]); dbda8d6ce9 2007-07-21 drh: *(uint32 *)buf = t; dbda8d6ce9 2007-07-21 drh: buf += 4; dbda8d6ce9 2007-07-21 drh: } while (--longs); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: /* The four core functions - F1 is optimized somewhat */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* #define F1(x, y, z) (x & y | ~x & z) */ dbda8d6ce9 2007-07-21 drh: #define F1(x, y, z) (z ^ (x & (y ^ z))) dbda8d6ce9 2007-07-21 drh: #define F2(x, y, z) F1(z, x, y) dbda8d6ce9 2007-07-21 drh: #define F3(x, y, z) (x ^ y ^ z) dbda8d6ce9 2007-07-21 drh: #define F4(x, y, z) (y ^ (x | ~z)) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* This is the central step in the MD5 algorithm. */ dbda8d6ce9 2007-07-21 drh: #define MD5STEP(f, w, x, y, z, data, s) \ dbda8d6ce9 2007-07-21 drh: ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * The core of the MD5 algorithm, this alters an existing MD5 hash to dbda8d6ce9 2007-07-21 drh: * reflect the addition of 16 longwords of new data. MD5Update blocks dbda8d6ce9 2007-07-21 drh: * the data and converts bytes into longwords for this routine. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void MD5Transform(uint32 buf[4], const uint32 in[16]){ dbda8d6ce9 2007-07-21 drh: register uint32 a, b, c, d; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: a = buf[0]; dbda8d6ce9 2007-07-21 drh: b = buf[1]; dbda8d6ce9 2007-07-21 drh: c = buf[2]; dbda8d6ce9 2007-07-21 drh: d = buf[3]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); dbda8d6ce9 2007-07-21 drh: MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); dbda8d6ce9 2007-07-21 drh: MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); dbda8d6ce9 2007-07-21 drh: MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); dbda8d6ce9 2007-07-21 drh: MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: buf[0] += a; dbda8d6ce9 2007-07-21 drh: buf[1] += b; dbda8d6ce9 2007-07-21 drh: buf[2] += c; dbda8d6ce9 2007-07-21 drh: buf[3] += d; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious dbda8d6ce9 2007-07-21 drh: * initialization constants. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void MD5Init(MD5Context *ctx){ dbda8d6ce9 2007-07-21 drh: ctx->isInit = 1; dbda8d6ce9 2007-07-21 drh: ctx->buf[0] = 0x67452301; dbda8d6ce9 2007-07-21 drh: ctx->buf[1] = 0xefcdab89; dbda8d6ce9 2007-07-21 drh: ctx->buf[2] = 0x98badcfe; dbda8d6ce9 2007-07-21 drh: ctx->buf[3] = 0x10325476; dbda8d6ce9 2007-07-21 drh: ctx->bits[0] = 0; dbda8d6ce9 2007-07-21 drh: ctx->bits[1] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * Update context to reflect the concatenation of another buffer full dbda8d6ce9 2007-07-21 drh: * of bytes. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static dbda8d6ce9 2007-07-21 drh: void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){ dbda8d6ce9 2007-07-21 drh: struct Context *ctx = (struct Context *)pCtx; dbda8d6ce9 2007-07-21 drh: uint32 t; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Update bitcount */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: t = ctx->bits[0]; dbda8d6ce9 2007-07-21 drh: if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) dbda8d6ce9 2007-07-21 drh: ctx->bits[1]++; /* Carry from low to high */ dbda8d6ce9 2007-07-21 drh: ctx->bits[1] += len >> 29; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Handle any leading odd-sized chunks */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: if ( t ) { dbda8d6ce9 2007-07-21 drh: unsigned char *p = (unsigned char *)ctx->in + t; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: t = 64-t; dbda8d6ce9 2007-07-21 drh: if (len < t) { dbda8d6ce9 2007-07-21 drh: memcpy(p, buf, len); dbda8d6ce9 2007-07-21 drh: return; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: memcpy(p, buf, t); dbda8d6ce9 2007-07-21 drh: byteReverse(ctx->in, 16); dbda8d6ce9 2007-07-21 drh: MD5Transform(ctx->buf, (uint32 *)ctx->in); dbda8d6ce9 2007-07-21 drh: buf += t; dbda8d6ce9 2007-07-21 drh: len -= t; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Process data in 64-byte chunks */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: while (len >= 64) { dbda8d6ce9 2007-07-21 drh: memcpy(ctx->in, buf, 64); dbda8d6ce9 2007-07-21 drh: byteReverse(ctx->in, 16); dbda8d6ce9 2007-07-21 drh: MD5Transform(ctx->buf, (uint32 *)ctx->in); dbda8d6ce9 2007-07-21 drh: buf += 64; dbda8d6ce9 2007-07-21 drh: len -= 64; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Handle any remaining bytes of data. */ dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: memcpy(ctx->in, buf, len); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: * Final wrapup - pad to 64-byte boundary with the bit pattern dbda8d6ce9 2007-07-21 drh: * 1 0* (64-bit count of bits processed, MSB-first) dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void MD5Final(unsigned char digest[16], MD5Context *pCtx){ dbda8d6ce9 2007-07-21 drh: struct Context *ctx = (struct Context *)pCtx; dbda8d6ce9 2007-07-21 drh: unsigned count; dbda8d6ce9 2007-07-21 drh: unsigned char *p; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Compute number of bytes mod 64 */ dbda8d6ce9 2007-07-21 drh: count = (ctx->bits[0] >> 3) & 0x3F; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Set the first char of padding to 0x80. This is safe since there is dbda8d6ce9 2007-07-21 drh: always at least one byte free */ dbda8d6ce9 2007-07-21 drh: p = ctx->in + count; dbda8d6ce9 2007-07-21 drh: *p++ = 0x80; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Bytes of padding needed to make 64 bytes */ dbda8d6ce9 2007-07-21 drh: count = 64 - 1 - count; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Pad out to 56 mod 64 */ dbda8d6ce9 2007-07-21 drh: if (count < 8) { dbda8d6ce9 2007-07-21 drh: /* Two lots of padding: Pad the first block to 64 bytes */ dbda8d6ce9 2007-07-21 drh: memset(p, 0, count); dbda8d6ce9 2007-07-21 drh: byteReverse(ctx->in, 16); dbda8d6ce9 2007-07-21 drh: MD5Transform(ctx->buf, (uint32 *)ctx->in); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Now fill the next block with 56 bytes */ dbda8d6ce9 2007-07-21 drh: memset(ctx->in, 0, 56); dbda8d6ce9 2007-07-21 drh: } else { dbda8d6ce9 2007-07-21 drh: /* Pad block to 56 bytes */ dbda8d6ce9 2007-07-21 drh: memset(p, 0, count-8); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: byteReverse(ctx->in, 14); dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* Append length in bits and transform */ dbda8d6ce9 2007-07-21 drh: ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; dbda8d6ce9 2007-07-21 drh: ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: MD5Transform(ctx->buf, (uint32 *)ctx->in); dbda8d6ce9 2007-07-21 drh: byteReverse((unsigned char *)ctx->buf, 4); dbda8d6ce9 2007-07-21 drh: memcpy(digest, ctx->buf, 16); dbda8d6ce9 2007-07-21 drh: memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Convert a digest into base-16. digest should be declared as dbda8d6ce9 2007-07-21 drh: ** "unsigned char digest[16]" in the calling function. The MD5 dbda8d6ce9 2007-07-21 drh: ** digest is stored in the first 16 bytes. zBuf should dbda8d6ce9 2007-07-21 drh: ** be "char zBuf[33]". dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static void DigestToBase16(unsigned char *digest, char *zBuf){ dbda8d6ce9 2007-07-21 drh: static char const zEncode[] = "0123456789abcdef"; dbda8d6ce9 2007-07-21 drh: int i, j; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(j=i=0; i<16; i++){ dbda8d6ce9 2007-07-21 drh: int a = digest[i]; dbda8d6ce9 2007-07-21 drh: zBuf[j++] = zEncode[(a>>4)&0xf]; dbda8d6ce9 2007-07-21 drh: zBuf[j++] = zEncode[a & 0xf]; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: zBuf[j] = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** The state of a incremental MD5 checksum computation. Only one dbda8d6ce9 2007-07-21 drh: ** such computation can be underway at a time, of course. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: static MD5Context incrCtx; dbda8d6ce9 2007-07-21 drh: static int incrInit = 0; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Initialize the incremental MD5 checksum. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void md5sum_init(void){ dbda8d6ce9 2007-07-21 drh: incrInit = 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add more text to the incremental MD5 checksum. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void md5sum_step_text(const char *zText, int nBytes){ dbda8d6ce9 2007-07-21 drh: if( !incrInit ){ dbda8d6ce9 2007-07-21 drh: MD5Init(&incrCtx); dbda8d6ce9 2007-07-21 drh: incrInit = 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: if( nBytes<=0 ){ dbda8d6ce9 2007-07-21 drh: if( nBytes==0 ) return; dbda8d6ce9 2007-07-21 drh: nBytes = strlen(zText); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: MD5Update(&incrCtx, (unsigned char*)zText, nBytes); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Add the content of a blob to the incremental MD5 checksum. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void md5sum_step_blob(Blob *p){ dbda8d6ce9 2007-07-21 drh: md5sum_step_text(blob_buffer(p), blob_size(p)); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Finish the incremental MD5 checksum. Store the result in blob pOut dbda8d6ce9 2007-07-21 drh: ** if pOut!=0. Also return a pointer to the result. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** This resets the incremental checksum preparing for the next round dbda8d6ce9 2007-07-21 drh: ** of computation. The return pointer points to a static buffer that dbda8d6ce9 2007-07-21 drh: ** is overwritten by subsequent calls to this function. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: char *md5sum_finish(Blob *pOut){ dbda8d6ce9 2007-07-21 drh: unsigned char zResult[16]; dbda8d6ce9 2007-07-21 drh: static char zOut[33]; dbda8d6ce9 2007-07-21 drh: md5sum_step_text(0,0); dbda8d6ce9 2007-07-21 drh: MD5Final(zResult, &incrCtx); dbda8d6ce9 2007-07-21 drh: incrInit = 0; dbda8d6ce9 2007-07-21 drh: DigestToBase16(zResult, zOut); dbda8d6ce9 2007-07-21 drh: if( pOut ){ dbda8d6ce9 2007-07-21 drh: blob_zero(pOut); dbda8d6ce9 2007-07-21 drh: blob_append(pOut, zOut, 32); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: return zOut; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the MD5 checksum of a file on disk. Store the resulting dbda8d6ce9 2007-07-21 drh: ** checksum in the blob pCksum. pCksum is assumed to be ininitialized. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the number of errors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int md5sum_file(const char *zFilename, Blob *pCksum){ dbda8d6ce9 2007-07-21 drh: FILE *in; dbda8d6ce9 2007-07-21 drh: MD5Context ctx; dbda8d6ce9 2007-07-21 drh: unsigned char zResult[16]; dbda8d6ce9 2007-07-21 drh: char zBuf[10240]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: in = fopen(zFilename,"rb"); dbda8d6ce9 2007-07-21 drh: if( in==0 ){ dbda8d6ce9 2007-07-21 drh: return 1; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: MD5Init(&ctx); dbda8d6ce9 2007-07-21 drh: for(;;){ dbda8d6ce9 2007-07-21 drh: int n; dbda8d6ce9 2007-07-21 drh: n = fread(zBuf, 1, sizeof(zBuf), in); dbda8d6ce9 2007-07-21 drh: if( n<=0 ) break; dbda8d6ce9 2007-07-21 drh: MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: fclose(in); dbda8d6ce9 2007-07-21 drh: blob_zero(pCksum); dbda8d6ce9 2007-07-21 drh: blob_resize(pCksum, 32); dbda8d6ce9 2007-07-21 drh: MD5Final(zResult, &ctx); dbda8d6ce9 2007-07-21 drh: DigestToBase16(zResult, blob_buffer(pCksum)); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** Compute the MD5 checksum of a blob in memory. Store the resulting dbda8d6ce9 2007-07-21 drh: ** checksum in the blob pCksum. pCksum is assumed to be either dbda8d6ce9 2007-07-21 drh: ** uninitialized or the same blob as pIn. dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Return the number of errors. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: int md5sum_blob(const Blob *pIn, Blob *pCksum){ dbda8d6ce9 2007-07-21 drh: MD5Context ctx; dbda8d6ce9 2007-07-21 drh: unsigned char zResult[16]; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: MD5Init(&ctx); dbda8d6ce9 2007-07-21 drh: MD5Update(&ctx, (unsigned char*)blob_buffer(pIn), blob_size(pIn)); dbda8d6ce9 2007-07-21 drh: if( pIn==pCksum ){ dbda8d6ce9 2007-07-21 drh: blob_reset(pCksum); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: blob_zero(pCksum); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: blob_resize(pCksum, 32); dbda8d6ce9 2007-07-21 drh: MD5Final(zResult, &ctx); dbda8d6ce9 2007-07-21 drh: DigestToBase16(zResult, blob_buffer(pCksum)); dbda8d6ce9 2007-07-21 drh: return 0; dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: /* dbda8d6ce9 2007-07-21 drh: ** COMMAND: test-md5sum dbda8d6ce9 2007-07-21 drh: ** dbda8d6ce9 2007-07-21 drh: ** Compute an MD5 checksum of all files named on the command-line. dbda8d6ce9 2007-07-21 drh: ** If an file is named "-" then take its content from standard input. dbda8d6ce9 2007-07-21 drh: */ dbda8d6ce9 2007-07-21 drh: void md5sum_test(void){ dbda8d6ce9 2007-07-21 drh: int i; dbda8d6ce9 2007-07-21 drh: Blob in; dbda8d6ce9 2007-07-21 drh: Blob cksum; dbda8d6ce9 2007-07-21 drh: dbda8d6ce9 2007-07-21 drh: for(i=2; i<g.argc; i++){ dbda8d6ce9 2007-07-21 drh: if( g.argv[i][0]=='-' && g.argv[i][1]==0 ){ dbda8d6ce9 2007-07-21 drh: blob_read_from_channel(&in, stdin, -1); dbda8d6ce9 2007-07-21 drh: md5sum_blob(&in, &cksum); dbda8d6ce9 2007-07-21 drh: }else{ dbda8d6ce9 2007-07-21 drh: md5sum_file(g.argv[i], &cksum); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: printf("%s %s\n", blob_str(&cksum), g.argv[i]); dbda8d6ce9 2007-07-21 drh: blob_reset(&cksum); dbda8d6ce9 2007-07-21 drh: } dbda8d6ce9 2007-07-21 drh: }