sábado, 28 de julio de 2007

Codificación Base 64

Base 64 en un sistema de codificación que permite representar datos binarios usando únicamente los caracteres imprimibles ASCII. Este sistema ha sido usado ampliamente para codificar los correos electrónicos, entre otras cosas.

A continuación se muestra un ejemplo de codificación en Base 64.




Para usar Base 64 en C se puede optar por hacerlo a través de una librería como openssl o por implementar directamente el algoritmo. Veremos los dos casos.


Base 64 y OpenSSL:

Para usar Base 64 desde la librería OpenSSL debemos incluir la cabecera "openssl/evp.h". Las funciones que nos pemiten codificar y descodificar B64 son EVP_EncodeBlock() y EVP_DecodeBlock(), respectivamente.
A continuación aparecen dos funciones: base64_encode() y base64_decode(). Ambas reciben como parámetro la cadena a codificar o descodificar y su longitud, y retornan una cadena con el resultado. Esta cadena apunta a una zona de memoria reservada con malloc(), por lo que queda en manos del programador liberarla.



unsigned char *base64_encode (unsigned char *buffer, unsigned int len)
{
unsigned char *ret = (unsigned char *) malloc ((((len+2)/3)*4)+1);
EVP_EncodeBlock (ret, buffer, len);
ret[(((len+2)/3)*4)] = 0;
return ret;
}

unsigned char *base64_decode (unsigned char *buffer, unsigned int *len)
{
unsigned char *ret = (unsigned char *) malloc (((strlen(buffer)+3)/4)*3);
*len = EVP_DecodeBlock (ret, buffer, strlen(buffer));
return ret;
}

Una implementación de Base 64:

Existen muchas implementaciones del algoritmo usado para codificar y descodificar en Base 64. A continuación pego una de Christophe Devine que se encuentra licenciada bajo GPL.


/**
* \file base64.h
*/
#ifndef _BASE64_H
#define _BASE64_H

#ifdef __cplusplus
extern "C" {
#endif

#define ERR_BASE64_BUFFER_TOO_SMALL 0x0010
#define ERR_BASE64_INVALID_CHARACTER 0x0012

/**
* \brief Encode a buffer into base64 format
*
* \param dst destination buffer
* \param dlen size of the buffer (updated after call)
* \param src source buffer
* \param slen amount of data to be encoded
*
* \return 0 if successful, or ERR_BASE64_BUFFER_TOO_SMALL.
* *dlen is always updated to reflect to amount of
* data that was written (or would have been written)
*
* \note Call this function with *dlen = 0 to obtain the
* required buffer size in *dlen
*/
int base64_encode( unsigned char *dst, int *dlen,
unsigned char *src, int slen );

/**
* \brief Decode a base64-formatted buffer
*
* \param dst destination buffer
* \param dlen size of the buffer (updated after call)
* \param src source buffer
* \param slen amount of data to be decoded
*
* \return 0 if successful, ERR_BASE64_BUFFER_TOO_SMALL, or
* ERR_BASE64_INVALID_DATA if an invalid char is found.
* *dlen is always updated to reflect to amount of
* data that was written (or would have been written)
*
* \note Call this function with *dlen = 0 to obtain the
* required buffer size in *dlen
*/
int base64_decode( unsigned char *dst, int *dlen,
unsigned char *src, int slen );

/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int base64_self_test( int verbose );

#ifdef __cplusplus
}
#endif






/*
* RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2006-2007 Christophe Devine
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License, version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/

#ifndef _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_DEPRECATE 1
#endif

#include "xyssl/base64.h"

static const int base64_enc_map[64] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/'
};

static const int base64_dec_map[128] =
{
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 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, 127, 127, 127, 127, 127, 127, 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, 127, 127, 127, 127, 127
};

/*
* Encode a buffer into base64 format
*/
int base64_encode( unsigned char *dst, int *dlen,
unsigned char *src, int slen )
{
int i, n;
int C1, C2, C3;
unsigned char *p;

if( slen == 0 )
return( 0 );

n = ( slen << dlen =" n" n =" (" i =" 0," p =" dst;" c1 =" *src++;" c2 =" *src++;" c3 =" *src++;">> 2 ) & 0x3F];
*p++ = base64_enc_map[((( C1 & 3 ) <<>> 4 )) &amp;amp;amp;amp;amp; 0x3F];
*p++ = base64_enc_map[((( C2 & 15 ) <<>> 6 )) &amp;amp;amp;amp;amp; 0x3F];
*p++ = base64_enc_map[C3 & 0x3F];
}

if( i < c1 =" *src++;" c2 =" ((i">> 2 ) & 0x3F];
*p++ = base64_enc_map[((( C1 & 3 ) <<>> 4 )) &amp;amp;amp;amp;amp; 0x3F];
*p++ = ((i + 1) < dlen =" p" p =" 0" i =" j" n =" 0;">= 2 &&
src[i] == '\r' && src[i + 1] == '\n' )
continue;

if( src[i] == '\n' )
continue;

if( src[i] == '=' && ++j > 2 )
return( ERR_BASE64_INVALID_CHARACTER );

if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
return( ERR_BASE64_INVALID_CHARACTER );

if( base64_dec_map[src[i]] < n ="=" n =" (">> 3;

if( *dlen < dlen =" n;" j =" 3," n =" x" p =" dst;"> 0; i--, src++ )
{
if( *src == '\r' || *src == '\n' )
continue;

j -= ( base64_dec_map[*src] == 64 );
x = ( x << n ="=" n =" 0;">> 16 );
if( j > 1 ) *p++ = (unsigned char) ( x >> 8 );
if( j > 2 ) *p++ = (unsigned char ) x;
}
}

*dlen = p - dst;

return( 0 );
}

static const char _base64_src[] = "_base64_src";

#if defined(SELF_TEST)

#include
#include

static const unsigned char base64_test_dec[64] =
{
0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
};

static const unsigned char base64_test_enc[] =
"JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
"swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";

/*
* Checkup routine
*/
int base64_self_test( int verbose )
{
int len;
unsigned char *src, buffer[128];

if( verbose != 0 )
printf( " Base64 encoding test: " );

len = sizeof( buffer );
src = (unsigned char *) base64_test_dec;

if( base64_encode( buffer, &len, src, 64 ) != 0 ||
memcmp( base64_test_enc, buffer, 88 ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );

return( 1 );
}

if( verbose != 0 )
printf( "passed\n Base64 decoding test: " );

len = sizeof( buffer );
src = (unsigned char *) base64_test_enc;

if( base64_decode( buffer, &len, src, 88 ) != 0 ||
memcmp( base64_test_dec, buffer, 64 ) != 0 )
{
if( verbose != 0 )
printf( "failed\n" );

return( 1 );
}

if( verbose != 0 )
printf( "passed\n\n" );

return( 0 );
}
#else
int base64_self_test( int verbose )
{
return( 0 );
}
#endif


#endif /* base64.h */




Referencias:

- http://es.wikipedia.org/wiki/Base64
- http://xyssl.org/code/source/base64
- OpenSSL




.

No hay comentarios: