2022-11-24 06:49:46 +00:00
/*
This is derived from the libb64 project , which has been placed in the public domain .
For details , see http : //sourceforge.net/projects/libb64
*/
2023-03-21 20:46:42 +00:00
# include <string.h>
2022-11-24 06:49:46 +00:00
# include "base64.h"
int base64_decode_value ( char value_in )
{
static const char decoding [ ] = { 62 , - 1 , - 1 , - 1 , 63 , 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , - 1 , - 1 , - 1 , - 2 , - 1 , - 1 , - 1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51 } ;
static const char decoding_size = sizeof ( decoding ) ;
value_in - = 43 ;
if ( value_in < 0 | | value_in > = decoding_size ) return - 1 ;
return decoding [ ( int ) value_in ] ;
}
void base64_init_decodestate ( base64_decodestate * state_in )
{
state_in - > step = step_a ;
state_in - > plainchar = 0 ;
}
int base64_decode_block ( const char * code_in , const int length_in , char * plaintext_out , base64_decodestate * state_in )
{
const char * codechar = code_in ;
char * plainchar = plaintext_out ;
char fragment ;
* plainchar = state_in - > plainchar ;
switch ( state_in - > step )
{
while ( 1 )
{
case step_a :
do {
if ( codechar = = code_in + length_in )
{
state_in - > step = step_a ;
state_in - > plainchar = * plainchar ;
return plainchar - plaintext_out ;
}
fragment = ( char ) base64_decode_value ( * codechar + + ) ;
} while ( fragment < 0 ) ;
* plainchar = ( fragment & 0x03f ) < < 2 ;
// fall through
case step_b :
do {
if ( codechar = = code_in + length_in )
{
state_in - > step = step_b ;
state_in - > plainchar = * plainchar ;
return plainchar - plaintext_out ;
}
fragment = ( char ) base64_decode_value ( * codechar + + ) ;
} while ( fragment < 0 ) ;
* plainchar + + | = ( fragment & 0x030 ) > > 4 ;
* plainchar = ( fragment & 0x00f ) < < 4 ;
// fall through
case step_c :
do {
if ( codechar = = code_in + length_in )
{
state_in - > step = step_c ;
state_in - > plainchar = * plainchar ;
return plainchar - plaintext_out ;
}
fragment = ( char ) base64_decode_value ( * codechar + + ) ;
} while ( fragment < 0 ) ;
* plainchar + + | = ( fragment & 0x03c ) > > 2 ;
* plainchar = ( fragment & 0x003 ) < < 6 ;
// fall through
case step_d :
do {
if ( codechar = = code_in + length_in )
{
state_in - > step = step_d ;
state_in - > plainchar = * plainchar ;
return plainchar - plaintext_out ;
}
fragment = ( char ) base64_decode_value ( * codechar + + ) ;
} while ( fragment < 0 ) ;
* plainchar + + | = ( fragment & 0x03f ) ;
}
}
/* control should not reach here */
return plainchar - plaintext_out ;
}
void base64_init_encodestate ( base64_encodestate * state_in )
{
state_in - > step = step_A ;
state_in - > result = 0 ;
state_in - > stepcount = 0 ;
}
char base64_encode_value ( char value_in )
{
static const char * encoding = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ " ;
if ( value_in > 63 ) return ' = ' ;
return encoding [ ( int ) value_in ] ;
}
int base64_encode_block ( const char * plaintext_in , int length_in , char * code_out , base64_encodestate * state_in )
{
const char * plainchar = plaintext_in ;
const char * const plaintextend = plaintext_in + length_in ;
char * codechar = code_out ;
char result ;
char fragment ;
result = state_in - > result ;
switch ( state_in - > step )
{
while ( 1 )
{
case step_A :
if ( plainchar = = plaintextend )
{
state_in - > result = result ;
state_in - > step = step_A ;
return codechar - code_out ;
}
fragment = * plainchar + + ;
result = ( fragment & 0x0fc ) > > 2 ;
* codechar + + = base64_encode_value ( result ) ;
result = ( fragment & 0x003 ) < < 4 ;
// fall through
case step_B :
if ( plainchar = = plaintextend )
{
state_in - > result = result ;
state_in - > step = step_B ;
return codechar - code_out ;
}
fragment = * plainchar + + ;
result | = ( fragment & 0x0f0 ) > > 4 ;
* codechar + + = base64_encode_value ( result ) ;
result = ( fragment & 0x00f ) < < 2 ;
// fall through
case step_C :
if ( plainchar = = plaintextend )
{
state_in - > result = result ;
state_in - > step = step_C ;
return codechar - code_out ;
}
fragment = * plainchar + + ;
result | = ( fragment & 0x0c0 ) > > 6 ;
* codechar + + = base64_encode_value ( result ) ;
result = ( fragment & 0x03f ) > > 0 ;
* codechar + + = base64_encode_value ( result ) ;
+ + ( state_in - > stepcount ) ;
# ifdef BASE64_USE_NEWLINES
if ( state_in - > stepcount = = BASE64_CHARS_PER_LINE / 4 )
{
* codechar + + = ' \n ' ;
state_in - > stepcount = 0 ;
}
# endif
}
}
/* control should not reach here */
return codechar - code_out ;
}
int base64_encode_blockend ( char * code_out , base64_encodestate * state_in )
{
char * codechar = code_out ;
switch ( state_in - > step )
{
case step_B :
* codechar + + = base64_encode_value ( state_in - > result ) ;
* codechar + + = ' = ' ;
* codechar + + = ' = ' ;
break ;
case step_C :
* codechar + + = base64_encode_value ( state_in - > result ) ;
* codechar + + = ' = ' ;
break ;
case step_A :
break ;
}
# ifdef BASE64_USE_NEWLINES
* codechar + + = ' \n ' ;
# endif
return codechar - code_out ;
}
// These "one-shot" functions were not in the original project, I have added them and still need to be sure they work
// note - output MUST be large enough to accomodate the base64'd input (i.e. must be 1/3 bigger than input_len plus the null terminator - 65 bytes for 48-byte input)
void base64_encode_oneshot ( char * input , int input_len , char * output ) {
base64_encodestate s ;
char * c = output ;
base64_init_encodestate ( & s ) ;
c + = base64_encode_block ( input , input_len , output , & s ) ;
c + = base64_encode_blockend ( c , & s ) ;
* c = ' \0 ' ;
}
// note - output MUST be large enough to accomodate the decoded input (i.e. must be at least 3/4 the size of the input - 48 bytes for 64-byte input)
void base64_decode_oneshot ( char * input , int input_len , char * output ) {
base64_decodestate s ;
base64_init_decodestate ( & s ) ;
base64_decode_block ( input , input_len , output , & s ) ;
2023-03-21 20:46:42 +00:00
}
// Provides the length of the binary you would get if you decoded base64 string b64, accounting for padding
int base64_binlength ( char * b64 ) {
int length , padding ;
length = strlen ( b64 ) ;
if ( length % 4 ! = 0 ) return - 1 ; // return -1 if length is not divisible by four (i.e. if invalid base64)
// somewhat messy way to determine how many bytes of padding are at the end of a base64 string
if ( b64 [ length - 1 ] = = ' = ' & & b64 [ length - 2 ] = = ' = ' & & b64 [ length - 3 ] = = ' = ' ) { padding = 3 ; }
else if ( b64 [ length - 1 ] = = ' = ' & & b64 [ length - 2 ] = = ' = ' ) { padding = 2 ; }
else if ( b64 [ length - 1 ] = = ' = ' ) { padding = 1 ; }
else { padding = 0 ; }
return ( ( ( length / 4 ) * 3 ) - padding ) ;
}
// Provides the base64 length of a binary of length binlength bytes
int base64_base64length ( int binlength ) {
return ( ( ( binlength + 2 ) / 3 ) * 4 ) ;
2022-11-24 06:49:46 +00:00
}