[C++] Codificador/Decodificador de Base64

Iniciado por Cervantes_xD, Julio 06, 2011, 11:17:13 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Julio 06, 2011, 11:17:13 PM Ultima modificación: Febrero 08, 2014, 05:47:39 PM por Expermicid
Base64.hpp
Código: cpp
#include <iostream>
#include <string>
#include <math.h>
#include <cstdio>
#include <cstdlib>

using namespace std;

class Base64
{
private:
static string alfabeto;
static string TextToBinBase(string a, int b);
static void Reverse(string &a);
static void Complete(string &a, int b);
public:
static string Encode(string a);
static string Decode(string a);
static string Binary(int a, int b);
static int BinToInt(string a);
static string TextToBin(string a, int b);

};


Base64.cpp
Código: cpp
#include "Base64.hpp"
#include <sstream>

using namespace std;

string Base64::alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

string Base64::Binary(int a, int b)
{
string result = "";
while(a != 0)
{
if((a%2) == 0)
result += '0';
else
result += '1';
a = a/2;
}

Complete(result, b);
Reverse(result);
return result;
}

string Base64::Encode(string a)
{
string binario = TextToBin(a, 8);
stringstream ret;
string *buffer;

int padding;
int alt = binario.length()%6;
int aux;

if(alt == 0)
{
int numcadenas = binario.length() / 6;
buffer = new string[numcadenas];
if(buffer != NULL)
{
for(int i = 0; i < numcadenas; i++)
{
buffer[ i ] = binario.substr(i*6, 6);
aux = BinToInt(buffer[ i ]);
ret << alfabeto.at(aux);
}

delete[] buffer;
}
}
else
{
padding = (6 - alt) / 2;
Complete(binario, binario.length() + (6-alt));
int numcadenas = binario.length() / 6;
buffer = new string[numcadenas];
if(buffer != NULL)
{
int i;
for(i = 0; i < numcadenas; i++)
{
buffer[ i ] = binario.substr(i*6, 6);
aux = BinToInt(buffer[ i ]);
ret << alfabeto.at(aux);
}

for(i = 0; i < padding; i++)
ret<<"=";

delete[] buffer;
}
}

return ret.str();
}

string Base64::Decode(string a)
{
string binario;
string cadena;
stringstream delpadding;

int i;

for(i = 0; i < a.length(); i++)
{
if(a.at(i) != '=')
delpadding<<a.at(i);
}

cadena = delpadding.str();
binario = TextToBinBase(cadena, 6);

stringstream ret;
string *buffer;

int padding;
int alt = binario.length()/8;
int aux;

buffer = new string[alt];

if(buffer != NULL)
{
for(i = 0; i < alt; i++)
{
buffer[ i ] = binario.substr(i*8, 8);
aux = BinToInt(buffer[ i ]);
ret << (char)aux;
}
cout<<endl;
delete[] buffer;
}

return ret.str();
}

string Base64::TextToBin(string a, int b)
{
stringstream c;
for(int i = 0; i < a.length(); i++)
{
c<<Binary((int)a.at(i), b);
}
return c.str();
}

string Base64::TextToBinBase(string a, int b)
{
stringstream c;
for(int i = 0; i < a.length(); i++)
{
int pos = (int)alfabeto.find(a.at(i));
c<<Binary(pos, b);
}
return c.str();
}

void Base64::Reverse(string& a)
{
string aux = "";
for(int i = 0; i < a.length(); i++)
aux += a.at(a.length() - i - 1);
a = aux;
}

void Base64::Complete(string &a, int b)
{
if(a.length() < b)
{
int fin = b - a.length();
a.append(fin, '0');
}
}

int Base64::BinToInt(string a)
{
int aux = 0;

for(int i = 0; i < a.length(); i++)
{
if(a.at(i) == '1')
{
float ex = a.length() -i -1;
aux += (int)pow(2, ex);
}
}

return aux;
}


Main.cpp
Código: cpp
#include "Base64.hpp"

/*
Compilación utilizando g++:
g++ Main.cpp Base64.cpp -o base64

Uso:
base64 -flag string
Ej:
base64 -c hola

Flags disponibles:

-c : Encripta
-d : Desencripta

Se pueden encriptar cadenas más grandes a una sola palabra si se coloca todo entre comillas dobles
Ej:
base64 -c "Encriptando textos con espacios"
*/

using namespace std;

void usage()
{
cout<<"Usage: "<<endl;
cout<<"base64 -c string || Crypt a string to a Base64 string"<<endl;
cout<<"base64 -d string || Decrypt a Base64 string"<<endl;
}

int main(int argv, char** args)
{
if(argv != 3)
{
usage();
}
else
{
string op, str;
op = args[1];
str = args[2];

if(op == "-d")
{
cout<<Base64::Decode(str)<<endl;
}
if(op == "-c")
{
cout<<Base64::Encode(str)<<endl;
}
if( (op != "-c") && (op != "-d"))
{
usage();
}
}
return 0;
}


Generado con el compilador de C++ de Visual C++ Express 2010

El proceso es el siguiente:
Codificación:

1.- Convertir el texto a binario utilizado el valor ASCII de sus caracteres, 8 bits deben salir (si es menos se rellena con ceros) por carácter
2.- Separar en cadenas de 6

Si la última cadena no es de 6 bits, se completa con 0 y a la hora de representar la cadena se añade el caracter = (padding), ¿cuántos? pues un = por cada dos ceros, a la hora de desencriptar no se tienen en cuenta

3.- Cada subcadena de 6 pasarla a entero y el valor que dé se corresponde con una posición en la tabla "alfabeto"

Decodificación:
1.- Convertir el texto a binario utilizado la posición que cada carácter ocupa en la tabla, 6 bits deben salir y no hay que rellenar nada (he ignorado el padding, por lo que su valor no se convierte :B es sólo un "aditivo" a la hora de encriptar)
2.- La longitud de la cadena es múltiplo de 8, así que se divide todo en subcadenas binarias de 8 bits
3.- Convertir cada cadena binaria a entero
4.- Pasar cada entero a ASCII (un simple casting :P)

Voilá! Espero que les sea de utilidad (aunque no lo creo x) )

He usado todo prácticamente estático porque no he visto la necesidad de tener que crear un objeto que lo único que tenga sean algoritmos y nada más sustancial, la ventaja es que obviamente no se necesita crear un objeto de la clase para poder encriptar/desencriptar

Un saludo

P.D: He usados tablas y cosas así, con lo cual hay bastantes cosas entre corchetes, y no sé si alguna de esas ha sido interpretada mal (como los [ i ] para poner la letra en cursiva xD)
Si no funciona me avisan y trato de arreglarlo
No tienes permitido ver los links. Registrarse o Entrar a mi cuenta