Una pregunta que se repite con cierta frecuencia en los foros de programación es como se puede cifrar y descifrar usando sha, md5, etc ... Suelen hacerlas gente que se esta iniciando en el mundo de la criptografía y no tiene muy claro todavía para que sirve cada cosa. La respuesta mas común es decirles que esos son algoritmos de reducción (resumen o simplemente "hash") y que no se pueden usar para cifrar / descifrar, pero eso no es del todo cierto.
El siguiente ejemplo muestra como se puede usar un algoritmo de reducción, como es SHA256, para cifrar y descifrar datos usando el método de cifrado por bloques conocido como Cipher feedback (CFB).
Las siguientes imágenes muestran brevemente como funciona este método:
Como se ve en la imágenes solamente necesitamos que el algoritmo de cifrado vaya en un sentido, por lo que se puede utilizar sin problemas una función de hash.
Un poco de código:
program Crypt; {$APPTYPE CONSOLE} uses Windows, SysUtils, Classes, SeSHA256 in 'SeSHA256.pas'; procedure Cifrar(Src, Dst: TStream; Key: WideString; Desc: Boolean); var i,j: Integer; Temp: TMemoryStream; Buffer, Hash: TSHA256HASH; begin Temp:= TMemoryStream.Create; try // Leemos el primer bloque (32 bytes) i:= Src.Read(Buffer,Sizeof(Buffer)); while i > 0 do begin // Añadimos la clave al buffer anterior para generar el Hash Temp.WriteBuffer(PWideChar(Key)^,Length(Key)*Sizeof(WideChar)); Temp.Position:= 0; // Generamos el hash de la clave y el buffer anterior Hash:= CalcSHA256(Temp); Temp.Clear; if Desc then // Si estamos descifrando usamos el buffer antes de descifrar Temp.WriteBuffer(Buffer,Sizeof(Buffer)); for j:= 0 to 7 do // Ciframos el buffer con el hash generado Buffer[j]:= Buffer[j] xor Hash[j]; // Escribimos el resultado Dst.WriteBuffer(Buffer,i); if not Desc then // Si estamos cifrando usamos el buffer despues de cifrar Temp.WriteBuffer(Buffer,Sizeof(Buffer)); // Leemos el siguiente bloque i:= Src.Read(Buffer,Sizeof(Buffer)); end; finally Temp.Free; end; end; var Origen, Destino: TFileStream; begin if ParamCount < 3 then Exit; try Origen:= TFileStream.Create(ParamStr(1),fmOpenRead or fmShareDenyWrite); try Destino:= TFileStream.Create(ParamStr(2),fmCreate); try // Ciframos o desciframos dependiendo del parametro /d Cifrar(Origen,Destino,ParamStr(3),FindCmdLineSwitch('d',TRUE)); finally Destino.Free; end; finally Origen.Free; end; except On E: Exception do Writeln(E.Message); end; end.
Para usarlo:
Crypt origen.txt cifrado.bin Clave Crypt cifrado.bin descifrado.txt Clave /d
Una de las ventajas de este método es que los datos cifrados tienen el mismo tamaño que el original y no un múltiplo del tamaño del bloque, por lo que no es necesario guardar aparte el tamaño del original. En cuanto a la seguridad, debería ser similar a métodos mas tradicionales de cifrado como AES, aunque no esta tan revisado y comprobado como este último.
Enlaces de interés:
http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_feedb...
https://github.com/dxeoane/secrypt
Comentarios
Código claro y conciso, como
Código claro y conciso, como siempre, Domingo.
Gracias.
Muy buen ejercicio amigo,
Muy buen ejercicio amigo, como siempre muy bien documentado. :)
Saludos
Edito: Muy difícil el captcha amigo, a éstas horas ya mi cerebro no quiere hacer operaciones aritméticas :D :D :D