⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 misc_rw.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 2 页
字号:

int writeUint32( STREAM *stream, const int value )
	{
	BYTE buffer[ UINT32_SIZE + 8 ];

	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	buffer[ 0 ] = ( value >> 24 ) & 0xFF;
	buffer[ 1 ] = ( value >> 16 ) & 0xFF;
	buffer[ 2 ] = ( value >> 8 ) & 0xFF;
	buffer[ 3 ] = value & 0xFF;
	return( swrite( stream, buffer, UINT32_SIZE ) );
	}

int writeUint64( STREAM *stream, const int value )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	swrite( stream, "\x00\x00\x00\x00", UINT64_SIZE / 2 );
	return( writeUint32( stream, value ) );
	}

/* Write 32- and 64-bit time values */

int writeUint32Time( STREAM *stream, const time_t timeVal )
	{
	return( writeUint32( stream, ( int ) timeVal ) );
	}

int writeUint64Time( STREAM *stream, const time_t timeVal )
	{
	return( writeUint64( stream, ( int ) timeVal ) );
	}

/* Write a string preceded by a 32-bit length */

int writeString32( STREAM *stream, const void *string,
				   const int stringLength )
	{
	const int length = ( stringLength > 0 ) ? stringLength : \
											  strlen( string );

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( stringLength == 0 || \
			isReadPtr( string, stringLength ) );

	writeUint32( stream, length );
	return( swrite( stream, string, length ) );
	}

/* Write large integers in various formats */

static int writeInteger( STREAM *stream, const void *integer,
						 const int integerLength ,
						 const LENGTH_TYPE lengthType )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( integer, integerLength ) );

	switch( lengthType )
		{
		case LENGTH_16U:
			writeUint16( stream, integerLength );
			break;
		
		case LENGTH_16U_BITS:
			writeUint16( stream, bytesToBits( integerLength ) );
			break;

		case LENGTH_32:
			{
			const BOOLEAN leadingOneBit = ( ( BYTE * ) integer )[ 0 ] & 0x80;

			writeUint32( stream, integerLength + ( leadingOneBit ? 1 : 0 ) );
			if( leadingOneBit )
				sputc( stream, 0 );	/* MPIs are signed values */
			break;
			}
		
		case LENGTH_32U_BITS:
			writeUint32( stream, bytesToBits( integerLength ) );
			break;

		default:
			assert( NOTREACHED );
			return( CRYPT_ERROR_NOTAVAIL );
		}
	return( swrite( stream, integer, integerLength ) );
	}

int writeInteger16U( STREAM *stream, const void *integer,
					 const int integerLength )
	{
	return( writeInteger( stream, integer, integerLength, LENGTH_16U ) );
	}

int writeInteger16Ubits( STREAM *stream, const void *integer,
						 const int integerLength )
	{
	return( writeInteger( stream, integer, integerLength, LENGTH_16U_BITS ) );
	}

int writeInteger32( STREAM *stream, const void *integer,
					const int integerLength )
	{
	return( writeInteger( stream, integer, integerLength, LENGTH_32 ) );
	}

int writeInteger32Ubits( STREAM *stream, const void *integer,
						 const int integerLength )
	{
	return( writeInteger( stream, integer, integerLength, LENGTH_32U_BITS ) );
	}

/* Write bignum integers in various formats */

int sizeofBignumInteger32( const void *bignum )
	{
	return( UINT32_SIZE + BN_num_bytes( bignum ) + \
						  BN_high_bit( ( BIGNUM * ) bignum ) );
	}

static int writeBignumInteger( STREAM *stream, const void *bignum, 
							   const LENGTH_TYPE lengthType )
	{
	BYTE buffer[ CRYPT_MAX_PKCSIZE + 8 ];
	int bnLength, status;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( isReadPtr( bignum, sizeof( BIGNUM ) ) );

	bnLength = BN_bn2bin( bignum, buffer );
	switch( lengthType )
		{
		case LENGTH_16U:
			status = writeInteger( stream, buffer, bnLength, LENGTH_16U );
			break;

		case LENGTH_16U_BITS:
			/* We can't call down to writeInteger16Ubits() from here because 
			   we need to write a precise length in bits rather than a value 
			   reconstructed from the byte count */
			writeUint16( stream, BN_num_bits( bignum ) );
			status = swrite( stream, buffer, bnLength );
			break;

		case LENGTH_32:
			status = writeInteger( stream, buffer, bnLength, LENGTH_32 );
			break;

		default:
			assert( NOTREACHED );
			status = CRYPT_ERROR_NOTAVAIL;
		}
	zeroise( buffer, CRYPT_MAX_PKCSIZE );
	return( status );
	}

int writeBignumInteger16U( STREAM *stream, const void *bignum )
	{
	return( writeBignumInteger( stream, bignum, LENGTH_16U ) );
	}

int writeBignumInteger16Ubits( STREAM *stream, const void *bignum )
	{
	return( writeBignumInteger( stream, bignum, LENGTH_16U_BITS ) );
	}

int writeBignumInteger32( STREAM *stream, const void *bignum )
	{
	return( writeBignumInteger( stream, bignum, LENGTH_32 ) );
	}

/****************************************************************************
*																			*
*							PGP Read/Write Routines							*
*																			*
****************************************************************************/

/* PGP-specific read/write routines to read and write PGP variable-length 
   length values.  We also have a short-length version which is used to read 
   small packets such as keyrings and sigs and which ensures that the length 
   is in the range 1...16K */

#define PGP_CTB				0x80	/* PGP 2.x CTB template */
#define PGP_CTB_OPENPGP		0xC0	/* OpenPGP CTB template */
#define PGP_CTB_COMPRESSED	0xA3	/* Compressed indef-length data */

static long pgpReadLength( STREAM *stream, const int ctb )
	{
	long length;

	/* If it doesn't look like PGP data, don't go any further */
	if( !( ctb & PGP_CTB ) )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );

	/* If it's an OpenPGP CTB, undo the hand-Huffman-coding */
	if( ( ctb & PGP_CTB_OPENPGP ) == PGP_CTB_OPENPGP )
		{
		length = sgetc( stream );

		if( length >= 192 )
			{
			if( length <= 223 )
				{
				length = ( ( length - 192 ) << 8 ) + sgetc( stream ) + 192;
				if( !sStatusOK( stream ) )
					length = sGetStatus( stream );
				}
			else
				{
				if( length != 0xFF )
					/* It's an indefinite-length encoding.  These are an
					   incredible pain to handle and don't seem to be
					   used by anything (the only data type that would need
					   them, compressed data, uses the 2.x CTB 0xA3 instead)
					   so we don't try and do anything with it */
					return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
				length = readUint32( stream );
				}
			}
		}
	else
		/* It's a PGP 2.x CTB, decode the length as a byte, word, or long */
		switch( ctb & 3 )
			{
			case 0:
				length = sgetc( stream );
				break;

			case 1:
				length = readUint16( stream );
				break;

			case 2:
				length = readUint32( stream );
				break;

			default:
				/* A length value of 3 indicates that the data length is 
				   determined externally, this is a deprecated PGP 2.x value 
				   that we don't handle */
				return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
			}
	if( cryptStatusError( length ) )
		return( length );
	if( length < 0 || length > MAX_INTLENGTH )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	return( length );
	}

int pgpReadShortLength( STREAM *stream, const int ctb )
	{
	const long length = pgpReadLength( stream, ctb );

	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	if( cryptStatusError( length ) )
		return( length );
	if( length <= 0 || length > 16384 )
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	return( ( int ) length );
	}

int pgpWriteLength( STREAM *stream, const int length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	if( length <= 191 )
		return( sputc( stream, length ) );
	if( length <= 8383 )
		{
		const long adjustedLength = length - 192;

		sputc( stream, ( ( adjustedLength >> 8 ) & 0xFF ) + 192 );
		return( sputc( stream, ( adjustedLength & 0xFF ) ) );
		}
	sputc( stream, 0xFF );
	sputc( stream, ( length >> 24 ) & 0xFF );
	sputc( stream, ( length >> 16 ) & 0xFF );
	sputc( stream, ( length >> 8 ) & 0xFF );
	return( sputc( stream, ( length & 0xFF ) ) );
	}

int pgpReadPacketHeader( STREAM *stream, int *ctb, long *length )
	{
	long localLength;
	int localCTB;

	assert( isWritePtr( stream, sizeof( STREAM ) ) );
	assert( ctb == NULL || isWritePtr( ctb, sizeof( int ) ) );
	assert( length == NULL || isWritePtr( length, sizeof( long ) ) );

	/* Clear return values */
	if( ctb != NULL )
		*ctb = 0;
	if( length != NULL )
		*length = CRYPT_ERROR;

	/* We always need at least two more bytes to do anything */
	if( sMemDataLeft( stream ) < 2 )
		return( CRYPT_ERROR_UNDERFLOW );

	/* Peek at the CTB and figure out whether we've got enough data left to
	   read the header */
	localCTB = sPeek( stream );
	if( !( localCTB & PGP_CTB ) )
		/* If it doesn't look like PGP data, don't go any further */
		return( sSetError( stream, CRYPT_ERROR_BADDATA ) );
	if( ( localCTB & PGP_CTB_OPENPGP ) == PGP_CTB_OPENPGP )
		{
		/* OpenPGP has an awkward variable-length encoding which requires
		   that we burrow further down into the data to get the actual
		   length, to avoid problems with having to undo this we assume a
		   worst-case length of 5 bytes.  This is safe because the shortest
		   possible packet type, a conventionally-encrypted data packet with
		   a 1-byte payload, contains a minimum of 11 bytes of data (8-byte
		   IV, 2 bytes of repeated IV data, and 1 byte of payload) */
		if( sMemDataLeft( stream ) < 5 )
			return( CRYPT_ERROR_UNDERFLOW );
		}
	else
		{
		static const int lengthOfLength[ 4 ] = { 1, 2, 4, 0 };

		/* If it's a compressed data packet, there's no length present.  
		   Normally we reject any indefinite-length packets since these 
		   can't be processed sensibly (PGP 2.x, which used intermediate 
		   files for everything, just read to EOF, OpenPGP deprecates them 
		   because this doesn't exactly lead to portable implementations).  
		   However, compressed-data packets can only be stored in this 
		   manner but can still be processed because the user has to 
		   explicitly flush the data at some point and we assume that this 
		   is EOF.  This isn't anywhere near as clean as the PKCS #7/CMS/
		   SMIME equivalent where we've got an explicit end-of-data 
		   indication, but it does the trick */
		if( localCTB == PGP_CTB_COMPRESSED )
			{
			sgetc( stream );	/* Skip CTB */
			if( ctb != NULL )
				*ctb = localCTB;
			if( length != NULL )
				*length = CRYPT_UNUSED;
			return( CRYPT_OK );
			}

		/* PGP 2.x has a predictable variable-length length encoding so we
		   can easily check whether there's enough data left */
		if( sMemDataLeft( stream ) < lengthOfLength[ localCTB & 3 ] )
			return( CRYPT_ERROR_UNDERFLOW );
		}

	/* Now that we know the format, get the length information */
	sgetc( stream );			/* Skip CTB */
	localLength = pgpReadLength( stream, localCTB );
	if( cryptStatusError( localLength ) )
		return( localLength );
	if( ctb != NULL )
		*ctb = localCTB;
	if( length != NULL )
		*length = localLength;

	return( CRYPT_OK );
	}

int pgpWritePacketHeader( STREAM *stream, const int packetType,
						  const long length )
	{
	assert( isWritePtr( stream, sizeof( STREAM ) ) );

	sputc( stream, PGP_CTB_OPENPGP | packetType );
	return( pgpWriteLength( stream, length ) );
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -