🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

1 total messages Started by Peter Gutmann pgut1 Fri, 07 Aug 1992 04:40
MDC (Message Digest Cipher)
#440
Author: Peter Gutmann pgut1
Date: Fri, 07 Aug 1992 04:40
978 lines
33597 bytes
The following code is a means of turning one-way hash functions into a 
secret-key cipher run in CFB mode.  The cipher runs virtually as fast as 
the hash function, and is as secure as the hash function (in fact it should 
be more secure - hash functions can be "broken" by finding a collision, 
whereas the cipher requires the reversing of the function).

The code below uses the MD5 message digest algorithm, with the Mysterious 
Constants replaced with key-dependant values.  Normally the constants are 
defined as:

>      In step i, the additive constant is the integer part of
>      4294967296 times abs(sin(i)), where i is in radians.

The cipher, called MDC (Message Digest Cipher), simply uses constants 
derived from a user-supplied key instead.  The key setup is basically the 
same as that used in my NSEA cipher code, with the Mysterious Constants and 
IV being generated by running MD5 over a buffer containing the user key, 
with the MD5 initial value being set to the salt.  These are then 
substituted for the standard MD5 constants to create the MDC function.

I need to look more closely at the exact security of this cipher - until 
then I thought I'd distribute it in case anyone else cares to comment.  As 
usual, the code is placed in the public domain (MD5 has already been made 
PD by it's originators).

Compile it with 'gcc md5.c mdc.c mdcmain.c -o mdc' - tested under DOS, OS/2,
and Ultrix.  Comments to pgut1@cs.aukuni.ac.nz.

-------------------------- Cut here with chainsaw ----------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./md5.c`
then
echo "writing ./md5.c"
cat > ./md5.c << '\End\Of\Shar\'
/****************************************************************************
*																			*
*	Implementation RSA Data Security, Inc. MD5 Message-Digest Algorithm		*
*	Created 2/17/90 RLR, revised 1/91 SRD,AJ,BSK,JT Reference C Version		*
*	  Copyright (C) 1990, RSA Data Security, Inc. All rights reserved		*
*																			*
****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include "md5.h"

/* To form the message digest for a message M, initialize a context buffer
   mdContext using MD5Init(); call MD5Update() on mdContext and M; and call
   MD5Final() on mdContext.  The message digest is now in
   mdContext->digest[ 0 ... 15 ] */

/****************************************************************************
*																			*
*							The MD5 Transformation							*
*																			*
****************************************************************************/

/* 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,shiftAmt,magicConst) \
	{ \
	A += F( B, C, D ) + X + magicConst; \
	A = ROTATE_LEFT( A, shiftAmt ); \
	A += B; \
	}

#define GG(A,B,C,D,X,shiftAmt,magicConst) \
	{ \
	A += G( B, C, D ) + X + magicConst; \
	A = ROTATE_LEFT( A, shiftAmt ); \
	A += B; \
	}

#define HH(A,B,C,D,X,shiftAmt,magicConst) \
	{ \
	A += H( B, C, D ) + X + magicConst; \
	A = ROTATE_LEFT( A, shiftAmt ); \
	A += B; \
	}

#define II(A,B,C,D,X,shiftAmt,magicConst) \
	{ \
	A += I( B, C, D ) + X + magicConst; \
	A = ROTATE_LEFT( A, shiftAmt ); \
	A += B; \
	}

/* Round 1 shift amounts */

#define S11	7
#define S12	12
#define S13	17
#define S14	22

/* Round 2 shift amounts */

#define S21 5
#define S22 9
#define S23 14
#define S24 20

/* Round 3 shift amounts */

#define S31 4
#define S32 11
#define S33 16
#define S34 23

/* Round 4 shift amounts */

#define S41 6
#define S42 10
#define S43 15
#define S44 21

/* The Mysterious Constants used in the MD5 transformation */

static LONG md5const[] = { 3614090360L, 3905402710L,  606105819L, 3250441966L,
						   4118548399L, 1200080426L, 2821735955L, 4249261313L,
						   1770035416L, 2336552879L, 4294925233L, 2304563134L,
						   1804603682L, 4254626195L, 2792965006L, 1236535329L,
						   4129170786L, 3225465664L,  643717713L, 3921069994L,
						   3593408605L,   38016083L, 3634488961L, 3889429448L,
							568446438L, 3275163606L, 4107603335L, 1163531501L,
						   2850285829L, 4243563512L, 1735328473L, 2368359562L,
						   4294588738L, 2272392833L, 1839030562L, 4259657740L,
						   2763975236L, 1272893353L, 4139469664L, 3200236656L,
							681279174L, 3936430074L, 3572445317L,   76029189L,
						   3654602809L, 3873151461L,  530742520L, 3299628645L,
						   4096336452L, 1126891415L, 2878612391L, 4237533241L,
						   1700485571L, 2399980690L, 4293915773L, 2240044497L,
						   1873313359L, 4264355552L, 2734768916L, 1309151649L,
						   4149444226L, 3174756917L,  718787259L, 3951481745L };
/* Storage for the Mysterious Constants (either md5const or user-defined) */

#define NO_CONST	64

LONG mConst[ NO_CONST ];

/* Basic MD5 step. Transforms buf based on in.  Note that if the Mysterious
   Constants are arranged backwards in little-endian order and decrypted with
   the DES they produce OCCULT MESSAGES! */

#if defined( IRIX ) || defined( ULTRIX ) || defined( __TSC__ )

/* MD5Transform is split into its component rounds since many optimizers
   choke on the grand unified version */

static void MD5TransformRound1( LONG *A, LONG *B, LONG *C, LONG *D, LONG *in )
	{
	/* Round 1 */
	FF( *A, *B, *C, *D, in[  0 ], S11, mConst[  0 ] );	/*  1 */
	FF( *D, *A, *B, *C, in[  1 ], S12, mConst[  1 ] );	/*  2 */
	FF( *C, *D, *A, *B, in[  2 ], S13, mConst[  2 ] );	/*  3 */
	FF( *B, *C, *D, *A, in[  3 ], S14, mConst[  3 ] );	/*  4 */
	FF( *A, *B, *C, *D, in[  4 ], S11, mConst[  4 ] );	/*  5 */
	FF( *D, *A, *B, *C, in[  5 ], S12, mConst[  5 ] );	/*  6 */
	FF( *C, *D, *A, *B, in[  6 ], S13, mConst[  6 ] );	/*  7 */
	FF( *B, *C, *D, *A, in[  7 ], S14, mConst[  7 ] );	/*  8 */
	FF( *A, *B, *C, *D, in[  8 ], S11, mConst[  8 ] );	/*  9 */
	FF( *D, *A, *B, *C, in[  9 ], S12, mConst[  9 ] );	/* 10 */
	FF( *C, *D, *A, *B, in[ 10 ], S13, mConst[ 10 ] );	/* 11 */
	FF( *B, *C, *D, *A, in[ 11 ], S14, mConst[ 11 ] );	/* 12 */
	FF( *A, *B, *C, *D, in[ 12 ], S11, mConst[ 12 ] );	/* 13 */
	FF( *D, *A, *B, *C, in[ 13 ], S12, mConst[ 13 ] );	/* 14 */
	FF( *C, *D, *A, *B, in[ 14 ], S13, mConst[ 14 ] );	/* 15 */
	FF( *B, *C, *D, *A, in[ 15 ], S14, mConst[ 15 ] );	/* 16 */
	}

static void MD5TransformRound2( LONG *A, LONG *B, LONG *C, LONG *D, LONG *in )
	{
	/* Round 2 */
	GG( *A, *B, *C, *D, in[  1 ], S21, mConst[ 16 ] );	/* 17 */
	GG( *D, *A, *B, *C, in[  6 ], S22, mConst[ 17 ] );	/* 18 */
	GG( *C, *D, *A, *B, in[ 11 ], S23, mConst[ 18 ] );	/* 19 */
	GG( *B, *C, *D, *A, in[  0 ], S24, mConst[ 19 ] );	/* 20 */
	GG( *A, *B, *C, *D, in[  5 ], S21, mConst[ 20 ] );	/* 21 */
	GG( *D, *A, *B, *C, in[ 10 ], S22, mConst[ 21 ] );	/* 22 */
	GG( *C, *D, *A, *B, in[ 15 ], S23, mConst[ 22 ] );	/* 23 */
	GG( *B, *C, *D, *A, in[  4 ], S24, mConst[ 23 ] );	/* 24 */
	GG( *A, *B, *C, *D, in[  9 ], S21, mConst[ 24 ] );	/* 25 */
	GG( *D, *A, *B, *C, in[ 14 ], S22, mConst[ 25 ] );	/* 26 */
	GG( *C, *D, *A, *B, in[  3 ], S23, mConst[ 26 ] );	/* 27 */
	GG( *B, *C, *D, *A, in[  8 ], S24, mConst[ 27 ] );	/* 28 */
	GG( *A, *B, *C, *D, in[ 13 ], S21, mConst[ 28 ] );	/* 29 */
	GG( *D, *A, *B, *C, in[  2 ], S22, mConst[ 29 ] );	/* 30 */
	GG( *C, *D, *A, *B, in[  7 ], S23, mConst[ 30 ] );	/* 31 */
	GG( *B, *C, *D, *A, in[ 12 ], S24, mConst[ 31 ] );	/* 32 */
	}

static void MD5TransformRound3( LONG *A, LONG *B, LONG *C, LONG *D, LONG *in )
	{
	/* Round 3 */
	HH( *A, *B, *C, *D, in[  5 ], S31, mConst[ 32 ] );	/* 33 */
	HH( *D, *A, *B, *C, in[  8 ], S32, mConst[ 33 ] );	/* 34 */
	HH( *C, *D, *A, *B, in[ 11 ], S33, mConst[ 34 ] );	/* 35 */
	HH( *B, *C, *D, *A, in[ 14 ], S34, mConst[ 35 ] );	/* 36 */
	HH( *A, *B, *C, *D, in[  1 ], S31, mConst[ 36 ] );	/* 37 */
	HH( *D, *A, *B, *C, in[  4 ], S32, mConst[ 37 ] );	/* 38 */
	HH( *C, *D, *A, *B, in[  7 ], S33, mConst[ 38 ] );	/* 39 */
	HH( *B, *C, *D, *A, in[ 10 ], S34, mConst[ 39 ] );	/* 40 */
	HH( *A, *B, *C, *D, in[ 13 ], S31, mConst[ 40 ] );	/* 41 */
	HH( *D, *A, *B, *C, in[  0 ], S32, mConst[ 41 ] );	/* 42 */
	HH( *C, *D, *A, *B, in[  3 ], S33, mConst[ 42 ] );	/* 43 */
	HH( *B, *C, *D, *A, in[  6 ], S34, mConst[ 43 ] );	/* 44 */
	HH( *A, *B, *C, *D, in[  9 ], S31, mConst[ 44 ] );	/* 45 */
	HH( *D, *A, *B, *C, in[ 12 ], S32, mConst[ 45 ] );	/* 46 */
	HH( *C, *D, *A, *B, in[ 15 ], S33, mConst[ 46 ] );	/* 47 */
	HH( *B, *C, *D, *A, in[  2 ], S34, mConst[ 47 ] );	/* 48 */
	}

static void MD5TransformRound4( LONG *A, LONG *B, LONG *C, LONG *D, LONG *in )
	{
	/* Round 4 */
	II( *A, *B, *C, *D, in[  0 ], S41, mConst[ 48 ] );	/* 49 */
	II( *D, *A, *B, *C, in[  7 ], S42, mConst[ 49 ] );	/* 50 */
	II( *C, *D, *A, *B, in[ 14 ], S43, mConst[ 50 ] );	/* 51 */
	II( *B, *C, *D, *A, in[  5 ], S44, mConst[ 51 ] );	/* 52 */
	II( *A, *B, *C, *D, in[ 12 ], S41, mConst[ 52 ] );	/* 53 */
	II( *D, *A, *B, *C, in[  3 ], S42, mConst[ 53 ] );	/* 54 */
	II( *C, *D, *A, *B, in[ 10 ], S43, mConst[ 54 ] );	/* 55 */
	II( *B, *C, *D, *A, in[  1 ], S44, mConst[ 55 ] );	/* 56 */
	II( *A, *B, *C, *D, in[  8 ], S41, mConst[ 56 ] );	/* 57 */
	II( *D, *A, *B, *C, in[ 15 ], S42, mConst[ 57 ] );	/* 58 */
	II( *C, *D, *A, *B, in[  6 ], S43, mConst[ 58 ] );	/* 59 */
	II( *B, *C, *D, *A, in[ 13 ], S44, mConst[ 59 ] );	/* 60 */
	II( *A, *B, *C, *D, in[  4 ], S41, mConst[ 60 ] );	/* 61 */
	II( *D, *A, *B, *C, in[ 11 ], S42, mConst[ 61 ] );	/* 62 */
	II( *C, *D, *A, *B, in[  2 ], S43, mConst[ 62 ] );	/* 63 */
	II( *B, *C, *D, *A, in[  9 ], S44, mConst[ 63 ] );	/* 64 */
	}

void MD5Transform( LONG *buf, LONG *in )
	{
	LONG A = buf[ 0 ], B = buf[ 1 ], C = buf[ 2 ], D = buf[ 3 ];

	MD5TransformRound1 (&A, &B, &C, &D, in);
	MD5TransformRound2 (&A, &B, &C, &D, in);
	MD5TransformRound3 (&A, &B, &C, &D, in);
	MD5TransformRound4 (&A, &B, &C, &D, in);

	buf[ 0 ] += A;
	buf[ 1 ] += B;
	buf[ 2 ] += C;
	buf[ 3 ] += D;
	}

#else

void MD5Transform( LONG *buf, LONG *in )
	{
	LONG A = buf[ 0 ], B = buf[ 1 ], C = buf[ 2 ], D = buf[ 3 ];

	/* Round 1 */
	FF( A, B, C, D, in[  0 ], S11, mConst[  0 ] );	/*  1 */
	FF( D, A, B, C, in[  1 ], S12, mConst[  1 ] );	/*  2 */
	FF( C, D, A, B, in[  2 ], S13, mConst[  2 ] );	/*  3 */
	FF( B, C, D, A, in[  3 ], S14, mConst[  3 ] );	/*  4 */
	FF( A, B, C, D, in[  4 ], S11, mConst[  4 ] );	/*  5 */
	FF( D, A, B, C, in[  5 ], S12, mConst[  5 ] );	/*  6 */
	FF( C, D, A, B, in[  6 ], S13, mConst[  6 ] );	/*  7 */
	FF( B, C, D, A, in[  7 ], S14, mConst[  7 ] );	/*  8 */
	FF( A, B, C, D, in[  8 ], S11, mConst[  8 ] );	/*  9 */
	FF( D, A, B, C, in[  9 ], S12, mConst[  9 ] );	/* 10 */
	FF( C, D, A, B, in[ 10 ], S13, mConst[ 10 ] );	/* 11 */
	FF( B, C, D, A, in[ 11 ], S14, mConst[ 11 ] );	/* 12 */
	FF( A, B, C, D, in[ 12 ], S11, mConst[ 12 ] );	/* 13 */
	FF( D, A, B, C, in[ 13 ], S12, mConst[ 13 ] );	/* 14 */
	FF( C, D, A, B, in[ 14 ], S13, mConst[ 14 ] );	/* 15 */
	FF( B, C, D, A, in[ 15 ], S14, mConst[ 15 ] );	/* 16 */

	/* Round 2 */
	GG( A, B, C, D, in[  1 ], S21, mConst[ 16 ] );	/* 17 */
	GG( D, A, B, C, in[  6 ], S22, mConst[ 17 ] );	/* 18 */
	GG( C, D, A, B, in[ 11 ], S23, mConst[ 18 ] );	/* 19 */
	GG( B, C, D, A, in[  0 ], S24, mConst[ 19 ] );	/* 20 */
	GG( A, B, C, D, in[  5 ], S21, mConst[ 20 ] );	/* 21 */
	GG( D, A, B, C, in[ 10 ], S22, mConst[ 21 ] );	/* 22 */
	GG( C, D, A, B, in[ 15 ], S23, mConst[ 22 ] );	/* 23 */
	GG( B, C, D, A, in[  4 ], S24, mConst[ 23 ] );	/* 24 */
	GG( A, B, C, D, in[  9 ], S21, mConst[ 24 ] );	/* 25 */
	GG( D, A, B, C, in[ 14 ], S22, mConst[ 25 ] );	/* 26 */
	GG( C, D, A, B, in[  3 ], S23, mConst[ 26 ] );	/* 27 */
	GG( B, C, D, A, in[  8 ], S24, mConst[ 27 ] );	/* 28 */
	GG( A, B, C, D, in[ 13 ], S21, mConst[ 28 ] );	/* 29 */
	GG( D, A, B, C, in[  2 ], S22, mConst[ 29 ] );	/* 30 */
	GG( C, D, A, B, in[  7 ], S23, mConst[ 30 ] );	/* 31 */
	GG( B, C, D, A, in[ 12 ], S24, mConst[ 31 ] );	/* 32 */

	/* Round 3 */
	HH( A, B, C, D, in[  5 ], S31, mConst[ 32 ] );	/* 33 */
	HH( D, A, B, C, in[  8 ], S32, mConst[ 33 ] );	/* 34 */
	HH( C, D, A, B, in[ 11 ], S33, mConst[ 34 ] );	/* 35 */
	HH( B, C, D, A, in[ 14 ], S34, mConst[ 35 ] );	/* 36 */
	HH( A, B, C, D, in[  1 ], S31, mConst[ 36 ] );	/* 37 */
	HH( D, A, B, C, in[  4 ], S32, mConst[ 37 ] );	/* 38 */
	HH( C, D, A, B, in[  7 ], S33, mConst[ 38 ] );	/* 39 */
	HH( B, C, D, A, in[ 10 ], S34, mConst[ 39 ] );	/* 40 */
	HH( A, B, C, D, in[ 13 ], S31, mConst[ 40 ] );	/* 41 */
	HH( D, A, B, C, in[  0 ], S32, mConst[ 41 ] );	/* 42 */
	HH( C, D, A, B, in[  3 ], S33, mConst[ 42 ] );	/* 43 */
	HH( B, C, D, A, in[  6 ], S34, mConst[ 43 ] );	/* 44 */
	HH( A, B, C, D, in[  9 ], S31, mConst[ 44 ] );	/* 45 */
	HH( D, A, B, C, in[ 12 ], S32, mConst[ 45 ] );	/* 46 */
	HH( C, D, A, B, in[ 15 ], S33, mConst[ 46 ] );	/* 47 */
	HH( B, C, D, A, in[  2 ], S34, mConst[ 47 ] );	/* 48 */

	/* Round 4 */
	II( A, B, C, D, in[  0 ], S41, mConst[ 48 ] );	/* 49 */
	II( D, A, B, C, in[  7 ], S42, mConst[ 49 ] );	/* 50 */
	II( C, D, A, B, in[ 14 ], S43, mConst[ 50 ] );	/* 51 */
	II( B, C, D, A, in[  5 ], S44, mConst[ 51 ] );	/* 52 */
	II( A, B, C, D, in[ 12 ], S41, mConst[ 52 ] );	/* 53 */
	II( D, A, B, C, in[  3 ], S42, mConst[ 53 ] );	/* 54 */
	II( C, D, A, B, in[ 10 ], S43, mConst[ 54 ] );	/* 55 */
	II( B, C, D, A, in[  1 ], S44, mConst[ 55 ] );	/* 56 */
	II( A, B, C, D, in[  8 ], S41, mConst[ 56 ] );	/* 57 */
	II( D, A, B, C, in[ 15 ], S42, mConst[ 57 ] );	/* 58 */
	II( C, D, A, B, in[  6 ], S43, mConst[ 58 ] );	/* 59 */
	II( B, C, D, A, in[ 13 ], S44, mConst[ 59 ] );	/* 60 */
	II( A, B, C, D, in[  4 ], S41, mConst[ 60 ] );	/* 61 */
	II( D, A, B, C, in[ 11 ], S42, mConst[ 61 ] );	/* 62 */
	II( C, D, A, B, in[  2 ], S43, mConst[ 62 ] );	/* 63 */
	II( B, C, D, A, in[  9 ], S44, mConst[ 63 ] );	/* 64 */

	buf[ 0 ] += A;
	buf[ 1 ] += B;
	buf[ 2 ] += C;
	buf[ 3 ] += D;
	}
#endif /* IRIX || ULTRIX || __TSC__ */

/****************************************************************************
*																			*
*							MD5 Support Routines							*
*																			*
****************************************************************************/

/* The routine MD5SetConst sets the Mysterious Constants to either the
   standard MD5 ones or to a user-defined set for MDC */

static BOOLEAN isMD5const = FALSE;

void MD5SetConst( BYTE *buffer )
	{
	if( buffer == NULL )
		{
		/* If the constants are already set up, don't bother re-setting them */
		if( !isMD5const )
			{
			memcpy( mConst, md5const, NO_CONST * sizeof( LONG ) );
			isMD5const = TRUE;
			}
		}
	else
		{
		memcpy( mConst, buffer, NO_CONST * sizeof( LONG ) );
		isMD5const = FALSE;
		}
	}

/* The routine MD5Init initializes the message-digest context mdContext. All
   fields are set to zero */

void MD5Init( MD5_CTX *mdContext )
	{
	mdContext->i[ 0 ] = mdContext->i[ 1 ] = 0L;

	/* Load magic initialization constants */
	mdContext->buf[ 0 ] = 0x67452301L;
	mdContext->buf[ 1 ] = 0xEFCDAB89L;
	mdContext->buf[ 2 ] = 0x98BADCFEL;
	mdContext->buf[ 3 ] = 0x10325476L;

	/* Set up the Mysterious Constants if necessary */
	if( !isMD5const )
		MD5SetConst( NULL );
	}

/* The routine MD5Update updates the message-digest context to account for
   the presence of each of the characters inBuf[ 0 .. inLen-1 ] in the
   message whose digest is being computed.  This is an optimized version
   which assumes that the buffer is a multiple of MD5_BLOCKSIZE bytes long */

#ifdef __MSDOS__

void MD5Update( MD5_CTX *mdContext, BYTE *buffer, unsigned int noBytes )
	{
	int bufIndex = 0;

	/* Update number of bits */
	if( ( mdContext->i[ 0 ] + ( ( LONG ) noBytes << 3 ) ) < mdContext->i[ 0 ] )
		mdContext->i[ 1 ]++;	/* Carry from low to high bitCount */
	mdContext->i[ 0 ] += ( ( LONG ) noBytes << 3 );
	mdContext->i[ 1 ] += ( ( LONG ) noBytes >> 29 );

	/* Process data in MD5_BLOCKSIZE chunks */
	while( noBytes >= MD5_BLOCKSIZE )
		{
		MD5Transform( mdContext->buf, ( LONG * ) ( buffer + bufIndex ) );
		bufIndex += MD5_BLOCKSIZE;
		noBytes -= MD5_BLOCKSIZE;
		}

	/* Handle any remaining bytes of data.  This should only happen once
	   on the final lot of data */
	memcpy( mdContext->in, buffer + bufIndex, noBytes );
	}

/* The routine MD5Final terminates the message-digest computation and ends
   with the desired message digest in mdContext->digest[ 0 ... 15 ] */

void MD5Final( MD5_CTX *mdContext )
	{
	int mdi, padLen;
	LONG lowBitcount = mdContext->i[ 0 ], highBitcount = mdContext->i[ 1 ];

	/* Compute number of bytes mod 64 */
	mdi = ( int ) ( ( mdContext->i[ 0 ] >> 3 ) & 0x3F );
	padLen = ( mdi < 56 ) ? ( 56 - mdi ) : ( 120 - mdi );

	/* Update number of bits */
	if( ( mdContext->i[ 0 ] + ( ( LONG ) padLen << 3 ) ) < mdContext->i[ 0 ] )
		mdContext->i[ 1 ]++;	/* Carry from low to high bitCount */
	mdContext->i[ 0 ] += ( ( LONG ) padLen << 3 );
	mdContext->i[ 1 ] += ( ( LONG ) padLen >> 29 );

	/* Pad out to 56 mod 64 */
	if( padLen )
		{
		/* Set first char of padding to 0x80 */
		mdContext->in[ mdi ] = 0x80;

		if( mdi >= 56 )
			{
			/* Two lots of padding:  Pad first block to 64 bytes, then fill
			   next block with 56 bytes */
			memset( &mdContext->in[ mdi + 1 ], 0, 63 - mdi );
			MD5Transform( mdContext->buf, ( LONG * ) mdContext->in );
			memset( mdContext->in, 0, 56 );
			}
		else
			/* Pad block to 56 bytes */
			memset( &mdContext->in[ mdi + 1 ], 0, padLen - 1 );
		}
	if( mdi + padLen == 64 )
		MD5Transform( mdContext->buf, ( LONG * ) mdContext->in );

	/* Append length in bits and transform */
	( ( LONG * ) mdContext->in )[ 14 ] = lowBitcount;
	( ( LONG * ) mdContext->in )[ 15 ] = highBitcount;

	MD5Transform( mdContext->buf, ( LONG * ) mdContext->in );

	/* Store buffer in digest */
	memcpy( mdContext->digest, mdContext->buf, 16 );
	}

#else

void MD5Update( MD5_CTX *mdContext, BYTE *inBuf, unsigned int inLen )
	{
	int mdi;
	LONG in[ 16 ];
	unsigned int i, ii;

	/* Compute number of bytes mod 64 */
	mdi = ( int ) ( ( mdContext->i[ 0 ] >> 3 ) & 0x3F );

	/* Update number of bits */
	if( ( mdContext->i[ 0 ] + ( ( LONG ) inLen << 3 ) ) < mdContext->i[ 0 ] )
		mdContext->i[ 1 ]++;	/* Carry from low to high bitCount */
	mdContext->i[ 0 ] += ( ( LONG ) inLen << 3 );
	mdContext->i[ 1 ] += ( ( LONG ) inLen >> 29 );

	while( inLen-- )
		{
		/* Add new character to buffer, increment mdi */
		mdContext->in[ mdi++ ] = *inBuf++;

		/* Transform if necessary */
		if( mdi == 0x40 )
			{
			for( i = 0, ii = 0; i < 16; i++, ii += 4 )
				in[ i ] = ( ( ( LONG ) mdContext->in[ ii + 3 ] ) << 24 ) | \
						  ( ( ( LONG ) mdContext->in[ ii + 2 ] ) << 16 ) | \
						  ( ( ( LONG ) mdContext->in[ ii + 1 ] ) << 8 ) | \
						  ( ( LONG ) mdContext->in[ ii ] );
			MD5Transform( mdContext->buf, in );
			mdi = 0;
			}
		}
	}

/* The routine MD5Final terminates the message-digest computation and ends
   with the desired message digest in mdContext->digest[ 0 ... 15 ] */

void MD5Final( MD5_CTX *mdContext )
	{
	int mdi, padLen;
	BYTE padding[ 64 ];
	unsigned int i, ii;
	LONG in[ 16 ];

	/* Save number of bits */
	in[ 14 ] = mdContext->i[ 0 ];
	in[ 15 ] = mdContext->i[ 1 ];

	/* Compute number of bytes mod 64 */
	mdi = ( int ) ( ( mdContext->i[ 0 ] >> 3 ) & 0x3F );

	/* Pad out to 56 mod 64 */
	padLen = ( mdi < 56 ) ? ( 56 - mdi ) : ( 120 - mdi );
	padding[ 0 ] = 0x80;
	memset( padding + 1, 0, padLen - 1 );
	MD5Update( mdContext, padding, padLen );

	/* Append length in bits and transform */
	for( i = 0, ii = 0; i < 14; i++, ii += 4 )
		in[ i ] = ( ( ( LONG ) mdContext->in[ ii + 3 ] ) << 24 ) | \
				  ( ( ( LONG ) mdContext->in[ ii + 2 ] ) << 16 ) | \
				  ( ( ( LONG ) mdContext->in[ ii + 1 ] ) << 8 ) | \
				  ( ( LONG ) mdContext->in[ ii ] );
	MD5Transform( mdContext->buf, in );

	/* Store buffer in digest */
	for( i = 0, ii = 0; i < 4; i++, ii += 4 )
		{
		mdContext->digest[ ii ] = ( BYTE ) ( mdContext->buf[ i ] & 0xFF );
		mdContext->digest[ ii + 1 ] = ( BYTE ) ( ( mdContext->buf[ i ] >> 8 ) & 0xFF );
		mdContext->digest[ ii + 2 ] = ( BYTE ) ( ( mdContext->buf[ i ] >> 16 ) & 0xFF );
		mdContext->digest[ ii + 3 ] = ( BYTE ) ( ( mdContext->buf[ i ] >> 24 ) & 0xFF ); /**/
		}
	}
#endif /* !__MSDOS__ */
\End\Of\Shar\
else
  echo "will not over write ./md5.c"
fi
if [ `wc -c ./md5.c | awk '{printf $1}'` -ne 18675 ]
then
echo `wc -c ./md5.c | awk '{print "Got " $1 ", Expected " 18675}'`
fi
if `test ! -s ./md5.h`
then
echo "writing ./md5.h"
cat > ./md5.h << '\End\Of\Shar\'
/* The following are system-dependant: Unsigned 8, 16, 32-bit quantities.*/

typedef unsigned char       BYTE;
typedef unsigned short      WORD;
typedef unsigned long       LONG;

typedef unsigned char		BOOLEAN;

/* Useful defines */

#define ERROR	-1
#define OK		0

#define TRUE	1
#define FALSE	0

/****************************************************************************
*																			*
*			RSA Data Security, Inc. MD5 Message-Digest Algorithm			*
*  Created 2/17/90 RLR, revised 12/27/90 SRD,AJ,BSK,JT Reference C version	*
*	Revised (for MD5) RLR 4/27/91: G modified to have y&~z instead of y&z,	*
* FF, GG, HH modified to add in last register done, access pattern: round 2 *
*	works mod 5, round 3 works mod 3, distinct additive constant for each	*
*					step round 4 added, working mod 7						*
*																			*
****************************************************************************/

/* Data structure for MD5 computation */

typedef struct {
			   LONG i[ 2 ];			/* Number of bits handled mod 2^64 */
			   LONG buf[ 4 ];		/* Scratch buffer */
			   BYTE in[ 64 ];		/* Input buffer */
			   BYTE digest[ 16 ];	/* Actual digest after MD5Final() call */
			   } MD5_CTX;

/* The size of an MD5 data block */

#define MD5_BLOCKSIZE	64

/* Message digest functions */

void MD5SetConst( BYTE *buffer );
void MD5Init( MD5_CTX *mdContext );
void MD5Update( MD5_CTX *mdContext, BYTE *buffer, unsigned int noBytes );
void MD5Final( MD5_CTX *mdContext );
\End\Of\Shar\
else
  echo "will not over write ./md5.h"
fi
if [ `wc -c ./md5.h | awk '{printf $1}'` -ne 1475 ]
then
echo `wc -c ./md5.h | awk '{print "Got " $1 ", Expected " 1475}'`
fi
if `test ! -s ./mdc.c`
then
echo "writing ./mdc.c"
cat > ./mdc.c << '\End\Of\Shar\'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mdc.h"

/* Information needed in CFB mode:  The IV, the encrypted IV, and the count
   of bytes already processed in the current block */

BYTE iv[ BLOCKSIZE ];			/* CFB initialization vector */
BYTE temp[ BLOCKSIZE ];			/* Encrypted IV */
int ivCount;					/* Count of bytes used in block */

/* The number of rounds in the MD5 transformation */

#define NO_ROUNDS		64

/****************************************************************************
*																			*
*				MDC Key Generation and Encryption Routines					*
*																			*
****************************************************************************/

/* The Mysterious Constants and IV are generated by running MD5 over a
   buffer containing the user key, with the MD5 initial value being set to
   the salt.  These are then substituted for the standard MD5 constants to
   create the MDC function.  The buffer looks as follows:

   [ Key length: 16 bits ] [ Key: 2032 bits ]

   These 2048 bits are used for the MDC constants - the salt is the MD5
   initial value */

void initKey( BYTE *key, int keyLength, const BYTE *salt )
	{
	BYTE keyData[ NO_ROUNDS * sizeof( LONG ) ];

	/* Copy the salt and key information into the key data buffer */
	memset( keyData, 0, NO_ROUNDS * sizeof( LONG ) );
	keyData[ 0 ] = ( BYTE ) ( keyLength >> 8 );
	keyData[ 1 ] = ( BYTE ) keyLength;
	memcpy( keyData + sizeof( WORD ), key, keyLength );

	/* Set up the IV intermediate with the salt */
	memcpy( temp, salt, SALT_SIZE );
	memcpy( temp + SALT_SIZE, salt, SALT_SIZE );

	/* Set the Mysterious Constants to the MD5 values and "encrypt" it.
	   Note that the act of encryption also sets up the IV */
	MD5SetConst( NULL );
	encryptCFB( keyData, NO_ROUNDS * sizeof( LONG ) );

	/* Set the Mysterious Constants to the generated values */
	MD5SetConst( keyData );

	/* Finally, wipe the keyData */
	memset( keyData, 0, sizeof( keyData ) );
	}

/* Get a salt value for the IV.  It doesn't matter much what it is, as
   long as it's completely different for each call */

void getSalt( BYTE *salt )
	{
	static BOOLEAN initialised = FALSE;
	static BYTE randomSalt[ BLOCKSIZE ];

	if( !initialised )
		{
		/* Seed the data with a value which is guaranteed to be different
		   each time (unless the entire program is rerun more than twice a
		   second, which is doubtful) */
		MD5SetConst( NULL );
		memset( randomSalt, 0, BLOCKSIZE );
		time( ( time_t * ) &randomSalt );
		initialised = TRUE;
		}

	/* Shuffle the bits.  It doesn't matter if we're using MD5 or MDC
	   constants here since all we want to do is shuffle them */
	encrypt( randomSalt, randomSalt );
	memcpy( salt, randomSalt, SALT_SIZE );
	}

/****************************************************************************
*																			*
*						Cipher Feedback Mode Routines						*
*																			*
****************************************************************************/

/* Encrypt data in CFB mode */

void encryptCFB( BYTE *buffer, int noBytes )
	{
	int bytesToUse, i;

	if( ivCount )
		{
		/* Use any material left in the encrypted IV */
		bytesToUse = BLOCKSIZE - ivCount;
		if( noBytes < bytesToUse )
			bytesToUse = noBytes;
		for( i = 0; i < bytesToUse; i++ )
			buffer[ i ] ^= temp[ i + ivCount ];
		memcpy( iv + ivCount, buffer, bytesToUse );
		noBytes -= bytesToUse;
		buffer += bytesToUse;
		ivCount += bytesToUse;
		}

	while( noBytes )
		{
		ivCount = ( noBytes > BLOCKSIZE ) ? BLOCKSIZE : noBytes;

		/* Encrypt the IV */
		encrypt( iv, temp );

		/* XOR the buffer contents with the encrypted IV */
		for( i = 0; i < ivCount; i++ )
			buffer[ i ] ^= temp[ i ];

		/* Shift ciphertext into IV */
		memcpy( iv, buffer, ivCount );

		/* Move on to next block of data */
		noBytes -= ivCount;
		buffer += ivCount;
		}
	}

/* Decrypt data in CFB mode */

void decryptCFB( BYTE *buffer, int noBytes )
	{
	int bytesToUse, i;

	if( ivCount )
		{
		/* Use any material left in the encrypted IV */
		bytesToUse = BLOCKSIZE - ivCount;
		if( noBytes < bytesToUse )
			bytesToUse = noBytes;
		memcpy( iv + ivCount, buffer, bytesToUse );
		for( i = 0; i < bytesToUse; i++ )
			buffer[ i ] ^= temp[ i + ivCount ];
		noBytes -= bytesToUse;
		buffer += bytesToUse;
		ivCount += bytesToUse;
		}

	while( noBytes )
		{
		ivCount = ( noBytes > BLOCKSIZE ) ? BLOCKSIZE : noBytes;

		/* Encrypt the IV */
		encrypt( iv, temp );

		/* Shift ciphertext into IV */
		memcpy( iv, buffer, ivCount );

		/* XOR the buffer contents with the encrypted IV */
		for( i = 0; i < ivCount; i++ )
			buffer[ i ] ^= temp[ i ];

		/* Move on to next block of data */
		noBytes -= ivCount;
		buffer += ivCount;
		}
	}
\End\Of\Shar\
else
  echo "will not over write ./mdc.c"
fi
if [ `wc -c ./mdc.c | awk '{printf $1}'` -ne 4718 ]
then
echo `wc -c ./mdc.c | awk '{print "Got " $1 ", Expected " 4718}'`
fi
if `test ! -s ./mdc.h`
then
echo "writing ./mdc.h"
cat > ./mdc.h << '\End\Of\Shar\'
#include "md5.h"

/* The block size (in bytes) */

#define BLOCKSIZE	16

/* The default salt value used to seed the cipher in initKey().  Changing
   this for each file precludes the use of precomputed encrypted data for
   very fast checking against known plaintext */

#define DEFAULT_SALT	"\0\0\0\0\0\0\0\0"

#define SALT_SIZE		8

/* Define for simple block encryption */

void MD5Transform( LONG *buffer, LONG *in );

#define encrypt(inData,outData)		MD5Transform( ( LONG * ) outData, ( LONG * ) inData )

/* Prototypes for functions in MDC.C */

void initKey( BYTE *key, int keyLength, const BYTE *salt );
void encryptCFB( BYTE *buffer, int length );
void decryptCFB( BYTE *buffer, int length );
void getSalt( BYTE *salt );
\End\Of\Shar\
else
  echo "will not over write ./mdc.h"
fi
if [ `wc -c ./mdc.h | awk '{printf $1}'` -ne 729 ]
then
echo `wc -c ./mdc.h | awk '{print "Got " $1 ", Expected " 729}'`
fi
if `test ! -s ./mdcmain.c`
then
echo "writing ./mdcmain.c"
cat > ./mdcmain.c << '\End\Of\Shar\'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mdc.h"

/* The encryption password lengths.  A minimum length of 8 bytes provides a
   reasonable level of security, as well as ensuring that the salt used to
   initialise the LFSR used to generate the S-boxes covers the full possible
   range of values */

#define MIN_KEYLENGTH	8
#define MAX_KEYLENGTH	80		/* Any reasonable value will do */

/****************************************************************************
*																			*
*		Sample Program:  File Encryption/Decryption using CFB mode			*
*																			*
****************************************************************************/

#define MDC_ID		"MDC "

void main( const int argc, const char *argv[] )
	{
#if !defined( TIME_TRIAL ) && !defined( SETUP_TRIAL )
	FILE *inFilePtr, *outFilePtr;
#endif /* !( TIME_TRIAL || SETUP_TRIAL ) */
#ifndef SETUP_TRIAL
	BYTE buffer[ 512 ];
#endif /* !SETUP_TRIAL */
	char key[ MAX_KEYLENGTH + 1 ];
	int count = 1;
	BYTE salt[ SALT_SIZE ];

#if !defined( TIME_TRIAL ) && !defined( SETUP_TRIAL )
	if( argc == 4 )
		{
		if( ( inFilePtr = fopen( argv[ 2 ], "rb" ) ) == NULL )
			{
			perror( argv[ 2 ] );
			exit( ERROR );
			}
		if( ( outFilePtr = fopen( argv[ 3 ], "wb" ) ) == NULL )
			{
			perror( argv[ 3 ] );
			exit( ERROR );
			}
		}
	else
		{
		puts( "Usage: mdc e|d <infile> <outfile>" );
		puts( "           e to encrypt data" );
		puts( "           d to decrypt data" );
		exit( ERROR );
		}
#endif /* !( TIME_TRIAL || SETUP_TRIAL ) */

#if !defined( TIME_TRIAL ) && !defined( SETUP_TRIAL )
	/* Read/write the header information */
	if( *argv[ 1 ] == 'e' )
		{
		getSalt( salt );
		fwrite( MDC_ID, 1, 4, outFilePtr );
		fwrite( salt, 1, SALT_SIZE, outFilePtr );
		}
	else
		{
		if( fread( buffer, 1, 4 + SALT_SIZE, inFilePtr ) != 4 + SALT_SIZE || \
			memcmp( buffer, MDC_ID, 4 ) )
			{
			puts( "Not an MDC-encrypted file" );
			exit( ERROR );
			}
		memcpy( salt, buffer + 4, SALT_SIZE );
		}
#endif /* !( TIME_TRIAL || SETUP_TRIAL ) */

	/* Set up the S-Boxes */
#if defined( TIME_TRIAL ) || defined( SETUP_TRIAL )
	strcpy( key, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" );
#else
	*key = '\0';
	while( strlen( key ) < MIN_KEYLENGTH )
		{
		printf( "Key (%d-%d chars): ", MIN_KEYLENGTH, MAX_KEYLENGTH );
		fgets( key, MAX_KEYLENGTH, stdin );	/* Should use something better */
		key[ strlen( key ) - 1 ] = '\0';	/* Stomp '\n' */
		putchar( '\n' );
		}
#endif /* TIME_TRIAL || SETUP_TRIAL */
#ifdef SETUP_TRIAL
	puts( "Performing 1000 key setup operations" );
	for( count = 0; count < 1000; count++ )
		initKey( ( BYTE * ) key, strlen( key ), salt );
	puts( "Done" );
#else
	initKey( ( BYTE * ) key, strlen( key ), salt );
#endif /* SETUP_TRIAL */

	/* We're done with the key, zap it */
	memset( key, 0, MAX_KEYLENGTH + 1 );

#if defined( TIME_TRIAL )
	/* Encrypt 1MB of data in 512-byte blocks */
	memset( buffer, 0, 512 );
	puts( "Encrypting 20480 x 512-byte blocks (10MB)..." );
	for( count = 0; count < 20480; count++ )
		encryptCFB( buffer, 512 );
	puts( "Done" );
#elif !defined( SETUP_TRIAL )

	/* Grovel through a file en/decrypting it */
	while( count )
		{
		/* Read in a block of chars */
		count = fread( buffer, 1, 512, inFilePtr );

		/* Encrypt/decrypt data block */
		if( *argv[ 1 ] == 'e' )
			encryptCFB( buffer, count );
		else
			decryptCFB( buffer, count );

		/* Write out block and reset counter */
		fwrite( buffer, 1, count, outFilePtr );
		}

	fclose( inFilePtr );
	fclose( outFilePtr );
#endif /* TIME_TRIAL */
	}
\End\Of\Shar\
else
  echo "will not over write ./mdcmain.c"
fi
if [ `wc -c ./mdcmain.c | awk '{printf $1}'` -ne 3577 ]
then
echo `wc -c ./mdcmain.c | awk '{print "Got " $1 ", Expected " 3577}'`
fi
echo "Finished archive 1 of 1"
exit
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads