📄 misc_rw.c
字号:
/****************************************************************************
* *
* Miscellaneous (Non-ASN.1) Read/Write Routines *
* Copyright Peter Gutmann 1992-2004 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "crypt.h"
#include "bn.h"
#include "misc_rw.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../bn/bn.h"
#include "misc_rw.h"
#else
#include "crypt.h"
#include "bn/bn.h"
#include "misc/misc_rw.h"
#endif /* Compiler-specific includes */
/****************************************************************************
* *
* Utility Routines *
* *
****************************************************************************/
/* Read large integer data */
typedef enum { LENGTH_16U, LENGTH_16U_BITS,
LENGTH_32, LENGTH_32U_BITS } LENGTH_TYPE;
static int readInteger( STREAM *stream, void *integer, int *integerLength,
const int minLength, const int maxLength,
const LENGTH_TYPE lengthType )
{
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( integer == NULL || isWritePtr( integer, maxLength ) );
assert( integerLength == NULL || \
isWritePtr( integerLength, sizeof( int ) ) );
/* Clear return values */
if( integer != NULL )
{
*( ( BYTE * ) integer ) = '\0';
*integerLength = 0;
}
/* Read the length and make sure that it's within range, with allowance
for extra zero-padding */
if( lengthType == LENGTH_16U || lengthType == LENGTH_16U_BITS )
length = readUint16( stream );
else
length = readUint32( stream );
if( cryptStatusError( length ) )
return( length );
if( lengthType == LENGTH_16U_BITS || lengthType == LENGTH_32U_BITS )
length = bitsToBytes( length );
if( length < minLength || length > maxLength + 2 )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
/* If we're reading a signed integer, the sign bit can't be set, since
this would produce a negative value. This differs from the ASN.1
code, where the incorrect setting of the sign bit is so common that
we always treat integers as unsigned */
if( lengthType == LENGTH_32 && ( sPeek( stream ) & 0x80 ) )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
/* Skip possible leading-zero padding and repeat the length check once
the zero-padding has been adjusted */
while( length > 0 && sPeek( stream ) == 0 )
{
int status;
status = sgetc( stream );
if( cryptStatusError( status ) )
return( status );
length--;
}
if( length < minLength || length > maxLength )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
/* Read the value */
if( integer == NULL )
return( sSkip( stream, length ) );
*integerLength = length;
return( sread( stream, integer, length ) );
}
/****************************************************************************
* *
* Data Read Routines *
* *
****************************************************************************/
/* Read 16-, 32- and 64-bit integer values. Although in theory we could do
the 16-bit read more simply with ( sgetc( stream ) << 8 ) | sgetc( stream ),
this will break with some compilers that reorder expressions */
int readUint16( STREAM *stream )
{
BYTE buffer[ UINT16_SIZE + 8 ];
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
status = sread( stream, buffer, UINT16_SIZE );
if( cryptStatusError( status ) )
return( status );
return( ( ( int ) buffer[ 0 ] << 8 ) | buffer[ 1 ] );
}
int readUint32( STREAM *stream )
{
BYTE buffer[ UINT32_SIZE + 8 ];
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
status = sread( stream, buffer, UINT32_SIZE );
if( cryptStatusError( status ) )
return( status );
if( buffer[ 0 ] & 0x80 )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
return( ( ( int ) buffer[ 0 ] << 24 ) | \
( ( int ) buffer[ 1 ] << 16 ) | \
( ( int ) buffer[ 2 ] << 8 ) | \
buffer[ 3 ] );
}
int readUint64( STREAM *stream )
{
BYTE buffer[ ( UINT64_SIZE / 2 ) + 8 ];
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
status = sread( stream, buffer, UINT64_SIZE / 2 );
if( cryptStatusError( status ) )
return( status );
if( memcmp( buffer, "\x00\x00\x00\x00", UINT64_SIZE / 2 ) )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
return( readUint32( stream ) );
}
/* Read 32- and 64-bit time values. Note that we can't just call down
directly to readUint32() for these since time_t may be unsigned or of a
different integral size than int */
int readUint32Time( STREAM *stream, time_t *timeVal )
{
int value;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( timeVal, sizeof( time_t ) ) );
value = readUint32( stream );
if( cryptStatusError( value ) )
return( value );
*timeVal = ( time_t ) value;
return( CRYPT_OK );
}
int readUint64Time( STREAM *stream, time_t *timeVal )
{
int value;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( timeVal, sizeof( time_t ) ) );
value = readUint64( stream );
if( cryptStatusError( value ) )
return( value );
*timeVal = ( time_t ) value;
return( CRYPT_OK );
}
/* Read a string preceded by a 32-bit length */
int readString32( STREAM *stream, void *string, int *stringLength,
const int maxLength )
{
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( ( string == NULL && stringLength == NULL ) || \
( isWritePtr( string, maxLength ) && \
isWritePtr( stringLength, sizeof( int ) ) ) );
assert( maxLength >= 1 );
/* Clear return values */
if( string != NULL )
{
( ( char * ) string )[ 0 ] = '\0';
*stringLength = 0;
}
/* Read the string, limiting the size to the maximum buffer size */
length = readUint32( stream );
if( length <= 0 )
return( length ); /* Error or zero length */
if( length > maxLength )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
if( string == NULL )
return( sSkip( stream, length ) );
*stringLength = length;
return( sread( stream, string, length ) );
}
/* Read a raw object preceded by a 32-bit length */
int readRawObject32( STREAM *stream, void *buffer, int *bufferLength,
const int maxLength )
{
BYTE *bufPtr = buffer;
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( ( buffer == NULL && bufferLength == NULL ) || \
( isWritePtr( buffer, maxLength ) &&
isWritePtr( bufferLength, sizeof( int ) ) ) );
assert( maxLength >= UINT32_SIZE + 1 );
/* Clear return values */
if( buffer != NULL )
{
memset( buffer, 0, UINT32_SIZE );
*bufferLength = 0;
}
/* Read the string, limiting the size to the maximum buffer size */
length = readUint32( stream );
if( length <= 0 )
/* Error or zero length. If it's zero length we don't return any
data */
return( length );
if( length > maxLength - UINT32_SIZE )
return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
bufPtr[ 0 ] = ( length >> 24 ) & 0xFF;
bufPtr[ 1 ] = ( length >> 16 ) & 0xFF;
bufPtr[ 2 ] = ( length >> 8 ) & 0xFF;
bufPtr[ 3 ] = length & 0xFF;
if( buffer == NULL )
return( sSkip( stream, length ) );
*bufferLength = length + UINT32_SIZE;
return( sread( stream, bufPtr + UINT32_SIZE, length ) );
}
/* Read a universal type and discard it, used to skip unknown or unwanted
types */
static int readUniversal( STREAM *stream, const LENGTH_TYPE lengthType )
{
int length;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* Read the length and skip the data */
if( lengthType == LENGTH_16U )
length = readUint16( stream );
else
length = readUint32( stream );
if( length <= 0 )
/* Error or zero length */
return( length );
return( sSkip( stream, length ) );
}
int readUniversal16( STREAM *stream )
{
return( readUniversal( stream, LENGTH_16U ) );
}
int readUniversal32( STREAM *stream )
{
return( readUniversal( stream, LENGTH_32 ) );
}
/* Read (large) integers in various formats */
int readInteger16U( STREAM *stream, void *integer, int *integerLength,
const int minLength, const int maxLength )
{
return( readInteger( stream, integer, integerLength, minLength,
maxLength, LENGTH_16U ) );
}
int readInteger16Ubits( STREAM *stream, void *integer, int *integerLength,
const int minLength, const int maxLength )
{
return( readInteger( stream, integer, integerLength, minLength,
maxLength, LENGTH_16U_BITS ) );
}
int readInteger32( STREAM *stream, void *integer, int *integerLength,
const int minLength, const int maxLength )
{
return( readInteger( stream, integer, integerLength, minLength,
maxLength, LENGTH_32 ) );
}
int readInteger32Ubits( STREAM *stream, void *integer, int *integerLength,
const int minLength, const int maxLength )
{
return( readInteger( stream, integer, integerLength, minLength,
maxLength, LENGTH_32U_BITS ) );
}
/* Read bignum integers in various formats */
static int readBignumInteger( STREAM *stream, void *bignum,
const int minLength, const int maxLength,
const LENGTH_TYPE lengthType )
{
BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
int length, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( bignum, sizeof( BIGNUM ) ) );
assert( minLength >= 1 && maxLength <= CRYPT_MAX_PKCSIZE );
/* Read the integer data */
status = readInteger( stream, buffer, &length, minLength, maxLength,
lengthType );
if( cryptStatusError( status ) )
return( status );
/* Convert the value to a bignum */
if( BN_bin2bn( buffer, length, bignum ) == NULL )
{
sSetError( stream, CRYPT_ERROR_MEMORY );
status = CRYPT_ERROR_MEMORY;
}
zeroise( buffer, CRYPT_MAX_PKCSIZE );
return( status );
}
int readBignumInteger16U( STREAM *stream, void *bignum, const int minLength,
const int maxLength )
{
return( readBignumInteger( stream, bignum, minLength, maxLength,
LENGTH_16U ) );
}
int readBignumInteger16Ubits( STREAM *stream, void *bignum, const int minBits,
const int maxBits )
{
return( readBignumInteger( stream, bignum, bitsToBytes( minBits ),
bitsToBytes( maxBits ), LENGTH_16U_BITS ) );
}
int readBignumInteger32( STREAM *stream, void *bignum, const int minLength,
const int maxLength )
{
return( readBignumInteger( stream, bignum, minLength, maxLength,
LENGTH_32 ) );
}
/****************************************************************************
* *
* Data Write Routines *
* *
****************************************************************************/
/* Write 16-, 32- and 64-bit integer values */
int writeUint16( STREAM *stream, const int value )
{
assert( isWritePtr( stream, sizeof( STREAM ) ) );
sputc( stream, ( value >> 8 ) & 0xFF );
return( sputc( stream, value & 0xFF ) );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -