Cifrar archivo con AES

Ya he tratado anteriormente este tema pero parece que son necesarios unos cuantos ejemplos mas, sobre todo a la hora de trabajar con ficheros, ya que hasta ahora la mayoría de los ejemplos que he puesto trabajan con cadenas de texto.

El siguiente ejemplo muestra dos funciones, una para cifrar y otra para descifrar:

uses AES, SHA256;
 
procedure CifrarArchivo(Origen,Destino: String; Clave: AnsiString);
var
  Src, Dst: TFileStream;
  Key: TAESKey;
  ExpandedKey: TAESExpandedKey;
  Size: int64;
begin
  Src:= TFileStream.Create(Origen,fmOpenRead or fmShareDenyNone);
  try
    Dst:= TFileStream.Create(Destino,fmCreate);
    try
      // Guardamos el tamaño del fichero original
      Size:= Src.Size;
      Dst.WriteBuffer(Size,Sizeof(Size));
      // Usamos como Key el hash SHA256 de la Clave
      TSHA256HASH(Key):= CalcSHA256(Clave);
      AEsExpandKey(ExpandedKey,Key);
      // Ciframos el archivo
      AESEncryptStreamECB(Src,Dst,ExpandedKey);
    finally
      Dst.Free;
    end;
  finally
    Src.Free;
  end;
end;
 
procedure DescifrarArchivo(Origen,Destino: String; Clave: AnsiString);
var
  Src, Dst: TFileStream;
  Key: TAESKey;
  ExpandedKey: TAESExpandedKey;
  Size: int64;
begin
  Src:= TFileStream.Create(Origen,fmOpenRead);
  try
    Dst:= TFileStream.Create(Destino,fmCreate);
    try
      // Leemos el tamaño del fichero
      Src.ReadBuffer(Size,Sizeof(Size));
      // Usamos como Key el hash SHA256 de la Clave
      TSHA256HASH(Key):= CalcSHA256(Clave);
      AEsExpandKey(ExpandedKey,Key);
      // Desciframos el archivo
      AESDecryptStreamECB(Src,Dst,ExpandedKey);
      // Lo recortamos a su tamaño original   
      Dst.Size:= Size;
    finally
      Dst.Free;
    end;
  finally
    Src.Free;
  end;
end;
 
// Por ejemplo
CifrarArchivo(ParamStr(0),ParamStr(0)+'.1','Password');
DesCifrarArchivo(ParamStr(0)+'.1',ParamStr(0)+'.2','Password');

Le podemos dar una vuelta de tuerca comprimiendo el fichero cifrado:

uses AES, SHA256, zlib;
 
procedure zCifrarArchivo(Origen,Destino: String; Clave: AnsiString);
var
  Src, Dst: TFileStream;
  Cmp: TCompressionStream;
  Key: TAESKey;
  ExpandedKey: TAESExpandedKey;
  Size: int64;
begin
  Src:= TFileStream.Create(Origen,fmOpenRead or fmShareDenyNone);
  try
    Dst:= TFileStream.Create(Destino,fmCreate);
    try
      // Guardamos el tamaño del fichero original
      Size:= Src.Size;
      Dst.WriteBuffer(Size,Sizeof(Size));
      // Usamos como Key el hash SHA256 de la Clave
      TSHA256HASH(Key):= CalcSHA256(Clave);
      AEsExpandKey(ExpandedKey,Key);
      // Ciframos el archivo y comprimimos el resultado
      Cmp:= TCompressionStream.Create(clMax,Dst);
      try
        AESEncryptStreamECB(Src,Cmp,ExpandedKey);
      finally
        Cmp.Free;
      end;
    finally
      Dst.Free;
    end;
  finally
    Src.Free;
  end;
end;
 
procedure zDescifrarArchivo(Origen,Destino: String; Clave: AnsiString);
var
  Src, Dst: TFileStream;
  Cmp: TDeCompressionStream;
  Key: TAESKey;
  ExpandedKey: TAESExpandedKey;
  Size: int64;
begin
  Src:= TFileStream.Create(Origen,fmOpenRead);
  try
    Dst:= TFileStream.Create(Destino,fmCreate);
    try
      // Leemos el tamaño del fichero
      Src.ReadBuffer(Size,Sizeof(Size));
      // Usamos como Key el hash SHA256 de la Clave
      TSHA256HASH(Key):= CalcSHA256(Clave);
      AEsExpandKey(ExpandedKey,Key);
      // Descomprimimos y desciframos el archivo
      Cmp:= TDeCompressionStream.Create(Src);
      try
        AESDecryptStreamECB(Cmp,Dst,ExpandedKey);
        Dst.Size:= Size;
      finally
        Cmp.Free;
      end;
    finally
      Dst.Free;
    end;
  finally
    Src.Free;
  end;
end;
 
// Por ejemplo
zCifrarArchivo(ParamStr(0),ParamStr(0)+'.1','Password');
zDesCifrarArchivo(ParamStr(0)+'.1',ParamStr(0)+'.2','Password');

Podemos hacer un ejemplo mas general, si en vez de archivos usamos streams

procedure CifrarStream(Src, Dst: TStream; Clave: AnsiString);
var
  Key: TAESKey;
  ExpandedKey: TAESExpandedKey;
  Size: int64;
begin
  // Guardamos el tamaño del stream original
  Size:= Src.Size;
  Dst.WriteBuffer(Size,Sizeof(Size));
  // Usamos como Key el hash SHA256 de la Clave
  TSHA256HASH(Key):= CalcSHA256(Clave);
  AEsExpandKey(ExpandedKey,Key);
  // Ciframos el stream
  AESEncryptStreamECB(Src,Dst,ExpandedKey);
end;
 
procedure DescifrarStream(Src, Dst: TStream; Clave: AnsiString);
var
  Key: TAESKey;
  ExpandedKey: TAESExpandedKey;
  Size: int64;
begin
  // Leemos el tamaño del stream original
  Src.ReadBuffer(Size,Sizeof(Size));
  // Usamos como Key el hash SHA256 de la Clave
  TSHA256HASH(Key):= CalcSHA256(Clave);
  AEsExpandKey(ExpandedKey,Key);
  // Descomprimimos el stream
  AESDecryptStreamECB(Src,Dst,ExpandedKey);
  Dst.Size:= Size;
end;
 
// Por ejemplo
var
  F1,F2: TFileStream;
  M: TMemorystream;
begin
  F1:= TFileStream.Create(ParamStr(0),fmOpenRead or fmShareDenyNone);
  try
    M:= TMemoryStream.Create;
    try
      // Ciframos el contenido del primer stream y
      // guardamos el resultado en el segundo stream
      CifrarStream(F1,M,'Password');
      // Ponemos el stream cifrado en la posicion 0
      M.Position:= 0;
      // Y lo desciframos
      F2:= TFileStream.Create(ParamStr(0)+'.1',fmCreate);
      try
        DescifrarStream(M,F2,'Password');
      finally
        F2.Free;
      end;
    finally
      M.Free;
    end;
  finally
    F1.Free;
  end;   
end;
 
// O este otro ejemplo
var
  M1, M2: TMemorystream;
begin
  M1:= TMemoryStream.Create;
  try
    M2:= TMemoryStream.Create;
    try
      Memo1.Lines.SaveToStream(M1);
      // Ponemos el stream en la posicion 0
      M1.Position:= 0;
      CifrarStream(M1,M2,'Password');
      // Ponemos el stream cifrado en la posicion 0
      M2.Position:= 0;
      // Borramos M1
      M1.Clear;
      // Y lo desciframos
      DescifrarStream(M2,M1,'Password');
      M1.Position:= 0;
      Memo2.Lines.LoadFromStream(M1);
    finally
      M2.Free;
    end;
  finally
    M1.Free;
  end;
end;

Enlaces de interes:
Cifrado AES-256 - http://delphi.jmrds.com/?q=node/31
Calcular el hash SHA256 de un texto - http://delphi.jmrds.com/?q=node/64

Comentarios

Estupendo, ¡gracias! :)

Funciona Perfecto. Eres un genio.

Un millón de gracias y otro tanto de saludos.

Añadir nuevo comentario