1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
45 #define MD5_HASH_LEN 16
46 #define MD5_BUFFER_SIZE 64
47 #define MD5_END_BUFFER (MD5_BUFFER_SIZE - 8)
49 #define CV0_1 0x67452301
50 #define CV0_2 0xefcdab89
51 #define CV0_3 0x98badcfe
52 #define CV0_4 0x10325476
54 #define T1_0 0xd76aa478
55 #define T1_1 0xe8c7b756
56 #define T1_2 0x242070db
57 #define T1_3 0xc1bdceee
58 #define T1_4 0xf57c0faf
59 #define T1_5 0x4787c62a
60 #define T1_6 0xa8304613
61 #define T1_7 0xfd469501
62 #define T1_8 0x698098d8
63 #define T1_9 0x8b44f7af
64 #define T1_10 0xffff5bb1
65 #define T1_11 0x895cd7be
66 #define T1_12 0x6b901122
67 #define T1_13 0xfd987193
68 #define T1_14 0xa679438e
69 #define T1_15 0x49b40821
71 #define T2_0 0xf61e2562
72 #define T2_1 0xc040b340
73 #define T2_2 0x265e5a51
74 #define T2_3 0xe9b6c7aa
75 #define T2_4 0xd62f105d
76 #define T2_5 0x02441453
77 #define T2_6 0xd8a1e681
78 #define T2_7 0xe7d3fbc8
79 #define T2_8 0x21e1cde6
80 #define T2_9 0xc33707d6
81 #define T2_10 0xf4d50d87
82 #define T2_11 0x455a14ed
83 #define T2_12 0xa9e3e905
84 #define T2_13 0xfcefa3f8
85 #define T2_14 0x676f02d9
86 #define T2_15 0x8d2a4c8a
88 #define T3_0 0xfffa3942
89 #define T3_1 0x8771f681
90 #define T3_2 0x6d9d6122
91 #define T3_3 0xfde5380c
92 #define T3_4 0xa4beea44
93 #define T3_5 0x4bdecfa9
94 #define T3_6 0xf6bb4b60
95 #define T3_7 0xbebfbc70
96 #define T3_8 0x289b7ec6
97 #define T3_9 0xeaa127fa
98 #define T3_10 0xd4ef3085
99 #define T3_11 0x04881d05
100 #define T3_12 0xd9d4d039
101 #define T3_13 0xe6db99e5
102 #define T3_14 0x1fa27cf8
103 #define T3_15 0xc4ac5665
105 #define T4_0 0xf4292244
106 #define T4_1 0x432aff97
107 #define T4_2 0xab9423a7
108 #define T4_3 0xfc93a039
109 #define T4_4 0x655b59c3
110 #define T4_5 0x8f0ccc92
111 #define T4_6 0xffeff47d
112 #define T4_7 0x85845dd1
113 #define T4_8 0x6fa87e4f
114 #define T4_9 0xfe2ce6e0
115 #define T4_10 0xa3014314
116 #define T4_11 0x4e0811a1
117 #define T4_12 0xf7537e82
118 #define T4_13 0xbd3af235
119 #define T4_14 0x2ad7d2bb
120 #define T4_15 0xeb86d391
210 struct MD5ContextStr
{
223 MD5_Hash(unsigned char *dest
, const char *src
)
225 return MD5_HashBuf(dest
, (unsigned char *)src
, PL_strlen(src
));
229 MD5_HashBuf(unsigned char *dest
, const unsigned char *src
, uint32 src_length
)
235 MD5_Update(&cx
, src
, src_length
);
236 MD5_End(&cx
, dest
, &len
, MD5_HASH_LEN
);
237 /* memset(&cx, 0, sizeof cx); */
244 /* no need to ZAlloc, MD5_Begin will init the context */
245 MD5Context
*cx
= (MD5Context
*)PORT_Alloc(sizeof(MD5Context
));
247 PORT_SetError(PR_OUT_OF_MEMORY_ERROR
);
254 MD5_DestroyContext(MD5Context
*cx
, PRBool freeit
)
256 /* memset(cx, 0, sizeof *cx); */
263 MD5_Begin(MD5Context
*cx
)
267 /* memset(cx->inBuf, 0, sizeof(cx->inBuf)); */
274 #define cls(i32, s) (tmp = i32, tmp << s | tmp >> (32 - s))
276 #if defined(SOLARIS) || defined(HPUX)
277 #define addto64(sumhigh, sumlow, addend) \
278 sumlow += addend; sumhigh += (sumlow < addend);
280 #define addto64(sumhigh, sumlow, addend) \
281 sumlow += addend; if (sumlow < addend) ++sumhigh;
284 #define MASK 0x00ff00ff
285 #ifdef IS_LITTLE_ENDIAN
286 #define lendian(i32) \
289 #define lendian(i32) \
290 (tmp = i32 >> 16 | i32 << 16, (tmp & MASK) << 8 | tmp >> 8 & MASK)
293 #ifndef IS_LITTLE_ENDIAN
295 #define lebytes(b4) \
296 ((b4)[3] << 24 | (b4)[2] << 16 | (b4)[1] << 8 | (b4)[0])
299 md5_prep_state_le(MD5Context
*cx
)
302 cx
->u
.w
[0] = lendian(cx
->u
.w
[0]);
303 cx
->u
.w
[1] = lendian(cx
->u
.w
[1]);
304 cx
->u
.w
[2] = lendian(cx
->u
.w
[2]);
305 cx
->u
.w
[3] = lendian(cx
->u
.w
[3]);
306 cx
->u
.w
[4] = lendian(cx
->u
.w
[4]);
307 cx
->u
.w
[5] = lendian(cx
->u
.w
[5]);
308 cx
->u
.w
[6] = lendian(cx
->u
.w
[6]);
309 cx
->u
.w
[7] = lendian(cx
->u
.w
[7]);
310 cx
->u
.w
[8] = lendian(cx
->u
.w
[8]);
311 cx
->u
.w
[9] = lendian(cx
->u
.w
[9]);
312 cx
->u
.w
[10] = lendian(cx
->u
.w
[10]);
313 cx
->u
.w
[11] = lendian(cx
->u
.w
[11]);
314 cx
->u
.w
[12] = lendian(cx
->u
.w
[12]);
315 cx
->u
.w
[13] = lendian(cx
->u
.w
[13]);
316 cx
->u
.w
[14] = lendian(cx
->u
.w
[14]);
317 cx
->u
.w
[15] = lendian(cx
->u
.w
[15]);
321 md5_prep_buffer_le(MD5Context
*cx
, const PRUint8
*beBuf
)
323 cx
->u
.w
[0] = lebytes(&beBuf
[0]);
324 cx
->u
.w
[1] = lebytes(&beBuf
[4]);
325 cx
->u
.w
[2] = lebytes(&beBuf
[8]);
326 cx
->u
.w
[3] = lebytes(&beBuf
[12]);
327 cx
->u
.w
[4] = lebytes(&beBuf
[16]);
328 cx
->u
.w
[5] = lebytes(&beBuf
[20]);
329 cx
->u
.w
[6] = lebytes(&beBuf
[24]);
330 cx
->u
.w
[7] = lebytes(&beBuf
[28]);
331 cx
->u
.w
[8] = lebytes(&beBuf
[32]);
332 cx
->u
.w
[9] = lebytes(&beBuf
[36]);
333 cx
->u
.w
[10] = lebytes(&beBuf
[40]);
334 cx
->u
.w
[11] = lebytes(&beBuf
[44]);
335 cx
->u
.w
[12] = lebytes(&beBuf
[48]);
336 cx
->u
.w
[13] = lebytes(&beBuf
[52]);
337 cx
->u
.w
[14] = lebytes(&beBuf
[56]);
338 cx
->u
.w
[15] = lebytes(&beBuf
[60]);
344 ((X & Y) | ((~X) & Z))
347 ((X & Z) | (Y & (~Z)))
355 #define FF(a, b, c, d, bufint, s, ti) \
356 a = b + cls(a + F(b, c, d) + bufint + ti, s)
358 #define GG(a, b, c, d, bufint, s, ti) \
359 a = b + cls(a + G(b, c, d) + bufint + ti, s)
361 #define HH(a, b, c, d, bufint, s, ti) \
362 a = b + cls(a + H(b, c, d) + bufint + ti, s)
364 #define II(a, b, c, d, bufint, s, ti) \
365 a = b + cls(a + I(b, c, d) + bufint + ti, s)
368 md5_compress(MD5Context
*cx
, const PRUint32
*wBuf
)
376 FF(a
, b
, c
, d
, wBuf
[R1B0
], S1_0
, T1_0
);
377 FF(d
, a
, b
, c
, wBuf
[R1B1
], S1_1
, T1_1
);
378 FF(c
, d
, a
, b
, wBuf
[R1B2
], S1_2
, T1_2
);
379 FF(b
, c
, d
, a
, wBuf
[R1B3
], S1_3
, T1_3
);
380 FF(a
, b
, c
, d
, wBuf
[R1B4
], S1_0
, T1_4
);
381 FF(d
, a
, b
, c
, wBuf
[R1B5
], S1_1
, T1_5
);
382 FF(c
, d
, a
, b
, wBuf
[R1B6
], S1_2
, T1_6
);
383 FF(b
, c
, d
, a
, wBuf
[R1B7
], S1_3
, T1_7
);
384 FF(a
, b
, c
, d
, wBuf
[R1B8
], S1_0
, T1_8
);
385 FF(d
, a
, b
, c
, wBuf
[R1B9
], S1_1
, T1_9
);
386 FF(c
, d
, a
, b
, wBuf
[R1B10
], S1_2
, T1_10
);
387 FF(b
, c
, d
, a
, wBuf
[R1B11
], S1_3
, T1_11
);
388 FF(a
, b
, c
, d
, wBuf
[R1B12
], S1_0
, T1_12
);
389 FF(d
, a
, b
, c
, wBuf
[R1B13
], S1_1
, T1_13
);
390 FF(c
, d
, a
, b
, wBuf
[R1B14
], S1_2
, T1_14
);
391 FF(b
, c
, d
, a
, wBuf
[R1B15
], S1_3
, T1_15
);
392 GG(a
, b
, c
, d
, wBuf
[R2B0
], S2_0
, T2_0
);
393 GG(d
, a
, b
, c
, wBuf
[R2B1
], S2_1
, T2_1
);
394 GG(c
, d
, a
, b
, wBuf
[R2B2
], S2_2
, T2_2
);
395 GG(b
, c
, d
, a
, wBuf
[R2B3
], S2_3
, T2_3
);
396 GG(a
, b
, c
, d
, wBuf
[R2B4
], S2_0
, T2_4
);
397 GG(d
, a
, b
, c
, wBuf
[R2B5
], S2_1
, T2_5
);
398 GG(c
, d
, a
, b
, wBuf
[R2B6
], S2_2
, T2_6
);
399 GG(b
, c
, d
, a
, wBuf
[R2B7
], S2_3
, T2_7
);
400 GG(a
, b
, c
, d
, wBuf
[R2B8
], S2_0
, T2_8
);
401 GG(d
, a
, b
, c
, wBuf
[R2B9
], S2_1
, T2_9
);
402 GG(c
, d
, a
, b
, wBuf
[R2B10
], S2_2
, T2_10
);
403 GG(b
, c
, d
, a
, wBuf
[R2B11
], S2_3
, T2_11
);
404 GG(a
, b
, c
, d
, wBuf
[R2B12
], S2_0
, T2_12
);
405 GG(d
, a
, b
, c
, wBuf
[R2B13
], S2_1
, T2_13
);
406 GG(c
, d
, a
, b
, wBuf
[R2B14
], S2_2
, T2_14
);
407 GG(b
, c
, d
, a
, wBuf
[R2B15
], S2_3
, T2_15
);
408 HH(a
, b
, c
, d
, wBuf
[R3B0
], S3_0
, T3_0
);
409 HH(d
, a
, b
, c
, wBuf
[R3B1
], S3_1
, T3_1
);
410 HH(c
, d
, a
, b
, wBuf
[R3B2
], S3_2
, T3_2
);
411 HH(b
, c
, d
, a
, wBuf
[R3B3
], S3_3
, T3_3
);
412 HH(a
, b
, c
, d
, wBuf
[R3B4
], S3_0
, T3_4
);
413 HH(d
, a
, b
, c
, wBuf
[R3B5
], S3_1
, T3_5
);
414 HH(c
, d
, a
, b
, wBuf
[R3B6
], S3_2
, T3_6
);
415 HH(b
, c
, d
, a
, wBuf
[R3B7
], S3_3
, T3_7
);
416 HH(a
, b
, c
, d
, wBuf
[R3B8
], S3_0
, T3_8
);
417 HH(d
, a
, b
, c
, wBuf
[R3B9
], S3_1
, T3_9
);
418 HH(c
, d
, a
, b
, wBuf
[R3B10
], S3_2
, T3_10
);
419 HH(b
, c
, d
, a
, wBuf
[R3B11
], S3_3
, T3_11
);
420 HH(a
, b
, c
, d
, wBuf
[R3B12
], S3_0
, T3_12
);
421 HH(d
, a
, b
, c
, wBuf
[R3B13
], S3_1
, T3_13
);
422 HH(c
, d
, a
, b
, wBuf
[R3B14
], S3_2
, T3_14
);
423 HH(b
, c
, d
, a
, wBuf
[R3B15
], S3_3
, T3_15
);
424 II(a
, b
, c
, d
, wBuf
[R4B0
], S4_0
, T4_0
);
425 II(d
, a
, b
, c
, wBuf
[R4B1
], S4_1
, T4_1
);
426 II(c
, d
, a
, b
, wBuf
[R4B2
], S4_2
, T4_2
);
427 II(b
, c
, d
, a
, wBuf
[R4B3
], S4_3
, T4_3
);
428 II(a
, b
, c
, d
, wBuf
[R4B4
], S4_0
, T4_4
);
429 II(d
, a
, b
, c
, wBuf
[R4B5
], S4_1
, T4_5
);
430 II(c
, d
, a
, b
, wBuf
[R4B6
], S4_2
, T4_6
);
431 II(b
, c
, d
, a
, wBuf
[R4B7
], S4_3
, T4_7
);
432 II(a
, b
, c
, d
, wBuf
[R4B8
], S4_0
, T4_8
);
433 II(d
, a
, b
, c
, wBuf
[R4B9
], S4_1
, T4_9
);
434 II(c
, d
, a
, b
, wBuf
[R4B10
], S4_2
, T4_10
);
435 II(b
, c
, d
, a
, wBuf
[R4B11
], S4_3
, T4_11
);
436 II(a
, b
, c
, d
, wBuf
[R4B12
], S4_0
, T4_12
);
437 II(d
, a
, b
, c
, wBuf
[R4B13
], S4_1
, T4_13
);
438 II(c
, d
, a
, b
, wBuf
[R4B14
], S4_2
, T4_14
);
439 II(b
, c
, d
, a
, wBuf
[R4B15
], S4_3
, T4_15
);
447 MD5_Update(MD5Context
*cx
, const unsigned char *input
, unsigned int inputLen
)
449 PRUint32 bytesToConsume
;
450 PRUint32 inBufIndex
= cx
->lsbInput
& 63;
451 const PRUint32
*wBuf
;
453 /* Add the number of input bytes to the 64-bit input counter. */
454 addto64(cx
->msbInput
, cx
->lsbInput
, inputLen
);
456 /* There is already data in the buffer. Fill with input. */
457 bytesToConsume
= PR_MIN(inputLen
, MD5_BUFFER_SIZE
- inBufIndex
);
458 memcpy(&cx
->inBuf
[inBufIndex
], input
, bytesToConsume
);
459 if (inBufIndex
+ bytesToConsume
>= MD5_BUFFER_SIZE
) {
460 /* The buffer is filled. Run the compression function. */
461 #ifndef IS_LITTLE_ENDIAN
462 md5_prep_state_le(cx
);
464 md5_compress(cx
, cx
->u
.w
);
466 /* Remaining input. */
467 inputLen
-= bytesToConsume
;
468 input
+= bytesToConsume
;
471 /* Iterate over 64-byte chunks of the message. */
472 while (inputLen
>= MD5_BUFFER_SIZE
) {
473 #ifdef IS_LITTLE_ENDIAN
475 /* x86 can handle arithmetic on non-word-aligned buffers */
476 wBuf
= (PRUint32
*)input
;
478 if ((ptrdiff_t)input
& 0x3) {
479 /* buffer not aligned, copy it to force alignment */
480 memcpy(cx
->inBuf
, input
, MD5_BUFFER_SIZE
);
483 /* buffer is aligned */
484 wBuf
= (PRUint32
*)input
;
488 md5_prep_buffer_le(cx
, input
);
491 md5_compress(cx
, wBuf
);
492 inputLen
-= MD5_BUFFER_SIZE
;
493 input
+= MD5_BUFFER_SIZE
;
496 /* Tail of message (message bytes mod 64). */
498 memcpy(cx
->inBuf
, input
, inputLen
);
501 static const unsigned char padbytes
[] = {
502 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
504 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
505 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
511 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
512 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
517 MD5_End(MD5Context
*cx
, unsigned char *digest
,
518 unsigned int *digestLen
, unsigned int maxDigestLen
)
520 #ifndef IS_LITTLE_ENDIAN
523 PRUint32 lowInput
, highInput
;
524 PRUint32 inBufIndex
= cx
->lsbInput
& 63;
526 if (maxDigestLen
< MD5_HASH_LEN
) {
527 PORT_SetError(SEC_ERROR_INVALID_ARGS
);
531 /* Copy out the length of bits input before padding. */
532 lowInput
= cx
->lsbInput
;
533 highInput
= (cx
->msbInput
<< 3) | (lowInput
>> 29);
536 if (inBufIndex
< MD5_END_BUFFER
) {
537 MD5_Update(cx
, padbytes
, MD5_END_BUFFER
- inBufIndex
);
539 MD5_Update(cx
, padbytes
,
540 MD5_END_BUFFER
+ MD5_BUFFER_SIZE
- inBufIndex
);
543 /* Store the number of bytes input (before padding) in final 64 bits. */
544 cx
->u
.w
[14] = lendian(lowInput
);
545 cx
->u
.w
[15] = lendian(highInput
);
547 /* Final call to compress. */
548 #ifndef IS_LITTLE_ENDIAN
549 md5_prep_state_le(cx
);
551 md5_compress(cx
, cx
->u
.w
);
553 /* Copy the resulting values out of the chain variables into return buf. */
554 *digestLen
= MD5_HASH_LEN
;
555 #ifndef IS_LITTLE_ENDIAN
556 cx
->cv
[0] = lendian(cx
->cv
[0]);
557 cx
->cv
[1] = lendian(cx
->cv
[1]);
558 cx
->cv
[2] = lendian(cx
->cv
[2]);
559 cx
->cv
[3] = lendian(cx
->cv
[3]);
561 memcpy(digest
, cx
->cv
, MD5_HASH_LEN
);
565 MD5_FlattenSize(MD5Context
*cx
)
571 MD5_Flatten(MD5Context
*cx
, unsigned char *space
)
573 memcpy(space
, cx
, sizeof(*cx
));
578 MD5_Resurrect(unsigned char *space
, void *arg
)
580 MD5Context
*cx
= MD5_NewContext();
582 memcpy(cx
, space
, sizeof(*cx
));
586 void MD5_Clone(MD5Context
*dest
, MD5Context
*src
)
588 memcpy(dest
, src
, sizeof *dest
);
592 MD5_TraceState(MD5Context
*cx
)
594 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR
);