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

📄 base64.c

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

#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "stream.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "../io/stream.h"
#else
  #include "crypt.h"
  #include "io/stream.h"
#endif /* Compiler-specific includes */

/* Base64 encode/decode tables from RFC 1113.  We convert from ASCII <-> 
   EBCDIC on entry and exit, so there's no need for special-case EBCDIC
   handling elsewhere */

#define BPAD		'='		/* Padding for odd-sized output */
#define BERR		0xFF	/* Illegal char marker */
#define BEOF		0x7F	/* EOF marker (padding char or EOL) */

static const FAR_BSS char binToAscii[] = \
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const FAR_BSS BYTE asciiToBin[ 256 ] =
	{ BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 00 */
	  BERR, BERR, BEOF, BERR, BERR, BEOF, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 10 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 20 */
	  BERR, BERR, BERR, 0x3E, BERR, BERR, BERR, 0x3F,
	  0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,	/* 30 */
	  0x3C, 0x3D, BERR, BERR, BERR, BEOF, BERR, BERR,
	  BERR, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,	/* 40 */
	  0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
	  0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,	/* 50 */
	  0x17, 0x18, 0x19, BERR, BERR, BERR, BERR, BERR,
	  BERR, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,	/* 60 */
	  0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
	  0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,	/* 70 */
	  0x31, 0x32, 0x33, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 80 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 90 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* A0 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* B0 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* C0 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* D0 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* E0 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* F0 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR
	};

#if 0

/* EBCDIC character mappings:
		A-I C1-C9
		J-R D1-D9
		S-Z E2-E9
		a-i 81-89
		j-r 91-99
		s-z A2-A9
		0-9 F0-F9
		+   4E
		/   61
		=   7E  Uses BEOF in table */

static const FAR_BSS BYTE asciiToBin[ 256 ] =
	{ BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 00 */
	  BERR, BERR, BEOF, BERR, BERR, BEOF, BERR, BERR,		/*	CR, LF */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 10 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 20 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 30 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 40 */
	  BERR, BERR, BERR, BERR, BERR, BERR, 0x3E, BERR,		/*	+ */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 50 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, 0x3F, BERR, BERR, BERR, BERR, BERR, BERR,	/* 60	/ */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* 70 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BEOF, BERR,		/*	= */
	  BERR, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,	/* 80	a-i */
	  0x21, 0x22, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,	/* 90	j-r */
	  0x2A, 0x2B, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31,	/* A0	s-z */
	  0x32, 0x33, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,	/* B0 */
	  BERR, BERR, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,	/* C0	A-I */
	  0x07, 0x08, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,	/* D0	J-R */
	  0x10, 0x11, BERR, BERR, BERR, BERR, BERR, BERR,
	  BERR, BERR, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,	/* E0	S-Z */
	  0x18, 0x19, BERR, BERR, BERR, BERR, BERR, BERR,
	  0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,	/* F0	0-9 */
	  0x3C, 0x3D, BERR, BERR, BERR, BERR, BERR, BERR
	};
#endif /* 0 */

/* The size of lines for PEM-type formatting.  This is only used for encoding,
   for decoding we adjust to whatever size the sender has used */

#define TEXT_LINESIZE	64
#define BINARY_LINESIZE	48

/* Basic single-char en/decode functions.  We cast the value to an unsigned
   char to avoid generating negative array offsets if the sign bit is set,
   since the strings are passed as char *'s */

#define encode(data)	binToAscii[ ( BYTE ) data ]
#define decode(data)	asciiToBin[ ( BYTE ) data ]

/* The headers and trailers used for base64-encoded certificate objects */

static const FAR_BSS struct {
	const CRYPT_CERTTYPE_TYPE type;
	const char *header, *trailer;
	} headerInfo[] = {
	{ CRYPT_CERTTYPE_CERTIFICATE,
	  "-----BEGIN CERTIFICATE-----" EOL,
	  "-----END CERTIFICATE-----" EOL },
	{ CRYPT_CERTTYPE_ATTRIBUTE_CERT,
	  "-----BEGIN ATTRIBUTE CERTIFICATE-----" EOL,
	  "-----END ATTRIBUTE CERTIFICATE-----" EOL },
	{ CRYPT_CERTTYPE_CERTCHAIN,
	  "-----BEGIN CERTIFICATE CHAIN-----" EOL,
	  "-----END CERTIFICATE CHAIN-----" EOL },
	{ CRYPT_CERTTYPE_CERTREQUEST,
	  "-----BEGIN NEW CERTIFICATE REQUEST-----" EOL,
	  "-----END NEW CERTIFICATE REQUEST-----" EOL },
	{ CRYPT_CERTTYPE_REQUEST_CERT,
	  "-----BEGIN NEW CERTIFICATE REQUEST-----" EOL,
	  "-----END NEW CERTIFICATE REQUEST-----" EOL },
	{ CRYPT_CERTTYPE_CRL,
	  "-----BEGIN CERTIFICATE REVOCATION LIST-----"  EOL,
	  "-----END CERTIFICATE REVOCATION LIST-----" EOL },
	{ CRYPT_CERTTYPE_NONE,			/* Universal catch-all */
	  "-----BEGIN CERTIFICATE OBJECT-----"  EOL,
	  "-----END CERTIFICATE OBJECT-----" EOL }
	};

/****************************************************************************
*																			*
*								Utility Functions							*
*																			*
****************************************************************************/

/* Read a line of text data ending in an EOL */

static int readLine( STREAM *stream, char *buffer, const int maxSize )
	{
	MIME_STATE state;
	int status;

	initMIMEstate( &state, maxSize );
	do
		{
		const int ch = sgetc( stream );

		status = ( cryptStatusError( ch ) ) ? ch : \
				 addMIMEchar( &state, buffer, ch );
		}
	while( cryptStatusOK( status ) );
	if( cryptStatusError( status ) && status != OK_SPECIAL )
		return( status );
	return( endMIMEstate( &state ) );
	}

/* Check for raw base64 data.  There isn't a 100% reliable check for this,
   but if the first 60 chars (the minimum base64 line length) are all valid
   base64 chars and the first chars match the required values then it's
   reasonably certain that it's base64 data */

static BOOLEAN checkBase64( STREAM *stream )
	{
	char buffer[ 8 ], headerBuffer[ 4 ];
	BOOLEAN gotHeader = FALSE;
	int i, status;

	/* Make sure that there's enough data present to perform a reliable 
	   check */
	if( sMemDataLeft( stream ) < 15 * 4 )
		return( FALSE );

	/* Check that we have at least 15 lots (60 chars) of base64-encoded
	   data */
	for( i = 0; i < 15; i++ )
		{
		BYTE c0, c1, c2, c3, cx;

		status = sread( stream, buffer, 4 );
		if( cryptStatusError( status ) )
			return( FALSE );
		if( !gotHeader )
			{
			memcpy( headerBuffer, buffer, 2 );
			gotHeader = TRUE;
			}
		c0 = decode( buffer[ 0 ] );
		c1 = decode( buffer[ 1 ] );
		c2 = decode( buffer[ 2 ] );
		c3 = decode( buffer[ 3 ] );
		cx = c0 | c1 | c2 | c3;

		if( cx == BEOF || cx == BERR )
			return( FALSE );
		}

	/* Make sure that the content is some form of encoded cert.  For cert
	   data that begins with 30 8x, the corresponding base64 values are
	   MI...; for an SSH public key that begins 00 00 it's AA...; for a PGP
	   public key that begins 99 0x it's mQ... */
	if( strCompare( headerBuffer, "MI", 2 ) && \
		strCompare( headerBuffer, "AA", 2 ) && \
		strCompare( headerBuffer, "mQ", 2 ) )
		return( FALSE );

	return( TRUE );
	}

/* Check for PEM-encapsulated data.  All we need to look for is the 
   '-----..' header, which is fairly simple although we also need to handle 
   the SSH '---- ...' variant (4 dashes and a space) */

static int checkPEMHeader( STREAM *stream, int *startPos )
	{
	BOOLEAN isSSH = FALSE, isPGP = FALSE;
	char buffer[ 1024 ], *bufPtr = buffer;
	int i, position, length;

	/* Check for the initial 5 dashes and 'BEGIN ' (unless we're SSH, in
	   which case we use 4 dashes, a space, and 'BEGIN ') */
	length = readLine( stream, buffer, 1024 );
	if( cryptStatusError( length ) )
		return( length );
	if( strCompare( bufPtr, "-----BEGIN ", 11 ) && \
		strCompare( bufPtr, "---- BEGIN ", 11 ) )
		return( CRYPT_CERTFORMAT_NONE );
	bufPtr += 11;
	length -= 11;

	/* Skip the object name */
	if( !strCompare( bufPtr, "SSH2 ", 5 ) )
		isSSH = TRUE;
	else
		if( !strCompare( bufPtr, "PGP ", 4 ) )
			isPGP = TRUE;
	while( length-- > 4 )
		if( *bufPtr++ == '-' )
			break;
	if( length != 4 && length != 3 )
		return( CRYPT_CERTFORMAT_NONE );

	/* Check the the trailing 5 (4 for SSH) dashes */
	if( strCompare( bufPtr, "----", length ) )
		return( CRYPT_CERTFORMAT_NONE );

	/* At this point SSH and PGP can continue with an arbitrary number of
	   type:value pairs that we have to strip before we get to the payload */
	if( isSSH )
		{
		/* SSH runs the header straight into the body so the only way to
		   tell whether we've hit the body is to check for the absence of
		   the ':' separator */
		do
			{
			position = stell( stream );
			length = readLine( stream, buffer, 1024 );
			if( cryptStatusError( length ) )
				return( CRYPT_CERTFORMAT_NONE );
			for( i = 0; i < length && buffer[ i ] != ':'; i++ );
			}
		while( i < length );
		sseek( stream, position );
		}
	if( isPGP )
		{
		/* PGP uses a conventional header format with a blank line as the
		   delimiter so all we have to do is look for a zero-length line */
		do
			{
			length = readLine( stream, buffer, 1024 );
			if( cryptStatusError( length ) )
				return( CRYPT_CERTFORMAT_NONE );
			}
		while( length > 0 );
		}

	/* Return the start position of the payload */
	*startPos = stell( stream );
	return( CRYPT_CERTFORMAT_TEXT_CERTIFICATE );
	}

/****************************************************************************
*																			*
*							Base64 En/Decoding Functions					*
*																			*
****************************************************************************/

/* Check whether a data item has a header that identifies it as some form of
   encoded object and return the start position of the encoded data.  For

⌨️ 快捷键说明

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