00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "pent_include.h"
00027
00028 #include <cstring>
00029
00030 #include "md5.h"
00031 #include "IDataSource.h"
00032
00033 namespace Pentagram {
00034
00035 typedef struct {
00036 uint32 total[2];
00037 uint32 state[4];
00038 uint8 buffer[64];
00039 } md5_context;
00040
00041 static void md5_starts(md5_context *ctx);
00042 static void md5_update(md5_context *ctx, const uint8 *input, uint32 length);
00043 static void md5_finish(md5_context *ctx, uint8 digest[16]);
00044
00045 #define GET_UINT32(n, b, i) n = b[i] + (b[i+1]<<8) + (b[i+2]<<16) + (b[i+3]<<24)
00046 #define PUT_UINT32(n, b, i) do { b[i] = n; b[i+1] = n >> 8; b[i+2] = n >> 16; b[i+3] = n >> 24; } while(0)
00047
00048 static void md5_starts(md5_context *ctx) {
00049 ctx->total[0] = 0;
00050 ctx->total[1] = 0;
00051
00052 ctx->state[0] = 0x67452301;
00053 ctx->state[1] = 0xEFCDAB89;
00054 ctx->state[2] = 0x98BADCFE;
00055 ctx->state[3] = 0x10325476;
00056 }
00057
00058 static void md5_process(md5_context *ctx, const uint8 data[64]) {
00059 uint32 X[16], A, B, C, D;
00060
00061 GET_UINT32(X[0], data, 0);
00062 GET_UINT32(X[1], data, 4);
00063 GET_UINT32(X[2], data, 8);
00064 GET_UINT32(X[3], data, 12);
00065 GET_UINT32(X[4], data, 16);
00066 GET_UINT32(X[5], data, 20);
00067 GET_UINT32(X[6], data, 24);
00068 GET_UINT32(X[7], data, 28);
00069 GET_UINT32(X[8], data, 32);
00070 GET_UINT32(X[9], data, 36);
00071 GET_UINT32(X[10], data, 40);
00072 GET_UINT32(X[11], data, 44);
00073 GET_UINT32(X[12], data, 48);
00074 GET_UINT32(X[13], data, 52);
00075 GET_UINT32(X[14], data, 56);
00076 GET_UINT32(X[15], data, 60);
00077
00078 #define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
00079
00080 #define P(a, b, c, d, k, s, t) \
00081 { \
00082 a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
00083 }
00084
00085 A = ctx->state[0];
00086 B = ctx->state[1];
00087 C = ctx->state[2];
00088 D = ctx->state[3];
00089
00090 #define F(x, y, z) (z ^ (x & (y ^ z)))
00091
00092 P(A, B, C, D, 0, 7, 0xD76AA478);
00093 P(D, A, B, C, 1, 12, 0xE8C7B756);
00094 P(C, D, A, B, 2, 17, 0x242070DB);
00095 P(B, C, D, A, 3, 22, 0xC1BDCEEE);
00096 P(A, B, C, D, 4, 7, 0xF57C0FAF);
00097 P(D, A, B, C, 5, 12, 0x4787C62A);
00098 P(C, D, A, B, 6, 17, 0xA8304613);
00099 P(B, C, D, A, 7, 22, 0xFD469501);
00100 P(A, B, C, D, 8, 7, 0x698098D8);
00101 P(D, A, B, C, 9, 12, 0x8B44F7AF);
00102 P(C, D, A, B, 10, 17, 0xFFFF5BB1);
00103 P(B, C, D, A, 11, 22, 0x895CD7BE);
00104 P(A, B, C, D, 12, 7, 0x6B901122);
00105 P(D, A, B, C, 13, 12, 0xFD987193);
00106 P(C, D, A, B, 14, 17, 0xA679438E);
00107 P(B, C, D, A, 15, 22, 0x49B40821);
00108
00109 #undef F
00110
00111 #define F(x, y, z) (y ^ (z & (x ^ y)))
00112
00113 P(A, B, C, D, 1, 5, 0xF61E2562);
00114 P(D, A, B, C, 6, 9, 0xC040B340);
00115 P(C, D, A, B, 11, 14, 0x265E5A51);
00116 P(B, C, D, A, 0, 20, 0xE9B6C7AA);
00117 P(A, B, C, D, 5, 5, 0xD62F105D);
00118 P(D, A, B, C, 10, 9, 0x02441453);
00119 P(C, D, A, B, 15, 14, 0xD8A1E681);
00120 P(B, C, D, A, 4, 20, 0xE7D3FBC8);
00121 P(A, B, C, D, 9, 5, 0x21E1CDE6);
00122 P(D, A, B, C, 14, 9, 0xC33707D6);
00123 P(C, D, A, B, 3, 14, 0xF4D50D87);
00124 P(B, C, D, A, 8, 20, 0x455A14ED);
00125 P(A, B, C, D, 13, 5, 0xA9E3E905);
00126 P(D, A, B, C, 2, 9, 0xFCEFA3F8);
00127 P(C, D, A, B, 7, 14, 0x676F02D9);
00128 P(B, C, D, A, 12, 20, 0x8D2A4C8A);
00129
00130 #undef F
00131
00132 #define F(x, y, z) (x ^ y ^ z)
00133
00134 P(A, B, C, D, 5, 4, 0xFFFA3942);
00135 P(D, A, B, C, 8, 11, 0x8771F681);
00136 P(C, D, A, B, 11, 16, 0x6D9D6122);
00137 P(B, C, D, A, 14, 23, 0xFDE5380C);
00138 P(A, B, C, D, 1, 4, 0xA4BEEA44);
00139 P(D, A, B, C, 4, 11, 0x4BDECFA9);
00140 P(C, D, A, B, 7, 16, 0xF6BB4B60);
00141 P(B, C, D, A, 10, 23, 0xBEBFBC70);
00142 P(A, B, C, D, 13, 4, 0x289B7EC6);
00143 P(D, A, B, C, 0, 11, 0xEAA127FA);
00144 P(C, D, A, B, 3, 16, 0xD4EF3085);
00145 P(B, C, D, A, 6, 23, 0x04881D05);
00146 P(A, B, C, D, 9, 4, 0xD9D4D039);
00147 P(D, A, B, C, 12, 11, 0xE6DB99E5);
00148 P(C, D, A, B, 15, 16, 0x1FA27CF8);
00149 P(B, C, D, A, 2, 23, 0xC4AC5665);
00150
00151 #undef F
00152
00153 #define F(x, y, z) (y ^ (x | ~z))
00154
00155 P(A, B, C, D, 0, 6, 0xF4292244);
00156 P(D, A, B, C, 7, 10, 0x432AFF97);
00157 P(C, D, A, B, 14, 15, 0xAB9423A7);
00158 P(B, C, D, A, 5, 21, 0xFC93A039);
00159 P(A, B, C, D, 12, 6, 0x655B59C3);
00160 P(D, A, B, C, 3, 10, 0x8F0CCC92);
00161 P(C, D, A, B, 10, 15, 0xFFEFF47D);
00162 P(B, C, D, A, 1, 21, 0x85845DD1);
00163 P(A, B, C, D, 8, 6, 0x6FA87E4F);
00164 P(D, A, B, C, 15, 10, 0xFE2CE6E0);
00165 P(C, D, A, B, 6, 15, 0xA3014314);
00166 P(B, C, D, A, 13, 21, 0x4E0811A1);
00167 P(A, B, C, D, 4, 6, 0xF7537E82);
00168 P(D, A, B, C, 11, 10, 0xBD3AF235);
00169 P(C, D, A, B, 2, 15, 0x2AD7D2BB);
00170 P(B, C, D, A, 9, 21, 0xEB86D391);
00171
00172 #undef F
00173
00174 ctx->state[0] += A;
00175 ctx->state[1] += B;
00176 ctx->state[2] += C;
00177 ctx->state[3] += D;
00178 }
00179
00180 static void md5_update(md5_context *ctx, const uint8 *input, uint32 length) {
00181 uint32 left, fill;
00182
00183 if (!length)
00184 return;
00185
00186 left = ctx->total[0] & 0x3F;
00187 fill = 64 - left;
00188
00189 ctx->total[0] += length;
00190 ctx->total[0] &= 0xFFFFFFFF;
00191
00192 if (ctx->total[0] < length)
00193 ctx->total[1]++;
00194
00195 if (left && length >= fill) {
00196 std::memcpy((void *)(ctx->buffer + left), (const void *)input, fill);
00197 md5_process(ctx, ctx->buffer);
00198 length -= fill;
00199 input += fill;
00200 left = 0;
00201 }
00202
00203 while (length >= 64) {
00204 md5_process(ctx, input);
00205 length -= 64;
00206 input += 64;
00207 }
00208
00209 if (length) {
00210 memcpy((void *)(ctx->buffer + left), (const void *)input, length);
00211 }
00212 }
00213
00214 static const uint8 md5_padding[64] = {
00215 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00216 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00219 };
00220
00221 static void md5_finish(md5_context *ctx, uint8 digest[16]) {
00222 uint32 last, padn;
00223 uint32 high, low;
00224 uint8 msglen[8];
00225
00226 high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
00227 low = (ctx->total[0] << 3);
00228
00229 PUT_UINT32(low, msglen, 0);
00230 PUT_UINT32(high, msglen, 4);
00231
00232 last = ctx->total[0] & 0x3F;
00233 padn = (last < 56) ? (56 - last) : (120 - last);
00234
00235 md5_update(ctx, md5_padding, padn);
00236 md5_update(ctx, msglen, 8);
00237
00238 PUT_UINT32(ctx->state[0], digest, 0);
00239 PUT_UINT32(ctx->state[1], digest, 4);
00240 PUT_UINT32(ctx->state[2], digest, 8);
00241 PUT_UINT32(ctx->state[3], digest, 12);
00242 }
00243
00244 bool md5_file(IDataSource* input, uint8 digest[16], uint32 length) {
00245 md5_context ctx;
00246 int i;
00247 unsigned char buf[1024];
00248 bool restricted = (length != 0);
00249 int readlen;
00250
00251 if (!restricted || sizeof(buf) <= length)
00252 readlen = sizeof(buf);
00253 else
00254 readlen = length;
00255
00256 md5_starts(&ctx);
00257
00258 while ((i = input->read(buf, readlen)) > 0) {
00259 md5_update(&ctx, buf, i);
00260
00261 length -= i;
00262 if (restricted && length == 0)
00263 break;
00264
00265 if (restricted && sizeof(buf) > length)
00266 readlen = length;
00267 }
00268
00269 md5_finish(&ctx, digest);
00270 return true;
00271 }
00272
00273 }