persistentstorage/sqlite3api/TEST/SRC/test_md5.c
changeset 0 08ec8eefde2f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 /*
       
     2 **
       
     3 ** Portions Copyright (c) 2008 Nokia Corporation and/or its subsidiaries. All rights reserved.
       
     4 **
       
     5 ** SQLite uses this code for testing only.  It is not a part of
       
     6 ** the SQLite library.  This file implements two new TCL commands
       
     7 ** "md5" and "md5file" that compute md5 checksums on arbitrary text
       
     8 ** and on complete files.  These commands are used by the "testfixture"
       
     9 ** program to help verify the correct operation of the SQLite library.
       
    10 **
       
    11 ** The original use of these TCL commands was to test the ROLLBACK
       
    12 ** feature of SQLite.  First compute the MD5-checksum of the database.
       
    13 ** Then make some changes but rollback the changes rather than commit
       
    14 ** them.  Compute a second MD5-checksum of the file and verify that the
       
    15 ** two checksums are the same.  Such is the original use of this code.
       
    16 ** New uses may have been added since this comment was written.
       
    17 **
       
    18 ** $Id: test_md5.c,v 1.8 2008/05/16 04:51:55 danielk1977 Exp $
       
    19 */
       
    20 /*
       
    21  * This code implements the MD5 message-digest algorithm.
       
    22  * The algorithm is due to Ron Rivest.  This code was
       
    23  * written by Colin Plumb in 1993, no copyright is claimed.
       
    24  * This code is in the public domain; do with it what you wish.
       
    25  *
       
    26  * Equivalent code is available from RSA Data Security, Inc.
       
    27  * This code has been tested against that, and is equivalent,
       
    28  * except that you don't need to include two pages of legalese
       
    29  * with every copy.
       
    30  *
       
    31  * To compute the message digest of a chunk of bytes, declare an
       
    32  * MD5Context structure, pass it to MD5Init, call MD5Update as
       
    33  * needed on buffers full of bytes, and then call MD5Final, which
       
    34  * will fill a supplied 16-byte array with the digest.
       
    35  */
       
    36 #include "tcl.h"
       
    37 #include <string.h>
       
    38 #include "sqlite3.h"
       
    39 #include <sys/param.h>
       
    40 
       
    41 /* Symbian OS */
       
    42 extern char* GetFullFilePath(char* aPath, const char* aFileName);
       
    43 
       
    44 /*
       
    45  * If compiled on a machine that doesn't have a 32-bit integer,
       
    46  * you just set "uint32" to the appropriate datatype for an
       
    47  * unsigned 32-bit integer.  For example:
       
    48  *
       
    49  *       cc -Duint32='unsigned long' md5.c
       
    50  *
       
    51  */
       
    52 #ifndef uint32
       
    53 #  define uint32 unsigned int
       
    54 #endif
       
    55 
       
    56 struct Context {
       
    57   int isInit;
       
    58   uint32 buf[4];
       
    59   uint32 bits[2];
       
    60   unsigned char in[64];
       
    61 };
       
    62 typedef struct Context MD5Context;
       
    63 
       
    64 /*
       
    65  * Note: this code is harmless on little-endian machines.
       
    66  */
       
    67 static void byteReverse (unsigned char *buf, unsigned longs){
       
    68         uint32 t;
       
    69         do {
       
    70                 t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 |
       
    71                             ((unsigned)buf[1]<<8 | buf[0]);
       
    72                 *(uint32 *)buf = t;
       
    73                 buf += 4;
       
    74         } while (--longs);
       
    75 }
       
    76 /* The four core functions - F1 is optimized somewhat */
       
    77 
       
    78 /* #define F1(x, y, z) (x & y | ~x & z) */
       
    79 #define F1(x, y, z) (z ^ (x & (y ^ z)))
       
    80 #define F2(x, y, z) F1(z, x, y)
       
    81 #define F3(x, y, z) (x ^ y ^ z)
       
    82 #define F4(x, y, z) (y ^ (x | ~z))
       
    83 
       
    84 /* This is the central step in the MD5 algorithm. */
       
    85 #define MD5STEP(f, w, x, y, z, data, s) \
       
    86         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
       
    87 
       
    88 /*
       
    89  * The core of the MD5 algorithm, this alters an existing MD5 hash to
       
    90  * reflect the addition of 16 longwords of new data.  MD5Update blocks
       
    91  * the data and converts bytes into longwords for this routine.
       
    92  */
       
    93 static void MD5Transform(uint32 buf[4], const uint32 in[16]){
       
    94         register uint32 a, b, c, d;
       
    95 
       
    96         a = buf[0];
       
    97         b = buf[1];
       
    98         c = buf[2];
       
    99         d = buf[3];
       
   100 
       
   101         MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
       
   102         MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
       
   103         MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
       
   104         MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
       
   105         MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
       
   106         MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
       
   107         MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
       
   108         MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
       
   109         MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
       
   110         MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
       
   111         MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
       
   112         MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
       
   113         MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
       
   114         MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
       
   115         MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
       
   116         MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
       
   117 
       
   118         MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
       
   119         MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
       
   120         MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
       
   121         MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
       
   122         MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
       
   123         MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
       
   124         MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
       
   125         MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
       
   126         MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
       
   127         MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
       
   128         MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
       
   129         MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
       
   130         MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
       
   131         MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
       
   132         MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
       
   133         MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
       
   134 
       
   135         MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
       
   136         MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
       
   137         MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
       
   138         MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
       
   139         MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
       
   140         MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
       
   141         MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
       
   142         MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
       
   143         MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
       
   144         MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
       
   145         MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
       
   146         MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
       
   147         MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
       
   148         MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
       
   149         MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
       
   150         MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
       
   151 
       
   152         MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
       
   153         MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
       
   154         MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
       
   155         MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
       
   156         MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
       
   157         MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
       
   158         MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
       
   159         MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
       
   160         MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
       
   161         MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
       
   162         MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
       
   163         MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
       
   164         MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
       
   165         MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
       
   166         MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
       
   167         MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
       
   168 
       
   169         buf[0] += a;
       
   170         buf[1] += b;
       
   171         buf[2] += c;
       
   172         buf[3] += d;
       
   173 }
       
   174 
       
   175 /*
       
   176  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
       
   177  * initialization constants.
       
   178  */
       
   179 static void MD5Init(MD5Context *ctx){
       
   180         ctx->isInit = 1;
       
   181         ctx->buf[0] = 0x67452301;
       
   182         ctx->buf[1] = 0xefcdab89;
       
   183         ctx->buf[2] = 0x98badcfe;
       
   184         ctx->buf[3] = 0x10325476;
       
   185         ctx->bits[0] = 0;
       
   186         ctx->bits[1] = 0;
       
   187 }
       
   188 
       
   189 /*
       
   190  * Update context to reflect the concatenation of another buffer full
       
   191  * of bytes.
       
   192  */
       
   193 static 
       
   194 void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){
       
   195         struct Context *ctx = (struct Context *)pCtx;
       
   196         uint32 t;
       
   197 
       
   198         /* Update bitcount */
       
   199 
       
   200         t = ctx->bits[0];
       
   201         if ((ctx->bits[0] = t + ((uint32)len << 3)) < t)
       
   202                 ctx->bits[1]++; /* Carry from low to high */
       
   203         ctx->bits[1] += len >> 29;
       
   204 
       
   205         t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
       
   206 
       
   207         /* Handle any leading odd-sized chunks */
       
   208 
       
   209         if ( t ) {
       
   210                 unsigned char *p = (unsigned char *)ctx->in + t;
       
   211 
       
   212                 t = 64-t;
       
   213                 if (len < t) {
       
   214                         memcpy(p, buf, len);
       
   215                         return;
       
   216                 }
       
   217                 memcpy(p, buf, t);
       
   218                 byteReverse(ctx->in, 16);
       
   219                 MD5Transform(ctx->buf, (uint32 *)ctx->in);
       
   220                 buf += t;
       
   221                 len -= t;
       
   222         }
       
   223 
       
   224         /* Process data in 64-byte chunks */
       
   225 
       
   226         while (len >= 64) {
       
   227                 memcpy(ctx->in, buf, 64);
       
   228                 byteReverse(ctx->in, 16);
       
   229                 MD5Transform(ctx->buf, (uint32 *)ctx->in);
       
   230                 buf += 64;
       
   231                 len -= 64;
       
   232         }
       
   233 
       
   234         /* Handle any remaining bytes of data. */
       
   235 
       
   236         memcpy(ctx->in, buf, len);
       
   237 }
       
   238 
       
   239 /*
       
   240  * Final wrapup - pad to 64-byte boundary with the bit pattern 
       
   241  * 1 0* (64-bit count of bits processed, MSB-first)
       
   242  */
       
   243 static void MD5Final(unsigned char digest[16], MD5Context *pCtx){
       
   244         struct Context *ctx = (struct Context *)pCtx;
       
   245         unsigned count;
       
   246         unsigned char *p;
       
   247 
       
   248         /* Compute number of bytes mod 64 */
       
   249         count = (ctx->bits[0] >> 3) & 0x3F;
       
   250 
       
   251         /* Set the first char of padding to 0x80.  This is safe since there is
       
   252            always at least one byte free */
       
   253         p = ctx->in + count;
       
   254         *p++ = 0x80;
       
   255 
       
   256         /* Bytes of padding needed to make 64 bytes */
       
   257         count = 64 - 1 - count;
       
   258 
       
   259         /* Pad out to 56 mod 64 */
       
   260         if (count < 8) {
       
   261                 /* Two lots of padding:  Pad the first block to 64 bytes */
       
   262                 memset(p, 0, count);
       
   263                 byteReverse(ctx->in, 16);
       
   264                 MD5Transform(ctx->buf, (uint32 *)ctx->in);
       
   265 
       
   266                 /* Now fill the next block with 56 bytes */
       
   267                 memset(ctx->in, 0, 56);
       
   268         } else {
       
   269                 /* Pad block to 56 bytes */
       
   270                 memset(p, 0, count-8);
       
   271         }
       
   272         byteReverse(ctx->in, 14);
       
   273 
       
   274         /* Append length in bits and transform */
       
   275         ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0];
       
   276         ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1];
       
   277 
       
   278         MD5Transform(ctx->buf, (uint32 *)ctx->in);
       
   279         byteReverse((unsigned char *)ctx->buf, 4);
       
   280         memcpy(digest, ctx->buf, 16);
       
   281         memset(ctx, 0, sizeof(ctx));    /* In case it is sensitive */
       
   282 }
       
   283 
       
   284 /*
       
   285 ** Convert a digest into base-16.  digest should be declared as
       
   286 ** "unsigned char digest[16]" in the calling function.  The MD5
       
   287 ** digest is stored in the first 16 bytes.  zBuf should
       
   288 ** be "char zBuf[33]".
       
   289 */
       
   290 static void DigestToBase16(unsigned char *digest, char *zBuf){
       
   291   static char const zEncode[] = "0123456789abcdef";
       
   292   int i, j;
       
   293 
       
   294   for(j=i=0; i<16; i++){
       
   295     int a = digest[i];
       
   296     zBuf[j++] = zEncode[(a>>4)&0xf];
       
   297     zBuf[j++] = zEncode[a & 0xf];
       
   298   }
       
   299   zBuf[j] = 0;
       
   300 }
       
   301 
       
   302 /*
       
   303 ** A TCL command for md5.  The argument is the text to be hashed.  The
       
   304 ** Result is the hash in base64.  
       
   305 */
       
   306 static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){
       
   307   MD5Context ctx;
       
   308   unsigned char digest[16];
       
   309 
       
   310   if( argc!=2 ){
       
   311     Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], 
       
   312         " TEXT\"", 0);
       
   313     return TCL_ERROR;
       
   314   }
       
   315   MD5Init(&ctx);
       
   316   MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1]));
       
   317   MD5Final(digest, &ctx);
       
   318   DigestToBase16(digest, interp->result);
       
   319   return TCL_OK;
       
   320 }
       
   321 
       
   322 /*
       
   323 ** A TCL command to take the md5 hash of a file.  The argument is the
       
   324 ** name of the file.
       
   325 */
       
   326 static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){
       
   327   FILE *in;
       
   328   MD5Context ctx;
       
   329   unsigned char digest[16];
       
   330   char zBuf[10240];
       
   331   char fnamebuf[MAXPATHLEN + 1];
       
   332 
       
   333   if( argc!=2 ){
       
   334     Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], 
       
   335         " FILENAME\"", 0);
       
   336     return TCL_ERROR;
       
   337   }
       
   338   if(GetFullFilePath(fnamebuf, argv[1]) == 0)
       
   339     return TCL_ERROR;
       
   340   in = fopen(fnamebuf,"rb");
       
   341   if( in==0 ){
       
   342     Tcl_AppendResult(interp,"unable to open file \"", fnamebuf, "\" for reading", 0);
       
   343     return TCL_ERROR;
       
   344   }
       
   345   MD5Init(&ctx);
       
   346   for(;;){
       
   347     int n;
       
   348     n = fread(zBuf, 1, sizeof(zBuf), in);
       
   349     if( n<=0 ) break;
       
   350     MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n);
       
   351   }
       
   352   fclose(in);
       
   353   MD5Final(digest, &ctx);
       
   354   DigestToBase16(digest, interp->result);
       
   355   return TCL_OK;
       
   356 }
       
   357 
       
   358 /*
       
   359 ** Register the two TCL commands above with the TCL interpreter.
       
   360 */
       
   361 int Md5_Init(Tcl_Interp *interp){
       
   362   Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, 0, 0);
       
   363   Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, 0, 0);
       
   364   return TCL_OK;
       
   365 }
       
   366 
       
   367 /*
       
   368 ** During testing, the special md5sum() aggregate function is available.
       
   369 ** inside SQLite.  The following routines implement that function.
       
   370 */
       
   371 static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){
       
   372   MD5Context *p;
       
   373   int i;
       
   374   if( argc<1 ) return;
       
   375   p = sqlite3_aggregate_context(context, sizeof(*p));
       
   376   if( p==0 ) return;
       
   377   if( !p->isInit ){
       
   378     MD5Init(p);
       
   379   }
       
   380   for(i=0; i<argc; i++){
       
   381     const char *zData = (char*)sqlite3_value_text(argv[i]);
       
   382     if( zData ){
       
   383       MD5Update(p, (unsigned char*)zData, strlen(zData));
       
   384     }
       
   385   }
       
   386 }
       
   387 static void md5finalize(sqlite3_context *context){
       
   388   MD5Context *p;
       
   389   unsigned char digest[16];
       
   390   char zBuf[33];
       
   391   p = sqlite3_aggregate_context(context, sizeof(*p));
       
   392   MD5Final(digest,p);
       
   393   DigestToBase16(digest, zBuf);
       
   394   sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
       
   395 }
       
   396 int Md5_Register(sqlite3 *db){
       
   397   int rc = sqlite3_create_function(db, "md5sum", -1, SQLITE_UTF8, 0, 0, 
       
   398                                  md5step, md5finalize);
       
   399   sqlite3_overload_function(db, "md5sum", -1);  /* To exercise this API */
       
   400   return rc;
       
   401 }