encodetostring decodificar convertir convert c++ openssl base64

c++ - decodificar - js base64 encoder



Codificación y decodificación Base64 con OpenSSL (5)

He estado tratando de descubrir la documentación de openssl para la decodificación y codificación de base64. Encontré algunos fragmentos de código a continuación

#include <openssl/sha.h> #include <openssl/hmac.h> #include <openssl/evp.h> #include <openssl/bio.h> #include <openssl/buffer.h> char *base64(const unsigned char *input, int length) { BIO *bmem, *b64; BUF_MEM *bptr; b64 = BIO_new(BIO_f_base64()); bmem = BIO_new(BIO_s_mem()); b64 = BIO_push(b64, bmem); BIO_write(b64, input, length); BIO_flush(b64); BIO_get_mem_ptr(b64, &bptr); char *buff = (char *)malloc(bptr->length); memcpy(buff, bptr->data, bptr->length-1); buff[bptr->length-1] = 0; BIO_free_all(b64); return buff; } char *decode64(unsigned char *input, int length) { BIO *b64, *bmem; char *buffer = (char *)malloc(length); memset(buffer, 0, length); b64 = BIO_new(BIO_f_base64()); bmem = BIO_new_mem_buf(input, length); bmem = BIO_push(b64, bmem); BIO_read(bmem, buffer, length); BIO_free_all(bmem); return buffer; }

Esto solo parece funcionar para cadenas de una sola línea, como "Inicio", en el momento en que introduzco cadenas complejas con líneas nuevas y espacios, etc., falla horriblemente.

Ni siquiera tiene que ser openssl, una clase simple o un conjunto de funciones que hacen lo mismo estaría bien, hay un proceso de compilación muy complicado para la solución y estoy tratando de evitar tener que ir allí y hacer varios cambios . La única razón por la que opté por openssl es porque la solución ya está compilada con las bibliotecas.


Base64 es realmente bastante simple; no debería tener problemas para encontrar cualquier cantidad de implementaciones a través de un rápido Google. Por ejemplo, aquí hay una implementación de referencia en C del Internet Software Consortium, con comentarios detallados que explican el proceso.

La implementación de openssl pone mucha complejidad con el material "BIO" que no es (IMHO) muy útil si todo lo que hace es descodificar / codificar.


Aquí hay un ejemplo de codificación / decodificación de base64 de OpenSSL que escribí:

Aviso, tengo algunas macros / clases en el código que escribí, pero ninguna de ellas es importante para el ejemplo. Es simplemente algunas envolturas de C ++ que escribí:

buffer base64::encode( const buffer& data ) { // bio is simply a class that wraps BIO* and it free the BIO in the destructor. bio b64(BIO_f_base64()); // create BIO to perform base64 BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); bio mem(BIO_s_mem()); // create BIO that holds the result // chain base64 with mem, so writing to b64 will encode base64 and write to mem. BIO_push(b64, mem); // write data bool done = false; int res = 0; while(!done) { res = BIO_write(b64, data.data, (int)data.size); if(res <= 0) // if failed { if(BIO_should_retry(b64)){ continue; } else // encoding failed { /* Handle Error!!! */ } } else // success! done = true; } BIO_flush(b64); // get a pointer to mem''s data char* dt; long len = BIO_get_mem_data(mem, &dt); // assign data to output std::string s(dt, len); return buffer(s.length()+sizeof(char), (byte*)s.c_str()); }


Respuesta mejorada de TCS para eliminar macros / estructuras de datos

unsigned char *encodeb64mem( unsigned char *data, int len, int *lenoutput ) { // bio is simply a class that wraps BIO* and it free the BIO in the destructor. BIO *b64 = BIO_new(BIO_f_base64()); // create BIO to perform base64 BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); BIO *mem = BIO_new(BIO_s_mem()); // create BIO that holds the result // chain base64 with mem, so writing to b64 will encode base64 and write to mem. BIO_push(b64, mem); // write data bool done = false; int res = 0; while(!done) { res = BIO_write(b64, data, len); if(res <= 0) // if failed { if(BIO_should_retry(b64)){ continue; } else // encoding failed { /* Handle Error!!! */ } } else // success! done = true; } BIO_flush(b64); // get a pointer to mem''s data unsigned char* output; *lenoutput = BIO_get_mem_data(mem, &output); // assign data to output //std::string s(dt, len2); return output; }

Para escribir en el archivo

int encodeb64(unsigned char* input, const char* filenm, int leni) { BIO *b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); BIO *file = BIO_new_file(filenm, "w"); BIO *mem = BIO_new(BIO_f_buffer()); BIO_push(b64, mem); BIO_push(mem, file); // write data bool done = false; int res = 0; while(!done) { res = BIO_write(b64, input, leni); if(res <= 0) // if failed { if(BIO_should_retry(b64)){ continue; } else // encoding failed { /* Handle Error!!! */ } } else // success! done = true; } BIO_flush(b64); BIO_pop(b64); BIO_free_all(b64); return 0; }

Codificación Base64 de archivo a archivo. Muchas veces, debido a restricciones de archivos, hemos leído en fragmentos de datos y hacemos codificación. A continuación está el código.

int encodeb64FromFile(const char* input, const char* outputfilename) { BIO *b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64,BIO_FLAGS_BASE64_NO_NL); int leni = 3*64; unsigned char *data[3*64]; BIO *file = BIO_new_file(outputfilename, "w"); BIO *mem = BIO_new(BIO_f_buffer()); BIO_push(b64, mem); BIO_push(mem, file); FILE *fp = fopen(input, "rb"); while ((leni = fread(data, 1, sizeof data, fp)) > 0) { // write data bool done = false; int res = 0; while(!done) { res = BIO_write(b64, data, leni); if(res <= 0) // if failed { if(BIO_should_retry(b64)){ continue; } else // encoding failed { /* Handle Error!!! */ } } else // success! done = true; } } BIO_flush(b64); BIO_pop(b64); BIO_free_all(b64); fclose(fp); return 0; }


#include <openssl/bio.h> typedef unsigned char byte; namespace base64 { static void Encode(const byte* in, size_t in_len, char** out, size_t* out_len) { BIO *buff, *b64f; BUF_MEM *ptr; b64f = BIO_new(BIO_f_base64()); buff = BIO_new(BIO_s_mem()); buff = BIO_push(b64f, buff); BIO_set_flags(buff, BIO_FLAGS_BASE64_NO_NL); BIO_set_close(buff, BIO_CLOSE); BIO_write(buff, in, in_len); BIO_flush(buff); BIO_get_mem_ptr(buff, &ptr); (*out_len) = ptr->length; (*out) = (char *) malloc(((*out_len) + 1) * sizeof(char)); memcpy(*out, ptr->data, (*out_len)); (*out)[(*out_len)] = ''/0''; BIO_free_all(buff); } static void Decode(const char* in, size_t in_len, byte** out, size_t* out_len) { BIO *buff, *b64f; b64f = BIO_new(BIO_f_base64()); buff = BIO_new_mem_buf((void *)in, in_len); buff = BIO_push(b64f, buff); (*out) = (byte *) malloc(in_len * sizeof(char)); BIO_set_flags(buff, BIO_FLAGS_BASE64_NO_NL); BIO_set_close(buff, BIO_CLOSE); (*out_len) = BIO_read(buff, (*out), in_len); (*out) = (byte *) realloc((void *)(*out), ((*out_len) + 1) * sizeof(byte)); (*out)[(*out_len)] = ''/0''; BIO_free_all(buff); } }


Personalmente, creo que la API de OpenSSL es tan increíblemente dolorosa de usar, la evito a menos que el costo de evitarla sea extremadamente alto. Me resulta bastante molesto que se haya convertido en la API estándar en el mundo de la criptografía.

Me sentía aburrido, y te escribí uno en C ++. Éste debería incluso manejar los casos límite que pueden causar problemas de seguridad, como, por ejemplo, la codificación de una cadena que da como resultado un desbordamiento de enteros porque es demasiado grande.

He hecho algunas pruebas unitarias en él, así que debería funcionar.

#include <string> #include <cassert> #include <limits> #include <stdexcept> #include <cctype> static const char b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static const char reverse_table[128] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 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, 64, 64, 64, 64, 64, 64, 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, 64, 64, 64, 64, 64 }; ::std::string base64_encode(const ::std::string &bindata) { using ::std::string; using ::std::numeric_limits; if (bindata.size() > (numeric_limits<string::size_type>::max() / 4u) * 3u) { throw ::std::length_error("Converting too large a string to base64."); } const ::std::size_t binlen = bindata.size(); // Use = signs so the end is properly padded. string retval((((binlen + 2) / 3) * 4), ''=''); ::std::size_t outpos = 0; int bits_collected = 0; unsigned int accumulator = 0; const string::const_iterator binend = bindata.end(); for (string::const_iterator i = bindata.begin(); i != binend; ++i) { accumulator = (accumulator << 8) | (*i & 0xffu); bits_collected += 8; while (bits_collected >= 6) { bits_collected -= 6; retval[outpos++] = b64_table[(accumulator >> bits_collected) & 0x3fu]; } } if (bits_collected > 0) { // Any trailing bits that are missing. assert(bits_collected < 6); accumulator <<= 6 - bits_collected; retval[outpos++] = b64_table[accumulator & 0x3fu]; } assert(outpos >= (retval.size() - 2)); assert(outpos <= retval.size()); return retval; } ::std::string base64_decode(const ::std::string &ascdata) { using ::std::string; string retval; const string::const_iterator last = ascdata.end(); int bits_collected = 0; unsigned int accumulator = 0; for (string::const_iterator i = ascdata.begin(); i != last; ++i) { const int c = *i; if (::std::isspace(c) || c == ''='') { // Skip whitespace and padding. Be liberal in what you accept. continue; } if ((c > 127) || (c < 0) || (reverse_table[c] > 63)) { throw ::std::invalid_argument("This contains characters not legal in a base64 encoded string."); } accumulator = (accumulator << 6) | reverse_table[c]; bits_collected += 6; if (bits_collected >= 8) { bits_collected -= 8; retval += static_cast<char>((accumulator >> bits_collected) & 0xffu); } } return retval; }