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

📄 base64.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 3 页
字号:
	assert( isWritePtr( destLen, sizeof( int ) ) );
	assert( srcLen > 10 && isReadPtr( src, srcLen ) );

	REQUIRES( destMaxLen > 10 && destMaxLen < MAX_INTLENGTH );
	REQUIRES( srcLen > 10 && srcLen < MAX_INTLENGTH );
	REQUIRES( format >= CRYPT_CERTFORMAT_NONE && \
			  format < CRYPT_CERTFORMAT_LAST );

	/* Clear return values */
	memset( dest, 0, min( 16, destMaxLen ) );
	*destLen = 0;

	sMemOpen( &stream, dest, destMaxLen );

	/* If it's not a certificate, it's a straight base64 string and we can
	   use the simplified decoding routines */
	if( format == CRYPT_CERTFORMAT_NONE )
		{
		status = fixedBase64decode( &stream, src, srcLen );
		if( cryptStatusOK( status ) )
			*destLen = stell( &stream );
		sMemDisconnect( &stream );
		return( status );
		}

	/* Decode the encoded object.  Since we're processing arbitrary-sized 
	   input we can't use the usual FAILSAFE_ITERATIONS_MAX to bound the 
	   loop because the input could be larger than this so we use 
	   MAX_INTLENGTH instead */
	for( srcIndex = 0, lineByteCount = 0;
		 srcIndex < srcLen && srcIndex < MAX_INTLENGTH;
		 srcIndex += 4, lineByteCount += 4 )
		{
		/* Depending on implementations, the length of the base64-encoded
		   line can vary from 60 to 72 characters.  We adjust for this by
		   checking for the first EOL and setting the line length to the
		   size of the first line of base64 text */
		if( lineSize <= 0 && \
			( src[ srcIndex ] == '\r' || src[ srcIndex ] == '\n' ) )
			{
			if( lineByteCount < 56 || lineByteCount > 128 )
				{
				/* Suspiciously short or long text line */
				sMemDisconnect( &stream );
				return( CRYPT_ERROR_BADDATA );
				}
			lineSize = lineByteCount;
			}

		/* If we've reached the end of a line of text, look for the EOL
		   marker */
		if( lineSize > 0 && lineByteCount >= lineSize )
			{
			int eolDataSize;

			status = checkEOL( src + srcIndex, srcLen - srcIndex, 
							   &eolDataSize, format );
			if( cryptStatusError( status ) )
				{
				/* If we get an OK_SPECIAL status it means that we've 
				   reached the EOF rather than just an EOL */
				if( status == OK_SPECIAL )
					{
					status = CRYPT_OK;
					break;
					}

				sMemDisconnect( &stream );
				return( status );
				}
			srcIndex += eolDataSize;
			lineByteCount = 0;
			}

		/* Decode a chunk of data from the input buffer */
		status = decodeBase64chunk( &stream, src + srcIndex, 
									srcLen - srcIndex, FALSE );
		if( cryptStatusError( status ) )
			{
			/* If we've reached the end of the input, we're done.  Note that 
			   we can't just wait for srcIndex to pass srcLen as for the 
			   fixed-length decode because there could be extra trailer data 
			   following the base64 data.

			   In theory we could call checkEOL() here to make sure that the
			   trailer is well-formed but if the data is truncated right on
			   the base64 end marker then this would produce an error so we
			   just stop decoding as soon as we find the end marker */
			if( status == OK_SPECIAL )
				{
				status = CRYPT_OK;
				break;
				}

			sMemDisconnect( &stream );
			return( status );
			}
		}
	ENSURES( srcIndex < MAX_INTLENGTH );
	if( cryptStatusOK( status ) )
		*destLen = stell( &stream );
	sMemDisconnect( &stream );

	return( CRYPT_OK );
	}

/* Calculate the size of a quantity of data once it's en/decoded */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
int base64decodeLen( IN_BUFFER( dataLength ) const char *data, 
					 IN_LENGTH_MIN( 10 ) const int dataLength,
					 OUT_LENGTH_Z int *decodedLength )
	{
	STREAM stream;
	int ch, length = DUMMY_INIT, iterationCount;

	assert( isReadPtr( data, dataLength ) );
	assert( isWritePtr( decodedLength, sizeof( int ) ) );

	REQUIRES( dataLength >= 10 && dataLength < MAX_INTLENGTH );

	/* Clear return value */
	*decodedLength = 0;

	/* Skip ahead until we find the end of the decodable data.  This ignores 
	   errors on the input stream since at this point all that we're 
	   interested in is how much we can decode from it and not whether it's 
	   valid or not.  Handling this gets a bit complicated since once the 
	   stream enters an error state stell() doesn't try and return a stream 
	   position any more because the stream is in the error state, so we have 
	   to check the position before every read.
	   
	   Since we're processing arbitrary-sized input we can't use the usual
	   FAILSAFE_ITERATIONS_MAX to bound the loop because the input could be
	   larger than this so we use MAX_INTLENGTH instead */
	sMemConnect( &stream, data, dataLength );
	for( iterationCount = 0; iterationCount < MAX_INTLENGTH; iterationCount++ )
		{
		length = stell( &stream );
		ch = sgetc( &stream );
		if( cryptStatusError( ch ) || ch == BPAD )
			break;
		if( ch == '\r' || ch == '\n' )
			{
			/* Don't try and decode out-of-band data */
			continue;
			}
		ch = decode( ch );
		if( ch == BERR || ch == BEOF )
			break;
		}
	ENSURES( iterationCount < MAX_INTLENGTH );
	sMemDisconnect( &stream );

	/* Return a rough estimate of how much room the decoded data will occupy.
	   This ignores the EOL size so it always overestimates, but a strict
	   value isn't necessary since it's only used for memory buffer
	   allocation */
	*decodedLength = ( length * 3 ) / 4;

	return( CRYPT_OK );
	}

/****************************************************************************
*																			*
*							Base64 Encoding Functions						*
*																			*
****************************************************************************/

/* Calculate the size of a quantity of data once it's encoded */

CHECK_RETVAL STDC_NONNULL_ARG( ( 2 ) ) \
int base64encodeLen( IN_LENGTH_MIN( 10 ) const int dataLength,
					 OUT_LENGTH_Z int *encodedLength,
					 IN_ENUM_OPT( CRYPT_CERTTYPE ) \
						const CRYPT_CERTTYPE_TYPE certType )
	{
	int length = roundUp( ( dataLength * 4 ) / 3, 4 ), headerInfoIndex;

	assert( isWritePtr( encodedLength, sizeof( int ) ) );

	REQUIRES( dataLength >= 10 && dataLength < MAX_INTLENGTH );
	REQUIRES( certType >= CRYPT_CERTTYPE_NONE && \
			  certType < CRYPT_CERTTYPE_LAST );
	
	ENSURES( length >= 10 && length < MAX_INTLENGTH );

	/* Clear return value */
	*encodedLength = 0;

	/* Find the header/trailer info for this format */
	for( headerInfoIndex = 0;
		 headerInfo[ headerInfoIndex ].type != certType && \
			headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE && \
			headerInfoIndex < FAILSAFE_ARRAYSIZE( headerInfo, HEADER_INFO ); 
		 headerInfoIndex++ );
	ENSURES( headerInfoIndex < FAILSAFE_ARRAYSIZE( headerInfo, HEADER_INFO ) );
	ENSURES( headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE );

	/* Calculate the extra length due to EOLs and delimiters */
	length += ( ( roundUp( length, BASE64_LINESIZE ) / BASE64_LINESIZE ) * EOL_LEN );
	length = headerInfo[ headerInfoIndex ].headerLen + length + \
			 headerInfo[ headerInfoIndex ].trailerLen;

	ENSURES( length > 10 && length < MAX_INTLENGTH );

	*encodedLength = length;

	return( CRYPT_OK );
	}

/* Encode a block of binary data into the base64 format */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
int base64encode( OUT_BUFFER( destMaxLen, *destLen ) char *dest, 
				  IN_LENGTH_MIN( 10 ) const int destMaxLen, 
				  OUT_LENGTH_Z int *destLen,
				  IN_BUFFER( srcLen ) const void *src, 
				  IN_LENGTH_MIN( 10 ) const int srcLen, 
				  IN_ENUM_OPT( CRYPT_CERTTYPE ) \
					const CRYPT_CERTTYPE_TYPE certType )
	{
	STREAM stream;
	const BYTE *srcPtr = src;
	int srcIndex, lineByteCount, remainder = srcLen % 3;
	int headerInfoIndex = DUMMY_INIT, status = DUMMY_INIT;

	assert( destMaxLen > 10 && isWritePtr( dest, destMaxLen ) );
	assert( isWritePtr( destLen, sizeof( int ) ) );
	assert( srcLen >= 10 && isReadPtr( src, srcLen ) );

	REQUIRES( destMaxLen >= 10 && destMaxLen > srcLen && \
			  destMaxLen < MAX_INTLENGTH );
	REQUIRES( srcLen >= 10 && srcLen < MAX_INTLENGTH );
	REQUIRES( certType >= CRYPT_CERTTYPE_NONE && \
			  certType < CRYPT_CERTTYPE_LAST );

	/* Clear return values */
	memset( dest, 0, min( 16, destMaxLen ) );
	*destLen = 0;

	sMemOpen( &stream, dest, destMaxLen );

	/* If it's an encoded certificate object rather than raw base64 data, 
	   add the header */
	if( certType != CRYPT_CERTTYPE_NONE )
		{
		for( headerInfoIndex = 0;
			 headerInfo[ headerInfoIndex ].type != certType && \
				headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE && \
				headerInfoIndex < FAILSAFE_ARRAYSIZE( headerInfo, HEADER_INFO );
			 headerInfoIndex++ );
		ENSURES( headerInfoIndex < FAILSAFE_ARRAYSIZE( headerInfo, HEADER_INFO ) );
		ENSURES( headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE );
		status = swrite( &stream, headerInfo[ headerInfoIndex ].header, 
						 headerInfo[ headerInfoIndex ].headerLen );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			return( status );
			}
		}

	/* Encode the data */
	for( srcIndex = 0, lineByteCount = 0; 
		 srcIndex < srcLen; 
		 lineByteCount += 4 )
		{
		const int srcLeft = srcLen - srcIndex;

		/* If we've reached the end of a line of binary data and it's a
		   certificate object rather than a raw binary blob, add the EOL 
		   marker */
		if( certType != CRYPT_CERTTYPE_NONE && \
			lineByteCount >= BASE64_LINESIZE )
			{
			status = swrite( &stream, EOL, EOL_LEN );
			if( cryptStatusError( status ) )
				{
				sMemDisconnect( &stream );
				return( status );
				}
			lineByteCount = 0;
			}

		/* Encode a block of data from the input buffer */
		sputc( &stream, encode( ( srcPtr[ srcIndex ] >> 2 ) & 0x3F ) );
		if( srcLeft < 2 )
			{
			REQUIRES( remainder == 1 );
			status = sputc( &stream, encode( ( srcPtr[ srcIndex ] << 4 ) & 0x30 ) );
			break;
			}
		sputc( &stream, encode( ( ( srcPtr[ srcIndex ] << 4 ) & 0x30 ) | \
								( ( srcPtr[ srcIndex + 1 ] >> 4 ) & 0x0F ) ) );
		srcIndex++;
		if( srcLeft < 3 )
			{
			REQUIRES( remainder == 2 );
			status = sputc( &stream, encode( ( srcPtr[ srcIndex ] << 2 ) & 0x3C ) );
			break;
			}
		sputc( &stream, encode( ( ( srcPtr[ srcIndex ] << 2 ) & 0x3C ) | \
								( ( srcPtr[ srcIndex + 1 ] >> 6 ) & 0x03 ) ) );
		srcIndex++;
		status = sputc( &stream, encode( srcPtr[ srcIndex++ ] & 0x3F ) );
		if( cryptStatusError( status ) )
			break;
		}
	if( cryptStatusError( status ) )
		{
		sMemDisconnect( &stream );
		return( status );
		}

	/* If it's a certificate object, add any required padding and the 
	   trailer */
	if( certType != CRYPT_CERTTYPE_NONE )
		{
		/* Add any necessary padding.  For 0 bytes of remainder there's no 
		   padding (the data fits exactly), for 1 byte of remainder there's 
		   2 bytes of padding ("X=="), and for 2 bytes of remainder there's 
		   1 byte of padding ("XX=") */
		if( remainder > 0 )
			{
			status = sputc( &stream, BPAD );
			if( remainder == 1 )
				status = sputc( &stream, BPAD );
			if( cryptStatusError( status ) )
				{
				sMemDisconnect( &stream );
				return( status );
				}
			}

		/* Add the trailer */
		swrite( &stream, EOL, EOL_LEN );
		status = swrite( &stream, headerInfo[ headerInfoIndex ].trailer, 
						 headerInfo[ headerInfoIndex ].trailerLen );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			return( status );
			}
		}
	*destLen = stell( &stream );
	sMemDisconnect( &stream );

	return( CRYPT_OK );
	}

⌨️ 快捷键说明

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