[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
You are not allowed to view links. You are not allowed to view links. Register or Login or You are not allowed to view links. Register or Login