md5.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 RFC 1321 compliant MD5 implementation,
00004 by Christophe Devine <devine(at)cr0.net>
00005 this program is licensed under the GPL.
00006 
00007 Copied from ScummVM's common/md5.cpp
00008 Modified for use in Pentagram.
00009 
00010 
00011 This program is free software; you can redistribute it and/or
00012 modify it under the terms of the GNU General Public License
00013 as published by the Free Software Foundation; either version 2
00014 of the License, or (at your option) any later version.
00015 
00016 This program is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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 }

Generated on Fri Jul 27 22:27:25 2007 for pentagram by  doxygen 1.4.7