ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

md5.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 /*
00024  * RFC 1321 compliant MD5 implementation,
00025  * by Christophe Devine <devine(at)cr0.net>
00026  * this program is licensed under the GPL.
00027  */
00028 
00029 #include "common/md5.h"
00030 #include "common/endian.h"
00031 #include "common/str.h"
00032 #include "common/stream.h"
00033 
00034 namespace Common {
00035 
00036 struct md5_context {
00037     uint32 total[2];
00038     uint32 state[4];
00039     uint8 buffer[64];
00040 };
00041 
00042 static void md5_starts(md5_context *ctx);
00043 static void md5_update(md5_context *ctx, const uint8 *input, uint32 length);
00044 static void md5_finish(md5_context *ctx, uint8 digest[16]);
00045 
00046 
00047 #define GET_UINT32(n, b, i) (n) = READ_LE_UINT32(b + i)
00048 #define PUT_UINT32(n, b, i) WRITE_LE_UINT32(b + i, n)
00049 
00050 void md5_starts(md5_context *ctx) {
00051     ctx->total[0] = 0;
00052     ctx->total[1] = 0;
00053 
00054     ctx->state[0] = 0x67452301;
00055     ctx->state[1] = 0xEFCDAB89;
00056     ctx->state[2] = 0x98BADCFE;
00057     ctx->state[3] = 0x10325476;
00058 }
00059 
00060 static void md5_process(md5_context *ctx, const uint8 data[64]) {
00061     uint32 X[16], A, B, C, D;
00062 
00063     GET_UINT32(X[0],  data,  0);
00064     GET_UINT32(X[1],  data,  4);
00065     GET_UINT32(X[2],  data,  8);
00066     GET_UINT32(X[3],  data, 12);
00067     GET_UINT32(X[4],  data, 16);
00068     GET_UINT32(X[5],  data, 20);
00069     GET_UINT32(X[6],  data, 24);
00070     GET_UINT32(X[7],  data, 28);
00071     GET_UINT32(X[8],  data, 32);
00072     GET_UINT32(X[9],  data, 36);
00073     GET_UINT32(X[10], data, 40);
00074     GET_UINT32(X[11], data, 44);
00075     GET_UINT32(X[12], data, 48);
00076     GET_UINT32(X[13], data, 52);
00077     GET_UINT32(X[14], data, 56);
00078     GET_UINT32(X[15], data, 60);
00079 
00080 #define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
00081 
00082 #define P(a, b, c, d, k, s, t)                    \
00083 {                                                 \
00084     a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
00085 }
00086 
00087     A = ctx->state[0];
00088     B = ctx->state[1];
00089     C = ctx->state[2];
00090     D = ctx->state[3];
00091 
00092 #define F(x, y, z) (z ^ (x & (y ^ z)))
00093 
00094     P(A, B, C, D,  0,  7, 0xD76AA478);
00095     P(D, A, B, C,  1, 12, 0xE8C7B756);
00096     P(C, D, A, B,  2, 17, 0x242070DB);
00097     P(B, C, D, A,  3, 22, 0xC1BDCEEE);
00098     P(A, B, C, D,  4,  7, 0xF57C0FAF);
00099     P(D, A, B, C,  5, 12, 0x4787C62A);
00100     P(C, D, A, B,  6, 17, 0xA8304613);
00101     P(B, C, D, A,  7, 22, 0xFD469501);
00102     P(A, B, C, D,  8,  7, 0x698098D8);
00103     P(D, A, B, C,  9, 12, 0x8B44F7AF);
00104     P(C, D, A, B, 10, 17, 0xFFFF5BB1);
00105     P(B, C, D, A, 11, 22, 0x895CD7BE);
00106     P(A, B, C, D, 12,  7, 0x6B901122);
00107     P(D, A, B, C, 13, 12, 0xFD987193);
00108     P(C, D, A, B, 14, 17, 0xA679438E);
00109     P(B, C, D, A, 15, 22, 0x49B40821);
00110 
00111 #undef F
00112 
00113 #define F(x, y, z) (y ^ (z & (x ^ y)))
00114 
00115     P(A, B, C, D,  1,  5, 0xF61E2562);
00116     P(D, A, B, C,  6,  9, 0xC040B340);
00117     P(C, D, A, B, 11, 14, 0x265E5A51);
00118     P(B, C, D, A,  0, 20, 0xE9B6C7AA);
00119     P(A, B, C, D,  5,  5, 0xD62F105D);
00120     P(D, A, B, C, 10,  9, 0x02441453);
00121     P(C, D, A, B, 15, 14, 0xD8A1E681);
00122     P(B, C, D, A,  4, 20, 0xE7D3FBC8);
00123     P(A, B, C, D,  9,  5, 0x21E1CDE6);
00124     P(D, A, B, C, 14,  9, 0xC33707D6);
00125     P(C, D, A, B,  3, 14, 0xF4D50D87);
00126     P(B, C, D, A,  8, 20, 0x455A14ED);
00127     P(A, B, C, D, 13,  5, 0xA9E3E905);
00128     P(D, A, B, C,  2,  9, 0xFCEFA3F8);
00129     P(C, D, A, B,  7, 14, 0x676F02D9);
00130     P(B, C, D, A, 12, 20, 0x8D2A4C8A);
00131 
00132 #undef F
00133 
00134 #define F(x, y, z) (x ^ y ^ z)
00135 
00136     P(A, B, C, D,  5,  4, 0xFFFA3942);
00137     P(D, A, B, C,  8, 11, 0x8771F681);
00138     P(C, D, A, B, 11, 16, 0x6D9D6122);
00139     P(B, C, D, A, 14, 23, 0xFDE5380C);
00140     P(A, B, C, D,  1,  4, 0xA4BEEA44);
00141     P(D, A, B, C,  4, 11, 0x4BDECFA9);
00142     P(C, D, A, B,  7, 16, 0xF6BB4B60);
00143     P(B, C, D, A, 10, 23, 0xBEBFBC70);
00144     P(A, B, C, D, 13,  4, 0x289B7EC6);
00145     P(D, A, B, C,  0, 11, 0xEAA127FA);
00146     P(C, D, A, B,  3, 16, 0xD4EF3085);
00147     P(B, C, D, A,  6, 23, 0x04881D05);
00148     P(A, B, C, D,  9,  4, 0xD9D4D039);
00149     P(D, A, B, C, 12, 11, 0xE6DB99E5);
00150     P(C, D, A, B, 15, 16, 0x1FA27CF8);
00151     P(B, C, D, A,  2, 23, 0xC4AC5665);
00152 
00153 #undef F
00154 
00155 #define F(x, y, z) (y ^ (x | ~z))
00156 
00157     P(A, B, C, D,  0,  6, 0xF4292244);
00158     P(D, A, B, C,  7, 10, 0x432AFF97);
00159     P(C, D, A, B, 14, 15, 0xAB9423A7);
00160     P(B, C, D, A,  5, 21, 0xFC93A039);
00161     P(A, B, C, D, 12,  6, 0x655B59C3);
00162     P(D, A, B, C,  3, 10, 0x8F0CCC92);
00163     P(C, D, A, B, 10, 15, 0xFFEFF47D);
00164     P(B, C, D, A,  1, 21, 0x85845DD1);
00165     P(A, B, C, D,  8,  6, 0x6FA87E4F);
00166     P(D, A, B, C, 15, 10, 0xFE2CE6E0);
00167     P(C, D, A, B,  6, 15, 0xA3014314);
00168     P(B, C, D, A, 13, 21, 0x4E0811A1);
00169     P(A, B, C, D,  4,  6, 0xF7537E82);
00170     P(D, A, B, C, 11, 10, 0xBD3AF235);
00171     P(C, D, A, B,  2, 15, 0x2AD7D2BB);
00172     P(B, C, D, A,  9, 21, 0xEB86D391);
00173 
00174 #undef F
00175 
00176     ctx->state[0] += A;
00177     ctx->state[1] += B;
00178     ctx->state[2] += C;
00179     ctx->state[3] += D;
00180 }
00181 
00182 void md5_update(md5_context *ctx, const uint8 *input, uint32 length) {
00183     uint32 left, fill;
00184 
00185     if (!length)
00186         return;
00187 
00188     left = ctx->total[0] & 0x3F;
00189     fill = 64 - left;
00190 
00191     ctx->total[0] += length;
00192     ctx->total[0] &= 0xFFFFFFFF;
00193 
00194     if (ctx->total[0] < length)
00195         ctx->total[1]++;
00196 
00197     if (left && length >= fill) {
00198         memcpy((void *)(ctx->buffer + left), (const void *)input, fill);
00199         md5_process(ctx, ctx->buffer);
00200         length -= fill;
00201         input  += fill;
00202         left = 0;
00203     }
00204 
00205     while (length >= 64) {
00206         md5_process(ctx, input);
00207         length -= 64;
00208         input  += 64;
00209     }
00210 
00211     if (length) {
00212         memcpy((void *)(ctx->buffer + left), (const void *)input, length);
00213     }
00214 }
00215 
00216 static const uint8 md5_padding[64] = {
00217     0x80, 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     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00220     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00221 };
00222 
00223 void md5_finish(md5_context *ctx, uint8 digest[16]) {
00224     uint32 last, padn;
00225     uint32 high, low;
00226     uint8 msglen[8];
00227 
00228     high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
00229     low  = (ctx->total[0] <<  3);
00230 
00231     PUT_UINT32(low,  msglen, 0);
00232     PUT_UINT32(high, msglen, 4);
00233 
00234     last = ctx->total[0] & 0x3F;
00235     padn = (last < 56) ? (56 - last) : (120 - last);
00236 
00237     md5_update(ctx, md5_padding, padn);
00238     md5_update(ctx, msglen, 8);
00239 
00240     PUT_UINT32(ctx->state[0], digest,  0);
00241     PUT_UINT32(ctx->state[1], digest,  4);
00242     PUT_UINT32(ctx->state[2], digest,  8);
00243     PUT_UINT32(ctx->state[3], digest, 12);
00244 }
00245 
00246 
00247 bool computeStreamMD5(ReadStream &stream, uint8 digest[16], uint32 length) {
00248 
00249 #ifdef DISABLE_MD5
00250     memset(digest, 0, 16);
00251 #else
00252     md5_context ctx;
00253     int i;
00254     unsigned char buf[1000];
00255     bool restricted = (length != 0);
00256     uint32 readlen;
00257 
00258     if (!restricted || sizeof(buf) <= length)
00259         readlen = sizeof(buf);
00260     else
00261         readlen = length;
00262 
00263     md5_starts(&ctx);
00264 
00265     while ((i = stream.read(buf, readlen)) > 0) {
00266         md5_update(&ctx, buf, i);
00267 
00268         if (restricted) {
00269             length -= i;
00270             if (length == 0)
00271                 break;
00272 
00273             if (sizeof(buf) > length)
00274                 readlen = length;
00275         }
00276     }
00277 
00278     md5_finish(&ctx, digest);
00279 #endif
00280     return true;
00281 }
00282 
00283 String computeStreamMD5AsString(ReadStream &stream, uint32 length) {
00284     String md5;
00285     uint8 digest[16];
00286     if (computeStreamMD5(stream, digest, length)) {
00287         for (int i = 0; i < 16; i++) {
00288             md5 += String::format("%02x", (int)digest[i]);
00289         }
00290     }
00291 
00292     return md5;
00293 }
00294 
00295 } // End of namespace Common


Generated on Sat Mar 23 2019 05:01:50 for ResidualVM by doxygen 1.7.1
curved edge   curved edge