Cifrar archivo asimetricamente con PHP

En este articulo dejare el código para cifrar archivos con PHP usando el API de OPENSSL Asimétricamente ( RSA )

Hay 2 formas de cifrar las cosas, cifrados asimétricos y simétrico.

Un cifrado simétrico es el que tiene una llave activada con un password único que deben conocer quiénes van a manipular esa información, la ironía de esto radica en que si son personas que están en lugares remotos enviar el password en primer lugar ya es un despropósito, un atacante snifeando la conexión puede capturar el passowrd, luego capturar los datos cifrados y usar el password para descifrarlos.

Un cifrado asimétrico es con claves públicas y privadas, actualmente no hay forma de atacar excepto con fuerza bruta ( a maquinazos ) siempre y cuando la cantidad de bits en la llaves de cifrado sea lo suficientemente alto permanece seguro, en el 2015 es inviable intentar atacar una llave de 2048 bits y ya ni hablar de 4096 bits, mientras más poder de cálculo/computo se tenga más larga puede ser la llave sin afectar el rendimiento

Asimétrico vs Simétrico

Un cifrado simétrico es muy seguro y rápido, su rapidez también es su perdición, actualmente con el poder de cómputo actual es casi imposible romper un AES pero en el futuro esto será posible porque su llave tiene un limite fijo

Un cifrado asimétrico tiene el mismo limitante, excepto que la longitud de la lleve puede ir al infinito, mientras más grande es la llave más seguro es, cuando aumente el poder de computo para darle un maquinazo lo único que habría que hacer es usar una llave con longitud más alta. Se debe considerar que al ser un sistema más complicado. Cifrar o descifrar cosas con un método asimétrico se vuelve lento y al CPU se le tortura con pesadas cargas de procesamiento.

Simplemente es una por otra, quieres velocidad de cifrado usas un método simétrico aunque es más vulnerable, quieres extrema seguridad usa asimétrico pero si tienes que cifrar y descifrar constantemente tus procesos entraras en un cuello de botella.

Lo mejor de los 2 mundos.

Actualmente lo que se hace es usar ambos métodos en una misma conexión, si el problema del método simétrico es enviar una clave para que el receptor descifre los datos. Lo que se hace es establecer la conexión asimétrica y una vez asegurada la conexión se envía en ese momento la clave se deja de usar asimétricamente y se pasa a simétrico.

Entendiendo el concepto de transporte según la llave y la longitud de la llave.

Muchas veces se habla de llaves de 1024 bits o de 128 bytes indistintamente, es porque son lo mismo.

Un byte son exactamente 8 bits, 128 bytes contienen exactamente 1024 bits ( 128 x 8 ) = 1024

Un bloque de información asimétrica con llave 1024 puede transportar un máximo de 128 bytes, por supuesto que no todos esos bytes son usados para el transporte de información, se requieren 11 bytes para el manejo de los datos cifrados dejando un total disponible de 117 bytes por cada bloque para ser usados por el programador o la aplicación y cifrar las cosas.

1024 bits = 128 bytes, de los cuales ( 128 bytes – 11 bytes ) = 117 útiles
2048 bits = 256 bytes de los cuales ( 256 bytes – 11 ) = 245 bytes útiles
4096 bits = 512 bytes , etc, etc

Asumiendo que trabajamos con una llave de 1024 bits

El bloque siempre tendrá un tamaño de 128 bytes aunque solo cifres la palabra hola, también hay que tomar en cuenta que si cada bloque es de un máximo de 117 bytes el archivo a cifrar se tiene que dividir en pequeños bloques de 117 bytes cada uno de estos bloques tendrá que ser cifrado individualmente para finalmente concatenar los bloques en un único archivo cifrado al 100%. Otra cosa a considerar es que el archivo cifrado aumentara considerablemente de tamaño debido a que cada 117 bytes reales del archivo se le suma los 11 bytes del algoritmo de cifrado.

Para descifrar el archivo se hace lo mismo pero la inversa, esta vez se toman los 128 bytes del bloque y se descifran dando por resultado los 117 bytes originales, que deberán ser concatenados en un único archivo descifrado dando por resultado el archivo original.

Ejemplo con PHP

Cifrar un archivo subido mediante formulario WEB

<?php

function ssl_encrypt($source,$type,$key){

$maxlength=245;
$output='';
while($source){
  $input= substr($source,0,$maxlength);
  $source=substr($source,$maxlength);
  if($type=='private'){
    $ok= openssl_private_encrypt($input,$encrypted,$key);
  }else{
    $ok= openssl_public_encrypt($input,$encrypted,$key);
  }

  $output.=$encrypted;
}
return $output;
}

$uploads_dir = "/tmp";
        $tmp_name =
$_FILES["userfile"]["tmp_name"][0];
        $name1 =
$_FILES["userfile"]["name"][0];
       
move_uploaded_file($tmp_name, "$uploads_dir/$name1");

$archivo1 = $uploads_dir."/".$name1;

$gestor = fopen($archivo1, "r");
$dato = fread($gestor, filesize($archivo1));
fclose($gestor);

unlink ($archivo1);

header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$name1.rsa\"");

echo ssl_encrypt($dato,"publica","file://publica.key");

?>

Descifrado de un archivo subido mediante formulario WEB

<?php

function ssl_decrypt($source,$type,$key){

$maxlength=256;
$output='';
while($source){
  $input= substr($source,0,$maxlength);
  $source=substr($source,$maxlength);
  if($type=='private'){
    $ok= openssl_private_decrypt($input,$out,$key);
  }else{
    $ok= openssl_public_decrypt($input,$out,$key);
  }

  $output.=$out;
}
return $output;

}

$uploads_dir = "/tmp";
        $tmp_name =
$_FILES["userfile"]["tmp_name"][0];
        $name1 =
$_FILES["userfile"]["name"][0];
       
move_uploaded_file($tmp_name, "$uploads_dir/$name1");

$archivo1 = $uploads_dir."/".$name1;

$gestor = fopen($archivo1, "r");
$dato = fread($gestor, filesize($archivo1));
fclose($gestor);

unlink ($archivo1);

$nombrearchivo = substr($name1, 0, -4);

header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$nombrearchivo\"");

echo ssl_decrypt($dato,"private","file://privada.key");

?>

Add a Comment

Comment spam protected by SpamBam