📄 lowlvl.c
字号:
if( cryptStatusError( status ) )
{
printf( "Couldn't decrypt data, status = %d.\n", status );
return( status );
}
return( CRYPT_OK );
}
#ifdef TEST_DH
if( cryptAlgo == CRYPT_ALGO_DH )
{
KEYAGREE_PARAMS keyAgreeParams;
int status;
/* Perform the DH key agreement */
memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
#if 0
status = krnlSendMessage( cryptContext, IMESSAGE_CTX_ENCRYPT,
&keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
if( cryptStatusOK( status ) )
status = krnlSendMessage( cryptContext, IMESSAGE_CTX_DECRYPT,
&keyAgreeParams, sizeof( KEYAGREE_PARAMS ) );
#else
status = cryptDeviceQueryCapability( cryptContext, 1001,
( CRYPT_QUERY_INFO * ) &keyAgreeParams );
if( cryptStatusOK( status ) )
status = cryptDeviceQueryCapability( cryptContext, 1002,
( CRYPT_QUERY_INFO * ) &keyAgreeParams );
#endif /* 0 */
if( cryptStatusError( status ) )
{
printf( "Couldn't perform DH key agreement, status = %d.\n",
status );
return( FALSE );
}
return( CRYPT_OK );
}
#endif /* TEST_DH */
if( cryptAlgo == CRYPT_ALGO_RSA )
{
static const BYTE rsa512Value[] = \
"\x4E\x1F\x2F\x10\xA9\xFB\x4F\xD9\xC1\x25\x79\x7A\x36\x00\x58\xD0"
"\x9E\x8B\x9F\xBA\xC7\x04\x10\x77\xDB\xBC\xC9\xD1\x70\xCD\xF6\x86"
"\xA4\xDC\x39\xA9\x57\xD7\xC7\xE0\x87\xF2\x31\xDF\x83\x7d\x27\x0E"
"\xB4\xA6\x93\x3D\x11\xEB\xA5\x0E\x42\x66\x7B\x30\x50\x84\xC1\x81";
static const BYTE rsa1024Value[] = \
"\x84\x8E\x00\x3E\x49\x11\x0D\x42\x4C\x71\x6B\xB4\xCF\x13\xDD\xCD"
"\x12\x30\x56\xC2\x4A\x55\x3B\xD8\x30\xA2\xB8\x73\xA7\xAB\xF0\x7A"
"\x2E\x07\x20\xCC\xBE\xEA\x58\x03\x56\xF6\x18\x27\x28\x4F\xE1\x02"
"\xC6\x49\x79\x6C\xB4\x7E\x6C\xC6\x93\x2E\xF1\x46\x83\x15\x5A\xB7"
"\x7D\xCC\x21\xEE\x4E\x3E\x0B\x8B\x85\xEE\x08\x21\xE6\xA7\x31\x53"
"\x2E\x92\x3D\x2D\xB0\xD4\xA1\x30\xF4\xE9\xEB\x37\xBF\xCD\x2F\xE1"
"\x60\x89\x19\xB6\x8C\x01\xFB\xD8\xAC\xF5\xC7\x4B\xB4\x74\x8A\x35"
"\x79\xE6\xE0\x48\xBD\x9C\x9F\xD7\x4A\x1C\x8A\x58\xAB\xA9\x3C\x44";
BYTE testBuffer[ TESTBUFFER_SIZE ], tmpBuffer[ 32 ];
BOOLEAN encryptOK = TRUE;
int length;
/* Take a copy of the input so we can compare it with decrypted
output and find out how much data we need to process */
memcpy( testBuffer, buffer, TESTBUFFER_SIZE );
cryptGetAttribute( cryptContext, CRYPT_CTXINFO_KEYSIZE, &length );
/* Since we're doing raw RSA encryption we need to format the data
specially to work with the RSA key being used. If we're using the
cryptlib native routines, we need to ensure that the magnitude of
the integer corresponding to the data to be encrypted is less than
the modulus, which we do by setting the first byte of the buffer
to 1. If we're using a crypto device, we need to create a (dummy)
PKCS #1-like format since some devices expect to see PKCS #1-
formatted data as input to/output from the RSA encryption/
decryption operation */
memcpy( tmpBuffer, buffer, 18 );
if( isDevice )
memcpy( buffer, "\x00\x02\xA5\xA5\xA5\xA5\xA5\xA5"
"\xA5\xA5\xA5\xA5\xA5\xA5\xA5\xA5"
"\xA5\x00", 18 );
else
buffer[ 0 ] = 1;
/* Since the PKC algorithms only handle a single block, we only
perform a single encrypt and decrypt operation */
status = cryptEncrypt( cryptContext, buffer, length );
if( cryptStatusError( status ) )
{
if( !noWarnFail )
printf( "Couldn't encrypt data, status = %d.\n", status );
return( status );
}
if( cryptAlgo == CRYPT_ALGO_RSA && !isDevice && \
memcmp( buffer, ( length == 64 ) ? rsa512Value : rsa1024Value,
length ) )
{
/* For a non-randomized PKC the encryption of the fixed value
produces known output, we make sure that this matches the
expected value. This makes diagnosing problems with crypto
devices rather easier */
puts( "The actual encrypted value doesn't match the expected value." );
encryptOK = FALSE;
}
status = cryptDecrypt( decryptContext, buffer, length );
if( cryptStatusError( status ) )
{
if( !noWarnFail )
{
if( encryptOK )
printf( "Couldn't decrypt data even though the "
"encrypted input data was valid,\nstatus = "
"%d.\n", status );
else
printf( "Couldn't decrypt data, probably because the "
"data produced by the encrypt step\nwas "
"invalid, status = %d.\n", status );
}
return( status );
}
if( isDevice )
memcpy( buffer, tmpBuffer, 18 );
else
buffer[ 0 ] = tmpBuffer[ 0 ];
/* Make sure that the recovered result matches the input data */
if( memcmp( buffer, testBuffer, length ) )
{
if( encryptOK )
/* This could happen with simple-minded CRT implementations
that only work when p > q (the test key has p < q in
order to find this problem) */
puts( "Decryption failed even though encryption produced "
"valid data. The RSA\ndecryption step is broken." );
else
puts( "Decryption failed because the encryption step "
"produced invalid data. The RSA\nencryption step is "
"broken." );
return( status );
}
else
if( !encryptOK )
{
puts( "Decryption succeeded even though encryption produced "
"invalid data. The RSA\nimplementation is broken." );
return( status );
}
return( CRYPT_OK );
}
if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH && \
cryptAlgo <= CRYPT_ALGO_LAST_MAC )
{
/* Hash the buffer in two odd-sized chunks. Note the use of the hash
wrap-up call, this is the only time when we can call
cryptEncrypt() with a zero length */
status = cryptEncrypt( cryptContext, buffer, 80 );
if( cryptStatusOK( status ) )
status = cryptEncrypt( cryptContext, buffer + 80,
TESTBUFFER_SIZE - 80 );
if( cryptStatusOK( status ) )
status = cryptEncrypt( cryptContext, buffer + TESTBUFFER_SIZE, 0 );
if( cryptStatusError( status ) )
{
printf( "Couldn't hash data, status = %d.\n", status );
return( status );
}
/* Hash the buffer in different odd-size chunks */
status = cryptEncrypt( decryptContext, buffer, 128 );
if( cryptStatusOK( status ) )
status = cryptEncrypt( decryptContext, buffer + 128,
TESTBUFFER_SIZE - 128 );
if( cryptStatusOK( status ) )
status = cryptEncrypt( decryptContext, buffer + TESTBUFFER_SIZE, 0 );
if( cryptStatusError( status ) )
{
printf( "Couldn't hash data, status = %d.\n", status );
return( status );
}
return( CRYPT_OK );
}
printf( "Unknown encryption algorithm/mode %d.\n", cryptAlgo );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Low-level Routines Test *
* *
****************************************************************************/
/* Test an algorithm/mode implementation */
int testLowlevel( const CRYPT_DEVICE cryptDevice,
const CRYPT_ALGO_TYPE cryptAlgo, const BOOLEAN checkOnly )
{
CRYPT_MODE_TYPE cryptMode = CRYPT_MODE_ECB;
CRYPT_CONTEXT cryptContext, decryptContext;
BYTE buffer[ TESTBUFFER_SIZE ], testBuffer[ TESTBUFFER_SIZE ];
const BOOLEAN isDevice = ( cryptDevice != CRYPT_UNUSED ) ? TRUE : FALSE;
BOOLEAN modesTested[ 8 ] = { 0 }, testSucceeded = FALSE;
int status;
/* Initialise the test buffers */
initTestBuffers( buffer, testBuffer, TESTBUFFER_SIZE );
/* Check cryptlib's capabilities */
if( !checkLowlevelInfo( cryptDevice, cryptAlgo ) )
return( FALSE );
/* If we're only doing a capability check, don't try anything else */
if( checkOnly )
return( TRUE );
/* Since DH and KEA only perform key agreement rather than a true key
exchange, we can't test their encryption capabilities unless we're
using a custom-modified version of cryptlib */
#ifndef TEST_DH
if( cryptAlgo == CRYPT_ALGO_DH )
return( TRUE );
#endif /* TEST_DH */
if( cryptAlgo == CRYPT_ALGO_KEA )
return( TRUE );
/* Test each mode of an algorithm. We have to be very careful about
destroying any objects we create before we exit, because objects left
active in a device will prevent it from being shut down once the
tests have completed */
do
{
/* Set up an encryption context, load a user key into it, and
perform a key setup */
switch( cryptAlgo )
{
case CRYPT_ALGO_DES:
status = loadContexts( &cryptContext, &decryptContext,
cryptDevice, cryptAlgo, cryptMode,
( BYTE * ) "12345678", 8 );
break;
case CRYPT_ALGO_SKIPJACK:
status = loadContexts( &cryptContext, &decryptContext,
cryptDevice, cryptAlgo, cryptMode,
( BYTE * ) "1234567890", 10 );
break;
case CRYPT_ALGO_CAST:
case CRYPT_ALGO_IDEA:
case CRYPT_ALGO_AES:
status = loadContexts( &cryptContext, &decryptContext,
cryptDevice, cryptAlgo, cryptMode,
( BYTE * ) "1234567887654321", 16 );
break;
case CRYPT_ALGO_3DES:
status = loadContexts( &cryptContext, &decryptContext,
cryptDevice, cryptAlgo, cryptMode,
( BYTE * ) "123456788765432112345678", 24 );
break;
case CRYPT_ALGO_RC2:
case CRYPT_ALGO_RC4:
case CRYPT_ALGO_RC5:
case CRYPT_ALGO_BLOWFISH:
case CRYPT_ALGO_HMAC_MD5:
case CRYPT_ALGO_HMAC_SHA:
case CRYPT_ALGO_HMAC_RIPEMD160:
status = loadContexts( &cryptContext, &decryptContext,
cryptDevice, cryptAlgo, cryptMode,
( BYTE * ) "1234567890098765432112345678900987654321", 40 );
break;
case CRYPT_ALGO_MD2:
case CRYPT_ALGO_MD4:
case CRYPT_ALGO_MD5:
case CRYPT_ALGO_SHA:
case CRYPT_ALGO_SHA2:
case CRYPT_ALGO_RIPEMD160:
status = loadContexts( &cryptContext, &decryptContext,
cryptDevice, cryptAlgo, CRYPT_MODE_NONE,
( BYTE * ) "", 0 );
break;
#ifdef TEST_DH
case CRYPT_ALGO_DH:
status = loadDHKey( cryptDevice, &cryptContext );
break;
#endif /* TEST_DH */
case CRYPT_ALGO_RSA:
status = loadRSAContexts( cryptDevice, &cryptContext,
&decryptContext );
break;
case CRYPT_ALGO_DSA:
status = loadDSAContexts( cryptDevice, &cryptContext,
&decryptContext );
break;
case CRYPT_ALGO_ELGAMAL:
status = loadElgamalContexts( &cryptContext, &decryptContext );
break;
default:
printf( "Unknown encryption algorithm ID %d, cannot perform "
"encryption test\n", cryptAlgo );
return( FALSE );
}
if( status == CRYPT_ERROR_NOTAVAIL )
{
/* It's a conventional algorithm for which this mode isn't
available, try a different mode */
cryptMode++;
continue;
}
if( !status )
return( FALSE );
/* DLP-based algorithms can't be called directly from user code
because of the special data-formatting requirements */
if( cryptAlgo == CRYPT_ALGO_DSA || cryptAlgo == CRYPT_ALGO_ELGAMAL )
{
destroyContexts( cryptDevice, cryptContext, decryptContext );
return( TRUE );
}
/* Perform a test en/decryption */
status = testCrypt( cryptContext, decryptContext, buffer, isDevice,
FALSE );
if( cryptStatusError( status ) )
{
destroyContexts( cryptDevice, cryptContext, decryptContext );
if( isDevice && status == CRYPT_ERROR_NOTAVAIL )
{
/* Some primitive tokens or accelerators support only the
barest minimum of functionality, which may include being
able to create objects but not use them (e.g. public key
objects in a device which is just an RSA private-key
modexp engine). Because of this we may get a
CRYPT_ERROR_NOTAVAIL when we try and perform a low-level
crypto test, this isn't normally a problem for cryptlib
high-level objects because public-key ops are always done
in software, but when we explicitly try to do them in the
token it's a problem. Because of this we report a problem
but continue anyway */
puts( "The crypto device reported that this operation isn't "
"available even though it\nsupports the use of "
"encryption objects that implement this algorithm. "
"This\nis probably a bare-bones device that only "
"supports minimal functionality (eg\nprivate-key "
"decryption but not encryption)." );
continue;
}
return( FALSE );
}
/* Make sure that everything went OK */
if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH )
{
BYTE hash1[ CRYPT_MAX_HASHSIZE ], hash2[ CRYPT_MAX_HASHSIZE ];
int length1, length2;
status = cryptGetAttributeString( cryptContext, CRYPT_CTXINFO_HASHVALUE,
hash1, &length1 );
cryptGetAttributeString( decryptContext, CRYPT_CTXINFO_HASHVALUE,
hash2, &length2 );
if( cryptStatusError( status ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -