📄 envelope.c
字号:
/****************************************************************************
* *
* cryptlib Enveloping Test Routines *
* Copyright Peter Gutmann 1996-2005 *
* *
****************************************************************************/
#include <limits.h> /* To determine max.buffer size we can encrypt */
#ifdef _MSC_VER
#include "../cryptlib.h"
#include "test.h"
#else
#include "cryptlib.h"
#include "test/test.h"
#endif /* Braindamaged MSC include handling */
#if defined( __MVS__ ) || defined( __VMCMS__ )
/* Suspend conversion of literals to ASCII. */
#pragma convlit( suspend )
#endif /* IBM big iron */
#if defined( __ILEC400__ )
#pragma convert( 0 )
#endif /* IBM medium iron */
/* Test data to use for the self-test. The PGP test data is slightly
different since it's not possible to include a null character in data
generated via the command-line versions of PGP. On EBCDIC systems we
have to hardcode in the character codes since the pre-generated data
came from an ASCII system */
#if defined( __MVS__ ) || defined( __VMCMS__ )
#define ENVELOPE_TESTDATA ( ( BYTE * ) "\x53\x6F\x6D\x65\x20\x74\x65\x73\x74\x20\x64\x61\x74\x61" )
#define ENVELOPE_PGP_TESTDATA ( ( BYTE * ) "\x53\x6F\x6D\x65\x20\x74\x65\x73\x74\x20\x64\x61\x74\x61\x2E" )
#define ENVELOPE_COMPRESSEDDATA "\x2F\x2A\x20\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x6C\x6F\x77\x65\x73\x74\x2D"
#else
#define ENVELOPE_TESTDATA ( ( BYTE * ) "Some test data" )
#define ENVELOPE_PGP_TESTDATA ( ( BYTE * ) "Some test data." )
#define ENVELOPE_COMPRESSEDDATA "/* This is a lowest-"
#endif /* EBCDIC systems */
#define ENVELOPE_TESTDATA_SIZE 15
#define ENVELOPE_COMPRESSEDDATA_SIZE 20
/* To convert a CMS blob into an S/MIME message, base64 encode it and add
the following header:
To: <address>
Subject: S/MIME test
From: <address>
MIME-Version: 1.0
Content-Type: application/x-pkcs7-mime;smime-type=signed-data;name="smime.p7m"
Content-Disposition: attachment;filename="smime.p7m"
Content-Transfer-Encoding: base64
<base64-encoded data>
To allow the inner message to be processed by a mailer, the contents will
themselves have to be MIME-formatted:
MIME-Version: 1.0
Content-Type: text/plain;charset="us-ascii"
Content-Transfer-Encoding: 7bit
<text> */
/* External flags which indicate that the key read/update routines worked OK.
This is set by earlier self-test code, if it isn't set some of the tests
are disabled */
extern int keyReadOK, doubleCertOK;
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* The general-purpose buffer used for enveloping. We use a fixed buffer
if possible to save having to add huge amounts of allocation/deallocation
code */
BYTE FAR_BSS globalBuffer[ BUFFER_SIZE ];
/* Determine the size of a file. If there's a problem, we return the
default buffer size, which will cause a failure further up the chain
where the error can be reported better */
static int getFileSize( const char *fileName )
{
FILE *filePtr;
long size;
if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
return( BUFFER_SIZE );
fseek( filePtr, 0L, SEEK_END );
size = ftell( filePtr );
fclose( filePtr );
if( size > INT_MAX )
return( BUFFER_SIZE );
return( ( int ) size );
}
/* Read test data from a file */
static int readFileData( const char *fileName, const char *description,
BYTE *buffer, const int bufSize )
{
FILE *filePtr;
int count;
if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
{
printf( "Couldn't find %s file, skipping test of data import...\n",
description );
return( 0 );
}
printf( "Testing %s import...\n", description );
count = fread( buffer, 1, bufSize, filePtr );
fclose( filePtr );
if( count == bufSize )
{
puts( "The data buffer size is too small for the data. To fix this, "
"either increase\nthe BUFFER_SIZE value in " __FILE__ " and "
"recompile the code, or use the\ntest code with dynamically-"
"allocated buffers." );
return( 0 ); /* Skip this test and continue */
}
if( count < 16 )
{
printf( "Read failed, only read %d bytes.\n", count );
return( 0 ); /* Skip this test and continue */
}
printf( "%s has size %d bytes.\n", description, count );
return( count );
}
/* Common routines to create an envelope, add enveloping information, push
data, pop data, and destroy an envelope */
static int createEnvelope( CRYPT_ENVELOPE *envelope,
const CRYPT_FORMAT_TYPE formatType )
{
int status;
/* Create the envelope */
status = cryptCreateEnvelope( envelope, CRYPT_UNUSED, formatType );
if( cryptStatusError( status ) )
{
printf( "cryptCreateEnvelope() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
return( TRUE );
}
static int createDeenvelope( CRYPT_ENVELOPE *envelope )
{
int status;
/* Create the envelope */
status = cryptCreateEnvelope( envelope, CRYPT_UNUSED, CRYPT_FORMAT_AUTO );
if( cryptStatusError( status ) )
{
printf( "cryptCreateDeevelope() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
return( TRUE );
}
static int addEnvInfoString( const CRYPT_ENVELOPE envelope,
const CRYPT_ATTRIBUTE_TYPE type,
const void *envInfo, const int envInfoLen )
{
int status;
status = cryptSetAttributeString( envelope, type, envInfo, envInfoLen );
if( cryptStatusError( status ) )
{
printf( "cryptSetAttributeString() failed with error code %d, "
"line %d.\n", status, __LINE__ );
return( FALSE );
}
return( TRUE );
}
static int addEnvInfoNumeric( const CRYPT_ENVELOPE envelope,
const CRYPT_ATTRIBUTE_TYPE type,
const int envInfo )
{
int status;
status = cryptSetAttribute( envelope, type, envInfo );
if( cryptStatusError( status ) )
{
printf( "cryptSetAttribute() failed with error code %d, line %d.\n",
status, __LINE__ );
return( FALSE );
}
return( TRUE );
}
static int pushData( const CRYPT_ENVELOPE envelope, const BYTE *buffer,
const int length, const void *stringEnvInfo,
const int numericEnvInfo )
{
BOOLEAN isRestartable = FALSE;
int bytesIn, contentType, status;
/* Push in the data */
status = cryptPushData( envelope, buffer, length, &bytesIn );
if( status == CRYPT_ENVELOPE_RESOURCE )
{
int cryptEnvInfo;
/* Add the appropriate enveloping information we need to continue */
status = cryptSetAttribute( envelope, CRYPT_ATTRIBUTE_CURRENT_GROUP,
CRYPT_CURSOR_FIRST );
if( cryptStatusError( status ) )
{
printf( "Attempt to move cursor to start of list failed with "
"error code %d, line %d.\n", status, __LINE__ );
return( status );
}
do
{
C_CHR label[ CRYPT_MAX_TEXTSIZE + 1 ];
int labelLength;
status = cryptGetAttribute( envelope, CRYPT_ATTRIBUTE_CURRENT,
&cryptEnvInfo );
if( cryptStatusError( status ) )
{
printf( "Attempt to read current group failed with error "
"code %d, line %d.\n", status, __LINE__ );
return( status );
}
switch( cryptEnvInfo )
{
case CRYPT_ATTRIBUTE_NONE:
/* The required information was supplied via other means
(in practice this means there's a crypto device
available and that was used for the decrypt), there's
nothing left to do */
puts( "(Decryption key was recovered using crypto device "
"or non-password-protected\n private key)." );
break;
case CRYPT_ENVINFO_PRIVATEKEY:
/* If there's no decryptoin password present, the
private key must be passed in directly */
if( stringEnvInfo == NULL )
{
status = cryptSetAttribute( envelope,
CRYPT_ENVINFO_PRIVATEKEY,
numericEnvInfo );
if( cryptStatusError( status ) )
{
printf( "Attempt to add private key failed with "
"error code %d, line %d.\n", status,
__LINE__ );
return( status );
}
isRestartable = TRUE;
break;
}
/* A private-key keyset is present in the envelope, we
need a password to decrypt the key */
status = cryptGetAttributeString( envelope,
CRYPT_ENVINFO_PRIVATEKEY_LABEL,
label, &labelLength );
if( cryptStatusError( status ) )
{
printf( "Private key label read failed with error "
"code %d, line %d.\n", status, __LINE__ );
return( status );
}
#ifdef UNICODE_STRINGS
label[ labelLength / sizeof( wchar_t ) ] = '\0';
printf( "Need password to decrypt private key '%S'.\n",
label );
#else
label[ labelLength ] = '\0';
printf( "Need password to decrypt private key '%s'.\n",
label );
#endif /* UNICODE_STRINGS */
if( !addEnvInfoString( envelope, CRYPT_ENVINFO_PASSWORD,
stringEnvInfo, paramStrlen( stringEnvInfo ) ) )
return( SENTINEL );
isRestartable = TRUE;
break;
case CRYPT_ENVINFO_PASSWORD:
puts( "Need user password." );
if( !addEnvInfoString( envelope, CRYPT_ENVINFO_PASSWORD,
stringEnvInfo, paramStrlen( stringEnvInfo ) ) )
return( SENTINEL );
isRestartable = TRUE;
break;
case CRYPT_ENVINFO_SESSIONKEY:
puts( "Need session key." );
if( !addEnvInfoNumeric( envelope, CRYPT_ENVINFO_SESSIONKEY,
numericEnvInfo ) )
return( SENTINEL );
isRestartable = TRUE;
break;
case CRYPT_ENVINFO_KEY:
puts( "Need conventional encryption key." );
if( !addEnvInfoNumeric( envelope, CRYPT_ENVINFO_KEY,
numericEnvInfo ) )
return( SENTINEL );
isRestartable = TRUE;
break;
case CRYPT_ENVINFO_SIGNATURE:
/* If we've processed the entire data block in one go,
we may end up with only signature information
available, in which case we defer processing them
until after we've finished with the deenveloped data */
break;
default:
printf( "Need unknown enveloping information type %d.\n",
cryptEnvInfo );
return( SENTINEL );
}
}
while( cryptSetAttribute( envelope, CRYPT_ATTRIBUTE_CURRENT_GROUP,
CRYPT_CURSOR_NEXT ) == CRYPT_OK );
/* If we're using some form of encrypted enveloping, report the
algorithm and keysize used */
if( cryptEnvInfo == CRYPT_ATTRIBUTE_NONE || \
cryptEnvInfo == CRYPT_ENVINFO_PRIVATEKEY || \
cryptEnvInfo == CRYPT_ENVINFO_PASSWORD )
{
int cryptAlgo, keySize;
status = cryptGetAttribute( envelope, CRYPT_CTXINFO_ALGO,
&cryptAlgo );
if( cryptStatusOK( status ) )
status = cryptGetAttribute( envelope, CRYPT_CTXINFO_KEYSIZE,
&keySize );
if( cryptStatusError( status ) )
{
printf( "Couldn't query encryption algorithm and keysize "
"used in envelope, status %d, line %d.\n", status,
__LINE__ );
return( status );
}
printf( "Data is protected using algorithm %d with %d bit key.\n",
cryptAlgo, keySize * 8 );
}
/* If we only got some of the data in due to the envelope stopping to
ask us for a decryption resource, push in the rest */
if( bytesIn < length && isRestartable )
{
const int initialBytesIn = bytesIn;
status = cryptPushData( envelope, buffer + initialBytesIn,
length - initialBytesIn, &bytesIn );
if( cryptStatusError( status ) )
{
printf( "cryptPushData() for remaining data failed with "
"error code %d, line %d.\n", status, __LINE__ );
return( status );
}
bytesIn += initialBytesIn;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -