md5_utils.c 7.78 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2 3 4 5
 * This code implements the MD5 message-digest algorithm.
 * The algorithm is due to Ron Rivest.  This code was
 * written by Colin Plumb in 1993, no copyright is claimed.
 * This code is in the public domain; do with it what you wish.
John Koleszar's avatar
John Koleszar committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * Equivalent code is available from RSA Data Security, Inc.
 * This code has been tested against that, and is equivalent,
 * except that you don't need to include two pages of legalese
 * with every copy.
 *
 * To compute the message digest of a chunk of bytes, declare an
 * MD5Context structure, pass it to MD5Init, call MD5Update as
 * needed on buffers full of bytes, and then call MD5Final, which
 * will fill a supplied 16-byte array with the digest.
 *
 * Changed so as no longer to depend on Colin Plumb's `usual.h' header
 * definitions
 *  - Ian Jackson <ian@chiark.greenend.org.uk>.
 * Still in the public domain.
John Koleszar's avatar
John Koleszar committed
21 22
 */

23
#include <sys/types.h>    /* for stupid systems */
John Koleszar's avatar
John Koleszar committed
24

25
#include <string.h>   /* for memcpy() */
John Koleszar's avatar
John Koleszar committed
26 27 28

#include "md5_utils.h"

29 30
void
byteSwap(UWORD32 *buf, unsigned words)
John Koleszar's avatar
John Koleszar committed
31
{
32
    md5byte *p;
John Koleszar's avatar
John Koleszar committed
33

34 35
    /* Only swap bytes for big endian machines */
    int i = 1;
John Koleszar's avatar
John Koleszar committed
36

37 38
    if (*(char *)&i == 1)
        return;
John Koleszar's avatar
John Koleszar committed
39

40 41 42 43 44 45 46
    p = (md5byte *)buf;

    do
    {
        *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
                 ((unsigned)p[1] << 8 | p[0]);
        p += 4;
John Koleszar's avatar
John Koleszar committed
47
    }
48 49
    while (--words);
}
John Koleszar's avatar
John Koleszar committed
50

51 52 53
/*
 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
 * initialization constants.
John Koleszar's avatar
John Koleszar committed
54
 */
55 56
void
MD5Init(struct MD5Context *ctx)
John Koleszar's avatar
John Koleszar committed
57
{
58 59 60 61 62 63 64
    ctx->buf[0] = 0x67452301;
    ctx->buf[1] = 0xefcdab89;
    ctx->buf[2] = 0x98badcfe;
    ctx->buf[3] = 0x10325476;

    ctx->bytes[0] = 0;
    ctx->bytes[1] = 0;
John Koleszar's avatar
John Koleszar committed
65 66
}

67 68 69
/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
John Koleszar's avatar
John Koleszar committed
70
 */
71 72
void
MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len)
John Koleszar's avatar
John Koleszar committed
73
{
74
    UWORD32 t;
John Koleszar's avatar
John Koleszar committed
75

76
    /* Update byte count */
John Koleszar's avatar
John Koleszar committed
77

78
    t = ctx->bytes[0];
John Koleszar's avatar
John Koleszar committed
79

80 81
    if ((ctx->bytes[0] = t + len) < t)
        ctx->bytes[1]++;  /* Carry from low to high */
John Koleszar's avatar
John Koleszar committed
82

83
    t = 64 - (t & 0x3f);  /* Space available in ctx->in (at least 1) */
John Koleszar's avatar
John Koleszar committed
84

85
    if (t > len)
John Koleszar's avatar
John Koleszar committed
86
    {
87 88 89
        memcpy((md5byte *)ctx->in + 64 - t, buf, len);
        return;
    }
John Koleszar's avatar
John Koleszar committed
90

91 92 93 94 95 96
    /* First chunk is an odd size */
    memcpy((md5byte *)ctx->in + 64 - t, buf, t);
    byteSwap(ctx->in, 16);
    MD5Transform(ctx->buf, ctx->in);
    buf += t;
    len -= t;
John Koleszar's avatar
John Koleszar committed
97

98 99 100 101 102 103 104 105
    /* Process data in 64-byte chunks */
    while (len >= 64)
    {
        memcpy(ctx->in, buf, 64);
        byteSwap(ctx->in, 16);
        MD5Transform(ctx->buf, ctx->in);
        buf += 64;
        len -= 64;
John Koleszar's avatar
John Koleszar committed
106 107
    }

108 109
    /* Handle any remaining bytes of data. */
    memcpy(ctx->in, buf, len);
John Koleszar's avatar
John Koleszar committed
110 111
}

112 113 114
/*
 * Final wrapup - pad to 64-byte boundary with the bit pattern
 * 1 0* (64-bit count of bits processed, MSB-first)
John Koleszar's avatar
John Koleszar committed
115
 */
116 117
void
MD5Final(md5byte digest[16], struct MD5Context *ctx)
John Koleszar's avatar
John Koleszar committed
118
{
119 120
    int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
    md5byte *p = (md5byte *)ctx->in + count;
John Koleszar's avatar
John Koleszar committed
121

122 123
    /* Set the first char of padding to 0x80.  There is always room. */
    *p++ = 0x80;
John Koleszar's avatar
John Koleszar committed
124

125 126
    /* Bytes of padding needed to make 56 bytes (-8..55) */
    count = 56 - 1 - count;
John Koleszar's avatar
John Koleszar committed
127

128
    if (count < 0)    /* Padding forces an extra block */
John Koleszar's avatar
John Koleszar committed
129
    {
130 131 132 133 134
        memset(p, 0, count + 8);
        byteSwap(ctx->in, 16);
        MD5Transform(ctx->buf, ctx->in);
        p = (md5byte *)ctx->in;
        count = 56;
John Koleszar's avatar
John Koleszar committed
135
    }
136 137 138 139 140 141 142 143 144 145 146 147

    memset(p, 0, count);
    byteSwap(ctx->in, 14);

    /* Append length in bits and transform */
    ctx->in[14] = ctx->bytes[0] << 3;
    ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
    MD5Transform(ctx->buf, ctx->in);

    byteSwap(ctx->buf, 4);
    memcpy(digest, ctx->buf, 16);
    memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
John Koleszar's avatar
John Koleszar committed
148 149
}

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
#ifndef ASM_MD5

/* The four core functions - F1 is optimized somewhat */

/* #define F1(x, y, z) (x & y | ~x & z) */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))

/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f,w,x,y,z,in,s) \
    (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)

/*
 * The core of the MD5 algorithm, this alters an existing MD5 hash to
 * reflect the addition of 16 longwords of new data.  MD5Update blocks
 * the data and converts bytes into longwords for this routine.
John Koleszar's avatar
John Koleszar committed
168
 */
169 170
void
MD5Transform(UWORD32 buf[4], UWORD32 const in[16])
John Koleszar's avatar
John Koleszar committed
171
{
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
    register UWORD32 a, b, c, d;

    a = buf[0];
    b = buf[1];
    c = buf[2];
    d = buf[3];

    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);

    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);

    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);

    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);

    buf[0] += a;
    buf[1] += b;
    buf[2] += c;
    buf[3] += d;
John Koleszar's avatar
John Koleszar committed
251
}
252 253

#endif