TMD5.cxx

Go to the documentation of this file.
00001 // @(#)root/base:$Id: TMD5.cxx 35202 2010-09-08 13:12:42Z rdm $
00002 // Author: Fons Rademakers   29/9/2001
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // TMD5                                                                 //
00015 //                                                                      //
00016 // This code implements the MD5 message-digest algorithm.               //
00017 // The algorithm is due to Ron Rivest. This code was                    //
00018 // written by Colin Plumb in 1993, no copyright is claimed.             //
00019 // This code is in the public domain; do with it what you wish.         //
00020 //                                                                      //
00021 // Equivalent code is available from RSA Data Security, Inc.            //
00022 // This code has been tested against that, and is equivalent,           //
00023 // except that you don't need to include two pages of legalese          //
00024 // with every copy.                                                     //
00025 //                                                                      //
00026 // To compute the message digest of a chunk of bytes, create an         //
00027 // TMD5 object, call Update() as needed on buffers full of bytes, and   //
00028 // then call Final(), which will, optionally, fill a supplied 16-byte   //
00029 // array with the  digest.                                              //
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    // Create TMD5 object. Set bit count to 0 and buffer to mysterious
00049    // initialization constants.
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    // Create finalized TMD5 object containing passed in 16 byte digest.
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    // Zero out sensitive information
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    // MD5 copy ctor. Special copy ctor avoids copying unnecessary
00089    // temp arrays when finalized.
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    // MD5 assignment operator. Special assignment operator avoids
00103    // copying unnecessary temp arrays when finalized.
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    // Update TMD5 object to reflect the concatenation of another buffer full
00120    // of bytes.
00121 
00122    if (fFinalized) {
00123       Error("TMD5::Update", "Final() has already been called");
00124       return;
00125    }
00126 
00127    UInt_t t;
00128 
00129    // Update bitcount
00130    t = fBits[0];
00131    if ((fBits[0] = t + (len << 3)) < t)
00132       fBits[1]++;        // Carry from low to high
00133    fBits[1] += len >> 29;
00134 
00135    t = (t >> 3) & 0x3f;
00136 
00137    // Handle any leading odd-sized chunks
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    // Process data in 64-byte chunks
00153    while (len >= 64) {
00154       memcpy(fIn, buf, 64);
00155       Transform(fBuf, fIn);
00156       buf += 64;
00157       len -= 64;
00158    }
00159 
00160    // Handle any remaining bytes of data
00161    memcpy(fIn, buf, len);
00162 }
00163 
00164 //______________________________________________________________________________
00165 void TMD5::Final(UChar_t digest[16])
00166 {
00167    // MD5 finalization, ends an MD5 message-digest operation, writing the
00168    // the message digest and zeroizing the context.
00169    // Returns digest.
00170 
00171    Final();
00172    memcpy(digest, fDigest, 16);
00173 }
00174 
00175 //______________________________________________________________________________
00176 void TMD5::Final()
00177 {
00178    // MD5 finalization, ends an MD5 message-digest operation, writing the
00179    // the message digest and zeroizing the context.
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    // Save number of bits
00194    Encode(bits, fBits, 8);
00195 
00196    // Pad out to 56 mod 64
00197    count = (fBits[0] >> 3) & 0x3f;
00198    padLen = (count < 56) ? (56 - count) : (120 - count);
00199    Update(padding, padLen);
00200 
00201    // Append length (before padding)
00202    Update(bits, 8);
00203 
00204    // Store state in digest
00205    Encode(fDigest, fBuf, 16);
00206 
00207    // Zero out sensitive information
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    // Print digest in ascii hex form.
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    // Return message digest as string. Returns "" in case Final() has
00234    // not yet been called. Copy result because it points to a statically
00235    // allocated string.
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    // Encodes input into output. Assumes len is a multiple of 4.
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    // Decodes input into output. Assumes len is a multiple of 4.
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 // The four core functions - F1 is optimized somewhat
00280 //#define F1(x, y, z) (x & y | ~x & z)
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 // This is the central step in the MD5 algorithm
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    // The core of the MD5 algorithm, this alters an existing MD5 hash to
00294    // reflect the addition of 16 longwords of new data. Update() blocks
00295    // the data and converts bytes into longwords for this routine.
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    // Zero out sensitive information
00380    memset(x, 0, sizeof(x));
00381 }
00382 
00383 //______________________________________________________________________________
00384 Bool_t operator==(const TMD5 &m1, const TMD5 &m2)
00385 {
00386    // Compare two message digests for equality.
00387 
00388    // Make sure both are finalized.
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    // Set the digest from the ASCII representation 'md5ascii'. The caller
00408    // is responsible to make sure that the 32 chars md5ascii are valid.
00409    // Returns -1 if md5ascii is malformed, returns 0 otherwise.
00410 
00411    if (!md5ascii || strlen(md5ascii) < 32) {
00412       // Invalid input or ASCII representation
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    // Returns checksum stored in ASCII in specified file. Use to read files
00434    // created via WriteChecksum(). The returned TMD5 object must be deleted
00435    // by the user. Returns 0 in case the file cannot be opened or in case of
00436    // error. Static utlity function.
00437 
00438    FILE *fid = fopen(file, "r");
00439    if (!fid) {
00440       // file cannot be opened
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    // Writes checksum in ASCII format to specified file. This file can
00464    // directly be read by ReadChecksum(). The md5 must have been finalized.
00465    // Returns -1 in case file cannot be opened or in case of error,
00466    // 0 otherwise. Static utility function.
00467 
00468    FILE *fid = fopen(file, "w");
00469    if (!fid) {
00470       // file cannot be opened
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    // Returns checksum of specified file. The returned TMD5 object must
00485    // be deleted by the user. Returns 0 in case the file does not exists
00486    // or in case of error. This function preserves the modtime of the file
00487    // so it can be safely used in conjunction with methods that keep track
00488    // of the file's modtime. Static utility function.
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       // file does not exist
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    // Returns checksum of specified file in digest argument. Returns -1 in
00550    // case of error, 0 otherwise. This method preserves the modtime of the
00551    // file so it can be safely used in conjunction with methods that keep
00552    // track of the file's modtime. Static utility function.
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    // Input operator.  Delegate to Streamer.
00569 
00570    R__ASSERT( buf.IsWriting() );
00571 
00572    const_cast<TMD5&>(uuid).Streamer(buf);
00573    return buf;
00574 }

Generated on Tue Jul 5 14:11:21 2011 for ROOT_528-00b_version by  doxygen 1.5.1