tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

md5.c (15455B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifdef FREEBL_NO_DEPEND
      6 #include "stubs.h"
      7 #endif
      8 
      9 #include "prerr.h"
     10 #include "secerr.h"
     11 
     12 #include "prtypes.h"
     13 #include "prlong.h"
     14 
     15 #include "blapi.h"
     16 #include "blapii.h"
     17 
     18 #define MD5_HASH_LEN 16
     19 #define MD5_BUFFER_SIZE 64
     20 #define MD5_END_BUFFER (MD5_BUFFER_SIZE - 8)
     21 
     22 #define CV0_1 0x67452301
     23 #define CV0_2 0xefcdab89
     24 #define CV0_3 0x98badcfe
     25 #define CV0_4 0x10325476
     26 
     27 #define T1_0 0xd76aa478
     28 #define T1_1 0xe8c7b756
     29 #define T1_2 0x242070db
     30 #define T1_3 0xc1bdceee
     31 #define T1_4 0xf57c0faf
     32 #define T1_5 0x4787c62a
     33 #define T1_6 0xa8304613
     34 #define T1_7 0xfd469501
     35 #define T1_8 0x698098d8
     36 #define T1_9 0x8b44f7af
     37 #define T1_10 0xffff5bb1
     38 #define T1_11 0x895cd7be
     39 #define T1_12 0x6b901122
     40 #define T1_13 0xfd987193
     41 #define T1_14 0xa679438e
     42 #define T1_15 0x49b40821
     43 
     44 #define T2_0 0xf61e2562
     45 #define T2_1 0xc040b340
     46 #define T2_2 0x265e5a51
     47 #define T2_3 0xe9b6c7aa
     48 #define T2_4 0xd62f105d
     49 #define T2_5 0x02441453
     50 #define T2_6 0xd8a1e681
     51 #define T2_7 0xe7d3fbc8
     52 #define T2_8 0x21e1cde6
     53 #define T2_9 0xc33707d6
     54 #define T2_10 0xf4d50d87
     55 #define T2_11 0x455a14ed
     56 #define T2_12 0xa9e3e905
     57 #define T2_13 0xfcefa3f8
     58 #define T2_14 0x676f02d9
     59 #define T2_15 0x8d2a4c8a
     60 
     61 #define T3_0 0xfffa3942
     62 #define T3_1 0x8771f681
     63 #define T3_2 0x6d9d6122
     64 #define T3_3 0xfde5380c
     65 #define T3_4 0xa4beea44
     66 #define T3_5 0x4bdecfa9
     67 #define T3_6 0xf6bb4b60
     68 #define T3_7 0xbebfbc70
     69 #define T3_8 0x289b7ec6
     70 #define T3_9 0xeaa127fa
     71 #define T3_10 0xd4ef3085
     72 #define T3_11 0x04881d05
     73 #define T3_12 0xd9d4d039
     74 #define T3_13 0xe6db99e5
     75 #define T3_14 0x1fa27cf8
     76 #define T3_15 0xc4ac5665
     77 
     78 #define T4_0 0xf4292244
     79 #define T4_1 0x432aff97
     80 #define T4_2 0xab9423a7
     81 #define T4_3 0xfc93a039
     82 #define T4_4 0x655b59c3
     83 #define T4_5 0x8f0ccc92
     84 #define T4_6 0xffeff47d
     85 #define T4_7 0x85845dd1
     86 #define T4_8 0x6fa87e4f
     87 #define T4_9 0xfe2ce6e0
     88 #define T4_10 0xa3014314
     89 #define T4_11 0x4e0811a1
     90 #define T4_12 0xf7537e82
     91 #define T4_13 0xbd3af235
     92 #define T4_14 0x2ad7d2bb
     93 #define T4_15 0xeb86d391
     94 
     95 #define R1B0 0
     96 #define R1B1 1
     97 #define R1B2 2
     98 #define R1B3 3
     99 #define R1B4 4
    100 #define R1B5 5
    101 #define R1B6 6
    102 #define R1B7 7
    103 #define R1B8 8
    104 #define R1B9 9
    105 #define R1B10 10
    106 #define R1B11 11
    107 #define R1B12 12
    108 #define R1B13 13
    109 #define R1B14 14
    110 #define R1B15 15
    111 
    112 #define R2B0 1
    113 #define R2B1 6
    114 #define R2B2 11
    115 #define R2B3 0
    116 #define R2B4 5
    117 #define R2B5 10
    118 #define R2B6 15
    119 #define R2B7 4
    120 #define R2B8 9
    121 #define R2B9 14
    122 #define R2B10 3
    123 #define R2B11 8
    124 #define R2B12 13
    125 #define R2B13 2
    126 #define R2B14 7
    127 #define R2B15 12
    128 
    129 #define R3B0 5
    130 #define R3B1 8
    131 #define R3B2 11
    132 #define R3B3 14
    133 #define R3B4 1
    134 #define R3B5 4
    135 #define R3B6 7
    136 #define R3B7 10
    137 #define R3B8 13
    138 #define R3B9 0
    139 #define R3B10 3
    140 #define R3B11 6
    141 #define R3B12 9
    142 #define R3B13 12
    143 #define R3B14 15
    144 #define R3B15 2
    145 
    146 #define R4B0 0
    147 #define R4B1 7
    148 #define R4B2 14
    149 #define R4B3 5
    150 #define R4B4 12
    151 #define R4B5 3
    152 #define R4B6 10
    153 #define R4B7 1
    154 #define R4B8 8
    155 #define R4B9 15
    156 #define R4B10 6
    157 #define R4B11 13
    158 #define R4B12 4
    159 #define R4B13 11
    160 #define R4B14 2
    161 #define R4B15 9
    162 
    163 #define S1_0 7
    164 #define S1_1 12
    165 #define S1_2 17
    166 #define S1_3 22
    167 
    168 #define S2_0 5
    169 #define S2_1 9
    170 #define S2_2 14
    171 #define S2_3 20
    172 
    173 #define S3_0 4
    174 #define S3_1 11
    175 #define S3_2 16
    176 #define S3_3 23
    177 
    178 #define S4_0 6
    179 #define S4_1 10
    180 #define S4_2 15
    181 #define S4_3 21
    182 
    183 struct MD5ContextStr {
    184    PRUint32 lsbInput;
    185    PRUint32 msbInput;
    186    PRUint32 cv[4];
    187    union {
    188        PRUint8 b[64];
    189        PRUint32 w[16];
    190    } u;
    191 };
    192 
    193 #define inBuf u.b
    194 
    195 SECStatus
    196 MD5_Hash(unsigned char *dest, const char *src)
    197 {
    198    return MD5_HashBuf(dest, (const unsigned char *)src, PORT_Strlen(src));
    199 }
    200 
    201 SECStatus
    202 MD5_HashBuf(unsigned char *dest, const unsigned char *src, PRUint32 src_length)
    203 {
    204    unsigned int len;
    205    MD5Context cx;
    206 
    207    MD5_Begin(&cx);
    208    MD5_Update(&cx, src, src_length);
    209    MD5_End(&cx, dest, &len, MD5_HASH_LEN);
    210    memset(&cx, 0, sizeof cx);
    211    return SECSuccess;
    212 }
    213 
    214 MD5Context *
    215 MD5_NewContext(void)
    216 {
    217    /* no need to ZAlloc, MD5_Begin will init the context */
    218    MD5Context *cx = (MD5Context *)PORT_Alloc(sizeof(MD5Context));
    219    if (cx == NULL) {
    220        PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
    221        return NULL;
    222    }
    223    return cx;
    224 }
    225 
    226 void
    227 MD5_DestroyContext(MD5Context *cx, PRBool freeit)
    228 {
    229    memset(cx, 0, sizeof *cx);
    230    if (freeit) {
    231        PORT_Free(cx);
    232    }
    233 }
    234 
    235 void
    236 MD5_Begin(MD5Context *cx)
    237 {
    238    cx->lsbInput = 0;
    239    cx->msbInput = 0;
    240    /*  memset(cx->inBuf, 0, sizeof(cx->inBuf)); */
    241    cx->cv[0] = CV0_1;
    242    cx->cv[1] = CV0_2;
    243    cx->cv[2] = CV0_3;
    244    cx->cv[3] = CV0_4;
    245 }
    246 
    247 #define cls(i32, s) (tmp = i32, tmp << s | tmp >> (32 - s))
    248 
    249 #if defined(SOLARIS) || defined(HPUX)
    250 #define addto64(sumhigh, sumlow, addend) \
    251    sumlow += addend;                    \
    252    sumhigh += (sumlow < addend);
    253 #else
    254 #define addto64(sumhigh, sumlow, addend) \
    255    sumlow += addend;                    \
    256    if (sumlow < addend)                 \
    257        ++sumhigh;
    258 #endif
    259 
    260 #define MASK 0x00ff00ff
    261 #ifdef IS_LITTLE_ENDIAN
    262 #define lendian(i32) \
    263    (i32)
    264 #else
    265 #define lendian(i32) \
    266    (tmp = (i32 >> 16) | (i32 << 16), ((tmp & MASK) << 8) | ((tmp >> 8) & MASK))
    267 #endif
    268 
    269 #ifndef IS_LITTLE_ENDIAN
    270 
    271 #define lebytes(b4) \
    272    ((b4)[3] << 24 | (b4)[2] << 16 | (b4)[1] << 8 | (b4)[0])
    273 
    274 static void
    275 md5_prep_state_le(MD5Context *cx)
    276 {
    277    PRUint32 tmp;
    278    cx->u.w[0] = lendian(cx->u.w[0]);
    279    cx->u.w[1] = lendian(cx->u.w[1]);
    280    cx->u.w[2] = lendian(cx->u.w[2]);
    281    cx->u.w[3] = lendian(cx->u.w[3]);
    282    cx->u.w[4] = lendian(cx->u.w[4]);
    283    cx->u.w[5] = lendian(cx->u.w[5]);
    284    cx->u.w[6] = lendian(cx->u.w[6]);
    285    cx->u.w[7] = lendian(cx->u.w[7]);
    286    cx->u.w[8] = lendian(cx->u.w[8]);
    287    cx->u.w[9] = lendian(cx->u.w[9]);
    288    cx->u.w[10] = lendian(cx->u.w[10]);
    289    cx->u.w[11] = lendian(cx->u.w[11]);
    290    cx->u.w[12] = lendian(cx->u.w[12]);
    291    cx->u.w[13] = lendian(cx->u.w[13]);
    292    cx->u.w[14] = lendian(cx->u.w[14]);
    293    cx->u.w[15] = lendian(cx->u.w[15]);
    294 }
    295 
    296 static void
    297 md5_prep_buffer_le(MD5Context *cx, const PRUint8 *beBuf)
    298 {
    299    cx->u.w[0] = lebytes(&beBuf[0]);
    300    cx->u.w[1] = lebytes(&beBuf[4]);
    301    cx->u.w[2] = lebytes(&beBuf[8]);
    302    cx->u.w[3] = lebytes(&beBuf[12]);
    303    cx->u.w[4] = lebytes(&beBuf[16]);
    304    cx->u.w[5] = lebytes(&beBuf[20]);
    305    cx->u.w[6] = lebytes(&beBuf[24]);
    306    cx->u.w[7] = lebytes(&beBuf[28]);
    307    cx->u.w[8] = lebytes(&beBuf[32]);
    308    cx->u.w[9] = lebytes(&beBuf[36]);
    309    cx->u.w[10] = lebytes(&beBuf[40]);
    310    cx->u.w[11] = lebytes(&beBuf[44]);
    311    cx->u.w[12] = lebytes(&beBuf[48]);
    312    cx->u.w[13] = lebytes(&beBuf[52]);
    313    cx->u.w[14] = lebytes(&beBuf[56]);
    314    cx->u.w[15] = lebytes(&beBuf[60]);
    315 }
    316 #endif
    317 
    318 #define F(X, Y, Z) \
    319    ((X & Y) | ((~X) & Z))
    320 
    321 #define G(X, Y, Z) \
    322    ((X & Z) | (Y & (~Z)))
    323 
    324 #define H(X, Y, Z) \
    325    (X ^ Y ^ Z)
    326 
    327 #define I(X, Y, Z) \
    328    (Y ^ (X | (~Z)))
    329 
    330 #define FF(a, b, c, d, bufint, s, ti) \
    331    a = b + cls(a + F(b, c, d) + bufint + ti, s)
    332 
    333 #define GG(a, b, c, d, bufint, s, ti) \
    334    a = b + cls(a + G(b, c, d) + bufint + ti, s)
    335 
    336 #define HH(a, b, c, d, bufint, s, ti) \
    337    a = b + cls(a + H(b, c, d) + bufint + ti, s)
    338 
    339 #define II(a, b, c, d, bufint, s, ti) \
    340    a = b + cls(a + I(b, c, d) + bufint + ti, s)
    341 
    342 static void NO_SANITIZE_ALIGNMENT
    343 md5_compress(MD5Context *cx, const PRUint32 *wBuf)
    344 {
    345    PRUint32 a, b, c, d;
    346    PRUint32 tmp;
    347    a = cx->cv[0];
    348    b = cx->cv[1];
    349    c = cx->cv[2];
    350    d = cx->cv[3];
    351    FF(a, b, c, d, wBuf[R1B0], S1_0, T1_0);
    352    FF(d, a, b, c, wBuf[R1B1], S1_1, T1_1);
    353    FF(c, d, a, b, wBuf[R1B2], S1_2, T1_2);
    354    FF(b, c, d, a, wBuf[R1B3], S1_3, T1_3);
    355    FF(a, b, c, d, wBuf[R1B4], S1_0, T1_4);
    356    FF(d, a, b, c, wBuf[R1B5], S1_1, T1_5);
    357    FF(c, d, a, b, wBuf[R1B6], S1_2, T1_6);
    358    FF(b, c, d, a, wBuf[R1B7], S1_3, T1_7);
    359    FF(a, b, c, d, wBuf[R1B8], S1_0, T1_8);
    360    FF(d, a, b, c, wBuf[R1B9], S1_1, T1_9);
    361    FF(c, d, a, b, wBuf[R1B10], S1_2, T1_10);
    362    FF(b, c, d, a, wBuf[R1B11], S1_3, T1_11);
    363    FF(a, b, c, d, wBuf[R1B12], S1_0, T1_12);
    364    FF(d, a, b, c, wBuf[R1B13], S1_1, T1_13);
    365    FF(c, d, a, b, wBuf[R1B14], S1_2, T1_14);
    366    FF(b, c, d, a, wBuf[R1B15], S1_3, T1_15);
    367    GG(a, b, c, d, wBuf[R2B0], S2_0, T2_0);
    368    GG(d, a, b, c, wBuf[R2B1], S2_1, T2_1);
    369    GG(c, d, a, b, wBuf[R2B2], S2_2, T2_2);
    370    GG(b, c, d, a, wBuf[R2B3], S2_3, T2_3);
    371    GG(a, b, c, d, wBuf[R2B4], S2_0, T2_4);
    372    GG(d, a, b, c, wBuf[R2B5], S2_1, T2_5);
    373    GG(c, d, a, b, wBuf[R2B6], S2_2, T2_6);
    374    GG(b, c, d, a, wBuf[R2B7], S2_3, T2_7);
    375    GG(a, b, c, d, wBuf[R2B8], S2_0, T2_8);
    376    GG(d, a, b, c, wBuf[R2B9], S2_1, T2_9);
    377    GG(c, d, a, b, wBuf[R2B10], S2_2, T2_10);
    378    GG(b, c, d, a, wBuf[R2B11], S2_3, T2_11);
    379    GG(a, b, c, d, wBuf[R2B12], S2_0, T2_12);
    380    GG(d, a, b, c, wBuf[R2B13], S2_1, T2_13);
    381    GG(c, d, a, b, wBuf[R2B14], S2_2, T2_14);
    382    GG(b, c, d, a, wBuf[R2B15], S2_3, T2_15);
    383    HH(a, b, c, d, wBuf[R3B0], S3_0, T3_0);
    384    HH(d, a, b, c, wBuf[R3B1], S3_1, T3_1);
    385    HH(c, d, a, b, wBuf[R3B2], S3_2, T3_2);
    386    HH(b, c, d, a, wBuf[R3B3], S3_3, T3_3);
    387    HH(a, b, c, d, wBuf[R3B4], S3_0, T3_4);
    388    HH(d, a, b, c, wBuf[R3B5], S3_1, T3_5);
    389    HH(c, d, a, b, wBuf[R3B6], S3_2, T3_6);
    390    HH(b, c, d, a, wBuf[R3B7], S3_3, T3_7);
    391    HH(a, b, c, d, wBuf[R3B8], S3_0, T3_8);
    392    HH(d, a, b, c, wBuf[R3B9], S3_1, T3_9);
    393    HH(c, d, a, b, wBuf[R3B10], S3_2, T3_10);
    394    HH(b, c, d, a, wBuf[R3B11], S3_3, T3_11);
    395    HH(a, b, c, d, wBuf[R3B12], S3_0, T3_12);
    396    HH(d, a, b, c, wBuf[R3B13], S3_1, T3_13);
    397    HH(c, d, a, b, wBuf[R3B14], S3_2, T3_14);
    398    HH(b, c, d, a, wBuf[R3B15], S3_3, T3_15);
    399    II(a, b, c, d, wBuf[R4B0], S4_0, T4_0);
    400    II(d, a, b, c, wBuf[R4B1], S4_1, T4_1);
    401    II(c, d, a, b, wBuf[R4B2], S4_2, T4_2);
    402    II(b, c, d, a, wBuf[R4B3], S4_3, T4_3);
    403    II(a, b, c, d, wBuf[R4B4], S4_0, T4_4);
    404    II(d, a, b, c, wBuf[R4B5], S4_1, T4_5);
    405    II(c, d, a, b, wBuf[R4B6], S4_2, T4_6);
    406    II(b, c, d, a, wBuf[R4B7], S4_3, T4_7);
    407    II(a, b, c, d, wBuf[R4B8], S4_0, T4_8);
    408    II(d, a, b, c, wBuf[R4B9], S4_1, T4_9);
    409    II(c, d, a, b, wBuf[R4B10], S4_2, T4_10);
    410    II(b, c, d, a, wBuf[R4B11], S4_3, T4_11);
    411    II(a, b, c, d, wBuf[R4B12], S4_0, T4_12);
    412    II(d, a, b, c, wBuf[R4B13], S4_1, T4_13);
    413    II(c, d, a, b, wBuf[R4B14], S4_2, T4_14);
    414    II(b, c, d, a, wBuf[R4B15], S4_3, T4_15);
    415    cx->cv[0] += a;
    416    cx->cv[1] += b;
    417    cx->cv[2] += c;
    418    cx->cv[3] += d;
    419 }
    420 
    421 void
    422 MD5_Update(MD5Context *cx, const unsigned char *input, unsigned int inputLen)
    423 {
    424    PRUint32 bytesToConsume;
    425    PRUint32 inBufIndex = cx->lsbInput & 63;
    426    const PRUint32 *wBuf;
    427 
    428    /* Add the number of input bytes to the 64-bit input counter. */
    429    addto64(cx->msbInput, cx->lsbInput, inputLen);
    430    if (inBufIndex) {
    431        /* There is already data in the buffer.  Fill with input. */
    432        bytesToConsume = PR_MIN(inputLen, MD5_BUFFER_SIZE - inBufIndex);
    433        memcpy(&cx->inBuf[inBufIndex], input, bytesToConsume);
    434        if (inBufIndex + bytesToConsume >= MD5_BUFFER_SIZE) {
    435 /* The buffer is filled.  Run the compression function. */
    436 #ifndef IS_LITTLE_ENDIAN
    437            md5_prep_state_le(cx);
    438 #endif
    439            md5_compress(cx, cx->u.w);
    440        }
    441        /* Remaining input. */
    442        inputLen -= bytesToConsume;
    443        input += bytesToConsume;
    444    }
    445 
    446    /* Iterate over 64-byte chunks of the message. */
    447    while (inputLen >= MD5_BUFFER_SIZE) {
    448 #ifdef IS_LITTLE_ENDIAN
    449 #ifdef HAVE_UNALIGNED_ACCESS
    450        /* x86 can handle arithmetic on non-word-aligned buffers */
    451        wBuf = (PRUint32 *)input;
    452 #else
    453        if ((ptrdiff_t)input & 0x3) {
    454            /* buffer not aligned, copy it to force alignment */
    455            memcpy(cx->inBuf, input, MD5_BUFFER_SIZE);
    456            wBuf = cx->u.w;
    457        } else {
    458            /* buffer is aligned */
    459            wBuf = (PRUint32 *)input;
    460        }
    461 #endif
    462 #else
    463        md5_prep_buffer_le(cx, input);
    464        wBuf = cx->u.w;
    465 #endif
    466        md5_compress(cx, wBuf);
    467        inputLen -= MD5_BUFFER_SIZE;
    468        input += MD5_BUFFER_SIZE;
    469    }
    470 
    471    /* Tail of message (message bytes mod 64). */
    472    if (inputLen)
    473        memcpy(cx->inBuf, input, inputLen);
    474 }
    475 
    476 static const unsigned char padbytes[] = {
    477    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    478    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    479    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    480    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    481    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    482    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    483    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    484    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    485    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    486    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    487    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    488    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    489 };
    490 
    491 void
    492 MD5_End(MD5Context *cx, unsigned char *digest,
    493        unsigned int *digestLen, unsigned int maxDigestLen)
    494 {
    495 #ifndef IS_LITTLE_ENDIAN
    496    PRUint32 tmp;
    497 #endif
    498    PRUint32 lowInput, highInput;
    499    PRUint32 inBufIndex = cx->lsbInput & 63;
    500 
    501    if (maxDigestLen < MD5_HASH_LEN) {
    502        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    503        return;
    504    }
    505 
    506    /* Copy out the length of bits input before padding. */
    507    lowInput = cx->lsbInput;
    508    highInput = (cx->msbInput << 3) | (lowInput >> 29);
    509    lowInput <<= 3;
    510 
    511    if (inBufIndex < MD5_END_BUFFER) {
    512        MD5_Update(cx, padbytes, MD5_END_BUFFER - inBufIndex);
    513    } else {
    514        MD5_Update(cx, padbytes,
    515                   MD5_END_BUFFER + MD5_BUFFER_SIZE - inBufIndex);
    516    }
    517 
    518    /* Store the number of bytes input (before padding) in final 64 bits. */
    519    cx->u.w[14] = lendian(lowInput);
    520    cx->u.w[15] = lendian(highInput);
    521 
    522 /* Final call to compress. */
    523 #ifndef IS_LITTLE_ENDIAN
    524    md5_prep_state_le(cx);
    525 #endif
    526    md5_compress(cx, cx->u.w);
    527 
    528    /* Copy the resulting values out of the chain variables into return buf. */
    529    if (digestLen)
    530        *digestLen = MD5_HASH_LEN;
    531 #ifndef IS_LITTLE_ENDIAN
    532    cx->cv[0] = lendian(cx->cv[0]);
    533    cx->cv[1] = lendian(cx->cv[1]);
    534    cx->cv[2] = lendian(cx->cv[2]);
    535    cx->cv[3] = lendian(cx->cv[3]);
    536 #endif
    537    memcpy(digest, cx->cv, MD5_HASH_LEN);
    538 }
    539 
    540 void
    541 MD5_EndRaw(MD5Context *cx, unsigned char *digest,
    542           unsigned int *digestLen, unsigned int maxDigestLen)
    543 {
    544 #ifndef IS_LITTLE_ENDIAN
    545    PRUint32 tmp;
    546 #endif
    547    PRUint32 cv[4];
    548 
    549    if (maxDigestLen < MD5_HASH_LEN) {
    550        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    551        return;
    552    }
    553 
    554    memcpy(cv, cx->cv, sizeof(cv));
    555 #ifndef IS_LITTLE_ENDIAN
    556    cv[0] = lendian(cv[0]);
    557    cv[1] = lendian(cv[1]);
    558    cv[2] = lendian(cv[2]);
    559    cv[3] = lendian(cv[3]);
    560 #endif
    561    memcpy(digest, cv, MD5_HASH_LEN);
    562    if (digestLen)
    563        *digestLen = MD5_HASH_LEN;
    564 }
    565 
    566 unsigned int
    567 MD5_FlattenSize(MD5Context *cx)
    568 {
    569    return sizeof(*cx);
    570 }
    571 
    572 SECStatus
    573 MD5_Flatten(MD5Context *cx, unsigned char *space)
    574 {
    575    memcpy(space, cx, sizeof(*cx));
    576    return SECSuccess;
    577 }
    578 
    579 MD5Context *
    580 MD5_Resurrect(unsigned char *space, void *arg)
    581 {
    582    MD5Context *cx = MD5_NewContext();
    583    if (cx)
    584        memcpy(cx, space, sizeof(*cx));
    585    return cx;
    586 }
    587 
    588 void
    589 MD5_Clone(MD5Context *dest, MD5Context *src)
    590 {
    591    memcpy(dest, src, sizeof *dest);
    592 }
    593 
    594 void
    595 MD5_TraceState(MD5Context *cx)
    596 {
    597    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
    598 }