/* @(#)md5.c 17.1.1.1 (ESO-DMD) 01/25/02 17:40:34 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. Correspondence concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /* ++++++++++++++++++++++++++++++++++++++++++++++++++ .LANGUAGE: C .AUTHOR: Klaus Banse ESO - Garching .IDENTIFICATION .KEYWORDS MD5, signature .PURPOSE calculate the MD5 signature from the data of a FITS file .ALGORITHM code is taken over from module fitsmd5.c of Nicolas Devillard as copied into /home/code_other/ND/fitsmd5/fitsmd5 .RETURNS return status, = 0 o.k., else not o.k. .VERSIONS 010731 last modif -------------------------------------------------- */ /*---------------------------------------------------------------------------- File name : fitsmd5.c Author : N. Devillard Created on : May 2001 Description : Display/Add/Update the DATAMD5 keyword/value This is a stand-alone utility. Compile it with any ANSI C compiler: % cc -o fitsmd5 fitsmd5.c [optional optimization options] ---------------------------------------------------------------------------*/ /* $Id: fitsmd5.c,v 1.12 2001/07/25 07:38:06 ndevilla Exp $ $Author: ndevilla $ $Date: 2001/07/25 07:38:06 $ $Revision: 1.12 $ */ /*---------------------------------------------------------------------------- Includes ---------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include /*---------------------------------------------------------------------------- Defines ---------------------------------------------------------------------------*/ /* Definitions related to FITS */ #define FITSLINESZ 80 /* a FITS line is 80 chars */ #define FITSCARDS 36 /* 36 cards per block */ #define FITSBLOCKSZ (FITSLINESZ*FITSCARDS) /* FITS block size=2880 */ /* Definitions related to MD5 */ #define MD5HASHSZ 32 /* an MD5 key length is 32 bytes = 128 bits */ /* FITS keyword used to store MD5 key */ #define FITSMD5KEY "DATAMD5 " /*---------------------------------------------------------------------------- New types ---------------------------------------------------------------------------*/ /* The following types defined for MD5 computation only */ typedef unsigned int word32 ; struct MD5Context { word32 buf[4]; word32 bits[2]; unsigned char in[64]; }; /*---------------------------------------------------------------------------- Function prototypes ---------------------------------------------------------------------------*/ static void MD5Init( #ifdef __STDC__ struct MD5Context * #endif ); static void MD5Update( #ifdef __STDC__ struct MD5Context *, unsigned char *, unsigned #endif ); static void MD5Final( #ifdef __STDC__ unsigned char *, struct MD5Context * #endif ); static void MD5Transform( #ifdef __STDC__ word32 *, word32 * #endif ); static void byteReverse( #ifdef __STDC__ unsigned char *, unsigned #endif ); static int fits_md5_check( #ifdef __STDC__ char *, int #endif ); static char * fits_pretty_string( #ifdef __STDC__ char * #endif ); static char * fits_getvalue( #ifdef __STDC__ char * #endif ); static void usage( #ifdef __STDC__ void #endif ); /*---------------------------------------------------------------------------- Global variables ---------------------------------------------------------------------------*/ static char * pname = NULL ; static char prog_desc[] = "Compute/Update the DATAMD5 keyword/value" ; static int silent_process=0 ; /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /* Midas wrapper for the top MD5 function: a) declare the signature string `datamd5' as static to have access to it from the wrapper routine and remove the corresponding declaration inside `fits_md5_check' inside `fits_md5_check' at section if (!silent_process) { declare char. array texxt[80] and switch from printf to sprintf + SCTPUT b) call the original routine `fits_md5_check' to fill the static string which is then copied and passed back to the calling routine c) for VMS we have to isolate the call of sync() d) finally the "main" code in the end of the original file has to be taken out this section of code (Midas_md5() has to be inserted into the original code after the section: Global variables and before section: MD5 function code */ /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ static char datamd5[MD5HASHSZ+1]; int Midas_md5( file, upda, mymd5 ) char *file, *mymd5; int upda; { int stat; stat = fits_md5_check(file,upda); (void) strcpy(mymd5,datamd5); return stat; } /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ /*---------------------------------------------------------------------------- MD5 function code ---------------------------------------------------------------------------*/ /* * Reverse bytes in a 32-bit word. This code is harmless on little endian * machines. */ static void byteReverse( buf, longs) unsigned char *buf; unsigned longs; { word32 t; do { t = (word32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(word32 *) buf = t; buf += 4; } while (--longs); } /* * Start MD5 accumulation. Set bit count to 0 and buffer to MD5 * initialization constants. */ static void MD5Init( ctx ) struct MD5Context *ctx; { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ static void MD5Update( ctx, buf, len ) struct MD5Context *ctx; unsigned char *buf; unsigned len; { register word32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((word32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memmove(p, buf, len); return; } memmove(p, buf, t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (word32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memmove(ctx->in, buf, 64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (word32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memmove(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ static void MD5Final( digest, ctx ) unsigned char digest[16]; struct MD5Context *ctx; { unsigned int count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (word32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((word32 *) ctx->in)[14] = ctx->bits[0]; ((word32 *) ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, (word32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memmove(digest, ctx->buf, 16); memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ static void MD5Transform( buf, in ) word32 *buf, *in; { register word32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } /*---------------------------------------------------------------------------- FITS-related functions ---------------------------------------------------------------------------*/ /* Pretty-print a FITS string value */ static char * fits_pretty_string( s ) char * s; { static char pretty[FITSLINESZ+1] ; int i,j ; /* bulletproof */ if (s==NULL) return NULL ; pretty[0] = (char)0 ; if (s[0]!='\'') return s ; /* skip first quote */ i=1 ; j=0 ; /* trim left-side blanks */ while (s[i]==' ') { if (i==(int)strlen(s)) break ; i++ ; } if (i>=(int)(strlen(s)-1)) return pretty ; /* copy string, changing double quotes to single ones */ while (i<(int)strlen(s)) { if (s[i]=='\'') { i++ ; } pretty[j]=s[i]; i++ ; j++ ; } /* NULL-terminate the pretty string */ pretty[j+1]=(char)0; /* trim right-side blanks */ j = (int)strlen(pretty)-1; while (pretty[j]==' ') j-- ; pretty[j+1]=(char)0; return pretty; } /* Get the FITS value in a FITS card */ static char * fits_getvalue( line ) char *line; { static char value[FITSLINESZ+1] ; int i ; int from, to ; int inq ; if (line==NULL) { return NULL ; } memset(value, 0, FITSLINESZ+1); /* * Get past the keyword */ i=0 ; while (line[i]!='=' && iFITSLINESZ) { return NULL ; } i++ ; while (line[i]==' ' && iFITSLINESZ) { return NULL ; } from=i; /* * Now in the value section * Look for the first slash '/' outside of a string */ inq = 0 ; while (i=0) i-- ; if (i<0) { return NULL ; } to=i ; if (to\n" "options are:\n" "\t-u update MD5 keyword in the file: %s\n" "\t-s silent mode\n" "\n" "This utility computes the MD5 checksum of all data sections\n" "in a given FITS file, and compares it against the value\n" "declared in DATAMD5 if present. It can also update the value\n" "of this keyword (if present) with its own computed MD5 sum.\n" "\n" "\n", pname, FITSMD5KEY); exit(0) ; }