pgpdes3.c

来自「著名的加密软件的应用于电子邮件中」· C语言 代码 · 共 607 行 · 第 1/2 页

C
607
字号
		leftt = ((leftt >> 1) | (leftt << 31));
		t = (leftt ^ right) & 0x55555555L;
		leftt ^= t;
		right ^= t;
		right = ((right >> 1) | (right << 31));

/* The main encryption loop */
iterate = 3;
goto Des0;
		do {
				t = right;
				right = leftt;
				leftt = t;
Des0: 	
			for (round = 0; round < 8; round++) {
					s = (right & 0xfcfcfcfc) ^ keys[0];
					t = (((right >> 28) | (right << 4)) & 0xfcfcfcfc)
						^ keys[1];
					leftt ^= *(word32 *)((char *)SP0+( s & 0x3fc))
					^ *(word32 *)((char *)SP0+((s >> 8 ) & 0x3fc))
					^ *(word32 *)((char *)SP0+((s >> 16) & 0x3fc))
					^ *(word32 *)((char *)SP0+((s >> 24) & 0x0fc))
					^ *(word32 *)((char *)SP1+( t & 0x3fc))
					^ *(word32 *)((char *)SP1+((t >> 8 ) & 0x3fc))
					^ *(word32 *)((char *)SP1+((t >> 16) & 0x3fc))
					^ *(word32 *)((char *)SP1+((t >> 24) & 0x0fc));

				s = (leftt & 0xfcfcfcfc) ^ keys[2];
				t = (((leftt >> 28) | (leftt << 4)) & 0xfcfcfcfc)
					^ keys[3];
				right ^= *(word32 *)((char *)SP0+( s & 0x3fc))
				^ *(word32 *)((char *)SP0+((s >> 8 ) & 0x3fc))
				^ *(word32 *)((char *)SP0+((s >> 16) & 0x3fc))
				^ *(word32 *)((char *)SP0+((s >> 24) & 0x0fc))
				^ *(word32 *)((char *)SP1+( t & 0x3fc))
				^ *(word32 *)((char *)SP1+((t >> 8 ) & 0x3fc))
				^ *(word32 *)((char *)SP1+((t >> 16) & 0x3fc))
				^ *(word32 *)((char *)SP1+((t >> 24) & 0x0fc));
				keys += 4;
		}
} while (--iterate);

/* Inverse IP */
leftt = ((leftt << 1) | (leftt >> 31));
		t = (leftt ^ right) & 0x55555555L;
		leftt ^= t;
		right ^= t;
		right = ((right << 1) | (right >> 31));
		t = ((leftt >> 8) ^ right) & 0x00ff00ffL;
		right ^= t;
		leftt ^= (t << 8);
		t = ((leftt >> 2) ^ right) & 0x33333333L;
		right ^= t;
		leftt ^= (t << 2);
		t = ((right >> 16) ^ leftt) & 0x0000ffffL;
		leftt ^= t;
		right ^= (t << 16);
		t = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
		leftt ^= t;
		right ^= (t << 4);

outblock[0] = (byte)(right >> 24);
outblock[1] = (byte)(right >> 16);
outblock[2] = (byte)(right >> 8);
outblock[3] = (byte)(right );
outblock[4] = (byte)(leftt >> 24);
outblock[5] = (byte)(leftt >> 16);
outblock[6] = (byte)(leftt >> 8);
outblock[7] = (byte)(leftt	);
return;
}

/*** Externally called functions ***/

static void
des3Key (void *priv, byte const *key)
{
		/* EDE triple-DES */
		deskey (key , 0, (word32 *)priv);
		deskey (key+ 8, 1, (word32 *)priv + DES_KEYWORDS);
		deskey (key+16, 0, (word32 *)priv + 2*DES_KEYWORDS);
		/* To decrypt, do DED with the keys in the opposite order */

/* Keep a copy of the unscheduled key for Washing purposes */
memcpy ((byte *)priv + DES3_KEYBYTES, key, DES3_USERKEYBYTES);
}

static void
des3Encrypt (void *priv, byte const *in, byte *out)
{
	des3DES (in, out, (word32 const *)priv);
}

/*
* Do one 64-bit step of a Triple Tandem Davies-Meyer hash computation.
* The hash buffer is 32 bytes long and contains H (0..7), then G (8..15),
* then F (16..23), then 8 bytes of scratch space. The buf is 8 bytes long.
* xkey is a temporary key schedule buffer, with room for *4* DES
* keys, i.e. 4*DESKEYWORDS words.
* This and the extra data in the hash buffer are allocated by the
* caller to reduce the amount of buffer-wiping we have to do.
* (It's only called from des3Wash, so the interface can be a bit
* specialized.)
*
* What is triple Tandem Davies-Meyer? Well, it's a simple
* extension of (double) Tandem Davies-Meyer, which goes
* like this, to hash (H,G) with message block M:
* H' = E_{G,M}(H)
* G' = E_{M,H'}(G)
* H ^= H'
* G ^= G'
*
* The extension, to a triple-width hash (H,G,F) is just:
* H' = E_{F,G,M}(H)
* G' = E_{F,M,H'}(G)
* F' = E_(M,G',H'}(F)
* H ^= H'
* G ^= G'
* F ^= F'
*
* This schedules individual DES keys to avoid having to copy the
* bits to contiguous buffers and to re-use the already-scheduled
* leys. F and H' are used twice in the same spot, and M is scheduled
* twice for encryption.
*/
static void
des3StepTripleDM(byte *hash, byte const *buf, word32 *xkey)
{
		int i;

		/* Set up triple-DES with F, G, M */
		deskey(hash+16, 0, xkey);
		deskey(hash+ 8, 1, xkey + DES_KEYWORDS);
		deskey(buf, 0, xkey + 2*DES_KEYWORDS);

		/* Compute H' and new H */
		des3DES(hash, hash+24, xkey);
		for (i = 0; i < 8; i++)
			hash[i] ^= hash[i+24];
		/* Copy encryption schedule for M out of harm's way */
		memcpy(xkey +3*DES_KEYWORDS, xkey+2*DES_KEYWORDS, DES_KEYBYTES);

		/* Set up triple-DES with F, M, H' */
		deskey(buf, 1, xkey + DES_KEYWORDS);
		deskey(hash+24, 0, xkey + 2*DES_KEYWORDS);

		/* Compute G' and new G */
		des3DES(hash+8, hash+24, xkey);
		for (i = 0; i < 8; i++)
			hash[i+8] ^= hash[i+24];

		/* Set up triple-DES with M, G', H' */
		memcpy(xkey, xkey+3*DES_KEYWORDS, DES_KEYBYTES);
		deskey(hash+24, 1, xkey + DES_KEYWORDS);

		/* Compute F' and new F */
		des3DES(hash+16, hash+24, xkey);
		for (i = 0; i < 8; i++)
			hash[i+16] ^= hash[i+24];
}

/*
* Munge the key of the CipherContext based on the supplied bytes.
* This is for random-number generation, so the exact technique is
* unimportant, but it happens to use the current key as the
* IV for computing a triple-Tandem Davies-Meyer hash of the bytes,
* and uses the output as the new key.
*/
static void
des3Wash(void *priv, byte const *buf, unsigned len)
{
		unsigned i;
		byte temp[8];
		word32 xkey[4*DES_KEYWORDS];

		/* The key is used as the IV for the hash */

		/* Do the initial blocks of the hash */
		i = len;
		while (i >= 8) {
				des3StepTripleDM((byte *)priv+DES3_KEYBYTES, buf, xkey);
				buf += 8;
				i -= 8;
		}
		/*
		* At the end, we do Damgard-Merkle strengthening, just like
		* MD5 or SHA. Pad with 0x80 then 0 bytes to 6 mod 8, then
		* add the length. We use a 16-bit length in bytes instead
		* of a 64-bit length in bits, but that is cryptographically
		* irrelevant, as long as the length is there.
		*/
		/* Do the first partial block - i <= 7 */
		memcpy(temp, buf, i);
		temp[i++] = 0x80;
		if (i > 6) {
			memset(temp+i, 0, 8-i);
			des3StepTripleDM((byte *)priv+DES3_KEYBYTES, temp, xkey);
			i = 0;
		}
		memset(temp+i, 0, 6-i);
		temp[6] = (byte)(len >> 8);
		temp[7] = (byte)len;
		des3StepTripleDM((byte *)priv+DES3_KEYBYTES, temp, xkey);

		/* Re-schedule the key */
		deskey ((byte *)priv+DES3_KEYBYTES , 0,
		(word32 *)priv);
		deskey ((byte *)priv+DES3_KEYBYTES+ 8, 1,
		(word32 *)priv + DES_KEYWORDS);
		deskey ((byte *)priv+DES3_KEYBYTES+16, 0,
		(word32 *)priv + 2*DES_KEYWORDS);

		memset(temp, 0, sizeof(temp));
		memset(xkey, 0, sizeof(xkey));
}

/*
* Define a struct Cipher for the generic cipher. This is the only real
* exported symbol -- everything else can be static, since everything
* is referenced through function pointers!
*/
struct PgpCipher const cipher3DES = {
		"3DES",
		PGP_CIPHER_3DES,
		8,			/* Blocksize */
		DES3_USERKEYBYTES,	/* Keysize */
		DES3_KEYBYTES + DES3_USERKEYBYTES,
		alignof(word32),
		des3Key,
		des3Encrypt,
		des3Wash
};

#if UNITTEST
/* Validation set:
*
* Double-length key, single-length plaintext -
* Key : 0123 4567 89ab cdef fedc ba98 7654 3210
* Plain : 0123 4567 89ab cde7
* Cipher : 7f1d 0a77 826b 8aff
*
***************************************************/

#include <stdio.h>
#include <time.h>

void
printhex(unsigned char const *buf, unsigned len)
{
		while (len--) {
				printf("%02X", *buf++);
				putchar(len ? ' ' : '\n');
		}
}

int
main(void)
{
		unsigned i;
		clock_t c;

		static unsigned char const key[24] = {
			0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
			0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
			0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
		};
		static unsigned char const plain[8] = {
			0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7
		};
		static unsigned char const cipher[8] = {
			0x7f, 0x1d, 0x0a, 0x77, 0x82, 0x6b, 0x8a, 0xff
		};
		unsigned char out[8];

		word32 xkey[DES3_KEYWORDS+6];

		des3Key(xkey, key);
		des3Encrypt(xkey, plain, out);
		printf("   key=");
		printhex(key, 24);
		printf(" plain=");
		printhex(plain, 8);
		printf("   out=");
		printhex(out, 8);
		printf("cipher=");
		printhex(cipher, 8);
		if (memcmp(cipher, out, 8) == 0)
			printf("Test successful\n");
		else
			printf("### ERROR\n");

		printf("Doing test encryptions\n");
		c = clock();
		for (i = 0; i < 100000; i++)
			des3Encrypt(xkey, out, out);
		c = clock() - c;
		printf("%u encryptions required %lu ticks\n",
			i, (unsigned long)c);
		return 0;
}

#endif

⌨️ 快捷键说明

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