Files
des_undes/third_party/cryptlib-0.99/crypt.c
T

1050 lines
35 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "crypt.h"
/****************************************************************************
* *
* General Work Routines *
* *
****************************************************************************/
/* Get an IV value. It doesn't matter much what it is, as long as it's
completely different for each call. We use the first built-in encrypt
capability we find (actually we just assume it's there to save some time) */
static void getIV( void *iv, int ivLength )
{
static BOOLEAN initialised = FALSE;
static BYTE ivBuffer[ CRYPT_MAX_IVSIZE ];
CRYPT_INFO cryptInfo;
CRYPT_INFO_MDCSHS cryptInfoEx;
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) */
memset( ivBuffer, 0, CRYPT_MAX_IVSIZE );
time( ( time_t * ) ivBuffer );
initialised = TRUE;
}
/* Use an extended setup call to only perform 2 setup iterations for
speed, since we're not concerned about security */
cryptInfoEx.keySetupIterations = 2;
/* Shuffle the bits and return them to the user. Since the encryption
will force a call to getIV() again, we cheat a bit by poking around
the cryptInfo internals to fool encryptBuffer() into thinking the IV
is already set */
initCryptContextEx( &cryptInfo, CRYPT_ALGO_MDCSHS, CRYPT_MODE_CFB,
&cryptInfoEx );
loadCryptContext( &cryptInfo, ivBuffer, CRYPT_MAX_IVSIZE );
cryptInfo.ivSet = TRUE; /* Nasty hack to stop recursion */
encryptBuffer( &cryptInfo, ivBuffer, CRYPT_MAX_IVSIZE );
destroyCryptContext( &cryptInfo );
memcpy( iv, ivBuffer, ivLength );
}
#ifdef LITTLE_ENDIAN
/* Byte-reverse an array of 16- and 32-bit words to/from network byte order
to account for processor endianness. These routines assume the given
count is a multiple of 16 or 32 bits. They are safe even for CPU's with
a word size > 32 bits since on a little-endian CPU the important 32 bits
are stored first, so that by zeroizing the first 32 bits and oring the
reversed value back in we don't need to rely on the processor only writing
32 bits into memory */
void longReverse( LONG *buffer, int count )
{
#ifdef _BIG_WORDS
BYTE *bufPtr = ( BYTE * ) buffer, temp;
count /= 4; /* sizeof( LONG ) != 4 */
while( count-- )
{
#if 0
LONG temp;
/* This code is cursed */
temp = value = *buffer & 0xFFFFFFFFUL;
value = ( ( value & 0xFF00FF00UL ) >> 8 ) | \
( ( value & 0x00FF00FFUL ) << 8 );
value = ( ( value << 16 ) | ( value >> 16 ) ) ^ temp;
*buffer ^= value;
buffer = ( LONG * ) ( ( BYTE * ) buffer + 4 );
#endif /* 0 */
/* There's really no nice way to do this - the above code generates
misaligned accesses on processors with a word size > 32 bits, so
we have to work at the byte level (either that or turn misaligned
access warnings off by trapping the signal the access corresponds
to. However a context switch per memory access is probably
somewhat slower than the current byte-twiddling mess) */
temp = bufPtr[ 3 ];
bufPtr[ 3 ] = bufPtr[ 0 ];
bufPtr[ 0 ] = temp;
temp = bufPtr[ 2 ];
bufPtr[ 2 ] = bufPtr[ 1 ];
bufPtr[ 1 ] = temp;
bufPtr += 4;
}
#else
LONG value;
count /= sizeof( LONG );
while( count-- )
{
value = *buffer;
value = ( ( value & 0xFF00FF00UL ) >> 8 ) | \
( ( value & 0x00FF00FFUL ) << 8 );
*buffer++ = ( value << 16 ) | ( value >> 16 );
}
#endif /* _BIG_WORDS */
}
void wordReverse( WORD *buffer, int count )
{
WORD value;
count /= sizeof( WORD );
while( count-- )
{
value = *buffer;
*buffer++ = ( value << 8 ) | ( value >> 8 );
}
}
#endif /* LITTLE_ENDIAN */
/* A safe free function which scrubs memory and zeroes the pointer */
void secureFree( void **pointer, int count )
{
if( *pointer != NULL )
{
/* Scrub the memory, free it, and zero the pointer */
memset( *pointer, 0, count );
free( *pointer );
*pointer = NULL;
}
}
/****************************************************************************
* *
* Capability Management Functions *
* *
****************************************************************************/
/* The parameters of most encryption algorithms are traditionally specified
in bytes, so we define a shorter form of the bitsToBytes() macro to allow
the capability information to be specified in bits */
#define bits(x) bitsToBytes(x)
/* The functions used to implement the null encryption routines */
int nullSelfTest( void );
int nullInit( CRYPT_INFO *cryptInfo );
int nullInitEx( CRYPT_INFO *cryptInfo, void *cryptInfoEx );
int nullEnd( CRYPT_INFO *cryptInfo );
int nullInitKey( CRYPT_INFO *cryptInfo );
int nullInitIV( CRYPT_INFO *cryptInfo );
int nullEncrypt( CRYPT_INFO *cryptInfo, void *buffer, int length );
int nullDecrypt( CRYPT_INFO *cryptInfo, void *buffer, int length );
/* The functions used to implement the MDC/SHS encryption routines */
int mdcshsSelfTest( void );
int mdcshsInit( CRYPT_INFO *cryptInfo );
int mdcshsInitEx( CRYPT_INFO *cryptInfo, void *cryptInfoEx );
int mdcshsEnd( CRYPT_INFO *cryptInfo );
int mdcshsInitKey( CRYPT_INFO *cryptInfo );
int mdcshsInitIV( CRYPT_INFO *cryptInfo );
int mdcshsEncrypt( CRYPT_INFO *cryptInfo, void *buffer, int length );
int mdcshsDecrypt( CRYPT_INFO *cryptInfo, void *buffer, int length );
/* The functions used to implement the DES encryption routines */
int desSelfTest( void );
int desInit( CRYPT_INFO *cryptInfo );
int desInitEx( CRYPT_INFO *cryptInfo, void *cryptInfoEx );
int desEnd( CRYPT_INFO *cryptInfo );
int desInitKey( CRYPT_INFO *cryptInfo );
int desEncryptECB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desDecryptECB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desEncryptCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desDecryptCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desEncryptCFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desDecryptCFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desEncryptOFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desDecryptOFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desEncryptPCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int desDecryptPCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
/* The functions used to implement the two-key triple DES encryption
routines */
int des3SelfTest( void );
int des3Init( CRYPT_INFO *cryptInfo );
int des3InitEx( CRYPT_INFO *cryptInfo, void *cryptInfoEx );
int des3End( CRYPT_INFO *cryptInfo );
int des3InitKey( CRYPT_INFO *cryptInfo );
int des3EncryptECB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int des3DecryptECB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int des3EncryptCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int des3DecryptCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int des3EncryptCFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int des3DecryptCFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int des3EncryptOFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int des3DecryptOFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
/* The functions used to implement the IDEA encryption routines */
int ideaSelfTest( void );
int ideaInit( CRYPT_INFO *cryptInfo );
int ideaInitEx( CRYPT_INFO *cryptInfo, void *cryptInfoEx );
int ideaEnd( CRYPT_INFO *cryptInfo );
int ideaInitKey( CRYPT_INFO *cryptInfo );
int ideaEncryptECB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int ideaDecryptECB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int ideaEncryptCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int ideaDecryptCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int ideaEncryptCFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int ideaDecryptCFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int ideaEncryptOFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int ideaDecryptOFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
/* The functions used to implement the RC4 encryption routines */
int rc4SelfTest( void );
int rc4Init( CRYPT_INFO *cryptInfo );
int rc4InitEx( CRYPT_INFO *cryptInfo, void *cryptInfoEx );
int rc4End( CRYPT_INFO *cryptInfo );
int rc4InitKey( CRYPT_INFO *cryptInfo );
int rc4Encrypt( CRYPT_INFO *cryptInfo, void *buffer, int length );
int rc4Decrypt( CRYPT_INFO *cryptInfo, void *buffer, int length );
/* The functions used to implement the SAFER and SAFER_SK encryption
routines */
int saferSelfTest( void );
int saferInit( CRYPT_INFO *cryptInfo );
int saferInitEx( CRYPT_INFO *cryptInfo, void *cryptInfoEx );
int saferEnd( CRYPT_INFO *cryptInfo );
int saferInitKey( CRYPT_INFO *cryptInfo );
int saferEncryptECB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int saferDecryptECB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int saferEncryptCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int saferDecryptCBC( CRYPT_INFO *cryptInfo, void *buffer, int length );
int saferEncryptCFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int saferDecryptCFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int saferEncryptOFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
int saferDecryptOFB( CRYPT_INFO *cryptInfo, void *buffer, int length );
/* The encryption library intrinsic capability list */
static CAPABILITY_INFO intrinsicCapabilities[] = {
/* The no-encryption capability */
{ CRYPT_ALGO_NONE, CRYPT_MODE_NONE, 0, "None", CRYPT_MAX_SPEED,
0, 0, 0,
0, 0, 0,
nullSelfTest, nullInit, nullInitEx, nullEnd, nullInitKey, nullInitIV,
nullEncrypt, nullDecrypt, CRYPT_ERROR, NULL },
/* The MDC/SHS capabilities */
{ CRYPT_ALGO_MDCSHS, CRYPT_MODE_CFB, bits( 8 ), "MDC/SHS", CRYPT_ERROR,
bits( 40 ), bits( 512 ), bits( 2048 ),
bits( 32 ), bits( 64 ), bits( 160 ),
mdcshsSelfTest, mdcshsInit, mdcshsInitEx, mdcshsEnd,
mdcshsInitKey, mdcshsInitIV, mdcshsEncrypt, mdcshsDecrypt,
CRYPT_ERROR, NULL },
/* The DES capabilities */
{ CRYPT_ALGO_DES, CRYPT_MODE_ECB, bits( 64 ), "DES-ECB", CRYPT_ERROR,
bits( 40 ), bits( 56 ), bits( 56 ),
bits( 0 ), bits( 0 ), bits( 0 ),
desSelfTest, desInit, desInitEx, desEnd, desInitKey, NULL,
desEncryptECB, desDecryptECB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_DES, CRYPT_MODE_CBC, bits( 64 ), "DES-CBC", CRYPT_ERROR,
bits( 40 ), bits( 56 ), bits( 56 ),
bits( 16 ), bits( 32 ), bits( 64 ),
desSelfTest, desInit, desInitEx, desEnd, desInitKey, NULL,
desEncryptCBC, desDecryptCBC, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_DES, CRYPT_MODE_CFB, bits( 8 ), "DES-CFB", CRYPT_ERROR,
bits( 40 ), bits( 56 ), bits( 56 ),
bits( 16 ), bits( 32 ), bits( 64 ),
desSelfTest, desInit, desInitEx, desEnd, desInitKey, NULL,
desEncryptCFB, desDecryptCFB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_DES, CRYPT_MODE_OFB, bits( 8 ), "DES-OFB", CRYPT_ERROR,
bits( 40 ), bits( 56 ), bits( 56 ),
bits( 16 ), bits( 32 ), bits( 64 ),
desSelfTest, desInit, desInitEx, desEnd, desInitKey, NULL,
desEncryptOFB, desDecryptOFB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_DES, CRYPT_MODE_PCBC, bits( 64 ), "DES-PCBC", CRYPT_ERROR,
bits( 40 ), bits( 56 ), bits( 56 ),
bits( 16 ), bits( 32 ), bits( 64 ),
desSelfTest, desInit, desInitEx, desEnd, desInitKey, NULL,
desEncryptPCBC, desDecryptPCBC, CRYPT_ERROR, NULL },
/* The two-key triple DES capabilities */
{ CRYPT_ALGO_3DES, CRYPT_MODE_ECB, bits( 64 ), "3DES-ECB", CRYPT_ERROR,
bits( 40 ), bits( 112 ), bits( 112 ),
bits( 0 ), bits( 0 ), bits( 0 ),
des3SelfTest, des3Init, des3InitEx, des3End, des3InitKey, NULL,
des3EncryptECB, des3DecryptECB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_3DES, CRYPT_MODE_CBC, bits( 64 ), "3DES-CBC", CRYPT_ERROR,
bits( 40 ), bits( 112 ), bits( 112 ),
bits( 16 ), bits( 32 ), bits( 64 ),
des3SelfTest, des3Init, des3InitEx, des3End, des3InitKey, NULL,
des3EncryptCBC, des3DecryptCBC, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_3DES, CRYPT_MODE_CFB, bits( 64 ), "3DES-CFB", CRYPT_ERROR,
bits( 40 ), bits( 112 ), bits( 112 ),
bits( 16 ), bits( 32 ), bits( 64 ),
des3SelfTest, des3Init, des3InitEx, des3End, des3InitKey, NULL,
des3EncryptCFB, des3DecryptCFB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_3DES, CRYPT_MODE_OFB, bits( 64 ), "3DES-OFB", CRYPT_ERROR,
bits( 40 ), bits( 112 ), bits( 112 ),
bits( 16 ), bits( 32 ), bits( 64 ),
des3SelfTest, des3Init, des3InitEx, des3End, des3InitKey, NULL,
des3EncryptOFB, des3DecryptOFB, CRYPT_ERROR, NULL },
/* The IDEA capabilities */
{ CRYPT_ALGO_IDEA, CRYPT_MODE_ECB, bits( 64 ), "IDEA-ECB", CRYPT_ERROR,
bits( 40 ), bits( 128 ), bits( 128 ),
bits( 0 ), bits( 0 ), bits( 0 ),
ideaSelfTest, ideaInit, ideaInitEx, ideaEnd, ideaInitKey, NULL,
ideaEncryptECB, ideaDecryptECB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_IDEA, CRYPT_MODE_CBC, bits( 64 ), "IDEA-CBC", CRYPT_ERROR,
bits( 40 ), bits( 128 ), bits( 128 ),
bits( 16 ), bits( 32 ), bits( 64 ),
ideaSelfTest, ideaInit, ideaInitEx, ideaEnd, ideaInitKey, NULL,
ideaEncryptCBC, ideaDecryptCBC, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_IDEA, CRYPT_MODE_CFB, bits( 8 ), "IDEA-CFB", CRYPT_ERROR,
bits( 40 ), bits( 128 ), bits( 128 ),
bits( 16 ), bits( 32 ), bits( 64 ),
ideaSelfTest, ideaInit, ideaInitEx, ideaEnd, ideaInitKey, NULL,
ideaEncryptCFB, ideaDecryptCFB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_IDEA, CRYPT_MODE_OFB, bits( 8 ), "IDEA-OFB", CRYPT_ERROR,
bits( 40 ), bits( 128 ), bits( 128 ),
bits( 16 ), bits( 32 ), bits( 64 ),
ideaSelfTest, ideaInit, ideaInitEx, ideaEnd, ideaInitKey, NULL,
ideaEncryptOFB, ideaDecryptOFB, CRYPT_ERROR, NULL },
/* The RC4 capabilities */
{ CRYPT_ALGO_RC4, CRYPT_MODE_STREAM, bits( 8 ), "RC4", CRYPT_ERROR,
bits( 40 ), bits( 128 ), bits( 256 ),
bits( 0 ), bits( 0 ), bits( 0 ),
rc4SelfTest, rc4Init, rc4InitEx, rc4End, rc4InitKey, NULL,
rc4Encrypt, rc4Decrypt, CRYPT_ERROR, NULL },
/* The SAFER capabilities */
{ CRYPT_ALGO_SAFER, CRYPT_MODE_ECB, bits( 64 ), "SAFER-ECB", CRYPT_ERROR,
bits( 40 ), bits( 64 ), bits( 128 ),
bits( 0 ), bits( 0 ), bits( 0 ),
saferSelfTest, saferInit, saferInitEx, saferEnd, saferInitKey, NULL,
saferEncryptECB, saferDecryptECB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_SAFER, CRYPT_MODE_CBC, bits( 64 ), "SAFER-CBC", CRYPT_ERROR,
bits( 40 ), bits( 64 ), bits( 128 ),
bits( 16 ), bits( 32 ), bits( 64 ),
saferSelfTest, saferInit, saferInitEx, saferEnd, saferInitKey, NULL,
saferEncryptCBC, saferDecryptCBC, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_SAFER, CRYPT_MODE_CFB, bits( 8 ), "SAFER-CFB", CRYPT_ERROR,
bits( 40 ), bits( 64 ), bits( 128 ),
bits( 16 ), bits( 32 ), bits( 64 ),
saferSelfTest, saferInit, saferInitEx, saferEnd, saferInitKey, NULL,
saferEncryptCFB, saferDecryptCFB, CRYPT_ERROR, NULL },
{ CRYPT_ALGO_SAFER, CRYPT_MODE_OFB, bits( 8 ), "SAFER-OFB", CRYPT_ERROR,
bits( 40 ), bits( 64 ), bits( 128 ),
bits( 16 ), bits( 32 ), bits( 64 ),
saferSelfTest, saferInit, saferInitEx, saferEnd, saferInitKey, NULL,
saferEncryptOFB, saferDecryptOFB, CRYPT_ERROR, NULL },
/* The end-of-list marker */
{ CRYPT_ALGO_NONE, CRYPT_MODE_NONE, CRYPT_ERROR, "", 0,
0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, CRYPT_ERROR, NULL }
};
/* The list of crypt library capability records. Even if initCapabilities()
is never called we still have a minimum non-encryption method available */
static CAPABILITY_INFO *capabilityListHead = intrinsicCapabilities;
static CAPABILITY_INFO *capabilityListTail = intrinsicCapabilities;
static CAPABILITY_INFO *intrinsicCapabilityListEnd = NULL;
/* Free the capability list */
static void freeCapabilityList( void )
{
CAPABILITY_INFO *capabilityListPtr = intrinsicCapabilityListEnd;
void *capabilityToFree;
/* Mark the list as being empty */
intrinsicCapabilityListEnd = NULL;
/* Free the capability record list list */
while( capabilityListPtr != NULL )
{
capabilityToFree = capabilityListPtr;
capabilityListPtr = capabilityListPtr->next;
secureFree( &capabilityToFree, sizeof( CAPABILITY_INFO ) );
}
}
/* Initialise the intrinsic encryption library capability list */
static int initCapabilities( void )
{
CAPABILITY_INFO *capabilityInfoPtr;
CRYPT_ALGO cryptAlgo = CRYPT_ERROR;
int i;
/* Add the built-in encryption capabilities */
for( i = 0; intrinsicCapabilities[ i + 1 ].blockSize != CRYPT_ERROR; i++ )
intrinsicCapabilities[ i ].next = &intrinsicCapabilities[ i + 1 ];
/* Perform the self-test for each encryption algorithm */
for( capabilityInfoPtr = capabilityListHead;
capabilityInfoPtr != NULL;
capabilityInfoPtr = capabilityInfoPtr->next )
{
CAPABILITY_INFO *capabilitySelfTestPtr;
int status;
/* If we've already encountered this algorithm, don't try the
self-test again */
if( capabilityInfoPtr->cryptAlgo == cryptAlgo )
continue;
cryptAlgo = capabilityInfoPtr->cryptAlgo;
/* Perform the self-test for this algorithm type */
status = capabilityInfoPtr->selfTestFunction();
/* Set the test status for each capability using this algorithm */
for( capabilitySelfTestPtr = capabilityInfoPtr;
capabilitySelfTestPtr != NULL;
capabilitySelfTestPtr = capabilitySelfTestPtr->next )
if( capabilitySelfTestPtr->cryptAlgo == capabilityInfoPtr->cryptAlgo )
capabilitySelfTestPtr->selfTestStatus = status;
}
return( CRYPT_OK );
}
/* Add a capability record to the library */
static int addCapability( CRYPT_ALGO cryptAlgo, CRYPT_MODE cryptMode, \
int blockSize, char *name, int speed, \
int minKeySize, int keySize, int maxKeySize )
{
CAPABILITY_INFO *newElement;
/* Check the passed-in parameters */
if( cryptAlgo < CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST )
return( CRYPT_BADPARM1 );
if( cryptMode < CRYPT_MODE_NONE || cryptMode > CRYPT_MODE_LAST )
return( CRYPT_BADPARM2 );
if( blockSize < 0 )
return( CRYPT_BADPARM3 );
if( name == NULL )
return( CRYPT_BADPARM4 );
if( ( speed != CRYPT_ERROR && speed < 0 ) || speed > CRYPT_MAX_SPEED )
return( CRYPT_BADPARM5 );
if( minKeySize < 0 )
return( CRYPT_BADPARM6 );
if( keySize < minKeySize )
return( CRYPT_BADPARM7 );
if( maxKeySize < keySize )
return( CRYPT_BADPARM8 );
/* Allocate memory for the new capability and its associated message */
if( ( newElement = ( CAPABILITY_INFO * ) malloc( sizeof( CAPABILITY_INFO ) ) ) == NULL )
return( CRYPT_NOMEM );
memset( newElement, 0, sizeof( CAPABILITY_INFO ) );
if( ( newElement->name = ( char * ) malloc( strlen( name ) + 1 ) ) == NULL )
{
free( newElement );
return( CRYPT_NOMEM );
}
/* Copy the information across */
newElement->cryptAlgo = cryptAlgo;
newElement->cryptMode = cryptMode;
newElement->blockSize = blockSize;
strcpy( newElement->name, name );
newElement->minKeySize = minKeySize;
newElement->keySize = keySize;
newElement->maxKeySize = maxKeySize;
newElement->next = NULL;
/* Link it into the list */
if( capabilityListHead == NULL )
capabilityListHead = newElement;
else
capabilityListTail->next = newElement;
capabilityListTail = newElement;
return( CRYPT_OK );
}
/* Find the capability record for a given encryption algorithm */
static CAPABILITY_INFO *findCapabilityInfo( CRYPT_ALGO cryptAlgo, \
CRYPT_MODE cryptMode )
{
CAPABILITY_INFO *capabilityInfoPtr;
/* Try and find information on the required algorithm */
for( capabilityInfoPtr = capabilityListHead;
capabilityInfoPtr != NULL;
capabilityInfoPtr = capabilityInfoPtr->next )
if( capabilityInfoPtr->cryptAlgo == cryptAlgo &&
( capabilityInfoPtr->cryptMode == cryptMode ||
cryptMode == CRYPT_MODE_NONE ) )
return( capabilityInfoPtr );
/* Nothing available */
return( NULL );
}
/****************************************************************************
* *
* Capability Query Functions *
* *
****************************************************************************/
/* Determine whether a given encryption mode is available */
CRET queryModeAvailability( CRYPT_ALGO cryptAlgo, CRYPT_MODE cryptMode )
{
/* Perform basic error checking */
if( cryptAlgo < CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST )
return( CRYPT_BADPARM1 );
if( cryptMode < CRYPT_MODE_NONE || cryptMode > CRYPT_MODE_LAST )
return( CRYPT_BADPARM2 );
/* Make sure the library has been initalised */
if( capabilityListHead == NULL )
return( CRYPT_NOTINITED );
/* See if we have any information on this encryption algo/mode */
if( findCapabilityInfo( cryptAlgo, cryptMode ) == NULL )
return( ( findCapabilityInfo( cryptAlgo, CRYPT_MODE_NONE ) == NULL ) ? \
CRYPT_NOALGO : CRYPT_NOMODE );
return( CRYPT_OK );
}
CRET queryAlgoAvailability( CRYPT_ALGO cryptAlgo )
{
return( queryModeAvailability( cryptAlgo, CRYPT_MODE_NONE ) );
}
/* Get information on a given encrytion algorithm */
CRET queryAlgoModeInformation( CRYPT_ALGO cryptAlgo, CRYPT_MODE cryptMode, \
CRYPT_QUERY_INFO CPTR cryptQueryInfo )
{
CAPABILITY_INFO *capabilityInfo;
/* Perform basic error checking */
if( cryptAlgo < CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST )
return( CRYPT_BADPARM1 );
if( cryptMode < CRYPT_MODE_NONE || cryptMode > CRYPT_MODE_LAST )
return( CRYPT_BADPARM2 );
if( cryptQueryInfo == NULL )
return( CRYPT_BADPARM3 );
/* Make sure the library has been initalised */
if( capabilityListHead == NULL )
return( CRYPT_NOTINITED );
/* Clear the fields in the query structure */
memset( cryptQueryInfo, 0, sizeof( CRYPT_QUERY_INFO ) );
/* Find the information record on this algorithm */
if( ( capabilityInfo = findCapabilityInfo( cryptAlgo, cryptMode ) ) == NULL )
{
cryptQueryInfo->algoName = "";
cryptQueryInfo->blockSize = CRYPT_ERROR;
cryptQueryInfo->minKeySize = CRYPT_ERROR;
cryptQueryInfo->keySize = CRYPT_ERROR;
cryptQueryInfo->maxKeySize = CRYPT_ERROR;
cryptQueryInfo->minIVsize = CRYPT_ERROR;
cryptQueryInfo->ivSize = CRYPT_ERROR;
cryptQueryInfo->maxIVsize = CRYPT_ERROR;
cryptQueryInfo->speed = CRYPT_ERROR;
return( ( findCapabilityInfo( cryptAlgo, CRYPT_MODE_NONE ) == NULL ) ? \
CRYPT_NOALGO : CRYPT_NOMODE );
}
/* Return the appropriate information */
cryptQueryInfo->cryptAlgo = cryptAlgo;
cryptQueryInfo->cryptMode = cryptMode;
cryptQueryInfo->algoName = capabilityInfo->name;
cryptQueryInfo->blockSize = capabilityInfo->blockSize;
cryptQueryInfo->minKeySize = capabilityInfo->minKeySize;
cryptQueryInfo->keySize = capabilityInfo->keySize;
cryptQueryInfo->maxKeySize = capabilityInfo->maxKeySize;
cryptQueryInfo->minIVsize = capabilityInfo->minIVsize;
cryptQueryInfo->ivSize = capabilityInfo->ivSize;
cryptQueryInfo->maxIVsize = capabilityInfo->maxIVsize;
cryptQueryInfo->speed = capabilityInfo->speed;
return( CRYPT_OK );
}
/* Get information on the algorithm used by a given encryption context */
CRET queryContextInformation( CRYPT_INFO CPTR cryptInfo,
CRYPT_QUERY_INFO CPTR cryptQueryInfo )
{
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( cryptInfo->capabilityInfo == NULL )
return( CRYPT_NOTINITED );
return( queryAlgoModeInformation( cryptInfo->capabilityInfo->cryptAlgo,
cryptInfo->capabilityInfo->cryptMode, cryptQueryInfo ) );
}
/* Initialise and shut down the encryption library */
CRET initLibrary( void )
{
return( initCapabilities() );
}
CRET endLibrary( void )
{
freeCapabilityList();
return( CRYPT_OK );
}
/****************************************************************************
* *
* Encryption Context Management Functions *
* *
****************************************************************************/
/* A magic value to detect whether an encryption context has been
initialised yet */
#define CRYPT_MAGIC 0xC0EDBABEL
/* Initialise and perform an extended initialisation of an encryption
context */
CRET initCryptContext( CRYPT_INFO CPTR cryptInfo, CRYPT_ALGO cryptAlgo, \
CRYPT_MODE cryptMode )
{
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( cryptAlgo < CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST )
return( CRYPT_BADPARM2 );
if( cryptMode < CRYPT_MODE_NONE || cryptMode > CRYPT_MODE_LAST )
return( CRYPT_BADPARM3 );
/* Set all fields to zero */
memset( cryptInfo, 0, sizeof( CRYPT_INFO ) );
/* Set up the pointer to the capability information */
if( ( cryptInfo->capabilityInfo = findCapabilityInfo( cryptAlgo, cryptMode ) ) == NULL )
return( ( queryAlgoAvailability( cryptAlgo ) ) ? \
CRYPT_NOMODE : CRYPT_NOALGO );
/* Make sure the algorithm self-test went OK */
if( cryptInfo->capabilityInfo->selfTestStatus != CRYPT_OK )
return( CRYPT_SELFTEST );
/* Perform any algorithm-specific initialization */
if( cryptInfo->capabilityInfo->initFunction != NULL )
{
int status;
status = cryptInfo->capabilityInfo->initFunction( cryptInfo );
if( isStatusError( status ) )
return( status );
}
/* Set up the IV information to the default values. This can be
overridden later if required */
cryptInfo->ivLength = cryptInfo->capabilityInfo->ivSize;
/* Set the check value. Note that we set it after the capability info
has been set, so that a check on this value will also tell us whether
the capability info is present */
cryptInfo->checkValue = CRYPT_MAGIC;
return( CRYPT_OK );
}
CRET initCryptContextEx( CRYPT_INFO CPTR cryptInfo, CRYPT_ALGO cryptAlgo, \
CRYPT_MODE cryptMode, void *cryptInfoEx )
{
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( cryptAlgo < CRYPT_ALGO_NONE || cryptAlgo >= CRYPT_ALGO_LAST )
return( CRYPT_BADPARM2 );
if( cryptMode < CRYPT_MODE_NONE || cryptMode > CRYPT_MODE_LAST )
return( CRYPT_BADPARM3 );
if( cryptInfoEx == NULL )
return( CRYPT_BADPARM4 );
/* Set all fields to zero */
memset( cryptInfo, 0, sizeof( CRYPT_INFO ) );
/* Set up the pointer to the capability information */
if( ( cryptInfo->capabilityInfo = findCapabilityInfo( cryptAlgo, cryptMode ) ) == NULL )
return( ( queryAlgoAvailability( cryptAlgo ) ) ? \
CRYPT_NOMODE : CRYPT_NOALGO );
/* Make sure the algorithm self-test went OK */
if( cryptInfo->capabilityInfo->selfTestStatus != CRYPT_OK )
return( CRYPT_SELFTEST );
/* Perform any algorithm-specific initialization */
if( cryptInfo->capabilityInfo->initExFunction != NULL )
{
int status;
status = cryptInfo->capabilityInfo->initExFunction( cryptInfo, cryptInfoEx );
if( isStatusError( status ) )
return( status );
}
/* Set up the IV information to the default values. This can be
overridden later if required */
cryptInfo->ivLength = cryptInfo->capabilityInfo->ivSize;
/* Set the check value. Note that we set it after the capability info
has been set, so that a check on this value will also tell us whether
the capability info is present */
cryptInfo->checkValue = CRYPT_MAGIC;
return( CRYPT_OK );
}
/* Destroy an encryption context */
CRET destroyCryptContext( CRYPT_INFO CPTR cryptInfo )
{
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( cryptInfo->checkValue != CRYPT_MAGIC ||
cryptInfo->capabilityInfo == NULL )
return( CRYPT_NOTINITED );
/* Perform any algorithm-specific shutdown */
if( cryptInfo->capabilityInfo->endFunction != NULL )
{
int status;
status = cryptInfo->capabilityInfo->endFunction( cryptInfo );
if( isStatusError( status ) )
return( status );
}
/* Clear all data in the encryption context */
memset( cryptInfo, 0, sizeof( CRYPT_INFO ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Keying Functions *
* *
****************************************************************************/
/* Load a user key into an encryption context */
CRET loadCryptContext( CRYPT_INFO CPTR cryptInfo, void CPTR userKey,
int userKeyLength )
{
int status;
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( userKey == NULL )
return( CRYPT_BADPARM2 );
if( cryptInfo->checkValue != CRYPT_MAGIC )
return( CRYPT_NOTINITED );
if( userKeyLength < cryptInfo->capabilityInfo->minKeySize ||
userKeyLength > cryptInfo->capabilityInfo->maxKeySize )
return( CRYPT_BADPARM3 );
if( cryptInfo->capabilityInfo->initKeyFunction == NULL )
return( CRYPT_NOALGO );
/* Load the user encryption key into the crypt context */
memcpy( cryptInfo->userKey, userKey, userKeyLength );
cryptInfo->userKeyLength = userKeyLength;
/* Remember that we need to set an IV before we encrypt anything */
cryptInfo->ivSet = FALSE;
/* Call the encryption routine for this algorithm/mode */
if( ( status = cryptInfo->capabilityInfo->initKeyFunction( cryptInfo ) ) != CRYPT_OK )
return( status );
/* Record the fact that the key has been initialized */
cryptInfo->keySet = TRUE;
return( CRYPT_OK );
}
/****************************************************************************
* *
* IV Handling Functions *
* *
****************************************************************************/
/* Load an IV key into an encryption context */
CRET loadIV( CRYPT_INFO CPTR cryptInfo, void CPTR iv, int ivLength )
{
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( cryptInfo->checkValue != CRYPT_MAGIC )
return( CRYPT_NOTINITED );
if( ivLength < cryptInfo->capabilityInfo->minIVsize ||
ivLength > cryptInfo->capabilityInfo->maxIVsize )
return( CRYPT_BADPARM3 );
/* Set the IV length and check whether we'll be using a user-supplied
IV */
cryptInfo->ivLength = ivLength;
cryptInfo->ivCount = 0;
if( iv != NULL )
{
/* Load the IV of the required length. If the required IV size is
less than the maximum possible IV size, we pad it with zeroes */
memset( cryptInfo->iv, 0, CRYPT_MAX_IVSIZE );
memcpy( cryptInfo->iv, iv, cryptInfo->ivLength );
memcpy( cryptInfo->currentIV, cryptInfo->iv, CRYPT_MAX_IVSIZE );
cryptInfo->ivSet = TRUE;
}
if( cryptInfo->capabilityInfo->initIVFunction != NULL )
{
int status;
status = cryptInfo->capabilityInfo->initIVFunction( cryptInfo );
if( isStatusError( status ) )
return( status );
}
return( CRYPT_OK );
}
/* Retrieve an IV from an encryption context */
CRET retrieveIV( CRYPT_INFO CPTR cryptInfo, void CPTR iv )
{
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( iv == NULL )
return( CRYPT_BADPARM2 );
if( cryptInfo->checkValue != CRYPT_MAGIC )
return( CRYPT_NOTINITED );
/* Make sure the IV has been set */
if( cryptInfo->ivSet == FALSE )
return( CRYPT_NOIV );
/* Copy the IV data of the required length to the output buffer */
memcpy( iv, cryptInfo->iv, cryptInfo->ivLength );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Encrypt/Decrypt Routines *
* *
****************************************************************************/
/* Encrypt a block of memory */
CRET encryptBuffer( CRYPT_INFO CPTR cryptInfo, void CPTR buffer, int length )
{
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( buffer == NULL )
return( CRYPT_BADPARM2 );
if( length < 0 )
return( CRYPT_BADPARM3 );
if( !cryptInfo->keySet )
return( CRYPT_NOKEY );
if( cryptInfo->checkValue != CRYPT_MAGIC )
return( CRYPT_NOTINITED );
if( cryptInfo->capabilityInfo->encryptFunction == NULL )
return( CRYPT_NOALGO );
/* If there's no IV set, generate one ourselves */
if( !cryptInfo->ivSet )
{
BYTE iv[ CRYPT_MAX_IVSIZE ];
int status;
getIV( iv, cryptInfo->ivLength );
status = loadIV( cryptInfo, iv, cryptInfo->ivLength );
if( isStatusError( status ) )
return( CRYPT_ERROR );
}
/* Call the encryption routine for this algorithm/mode */
return( cryptInfo->capabilityInfo->encryptFunction( cryptInfo, buffer, length ) );
}
/* Decrypt a block of memory */
CRET decryptBuffer( CRYPT_INFO CPTR cryptInfo, void CPTR buffer, int length )
{
/* Perform basic error checking */
if( cryptInfo == NULL )
return( CRYPT_BADPARM1 );
if( buffer == NULL )
return( CRYPT_BADPARM2 );
if( length < 0 )
return( CRYPT_BADPARM3 );
if( !cryptInfo->keySet )
return( CRYPT_NOKEY );
if( cryptInfo->checkValue != CRYPT_MAGIC )
return( CRYPT_NOTINITED );
if( cryptInfo->capabilityInfo->decryptFunction == NULL )
return( CRYPT_NOALGO );
/* Make sure the IV has been set */
if( cryptInfo->ivSet == FALSE )
return( CRYPT_NOIV );
/* Call the decryption routine for this algorithm/mode */
return( cryptInfo->capabilityInfo->decryptFunction( cryptInfo, buffer, length ) );
}
/****************************************************************************
* *
* Dynamic Library Update Support *
* *
****************************************************************************/
/* Add a new encryption capability to the library. This routine is quite
powerful, but what a kludge! */
CRET addCryptCapability( CRYPT_ALGO cryptAlgo, CRYPT_MODE cryptMode, \
int blockSize, char *name, int speed, \
int minKeySize, int keySize, int maxKeySize )
{
int status;
/* Add the basic capability information */
status = addCapability( cryptAlgo, cryptMode, blockSize, name,
speed, minKeySize, keySize, maxKeySize );
if( isStatusError( status ) )
return( status );
/* Add the handlers */
/* Not implemented yet */
return( CRYPT_OK );
}
/****************************************************************************
* *
* OS-Specific Support Routines *
* *
****************************************************************************/
#if defined( __WINDOWS__ ) && !( defined( WIN32 ) || defined( _WIN32 ) )
/* Whether LibMain() has been called before */
static BOOLEAN libMainCalled = FALSE;
static HWND hInst;
/* The main function for the DLL */
int CALLBACK LibMain( HINSTANCE hInstance, WORD wDataSeg, WORD wHeapSize, \
LPSTR lpszCmdLine )
{
/* Rot bilong kargo */
if( wHeapSize > 0 )
UnlockData( 0 ); /* Allow heap to move */
/* If we've been called before, return with an error message */
if( libMainCalled )
return( FALSE );
libMainCalled = TRUE;
/* Initialise the library */
if( initLibrary() != CRYPT_OK )
return( FALSE );
/* Remember the proc instance for later */
hInst = hInstance;
return( TRUE );
}
/* Shut down the DLL */
int CALLBACK WEP( int nSystemExit )
{
switch( nSystemExit )
{
case WEP_SYSTEM_EXIT:
/* System is shutting down */
break;
case WEP_FREE_DLL:
/* DLL reference count = 0, DLL-only shutdown */
break;
}
/* Shut down the encryption library if necessary */
endLibrary();
return( TRUE );
}
#elif defined( __WINDOWS__ ) && ( defined( WIN32 ) || defined( _WIN32 ) )
/* Whether LibMain() has been called before */
static BOOLEAN libMainCalled = FALSE;
static HWND hInst;
int LibMain( HANDLE hInstance, ULONG ulReasonCalled, LPVOID lpReserved )
{
/* If we've been called before, return with an error message */
if( libMainCalled )
return( FALSE );
libMainCalled = TRUE;
/* Initialise the library */
if( initLibrary() != CRYPT_OK )
return( FALSE );
/* Remember the proc instance for later */
hInst = hInstance;
return( TRUE );
}
int CALLBACK WEP( int nSystemExit )
{
/* Shut down the encryption library if necessary */
endLibrary();
return( TRUE );
}
#endif /* __WINDOWS__ */