📄 asn1s_rw.c
字号:
}
return( CRYPT_ERROR );
}
/* Map an algorithm and optional sub-algorithm to an OID. These functions
are almost identical, the only difference is that the one used for
checking only doesn't throw an exception when it encounters an algorithm
value that it can't encode as an OID */
static const BYTE *algorithmToOID( const CRYPT_ALGO_TYPE algorithm,
const CRYPT_ALGO_TYPE subAlgorithm )
{
int i;
for( i = 0; algoIDmap[ i ].algorithm != CRYPT_ALGO_NONE; i++ )
if( algoIDmap[ i ].algorithm == algorithm && \
algoIDmap[ i ].subAlgorithm == subAlgorithm )
return( algoIDmap[ i ].oid );
assert( NOTREACHED );
return( NULL ); /* Get rid of compiler warning */
}
static const BYTE *algorithmToOIDcheck( const CRYPT_ALGO_TYPE algorithm,
const CRYPT_ALGO_TYPE subAlgorithm )
{
int i;
for( i = 0; algoIDmap[ i ].algorithm != CRYPT_ALGO_NONE; i++ )
if( algoIDmap[ i ].algorithm == algorithm && \
algoIDmap[ i ].subAlgorithm == subAlgorithm )
return( algoIDmap[ i ].oid );
return( NULL );
}
int readOID( STREAM *stream, const BYTE *oid )
{
BYTE buffer[ MAX_OID_SIZE ];
int dummy, status;
status = readRawObject( stream, buffer, &dummy, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) || \
memcmp( buffer, oid, sizeofOID( oid ) ) )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
status = CRYPT_ERROR_BADDATA;
}
return( status );
}
int readOIDSelection( STREAM *stream, const OID_SELECTION *oidSelection,
int *selection )
{
BYTE buffer[ MAX_OID_SIZE ];
int length, oidEntry, status;
/* Read the OID data */
status = readRawObject( stream, buffer, &length, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
/* Try and find the entry for the OID */
for( oidEntry = 0; oidSelection[ oidEntry ].oid != NULL; oidEntry++ )
if( length == sizeofOID( oidSelection[ oidEntry ].oid ) && \
!memcmp( buffer, oidSelection[ oidEntry ].oid, length ) )
break;
if( oidSelection[ oidEntry ].oid == NULL )
{
sSetError( stream, CRYPT_ERROR_BADDATA );
status = CRYPT_ERROR_BADDATA;
}
if( selection != NULL )
*selection = oidSelection[ oidEntry ].selection;
return( status );
}
/****************************************************************************
* *
* EncryptionAlgorithmIdentifier Routines *
* *
****************************************************************************/
/* EncryptionAlgorithmIdentifier parameters:
aesXcbc, aesXofb: AES FIPS
iv OCTET STRING SIZE (16)
aesXcfb: AES FIPS
SEQUENCE {
iv OCTET STRING SIZE (16),
noOfBits INTEGER (128)
}
cast5cbc: RFC 2144
SEQUENCE {
iv OCTET STRING DEFAULT 0,
keyLen INTEGER (128)
}
blowfishCBC, desCBC, desEDE3-CBC: Blowfish RFC/OIW
iv OCTET STRING SIZE (8)
blowfishCFB, blowfishOFB, desCFB, desOFB: Blowfish RFC/OIW
SEQUENCE {
iv OCTET STRING SIZE (8),
noBits INTEGER (64)
}
ideaCBC: Ascom Tech
SEQUENCE {
iv OCTET STRING OPTIONAL
}
ideaCFB: Ascom Tech
SEQUENCE {
r [ 0 ] INTEGER DEFAULT 64,
k [ 1 ] INTEGER DEFAULT 64,
j [ 2 ] INTEGER DEFAULT 64,
iv [ 3 ] OCTET STRING OPTIONAL
}
ideaOFB: Ascom Tech
SEQUENCE {
j INTEGER DEFAULT 64,
iv OCTET STRING OPTIONAL
}
rc2CBC: RFC 2311
SEQUENCE {
rc2Param INTEGER (58), -- 128 bit key
iv OCTET STRING SIZE (8)
}
rc4: RFC 2311
NULL
rc5: RFC 2040
SEQUENCE {
version INTEGER (16),
rounds INTEGER (12),
blockSize INTEGER (64),
iv OCTET STRING OPTIONAL
}
skipjackCBC: SDN.701
SEQUENCE {
iv OCTET STRING
}
Because of the haphazard and arbitrary nature of encryption
AlgorithmIdentifier definitions, we can only handle the following
algorithm/mode combinations:
AES ECB, CBC, CFB, OFB
Blowfish ECB, CBC, CFB, OFB
CAST128 CBC
DES ECB, CBC, CFB, OFB
3DES ECB, CBC, CFB, OFB
IDEA ECB, CBC, CFB, OFB
RC2 ECB, CBC
RC4
RC5 CBC
Skipjack CBC */
/* Magic value to denote 128-bit RC2 keys */
#define RC2_KEYSIZE_MAGIC 58
/* Read an EncryptionAlgorithmIdentifier record */
static int readAlgoIDInfo( STREAM *stream, QUERY_INFO *queryInfo,
const int tag )
{
CRYPT_ALGO_TYPE cryptAlgo;
BYTE buffer[ MAX_OID_SIZE ];
int length, bufferLength, cryptMode, status;
/* Read the AlgorithmIdentifier header and OID */
if( tag == DEFAULT_TAG )
readSequence( stream, &length );
else
readConstructed( stream, &length, tag );
status = readRawObject( stream, buffer, &bufferLength, MAX_OID_SIZE,
BER_OBJECT_IDENTIFIER );
if( cryptStatusError( status ) )
return( status );
if( ( cryptAlgo = oidToAlgorithm( buffer, &cryptMode ) ) == CRYPT_ERROR )
return( CRYPT_ERROR_NOTAVAIL );
queryInfo->cryptAlgo = cryptAlgo;
queryInfo->cryptMode = cryptMode;
length -= bufferLength;
/* Non-conventional-encryption algorithms will either have NULL
parameters or none at all depending on which interpreation of which
standard the sender used, so if it's not a conventional encryption
algorithm we just skip any remaining parameter data and return */
if( queryInfo->cryptAlgo < CRYPT_ALGO_FIRST_CONVENTIONAL || \
queryInfo->cryptAlgo > CRYPT_ALGO_LAST_CONVENTIONAL )
return( ( length > 0 ) ? sSkip( stream, length ) : CRYPT_OK );
/* Read the algorithm parameters. In theory we should do something with
some of the values like the IV size parameter, but since the standard
never explains what to do if it's something other than the algorithm
block size (Left pad? Right pad? Sign-extend? Repeat the data?) it's
safer not to do anything ("Never check for an error you don't know how
to handle"). In any case there are no known cases of these strange
values ever being used (probably because all existing software would
break) so for now we just make sure they're present but otherwise
ignore them */
if( cryptAlgo == CRYPT_ALGO_CAST )
{
readSequence( stream, NULL );
readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
CRYPT_MAX_IVSIZE );
return( readShortInteger( stream, NULL ) );
}
if( cryptAlgo == CRYPT_ALGO_AES || cryptAlgo == CRYPT_ALGO_DES || \
cryptAlgo == CRYPT_ALGO_3DES || cryptAlgo == CRYPT_ALGO_BLOWFISH )
{
if( cryptMode == CRYPT_MODE_ECB )
return( readNull( stream ) );
if( ( cryptMode == CRYPT_MODE_CBC ) || \
( cryptAlgo == CRYPT_ALGO_AES && cryptMode == CRYPT_MODE_OFB ) )
return( readOctetString( stream, queryInfo->iv,
&queryInfo->ivLength, CRYPT_MAX_IVSIZE ) );
readSequence( stream, NULL );
readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
CRYPT_MAX_IVSIZE );
return( readShortInteger( stream, NULL ) );
}
if( cryptAlgo == CRYPT_ALGO_IDEA )
{
int paramTag;
if( cryptMode == CRYPT_MODE_ECB )
return( readNull( stream ) );
readSequence( stream, NULL );
paramTag = peekTag( stream );
if( cryptMode == CRYPT_MODE_CFB )
{
/* Skip the CFB r, k, and j parameters */
while( paramTag == MAKE_CTAG_PRIMITIVE( 0 ) || \
paramTag == MAKE_CTAG_PRIMITIVE( 1 ) || \
paramTag == MAKE_CTAG_PRIMITIVE( 2 ) )
{
long value;
status = readShortIntegerTag( stream, &value, paramTag );
if( cryptStatusError( status ) || value != 64 )
return( CRYPT_ERROR_NOTAVAIL );
paramTag = peekTag( stream );
}
return( readOctetStringTag( stream, queryInfo->iv,
&queryInfo->ivLength,
CRYPT_MAX_IVSIZE, 3 ) );
}
if( cryptMode == CRYPT_MODE_OFB && paramTag == BER_INTEGER )
{
long value;
/* Skip the OFB j parameter */
status = readShortInteger( stream, &value );
if( cryptStatusError( status ) || value != 64 )
return( CRYPT_ERROR_NOTAVAIL );
}
return( readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
CRYPT_MAX_IVSIZE ) );
}
if( cryptAlgo == CRYPT_ALGO_RC2 )
{
/* In theory we should check that the parameter value ==
RC2_KEYSIZE_MAGIC (corresponding to a 128-bit key) but in practice
this doesn't really matter, we just use whatever we find inside
the PKCS #1 padding */
readSequence( stream, NULL );
if( cryptMode != CRYPT_MODE_CBC )
return( readShortInteger( stream, NULL ) );
readShortInteger( stream, NULL );
return( readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
CRYPT_MAX_IVSIZE ) );
}
if( cryptAlgo == CRYPT_ALGO_RC4 )
return( readNull( stream ) );
if( cryptAlgo == CRYPT_ALGO_RC5 )
{
long val1, val2, val3;
readSequence( stream, NULL );
readShortInteger( stream, &val1 ); /* Version */
readShortInteger( stream, &val2 ); /* Rounds */
status = readShortInteger( stream, &val3 ); /* Block size */
if( cryptStatusError( status ) || \
val1 != 16 || val2 != 12 || val3 != 64 )
/* This algorithm makes enough of a feature of its variable
parameters that we do actually check to make sure they're
sensible since it may just be possible that someone playing
with an implementation decides to use weird values */
return( CRYPT_ERROR_NOTAVAIL );
return( readOctetString( stream, queryInfo->iv, &queryInfo->ivLength,
CRYPT_MAX_IVSIZE ) );
}
if( cryptAlgo == CRYPT_ALGO_SKIPJACK )
{
readSequence( stream, NULL );
return( readOctetString( stream, queryInfo->iv,
&queryInfo->ivLength, CRYPT_MAX_IVSIZE ) );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* Write an EncryptionAlgorithmIdentifier record */
static int writeContextCryptAlgoID( STREAM *stream,
const CRYPT_CONTEXT iCryptContext )
{
const BYTE *oid;
BYTE iv[ CRYPT_MAX_IVSIZE ];
CRYPT_ALGO_TYPE algorithm;
CRYPT_MODE_TYPE mode;
int oidSize, ivSize = 0, sizeofIV = 0, status;
/* Extract the information we need to write the AlgorithmIdentifier */
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&algorithm, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&mode, CRYPT_CTXINFO_MODE );
if( cryptStatusOK( status ) && !isStreamCipher( algorithm ) && \
needsIV( mode ) )
{
RESOURCE_DATA msgData;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -