program CifradorBloques;

{$mode objfpc}{$H+}
{$APPTYPE CONSOLE}
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes, SysUtils, md5;


var
  fuente, destino : File;
  nombre_fuente,  nombre_destino, Hash, nombre_claves  : string;
  cont                   :  byte;
  buffer                 : Array [1..2048] of Byte;
  RegLeidos, RegEscritos,  Num    : Word;


begin
  WriteLn ('***** CIFRADO XOR *****');
  WriteLn ('***********************');
  Write('Archivo Origen     : '); Readln(nombre_fuente);
  Write('Archivo Destino    : '); Readln(nombre_destino);
  Write('Archivo de Clave   : '); Readln(nombre_claves);


  AssignFile(fuente,nombre_fuente);
  AssignFile(destino,nombre_destino);

  {$I+}
  try
    if FileExists(nombre_claves) then
      begin
      Hash := MD5Print(MD5File(nombre_claves));
      Reset(fuente, 1);   // cada bloque 1 byte
      Rewrite(destino, 1);  // cada bloque 1 byte
      end

    else Writeln('Archivo de Clave NO existe', sLineBreak);

  cont := 1;
   try
   Repeat
     BlockRead(fuente, buffer, SizeOf(buffer), RegLeidos);
     for Num := 1 to RegLeidos do
       begin
         buffer[Num] := buffer[Num] xor Ord(Hash[cont]); // xor byte a byte
         cont += 1;
         if cont > length(Hash) then cont := 1
       end;

     BlockWrite(destino,buffer,RegLeidos,RegEscritos);
   Until (RegLeidos = 0) or (RegEscritos <> RegLeidos);

  if RegEscritos <> RegLeidos
     then Writeln('Error. ¿Disco lleno?');
  finally
  CloseFile(fuente);
  CloseFile(destino);
  end;
   except
    on E: EInOutError do
    begin
     Writeln('Ha ocurrido un error. Detalles:'+E.ClassName+'/'+E.Message, sLineBreak);
    end;
  end;
    Writeln('Proceso acabado. Pulse Enter');
    {$IFDEF WINDOWS}
    ReadLn;
    {$ENDIF}

end.

