iPXE
base64.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdint.h>
00027 #include <string.h>
00028 #include <ctype.h>
00029 #include <errno.h>
00030 #include <assert.h>
00031 #include <ipxe/base64.h>
00032 
00033 /** @file
00034  *
00035  * Base64 encoding
00036  *
00037  */
00038 
00039 static const char base64[64] =
00040         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00041 
00042 /**
00043  * Base64-encode data
00044  *
00045  * @v raw               Raw data
00046  * @v raw_len           Length of raw data
00047  * @v data              Buffer
00048  * @v len               Length of buffer
00049  * @ret len             Encoded length
00050  */
00051 size_t base64_encode ( const void *raw, size_t raw_len, char *data,
00052                        size_t len ) {
00053         const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
00054         size_t raw_bit_len = ( 8 * raw_len );
00055         size_t used = 0;
00056         unsigned int bit;
00057         unsigned int byte;
00058         unsigned int shift;
00059         unsigned int tmp;
00060 
00061         for ( bit = 0 ; bit < raw_bit_len ; bit += 6, used++ ) {
00062                 byte = ( bit / 8 );
00063                 shift = ( bit % 8 );
00064                 tmp = ( raw_bytes[byte] << shift );
00065                 if ( ( byte + 1 ) < raw_len )
00066                         tmp |= ( raw_bytes[ byte + 1 ] >> ( 8 - shift ) );
00067                 tmp = ( ( tmp >> 2 ) & 0x3f );
00068                 if ( used < len )
00069                         data[used] = base64[tmp];
00070         }
00071         for ( ; ( bit % 8 ) != 0 ; bit += 6, used++ ) {
00072                 if ( used < len )
00073                         data[used] = '=';
00074         }
00075         if ( used < len )
00076                 data[used] = '\0';
00077         if ( len )
00078                 data[ len - 1 ] = '\0'; /* Ensure terminator exists */
00079 
00080         return used;
00081 }
00082 
00083 /**
00084  * Base64-decode string
00085  *
00086  * @v encoded           Encoded string
00087  * @v data              Buffer
00088  * @v len               Length of buffer
00089  * @ret len             Length of data, or negative error
00090  */
00091 int base64_decode ( const char *encoded, void *data, size_t len ) {
00092         const char *in = encoded;
00093         uint8_t *out = data;
00094         uint8_t in_char;
00095         char *match;
00096         int in_bits;
00097         unsigned int bit = 0;
00098         unsigned int pad_count = 0;
00099         size_t offset;
00100 
00101         /* Zero the output buffer */
00102         memset ( data, 0, len );
00103 
00104         /* Decode string */
00105         while ( ( in_char = *(in++) ) ) {
00106 
00107                 /* Ignore whitespace characters */
00108                 if ( isspace ( in_char ) )
00109                         continue;
00110 
00111                 /* Process pad characters */
00112                 if ( in_char == '=' ) {
00113                         if ( pad_count >= 2 ) {
00114                                 DBG ( "Base64-encoded string \"%s\" has too "
00115                                       "many pad characters\n", encoded );
00116                                 return -EINVAL;
00117                         }
00118                         pad_count++;
00119                         bit -= 2; /* unused_bits = ( 2 * pad_count ) */
00120                         continue;
00121                 }
00122                 if ( pad_count ) {
00123                         DBG ( "Base64-encoded string \"%s\" has invalid pad "
00124                               "sequence\n", encoded );
00125                         return -EINVAL;
00126                 }
00127 
00128                 /* Process normal characters */
00129                 match = strchr ( base64, in_char );
00130                 if ( ! match ) {
00131                         DBG ( "Base64-encoded string \"%s\" contains invalid "
00132                               "character '%c'\n", encoded, in_char );
00133                         return -EINVAL;
00134                 }
00135                 in_bits = ( match - base64 );
00136 
00137                 /* Add to raw data */
00138                 in_bits <<= 2;
00139                 offset = ( bit / 8 );
00140                 if ( offset < len )
00141                         out[offset] |= ( in_bits >> ( bit % 8 ) );
00142                 offset++;
00143                 if ( offset < len )
00144                         out[offset] |= ( in_bits << ( 8 - ( bit % 8 ) ) );
00145                 bit += 6;
00146         }
00147 
00148         /* Check that we decoded a whole number of bytes */
00149         if ( ( bit % 8 ) != 0 ) {
00150                 DBG ( "Base64-encoded string \"%s\" has invalid bit length "
00151                       "%d\n", encoded, bit );
00152                 return -EINVAL;
00153         }
00154 
00155         /* Return length in bytes */
00156         return ( bit / 8 );
00157 }