📄 pgpcbc.c
字号:
/*____________________________________________________________________________
pgpCBC.c
Copyright (C) 1997 Network Associates Inc. and affiliated companies.
All rights reserved.
$Id: pgpCBC.c,v 1.13 1999/03/10 02:47:07 heller Exp $
____________________________________________________________________________*/
#include "pgpConfig.h"
#include <string.h>
#include "pgpSDKBuildFlags.h"
#include "pgpMem.h"
#include "pgpErrors.h"
#include "pgpSymmetricCipherPriv.h"
#include "pgpCBCPriv.h"
#include "pgpUtilitiesPriv.h"
#define PGPValidateCBC( CBC ) \
PGPValidateParam( pgpCBCIsValid( CBC ) );
/*____________________________________________________________________________
In CBC, iv[] is the previous block's ciphertext, or the Initial
Vector before the first block is processed. As we read plaintext
bytes during encryption, they are xored into iv[] until it is
full, then the symmetric cipher is run. For decryption, iv[] is
loaded with the previous ciphertext after we finish decrypting the
current block.
____________________________________________________________________________*/
struct PGPCBCContext
{
#define kCBCMagic 0xBAAB0957
PGPUInt32 magic;
PGPMemoryMgrRef memoryMgr;
PGPBoolean CBCInited;
PGPSymmetricCipherContextRef symmetricRef;
PGPByte iv1[ PGP_CBC_MAXBLOCKSIZE ];
PGPByte iv2[ PGP_CBC_MAXBLOCKSIZE ];
PGPByte * iv;
};
static PGPBoolean
pgpCBCIsValid( const PGPCBCContext * ref)
{
PGPBoolean valid = FALSE;
valid = IsntNull( ref ) && ref->magic == kCBCMagic
&& (ref->iv == ref->iv1 || ref->iv == ref->iv2);
return( valid );
}
/*____________________________________________________________________________
Internal forward references
____________________________________________________________________________*/
static void pgpCBCInit( PGPCBCContext * ref,
void const * key, void const * iv);
static PGPError pgpCBCEncrypt( PGPCBCContext *ref,
void const * src, PGPSize len, void * dest );
static PGPError pgpCBCDecrypt( PGPCBCContext *ref,
void const * src, PGPSize len, void * dest );
/*____________________________________________________________________________
Exported routines
____________________________________________________________________________*/
PGPError
PGPNewCBCContext(
PGPSymmetricCipherContextRef symmetricRef,
PGPCBCContextRef * outRef )
{
PGPCBCContextRef newRef = NULL;
PGPError err = kPGPError_NoErr;
PGPMemoryMgrRef memoryMgr = NULL;
PGPValidatePtr( outRef );
*outRef = NULL;
PGPValidatePtr( symmetricRef );
memoryMgr = pgpGetSymmetricCipherMemoryMgr( symmetricRef );
newRef = (PGPCBCContextRef)
PGPNewData( memoryMgr,
sizeof( *newRef ), 0 | kPGPMemoryMgrFlags_Clear);
if ( IsntNull( newRef ) )
{
#if PGP_DEBUG
/* make original invalid to enforce semantics */
PGPSymmetricCipherContextRef tempRef;
err = PGPCopySymmetricCipherContext( symmetricRef, &tempRef );
if ( IsntPGPError( err ) )
{
PGPFreeSymmetricCipherContext( symmetricRef );
symmetricRef = tempRef;
}
err = kPGPError_NoErr;
#endif
newRef->magic = kCBCMagic;
newRef->CBCInited = FALSE;
newRef->symmetricRef = symmetricRef;
newRef->iv = newRef->iv1;
newRef->memoryMgr = memoryMgr;
/* make sure we clean up */
if ( IsPGPError( err ) )
{
PGPFreeCBCContext( newRef );
newRef = NULL;
}
}
else
{
/* we own it, so dispose it */
PGPFreeSymmetricCipherContext( symmetricRef );
err = kPGPError_OutOfMemory;
}
*outRef = newRef;
return( err );
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
PGPFreeCBCContext( PGPCBCContextRef ref )
{
PGPError err = kPGPError_NoErr;
PGPValidateCBC( ref );
PGPFreeSymmetricCipherContext( ref->symmetricRef );
pgpClearMemory( ref, sizeof( *ref ) );
PGPFreeData( ref );
return( err );
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
PGPCopyCBCContext(
PGPCBCContextRef inRef,
PGPCBCContextRef * outRef )
{
PGPError err = kPGPError_NoErr;
PGPCBCContextRef newRef = NULL;
PGPValidatePtr( outRef );
*outRef = NULL;
PGPValidateCBC( inRef );
newRef = (PGPCBCContextRef)
PGPNewData( inRef->memoryMgr,
sizeof( *newRef ), 0);
if ( IsntNull( newRef ) )
{
*newRef = *inRef;
newRef->iv = (inRef->iv==inRef->iv1) ? newRef->iv1 : newRef->iv2;
/* clear symmetric cipher in case later allocation fails */
newRef->symmetricRef = NULL;
/* copy symmetric cipher */
err = PGPCopySymmetricCipherContext(
inRef->symmetricRef, &newRef->symmetricRef );
if ( IsPGPError( err ) )
{
PGPFreeCBCContext( newRef );
newRef = NULL;
}
}
else
{
err = kPGPError_OutOfMemory;
}
*outRef = newRef;
return( err );
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
PGPInitCBC(
PGPCBCContextRef ref,
const void * key,
const void * initializationVector )
{
PGPError err = kPGPError_NoErr;
PGPValidateCBC( ref );
/* at least one param must be non-nil */
PGPValidateParam( IsntNull( key ) || IsntNull( initializationVector ) );
pgpCBCInit( ref, key, initializationVector);
return( err );
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
pgpCBCEncryptInternal(
PGPCBCContextRef ref,
const void * in,
PGPSize bytesIn,
void * out )
{
PGPError err;
if ( ref->CBCInited )
{
err = pgpCBCEncrypt( ref, in, bytesIn, out);
}
else
{
err = kPGPError_ImproperInitialization;
}
return( err );
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
PGPCBCEncrypt(
PGPCBCContextRef ref,
const void * in,
PGPSize bytesIn,
void * out )
{
PGPValidatePtr( out );
PGPValidateCBC( ref );
PGPValidatePtr( in );
PGPValidateParam( bytesIn != 0 );
#if PGP_ENCRYPT_DISABLE
return( kPGPError_FeatureNotAvailable );
#else
return( pgpCBCEncryptInternal( ref, in, bytesIn, out ) );
#endif
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
pgpCBCDecryptInternal(
PGPCBCContextRef ref,
const void * in,
PGPSize bytesIn,
void * out )
{
PGPError err;
if ( ref->CBCInited )
{
err = pgpCBCDecrypt( ref, in, bytesIn, out);
}
else
{
err = kPGPError_ImproperInitialization;
}
return( err );
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
PGPCBCDecrypt(
PGPCBCContextRef ref,
const void * in,
PGPSize bytesIn,
void * out )
{
PGPValidatePtr( out );
PGPValidateCBC( ref );
PGPValidatePtr( in );
PGPValidateParam( bytesIn != 0 );
#if PGP_DECRYPT_DISABLE
return( kPGPError_FeatureNotAvailable );
#else
return( pgpCBCDecryptInternal( ref, in, bytesIn, out ) );
#endif
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPError
PGPCBCGetSymmetricCipher(
PGPCBCContextRef ref,
PGPSymmetricCipherContextRef * outRef )
{
PGPError err = kPGPError_NoErr;
PGPSymmetricCipherContextRef symmetricRef = NULL;
PGPValidatePtr( outRef );
*outRef = NULL;
PGPValidateCBC( ref );
symmetricRef = ref->symmetricRef;
*outRef = symmetricRef;
return( err );
}
#if PRAGMA_MARK_SUPPORTED
#pragma mark --- Internal Routines ---
#endif
/*____________________________________________________________________________
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
pgpCBCInit(
PGPCBCContext * ref,
void const * key,
void const * iv)
{
PGPSize blockSize;
void const * curIV = iv;
PGPGetSymmetricCipherSizes( ref->symmetricRef, NULL, &blockSize );
if ( IsntNull( key ) )
{
PGPInitSymmetricCipher( ref->symmetricRef, key );
}
pgpClearMemory( ref->iv1, sizeof( ref->iv1 ) );
pgpClearMemory( ref->iv2, sizeof( ref->iv2 ) );
ref->iv = ref->iv1;
if ( IsntNull( iv ) )
{
pgpCopyMemory( curIV, ref->iv, blockSize );
}
/* 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->CBCInited = TRUE;
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPSize
pgpCBCGetKeySize( PGPCBCContextRef ref )
{
PGPSize keySize;
pgpAssert( pgpCBCIsValid( ref ) );
PGPGetSymmetricCipherSizes( ref->symmetricRef, &keySize, NULL );
return( keySize );
}
/*____________________________________________________________________________
____________________________________________________________________________*/
PGPSize
pgpCBCGetBlockSize( PGPCBCContextRef ref )
{
PGPSize blockSize;
pgpAssert( pgpCBCIsValid( ref ) );
PGPGetSymmetricCipherSizes( ref->symmetricRef, NULL, &blockSize );
return( blockSize );
}
/*____________________________________________________________________________
Encrypt a buffer of data blocks, using a block cipher in CBC mode.
____________________________________________________________________________*/
static PGPError
pgpCBCEncrypt(
PGPCBCContext * ref,
void const * srcParam,
PGPSize len,
void * destParam )
{
PGPSize blockSize;
PGPSize bufcnt;
PGPByte * bufptr;
const PGPByte * src = (const PGPByte *) srcParam;
PGPByte * dest = (PGPByte *) destParam;
PGPGetSymmetricCipherSizes( ref->symmetricRef, NULL, &blockSize );
/* Length must be a multiple of blocksize */
if( len % blockSize != 0 )
{
return kPGPError_BadParams;
}
while( len != 0 )
{
bufptr = ref->iv;
bufcnt = blockSize;
/* XOR new data into iv buffer */
while( bufcnt-- )
{
*bufptr++ ^= *src++;
}
/* Encrypt IV buffer to itself to form ciphertext */
bufptr = ref->iv;
pgpSymmetricCipherEncryptInternal(ref->symmetricRef, bufptr, bufptr);
/* Copy ciphertext to destination buffer */
bufcnt = blockSize;
while( bufcnt-- )
{
*dest++ = *bufptr++;
}
/* Loop until we have exhausted the data */
len -= blockSize;
}
return kPGPError_NoErr;
}
/*____________________________________________________________________________
Decrypt a buffer of data blocks, using a block cipher in CBC mode.
____________________________________________________________________________*/
static PGPError
pgpCBCDecrypt(
PGPCBCContext * ref,
void const * srcParam,
PGPSize len,
void * destParam )
{
PGPSize blockSize;
PGPSize bufcnt;
PGPByte * bufptr;
const PGPByte * src = (const PGPByte *) srcParam;
PGPByte * dest = (PGPByte *) destParam;
PGPGetSymmetricCipherSizes( ref->symmetricRef, NULL, &blockSize );
/* Length must be a multiple of blocksize */
if( len % blockSize != 0 )
{
return kPGPError_BadParams;
}
while( len != 0 )
{
PGPByte * altiv;
/* Copy input ciphertext into alternate iv buffer */
altiv = (ref->iv == ref->iv1) ? ref->iv2 : ref->iv1;
bufcnt = blockSize;
bufptr = altiv;
while( bufcnt-- )
{
*bufptr++ = *src++;
}
/* Decrypt ciphertext into destination */
pgpSymmetricCipherDecryptInternal(ref->symmetricRef, altiv, dest);
/* XOR iv into output data to form plaintext */
bufcnt = blockSize;
bufptr = ref->iv;
while( bufcnt-- )
{
*dest++ ^= *bufptr++;
}
/* Toggle the IV buffers each iteration */
ref->iv = altiv;
/* Loop until we have exhausted the data */
len -= blockSize;
}
return kPGPError_NoErr;
}
/*__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 + -