md5_utils.c 7.41 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 <string.h>   /* for memcpy() */
John Koleszar's avatar
John Koleszar committed
24 25 26

#include "md5_utils.h"

27
static void
John Koleszar's avatar
John Koleszar committed
28 29
byteSwap(UWORD32 *buf, unsigned words) {
  md5byte *p;
John Koleszar's avatar
John Koleszar committed
30

John Koleszar's avatar
John Koleszar committed
31 32
  /* Only swap bytes for big endian machines */
  int i = 1;
John Koleszar's avatar
John Koleszar committed
33

John Koleszar's avatar
John Koleszar committed
34 35
  if (*(char *)&i == 1)
    return;
John Koleszar's avatar
John Koleszar committed
36

John Koleszar's avatar
John Koleszar committed
37
  p = (md5byte *)buf;
38

John Koleszar's avatar
John Koleszar committed
39 40 41 42 43
  do {
    *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
             ((unsigned)p[1] << 8 | p[0]);
    p += 4;
  } while (--words);
44
}
John Koleszar's avatar
John Koleszar committed
45

46 47 48
/*
 * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
 * initialization constants.
John Koleszar's avatar
John Koleszar committed
49
 */
50
void
John Koleszar's avatar
John Koleszar committed
51 52 53 54 55 56 57 58
MD5Init(struct MD5Context *ctx) {
  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
59 60
}

61 62 63
/*
 * Update context to reflect the concatenation of another buffer full
 * of bytes.
John Koleszar's avatar
John Koleszar committed
64
 */
65
void
John Koleszar's avatar
John Koleszar committed
66 67
MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) {
  UWORD32 t;
John Koleszar's avatar
John Koleszar committed
68

John Koleszar's avatar
John Koleszar committed
69
  /* Update byte count */
John Koleszar's avatar
John Koleszar committed
70

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

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

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

John Koleszar's avatar
John Koleszar committed
78 79 80 81
  if (t > len) {
    memcpy((md5byte *)ctx->in + 64 - t, buf, len);
    return;
  }
John Koleszar's avatar
John Koleszar committed
82

John Koleszar's avatar
John Koleszar committed
83 84 85 86 87 88 89 90 91 92
  /* 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;

  /* Process data in 64-byte chunks */
  while (len >= 64) {
    memcpy(ctx->in, buf, 64);
93 94
    byteSwap(ctx->in, 16);
    MD5Transform(ctx->buf, ctx->in);
John Koleszar's avatar
John Koleszar committed
95 96 97 98 99 100
    buf += 64;
    len -= 64;
  }

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

103 104 105
/*
 * 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
106
 */
107
void
John Koleszar's avatar
John Koleszar committed
108 109 110 111 112 113 114 115 116 117 118 119 120
MD5Final(md5byte digest[16], struct MD5Context *ctx) {
  int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
  md5byte *p = (md5byte *)ctx->in + count;

  /* Set the first char of padding to 0x80.  There is always room. */
  *p++ = 0x80;

  /* Bytes of padding needed to make 56 bytes (-8..55) */
  count = 56 - 1 - count;

  if (count < 0) {  /* Padding forces an extra block */
    memset(p, 0, count + 8);
    byteSwap(ctx->in, 16);
121
    MD5Transform(ctx->buf, ctx->in);
John Koleszar's avatar
John Koleszar committed
122 123 124 125 126 127 128 129 130 131 132
    p = (md5byte *)ctx->in;
    count = 56;
  }

  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);
133

John Koleszar's avatar
John Koleszar committed
134 135 136
  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
137 138
}

139 140 141 142 143 144 145 146 147 148 149 150
#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) \
John Koleszar's avatar
John Koleszar committed
151
  (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
152 153 154 155 156

/*
 * 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
157
 */
158
void
John Koleszar's avatar
John Koleszar committed
159 160 161 162 163 164 165 166 167 168 169 170 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
MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) {
  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
239
}
240 241

#endif