md5_utils.c 7.81 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
 */

clang-format's avatar
clang-format committed
23
#include <string.h> /* for memcpy() */
John Koleszar's avatar
John Koleszar committed
24 25 26

#include "md5_utils.h"

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

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

clang-format's avatar
clang-format committed
33
  if (*(char *)&i == 1) return;
John Koleszar's avatar
John Koleszar committed
34

John Koleszar's avatar
John Koleszar committed
35
  p = (md5byte *)buf;
36

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

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

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

John Koleszar's avatar
John Koleszar committed
65
  /* Update byte count */
John Koleszar's avatar
John Koleszar committed
66

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

John Koleszar's avatar
John Koleszar committed
69
  if ((ctx->bytes[0] = t + len) < t)
clang-format's avatar
clang-format committed
70
    ctx->bytes[1]++; /* Carry from low to high */
John Koleszar's avatar
John Koleszar committed
71

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

John Koleszar's avatar
John Koleszar committed
74 75 76 77
  if (t > len) {
    memcpy((md5byte *)ctx->in + 64 - t, buf, len);
    return;
  }
John Koleszar's avatar
John Koleszar committed
78

John Koleszar's avatar
John Koleszar committed
79 80 81 82 83 84 85 86 87 88
  /* 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);
89 90
    byteSwap(ctx->in, 16);
    MD5Transform(ctx->buf, ctx->in);
John Koleszar's avatar
John Koleszar committed
91 92 93 94 95 96
    buf += 64;
    len -= 64;
  }

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

99 100 101
/*
 * 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
102
 */
clang-format's avatar
clang-format committed
103
void MD5Final(md5byte digest[16], struct MD5Context *ctx) {
John Koleszar's avatar
John Koleszar committed
104 105 106 107 108 109 110 111 112
  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;

clang-format's avatar
clang-format committed
113
  if (count < 0) { /* Padding forces an extra block */
John Koleszar's avatar
John Koleszar committed
114 115
    memset(p, 0, count + 8);
    byteSwap(ctx->in, 16);
116
    MD5Transform(ctx->buf, ctx->in);
John Koleszar's avatar
John Koleszar committed
117 118 119 120 121 122 123 124 125 126 127
    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);
128

John Koleszar's avatar
John Koleszar committed
129 130 131
  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
132 133
}

134 135 136 137 138 139 140 141 142 143 144
#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. */
clang-format's avatar
clang-format committed
145 146
#define MD5STEP(f, w, x, y, z, in, s) \
  (w += f(x, y, z) + in, w = (w << s | w >> (32 - s)) + x)
147

148 149
#if defined(__clang__) && defined(__has_attribute)
#if __has_attribute(no_sanitize)
150
#define AOM_NO_UNSIGNED_OVERFLOW_CHECK \
151 152 153 154
  __attribute__((no_sanitize("unsigned-integer-overflow")))
#endif
#endif

155 156
#ifndef AOM_NO_UNSIGNED_OVERFLOW_CHECK
#define AOM_NO_UNSIGNED_OVERFLOW_CHECK
157 158
#endif

159 160 161 162
/*
 * 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
163
 */
164
AOM_NO_UNSIGNED_OVERFLOW_CHECK void MD5Transform(UWORD32 buf[4],
clang-format's avatar
clang-format committed
165
                                                 UWORD32 const in[16]) {
John Koleszar's avatar
John Koleszar committed
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 239 240 241 242 243 244
  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
245
}
246

247
#undef AOM_NO_UNSIGNED_OVERFLOW_CHECK
248

249
#endif