PHP nos brinda muchas herramientas para encriptar, tenemos las que son “One Way” (aquellas que sólo van de un sólo sentido, que en realidad solo generan un Hash) como son MD5 y SHA1, y las que son reversibles como el base64_encode.
La clase que implemento a continuación (paso a paso) es para una encriptación reversible (Inspirado en una estupidez que comete mi universidad en su web).
¿ Para qué me sirve esto ? Esta clase la pueden usar para encriptar cookies, direcciones, etc; en fin para cualquier cadena de texto que se tenga, por ejemplo: “http://mipagina.com/algoprivado.php?valor=cadenaencriptada“, en vez de usar el base64_encode (u otros) que es fácil de desencriptar con cualquier herramienta. Si alguien quisiera desencriptar una cadena necesariamente tendría que conocer la estructura interna del algoritmo y nuestras llaves.
1. Declaramos dos atributos privados de clase, que serán llamados “Llaves”, podemos llamarlos llaveA y llaveB, o llaveInterna y llaveExterna (Ambos serán arrays con la misma cantidad de elementos)
private $LlaveExterna;
private $LlaveInterna;
2. En el metodo constructor asignaremos los valores a los arrays:
- Primero definimos un alfabeto, puede ser el abecedario (a,b,c,d,e,..,z); el abecedario incluyendo mayusculas; el abecedario con números; o el más amplio que seria el abecedario con mayúsculas, minúsculas, números y algunos simbolos comunes (@,-,+,!,etc). El que yo uso para este ejemplo explicativo son las vocales (A,E,I,O,U). Recuerda que no pueden repetirse los símbolos.
- Obtenemos la cantidad de elementos de nuestro alfabeto, llamémosle N (en nuestro caso N=5), ahora asignamos aleatoriamente valores de cero a N-1 a cada elemento del primer array (sin repetirse los números); hacemos lo mismo para el segundo array. Recuerda que los array deben ser distintos, y los valores numéricos no deben ser correlativos.
public function __construct()
{
$this->LlaveExterna['A'] = 3;
$this->LlaveExterna['E'] = 1;
$this->LlaveExterna['I'] = 0;
$this->LlaveExterna['O'] = 2;
$this->LlaveExterna['U'] = 4;
$this->LlaveInterna['A'] = 0;
$this->LlaveInterna['E'] = 3;
$this->LlaveInterna['I'] = 4;
$this->LlaveInterna['O'] = 1;
$this->LlaveInterna['U'] = 2;
}
3. Creamos nuestros métodos Get y Set (sólo si fuese necesario):
function get_LlaveExterna()
{
return $this->LlaveExterna;
}
function set_LlaveExterna($aLlaveExterna)
{
$this->LlaveExterna = $aLlaveExterna;
}
function get_LlaveInterna()
{
return $this->LlaveInterna;
}
function set_LlaveInterna($aLlaveInterna)
{
$this->LlaveInterna = $aLlaveInterna;
}
4. Creamos nuestro método Encriptar Cadena que devolverá una cadena encriptada a partir de otra no encriptada, la cadena devuelta tendrá la misma longitud de la de entrada. El proceso de encriptación se realizará caracter por caracter, mediante el método EncriptarCaracter que tendrá como parámetros el i-ésimo caracter de la cadena original, la longitud de la cadena, y el valor de i (que irá incrementando desde cero hasta la longitud de la cadena original, osea recorrerá la cadena):
function EncriptarCadena($sCadena)
{
$NoEncriptado = $sCadena;
$SiEncriptado = "";
$iLength = strlen($sCadena);
for ($i = 0; $i < $iLength; $i++)
{
$SiEncriptado .= $this->EncriptarCaracter($NoEncriptado[$i], $iLength, $i);
}
return $SiEncriptado;
}
5. Nuestro método EncriptarCaracter, que será la base de nuestro algoritmo, devolverá un elemento de nuestro alfabeto (en nuestro caso A,E,I,O,U), de tal manera que no se pueda crear ninguna asociación como “la A es I encriptada”, sino dependerá de la ubicación del caracter en la cadena original y de la longitud de ésta. Para esto se hará lo siguiente:
- Buscará el valor del arreglo LlaveExterna con el caracter de parámetro como indice, es decir, cuanto vale LlaveExterna[caracter], ejm: LlaveExterna['A'] = 3.
- A el valor anterior se sumará la longitud de la cadena a encriptar, y ademas el índice (la posición) del caracter no encriptado en la cadena original, es decir: LlaveExterna[caracter] + LongitudCadena + Indice.
- Al valor obtenido anteriormente se le divide entre N (N=5, cantidad de elementos de nuestro alfabeto), y el resto, lo guardamos.
- Ahora como paso final, buscamos el Indice del otro array (LlaveInterna), donde se encuentra el valor obtenido en el paso anterior (resto de la división); como los indices son Caracteres (elementos de nuestro alfabeto), nos devolverá un Caracter, que será el encriptado en la cadena. Esto se irá concatenando en la cadena encriptada, segun se recorra la cadena original.
function EncriptarCaracter($sCaracter, $iTamanio, $iIndice)
{
$iIndiceAux = ($this->LlaveExterna[$sCaracter] + $iTamanio + $iIndice) % (5);
return array_search($iIndiceAux, $this->LlaveInterna);
}
6. Los métodos DesencriptarCadena y DesencriptarCaracter, son de manera inversa:
function DesencriptarCadena($sCadena)
{
$SiEncriptado = $sCadena;
$NoEncriptado = "";
$iLength = strlen($sCadena);
for ($i = 0; $i < $iLength; $i++)
{
$NoEncriptado .= $this->DesencriptarCaracter($SiEncriptado[$i], $iLength, $i);
}
return $NoEncriptado;
}
function DesencriptarCaracter($sCaracter, $iTamanio, $iIndice)
{
$iIndiceAux = ($this->LlaveInterna[$sCaracter] - $iTamanio - $iIndice) % (5);
if ($iIndiceAux < 0)
{
$iIndiceAux += (5);
}
return array_search($iIndiceAux, $this->LlaveExterna);
}
Como vemos el método DesencriptarCaracter, ademas cuenta con una sentencia “if” que evita que se obtenga valores negativos (entre cero y -N+1) en el valor del indice.
Usando el algoritmo y para nuestro ejemplo (alfabeto: A,E,I,O,U), podemos obtener valores como los siguientes (original = encriptado):
A = I
AA = AO
AAA = OUE
AEIOU = EUUAE
AAEEIEOIOUIEIUOIEUI = UEUEEAUOIUIOOOAIOAU
AAEEIEOIOUIEIUOIEUIA = EIEIIOEUAEAUUUOAUOEU
Los 3 primeros ejemplos no tienen ninguna relación, siendo éstos la misma vocal, sólo que repetida distintas veces; el últimos ejemplo sólo es una modificación del anterior agregandole la “A” al final, y el resultado es completamente distinto.
Imáginate lo que puedes encriptar si trabajas con alfabetos más grandes, o si aplicas el mismo algoritmo para archivos pero ya tambien con bytes (desde cero hasta 255), obtienes una encriptación más que segura, siempre y cuando tus llaves sean privadas.
Les dejo un TXT, que contiene esta clase Encriptadora, hecha para el abecedario completo con mayúsculas y minúsculas, además de dígitos.
DOWNLOAD FILE