1*1da57d55SToomas Soome /*
27c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
37c478bd9Sstevel@tonic-gate * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate */
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
77c478bd9Sstevel@tonic-gate */
87c478bd9Sstevel@tonic-gate
97c478bd9Sstevel@tonic-gate /* Function names changed to avoid namespace collisions: Rob Siemborski */
107c478bd9Sstevel@tonic-gate
117c478bd9Sstevel@tonic-gate /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
127c478bd9Sstevel@tonic-gate rights reserved.
137c478bd9Sstevel@tonic-gate
147c478bd9Sstevel@tonic-gate License to copy and use this software is granted provided that it
157c478bd9Sstevel@tonic-gate is identified as the "RSA Data Security, Inc. MD5 Message-Digest
167c478bd9Sstevel@tonic-gate Algorithm" in all material mentioning or referencing this software
177c478bd9Sstevel@tonic-gate or this function.
187c478bd9Sstevel@tonic-gate
197c478bd9Sstevel@tonic-gate License is also granted to make and use derivative works provided
207c478bd9Sstevel@tonic-gate that such works are identified as "derived from the RSA Data
217c478bd9Sstevel@tonic-gate Security, Inc. MD5 Message-Digest Algorithm" in all material
227c478bd9Sstevel@tonic-gate mentioning or referencing the derived work.
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate RSA Data Security, Inc. makes no representations concerning either
257c478bd9Sstevel@tonic-gate the merchantability of this software or the suitability of this
267c478bd9Sstevel@tonic-gate software for any particular purpose. It is provided "as is"
277c478bd9Sstevel@tonic-gate without express or implied warranty of any kind.
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate These notices must be retained in any copies of any part of this
307c478bd9Sstevel@tonic-gate documentation and/or software.
317c478bd9Sstevel@tonic-gate */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #include <config.h>
347c478bd9Sstevel@tonic-gate #include "md5global.h"
357c478bd9Sstevel@tonic-gate #ifdef _HAVE_LIB_MD5
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate * If libmd5 is available, we will use it.
387c478bd9Sstevel@tonic-gate * sasl_hmac_md5* functions are still needed.
397c478bd9Sstevel@tonic-gate */
407c478bd9Sstevel@tonic-gate #include "md5_private.h"
417c478bd9Sstevel@tonic-gate #else
427c478bd9Sstevel@tonic-gate #include "md5.h"
437c478bd9Sstevel@tonic-gate #endif /* _HAVE_LIB_MD5 */
447c478bd9Sstevel@tonic-gate #include "hmac-md5.h"
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate #ifndef WIN32
477c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
487c478bd9Sstevel@tonic-gate #endif
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate /* Constants for MD5Transform routine.
517c478bd9Sstevel@tonic-gate */
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate #define S11 7
547c478bd9Sstevel@tonic-gate #define S12 12
557c478bd9Sstevel@tonic-gate #define S13 17
567c478bd9Sstevel@tonic-gate #define S14 22
577c478bd9Sstevel@tonic-gate #define S21 5
587c478bd9Sstevel@tonic-gate #define S22 9
597c478bd9Sstevel@tonic-gate #define S23 14
607c478bd9Sstevel@tonic-gate #define S24 20
617c478bd9Sstevel@tonic-gate #define S31 4
627c478bd9Sstevel@tonic-gate #define S32 11
637c478bd9Sstevel@tonic-gate #define S33 16
647c478bd9Sstevel@tonic-gate #define S34 23
657c478bd9Sstevel@tonic-gate #define S41 6
667c478bd9Sstevel@tonic-gate #define S42 10
677c478bd9Sstevel@tonic-gate #define S43 15
687c478bd9Sstevel@tonic-gate #define S44 21
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate #ifdef _HAVE_LIB_MD5
717c478bd9Sstevel@tonic-gate #define MD5_memcpy(s1, s2, n) memcpy(s1, s2, n)
727c478bd9Sstevel@tonic-gate #define MD5_memset(s1, c, n) memset(s1, c, n)
737c478bd9Sstevel@tonic-gate #else
747c478bd9Sstevel@tonic-gate static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
757c478bd9Sstevel@tonic-gate static void Encode PROTO_LIST
76*1da57d55SToomas Soome ((unsigned char *, UINT4 *, unsigned int));
777c478bd9Sstevel@tonic-gate static void Decode PROTO_LIST
78*1da57d55SToomas Soome ((UINT4 *, unsigned char *, unsigned int));
797c478bd9Sstevel@tonic-gate static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
807c478bd9Sstevel@tonic-gate static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate static unsigned char PADDING[64] = {
837c478bd9Sstevel@tonic-gate 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,
84*1da57d55SToomas Soome 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
857c478bd9Sstevel@tonic-gate };
867c478bd9Sstevel@tonic-gate #endif /* _HAVE_LIB_MD5 */
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate /* F, G, H and I are basic MD5 functions.
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate #ifdef I
927c478bd9Sstevel@tonic-gate /* This might be defined via NANA */
937c478bd9Sstevel@tonic-gate #undef I
947c478bd9Sstevel@tonic-gate #endif
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
977c478bd9Sstevel@tonic-gate #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
987c478bd9Sstevel@tonic-gate #define H(x, y, z) ((x) ^ (y) ^ (z))
997c478bd9Sstevel@tonic-gate #define I(x, y, z) ((y) ^ ((x) | (~z)))
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate /* ROTATE_LEFT rotates x left n bits.
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate */
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
1087c478bd9Sstevel@tonic-gate Rotation is separate from addition to prevent recomputation.
1097c478bd9Sstevel@tonic-gate */
1107c478bd9Sstevel@tonic-gate
111*1da57d55SToomas Soome #define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
112*1da57d55SToomas Soome #define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
113*1da57d55SToomas Soome #define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
114*1da57d55SToomas Soome #define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /* MD5 initialization. Begins an MD5 operation, writing a new context.
1177c478bd9Sstevel@tonic-gate */
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate #ifndef _HAVE_LIB_MD5
_sasl_MD5Init(context)1207c478bd9Sstevel@tonic-gate void _sasl_MD5Init (context)
1217c478bd9Sstevel@tonic-gate MD5_CTX *context; /* context */
1227c478bd9Sstevel@tonic-gate {
123*1da57d55SToomas Soome context->count[0] = context->count[1] = 0;
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate /* Load magic initialization constants. */
126*1da57d55SToomas Soome context->state[0] = 0x67452301;
127*1da57d55SToomas Soome context->state[1] = 0xefcdab89;
128*1da57d55SToomas Soome context->state[2] = 0x98badcfe;
129*1da57d55SToomas Soome context->state[3] = 0x10325476;
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate /* MD5 block update operation. Continues an MD5 message-digest
133*1da57d55SToomas Soome operation, processing another message block, and updating the context.
1347c478bd9Sstevel@tonic-gate */
1357c478bd9Sstevel@tonic-gate
_sasl_MD5Update(context,input,inputLen)1367c478bd9Sstevel@tonic-gate void _sasl_MD5Update (context, input, inputLen)
1377c478bd9Sstevel@tonic-gate MD5_CTX *context; /* context */
1387c478bd9Sstevel@tonic-gate unsigned char *input; /* input block */
1397c478bd9Sstevel@tonic-gate unsigned int inputLen; /* length of input block */
1407c478bd9Sstevel@tonic-gate {
141*1da57d55SToomas Soome unsigned int i, index, partLen;
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate /* Compute number of bytes mod 64 */
1447c478bd9Sstevel@tonic-gate index = (unsigned int)((context->count[0] >> 3) & 0x3F);
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate /* Update number of bits */
1477c478bd9Sstevel@tonic-gate if ((context->count[0] += ((UINT4)inputLen << 3))
1487c478bd9Sstevel@tonic-gate < ((UINT4)inputLen << 3))
1497c478bd9Sstevel@tonic-gate context->count[1]++;
1507c478bd9Sstevel@tonic-gate context->count[1] += ((UINT4)inputLen >> 29);
1517c478bd9Sstevel@tonic-gate
152*1da57d55SToomas Soome partLen = 64 - index;
1537c478bd9Sstevel@tonic-gate
1547c478bd9Sstevel@tonic-gate /* Transform as many times as possible.
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate */
157*1da57d55SToomas Soome if (inputLen >= partLen) {
158*1da57d55SToomas Soome MD5_memcpy
1597c478bd9Sstevel@tonic-gate ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform
160*1da57d55SToomas Soome (context->state, context->buffer);
1617c478bd9Sstevel@tonic-gate
162*1da57d55SToomas Soome for (i = partLen; i + 63 < inputLen; i += 64)
163*1da57d55SToomas Soome MD5Transform (context->state, &input[i]);
1647c478bd9Sstevel@tonic-gate
165*1da57d55SToomas Soome index = 0;
166*1da57d55SToomas Soome }
167*1da57d55SToomas Soome else
168*1da57d55SToomas Soome i = 0;
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate /* Buffer remaining input */
1717c478bd9Sstevel@tonic-gate MD5_memcpy
1727c478bd9Sstevel@tonic-gate ((POINTER)&context->buffer[index], (POINTER)&input[i],
1737c478bd9Sstevel@tonic-gate inputLen-i);
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate /* MD5 finalization. Ends an MD5 message-digest operation, writing the
178*1da57d55SToomas Soome the message digest and zeroizing the context.
1797c478bd9Sstevel@tonic-gate */
1807c478bd9Sstevel@tonic-gate
_sasl_MD5Final(digest,context)1817c478bd9Sstevel@tonic-gate void _sasl_MD5Final (digest, context)
1827c478bd9Sstevel@tonic-gate unsigned char digest[16]; /* message digest */
1837c478bd9Sstevel@tonic-gate MD5_CTX *context; /* context */
1847c478bd9Sstevel@tonic-gate {
185*1da57d55SToomas Soome unsigned char bits[8];
186*1da57d55SToomas Soome unsigned int index, padLen;
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate /* Save number of bits */
1897c478bd9Sstevel@tonic-gate Encode (bits, context->count, 8);
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate /* Pad out to 56 mod 64. */
192*1da57d55SToomas Soome index = (unsigned int)((context->count[0] >> 3) & 0x3f);
193*1da57d55SToomas Soome padLen = (index < 56) ? (56 - index) : (120 - index);
194*1da57d55SToomas Soome _sasl_MD5Update (context, PADDING, padLen);
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate /* Append length (before padding) */
1977c478bd9Sstevel@tonic-gate _sasl_MD5Update (context, bits, 8);
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate /* Store state in digest */
2007c478bd9Sstevel@tonic-gate Encode (digest, context->state, 16);
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate /* Zeroize sensitive information. */
203*1da57d55SToomas Soome MD5_memset ((POINTER)context, 0, sizeof (*context));
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate /* MD5 basic transformation. Transforms state based on block. */
2077c478bd9Sstevel@tonic-gate
MD5Transform(state,block)2087c478bd9Sstevel@tonic-gate static void MD5Transform (state, block)
2097c478bd9Sstevel@tonic-gate UINT4 state[4];
2107c478bd9Sstevel@tonic-gate unsigned char block[64];
2117c478bd9Sstevel@tonic-gate {
212*1da57d55SToomas Soome UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
2137c478bd9Sstevel@tonic-gate
214*1da57d55SToomas Soome Decode (x, block, 64);
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate /* Round 1 */
2177c478bd9Sstevel@tonic-gate FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
2187c478bd9Sstevel@tonic-gate FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
2197c478bd9Sstevel@tonic-gate FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
2207c478bd9Sstevel@tonic-gate FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
2217c478bd9Sstevel@tonic-gate FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
2227c478bd9Sstevel@tonic-gate FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
2237c478bd9Sstevel@tonic-gate FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
2247c478bd9Sstevel@tonic-gate FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
2257c478bd9Sstevel@tonic-gate FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
2267c478bd9Sstevel@tonic-gate FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
2277c478bd9Sstevel@tonic-gate FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
2287c478bd9Sstevel@tonic-gate FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
2297c478bd9Sstevel@tonic-gate FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
2307c478bd9Sstevel@tonic-gate FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
2317c478bd9Sstevel@tonic-gate FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
2327c478bd9Sstevel@tonic-gate FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate /* Round 2 */
2357c478bd9Sstevel@tonic-gate GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
2367c478bd9Sstevel@tonic-gate GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
2377c478bd9Sstevel@tonic-gate GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
2387c478bd9Sstevel@tonic-gate GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
2397c478bd9Sstevel@tonic-gate GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
2407c478bd9Sstevel@tonic-gate GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
2417c478bd9Sstevel@tonic-gate GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
2427c478bd9Sstevel@tonic-gate GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
2437c478bd9Sstevel@tonic-gate GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
2447c478bd9Sstevel@tonic-gate GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
2457c478bd9Sstevel@tonic-gate GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
246*1da57d55SToomas Soome GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
247*1da57d55SToomas Soome GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
248*1da57d55SToomas Soome GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
249*1da57d55SToomas Soome GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
250*1da57d55SToomas Soome GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate /* Round 3 */
2537c478bd9Sstevel@tonic-gate HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
2547c478bd9Sstevel@tonic-gate HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
2557c478bd9Sstevel@tonic-gate HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
2567c478bd9Sstevel@tonic-gate HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
2577c478bd9Sstevel@tonic-gate HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
2587c478bd9Sstevel@tonic-gate HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
2597c478bd9Sstevel@tonic-gate HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
2607c478bd9Sstevel@tonic-gate HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
2617c478bd9Sstevel@tonic-gate HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
2627c478bd9Sstevel@tonic-gate HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
2637c478bd9Sstevel@tonic-gate HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
2647c478bd9Sstevel@tonic-gate HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
2657c478bd9Sstevel@tonic-gate HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
2667c478bd9Sstevel@tonic-gate HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
2677c478bd9Sstevel@tonic-gate HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
2687c478bd9Sstevel@tonic-gate HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate /* Round 4 */
2717c478bd9Sstevel@tonic-gate II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
2727c478bd9Sstevel@tonic-gate II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
2737c478bd9Sstevel@tonic-gate II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
2747c478bd9Sstevel@tonic-gate II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
2757c478bd9Sstevel@tonic-gate II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
2767c478bd9Sstevel@tonic-gate II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
2777c478bd9Sstevel@tonic-gate II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
2787c478bd9Sstevel@tonic-gate II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
2797c478bd9Sstevel@tonic-gate II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
2807c478bd9Sstevel@tonic-gate II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
2817c478bd9Sstevel@tonic-gate II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
2827c478bd9Sstevel@tonic-gate II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
2837c478bd9Sstevel@tonic-gate II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
2847c478bd9Sstevel@tonic-gate II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
2857c478bd9Sstevel@tonic-gate II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
2867c478bd9Sstevel@tonic-gate II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
2877c478bd9Sstevel@tonic-gate
288*1da57d55SToomas Soome state[0] += a;
289*1da57d55SToomas Soome state[1] += b;
290*1da57d55SToomas Soome state[2] += c;
291*1da57d55SToomas Soome state[3] += d;
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate /* Zeroize sensitive information.
2947c478bd9Sstevel@tonic-gate */
295*1da57d55SToomas Soome MD5_memset ((POINTER)x, 0, sizeof (x));
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate /* Encodes input (UINT4) into output (unsigned char). Assumes len is
299*1da57d55SToomas Soome a multiple of 4.
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate */
3027c478bd9Sstevel@tonic-gate
Encode(output,input,len)3037c478bd9Sstevel@tonic-gate static void Encode (output, input, len)
3047c478bd9Sstevel@tonic-gate unsigned char *output;
3057c478bd9Sstevel@tonic-gate UINT4 *input;
3067c478bd9Sstevel@tonic-gate unsigned int len;
3077c478bd9Sstevel@tonic-gate {
308*1da57d55SToomas Soome unsigned int i, j;
309*1da57d55SToomas Soome
310*1da57d55SToomas Soome for (i = 0, j = 0; j < len; i++, j += 4) {
311*1da57d55SToomas Soome output[j] = (unsigned char)(input[i] & 0xff);
312*1da57d55SToomas Soome output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
313*1da57d55SToomas Soome output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
314*1da57d55SToomas Soome output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
315*1da57d55SToomas Soome }
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate /* Decodes input (unsigned char) into output (UINT4). Assumes len is
319*1da57d55SToomas Soome a multiple of 4.
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate */
3227c478bd9Sstevel@tonic-gate
Decode(output,input,len)3237c478bd9Sstevel@tonic-gate static void Decode (output, input, len)
3247c478bd9Sstevel@tonic-gate UINT4 *output;
3257c478bd9Sstevel@tonic-gate unsigned char *input;
3267c478bd9Sstevel@tonic-gate unsigned int len;
3277c478bd9Sstevel@tonic-gate {
328*1da57d55SToomas Soome unsigned int i, j;
3297c478bd9Sstevel@tonic-gate
330*1da57d55SToomas Soome for (i = 0, j = 0; j < len; i++, j += 4)
3317c478bd9Sstevel@tonic-gate output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16)
332*1da57d55SToomas Soome | (((UINT4)input[j+3]) << 24);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate /* Note: Replace "for loop" with standard memcpy if possible.
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate */
3387c478bd9Sstevel@tonic-gate
MD5_memcpy(output,input,len)3397c478bd9Sstevel@tonic-gate static void MD5_memcpy (output, input, len)
3407c478bd9Sstevel@tonic-gate POINTER output;
3417c478bd9Sstevel@tonic-gate POINTER input;
3427c478bd9Sstevel@tonic-gate unsigned int len;
3437c478bd9Sstevel@tonic-gate {
344*1da57d55SToomas Soome unsigned int i;
3457c478bd9Sstevel@tonic-gate
346*1da57d55SToomas Soome for (i = 0; i < len; i++)
347*1da57d55SToomas Soome output[i] = input[i];
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate /* Note: Replace "for loop" with standard memset if possible.
3517c478bd9Sstevel@tonic-gate */
3527c478bd9Sstevel@tonic-gate
MD5_memset(output,value,len)3537c478bd9Sstevel@tonic-gate static void MD5_memset (output, value, len)
3547c478bd9Sstevel@tonic-gate POINTER output;
3557c478bd9Sstevel@tonic-gate int value;
3567c478bd9Sstevel@tonic-gate unsigned int len;
3577c478bd9Sstevel@tonic-gate {
358*1da57d55SToomas Soome unsigned int i;
3597c478bd9Sstevel@tonic-gate
360*1da57d55SToomas Soome for (i = 0; i < len; i++)
361*1da57d55SToomas Soome ((char *)output)[i] = (char)value;
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate #endif /* !_HAVE_LIB_MD5 */
3647c478bd9Sstevel@tonic-gate
_sasl_hmac_md5_init(HMAC_MD5_CTX * hmac,const unsigned char * key,int key_len)3657c478bd9Sstevel@tonic-gate void _sasl_hmac_md5_init(HMAC_MD5_CTX *hmac,
3667c478bd9Sstevel@tonic-gate const unsigned char *key,
3677c478bd9Sstevel@tonic-gate int key_len)
3687c478bd9Sstevel@tonic-gate {
3697c478bd9Sstevel@tonic-gate unsigned char k_ipad[65]; /* inner padding -
3707c478bd9Sstevel@tonic-gate * key XORd with ipad
3717c478bd9Sstevel@tonic-gate */
3727c478bd9Sstevel@tonic-gate unsigned char k_opad[65]; /* outer padding -
3737c478bd9Sstevel@tonic-gate * key XORd with opad
3747c478bd9Sstevel@tonic-gate */
3757c478bd9Sstevel@tonic-gate unsigned char tk[16];
3767c478bd9Sstevel@tonic-gate int i;
3777c478bd9Sstevel@tonic-gate /* if key is longer than 64 bytes reset it to key=MD5(key) */
3787c478bd9Sstevel@tonic-gate if (key_len > 64) {
379*1da57d55SToomas Soome
3807c478bd9Sstevel@tonic-gate MD5_CTX tctx;
3817c478bd9Sstevel@tonic-gate
382*1da57d55SToomas Soome _sasl_MD5Init(&tctx);
383*1da57d55SToomas Soome _sasl_MD5Update(&tctx, key, key_len);
384*1da57d55SToomas Soome _sasl_MD5Final(tk, &tctx);
3857c478bd9Sstevel@tonic-gate
386*1da57d55SToomas Soome key = tk;
387*1da57d55SToomas Soome key_len = 16;
388*1da57d55SToomas Soome }
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate * the HMAC_MD5 transform looks like:
3927c478bd9Sstevel@tonic-gate *
3937c478bd9Sstevel@tonic-gate * MD5(K XOR opad, MD5(K XOR ipad, text))
3947c478bd9Sstevel@tonic-gate *
3957c478bd9Sstevel@tonic-gate * where K is an n byte key
3967c478bd9Sstevel@tonic-gate * ipad is the byte 0x36 repeated 64 times
3977c478bd9Sstevel@tonic-gate * opad is the byte 0x5c repeated 64 times
3987c478bd9Sstevel@tonic-gate * and text is the data being protected
3997c478bd9Sstevel@tonic-gate */
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate /* start out by storing key in pads */
4027c478bd9Sstevel@tonic-gate MD5_memset(k_ipad, '\0', sizeof k_ipad);
4037c478bd9Sstevel@tonic-gate MD5_memset(k_opad, '\0', sizeof k_opad);
4047c478bd9Sstevel@tonic-gate MD5_memcpy( k_ipad, key, key_len);
4057c478bd9Sstevel@tonic-gate MD5_memcpy( k_opad, key, key_len);
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /* XOR key with ipad and opad values */
4087c478bd9Sstevel@tonic-gate for (i=0; i<64; i++) {
4097c478bd9Sstevel@tonic-gate k_ipad[i] ^= 0x36;
4107c478bd9Sstevel@tonic-gate k_opad[i] ^= 0x5c;
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate _sasl_MD5Init(&hmac->ictx); /* init inner context */
4147c478bd9Sstevel@tonic-gate _sasl_MD5Update(&hmac->ictx, k_ipad, 64); /* apply inner pad */
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate _sasl_MD5Init(&hmac->octx); /* init outer context */
4177c478bd9Sstevel@tonic-gate _sasl_MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
4187c478bd9Sstevel@tonic-gate
4197c478bd9Sstevel@tonic-gate /* scrub the pads and key context (if used) */
4207c478bd9Sstevel@tonic-gate MD5_memset(&k_ipad, 0, sizeof(k_ipad));
4217c478bd9Sstevel@tonic-gate MD5_memset(&k_opad, 0, sizeof(k_opad));
4227c478bd9Sstevel@tonic-gate MD5_memset(&tk, 0, sizeof(tk));
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate /* and we're done. */
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate /* The precalc and import routines here rely on the fact that we pad
4287c478bd9Sstevel@tonic-gate * the key out to 64 bytes and use that to initialize the md5
4297c478bd9Sstevel@tonic-gate * contexts, and that updating an md5 context with 64 bytes of data
4307c478bd9Sstevel@tonic-gate * leaves nothing left over; all of the interesting state is contained
4317c478bd9Sstevel@tonic-gate * in the state field, and none of it is left over in the count and
4327c478bd9Sstevel@tonic-gate * buffer fields. So all we have to do is save the state field; we
4337c478bd9Sstevel@tonic-gate * can zero the others when we reload it. Which is why the decision
4347c478bd9Sstevel@tonic-gate * was made to pad the key out to 64 bytes in the first place. */
_sasl_hmac_md5_precalc(HMAC_MD5_STATE * state,const unsigned char * key,int key_len)4357c478bd9Sstevel@tonic-gate void _sasl_hmac_md5_precalc(HMAC_MD5_STATE *state,
4367c478bd9Sstevel@tonic-gate const unsigned char *key,
4377c478bd9Sstevel@tonic-gate int key_len)
4387c478bd9Sstevel@tonic-gate {
4397c478bd9Sstevel@tonic-gate HMAC_MD5_CTX hmac;
4407c478bd9Sstevel@tonic-gate unsigned lupe;
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate _sasl_hmac_md5_init(&hmac, key, key_len);
4437c478bd9Sstevel@tonic-gate for (lupe = 0; lupe < 4; lupe++) {
4447c478bd9Sstevel@tonic-gate state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
4457c478bd9Sstevel@tonic-gate state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate MD5_memset(&hmac, 0, sizeof(hmac));
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate
_sasl_hmac_md5_import(HMAC_MD5_CTX * hmac,HMAC_MD5_STATE * state)4517c478bd9Sstevel@tonic-gate void _sasl_hmac_md5_import(HMAC_MD5_CTX *hmac,
4527c478bd9Sstevel@tonic-gate HMAC_MD5_STATE *state)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate unsigned lupe;
4557c478bd9Sstevel@tonic-gate MD5_memset(hmac, 0, sizeof(HMAC_MD5_CTX));
4567c478bd9Sstevel@tonic-gate for (lupe = 0; lupe < 4; lupe++) {
4577c478bd9Sstevel@tonic-gate hmac->ictx.state[lupe] = ntohl(state->istate[lupe]);
4587c478bd9Sstevel@tonic-gate hmac->octx.state[lupe] = ntohl(state->ostate[lupe]);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate /* Init the counts to account for our having applied
4617c478bd9Sstevel@tonic-gate * 64 bytes of key; this works out to 0x200 (64 << 3; see
4627c478bd9Sstevel@tonic-gate * MD5Update above...) */
4637c478bd9Sstevel@tonic-gate hmac->ictx.count[0] = hmac->octx.count[0] = 0x200;
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate
_sasl_hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],HMAC_MD5_CTX * hmac)4667c478bd9Sstevel@tonic-gate void _sasl_hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
4677c478bd9Sstevel@tonic-gate HMAC_MD5_CTX *hmac)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate _sasl_MD5Final(digest, &hmac->ictx); /* Finalize inner md5 */
4707c478bd9Sstevel@tonic-gate _sasl_MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */
4717c478bd9Sstevel@tonic-gate _sasl_MD5Final(digest, &hmac->octx); /* Finalize outer md5 */
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate
4747c478bd9Sstevel@tonic-gate
_sasl_hmac_md5(text,text_len,key,key_len,digest)4757c478bd9Sstevel@tonic-gate void _sasl_hmac_md5(text, text_len, key, key_len, digest)
4767c478bd9Sstevel@tonic-gate const unsigned char* text; /* pointer to data stream */
4777c478bd9Sstevel@tonic-gate int text_len; /* length of data stream */
4787c478bd9Sstevel@tonic-gate const unsigned char* key; /* pointer to authentication key */
4797c478bd9Sstevel@tonic-gate int key_len; /* length of authentication key */
4807c478bd9Sstevel@tonic-gate unsigned char *digest; /* caller digest to be filled in */
4817c478bd9Sstevel@tonic-gate {
482*1da57d55SToomas Soome MD5_CTX context;
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate unsigned char k_ipad[65]; /* inner padding -
4857c478bd9Sstevel@tonic-gate * key XORd with ipad
4867c478bd9Sstevel@tonic-gate */
4877c478bd9Sstevel@tonic-gate unsigned char k_opad[65]; /* outer padding -
4887c478bd9Sstevel@tonic-gate * key XORd with opad
4897c478bd9Sstevel@tonic-gate */
4907c478bd9Sstevel@tonic-gate unsigned char tk[16];
4917c478bd9Sstevel@tonic-gate int i;
4927c478bd9Sstevel@tonic-gate /* if key is longer than 64 bytes reset it to key=MD5(key) */
4937c478bd9Sstevel@tonic-gate if (key_len > 64) {
494*1da57d55SToomas Soome
4957c478bd9Sstevel@tonic-gate MD5_CTX tctx;
4967c478bd9Sstevel@tonic-gate
497*1da57d55SToomas Soome _sasl_MD5Init(&tctx);
498*1da57d55SToomas Soome _sasl_MD5Update(&tctx, key, key_len);
499*1da57d55SToomas Soome _sasl_MD5Final(tk, &tctx);
5007c478bd9Sstevel@tonic-gate
501*1da57d55SToomas Soome key = tk;
502*1da57d55SToomas Soome key_len = 16;
503*1da57d55SToomas Soome }
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate /*
5067c478bd9Sstevel@tonic-gate * the HMAC_MD5 transform looks like:
5077c478bd9Sstevel@tonic-gate *
5087c478bd9Sstevel@tonic-gate * MD5(K XOR opad, MD5(K XOR ipad, text))
5097c478bd9Sstevel@tonic-gate *
5107c478bd9Sstevel@tonic-gate * where K is an n byte key
5117c478bd9Sstevel@tonic-gate * ipad is the byte 0x36 repeated 64 times
5127c478bd9Sstevel@tonic-gate * opad is the byte 0x5c repeated 64 times
5137c478bd9Sstevel@tonic-gate * and text is the data being protected
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /* start out by storing key in pads */
5177c478bd9Sstevel@tonic-gate MD5_memset(k_ipad, '\0', sizeof k_ipad);
5187c478bd9Sstevel@tonic-gate MD5_memset(k_opad, '\0', sizeof k_opad);
5197c478bd9Sstevel@tonic-gate MD5_memcpy( k_ipad, key, key_len);
5207c478bd9Sstevel@tonic-gate MD5_memcpy( k_opad, key, key_len);
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate /* XOR key with ipad and opad values */
5237c478bd9Sstevel@tonic-gate for (i=0; i<64; i++) {
5247c478bd9Sstevel@tonic-gate k_ipad[i] ^= 0x36;
5257c478bd9Sstevel@tonic-gate k_opad[i] ^= 0x5c;
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate * perform inner MD5
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate _sasl_MD5Init(&context); /* init context for 1st
5327c478bd9Sstevel@tonic-gate * pass */
5337c478bd9Sstevel@tonic-gate _sasl_MD5Update(&context, k_ipad, 64); /* start with inner pad */
5347c478bd9Sstevel@tonic-gate _sasl_MD5Update(&context, text, text_len); /* then text of datagram */
5357c478bd9Sstevel@tonic-gate _sasl_MD5Final(digest, &context); /* finish up 1st pass */
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate /*
5387c478bd9Sstevel@tonic-gate * perform outer MD5
5397c478bd9Sstevel@tonic-gate */
5407c478bd9Sstevel@tonic-gate _sasl_MD5Init(&context); /* init context for 2nd
5417c478bd9Sstevel@tonic-gate * pass */
5427c478bd9Sstevel@tonic-gate _sasl_MD5Update(&context, k_opad, 64); /* start with outer pad */
5437c478bd9Sstevel@tonic-gate _sasl_MD5Update(&context, digest, 16); /* then results of 1st
5447c478bd9Sstevel@tonic-gate * hash */
5457c478bd9Sstevel@tonic-gate _sasl_MD5Final(digest, &context); /* finish up 2nd pass */
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate }
548