📄 base64.c
字号:
else
if( src[ srcIndex ] == '\r' )
{
srcIndex++;
/* Some broken implementations emit two CRs before the
LF. Stripping these extra CRs clashes with other
broken implementations that emit only CRs, which means
that we'll be stripping the EOT blank line in MIME
encapsulation, however it looks like the two-CR bug
(usually from Netscape) appears to be more prevalent
than the CR-only bug (old Mac software) */
if( src[ srcIndex ] == '\r' )
srcIndex++;
if( src[ srcIndex ] == '\n' )
srcIndex++;
}
lineCount = 0;
/* Check for '\0' or EOL (S/MIME) or '----END...' (PEM) after
EOL */
if( ( format == CRYPT_ICERTFORMAT_SMIME_CERTIFICATE && \
( !src[ srcIndex ] || src[ srcIndex ] == '\n' || \
src[ srcIndex ] == '\r' ) ) || \
( format == CRYPT_CERTFORMAT_TEXT_CERTIFICATE && \
!strCompare( src + srcIndex, "-----END ", 9 ) ) )
{
c0 = c1 = c2 = BEOF;
srcIndex += 4;
break;
}
/* Make sure that we haven't run off into the weeds */
if( srcIndex >= srcLen )
break;
}
/* Decode a block of data from the input buffer */
c0 = decode( src[ srcIndex++ ] );
c1 = decode( src[ srcIndex++ ] );
c2 = decode( src[ srcIndex++ ] );
c3 = decode( src[ srcIndex++ ] );
cx = c0 | c1 | c2 | c3;
if( c0 == BEOF || cx == BEOF )
/* We need to check c0 separately since hitting an EOF at c0 may
cause later chars to be decoded as BERR */
break;
else
if( cx == BERR )
return( CRYPT_ERROR_BADDATA );
lineCount += 4;
/* Copy the decoded data to the output buffer */
destPtr[ destIndex++ ] = ( c0 << 2 ) | ( c1 >> 4 );
destPtr[ destIndex++ ] = ( c1 << 4 ) | ( c2 >> 2 );
destPtr[ destIndex++ ] = ( c2 << 6 ) | ( c3 );
if( destIndex > destMaxLen )
return( CRYPT_ERROR_OVERFLOW );
}
/* Handle the truncation of data at the end. Due to the 3 -> 4 encoding,
we have the following mapping: 0 chars -> nothing, 1 char -> 2 + 2 pad,
2 chars = 3 + 1 pad */
if( c0 == BEOF )
/* No padding, move back 4 chars */
srcIndex -= 4;
else
{
/* 2 chars padding, decode 1 from 2 */
destPtr[ destIndex++ ] = ( c0 << 2 ) | ( c1 >> 4 );
if( c2 != BEOF )
/* 1 char padding, decode 2 from 3 */
destPtr[ destIndex++ ] = ( c1 << 4 ) | ( c2 >> 2);
}
/* Return count of decoded bytes */
return( destIndex );
}
/* Calculate the size of a quantity of data once it's en/decoded */
int base64decodeLen( const char *data, const int dataLength )
{
STREAM stream;
int ch, length;
assert( isReadPtr( data, dataLength ) );
/* Skip ahead until we find the end of the decodable data */
sMemConnect( &stream, data, dataLength );
do
{
ch = sgetc( &stream );
if( cryptStatusError( ch ) || ch == BPAD )
break;
ch = decode( ch );
}
while( ch != BERR );
length = stell( &stream );
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 */
return( ( length * 3 ) / 4 );
}
int base64encodeLen( const int dataLength,
const CRYPT_CERTTYPE_TYPE certType )
{
int length = roundUp( ( dataLength * 4 ) / 3, 4 ), headerInfoIndex;
for( headerInfoIndex = 0;
headerInfo[ headerInfoIndex ].type != certType && \
headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE;
headerInfoIndex++ );
assert( headerInfo[ headerInfoIndex ].type != CRYPT_CERTTYPE_NONE );
/* Calculate extra length due to EOL's */
length += ( ( roundUp( length, TEXT_LINESIZE ) / TEXT_LINESIZE ) * EOL_LEN );
/* Return the total length due to delimiters */
return( strlen( headerInfo[ headerInfoIndex ].header ) + length + \
strlen( headerInfo[ headerInfoIndex ].trailer ) );
}
/****************************************************************************
* *
* PKI User ID En/Decoding Functions *
* *
****************************************************************************/
/* En/decode text representations of binary keys */
static const char codeTable[] = \
"ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; /* No O/0, I/1 */
static const int hiMask[] = { 0x00, 0x00, 0x00, 0x00, 0x0F, 0x07, 0x03, 0x01 };
static const int loMask[] = { 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0 };
BOOLEAN isPKIUserValue( const char *encVal, const int encValLength )
{
int i = 0;
assert( isReadPtr( encVal, encValLength ) );
/* Check whether a user value is of the form XXXXX-XXXXX-XXXXX{-XXXXX} */
if( ( encValLength != ( 3 * 5 ) + 2 ) && \
( encValLength != ( 4 * 5 ) + 3 ) )
return( FALSE );
while( i < encValLength )
{
int j;
for( j = 0; j < 5; j++ )
{
const int ch = encVal[ i++ ];
if( !isAlnum( ch ) )
return( FALSE );
}
if( i < encValLength && encVal[ i++ ] != '-' )
return( FALSE );
}
return( TRUE );
}
int adjustPKIUserValue( BYTE *value, const int noCodeGroups )
{
const int noBits = noCodeGroups * 25;
const int length = ( roundUp( noBits, 8 ) / 8 ) - 1;
assert( isWritePtr( value, roundUp( noCodeGroups * 25, 8 ) / 8 ) );
/* Mask off any bits at the end of the data that can't be encoded using
the given number of code groups */
value[ length - 1 ] &= 0xFF << ( 8 - ( noBits % 8 ) );
return( length );
}
int encodePKIUserValue( char *encVal, const BYTE *value,
const int noCodeGroups )
{
BYTE valBuf[ 128 ];
const int dataBytes = ( roundUp( noCodeGroups * 25, 8 ) / 8 );
int i, byteCount = 0, bitCount = 0, length;
assert( isReadPtr( value, dataBytes ) );
/* Copy across the data bytes, leaving a gap at the start for the
checksum */
memcpy( valBuf + 1, value, dataBytes );
length = adjustPKIUserValue( valBuf + 1, noCodeGroups ) + 1;
/* Calculate the Fletcher checksum and prepend it to the data bytes
This is easier than handling the addition of a non-byte-aligned
quantity to the end of the data */
valBuf[ 0 ] = checksumData( valBuf + 1, length - 1 ) & 0xFF;
/* Encode the binary data as text */
for( length = 0, i = 1; i <= noCodeGroups * 5; i++ )
{
int chunkValue;
/* Extract the next 5-bit chunk and convert it to text form */
if( bitCount < 3 )
/* Everything's present in one byte, shift it down to the LSB */
chunkValue = ( valBuf[ byteCount ] >> ( 3 - bitCount ) ) & 0x1F;
else
if( bitCount == 3 )
/* It's the 5 LSB's */
chunkValue = valBuf[ byteCount ] & 0x1F;
else
/* The data spans two bytes, shift the bits from the high
byte up and the bits from the low byte down */
chunkValue = ( ( valBuf[ byteCount ] & \
hiMask[ bitCount ] ) << ( bitCount - 3 ) ) | \
( ( valBuf[ byteCount + 1 ] & \
loMask[ bitCount ] ) >> ( 11 - bitCount ) );
encVal[ length++ ] = codeTable[ chunkValue ];
if( !( i % 5 ) && i < noCodeGroups * 5 )
encVal[ length++ ] = '-';
/* Advance by 5 bits */
bitCount += 5;
if( bitCount >= 8 )
{
bitCount -= 8;
byteCount++;
}
}
return( length );
}
int decodePKIUserValue( BYTE *value, const char *encVal,
const int encValLength )
{
BYTE valBuf[ 128 ];
char encBuf[ 128 ], *encBufPtr = encBuf;
int i = 0, byteCount = 0, bitCount = 0, length = 0;
assert( isReadPtr( encVal, encValLength ) );
/* Undo the formatting of the encoded value */
while( i < encValLength )
{
int j;
for( j = 0; j < 5; j++ )
{
const int ch = encVal[ i++ ];
if( !isAlnum( ch ) || length >= encValLength )
return( CRYPT_ERROR_BADDATA );
encBuf[ length++ ] = toUpper( ch );
}
if( i < encValLength && encVal[ i++ ] != '-' )
return( CRYPT_ERROR_BADDATA );
}
if( length % 5 )
return( CRYPT_ERROR_BADDATA );
/* Decode the text data into binary */
memset( valBuf, 0, 128 );
for( i = 0; i < length; i ++ )
{
const int ch = *encBufPtr++;
int chunkValue;
for( chunkValue = 0; chunkValue < 0x20; chunkValue++ )
if( codeTable[ chunkValue ] == ch )
break;
if( chunkValue == 0x20 )
return( CRYPT_ERROR_BADDATA );
/* Extract the next 5-bit chunk and convert it to text form */
if( bitCount < 3 )
/* Everything's present in one byte, shift it up into position */
valBuf[ byteCount ] |= chunkValue << ( 3 - bitCount );
else
if( bitCount == 3 )
/* It's the 5 LSB's */
valBuf[ byteCount ] |= chunkValue;
else
{
/* The data spans two bytes, shift the bits from the high
byte down and the bits from the low byte up */
valBuf[ byteCount ] |= \
( chunkValue >> ( bitCount - 3 ) ) & hiMask[ bitCount ];
valBuf[ byteCount + 1 ] = \
( chunkValue << ( 11 - bitCount ) ) & loMask[ bitCount ];
}
/* Advance by 5 bits */
bitCount += 5;
if( bitCount >= 8 )
{
bitCount -= 8;
byteCount++;
}
}
/* Calculate the Fletcher checksum and make sure that it matches the
value at the start of the data bytes */
if( bitCount )
byteCount++; /* More bits in the last partial byte */
if( valBuf[ 0 ] != ( checksumData( valBuf + 1, byteCount - 1 ) & 0xFF ) )
return( CRYPT_ERROR_BADDATA );
/* Return the decoded value to the caller */
if( value != NULL )
memcpy( value, valBuf + 1, byteCount - 1 );
return( byteCount - 1 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -