⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 idea.c

📁 IDEA加密算法属于数据块加密算法(Block Cipher)类。IDEA使用长度为128bit的密钥
💻 C
字号:
/*
 *	idea.c - C source code for IDEA block cipher.
 *	IDEA (International Data Encryption Algorithm), formerly known as 
 *	IPES (Improved Proposed Encryption Standard).
 *	Algorithm developed by Xuejia Lai and James L. Massey, of ETH Zurich.
 *
 *	CFB functions added.  Random number routines added.
 *
 *	There are two adjustments that can be made to this code to
 *	speed it up.  Defaults may be used for PCs.  Only the -DIDEA32
 *	pays off significantly if selectively set or not set.
 *	Experiment to see what works best for your machine.
 *
 *	Multiplication: default is inline, -DAVOID_JUMPS uses a
 *		different version that does not do any conditional
 *		jumps (a few percent worse on a SPARC), while
 *		-DSMALL_CACHE takes it out of line to stay
 *		within a small on-chip code cache.
 *	Variables: normally, 16-bit variables are used, but some
 *		machines (notably RISCs) do not have 16-bit registers,
 *		so they do a great deal of masking.  -DIDEA32 uses "int"
 *		register variables and masks explicitly only where
 *		necessary.  On a SPARC, for example, this boosts
 *		performace by 30%.
 *
 *	The IDEA block cipher uses a 64-bit block size, and a 128-bit key 
 *	size.  It breaks the 64-bit cipher block into four 16-bit words
 *	because all of the primitive inner operations are done with 16-bit 
 *	arithmetic.  It likewise breaks the 128-bit cipher key into eight 
 *	16-bit words.
 *
 *	This code runs on arrays of bytes by taking pairs in big-endian
 *	order to make the 16-bit words that IDEA uses internally.  This
 *	produces the same result regardless of the BYTE order of the
 *	native CPU.
 */

#include <stdio.h>
#include <string.h>
#include <io.h>
#include <process.h>
#include <time.h>
#include "idea.h"

#define IDEA32 YES // define IDEA32
#define HIGHFIRST // be sure to define this when using IDEA32

#ifdef IDEA32	/* Use >16-bit temporaries */
	#define LOW16(x) ((x) & 0xFFFF)
	typedef unsigned int UINT16;	/* at LEAST 16 bits, maybe more */
#else
	#define LOW16(x) (x)	/* this is only ever applied to UINT16's */
	typedef WORD16 UINT16;
#endif

/*
 *	Multiplication, modulo (2**16)+1
 * Note that this code is structured on the assumption that
 * untaken branches are cheaper than taken branches, and the
 * compiler doesn't schedule branches.
 */
#ifdef SMALL_CACHE
static UINT16 mul(register UINT16 a, register UINT16 b)
{
	register WORD32 p;

	p = (WORD32)a * b;
	if (p)
	{
		b = LOW16(p);
		a = p>>16;
		return (b - a) + (b < a);
	}
	else if (a)
	{
		return 1-b;
	}
	else
	{
		return 1-a;
	}
} /* mul */
#endif /* SMALL_CACHE */

/*
 * Compute the multiplicative inverse of x, modulo 65537, using Euclid's
 * algorithm. It is unrolled twice to avoid swapping the registers each
 * iteration, and some subtracts of t have been changed to adds.
 */
static UINT16 mulInv(UINT16 x)     
{
	UINT16 t0, t1;
	UINT16 q, y;

	if( x <= 1 )
		return x;	/* 0 and 1 are self-inverse */
	t1 = 0x10001L / x;	/* Since x >= 2, this fits into 16 bits */
	y = 0x10001L % x;
	if( y == 1 )
		return LOW16( 1 - t1 );
	t0 = 1;
	do
	{
		q = x / y;
		x = x % y;
		t0 += q * t1;
		if (x == 1)
			return t0;
		q = y / x;
		y = y % x;
		t1 += q * t0;
	} while( y != 1 );

	return LOW16( 1 - t1 );
} /* mukInv */

/*
 * Expand a 128-bit user key to a working encryption key EK
 */
static void ideaExpandKey(BYTE const *UserKey, WORD16 *EK)
{
	int i,j;

	for( j=0; j<8; j++ )
	{
		EK[j] = (UserKey[0]<<8) + UserKey[1];
		UserKey += 2;
	}

	for (i=0; j < IDEAKEYLEN; j++)
	{
		i++;
		EK[i+7] = ( EK[i & 7] << 9 ) | ( EK[(i+1) & 7] >> 7 );
		EK += i & 8;
		i &= 7;
	}
} /* ideaExpandKey */

/*
 * Compute IDEA decryption key DK from an expanded IDEA encryption key EK
 * Note that the input and output may be the same.  Thus, the key is
 * inverted into an internal buffer, and then copied to the output.
 */
static void ideaInvertKey(WORD16 const *EK, WORD16 DK[IDEAKEYLEN])
{
	int i;
	UINT16 t1, t2, t3;
	WORD16 temp[IDEAKEYLEN];
	WORD16 *p = temp + IDEAKEYLEN;

	t1 = mulInv(*EK++);
	t2 = -*EK++;
	t3 = -*EK++;
	*--p = mulInv(*EK++);
	*--p = t3;
	*--p = t2;
	*--p = t1;

	for (i = 0; i < IDEAROUNDS-1; i++)
	{
		t1 = *EK++;
		*--p = *EK++;
		*--p = t1;

		t1 = mulInv(*EK++);
		t2 = -*EK++;
		t3 = -*EK++;
		*--p = mulInv(*EK++);
		*--p = t2;
		*--p = t3;
		*--p = t1;
	}

	t1 = *EK++;
	*--p = *EK++;
	*--p = t1;

	t1 = mulInv(*EK++);
	t2 = -*EK++;
	t3 = -*EK++;
	*--p = mulInv(*EK++);
	*--p = t3;
	*--p = t2;
	*--p = t1;

	/* Copy and destroy temp copy */
	memcpy(DK, temp, sizeof(temp));
	memset(temp, 0, sizeof(temp));
} /* ideaInvertKey */

/*
 * MUL(x,y) computes x = x*y, modulo 0x10001.  Requires two temps, 
 * t16 and t32.  x is modified, and must me a side-effect-free lvalue.
 * y may be anything, but unlike x, must be strictly 16 bits even if
 * LOW16() is #defined.
 * All of these are equivalent - see which is faster on your machine
 */
#ifdef SMALL_CACHE
	#define MUL(x,y) (x = mul(LOW16(x),y))
#else /* !SMALL_CACHE */
	#ifdef AVOID_JUMPS
		#define MUL(x,y) (x = LOW16(x-1), t16 = LOW16((y)-1), \
				t32 = (WORD32)x*t16 + x + t16 + 1, x = LOW16(t32), \
				t16 = t32>>16, x = (x-t16) + (x<t16) )
	#else /* !AVOID_JUMPS (default) */
		#define MUL(x,y) \
			( (t16 = (y)) ? \
				( (x=LOW16(x)) ? \
					t32 = (WORD32)x*t16, \
					x = LOW16(t32), \
					t16 = t32>>16, \
	 				x = (x-t16)+(x<t16) \
				: (x = 1-t16) ) \
			: (x = 1-x) )
	#endif
#endif

/*	IDEA encryption/decryption algorithm */
/* Note that in and out can be the same buffer */
static void ideaCipher(BYTE const (inbuf[8]), BYTE (outbuf[8]), WORD16 const *key)
{
	register UINT16 x1, x2, x3, x4, s2, s3;
	WORD16 *in, *out;
#ifndef SMALL_CACHE
	register UINT16 t16;	/* Temporaries needed by MUL macro */
	register WORD32 t32;
#endif
	int r = IDEAROUNDS;

	in = (WORD16 *)inbuf;
	x1 = *in++;  x2 = *in++;
	x3 = *in++;  x4 = *in;
#ifndef HIGHFIRST
	x1 = (x1 >>8) | (x1<<8);
	x2 = (x2 >>8) | (x2<<8);
	x3 = (x3 >>8) | (x3<<8);
	x4 = (x4 >>8) | (x4<<8);
#endif
	do
	{
		MUL(x1,*key++);
		x2 += *key++;
		x3 += *key++;
		MUL(x4, *key++);

		s3 = x3;
		x3 ^= x1;
		MUL(x3, *key++);
		s2 = x2;
		x2 ^= x4;
		x2 += x3;
		MUL(x2, *key++);
		x3 += x2;

		x1 ^= x2;  x4 ^= x3;

		x2 ^= s3;  x3 ^= s2;
	} while( --r );

	MUL(x1, *key++);
	x3 += *key++;
	x2 += *key++;
	MUL(x4, *key);

	out = (WORD16 *)outbuf;
#ifdef HIGHFIRST
	*out++ = x1;
	*out++ = x3;
	*out++ = x2;
	*out = x4;
#else /* !HIGHFIRST */
	*out++ = (x1 >>8) | (x1<<8);
	*out++ = (x3 >>8) | (x3<<8);
	*out++ = (x2 >>8) | (x2<<8);
	*out = (x4 >>8) | (x4<<8);
#endif
} /* ideaCipher */

/*************************************************************************/

void ideaCfbReinit(struct IdeaCfbContext *context, BYTE const *iv)
{
	if (iv)
		memcpy(context->iv, iv, 8);
	else
		memset(context->iv, 0, 8);
	context->bufleft = 0;
}

void ideaCfbInit(struct IdeaCfbContext *context, BYTE const (key[16]))
{
	ideaExpandKey(key, context->key);

	// set initial vector zero
	ideaCfbReinit(context,0);
}

void ideaCfbDestroy(struct IdeaCfbContext *context)
{
	memset(context, 0, sizeof(struct IdeaCfbContext));
}

/*
 * Encrypt a buffer of data, using IDEA in CFB mode.
 * There are more compact ways of writing this, but this is
 * written for speed.
 */
void ideaCfbEncrypt(struct IdeaCfbContext *context, BYTE const *src,
	       BYTE *dest, int count)
{
	int bufleft = context->bufleft;
	BYTE *bufptr = context->iv + 8-bufleft;

	/* If there are no more bytes to encrypt that there are bytes
	 * in the buffer, XOR them in and return.
	 */
	if (count <= bufleft)
	{
		context->bufleft = bufleft - count;
		while (count--)
		{
			*dest++ = *bufptr++ ^= *src++;
		}
		return;
	}
	count -= bufleft;

	/* Encrypt the first bufleft (0 to 7) bytes of the input by XOR
	 * with the last bufleft bytes in the iv buffer.
	 */
	while (bufleft--)
	{
		*dest++ = (*bufptr++ ^= *src++);
	}
	/* Encrypt middle blocks of the input by cranking the cipher,
	 * XORing 8-BYTE blocks, and repeating until the count
	 * is 8 or less.
	 */
	while (count > 8)
	{
		bufptr = context->iv;
		ideaCipher(bufptr, bufptr, context->key);
		bufleft = 8;
		count -= 8;
		do
		{
			*dest++ = (*bufptr++ ^= *src++);
		} while (--bufleft);
	}

	/* Do the last 1 to 8 bytes */
	bufptr = context->iv;
	ideaCipher(bufptr, bufptr, context->key);
	context->bufleft = 8-count;
	do
	{
		*dest++ = (*bufptr++ ^= *src++);
	} while (--count);
}

/*
 * Decrypt a buffer of data, using IDEA in CFB mode.
 * There are more compact ways of writing this, but this is
 * written for speed.
 */
void ideaCfbDecrypt(struct IdeaCfbContext *context, BYTE const *src,
	       BYTE *dest, int count)
{
	int bufleft = context->bufleft;
	static BYTE *bufptr;
	BYTE t;

	bufptr = context->iv + (8-bufleft);
	if (count <= bufleft)
	{
		context->bufleft = bufleft - count;
		while (count--)
		{
			t = *bufptr;
			*dest++ = t ^ (*bufptr++ = *src++);
		}
		return;
	}

	count -= bufleft;
	while (bufleft--)
	{
		t = *bufptr;
		*dest++ = t ^ (*bufptr++ = *src++);
	}

	while (count > 8)
	{
		bufptr = context->iv;
		ideaCipher(bufptr, bufptr, context->key);
		bufleft = 8;
		count -= 8;
		do
		{
			t = *bufptr;
			*dest++ = t ^ (*bufptr++ = *src++);
		} while (--bufleft);
	}

	bufptr = context->iv;
	ideaCipher(bufptr, bufptr, context->key);
	context->bufleft = 8-count;

	do
	{
		t = *bufptr;
		*dest++ = t ^ (*bufptr++ = *src++);
	} while (--count);
}

/********************************************************************/
/*
 * Initialize a cryptographic random-number generator.
 * key and seed should be arbitrary; timestamp should
 * be a current timestamp.
 */
void ideaRandInit( struct IdeaRandContext *context, BYTE const (key[16]),
	     BYTE const (seed[8]), WORD32 timestamp )
{
	int i;

	ideaExpandKey(key, context->key);
	context->bufleft = 0;
	memcpy(context->internalbuf, seed, 8);

	for (i = 0; i < 8; i++)
	{
		context->timestamp[i] = (BYTE)timestamp;
		timestamp >>= 8;
	}

	ideaCipher(context->timestamp, context->timestamp, context->key);
}

/*
 * Cryptographic pseudo-random-number generator, used for generating
 * session keys.
 * Much of the design comes from Appendix C of ANSI X9.17.
 */
BYTE ideaRandByte(struct IdeaRandContext *c)
{
	int i;

	if (!c->bufleft)
	{
		/* Compute next 8 bytes of output */
		for (i=0; i<8; i++)
			c->outbuf[i] = c->internalbuf[i] ^ c->timestamp[i];
		ideaCipher(c->outbuf, c->outbuf, c->key);

		/* Compute new seed vector */
		for (i=0; i<8; i++)
			c->internalbuf[i] = c->outbuf[i] ^ c->timestamp[i];
		ideaCipher(c->internalbuf, c->internalbuf, c->key);

		c->bufleft = 8;
	}
	return c->outbuf[--c->bufleft];
}

int EncryptFile( char *szSrcFile, char *szEncFile, BYTE *UserKey )
{
	FILE *fpIn, *fpOut;
	struct IdeaCfbContext cfbContext;
	char szBuffIn[KBYTES], szBuffOut[KBYTES];
	unsigned int nBlockLen;
	long nFileLen = 0;

	if( (fpIn = fopen(szSrcFile, "r+b")) == NULL )
	{
		printf("\nError opening input file %s\n", szSrcFile);
		return 1;
	}

	if( (fpOut = fopen(szEncFile, "w+b")) == NULL )
	{
		printf("\nError opening output file %s\n", szEncFile);
		return 1;
	}

	ideaCfbInit( &cfbContext, UserKey );

	nFileLen = filelength( fileno(fpIn) );
	fwrite( &nFileLen, sizeof(long), 1, fpOut );

	while( ( nBlockLen = fread( szBuffIn, 1, KBYTES, fpIn ) ) > 0 )
	{
		ideaCfbEncrypt( &cfbContext, szBuffIn, szBuffOut, nBlockLen );
		fwrite( szBuffOut, 1, nBlockLen, fpOut );

		if( feof(fpIn) )
		{
			break;
		}
	}

	ideaCfbDestroy( &cfbContext );
	fclose(fpIn);
	fclose(fpOut);

	return 0;
}

int DecryptFile( char *szSrcFile, char *EncFile, BYTE *UserKey )
{
	FILE *fpIn, *fpOut;
	struct IdeaCfbContext cfbContext;
	unsigned int nBlockLen;
	long nFileLen = 0;
	char szBuffIn[KBYTES], szBuffOut[KBYTES];

	if( (fpIn = fopen(szSrcFile, "r+b")) == NULL )
	{
		printf("\nError opening input file %s\n", szSrcFile);
		return 1;
	}

	if( (fpOut = fopen(EncFile, "w+b")) == NULL )
	{
		printf("\nError opening output file\n");
		return 1;
	}

	ideaCfbInit( &cfbContext, UserKey );

	fread( &nFileLen, sizeof(long), 1, fpIn );
	while( ( nBlockLen = fread( szBuffIn, 1, KBYTES, fpIn ) ) > 0 )
	{
		ideaCfbDecrypt( &cfbContext, szBuffIn, szBuffOut, nBlockLen );
		fwrite( szBuffOut, 1, nBlockLen, fpOut );
		if( feof(fpIn) )
		{
			break;
		}
	}

	ideaCfbDestroy( &cfbContext );
	fclose(fpIn);
	fclose(fpOut);

	return 0;
}

void GetUserKey(BYTE *UserKey, char *arg)
{
	unsigned int x;

	for ( x = 0; ( x < strlen(arg) ) && (x < IDEAKEYSIZE); x++ )
	{
		UserKey[x] = arg[x];
	}

	if( strlen(arg) > IDEAKEYSIZE ) printf( "\nONLY first %d characters of key used!\n", IDEAKEYSIZE );

	while( x < IDEAKEYSIZE )
	{
		UserKey[x++] = 0;
	}
}

int main(int argc, char **argv)
{
	BYTE UserKey[IDEAKEYSIZE];
	char szInFile[MAX_PATHLEN];
	char szOutFile[MAX_PATHLEN];
	int nMode;

	if( argc != 5 )
	{
		printf("\nUsage: idea [e|d[w]] key InFile OutFile\n");
		printf("  e=encode   d=decode   w=Overwrite file\n");
		printf("  NOTE: Key must be no longer than 8 characters long!!!\n");
		return 1;
	}

	if( argv[1][0] == 'e' || argv[1][0] == 'E' )
		nMode = 1;
	else if( argv[1][0] == 'd' || argv[1][0] == 'D' )
		nMode = 0;
	else
	{
		printf("\nUsage: idea [e|d] key InFile OutFile\n");
		printf("  e = encrypt d = decrypt w = Overwrite file\n");
		printf("  NOTE: Key must be no longer than 8 characters long!!!\n");
		exit(-1);
	}

	strcpy(szInFile, argv[3]);
	strcpy(szOutFile, argv[4]);

	GetUserKey( UserKey, argv[2] );

	if( nMode == 1 )
	{
		printf( "\nEncoding file %s   ", szInFile );

		EncryptFile( szInFile, szOutFile, UserKey );
	}
	else
	{
		printf( "\nDecoding file %s   ", szInFile );

		DecryptFile( szInFile, szOutFile, UserKey );
	}

	memset( UserKey, 0, sizeof(UserKey) );

	return 0;
}

/* end of idea.c */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -