Saltar al contenido

Codificación y decodificación Base64 con OpenSSL

Bienvenido a nuestra comunidad, en este sitio encontrarás la respuesta a lo que andabas buscando.

Solución:

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

Me sentía aburrido y te escribí uno en C++. Este debería incluso manejar los casos extremos que pueden causar problemas de seguridad, como, por ejemplo, codificar un string eso da como resultado un desbordamiento de enteros porque es demasiado grande.

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

#include 
#include 
#include 
#include 
#include 

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::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)  (*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) 
   return retval;

En lugar de usar el BIO_ interfaz es mucho más fácil usar la EVP_ interfaz. Por ejemplo:

#include 
#include 
#include 

char *base64(const unsigned char *input, int length) 
  const auto pl = 4*((length+2)/3);
  auto output = reinterpret_cast(calloc(pl+1, 1)); //+1 for the terminating null that EVP_EncodeBlock adds on
  const auto ol = EVP_EncodeBlock(reinterpret_cast(output), input, length);
  if (pl != ol)  std::cerr << "Whoops, encode predicted " << pl << " but we got " << ol << "n"; 
  return output;


unsigned char *decode64(const char *input, int length) 
  const auto pl = 3*length/4;
  auto output = reinterpret_cast(calloc(pl+1, 1));
  const auto ol = EVP_DecodeBlock(output, reinterpret_cast(input), length);
  if (pl != ol)  std::cerr << "Whoops, decode predicted " << pl << " but we got " << ol << "n"; 
  return output;

Las funciones de EVP también incluyen una interfaz de transmisión, consulte la página del manual.

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

Tenga en cuenta que tengo algunas macros/clases en el código que escribí, pero ninguna de ellas es importante para el ejemplo. Son simplemente algunos envoltorios 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());

valoraciones y reseñas

Tienes la opción de amparar nuestro estudio exponiendo un comentario o puntuándolo te lo agradecemos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *