michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef FREEBL_NO_DEPEND michael@0: #include "stubs.h" michael@0: #endif michael@0: michael@0: #include "prerr.h" michael@0: #include "secerr.h" michael@0: michael@0: #include "prtypes.h" michael@0: #include "prlong.h" michael@0: michael@0: #include "blapi.h" michael@0: michael@0: #define MD5_HASH_LEN 16 michael@0: #define MD5_BUFFER_SIZE 64 michael@0: #define MD5_END_BUFFER (MD5_BUFFER_SIZE - 8) michael@0: michael@0: #define CV0_1 0x67452301 michael@0: #define CV0_2 0xefcdab89 michael@0: #define CV0_3 0x98badcfe michael@0: #define CV0_4 0x10325476 michael@0: michael@0: #define T1_0 0xd76aa478 michael@0: #define T1_1 0xe8c7b756 michael@0: #define T1_2 0x242070db michael@0: #define T1_3 0xc1bdceee michael@0: #define T1_4 0xf57c0faf michael@0: #define T1_5 0x4787c62a michael@0: #define T1_6 0xa8304613 michael@0: #define T1_7 0xfd469501 michael@0: #define T1_8 0x698098d8 michael@0: #define T1_9 0x8b44f7af michael@0: #define T1_10 0xffff5bb1 michael@0: #define T1_11 0x895cd7be michael@0: #define T1_12 0x6b901122 michael@0: #define T1_13 0xfd987193 michael@0: #define T1_14 0xa679438e michael@0: #define T1_15 0x49b40821 michael@0: michael@0: #define T2_0 0xf61e2562 michael@0: #define T2_1 0xc040b340 michael@0: #define T2_2 0x265e5a51 michael@0: #define T2_3 0xe9b6c7aa michael@0: #define T2_4 0xd62f105d michael@0: #define T2_5 0x02441453 michael@0: #define T2_6 0xd8a1e681 michael@0: #define T2_7 0xe7d3fbc8 michael@0: #define T2_8 0x21e1cde6 michael@0: #define T2_9 0xc33707d6 michael@0: #define T2_10 0xf4d50d87 michael@0: #define T2_11 0x455a14ed michael@0: #define T2_12 0xa9e3e905 michael@0: #define T2_13 0xfcefa3f8 michael@0: #define T2_14 0x676f02d9 michael@0: #define T2_15 0x8d2a4c8a michael@0: michael@0: #define T3_0 0xfffa3942 michael@0: #define T3_1 0x8771f681 michael@0: #define T3_2 0x6d9d6122 michael@0: #define T3_3 0xfde5380c michael@0: #define T3_4 0xa4beea44 michael@0: #define T3_5 0x4bdecfa9 michael@0: #define T3_6 0xf6bb4b60 michael@0: #define T3_7 0xbebfbc70 michael@0: #define T3_8 0x289b7ec6 michael@0: #define T3_9 0xeaa127fa michael@0: #define T3_10 0xd4ef3085 michael@0: #define T3_11 0x04881d05 michael@0: #define T3_12 0xd9d4d039 michael@0: #define T3_13 0xe6db99e5 michael@0: #define T3_14 0x1fa27cf8 michael@0: #define T3_15 0xc4ac5665 michael@0: michael@0: #define T4_0 0xf4292244 michael@0: #define T4_1 0x432aff97 michael@0: #define T4_2 0xab9423a7 michael@0: #define T4_3 0xfc93a039 michael@0: #define T4_4 0x655b59c3 michael@0: #define T4_5 0x8f0ccc92 michael@0: #define T4_6 0xffeff47d michael@0: #define T4_7 0x85845dd1 michael@0: #define T4_8 0x6fa87e4f michael@0: #define T4_9 0xfe2ce6e0 michael@0: #define T4_10 0xa3014314 michael@0: #define T4_11 0x4e0811a1 michael@0: #define T4_12 0xf7537e82 michael@0: #define T4_13 0xbd3af235 michael@0: #define T4_14 0x2ad7d2bb michael@0: #define T4_15 0xeb86d391 michael@0: michael@0: #define R1B0 0 michael@0: #define R1B1 1 michael@0: #define R1B2 2 michael@0: #define R1B3 3 michael@0: #define R1B4 4 michael@0: #define R1B5 5 michael@0: #define R1B6 6 michael@0: #define R1B7 7 michael@0: #define R1B8 8 michael@0: #define R1B9 9 michael@0: #define R1B10 10 michael@0: #define R1B11 11 michael@0: #define R1B12 12 michael@0: #define R1B13 13 michael@0: #define R1B14 14 michael@0: #define R1B15 15 michael@0: michael@0: #define R2B0 1 michael@0: #define R2B1 6 michael@0: #define R2B2 11 michael@0: #define R2B3 0 michael@0: #define R2B4 5 michael@0: #define R2B5 10 michael@0: #define R2B6 15 michael@0: #define R2B7 4 michael@0: #define R2B8 9 michael@0: #define R2B9 14 michael@0: #define R2B10 3 michael@0: #define R2B11 8 michael@0: #define R2B12 13 michael@0: #define R2B13 2 michael@0: #define R2B14 7 michael@0: #define R2B15 12 michael@0: michael@0: #define R3B0 5 michael@0: #define R3B1 8 michael@0: #define R3B2 11 michael@0: #define R3B3 14 michael@0: #define R3B4 1 michael@0: #define R3B5 4 michael@0: #define R3B6 7 michael@0: #define R3B7 10 michael@0: #define R3B8 13 michael@0: #define R3B9 0 michael@0: #define R3B10 3 michael@0: #define R3B11 6 michael@0: #define R3B12 9 michael@0: #define R3B13 12 michael@0: #define R3B14 15 michael@0: #define R3B15 2 michael@0: michael@0: #define R4B0 0 michael@0: #define R4B1 7 michael@0: #define R4B2 14 michael@0: #define R4B3 5 michael@0: #define R4B4 12 michael@0: #define R4B5 3 michael@0: #define R4B6 10 michael@0: #define R4B7 1 michael@0: #define R4B8 8 michael@0: #define R4B9 15 michael@0: #define R4B10 6 michael@0: #define R4B11 13 michael@0: #define R4B12 4 michael@0: #define R4B13 11 michael@0: #define R4B14 2 michael@0: #define R4B15 9 michael@0: michael@0: #define S1_0 7 michael@0: #define S1_1 12 michael@0: #define S1_2 17 michael@0: #define S1_3 22 michael@0: michael@0: #define S2_0 5 michael@0: #define S2_1 9 michael@0: #define S2_2 14 michael@0: #define S2_3 20 michael@0: michael@0: #define S3_0 4 michael@0: #define S3_1 11 michael@0: #define S3_2 16 michael@0: #define S3_3 23 michael@0: michael@0: #define S4_0 6 michael@0: #define S4_1 10 michael@0: #define S4_2 15 michael@0: #define S4_3 21 michael@0: michael@0: struct MD5ContextStr { michael@0: PRUint32 lsbInput; michael@0: PRUint32 msbInput; michael@0: PRUint32 cv[4]; michael@0: union { michael@0: PRUint8 b[64]; michael@0: PRUint32 w[16]; michael@0: } u; michael@0: }; michael@0: michael@0: #define inBuf u.b michael@0: michael@0: SECStatus michael@0: MD5_Hash(unsigned char *dest, const char *src) michael@0: { michael@0: return MD5_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src)); michael@0: } michael@0: michael@0: SECStatus michael@0: MD5_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length) michael@0: { michael@0: unsigned int len; michael@0: MD5Context cx; michael@0: michael@0: MD5_Begin(&cx); michael@0: MD5_Update(&cx, src, src_length); michael@0: MD5_End(&cx, dest, &len, MD5_HASH_LEN); michael@0: memset(&cx, 0, sizeof cx); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: MD5Context * michael@0: MD5_NewContext(void) michael@0: { michael@0: /* no need to ZAlloc, MD5_Begin will init the context */ michael@0: MD5Context *cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context)); michael@0: if (cx == NULL) { michael@0: PORT_SetError(PR_OUT_OF_MEMORY_ERROR); michael@0: return NULL; michael@0: } michael@0: return cx; michael@0: } michael@0: michael@0: void michael@0: MD5_DestroyContext(MD5Context *cx, PRBool freeit) michael@0: { michael@0: memset(cx, 0, sizeof *cx); michael@0: if (freeit) { michael@0: PORT_Free(cx); michael@0: } michael@0: } michael@0: michael@0: void michael@0: MD5_Begin(MD5Context *cx) michael@0: { michael@0: cx->lsbInput = 0; michael@0: cx->msbInput = 0; michael@0: /* memset(cx->inBuf, 0, sizeof(cx->inBuf)); */ michael@0: cx->cv[0] = CV0_1; michael@0: cx->cv[1] = CV0_2; michael@0: cx->cv[2] = CV0_3; michael@0: cx->cv[3] = CV0_4; michael@0: } michael@0: michael@0: #define cls(i32, s) (tmp = i32, tmp << s | tmp >> (32 - s)) michael@0: michael@0: #if defined(SOLARIS) || defined(HPUX) michael@0: #define addto64(sumhigh, sumlow, addend) \ michael@0: sumlow += addend; sumhigh += (sumlow < addend); michael@0: #else michael@0: #define addto64(sumhigh, sumlow, addend) \ michael@0: sumlow += addend; if (sumlow < addend) ++sumhigh; michael@0: #endif michael@0: michael@0: #define MASK 0x00ff00ff michael@0: #ifdef IS_LITTLE_ENDIAN michael@0: #define lendian(i32) \ michael@0: (i32) michael@0: #else michael@0: #define lendian(i32) \ michael@0: (tmp = i32 >> 16 | i32 << 16, (tmp & MASK) << 8 | tmp >> 8 & MASK) michael@0: #endif michael@0: michael@0: #ifndef IS_LITTLE_ENDIAN michael@0: michael@0: #define lebytes(b4) \ michael@0: ((b4)[3] << 24 | (b4)[2] << 16 | (b4)[1] << 8 | (b4)[0]) michael@0: michael@0: static void michael@0: md5_prep_state_le(MD5Context *cx) michael@0: { michael@0: PRUint32 tmp; michael@0: cx->u.w[0] = lendian(cx->u.w[0]); michael@0: cx->u.w[1] = lendian(cx->u.w[1]); michael@0: cx->u.w[2] = lendian(cx->u.w[2]); michael@0: cx->u.w[3] = lendian(cx->u.w[3]); michael@0: cx->u.w[4] = lendian(cx->u.w[4]); michael@0: cx->u.w[5] = lendian(cx->u.w[5]); michael@0: cx->u.w[6] = lendian(cx->u.w[6]); michael@0: cx->u.w[7] = lendian(cx->u.w[7]); michael@0: cx->u.w[8] = lendian(cx->u.w[8]); michael@0: cx->u.w[9] = lendian(cx->u.w[9]); michael@0: cx->u.w[10] = lendian(cx->u.w[10]); michael@0: cx->u.w[11] = lendian(cx->u.w[11]); michael@0: cx->u.w[12] = lendian(cx->u.w[12]); michael@0: cx->u.w[13] = lendian(cx->u.w[13]); michael@0: cx->u.w[14] = lendian(cx->u.w[14]); michael@0: cx->u.w[15] = lendian(cx->u.w[15]); michael@0: } michael@0: michael@0: static void michael@0: md5_prep_buffer_le(MD5Context *cx, const PRUint8 *beBuf) michael@0: { michael@0: cx->u.w[0] = lebytes(&beBuf[0]); michael@0: cx->u.w[1] = lebytes(&beBuf[4]); michael@0: cx->u.w[2] = lebytes(&beBuf[8]); michael@0: cx->u.w[3] = lebytes(&beBuf[12]); michael@0: cx->u.w[4] = lebytes(&beBuf[16]); michael@0: cx->u.w[5] = lebytes(&beBuf[20]); michael@0: cx->u.w[6] = lebytes(&beBuf[24]); michael@0: cx->u.w[7] = lebytes(&beBuf[28]); michael@0: cx->u.w[8] = lebytes(&beBuf[32]); michael@0: cx->u.w[9] = lebytes(&beBuf[36]); michael@0: cx->u.w[10] = lebytes(&beBuf[40]); michael@0: cx->u.w[11] = lebytes(&beBuf[44]); michael@0: cx->u.w[12] = lebytes(&beBuf[48]); michael@0: cx->u.w[13] = lebytes(&beBuf[52]); michael@0: cx->u.w[14] = lebytes(&beBuf[56]); michael@0: cx->u.w[15] = lebytes(&beBuf[60]); michael@0: } michael@0: #endif michael@0: michael@0: michael@0: #define F(X, Y, Z) \ michael@0: ((X & Y) | ((~X) & Z)) michael@0: michael@0: #define G(X, Y, Z) \ michael@0: ((X & Z) | (Y & (~Z))) michael@0: michael@0: #define H(X, Y, Z) \ michael@0: (X ^ Y ^ Z) michael@0: michael@0: #define I(X, Y, Z) \ michael@0: (Y ^ (X | (~Z))) michael@0: michael@0: #define FF(a, b, c, d, bufint, s, ti) \ michael@0: a = b + cls(a + F(b, c, d) + bufint + ti, s) michael@0: michael@0: #define GG(a, b, c, d, bufint, s, ti) \ michael@0: a = b + cls(a + G(b, c, d) + bufint + ti, s) michael@0: michael@0: #define HH(a, b, c, d, bufint, s, ti) \ michael@0: a = b + cls(a + H(b, c, d) + bufint + ti, s) michael@0: michael@0: #define II(a, b, c, d, bufint, s, ti) \ michael@0: a = b + cls(a + I(b, c, d) + bufint + ti, s) michael@0: michael@0: static void michael@0: md5_compress(MD5Context *cx, const PRUint32 *wBuf) michael@0: { michael@0: PRUint32 a, b, c, d; michael@0: PRUint32 tmp; michael@0: a = cx->cv[0]; michael@0: b = cx->cv[1]; michael@0: c = cx->cv[2]; michael@0: d = cx->cv[3]; michael@0: FF(a, b, c, d, wBuf[R1B0 ], S1_0, T1_0); michael@0: FF(d, a, b, c, wBuf[R1B1 ], S1_1, T1_1); michael@0: FF(c, d, a, b, wBuf[R1B2 ], S1_2, T1_2); michael@0: FF(b, c, d, a, wBuf[R1B3 ], S1_3, T1_3); michael@0: FF(a, b, c, d, wBuf[R1B4 ], S1_0, T1_4); michael@0: FF(d, a, b, c, wBuf[R1B5 ], S1_1, T1_5); michael@0: FF(c, d, a, b, wBuf[R1B6 ], S1_2, T1_6); michael@0: FF(b, c, d, a, wBuf[R1B7 ], S1_3, T1_7); michael@0: FF(a, b, c, d, wBuf[R1B8 ], S1_0, T1_8); michael@0: FF(d, a, b, c, wBuf[R1B9 ], S1_1, T1_9); michael@0: FF(c, d, a, b, wBuf[R1B10], S1_2, T1_10); michael@0: FF(b, c, d, a, wBuf[R1B11], S1_3, T1_11); michael@0: FF(a, b, c, d, wBuf[R1B12], S1_0, T1_12); michael@0: FF(d, a, b, c, wBuf[R1B13], S1_1, T1_13); michael@0: FF(c, d, a, b, wBuf[R1B14], S1_2, T1_14); michael@0: FF(b, c, d, a, wBuf[R1B15], S1_3, T1_15); michael@0: GG(a, b, c, d, wBuf[R2B0 ], S2_0, T2_0); michael@0: GG(d, a, b, c, wBuf[R2B1 ], S2_1, T2_1); michael@0: GG(c, d, a, b, wBuf[R2B2 ], S2_2, T2_2); michael@0: GG(b, c, d, a, wBuf[R2B3 ], S2_3, T2_3); michael@0: GG(a, b, c, d, wBuf[R2B4 ], S2_0, T2_4); michael@0: GG(d, a, b, c, wBuf[R2B5 ], S2_1, T2_5); michael@0: GG(c, d, a, b, wBuf[R2B6 ], S2_2, T2_6); michael@0: GG(b, c, d, a, wBuf[R2B7 ], S2_3, T2_7); michael@0: GG(a, b, c, d, wBuf[R2B8 ], S2_0, T2_8); michael@0: GG(d, a, b, c, wBuf[R2B9 ], S2_1, T2_9); michael@0: GG(c, d, a, b, wBuf[R2B10], S2_2, T2_10); michael@0: GG(b, c, d, a, wBuf[R2B11], S2_3, T2_11); michael@0: GG(a, b, c, d, wBuf[R2B12], S2_0, T2_12); michael@0: GG(d, a, b, c, wBuf[R2B13], S2_1, T2_13); michael@0: GG(c, d, a, b, wBuf[R2B14], S2_2, T2_14); michael@0: GG(b, c, d, a, wBuf[R2B15], S2_3, T2_15); michael@0: HH(a, b, c, d, wBuf[R3B0 ], S3_0, T3_0); michael@0: HH(d, a, b, c, wBuf[R3B1 ], S3_1, T3_1); michael@0: HH(c, d, a, b, wBuf[R3B2 ], S3_2, T3_2); michael@0: HH(b, c, d, a, wBuf[R3B3 ], S3_3, T3_3); michael@0: HH(a, b, c, d, wBuf[R3B4 ], S3_0, T3_4); michael@0: HH(d, a, b, c, wBuf[R3B5 ], S3_1, T3_5); michael@0: HH(c, d, a, b, wBuf[R3B6 ], S3_2, T3_6); michael@0: HH(b, c, d, a, wBuf[R3B7 ], S3_3, T3_7); michael@0: HH(a, b, c, d, wBuf[R3B8 ], S3_0, T3_8); michael@0: HH(d, a, b, c, wBuf[R3B9 ], S3_1, T3_9); michael@0: HH(c, d, a, b, wBuf[R3B10], S3_2, T3_10); michael@0: HH(b, c, d, a, wBuf[R3B11], S3_3, T3_11); michael@0: HH(a, b, c, d, wBuf[R3B12], S3_0, T3_12); michael@0: HH(d, a, b, c, wBuf[R3B13], S3_1, T3_13); michael@0: HH(c, d, a, b, wBuf[R3B14], S3_2, T3_14); michael@0: HH(b, c, d, a, wBuf[R3B15], S3_3, T3_15); michael@0: II(a, b, c, d, wBuf[R4B0 ], S4_0, T4_0); michael@0: II(d, a, b, c, wBuf[R4B1 ], S4_1, T4_1); michael@0: II(c, d, a, b, wBuf[R4B2 ], S4_2, T4_2); michael@0: II(b, c, d, a, wBuf[R4B3 ], S4_3, T4_3); michael@0: II(a, b, c, d, wBuf[R4B4 ], S4_0, T4_4); michael@0: II(d, a, b, c, wBuf[R4B5 ], S4_1, T4_5); michael@0: II(c, d, a, b, wBuf[R4B6 ], S4_2, T4_6); michael@0: II(b, c, d, a, wBuf[R4B7 ], S4_3, T4_7); michael@0: II(a, b, c, d, wBuf[R4B8 ], S4_0, T4_8); michael@0: II(d, a, b, c, wBuf[R4B9 ], S4_1, T4_9); michael@0: II(c, d, a, b, wBuf[R4B10], S4_2, T4_10); michael@0: II(b, c, d, a, wBuf[R4B11], S4_3, T4_11); michael@0: II(a, b, c, d, wBuf[R4B12], S4_0, T4_12); michael@0: II(d, a, b, c, wBuf[R4B13], S4_1, T4_13); michael@0: II(c, d, a, b, wBuf[R4B14], S4_2, T4_14); michael@0: II(b, c, d, a, wBuf[R4B15], S4_3, T4_15); michael@0: cx->cv[0] += a; michael@0: cx->cv[1] += b; michael@0: cx->cv[2] += c; michael@0: cx->cv[3] += d; michael@0: } michael@0: michael@0: void michael@0: MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen) michael@0: { michael@0: PRUint32 bytesToConsume; michael@0: PRUint32 inBufIndex = cx->lsbInput & 63; michael@0: const PRUint32 *wBuf; michael@0: michael@0: /* Add the number of input bytes to the 64-bit input counter. */ michael@0: addto64(cx->msbInput, cx->lsbInput, inputLen); michael@0: if (inBufIndex) { michael@0: /* There is already data in the buffer. Fill with input. */ michael@0: bytesToConsume = PR_MIN(inputLen, MD5_BUFFER_SIZE - inBufIndex); michael@0: memcpy(&cx->inBuf[inBufIndex], input, bytesToConsume); michael@0: if (inBufIndex + bytesToConsume >= MD5_BUFFER_SIZE) { michael@0: /* The buffer is filled. Run the compression function. */ michael@0: #ifndef IS_LITTLE_ENDIAN michael@0: md5_prep_state_le(cx); michael@0: #endif michael@0: md5_compress(cx, cx->u.w); michael@0: } michael@0: /* Remaining input. */ michael@0: inputLen -= bytesToConsume; michael@0: input += bytesToConsume; michael@0: } michael@0: michael@0: /* Iterate over 64-byte chunks of the message. */ michael@0: while (inputLen >= MD5_BUFFER_SIZE) { michael@0: #ifdef IS_LITTLE_ENDIAN michael@0: #ifdef NSS_X86_OR_X64 michael@0: /* x86 can handle arithmetic on non-word-aligned buffers */ michael@0: wBuf = (PRUint32 *)input; michael@0: #else michael@0: if ((ptrdiff_t)input & 0x3) { michael@0: /* buffer not aligned, copy it to force alignment */ michael@0: memcpy(cx->inBuf, input, MD5_BUFFER_SIZE); michael@0: wBuf = cx->u.w; michael@0: } else { michael@0: /* buffer is aligned */ michael@0: wBuf = (PRUint32 *)input; michael@0: } michael@0: #endif michael@0: #else michael@0: md5_prep_buffer_le(cx, input); michael@0: wBuf = cx->u.w; michael@0: #endif michael@0: md5_compress(cx, wBuf); michael@0: inputLen -= MD5_BUFFER_SIZE; michael@0: input += MD5_BUFFER_SIZE; michael@0: } michael@0: michael@0: /* Tail of message (message bytes mod 64). */ michael@0: if (inputLen) michael@0: memcpy(cx->inBuf, input, inputLen); michael@0: } michael@0: michael@0: static const unsigned char padbytes[] = { michael@0: 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, michael@0: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 michael@0: }; michael@0: michael@0: void michael@0: MD5_End(MD5Context *cx, unsigned char *digest, michael@0: unsigned int *digestLen, unsigned int maxDigestLen) michael@0: { michael@0: #ifndef IS_LITTLE_ENDIAN michael@0: PRUint32 tmp; michael@0: #endif michael@0: PRUint32 lowInput, highInput; michael@0: PRUint32 inBufIndex = cx->lsbInput & 63; michael@0: michael@0: if (maxDigestLen < MD5_HASH_LEN) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return; michael@0: } michael@0: michael@0: /* Copy out the length of bits input before padding. */ michael@0: lowInput = cx->lsbInput; michael@0: highInput = (cx->msbInput << 3) | (lowInput >> 29); michael@0: lowInput <<= 3; michael@0: michael@0: if (inBufIndex < MD5_END_BUFFER) { michael@0: MD5_Update(cx, padbytes, MD5_END_BUFFER - inBufIndex); michael@0: } else { michael@0: MD5_Update(cx, padbytes, michael@0: MD5_END_BUFFER + MD5_BUFFER_SIZE - inBufIndex); michael@0: } michael@0: michael@0: /* Store the number of bytes input (before padding) in final 64 bits. */ michael@0: cx->u.w[14] = lendian(lowInput); michael@0: cx->u.w[15] = lendian(highInput); michael@0: michael@0: /* Final call to compress. */ michael@0: #ifndef IS_LITTLE_ENDIAN michael@0: md5_prep_state_le(cx); michael@0: #endif michael@0: md5_compress(cx, cx->u.w); michael@0: michael@0: /* Copy the resulting values out of the chain variables into return buf. */ michael@0: if (digestLen) michael@0: *digestLen = MD5_HASH_LEN; michael@0: #ifndef IS_LITTLE_ENDIAN michael@0: cx->cv[0] = lendian(cx->cv[0]); michael@0: cx->cv[1] = lendian(cx->cv[1]); michael@0: cx->cv[2] = lendian(cx->cv[2]); michael@0: cx->cv[3] = lendian(cx->cv[3]); michael@0: #endif michael@0: memcpy(digest, cx->cv, MD5_HASH_LEN); michael@0: } michael@0: michael@0: void michael@0: MD5_EndRaw(MD5Context *cx, unsigned char *digest, michael@0: unsigned int *digestLen, unsigned int maxDigestLen) michael@0: { michael@0: #ifndef IS_LITTLE_ENDIAN michael@0: PRUint32 tmp; michael@0: #endif michael@0: PRUint32 cv[4]; michael@0: michael@0: if (maxDigestLen < MD5_HASH_LEN) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: return; michael@0: } michael@0: michael@0: memcpy(cv, cx->cv, sizeof(cv)); michael@0: #ifndef IS_LITTLE_ENDIAN michael@0: cv[0] = lendian(cv[0]); michael@0: cv[1] = lendian(cv[1]); michael@0: cv[2] = lendian(cv[2]); michael@0: cv[3] = lendian(cv[3]); michael@0: #endif michael@0: memcpy(digest, cv, MD5_HASH_LEN); michael@0: if (digestLen) michael@0: *digestLen = MD5_HASH_LEN; michael@0: } michael@0: michael@0: unsigned int michael@0: MD5_FlattenSize(MD5Context *cx) michael@0: { michael@0: return sizeof(*cx); michael@0: } michael@0: michael@0: SECStatus michael@0: MD5_Flatten(MD5Context *cx, unsigned char *space) michael@0: { michael@0: memcpy(space, cx, sizeof(*cx)); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: MD5Context * michael@0: MD5_Resurrect(unsigned char *space, void *arg) michael@0: { michael@0: MD5Context *cx = MD5_NewContext(); michael@0: if (cx) michael@0: memcpy(cx, space, sizeof(*cx)); michael@0: return cx; michael@0: } michael@0: michael@0: void MD5_Clone(MD5Context *dest, MD5Context *src) michael@0: { michael@0: memcpy(dest, src, sizeof *dest); michael@0: } michael@0: michael@0: void michael@0: MD5_TraceState(MD5Context *cx) michael@0: { michael@0: PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); michael@0: }