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

📄 pgpcfb.c

📁 vc环境下的pgp源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	const void *		salt)
{
	PGPError	err	= kPGPError_NoErr;
	
	PGPValidateCFB( ref );
	PGPValidatePtr( salt );
	PGPValidateParam( ref->interleave == 1 );
	
	pgpCFBRandCycle( ref, salt);
	
	return( err );
}

					
					
/*____________________________________________________________________________
____________________________________________________________________________*/
	PGPError 
PGPCFBRandomWash(
	PGPCFBContextRef	ref,
	const void *		in,
	PGPSize				bytesIn )
{
	PGPError	err	= kPGPError_NoErr;
	
	PGPValidateCFB( ref );
	PGPValidatePtr( in );
	PGPValidateParam( ref->interleave == 1 );
	
	pgpCFBRandWash( ref, in, bytesIn );
	
	return( err );
}







#if PRAGMA_MARK_SUPPORTED
#pragma mark --- Internal Routines ---
#endif









	PGPCFBContextRef
pgpCFBCreate(
	PGPMemoryMgrRef			memoryMgr,
	PGPCipherVTBL const *	vtbl)
{
	PGPError						err				= kPGPError_NoErr;
	PGPCFBContextRef		newRef			= NULL;
	PGPSymmetricCipherContextRef	symmetricRef	= NULL;
	
	pgpAssert( vtbl->blocksize <= PGP_CFB_MAXBLOCKSIZE );
	pgpAssert( PGPMemoryMgrIsValid( memoryMgr ) );
		
	err	= pgpNewSymmetricCipherContextInternal( memoryMgr,
		vtbl->algorithm, vtbl->keysize, &symmetricRef );
	if ( IsntPGPError( err ) )
	{
		err	= PGPNewCFBContext( symmetricRef, 1, &newRef );
		if ( IsPGPError( err ) )
		{
			PGPFreeSymmetricCipherContext( symmetricRef );
			symmetricRef	= NULL;
			pgpAssert( IsNull( newRef ) );
		}
	}
	
	return newRef;
}


/*____________________________________________________________________________
	Initialize contexts.
	If key is NULL, the current key is not changed.
	if iv is NULL, the IV is set to all zero.
____________________________________________________________________________*/
	static void
pgpCFBInit(
	PGPCFBContext *	ref,
	void const *	key,
	void const *	iv)
{
	PGPSize			blockSize;
	PGPUInt32		cfbIndex;
	PGPByte const *	curIV	= (const PGPByte *) iv;
	
	PGPGetSymmetricCipherSizes( IndCFB( ref, 0 ).symmetricRef,
		NULL, &blockSize );
	
	for ( cfbIndex = 0; cfbIndex < ref->interleave; ++cfbIndex )
	{
		CFBInterleaveStruct *	cfb;
		
		cfb	= &IndCFB( ref, cfbIndex);
		
		if ( IsntNull( key ) )
		{
			PGPInitSymmetricCipher( cfb->symmetricRef, key );
		}
		
		pgpClearMemory( cfb->prev, sizeof( cfb->prev )  );
		pgpClearMemory( cfb->iv, sizeof( cfb->iv )  );
		if ( IsntNull( iv ) )
		{
			pgpCopyMemory( curIV, &cfb->iv, blockSize );
			curIV	+= blockSize;
		}
		
		cfb->bufLeft	= 0;
	}
	
	ref->curCFBIndex	= 0;
	ref->bytesInCur		= 0;
	/* rely on the symmetric cipher to know whether it has been inited */
	/* also, iv of NULL is OK, since semantics say that means zeroes */
	ref->cfbInited		= TRUE;
}



	PGPSize
pgpCFBGetKeySize( PGPCFBContextRef ref )
{
	PGPSize	keySize;
	
	pgpAssert( pgpCFBIsValid( ref ) );
	
	PGPGetSymmetricCipherSizes( IndCFB( ref, 0).symmetricRef, &keySize, NULL );
	return( keySize );
}

	PGPSize
pgpCFBGetBlockSize( PGPCFBContextRef ref )
{
	PGPSize	blockSize;
	
	pgpAssert( pgpCFBIsValid( ref ) );
	
	PGPGetSymmetricCipherSizes( IndCFB( ref, 0).symmetricRef,
		NULL, &blockSize );
	return( blockSize );
}



	void
pgpCFBWipe( PGPCFBContextRef	ref)
{
	PGPUInt32	cfbIndex;
	
	ref->cfbInited			= FALSE;
		
	pgpAssert( pgpCFBIsValid( ref ) );
	
	for ( cfbIndex = 0; cfbIndex < ref->interleave; ++cfbIndex )
	{
		CFBInterleaveStruct *	cfb;
		
		cfb	= &IndCFB( ref, cfbIndex);
		
		PGPWipeSymmetricCipher( cfb->symmetricRef );
		
		pgpClearMemory( cfb->prev, sizeof( cfb->prev )  );
		pgpClearMemory( cfb->iv, sizeof( cfb->iv )  );
		
		cfb->bufLeft = 0;
	}
	
	ref->curCFBIndex	= 0;
}



/*____________________________________________________________________________
	Encrypt a buffer of data, using a block cipher in CFB mode.
	here are more compact ways of writing this, but this is
	written for speed.
____________________________________________________________________________*/
	static void
pgpCFBEncrypt(
	CFBInterleaveStruct *	cfb,
	void const *			srcParam,
	PGPSize					len,
	void *					destParam )
{
	PGPSize			blockSize;
	PGPSize			bufLeft		= cfb->bufLeft;
	PGPByte *		bufptr;
	const PGPByte *	src;
	PGPByte *		dest;
	
	PGPGetSymmetricCipherSizes( cfb->symmetricRef, NULL, &blockSize );
	
	bufptr	= cfb->iv + blockSize - bufLeft;
	src		= (const PGPByte *) srcParam;
	dest	= (PGPByte *) destParam;
	
	/*
	 * If there are no more bytes to encrypt that there are bytes
	 * in the buffer, XOR them in and return.
	 */
	if (len <= bufLeft)
	{
		cfb->bufLeft = bufLeft - len;
		while (len--)
		{
			*dest++ = *bufptr++ ^= *src++;
		}
		return;
	}
	len -= 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 blockSize-byte blocks, and repeating until the len
	 * is blockSize or less.
	 */
	while (len > blockSize)
	{
		bufptr = cfb->iv;
		pgpCopyMemory( bufptr, cfb->prev, blockSize);
		pgpSymmetricCipherEncryptInternal(cfb->symmetricRef, bufptr, bufptr);
		bufLeft = blockSize;
		len -= blockSize;
		do
		{
			*dest++ = (*bufptr++ ^= *src++);
		} while (--bufLeft);
	}
	/* Do the last 1 to blockSize bytes */
	bufptr = cfb->iv;
	pgpCopyMemory( bufptr, cfb->prev, blockSize);
	pgpSymmetricCipherEncryptInternal(cfb->symmetricRef, bufptr, bufptr);
	cfb->bufLeft = blockSize-len;
	do 
	{
		*dest++ = (*bufptr++ ^= *src++);
	} while (--len);
}


/*____________________________________________________________________________
	Decrypt a buffer of data, using a cipher in CFB mode.
	There are more compact ways of writing this, but this is
	written for speed.
____________________________________________________________________________*/
	static void
pgpCFBDecrypt(
	CFBInterleaveStruct *	cfb,
	void const *			srcParam,
	PGPSize					len,
	void *					destParam )
{
	PGPSize			blockSize;
	PGPSize			bufLeft = cfb->bufLeft;
	PGPByte *		bufptr	= NULL;
	PGPByte			t;
	const PGPByte *	src = (const PGPByte *) srcParam;
	PGPByte *		dest = (PGPByte *) destParam;
	
	PGPGetSymmetricCipherSizes( cfb->symmetricRef, NULL, &blockSize );

	bufptr = cfb->iv + (blockSize-bufLeft);
	if (len <= bufLeft)
	{
		cfb->bufLeft = bufLeft - len;
		while (len--)
		{
			t = *bufptr;
			*dest++ = t ^ (*bufptr++ = *src++);
		}
		return;
	}
	len -= bufLeft;
	while (bufLeft--)
	{
		t = *bufptr;
		*dest++ = t ^ (*bufptr++ = *src++);
	}
	while (len > blockSize)
	{
		bufptr = cfb->iv;
		pgpCopyMemory( bufptr, cfb->prev, 8);
		pgpSymmetricCipherEncryptInternal(cfb->symmetricRef, bufptr, bufptr);
		bufLeft = blockSize;
		len -= blockSize;
		do
		{
			t = *bufptr;
			*dest++ = t ^ (*bufptr++ = *src++);
		} while (--bufLeft);
	}
	bufptr = cfb->iv;
	pgpCopyMemory( bufptr, cfb->prev, blockSize);
	pgpSymmetricCipherEncryptInternal(cfb->symmetricRef, bufptr, bufptr);
	cfb->bufLeft = blockSize-len;
	do
	{
		t = *bufptr;
		*dest++ = t ^ (*bufptr++ = *src++);
	} while (--len);
}

/*____________________________________________________________________________
	Okay, explanation time:
	Phil invented a unique way of doing CFB that's sensitive to semantic
	boundaries within the data being encrypted.  One way to phrase
	CFB en/decryption on an 8-byte block cipher is to say that you XOR
	the current 8 bytes with CRYPT(previous 8 bytes of ciphertext).
	Normally, you repeat this at 8-byte intervals, but Phil decided to
	resync things on the boundaries between elements in the stream being
	encrypted.

	That is, the last 4 bytes of a 12-byte field are en/decrypted using
	the first 4 bytes of CRYPT(previous 8 bytes of ciphertext), but then
	the last 4 bytes of that CRYPT computation are thrown away, and the
	first 8 bytes of the next field are en/decrypted using
	CRYPT(last 8 bytes of ciphertext).  This is equivalent to using a
	shorter feedback length (if you're familiar with the general CFB
	technique) briefly, and doesn't weaken the cipher any (using shorter
	CFB lengths makes it stronger, actually), it just makes it a bit unusual.

	Anyway, to accomodate this behaviour, every time we do an
	encryption of 8 bytes of ciphertext to get 8 bytes of XOR mask,
	we remember the ciphertext.  Then if we have to resync things
	after having processed, say, 2 bytes, we refill the iv buffer
	with the last 6 bytes of the old ciphertext followed by the
	2 bytes of new ciphertext stored in the front of the iv buffer.
____________________________________________________________________________*/
	static void
pgpCFBSync(CFBInterleaveStruct *cfb)
{
	PGPSize	blockSize;
	PGPSize	bufLeft		= cfb->bufLeft;

	(void)PGPGetSymmetricCipherSizes( cfb->symmetricRef, NULL, &blockSize );
	
	if (bufLeft)
	{
		pgpCopyMemory( cfb->iv, cfb->iv + bufLeft, blockSize - bufLeft);
		pgpCopyMemory( cfb->prev + blockSize - bufLeft, cfb->iv, bufLeft);
		cfb->bufLeft	= 0;
	}
}

/*____________________________________________________________________________
	Cryptographically strong pseudo-random-number generator.
	The design is from Appendix C of ANSI X9.17, "Financial
	Institution Key Management (Wholesale)", with IDEA
	substituted for triple-DES.
 
	This generates one block (64 bits) of random number R, based on a
	key K, an initial vector V, and a time-dependent salt I.  I need not
	be truly random, but should differ for each block of output R, and
	contain as much entropy as possible.  In X9.17, I is encrypt(K,time()),
	where time() is the most accurate time available.  This has I supplied
	(from the true random number pool, which is based on similar information)
	to the ideaRandCycle function.

	The operation of ideaRandCycle is straight from X9.17::
	R = encrypt(K, V^I)
	V = encrypt(K, R^I)

	One thing worth noting is that, given fixed values of K and V,
	there is an isomorphism between values of I and values of R.
	Thus, R always contains at least as much entropy as is in I;
	if I is truly completely random, it does not matter if K and/or V
	are known.  Thus, if the supplied I (from the true random number pool)
	are good, the output of this is good.


	Fills in the supplied buffer with up to "count" pseudo-random bytes.
	Returns the number of bytes filled in.  If less than "count",
	pgpCFBRandCycle will need to be called with a new random salt value
	before more bytes are available.  pgpCFBRandBytes will return 0 until
	that is done.
____________________________________________________________________________*/

	static PGPSize
pgpCFBRandBytes(
	PGPCFBContextRef	ref,
	PGPSize				count,
	void *				dest )
{
	PGPSize					bufLeft;
	CFBInterleaveStruct *	cfb;

	pgpAssert( ref->interleave == 1 );
	
	cfb	= &IndCFB( ref, 0 );
	
	bufLeft = cfb->bufLeft;
	
	if (count > bufLeft)
		count = bufLeft;
		
	cfb->bufLeft = bufLeft - count;
	pgpCopyMemory( cfb->prev + pgpCFBGetBlockSize( ref ) - bufLeft,
		dest, count);
		
	return count;
}


/*____________________________________________________________________________
	Make more random bytes available from ideaRandBytes using the X9.17
	algorithm and the supplied random salt.  Expects "ref->cipher->blockSize"
	bytes of salt.
____________________________________________________________________________*/
	static void
pgpCFBRandCycle(
	PGPCFBContext *	ref,
	void const *	saltParam)
{
	PGPSize					i;
	PGPSize					blockSize = pgpCFBGetBlockSize( ref );
	CFBInterleaveStruct *	cfb;
	const PGPByte *			salt = (const PGPByte *) saltParam;
	
	pgpAssert( ref->interleave == 1 );
	
	cfb	= &IndCFB( ref, 0 );

	pgpAssert( ref->interleave == 1 );
	
	for (i = 0; i < blockSize; i++)
	{
		cfb->iv[i] ^= salt[i];
	}
	
	pgpSymmetricCipherEncryptInternal( cfb->symmetricRef, cfb->iv, cfb->prev);
	
	for (i = 0; i < blockSize; i++)
	{
		cfb->iv[i] = cfb->prev[i] ^ salt[i];
	}
	
	pgpSymmetricCipherEncryptInternal( cfb->symmetricRef, cfb->iv, cfb->iv);
	cfb->bufLeft = blockSize;
}


/*____________________________________________________________________________
	"Wash" the random number state using an irreversible transformation
	based on the input buffer and the previous state.
____________________________________________________________________________*/
	static void
pgpCFBRandWash(
	PGPCFBContextRef	ref,
	void const *		bufParam,
	PGPSize				len)
{
	PGPSize							blockSize = pgpCFBGetBlockSize( ref );
	PGPSize 						i, j;
	CFBInterleaveStruct *			cfb	= NULL;
	PGPSymmetricCipherContextRef	symmetricRef;
	const PGPByte *					buf = (const PGPByte *) bufParam;
	
	pgpAssert( ref->interleave == 1 );
	
	cfb	= &IndCFB( ref, 0 );
	symmetricRef	= cfb->symmetricRef;

	/* Wash the key (if supported) */
	PGPWashSymmetricCipher( symmetricRef, buf, len);

	/*
	 * Wash the IV - a bit ad-hoc, but it works.   It's
	 * basically a CBC-MAC.
	 */
	for (i = j = 0; i < len; i++)
	{
		cfb->iv[j] ^= buf[i];
		if (++j == blockSize)
		{
			pgpSymmetricCipherEncryptInternal(symmetricRef, cfb->iv, cfb->iv);
			j = 0;
		}
	}
	/* Pad with typical CBC padding indicating the length */
	while (j < blockSize)
	{
		cfb->iv[j++] ^= (PGPByte)len;
	}
	
	pgpSymmetricCipherEncryptInternal( symmetricRef, cfb->iv, cfb->iv);

	/* Set to empty */
	cfb->bufLeft = 0;
}
















/*__Editor_settings____

	Local Variables:
	tab-width: 4
	End:
	vi: ts=4 sw=4
	vim: si
_____________________*/

⌨️ 快捷键说明

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