Webdev del picudo

Criptografía XOR con base64 en PHP

1 comentario

crypto-pic

Hola a todos, espero que estén de maravilla. Pues me encontraba haciendo un post sobre SQL Injection, sin embargo, hoy en la chamba estuve haciendo algo para un proyecto en C# que es encriptar una cadena de caracteres con XOR y sacando el resultado en base64 :P, esto con el fin de agregar un poco de seguridad a la conexión a la base de datos. Aunque era una aplicación intranet, cabe destacar que no importa si la aplicación vaya a ser con ese fin, siempre hay que pensar en que algún gandalla esté dentro de la organización y filtre la aplicación, esto nos puede llevar a que si tenemos hardcodeada la conexión, obtengan las credenciales para accesar. Es por ello que mejor las encripté y así les va a costar uno y la mitad del otro, aún habiendole hecho ingeniería inversa al código (esto si es que el mismo está ofuscado).

Pero bueno, ahora quiero compartir el mismo método de encriptación para que puedan implementarlo en sus proyectos web. Al final del post les incluiré el RAR con el código fuente para que lo implementen.

¿Qué es XOR?

El operador Exclusive OR, mejor conocido como EXOR, o XOR en programación es un operador lógico en donde el resultado es 1 si es que únicamente uno de los bits con los que se está trabajando es 1, nunca si son 2 o más, por lo que tendríamos para este operador lógico la siguiente tabla de verdad:

X Y XY
0 0 0
0 1 1
1 0 1
1 1 0

Como pueden observar, el bit que hace la conjunción de ambos valores únicamente se activa si es que uno de los 2 bits de operación lo está, entonces, nosotros partiendo de esta base vamos a hacer que una cadena de caracteres con una llave privada cualquiera sea encriptada y únicamente con dicha llave privada podemos desencriptarla.

Teoría del sistema de encriptación

El sistema va a trabajar de la siguiente manera, lo estuve analizando incluso a mano con Yagarasu y nos salió a la perfección :). Los pasos a seguir son los siguientes:

  1. Convertiremos ambas cadenas de caracteres (la cadena a encriptar y la llave privada) a su valor en ASCII.
  2. Se hará XOR a cada uno de los caracteres, es decir el primero de la cadena se comparará con el primero de la llave privada y así sucesivamente, si la llave privada es más corta que la cadena a encriptar, la llave privada vuelve a empezar hasta que se termine.
  3. Al resultado se le agregará una SALT, es decir, alteraremos el contenido original para agregarle vitaminas y minerales a la encriptación, consiste en sumarle la longitud de la llave privada al resultado de la operación XOR.
  4. El resultado con SALT será convertido a un octeto binario (si sale 15 no lo expresaremos como 1111, sino como 00001111).
  5. Este resultado se concatenará y al terminar se obtendrán nibbles.
  6. Cada nibble será convertido a decimal
  7. Al resultado de la conversión le agregaremos una segunda SALT, esta consiste en multiplicar el resultado por 4 y sumarle 0,1,2 o 3, según sea el caso.
  8. Finalmente convertiremos este valor a base64 y lo concatenaremos a la cadena encriptada.

El proceso para desencriptar es este mismo pero a la inversa. Una vez ya visto esto, pues manos a la obra. Primero lo haremos matemáticamente (como los warriors y después lo haremos con código).

MATEMÁTICO

Sean "hello" la cadena a encriptar y la llave privada "foo":
PASO 1
Valor en ASCII de "hello" ---> 104 101 108 108 111
Valor en ASCII de "foo" ---> 102 111 111

PASO 2
XOR set 1 ---> 104 ^ 102 = 14
XOR set 2 ---> 101 ^ 111 = 10
XOR set 3 ---> 108 ^ 111 = 3
XOR set 4 ---> 108 ^ 102 = 10
XOR set 5 ---> 111 ^ 111 = 0

PASO 3
14 + 3 (longitud de la llave privada) = 17
10 + 3 = 13
3 + 3 = 6
10 + 3 = 13
0 + 3 = 3

PASO 4
Binario de 17 = 00010001
Binario de 13 = 00001101
Binario de 6  = 00000110
Binario de 13 = 00001101
Binario de 3  = 00000011

Por lo que la cadena a separar por nibbles sería 0001000100001101000001100000110100000011

PASO 5
Cadena separada por nibbles = 0001 0001 0000 1101 0000 0110 0000 1101 0000 0011

PASO 6
Convertidos los nibbles a decimal resulta en los siguientes números: 1 1 0 13 0 6 0 13 0 3

PASO 7
Aplicando la segunda SALT:
 1 * 4 =  4 + 0 = 4
 1 * 4 =  4 + 1 = 5
 0 * 4 =  0 + 2 = 2
13 * 4 = 52 + 3 = 55
 0 * 4 =  0 + 0 = 0
 6 * 4 = 24 + 1 = 25
 0 * 4 =  0 + 2 = 2
13 * 4 = 52 + 3 = 55
 0 * 4 =  0 + 0 = 0
 3 * 4 = 12 + 1 = 13

PASO 8
Finalmente convirtiendo los resultados a base64 tenemos la cadena encriptada que es:
E F C 3 A Z C 3 A N ---> EFC3AZC3AN

PROGRAMACION DEL SISTEMA EN PHP

Para la programación en PHP, lo voy a hacer en clase, por lo que comenzaremos con la construcción de la misma, siendo así:

class XORB64Crypto {
      private $privatekey;
      private $string;
      private $base64alphabet;

      public function __construct(){
          $this->base64alphabet = str_split("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 1);
      }

      public function encode($string, $key){
          $this->privatekey = $key;
          $this->string = $string;
      }
      public function decode($hash, $key){

      }
}

Como pueden observar, nosotros requeriremos desde el constructor que nos entregue los valores de la cadena a encriptar y de la llave privada, por lo que únicamente las funciones encode y decode se dedicarán a tomarlas de las variables miembro para hacer el procedimiento. Ustedes pueden hacerlo como gusten, obviamente si siguen la regla de oro de hash ‘n slash: no hagas copy/paste del código aquí descrito. Es con la finalidad de que aprendan a hacerlo, no por estar de mamón 😛

Ahora bien, nos dedicaremos por el momento a la función encode, por lo que para los pasos 1 y 2 agregaremos estas líneas de código:

 $stringarray = str_split($this->string, 1);
 $privatekeyarray = str_split($this->privatekey, 1);
 $privatekeylength = count($privatekeyarray);
 $privatekeycharcount = 0;

 foreach($stringarray as $char){
 $ascii = ord($char);
 $privatekeycharcount = ($privatekeycharcount != 0 && $privatekeycharcount % $privatekeylength == 0) ? 0 : $privatekeycharcount;

 $asciikey = ord($privatekeyarray[$privatekeycharcount]);

 $xor = $ascii ^ $asciikey;
 $privatekeycharcount++; // Esta línea va al final de todo el procedimiento dentro del foreach

Ahora bien para el paso 3 , solamente se agrega a la función esta línea:

 $xorsalt = $xor + $privatekeylength; 

Para el paso 4 agregamos lo siguiente:

 $binary = decbin($xorsalt);
 $binary = substr("00000000", 0, 8 - strlen($binary)) . $binary;

A continuación los pasos 5, 6 y 7 se hacen en un ciclo for que corresponde a la separación por nibbles de la cadena binaria.

for($k = 0; $k < strlen($binary); $k += 4){      $nibble = bindec(substr($binary, $k, 4));      $nibble = ($nibble * 4) + $m;      $encoded .= $this->base64FromInt($nibble);
     ++$m;

     $m = ($m > 3) ? 0 : $m;
}

Finalmente ya fuera del foreach y de todo ciclo, solamente regresen la cadena generada:

 return $encoded; 

Ahora bien, para implementarlo de una manera básica usen la siguiente sintaxis en otro archivo PHP que tenga una vista, es decir, que ya tenga algo de código HTML (de jodido el body xD):

 	require("sys/XORB64Crypto.class.php"); //Sustituyan por la ruta donde tengan su clase
 	$crypto = new XORB64Crypto("hello", "foo");
 	var_dump($crypto->encode());

Pues bien, ahora al probarlo en el explorador debe de salir el siguiente mensaje:

Resultado de la codificación XOR con base64

Resultado de la codificación XOR con base64

Si lo comparamos con el resultado matemático habremos hecho correctamente el procedimiento, ahora bien, como les comenté, el procedimiento de decriptación es exáctamente la inversa, por lo que el código de la función decode es el siguiente:

public function decode($hash, $key){
	$decoded = "";
	$binarydata = "";
	$keyarray = str_split($hash, 1);
	$m = 0;

	$hash = str_split($hash, 1);
	$key = str_split($key, 1);

	foreach($hash as $c){
		$v = ($this->intFromBase64($c) - $m) / 4;
		$b = decbin($v);
		$binarydata .= substr("0000", 0, 4 - strlen($b)).$b;

		++$m;
		$m = ($m > 3) ? 0 : $m;
	}

	$keypos = 0;

	for($i = 0; $i < strlen($binarydata); $i += 8){
                if($i + 8 > strlen($binarydata)){ break; }
		$c = bindec(substr($binarydata, $i, 8));

		$xorc = ($c - count($key)) ^ ord($key[$keypos]);
		++$keypos;
		$keypos = ($keypos >= count($key)) ? 0 : $keypos;

		$decoded .= chr($xorc);
	}

	return $decoded;
}

La implementación de la función de decodificación es exáctamente igual y debe darles como resultado “hello”, al ser el procedimiento inverso. Pues no me queda más que agradecerles por su amable atención y espero que les sirva en sus proyectos en cuanto a seguridad se refiere, pueden dejarme un comentario en caso de que lo tengan, dudas, etc. Estoy para ayudarles si es que se atoran en alguna parte del proceso. Casi lo olvidaba, aquí les dejo el código fuente

Saludos y feliz coding.

Anuncios

Autor: RZEROSTERN

Solamente soy un desarrollador que se dedica de tiempo completo a armar una que otra pendejada en la web xD. Fan de Phineas y Ferb, del merol y de muchas otras cosas más.

Un pensamiento en “Criptografía XOR con base64 en PHP

  1. Excelente post, mano. Chingón que en sólo día y medio implementaras el algoritmo en C#, lo trasladaras a PHP orientado a objetos y aparte escribieras un post acerca de eso :D.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s