/* librock_CHISEL _summary Compute the RSA MD5 Message Digest */ /**************************************************************/ #ifdef librock_NOTLIBROCK /* ABOUT THIS FILE: GUIDE TO QUICK REUSE WITHOUT REWORK All source code from librock is Free (libre), free (no cost), rock- stable API, namespace restricted, industrial-level quality. Works on gcc/MS/Windows/Linux/BSD/more. Get originals, updates, and details at http://www.mibsoftware.com/librock This file has many preprocessor conditional blocks which are used in publishing http://www.mibsoftware.com/librock/ Here is an easy method to use this file without those features: 1. At compile time, enable this conditional block by defining the preprocessor symbol librock_NOTLIBROCK, either with a compiler command line parameter, or as a #define in a source file which then #includes this source file. 2. Define any preprocessor symbols in this block (if any) appropriately for your machine and compilation environment. 3. Copy and use the declarations from this block in your source files as appropriate. */ #define librock_ISOLATED #include #define librock_PTR #define librock_CONST const #define librock_PRIVATE static #define librock_uint32_t unsigned long /* Match your target for 32-bit wide*/ #define PROTO_LIST(a) a #define UINT4 librock_uint32_t #define POINTER unsigned char * #define MD5_CTX librock_MD5_CTX #define MD5_CTX librock_MD5_CTX #define MD5Update librock_MD5Update #define MD5Init librock_MD5Init #define MD5Final librock_MD5Final typedef struct { librock_uint32_t state[4]; /* state (ABCD) */ librock_uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } librock_MD5_CTX; void librock_MD5Init (librock_MD5_CTX *); void librock_MD5Update (librock_MD5_CTX *, const unsigned char *, unsigned int); void librock_MD5Final (unsigned char [16], librock_MD5_CTX *); #endif /* ifdef librock_NOTLIBROCK */ /**************************************************************/ #ifndef librock_ISOLATED /**************************************************************/ #define librock_IMPLEMENT_md5c #include #include #define PROTO_LIST(a) a #define UINT4 librock_uint32_t #define POINTER unsigned char * #define MD5_CTX librock_MD5_CTX #define MD5_CTX librock_MD5_CTX #define MD5Update librock_MD5Update #define MD5Init librock_MD5Init #define MD5Final librock_MD5Final /**************************************************************/ #endif #ifdef librock_IMPL_LIDESC #ifndef librock_NOIMPL_LIDESC_md5c /**************************************************************/ /* License awareness system. See http://www.mibsoftware.com/librock */ #include /* librock_LIDESC_HC=9158056e4c8de700136ef3b6279e544e8d5224d7 */ char *librock_LIDESC_md5c[] = { "\n" __FILE__ librock_LIDESC_md5rsa "\n", 0 }; /**************************************************************/ #endif #endif #ifdef librock_MANUAL_md5 /* librock_md5 - Compute RSA MD5 message digest. */ /**/ #include #include void librock_MD5Init (librock_MD5_CTX *ctx); void librock_MD5Update (librock_MD5_CTX *ctx, unsigned char *buf, unsigned int len); void librock_MD5Final (unsigned char result[16], /* result stored there */ librock_MD5_CTX *ctx); /* This is the RSA Data Security, Inc. MD5 Message-Digest Algorithm, implemented in md5c.c from the RSAref library. The names in the file were changed to use the librock_ prefix, and the necessary definitions from the include files were incorporated. The implementation is unchanged. To compute the MD5 Message-Digest, declare a librock_MD5_CTX (a typedef'ed structure) which is initialized with a call to librock_MD5Init(). After making one or more calls to librock_MD5Update(), call librock_MD5Final() to place the result into a 16 byte buffer. The algorithm is described in IETF RFC1321 (R. Rivest. RFC 1321: The MD5 Message-Digest Algorithm. April 1992.) The design property that is that the 16 byte result is unique for unique input, and it is computationally infeasible to create text with a given result. That RFC also has this implementation source code. MD5 message digests are used as a unique "fingerprint" (which can verify the integrity of a file or character sequence without a byte by byte comparison.) They are also used as unique hash values. (The computational load to compute the md5 result is significant compared to CRC32, so it should be used only when the uniqueness of the result for unique input is essential, or protecting against generated input which matches a known result is required.) librock_MD5Update() may save not more than 64 bytes of a buffer in the librock_MD5_CTX structure in between calls. That memory is zeroed on librock_MD5Final. But callers may want to use care when working with input which must not be exposed. Typical use: */ #ifdef librock_TYPICAL_USE_MD5Update #include #include #include unsigned char digest[16]; char ascdigest[16*2+1]; char buf[8192]; int ind; librock_MD5_CTX md5Ctx; FILE * f = 0; librock_MD5Init(&md5Ctx); if (f) { while(!feof(f)) { int cnt = fread(buf,1,sizeof(buf),f); if (cnt <= 0) { break; } librock_MD5Update(&md5Ctx,(unsigned char *) buf,cnt); } } else { librock_MD5Update(&md5Ctx,"Hello!",6); } librock_MD5Final(digest,&md5Ctx); /* Now create ASCII hexadecimal representation */ ascdigest[0] = '\0'; ind = 0; while(ind < 16) { sprintf(ascdigest+strlen(ascdigest),"%02x",digest[ind] & 0xff); ind++; } printf("%s\n",ascdigest); #endif /* // No external calls // Well-behaved in multi-threaded uses. */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. Licensed under BSD-ish license, NO WARRANTY. Copies must retain this block. License text in librock_LIDESC_HC=ec1a2c9549fec7790a691ac943b38f06 */ #endif /* MANUAL */ /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ #if 0 #include "global.h" #include "md5.h" #endif /* Constants for MD5Transform routine. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 librock_PRIVATE void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64])); librock_PRIVATE void Encode PROTO_LIST ((unsigned char *, UINT4 *, unsigned int)); librock_PRIVATE void Decode PROTO_LIST ((UINT4 *, const unsigned char *, unsigned int)); librock_PRIVATE void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); librock_PRIVATE void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); librock_PRIVATE 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) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } /* MD5 initialization. Begins an MD5 operation, writing a new context. */ void MD5Init ( MD5_CTX *context) /* 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 MD5Update ( MD5_CTX *context, /* context */ const unsigned char *input, /* input block */ unsigned int inputLen) /* length of input block */ { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int)((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) context->count[1]++; context->count[1] += ((UINT4)inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform (context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) MD5Transform (context->state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); } /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. */ void MD5Final ( unsigned char digest[16], /* message digest */ MD5_CTX *context /* context */ ) { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ Encode (bits, context->count, 8); /* Pad out to 56 mod 64. */ index = (unsigned int)((context->count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); MD5Update (context, PADDING, padLen); /* Append length (before padding) */ MD5Update (context, bits, 8); /* Store state in digest */ Encode (digest, context->state, 16); /* Zeroize sensitive information. */ MD5_memset ((POINTER)context, 0, sizeof (*context)); } /* MD5 basic transformation. Transforms state based on block. */ librock_PRIVATE void MD5Transform (UINT4 state[4],const unsigned char block[64]) { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode (x, block, 64); /* Round 1 */ 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 */ 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 */ 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 */ 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. */ MD5_memset ((POINTER)x, 0, sizeof (x)); } /* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */ librock_PRIVATE void Encode ( unsigned char *output, UINT4 *input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char)(input[i] & 0xff); output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ librock_PRIVATE void Decode ( UINT4 *output, const unsigned char *input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); } /* Note: Replace "for loop" with standard memcpy if possible. */ librock_PRIVATE void MD5_memcpy ( POINTER output, POINTER input, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } /* Note: Replace "for loop" with standard memset if possible. */ librock_PRIVATE void MD5_memset ( POINTER output, int value, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) ((char *)output)[i] = (char)value; } /* $Log: md5c.c,v $ Revision 1.9 2002/08/01 21:52:23 forrest@mibsoftware.com rights=#1 Use ANSI prototypes (few places were still K&R) Use librock_PRIVATE Updated TYPICAL_USE section. Added NOTLIBROCK section. Moved CVS log to end. Changed LIDESC MD5 to HC. Revision 1.8 2002/04/19 14:48:36 forrest@mibsoftware.com rights=#1 const correctness. Revision 1.7 2002/04/09 03:36:44 forrest@mibsoftware.com rights=#1 Updated FNTYPEs. Updated LICENSE in manual. Revision 1.6 2002/04/06 04:26:10 forrest@mibsoftware.com rights=#1 procede.h is obsolete. Revision 1.5 2002/02/10 03:51:18 forrest@mibsoftware.com rights=#1 Standardized chg log Revision 1.4 2002/01/30 16:07:48 forrest@mibsoftware.com rights=#1 Renamed some .h files Revision 1.3 2002/01/29 20:16:01 forrest@mibsoftware.com rights=#1 Improved some comments at top of file Revision 1.2 2002/01/29 04:46:11 forrest@mibsoftware.com rights=#1 LIDESC, types Revision 1.1 2001/11/09 16:43:17 forrest@mibsoftware.com rights=#1 Initial, added manual page. rights#1 Copyright (c) Forrest J Cavalier III d-b-a Mib Software rights#1 License text in librock_LIDESC_HC=12440211096131f5976d36be0cddca4cd9152e45 librock_ACQUIRED: 1998-03-10 rsaref20.tar.Z http://www.rsa.com/ See http://www.mibsoftware.com/librock */