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
00027
00028
00029
00030
00031
00032
00033 #include "TMD5.h"
00034 #include "TError.h"
00035 #include "TSystem.h"
00036 #include "Bytes.h"
00037 #include <string.h>
00038 #include <errno.h>
00039 #ifdef R__WIN32
00040 #include <io.h>
00041 #endif
00042
00043 ClassImp(TMD5)
00044
00045
00046 TMD5::TMD5()
00047 {
00048
00049
00050
00051 fBuf[0] = 0x67452301;
00052 fBuf[1] = 0xefcdab89;
00053 fBuf[2] = 0x98badcfe;
00054 fBuf[3] = 0x10325476;
00055
00056 fBits[0] = 0;
00057 fBits[1] = 0;
00058
00059 memset(fIn, 0, 64);
00060
00061 memset(fDigest, 0, 16);
00062 fFinalized = kFALSE;
00063 }
00064
00065
00066 TMD5::TMD5(const UChar_t *digest)
00067 {
00068
00069
00070 if (digest)
00071 memcpy(fDigest, digest, 16);
00072 else {
00073 memset(fDigest, 0, 16);
00074 Error("TMD5::TMD5", "digest is 0");
00075 }
00076
00077
00078 memset(fBuf, 0, 4*sizeof(UInt_t));
00079 memset(fBits, 0, 2*sizeof(UInt_t));
00080 memset(fIn, 0, 64);
00081
00082 fFinalized = kTRUE;
00083 }
00084
00085
00086 TMD5::TMD5(const TMD5 &md5)
00087 {
00088
00089
00090
00091 memcpy(fBuf, md5.fBuf, 4*sizeof(UInt_t));
00092 memcpy(fBits, md5.fBits, 2*sizeof(UInt_t));
00093 memcpy(fIn, md5.fIn, 64);
00094
00095 memcpy(fDigest, md5.fDigest, 16);
00096 fFinalized = md5.fFinalized;
00097 }
00098
00099
00100 TMD5 &TMD5::operator=(const TMD5 &rhs)
00101 {
00102
00103
00104
00105 if (this != &rhs) {
00106 memcpy(fBuf, rhs.fBuf, 4*sizeof(UInt_t));
00107 memcpy(fBits, rhs.fBits, 2*sizeof(UInt_t));
00108 memcpy(fIn, rhs.fIn, 64);
00109
00110 memcpy(fDigest, rhs.fDigest, 16);
00111 fFinalized = rhs.fFinalized;
00112 }
00113 return *this;
00114 }
00115
00116
00117 void TMD5::Update(const UChar_t *buf, UInt_t len)
00118 {
00119
00120
00121
00122 if (fFinalized) {
00123 Error("TMD5::Update", "Final() has already been called");
00124 return;
00125 }
00126
00127 UInt_t t;
00128
00129
00130 t = fBits[0];
00131 if ((fBits[0] = t + (len << 3)) < t)
00132 fBits[1]++;
00133 fBits[1] += len >> 29;
00134
00135 t = (t >> 3) & 0x3f;
00136
00137
00138 if (t) {
00139 UChar_t *p = (UChar_t *) fIn + t;
00140
00141 t = 64 - t;
00142 if (len < t) {
00143 memcpy(p, buf, len);
00144 return;
00145 }
00146 memcpy(p, buf, t);
00147 Transform(fBuf, fIn);
00148 buf += t;
00149 len -= t;
00150 }
00151
00152
00153 while (len >= 64) {
00154 memcpy(fIn, buf, 64);
00155 Transform(fBuf, fIn);
00156 buf += 64;
00157 len -= 64;
00158 }
00159
00160
00161 memcpy(fIn, buf, len);
00162 }
00163
00164
00165 void TMD5::Final(UChar_t digest[16])
00166 {
00167
00168
00169
00170
00171 Final();
00172 memcpy(digest, fDigest, 16);
00173 }
00174
00175
00176 void TMD5::Final()
00177 {
00178
00179
00180
00181 if (fFinalized)
00182 return;
00183
00184 UInt_t count, padLen;
00185 UChar_t bits[8];
00186
00187 static UChar_t padding[64] = {
00188 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00189 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00191 };
00192
00193
00194 Encode(bits, fBits, 8);
00195
00196
00197 count = (fBits[0] >> 3) & 0x3f;
00198 padLen = (count < 56) ? (56 - count) : (120 - count);
00199 Update(padding, padLen);
00200
00201
00202 Update(bits, 8);
00203
00204
00205 Encode(fDigest, fBuf, 16);
00206
00207
00208 memset(fBuf, 0, 4*sizeof(UInt_t));
00209 memset(fBits, 0, 2*sizeof(UInt_t));
00210 memset(fIn, 0, 64);
00211
00212 fFinalized = kTRUE;
00213 }
00214
00215
00216 void TMD5::Print() const
00217 {
00218
00219
00220 if (!fFinalized) {
00221 Error("TMD5::Print", "Final() has not yet been called");
00222 return;
00223 }
00224
00225 for (int i = 0; i < 16; i++)
00226 printf("%.2hx", (UShort_t)fDigest[i]);
00227 printf("\n");
00228 }
00229
00230
00231 const char *TMD5::AsString() const
00232 {
00233
00234
00235
00236
00237 if (!fFinalized) {
00238 Error("TMD5::AsString", "Final() has not yet been called");
00239 return "";
00240 }
00241
00242 static char s[33];
00243
00244 for (int i = 0; i < 16; i++)
00245 sprintf((s+2*i), "%.2hx", (UShort_t)fDigest[i]);
00246 s[32] = 0;
00247
00248 return s;
00249 }
00250
00251
00252 void TMD5::Encode(UChar_t *out, const UInt_t *in, UInt_t len)
00253 {
00254
00255
00256 UInt_t i, j;
00257
00258 for (i = 0, j = 0; j < len; i++, j += 4) {
00259 out[j] = (UChar_t)(in[i] & 0xff);
00260 out[j+1] = (UChar_t)((in[i] >> 8) & 0xff);
00261 out[j+2] = (UChar_t)((in[i] >> 16) & 0xff);
00262 out[j+3] = (UChar_t)((in[i] >> 24) & 0xff);
00263 }
00264 }
00265
00266
00267 void TMD5::Decode(UInt_t *out, const UChar_t *in, UInt_t len)
00268 {
00269
00270
00271 UInt_t i, j;
00272
00273 for (i = 0, j = 0; j < len; i++, j += 4)
00274 out[i] = ((UInt_t)in[j]) | (((UInt_t)in[j+1]) << 8) |
00275 (((UInt_t)in[j+2]) << 16) | (((UInt_t)in[j+3]) << 24);
00276 }
00277
00278
00279
00280
00281 #define F1(x, y, z) (z ^ (x & (y ^ z)))
00282 #define F2(x, y, z) F1(z, x, y)
00283 #define F3(x, y, z) (x ^ y ^ z)
00284 #define F4(x, y, z) (y ^ (x | ~z))
00285
00286
00287 #define MD5STEP(f, w, x, y, z, data, s) \
00288 ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
00289
00290
00291 void TMD5::Transform(UInt_t buf[4], const UChar_t in[64])
00292 {
00293
00294
00295
00296
00297 UInt_t a, b, c, d, x[16];
00298
00299 a = buf[0];
00300 b = buf[1];
00301 c = buf[2];
00302 d = buf[3];
00303
00304 Decode(x, in, 64);
00305
00306 MD5STEP(F1, a, b, c, d, x[0] + 0xd76aa478, 7);
00307 MD5STEP(F1, d, a, b, c, x[1] + 0xe8c7b756, 12);
00308 MD5STEP(F1, c, d, a, b, x[2] + 0x242070db, 17);
00309 MD5STEP(F1, b, c, d, a, x[3] + 0xc1bdceee, 22);
00310 MD5STEP(F1, a, b, c, d, x[4] + 0xf57c0faf, 7);
00311 MD5STEP(F1, d, a, b, c, x[5] + 0x4787c62a, 12);
00312 MD5STEP(F1, c, d, a, b, x[6] + 0xa8304613, 17);
00313 MD5STEP(F1, b, c, d, a, x[7] + 0xfd469501, 22);
00314 MD5STEP(F1, a, b, c, d, x[8] + 0x698098d8, 7);
00315 MD5STEP(F1, d, a, b, c, x[9] + 0x8b44f7af, 12);
00316 MD5STEP(F1, c, d, a, b, x[10] + 0xffff5bb1, 17);
00317 MD5STEP(F1, b, c, d, a, x[11] + 0x895cd7be, 22);
00318 MD5STEP(F1, a, b, c, d, x[12] + 0x6b901122, 7);
00319 MD5STEP(F1, d, a, b, c, x[13] + 0xfd987193, 12);
00320 MD5STEP(F1, c, d, a, b, x[14] + 0xa679438e, 17);
00321 MD5STEP(F1, b, c, d, a, x[15] + 0x49b40821, 22);
00322
00323 MD5STEP(F2, a, b, c, d, x[1] + 0xf61e2562, 5);
00324 MD5STEP(F2, d, a, b, c, x[6] + 0xc040b340, 9);
00325 MD5STEP(F2, c, d, a, b, x[11] + 0x265e5a51, 14);
00326 MD5STEP(F2, b, c, d, a, x[0] + 0xe9b6c7aa, 20);
00327 MD5STEP(F2, a, b, c, d, x[5] + 0xd62f105d, 5);
00328 MD5STEP(F2, d, a, b, c, x[10] + 0x02441453, 9);
00329 MD5STEP(F2, c, d, a, b, x[15] + 0xd8a1e681, 14);
00330 MD5STEP(F2, b, c, d, a, x[4] + 0xe7d3fbc8, 20);
00331 MD5STEP(F2, a, b, c, d, x[9] + 0x21e1cde6, 5);
00332 MD5STEP(F2, d, a, b, c, x[14] + 0xc33707d6, 9);
00333 MD5STEP(F2, c, d, a, b, x[3] + 0xf4d50d87, 14);
00334 MD5STEP(F2, b, c, d, a, x[8] + 0x455a14ed, 20);
00335 MD5STEP(F2, a, b, c, d, x[13] + 0xa9e3e905, 5);
00336 MD5STEP(F2, d, a, b, c, x[2] + 0xfcefa3f8, 9);
00337 MD5STEP(F2, c, d, a, b, x[7] + 0x676f02d9, 14);
00338 MD5STEP(F2, b, c, d, a, x[12] + 0x8d2a4c8a, 20);
00339
00340 MD5STEP(F3, a, b, c, d, x[5] + 0xfffa3942, 4);
00341 MD5STEP(F3, d, a, b, c, x[8] + 0x8771f681, 11);
00342 MD5STEP(F3, c, d, a, b, x[11] + 0x6d9d6122, 16);
00343 MD5STEP(F3, b, c, d, a, x[14] + 0xfde5380c, 23);
00344 MD5STEP(F3, a, b, c, d, x[1] + 0xa4beea44, 4);
00345 MD5STEP(F3, d, a, b, c, x[4] + 0x4bdecfa9, 11);
00346 MD5STEP(F3, c, d, a, b, x[7] + 0xf6bb4b60, 16);
00347 MD5STEP(F3, b, c, d, a, x[10] + 0xbebfbc70, 23);
00348 MD5STEP(F3, a, b, c, d, x[13] + 0x289b7ec6, 4);
00349 MD5STEP(F3, d, a, b, c, x[0] + 0xeaa127fa, 11);
00350 MD5STEP(F3, c, d, a, b, x[3] + 0xd4ef3085, 16);
00351 MD5STEP(F3, b, c, d, a, x[6] + 0x04881d05, 23);
00352 MD5STEP(F3, a, b, c, d, x[9] + 0xd9d4d039, 4);
00353 MD5STEP(F3, d, a, b, c, x[12] + 0xe6db99e5, 11);
00354 MD5STEP(F3, c, d, a, b, x[15] + 0x1fa27cf8, 16);
00355 MD5STEP(F3, b, c, d, a, x[2] + 0xc4ac5665, 23);
00356
00357 MD5STEP(F4, a, b, c, d, x[0] + 0xf4292244, 6);
00358 MD5STEP(F4, d, a, b, c, x[7] + 0x432aff97, 10);
00359 MD5STEP(F4, c, d, a, b, x[14] + 0xab9423a7, 15);
00360 MD5STEP(F4, b, c, d, a, x[5] + 0xfc93a039, 21);
00361 MD5STEP(F4, a, b, c, d, x[12] + 0x655b59c3, 6);
00362 MD5STEP(F4, d, a, b, c, x[3] + 0x8f0ccc92, 10);
00363 MD5STEP(F4, c, d, a, b, x[10] + 0xffeff47d, 15);
00364 MD5STEP(F4, b, c, d, a, x[1] + 0x85845dd1, 21);
00365 MD5STEP(F4, a, b, c, d, x[8] + 0x6fa87e4f, 6);
00366 MD5STEP(F4, d, a, b, c, x[15] + 0xfe2ce6e0, 10);
00367 MD5STEP(F4, c, d, a, b, x[6] + 0xa3014314, 15);
00368 MD5STEP(F4, b, c, d, a, x[13] + 0x4e0811a1, 21);
00369 MD5STEP(F4, a, b, c, d, x[4] + 0xf7537e82, 6);
00370 MD5STEP(F4, d, a, b, c, x[11] + 0xbd3af235, 10);
00371 MD5STEP(F4, c, d, a, b, x[2] + 0x2ad7d2bb, 15);
00372 MD5STEP(F4, b, c, d, a, x[9] + 0xeb86d391, 21);
00373
00374 buf[0] += a;
00375 buf[1] += b;
00376 buf[2] += c;
00377 buf[3] += d;
00378
00379
00380 memset(x, 0, sizeof(x));
00381 }
00382
00383
00384 Bool_t operator==(const TMD5 &m1, const TMD5 &m2)
00385 {
00386
00387
00388
00389 if (!m1.fFinalized || !m2.fFinalized) {
00390 if (!m1.fFinalized)
00391 Error("TMD5::operator==(const TMD5&, const TMD5&)", "arg1.Final() not yet called");
00392 if (!m2.fFinalized)
00393 Error("TMD5::operator==(const TMD5&, const TMD5&)", "arg2.Final() not yet called");
00394 return kFALSE;
00395 }
00396
00397 for (int i = 0; i < 16; i++)
00398 if (m1.fDigest[i] != m2.fDigest[i])
00399 return kFALSE;
00400
00401 return kTRUE;
00402 }
00403
00404
00405 Int_t TMD5::SetDigest(const char *md5ascii)
00406 {
00407
00408
00409
00410
00411 if (!md5ascii || strlen(md5ascii) < 32) {
00412
00413 return -1;
00414 }
00415
00416 char *buf = (char *) md5ascii;
00417 for (int i = 0; i < 16; i++) {
00418 UShort_t d;
00419 char s = buf[2+2*i];
00420 buf[2+2*i] = 0;
00421 sscanf(buf+2*i, "%hx", &d);
00422 buf[2+2*i] = s;
00423 fDigest[i] = (UChar_t) d;
00424 }
00425 fFinalized = kTRUE;
00426
00427 return 0;
00428 }
00429
00430
00431 TMD5 *TMD5::ReadChecksum(const char *file)
00432 {
00433
00434
00435
00436
00437
00438 FILE *fid = fopen(file, "r");
00439 if (!fid) {
00440
00441 return 0;
00442 }
00443
00444 char buf[33];
00445
00446 if (!fgets(buf, 33, fid)) {
00447 SysError("TMD5::ReadChecksum", "error reading checksum from %s", file);
00448 fclose(fid);
00449 return 0;
00450 }
00451
00452 fclose(fid);
00453
00454 TMD5 *md5 = new TMD5;
00455 md5->SetDigest(buf);
00456
00457 return md5;
00458 }
00459
00460
00461 Int_t TMD5::WriteChecksum(const char *file, const TMD5 *md5)
00462 {
00463
00464
00465
00466
00467
00468 FILE *fid = fopen(file, "w");
00469 if (!fid) {
00470
00471 return -1;
00472 }
00473
00474 fputs(md5->AsString(), fid);
00475
00476 fclose(fid);
00477
00478 return 0;
00479 }
00480
00481
00482 TMD5 *TMD5::FileChecksum(const char *file)
00483 {
00484
00485
00486
00487
00488
00489
00490 Long64_t size;
00491 Long_t id, flags, modtime;
00492 if (gSystem->GetPathInfo(file, &id, &size, &flags, &modtime) == 0) {
00493 if (flags > 1) {
00494 Error("TMD5::FileChecksum", "%s not a regular file (%ld)", file, flags);
00495 return 0;
00496 }
00497 } else {
00498
00499 return 0;
00500 }
00501
00502 #ifndef WIN32
00503 Int_t fd = open(file, O_RDONLY);
00504 #else
00505 Int_t fd = open(file, O_RDONLY | O_BINARY);
00506 #endif
00507 if (fd < 0) {
00508 Error("TMD5::FileChecksum", "cannot open %s in read mode", file);
00509 return 0;
00510 }
00511
00512 TMD5 *md5 = new TMD5;
00513
00514 Long64_t pos = 0;
00515 const Int_t bufSize = 8192;
00516 UChar_t buf[bufSize];
00517
00518 while (pos < size) {
00519 Long64_t left = Long64_t(size - pos);
00520 if (left > bufSize)
00521 left = bufSize;
00522 Int_t siz;
00523 while ((siz = read(fd, buf, left)) < 0 && TSystem::GetErrno() == EINTR)
00524 TSystem::ResetErrno();
00525 if (siz < 0 || siz != left) {
00526 Error("TMD5::FileChecksum", "error reading from file %s", file);
00527 close(fd);
00528 delete md5;
00529 return 0;
00530 }
00531
00532 md5->Update(buf, left);
00533
00534 pos += left;
00535 }
00536
00537 close(fd);
00538
00539 md5->Final();
00540
00541 gSystem->Utime(file, modtime, modtime);
00542
00543 return md5;
00544 }
00545
00546
00547 Int_t TMD5::FileChecksum(const char *file, UChar_t digest[16])
00548 {
00549
00550
00551
00552
00553
00554 TMD5 *md5 = FileChecksum(file);
00555 if (md5) {
00556 memcpy(digest, md5->fDigest, 16);
00557 delete md5;
00558 return 0;
00559 } else
00560 memset(digest, 0, 16);
00561
00562 return -1;
00563 }
00564
00565
00566 TBuffer &operator<<(TBuffer &buf, const TMD5 &uuid)
00567 {
00568
00569
00570 R__ASSERT( buf.IsWriting() );
00571
00572 const_cast<TMD5&>(uuid).Streamer(buf);
00573 return buf;
00574 }