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

📄 base64.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 3 页
字号:
   S/MIME certificate data this can in theory get quite complex because
   there are many possible variations in the headers.  Some early S/MIME
   agents used a content type of "application/x-pkcs7-mime",
   "application/x-pkcs7-signature", and "application/x-pkcs10", while newer
   ones use the same without the "x-" at the start.  In addition Netscape
   have their own MIME data types for certificates, "application/x-x509-"
   "{user-cert|ca-cert|email-cert}, and there are further types in the
   endless stream of RFCs that PKIX churns out.  There are a whole pile of
   other possible headers as well, none of them terribly relevant for our
   purposes, so all we check for is the base64 indicator */
   
CRYPT_CERTFORMAT_TYPE base64checkHeader( const char *data,
										 const int dataLength, int *startPos )
	{
	STREAM stream;
	BOOLEAN seenTransferEncoding = FALSE, isBinaryEncoding = FALSE;
	int position, ch, status;

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

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

	/* If the item is too small to contain any useful data, we don't even try
	   and examine it */
	if( dataLength < 64 )
		return( CRYPT_CERTFORMAT_NONE );

	sMemConnect( &stream, data, dataLength );

	/* Sometimes the object can be preceded by a few blank lines.  We're
	   fairly lenient with this.  Note that we can't use readLine() at this
	   point because we don't know yet whether we're getting binary or ASCII
	   data */
	do
		ch = sgetc( &stream );
	while( ch == '\r' || ch == '\n' );
	position = stell( &stream ) - 1;

	/* Perform a quick check to weed out non-encoded cert data, which is
	   usually the case */
	if( ( ch == 0x30 ) && ( !isAlpha( sgetc( &stream ) ) || \
							!isAlpha( sgetc( &stream ) ) || \
							!isAlpha( sgetc( &stream ) ) ) )
		{
		sMemDisconnect( &stream );
		return( CRYPT_CERTFORMAT_NONE );
		}
	sseek( &stream, position );

	/* If it starts with a dash, check for PEM header encapsulation */
	if( ch == '-' )
		{
		status = checkPEMHeader( &stream, startPos );
		if( cryptStatusError( status ) )
			{
			sMemDisconnect( &stream );
			return( status );
			}
		if( checkBase64( &stream ) )
			{
			sMemDisconnect( &stream );
			return( CRYPT_CERTFORMAT_TEXT_CERTIFICATE );
			}
		}

	/* Check for raw base64 data */
	if( checkBase64( &stream ) )
		{
		sMemDisconnect( &stream );
		*startPos = position;
		return( CRYPT_CERTFORMAT_TEXT_CERTIFICATE );
		}
	sseek( &stream, position );

	/* It doesn't look like raw base64, check for an S/MIME header */
	do
		{
		char buffer[ 1024 ];

		status = readLine( &stream, buffer, 1024 );
		if( !cryptStatusError( status ) && status >= 33 && \
			!strCompare( buffer, "Content-Transfer-Encoding:", 26 ) )
			{
			int index;

			/* Check for a valid content encoding type */
			for( index = 26; index < status && buffer[ index ] == ' '; 
				 index++ );
			if( status - index < 6 )
				/* It's too short to be a valid encoding type, skip it */
				continue;	
			if( !strCompare( buffer + index, "base64", 6 ) )
				seenTransferEncoding = TRUE;
			else
				if( !strCompare( buffer + index, "binary", 6 ) )
					seenTransferEncoding = isBinaryEncoding = TRUE;
			}
		}
	while( status > 0 );
	if( cryptStatusError( status ) || !seenTransferEncoding )
		{
		sMemDisconnect( &stream );
		return( CRYPT_CERTFORMAT_NONE );
		}

	/* Skip trailing blank lines */
	do
		ch = sgetc( &stream );
	while( ch == '\r' || ch == '\n' );
	position = stell( &stream ) - 1;
	sseek( &stream, position );

	/* Make sure that the content is some form of encoded cert */
	*startPos = position;
	status = isBinaryEncoding ? CRYPT_CERTFORMAT_CERTIFICATE : \
			 checkBase64( &stream ) ? CRYPT_ICERTFORMAT_SMIME_CERTIFICATE : \
									  CRYPT_CERTFORMAT_NONE;
	sMemDisconnect( &stream );
	return( status );
	}

/* Encode a block of binary data into the base64 format, returning the total
   number of output bytes */

int base64encode( char *dest, const int destMaxLen, const void *src, 
				  const int srcLen, const CRYPT_CERTTYPE_TYPE certType )
	{
	BYTE *srcPtr = ( BYTE * ) src;
	int srcIndex = 0, destIndex = 0, lineCount = 0, remainder = srcLen % 3;
	int headerInfoIndex;

	assert( destMaxLen > 10 && isWritePtr( dest, destMaxLen ) );
	assert( srcLen > 10 && isReadPtr( src, srcLen ) );

	/* If it's a certificate object, add the header */
	if( certType != CRYPT_CERTTYPE_NONE )
		{
		for( headerInfoIndex = 0;
			 headerInfo[ headerInfoIndex ].type != certType && \
				headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE;
			 headerInfoIndex++ );
		assert( headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE );
		destIndex = strlen( headerInfo[ headerInfoIndex ].header );
		if( destIndex > destMaxLen )
			return( CRYPT_ERROR_OVERFLOW );
		memcpy( dest, headerInfo[ headerInfoIndex ].header, destIndex );
		}

	/* Encode the data */
	while( srcIndex < srcLen )
		{
		/* If we've reached the end of a line of binary data and it's a
		   certificate, add the EOL marker */
		if( certType != CRYPT_CERTTYPE_NONE && lineCount >= BINARY_LINESIZE )
			{
			strcpy( dest + destIndex, EOL );
			destIndex += EOL_LEN;
			lineCount = 0;
			}
		lineCount += 3;

		/* Encode a block of data from the input buffer */
		dest[ destIndex++ ] = encode( srcPtr[ srcIndex ] >> 2 );
		dest[ destIndex++ ] = encode( ( ( srcPtr[ srcIndex ] << 4 ) & 0x30 ) |
									  ( ( srcPtr[ srcIndex + 1 ] >> 4 ) & 0x0F ) );
		srcIndex++;
		dest[ destIndex++ ] = encode( ( ( srcPtr[ srcIndex ] << 2 ) & 0x3C ) |
									  ( ( srcPtr[ srcIndex + 1 ] >> 6 ) & 0x03 ) );
		srcIndex++;
		dest[ destIndex++ ] = encode( srcPtr[ srcIndex++ ] & 0x3F );
		if( destIndex > destMaxLen )
			return( CRYPT_ERROR_OVERFLOW );
		}

	/* Go back and add padding and correctly encode the last char if we've
	   encoded too many characters */
	if( remainder == 2 )
		{
		/* There were only 2 bytes in the last group */
		dest[ destIndex - 1 ] = BPAD;
		dest[ destIndex - 2 ] = \
					encode( ( srcPtr[ srcIndex - 2 ] << 2 ) & 0x3C );
		}
	else
		if( remainder == 1 )
			{
			/* There was only 1 byte in the last group */
			dest[ destIndex - 2 ] = dest[ destIndex - 1 ] = BPAD;
			dest[ destIndex - 3 ] = \
					encode( ( srcPtr[ srcIndex - 3 ] << 4 ) & 0x30 );
			}

	/* If it's a certificate object, add the trailer */
	if( certType != CRYPT_CERTTYPE_NONE )
		{
		const int length = strlen( headerInfo[ headerInfoIndex ].trailer );

		if( destIndex + EOL_LEN + length > destMaxLen )
			return( CRYPT_ERROR_OVERFLOW );
		memcpy( dest + destIndex, EOL, EOL_LEN );
		memcpy( dest + destIndex + EOL_LEN,
				headerInfo[ headerInfoIndex ].trailer, length );
		destIndex += EOL_LEN + length;
		}
	else
		/* It's not a certificate, truncate the unnecessary padding */
		destIndex -= ( 3 - remainder ) % 3;

	/* Return a count of encoded bytes */
#ifdef EBCDIC_CHARS
	asciiToEbcdic( dest, dest, length );
#endif /* EBCDIC_CHARS */
	return( destIndex );
	}

/* Decode a block of binary data from the base64 format, returning the total
   number of decoded bytes */

static int fixedBase64decode( void *dest, const int destMaxLen, 
							  const char *src, const int srcLen )
	{
	int srcIndex = 0, destIndex = 0;
	BYTE *destPtr = dest;

	/* Decode the base64 string as a fixed-length continuous string without
	   padding or newlines */
	while( srcIndex < srcLen )
		{
		BYTE c0, c1, c2 = 0, c3 = 0;
		const int delta = srcLen - srcIndex;

		/* Decode a block of data from the input buffer */
		c0 = decode( src[ srcIndex++ ] );
		c1 = decode( src[ srcIndex++ ] );
		if( delta > 2 )
			{
			c2 = decode( src[ srcIndex++ ] );
			if( delta > 3 )
				c3 = decode( src[ srcIndex++ ] );
			}
		if( ( c0 | c1 | c2 | c3 ) == BERR )
			return( CRYPT_ERROR_BADDATA );

		/* Copy the decoded data to the output buffer */
		destPtr[ destIndex++ ] = ( c0 << 2 ) | ( c1 >> 4 );
		if( delta > 2 )
			{
			destPtr[ destIndex++ ] = ( c1 << 4 ) | ( c2 >> 2);
			if( delta > 3 )
				destPtr[ destIndex++ ] = ( c2 << 6 ) | ( c3 );
			}
		if( destIndex > destMaxLen )
			return( CRYPT_ERROR_OVERFLOW );
		}

	/* Return count of decoded bytes */
	return( destIndex );
	}

int base64decode( void *dest, const int destMaxLen, const char *src, 
				  const int srcLen, const CRYPT_CERTFORMAT_TYPE format )
	{
	int srcIndex = 0, destIndex = 0, lineCount = 0, lineSize = 0;
	BYTE c0, c1, c2, c3, *destPtr = dest;

	assert( destMaxLen > 10 && isWritePtr( dest, destMaxLen ) );
	assert( srcLen > 10 && isReadPtr( src, srcLen ) );

	/* 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 )
		return( fixedBase64decode( dest, destMaxLen, src, srcLen ) );

	/* Decode the encoded object */
	while( srcIndex < srcLen )
		{
		BYTE cx;

		/* Depending on implementations, the length of the base64-encoded
		   line can vary from 60 to 72 chars, we adjust for this by checking
		   for an EOL and setting the line length to this size */
		if( !lineSize && \
			( src[ srcIndex ] == '\r' || src[ srcIndex ] == '\n' ) )
			lineSize = lineCount;

		/* If we've reached the end of a line of text, look for the EOL
		   marker.  There's one problematic special case here where, if the
		   encoding has produced bricktext, the end of the data will 
		   coincide with the EOL.  For CRYPT_CERTFORMAT_TEXT_CERTIFICATE 
		   this will give us '-----END...' on the next line which is easy to 
		   check for, but for CRYPT_ICERTFORMAT_SMIME_CERTIFICATE what we 
		   end up with depends on the calling code, it could truncate 
		   immediately at the end of the data (which it isn't supposed to) 
		   so we get '\0', it could truncate after the EOL (so we get EOL + 
		   '\0'), it could continue with a futher content type after a blank 
		   line (so we get EOL + EOL), or it could truncate without the '\0' 
		   so we get garbage, which is the caller's problem.  Because of 
		   this we look for all of these situations and, if any are found, 
		   set c0 to BEOF and advance srcIndex by 4 to take into account the 
		   adjustment for overshoot that occurs when we break out of the 
		   loop */
		if( lineCount >= lineSize )
			{
			/* Check for '\0' at the end of the data */
			if( format == CRYPT_ICERTFORMAT_SMIME_CERTIFICATE && \
				!src[ srcIndex ] )
				{
				c0 = c1 = c2 = BEOF;
				srcIndex += 4;
				break;
				}

			/* Check for EOL */
			if( src[ srcIndex ] == '\n' )
				srcIndex++;

⌨️ 快捷键说明

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