Return to the C Tips
MD5 in C language for AS400 from tan-tai HUYNH
The MD5 via RPG does not read the contents of a file. It only handles a characters string. Here is a complete MD5 checksum in C for AS400. It makes the same checksum as for a text file(read the contains of a file and hash the message digest). It includes an EBCDIC-ASCII conversion table. Text file sent by FTP or CFT to AS400 file. If the AS400 file has for example 160 characters : the text file must have the same length. Each record must be ended by a return carriage after the 160th characters Make a Md5checksum on this text file (read contains of the file). It will generate a message digest. When the text file is downloaded to AS400 file. Call the PFCSMD5 passing paramaters : '-a' conversion to ASCII '-lxxx' xxx is number characters of the file (e.g 160 --> '-l160') Name of the database to check The whole procedure looks like this : call PFCSMD5 parm('-a' '-l160' file160) It will calculate the MD5 signature. This MD5 signature must match the one generated from the original text file. The AS400 program simulates the return carriage values (ASCII hex x'0A' and x'0D') because MD5 checksum on Windows platform does it. The output MD5 signature is in the file name 'MD5OUT' normally created in QTEMP library. Each one can modify the script for his own purpose. It is an usefull program to check the integrity of a text file sent to AS400. Here is the coding of this program. It contains downloaded algorithm from web + an EBCDIC --> ASCII table + calculation of the return carriage value. Hope you'll insert in your tips and techniques. tan-tai HUYNH AS400 Systems Paris mailto:tan-tai.huynh@egg.com Source code starts here: /*-------------- EGG/France - EXPLOITATION------------------ - md5 par Yann GRAIGNIC - - tan-tai HUYNH - ---------------------------------------------------------- */ #include#include #include #include /* Bien degeu les variables globales mais tellement plus facile */ char DEBUG = '0'; char AS400 = '0'; int LONG = 0; char UNE_LIGNE = '0'; char OUTPUT = 'S'; /* S:std, F:file */ void ASCII_to_EBCDIC ( long, unsigned char *) ; void EBCDIC_to_ASCII ( long, unsigned char *) ; static unsigned char ASCII_translate_EBCDIC [ 256 ] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D, 0x7D, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xC0, 0x6A, 0xD0, 0xA1, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B } ; static unsigned char EBCDIC_translate_ASCII [ 256 ] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x2E, 0x2E, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x2E, 0x3F, 0x20, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, 0x26, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0x5E, 0x2D, 0x2F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x7C, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, 0x2E, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x2E, 0x2E, 0x2E, 0x5B, 0x2E, 0x2E, 0x2E, 0x23, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x5D, 0x2E, 0x2E, 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x5C, 0x2E, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E, 0x2E } ; /* ======================================================================= */ void EBCDIC_to_ASCII ( long buf_length, unsigned char *buf_addr) { int i; unsigned char temp; for (i=0; i < buf_length; i++) { temp = buf_addr[i]; buf_addr[i] = EBCDIC_translate_ASCII[temp]; } } /* ======================================================================= */ void ASCII_to_EBCDIC ( long buf_length, unsigned char *buf_addr) { int i; unsigned char temp; for (i=0; i < buf_length; i++) { temp = buf_addr[i]; buf_addr[i] = ASCII_translate_EBCDIC[temp]; } } /* Length of test block, number of test blocks. */ #define TEST_BLOCK_LEN 1000 #define TEST_BLOCK_COUNT 1000 #ifndef MD #define MD 5 #endif #define MD5 5 #if MD == MD5 #define MD_CTX MD5_CTX #define MDInit MD5Init #define MDUpdate MD5Update #define MDFinal MD5Final #endif /* POINTER defines a generic pointer type */ typedef unsigned char *POINTER; /* UINT2 defines a two byte word */ typedef unsigned short int UINT2; /* UINT4 defines a four byte word */ typedef unsigned long int UINT4; /* MD5.H - header file for MD5C.C */ /* MD5 context. */ typedef struct { UINT4 state[4]; /* state (ABCD) */ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ unsigned char buffer[64]; /* input buffer */ } MD5_CTX; void MD5Init ( MD5_CTX * ); void MD5Update ( MD5_CTX *, unsigned char *, unsigned int ); void MD5Final ( unsigned char [16], MD5_CTX * ); static void MD5Transform ( UINT4 [4], unsigned char [64]); static void Encode ( unsigned char *, UINT4 *, unsigned int ); static void Decode ( UINT4 *, unsigned char *, unsigned int ); static void MD5_memcpy ( POINTER, POINTER, unsigned int ); static void MD5_memset ( POINTER, int, unsigned int ); static void MDString ( char * ); static void MDTimeTrial ( void ); static void MDTestSuite ( void ); static void MDFile ( char * ); static void MDFilter ( void ); static void MDPrint ( unsigned char [16] ); /* Constants for MD5Transform routine. */ #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) /* ROTATE_LEFT rotates x left n bits. */ #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ #define FF(a, b, c, d, x, s, ac) { \ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } /* MD5 initialization. Begins an MD5 operation, writing a new context. ======================================================================= */ void MD5Init (MD5_CTX *context) { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; context->state[2] = 0x98badcfe; context->state[3] = 0x10325476; } /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. ======================================================================= */ void MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen) /* context */ /* input block */ /* length of input block */ { unsigned int i, index, partLen; if( DEBUG == 'D' ) { /* Mode debug */ unsigned char *copyinput; char c; copyinput = input; while ( c = *copyinput ++ ) { printf ( "\ndebug: \\%ld '%c'\n", (unsigned long int)c, c ); } } /* Compute number of bytes mod 64 */ index = (unsigned int)((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += ((UINT4)inputLen << 3)) < ((UINT4)inputLen << 3)) context->count[1]++; context->count[1] += ((UINT4)inputLen >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform (context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) MD5Transform (context->state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); } /* MD5 finalization. Ends an MD5 message-digest operation, writing the the message digest and zeroizing the context. ======================================================================= */ void MD5Final (unsigned char digest[16], MD5_CTX *context) /* message digest */ /* context */ { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ Encode (bits, context->count, 8); /* Pad out to 56 mod 64.*/ index = (unsigned int)((context->count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); MD5Update (context, PADDING, padLen); /* Append length (before padding) */ MD5Update (context, bits, 8); /* Store state in digest */ Encode (digest, context->state, 16); /* Zeroize sensitive information.*/ MD5_memset ((POINTER)context, 0, sizeof (*context)); } /* MD5 basic transformation. Transforms state based on block. ======================================================================= */ static void MD5Transform (UINT4 state[4], unsigned char block[64]) { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode (x, block, 64); /* Round 1 */ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ MD5_memset ((POINTER)x, 0, sizeof (x)); } /* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. ======================================================================= */ static void Encode (unsigned char *output, UINT4 *input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = (unsigned char)(input[i] & 0xff); output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); } } /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. ======================================================================= */ static void Decode (UINT4 *output, unsigned char *input, unsigned int len) { unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); } /* Note: Replace "for loop" with standard memcpy if possible. ======================================================================= */ static void MD5_memcpy (POINTER output, POINTER input, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } /* Note: Replace "for loop" with standard memset if possible. ======================================================================= */ static void MD5_memset (POINTER output, int value, unsigned int len) { unsigned int i; for (i = 0; i < len; i++) ((char *)output)[i] = (char)value; } /* Digests a string and prints the result. ======================================================================= */ static void MDString (char *string) { MD_CTX context; unsigned char digest[16]; unsigned int len = strlen (string); if (AS400 == 'A') { EBCDIC_to_ASCII ( sizeof ( string ), (unsigned char*)string ) ; } MDInit (&context); MDUpdate (&context, (unsigned char*)string, len); MDFinal (digest, &context); printf ("MD%d (\"%s\") = ", MD, string); MDPrint (digest); printf ("\n"); } /* Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks. ======================================================================= */ static void MDTimeTrial () { MD_CTX context; time_t endTime, startTime; unsigned char block[TEST_BLOCK_LEN], digest[16]; unsigned int i; printf ("MD%d time trial. Digesting %d %d-byte blocks ...", MD, TEST_BLOCK_LEN, TEST_BLOCK_COUNT); /* Initialize block */ for (i = 0; i < TEST_BLOCK_LEN; i++) block[i] = (unsigned char)(i & 0xff); /* Start timer */ time (&startTime); /* Digest blocks */ MDInit (&context); for (i = 0; i < TEST_BLOCK_COUNT; i++) MDUpdate (&context, block, TEST_BLOCK_LEN); MDFinal (digest, &context); /* Stop timer */ time (&endTime); printf (" done\n"); printf ("Digest = "); MDPrint (digest); printf ("\nTime = %ld seconds\n", (long)(endTime-startTime)); printf ("Speed = %ld bytes/second\n", (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime)); } /* Digests a reference suite of strings and prints the results. ======================================================================= */ static void MDTestSuite () { char buf1[256], buf2[256], buf3[256], buf4[256] ; char buf5[256], buf6[256], buf7[256] ; strcpy (buf1, ""); strcpy (buf2, "a"); strcpy (buf3, "abc"); strcpy (buf4, "message digest"); strcpy (buf5, "abcdefghijklmnopqrstuvwxyz"); strcpy (buf6, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); strcpy (buf7, "1234567890123456789012345678901234567890\ 1234567890123456789012345678901234567890"); if (AS400 == 'A') { EBCDIC_to_ASCII ( sizeof ( buf1 ), (unsigned char*)buf1 ) ; EBCDIC_to_ASCII ( sizeof ( buf2 ), (unsigned char*)buf2 ) ; EBCDIC_to_ASCII ( sizeof ( buf3 ), (unsigned char*)buf3 ) ; EBCDIC_to_ASCII ( sizeof ( buf4 ), (unsigned char*)buf4 ) ; EBCDIC_to_ASCII ( sizeof ( buf5 ), (unsigned char*)buf5 ) ; EBCDIC_to_ASCII ( sizeof ( buf6 ), (unsigned char*)buf6 ) ; EBCDIC_to_ASCII ( sizeof ( buf7 ), (unsigned char*)buf7 ) ; } printf ("MD%d test suite:\n", MD); MDString (buf1); MDString (buf2); MDString (buf3); MDString (buf4); MDString (buf5); MDString (buf6); MDString (buf7); } /* Digests a file and prints the result. ======================================================================= */ static void MDFile (char *filename) { FILE *file; FILE *ofile; MD_CTX context; int len; int nb_car_x; long ind1, ind2=0; unsigned char buffer[1024], buffer2[1024], digest[16]; unsigned char *Pointeur_buffer; long int l_read; if ((file = fopen (filename, "rb")) == NULL) printf ("%s can't be opened\n", filename); else { MDInit (&context); if (LONG != 0 ) l_read = LONG; else l_read = 1024; while (len = fread (buffer, 1, l_read, file)) { nb_car_x=0; if (AS400 == 'A') EBCDIC_to_ASCII ( sizeof ( buffer ), (unsigned char*)buffer ) ; if (LONG != 0 && (len+2) < sizeof(buffer) ) { /* insertion d'un caract?re CR (13 d?cimal = 15 octal = 0D hex) et LF (10 d?cimal = 12 octal = 0A hex) */ buffer[len] ='\15'; buffer[len+1]='\12'; buffer[len+2]='\0'; len+=2; } /* gestion de la mise ? plat d'un fichier */ /* pour siluler sur un PC, le calcul de la MD5 */ /* du m?me fichier apr?s transfert sur AS400 */ if (UNE_LIGNE == '1'){ ind2=0; nb_car_x=0; for (ind1=0; ind1 < len; ind1++ ) { if ( buffer[ind1] != '\15' && buffer[ind1] != '\12' ) { buffer2[ind2++] = buffer[ind1]; } else { nb_car_x++; } } Pointeur_buffer = buffer2; } else Pointeur_buffer = buffer; MDUpdate (&context, Pointeur_buffer, len-nb_car_x); } MDFinal (digest, &context); fclose (file); if (OUTPUT == 'F') { /* Ecriture de la clef calcul?e dans le fichier md5out*/ if ((ofile = fopen("md5out", "w")) == NULL) printf ("%s can't be opened\n", filename); else { int i; for (i = 0; i < 16; i++) fprintf (ofile, "%02x", digest[i]); fflush (ofile); fclose (ofile); } } else { /* printf ("MD%d (%s) = ", MD, filename); */ MDPrint (digest); /*printf ("\n");*/ } } } /* Digests the standard input and prints the result. ======================================================================= */ static void MDFilter () { MD_CTX context; int len; unsigned char buffer[16], digest[16]; MDInit (&context); while (len = fread (buffer, 1, 16, stdin)){ if (AS400 == 'A') EBCDIC_to_ASCII ( sizeof ( buffer ), (unsigned char*)buffer ) ; MDUpdate (&context, buffer, len); } MDFinal (digest, &context); MDPrint (digest); printf ("\n"); } /* Prints a message digest in hexadecimal. ======================================================================= */ static void MDPrint (unsigned char digest[16]) { unsigned int i; for (i = 0; i < 16; i++) printf ("%02x", digest[i]); } /* Prints a message digest in hexadecimal. ======================================================================= */ static void MDHelp () { printf ("-------------- EGG/France - EXPLOITATION------------------\n"); printf ("- md5 par Yann GRAIGNIC pour Tan-Tai Huynh -\n"); printf ("----------------------------------------------------------\n"); printf ("Options:\n"); printf (" -a : EBCDIC to ASCII convertion (reserved for AS400 usage)\n"); printf (" output is made into the file \"md5out\"\n"); printf (" -lxxx : xxx is the length of a line. The programm simulates\n"); printf (" a Carriage Return and Line Feed characters at the and\n"); printf (" of each fixed length line in order to evaluate the \n"); printf (" same md5 key as it should be on a PC\n"); printf (" -1 : On a PC, exclude CR/LF from the treatment in order to\n"); printf (" simulate the AS400 md5 key\ (on a file with fixed length lines\n"); printf (" -sString: String is the digests string\n"); printf (" filename : name of the digests file\n"); printf ("\nExamples:\n"); printf (" PC : md5 file160.dat\n"); printf (" AS400: md5 -a -l160 file160.dat\n\n"); printf (" PC : md5 -1 file160.dat\n"); printf (" AS400: md5 -a file160.dat\n\n"); printf (" AS400: md5 -a -sABCDEF\n"); printf (" PC : md5 -sABCDEF\n"); } /* Main driver. ======================================================================= Arguments (may be any combination): -d - mode debug -a - mode AS400 conversion EBCDIC-ASCII et sorite dans le fichier md5out plutot que sur la sortie standard -lxxx - longueur d'enregistrement fixe de xxx caract?res. injection artificielle de caract?re CR LF pour calculer une clef md5 sur AS400 identique ? celle calcul?e sur PC Cette option ne s'applique que dans le cas d'un fichier de longueur fixe -1 - Sur PC, supprime les CR et LF du calcul de la clef md5 pour simuler la clef qui sera calcul?e nativement sur AS400 (sous r?serve que le fichier aie des enregistrements de longueur fixe) -sstring - digests string -t - runs time trial -x - runs test script filename - digests file (none) - digests standard input */ int main (int argc, char *argv[]) { int i; if (argc > 1) for (i = 1; i < argc; i++) if (argv[i][0] == '-' && argv[i][1] == 's') MDString (argv[i] + 2); else if (argv[i][0] == '-' && argv[i][1] == 'l' && argc > i) LONG = atoi( argv[i] + 2 ); /* longueur fixe d'un enregistrement*/ else if (strcmp (argv[i], "-d") == 0) DEBUG='D'; else if (strcmp (argv[i], "-a") == 0){ AS400='A'; OUTPUT='F'; } else if (strcmp (argv[i], "-1") == 0) UNE_LIGNE='1'; else if (strcmp (argv[i], "-o") == 0) OUTPUT='F'; else if (strcmp (argv[i], "-t") == 0) MDTimeTrial (); else if (strcmp (argv[i], "-x") == 0) MDTestSuite (); else if ((strcmp (argv[i], "-h") == 0)||(strcmp(argv[i], "-help") == 0)) MDHelp (); else MDFile (argv[i]); else MDFilter (); return (0); }
[report a broken link by clicking here]