📄 asn1_ext.c
字号:
BYTE iv[ CRYPT_MAX_IVSIZE ];
CRYPT_ALGO_TYPE algorithm;
CRYPT_MODE_TYPE mode;
int oidSize, ivSize = 0, sizeofIV = 0, paramSize, status;
/* Extract the information that 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;
setMessageData( &msgData, iv, CRYPT_MAX_IVSIZE );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_IV );
#if 0 /* 18/4/04 No longer needed since IV is always set */
if( status == CRYPT_ERROR_NOTINITED && sIsNullStream( stream ) )
/* If we're just doing a length check there may not be an IV set
yet, so we just use dummy data */
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&ivSize, CRYPT_CTXINFO_IVSIZE );
else
#endif /* 0 */
ivSize = msgData.length;
sizeofIV = ( int ) sizeofObject( ivSize );
}
if( cryptStatusError( status ) )
{
assert( NOTREACHED );
return( status );
}
if( ( oid = algorithmToOIDcheck( algorithm,
( CRYPT_ALGO_TYPE ) mode ) ) == NULL )
/* Some algorithm+mode combinations can't be encoded using the
available PKCS #7 OIDs, the best that we can do is return a
CRYPT_ERROR_NOTAVAIL */
return( CRYPT_ERROR_NOTAVAIL );
oidSize = sizeofOID( oid );
/* Write the algorithm-specific parameters */
switch( algorithm )
{
case CRYPT_ALGO_3DES:
case CRYPT_ALGO_AES:
case CRYPT_ALGO_BLOWFISH:
case CRYPT_ALGO_DES:
{
const int noBits = ( algorithm == CRYPT_ALGO_AES ) ? 128 : 64;
paramSize = ( mode == CRYPT_MODE_ECB ) ? sizeofNull() : \
( ( mode == CRYPT_MODE_CBC ) || \
( algorithm == CRYPT_ALGO_AES && mode == CRYPT_MODE_OFB ) ) ? \
sizeofIV : \
( int ) sizeofObject( sizeofIV + sizeofShortInteger( noBits ) );
writeSequence( stream, oidSize + paramSize );
if( algorithm == CRYPT_ALGO_AES )
{
int keySize;
/* AES uses a somewhat odd encoding in which the last byte
of the OID jumps in steps of 20 depending on the key
size, so we adjust the OID that we actually write based
on the key size. It's somewhat unlikely that any
implementation actually cares about this since the size
information is always communicated anderswhere, but we do
it just in case */
krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&keySize, CRYPT_CTXINFO_KEYSIZE );
swrite( stream, oid, oidSize - 1 );
sputc( stream, oid[ oidSize - 1 ] + \
( ( keySize == 16 ) ? 0 : \
( keySize == 24 ) ? 20 : 40 ) );
}
else
swrite( stream, oid, oidSize );
if( mode == CRYPT_MODE_ECB )
return( writeNull( stream, DEFAULT_TAG ) );
if( ( mode == CRYPT_MODE_CBC ) || \
( algorithm == CRYPT_ALGO_AES && mode == CRYPT_MODE_OFB ) )
return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
writeSequence( stream, sizeofIV + sizeofShortInteger( noBits ) );
writeOctetString( stream, iv, ivSize, DEFAULT_TAG );
return( writeShortInteger( stream, noBits, DEFAULT_TAG ) );
}
case CRYPT_ALGO_CAST:
paramSize = sizeofIV + sizeofShortInteger( 128 );
writeSequence( stream, oidSize + \
( int ) sizeofObject( paramSize ) );
swrite( stream, oid, oidSize );
writeSequence( stream, paramSize );
writeOctetString( stream, iv, ivSize, DEFAULT_TAG );
return( writeShortInteger( stream, 128, DEFAULT_TAG ) );
case CRYPT_ALGO_IDEA:
paramSize = ( mode == CRYPT_MODE_ECB ) ? \
sizeofNull() : \
( int ) sizeofObject( sizeofIV );
writeSequence( stream, oidSize + paramSize );
swrite( stream, oid, oidSize );
if( mode == CRYPT_MODE_ECB )
return( writeNull( stream, DEFAULT_TAG ) );
writeSequence( stream, sizeofIV );
return( writeOctetString( stream, iv, ivSize, \
( mode == CRYPT_MODE_CFB ) ? \
3 : DEFAULT_TAG ) );
case CRYPT_ALGO_RC2:
paramSize = ( ( mode == CRYPT_MODE_ECB ) ? 0 : sizeofIV ) + \
sizeofShortInteger( RC2_KEYSIZE_MAGIC );
writeSequence( stream, oidSize + \
( int ) sizeofObject( paramSize ) );
swrite( stream, oid, oidSize );
writeSequence( stream, paramSize );
if( mode != CRYPT_MODE_CBC )
return( writeShortInteger( stream, RC2_KEYSIZE_MAGIC,
DEFAULT_TAG ) );
writeShortInteger( stream, RC2_KEYSIZE_MAGIC, DEFAULT_TAG );
return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
case CRYPT_ALGO_RC4:
writeSequence( stream, oidSize + sizeofNull() );
swrite( stream, oid, oidSize );
return( writeNull( stream, DEFAULT_TAG ) );
case CRYPT_ALGO_RC5:
paramSize = sizeofShortInteger( 16 ) + \
sizeofShortInteger( 12 ) + \
sizeofShortInteger( 64 ) + \
sizeofIV;
writeSequence( stream, oidSize + \
( int ) sizeofObject( paramSize ) );
swrite( stream, oid, oidSize );
writeSequence( stream, paramSize );
writeShortInteger( stream, 16, DEFAULT_TAG ); /* Version */
writeShortInteger( stream, 12, DEFAULT_TAG ); /* Rounds */
writeShortInteger( stream, 64, DEFAULT_TAG ); /* Block size */
return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
case CRYPT_ALGO_SKIPJACK:
writeSequence( stream, oidSize + \
( int ) sizeofObject( sizeofIV ) );
swrite( stream, oid, oidSize );
writeSequence( stream, sizeofIV );
return( writeOctetString( stream, iv, ivSize, DEFAULT_TAG ) );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/****************************************************************************
* *
* AlgorithmIdentifier Routines *
* *
****************************************************************************/
/* Because AlgorithmIdentifiers are only defined for a subset of the
algorithms that cryptlib supports, we have to check that the algorithm
and mode being used can be represented in encoded data before we try to
do anything with it */
BOOLEAN checkAlgoID( const CRYPT_ALGO_TYPE algorithm,
const CRYPT_MODE_TYPE mode )
{
return( ( algorithmToOIDcheck( algorithm, \
( CRYPT_ALGO_TYPE ) mode ) != NULL ) ? TRUE : FALSE );
}
/* Determine the size of an AlgorithmIdentifier record */
int sizeofAlgoIDex( const CRYPT_ALGO_TYPE algorithm,
const CRYPT_ALGO_TYPE subAlgorithm,
const int extraLength )
{
const BYTE *oid = algorithmToOID( algorithm, subAlgorithm );
if( oid == NULL )
{
assert( NOTREACHED );
return( 0 );
}
return( ( int ) sizeofObject( sizeofOID( oid ) + \
( ( extraLength > 0 ) ? extraLength : \
sizeofNull() ) ) );
}
int sizeofAlgoID( const CRYPT_ALGO_TYPE algorithm )
{
return( sizeofAlgoIDex( algorithm, CRYPT_ALGO_NONE, 0 ) );
}
/* Write an AlgorithmIdentifier record */
int writeAlgoIDex( STREAM *stream, const CRYPT_ALGO_TYPE algorithm,
const CRYPT_ALGO_TYPE subAlgorithm, const int extraLength )
{
const BYTE *oid = algorithmToOID( algorithm, subAlgorithm );
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
if( oid == NULL )
{
assert( NOTREACHED );
return( CRYPT_ERROR_WRITE );
}
/* Write the AlgorithmIdentifier field */
writeSequence( stream, sizeofOID( oid ) + \
( ( extraLength > 0 ) ? extraLength : sizeofNull() ) );
status = swrite( stream, oid, sizeofOID( oid ) );
if( extraLength <= 0 )
/* No extra parameters so we need to write a NULL */
status = writeNull( stream, DEFAULT_TAG );
return( status );
}
int writeAlgoID( STREAM *stream, const CRYPT_ALGO_TYPE algorithm )
{
return( writeAlgoIDex( stream, algorithm, CRYPT_ALGO_NONE, 0 ) );
}
/* Read an AlgorithmIdentifier record */
int readAlgoIDex( STREAM *stream, CRYPT_ALGO_TYPE *algorithm,
CRYPT_ALGO_TYPE *subAlgorithm, int *extraLength )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( algorithm == NULL || \
isWritePtr( algorithm, sizeof( CRYPT_ALGO_TYPE ) ) );
assert( subAlgorithm == NULL || \
isWritePtr( subAlgorithm, sizeof( CRYPT_ALGO_TYPE ) ) );
assert( extraLength == NULL || \
isWritePtr( extraLength, sizeof( int ) ) );
return( readAlgoIDheader( stream, algorithm, subAlgorithm, extraLength,
DEFAULT_TAG ) );
}
int readAlgoID( STREAM *stream, CRYPT_ALGO_TYPE *algorithm )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( algorithm == NULL || \
isWritePtr( algorithm, sizeof( CRYPT_ALGO_TYPE ) ) );
return( readAlgoIDheader( stream, algorithm, NULL, NULL, DEFAULT_TAG ) );
}
/* Determine the size of an AlgorithmIdentifier record from an encryption
context */
int sizeofContextAlgoID( const CRYPT_CONTEXT iCryptContext,
const CRYPT_ALGO_TYPE subAlgorithm,
const int flags )
{
int cryptAlgo, status;
assert( isHandleRangeValid( iCryptContext ) );
/* If it's a standard write, determine how large the algoID and
parameters are. Because this is a rather complex operation, the
easiest way to do it is to write to a null stream and get its
size */
if( flags == ALGOID_FLAG_NONE )
{
STREAM nullStream;
sMemOpen( &nullStream, NULL, 0 );
status = writeContextAlgoID( &nullStream, iCryptContext,
subAlgorithm, ALGOID_FLAG_NONE );
if( cryptStatusOK( status ) )
status = stell( &nullStream );
sMemClose( &nullStream );
return( status );
}
assert( flags == ALGOID_FLAG_ALGOID_ONLY );
/* Write the algoID only */
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
return( sizeofAlgoIDex( cryptAlgo, subAlgorithm, 0 ) );
}
/* Write an AlgorithmIdentifier record from an encryption context */
int writeContextAlgoID( STREAM *stream, const CRYPT_CONTEXT iCryptContext,
const CRYPT_ALGO_TYPE subAlgorithm,
const int flags )
{
int cryptAlgo, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isHandleRangeValid( iCryptContext ) );
status = krnlSendMessage( iCryptContext, IMESSAGE_GETATTRIBUTE,
&cryptAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
if( flags & ALGOID_FLAG_ALGOID_ONLY )
return( writeAlgoIDex( stream, cryptAlgo, subAlgorithm, 0 ) );
/* If we're writing parameters such as key and block sizes and IVs
alongside the algorithm identifier, it has to be a conventional
context */
assert( subAlgorithm == CRYPT_ALGO_NONE );
assert( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL );
return( writeContextCryptAlgoID( stream, iCryptContext ) );
}
/* Turn an AlgorithmIdentifier into a hash/encryption context */
int readContextAlgoID( STREAM *stream, CRYPT_CONTEXT *iCryptContext,
QUERY_INFO *queryInfo, const int tag )
{
QUERY_INFO localQueryInfo, *queryInfoPtr = ( queryInfo == NULL ) ? \
&localQueryInfo : queryInfo;
MESSAGE_CREATEOBJECT_INFO createInfo;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( iCryptContext == NULL || \
isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
assert( queryInfo == NULL || \
isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) );
/* Read the algorithm info. If we're not creating a context from the
info, we're done */
if( iCryptContext != NULL )
*iCryptContext = CRYPT_ERROR;
status = readAlgoIDInfo( stream, queryInfoPtr, tag );
if( cryptStatusError( status ) || iCryptContext == NULL )
{
if( status == CRYPT_ERROR_BADDATA || status == CRYPT_ERROR_UNDERFLOW )
/* It's a stream-related error, make it persistent */
sSetError( stream, status );
return( status );
}
/* Create the object from it */
setMessageCreateObjectInfo( &createInfo, queryInfoPtr->cryptAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
if( queryInfoPtr->cryptAlgo > CRYPT_ALGO_LAST_CONVENTIONAL )
{
/* If it's not a conventional encryption algorithm, we're done */
*iCryptContext = createInfo.cryptHandle;
return( CRYPT_OK );
}
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
&queryInfoPtr->cryptMode, CRYPT_CTXINFO_MODE );
if( cryptStatusOK( status ) && \
!isStreamCipher( queryInfoPtr->cryptAlgo ) )
{
int ivLength;
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_GETATTRIBUTE, &ivLength,
CRYPT_CTXINFO_IVSIZE );
if( cryptStatusOK( status ) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -