Borrado seguro de archivos

2613 vistas

puede ser interesante poder borrar de forma segura un archivo, es decir, de forma que sea casi imposible su recuperación con ningún programa "recuperador de archivos".

Esta función implementa el estándar DOD 5220.22-M del Depto. de defensa de EEUU para la limpieza y saneado de datos.

La rútina realiza lo siguiente:
  1. Machaca el contenido del archivo 3 veces con un patrón distinto: todo a ceros, todo a unos y contenido aleatorio
  2. Renombra el archivo 26 veces
  3. Finalmente, borra el archivo

Aquà presentamos la unit entera:



delphi
  1. unit SecureDel;
  2.  
  3. interface
  4.  
  5. function BorrarFichero(const NombreFichero: String): Boolean;
  6.  
  7. implementation
  8.  
  9. uses
  10.   Windows, SysUtils;
  11.  
  12. const
  13.   TAMANIO_BUFFER = 65536;
  14.   NRO_BUFFERS = 3;
  15.  
  16. var
  17.   FBuffers: array [0..NRO_BUFFERS-1] of ^byte;
  18.  
  19. procedure CrearBuffers;
  20. var
  21.   i, j: Integer;
  22.   p: ^byte;
  23. begin
  24.   // obtenemos la memoria para los buffers (64Kb cada uno)
  25.   // y los rellenamos con info aleatoria
  26.   Randomize;
  27.   for i:=0 to Pred( NRO_BUFFERS ) do begin
  28.       GetMem( FBuffers[i], TAMANIO_BUFFER );
  29.       case i of
  30.             0: ;  // relleno con ceros (lo hace el sistema)
  31.             1: FillChar( FBuffers[i]^, TAMANIO_BUFFER, $FF );
  32.             2: begin
  33.                   p := @(FBuffers[i]^);
  34.                   for j := TAMANIO_BUFFER downto 1 do begin
  35.                       p^ := byte( Random( $FF ) );
  36.                       Inc(p);
  37.                   end;
  38.               end;
  39.       end;
  40.   end;
  41. end;
  42.  
  43. procedure DestruirBuffers;
  44. var i: Integer;
  45. begin
  46.   for i:=0 to Pred( NRO_BUFFERS ) do FreeMem( FBuffers[i] )
  47. end;
  48.  
  49. function RenombrarFichero(const NombreFichero: String; var NuevoNombreFichero: String): Boolean;
  50. const
  51.   NRO_VECES_RENOMBRA = 26;
  52. var
  53.   i, j : Integer;
  54.   TmpNombreFichero, Ruta: String;
  55. begin
  56.   Ruta := ExtractFilePath( NombreFichero );
  57.   TmpNombreFichero := ExtractFileName( NombreFichero );
  58.   NuevoNombreFichero := TmpNombreFichero;
  59.   for i:= 0 to Pred( NRO_VECES_RENOMBRA ) do begin
  60.       for j := 1 to Length( NuevoNombreFichero ) do
  61.           if NuevoNombreFichero[j] <> '.'
  62.               then NuevoNombreFichero[j] := Char( Ord('A') + i );
  63.       if FileExists( Ruta + NuevoNombreFichero )
  64.           then Continue;
  65.       Result := RenameFile( Ruta + TmpNombreFichero, Ruta + NuevoNombreFichero );
  66.       if not Result
  67.           then Exit;
  68.       TmpNombreFichero := NuevoNombreFichero;
  69.   end;
  70.   NuevoNombreFichero := Ruta + NuevoNombreFichero;
  71. end;
  72.  
  73. procedure MachacarFichero(const h: THandle; Longitud: Cardinal);
  74. var
  75.   i: Integer;
  76.   Posicion, TotalBytes, BytesEscritos, BytesAEscribir: Cardinal;
  77. begin
  78.   Posicion := Longitud;
  79.   for i:=0 to NRO_BUFFERS-1 do begin
  80.     if i <> 0
  81.         then SetFilePointer( h, -Posicion, nil, FILE_CURRENT );
  82.     TotalBytes := 0;
  83.     while TotalBytes < Longitud do begin
  84.         if Longitud - TotalBytes > TAMANIO_BUFFER
  85.                 then BytesAEscribir := TAMANIO_BUFFER
  86.                 else BytesAEscribir := Longitud - TotalBytes;
  87.         BytesEscritos := FileWrite( h, (FBuffers[i])^, BytesAEscribir );
  88.         if BytesEscritos = $FFFFFFFF
  89.             then RaiseLastWin32Error;
  90.         Inc( TotalBytes, BytesEscritos );
  91.     end;
  92.   end;
  93. end;
  94.  
  95. function BorrarFichero(const NombreFichero: String): Boolean;
  96. var
  97.   h: THandle;
  98.   UltNomFich: String;
  99.   TamanioFileHi, TamanioFileLo, BytesAEscribir: Cardinal;
  100.   TamanioFile, BytesEscritos: Int64;
  101. begin
  102.  
  103.   Result := False;
  104.  
  105.   // cambiamos atributos del archivo por si tuviera atributos de solo lectura
  106.   Result := FileSetAttr( NombreFichero, faArchive ) = 0;
  107.   if not Result then begin
  108.     RaiseLastWin32Error;
  109.     Exit;
  110.   end;
  111.  
  112.   // abrimos el archivo para escritura
  113.   h := FileOpen( NombreFichero, fmOpenWrite );
  114.   Result := h <> -1;
  115.   if not Result then begin
  116.     RaiseLastWin32Error;
  117.     Exit;
  118.   end;
  119.  
  120.   // creamos los buffers de escritura de archivo
  121.   CrearBuffers;
  122.  
  123.   try
  124.     // obtenemos tamaño del archivo
  125.     TamanioFileLo := GetFileSize( h, @TamanioFileHi );
  126.  
  127.     // si el archivo no tiene tamaño 0, lo machacamos
  128.     if ( TamanioFileLo > 0 ) or ( TamanioFileHi > 0 ) then begin
  129.  
  130.         // ponemos el puntero del archivo al final
  131.         Dec( TamanioFileLo );
  132.         if ( TamanioFileLo = $FFFFFFFF ) and ( TamanioFileHi > 0 )
  133.             then Dec( TamanioFileHi );
  134.         SetFilePointer( h, TamanioFileLo, @TamanioFileHi, FILE_BEGIN );
  135.  
  136.         // escribimos un cero byte al final del archivo, lo q hace
  137.         // q el SO rellene con ceros todo el espacio ocupado por el archivo
  138.         MachacarFichero(h, 1);
  139.  
  140.         // volvemos al principio del archivo y sobreescribimos
  141.         SetFilePointer( h, 0, nil, FILE_BEGIN );
  142.         BytesEscritos := 0;
  143.         TamanioFile := TamanioFileLo or (TamanioFileHi shl 32);
  144.         while BytesEscritos < TamanioFile do
  145.         begin
  146.             if TamanioFile - BytesEscritos < TAMANIO_BUFFER
  147.                 then BytesAEscribir := TamanioFile - BytesEscritos
  148.                 else BytesAEscribir := TAMANIO_BUFFER;
  149.             MachacarFichero( h, BytesAEscribir );
  150.             Inc( BytesEscritos, BytesAEscribir );
  151.         end;
  152.     end;
  153.   finally
  154.     // cerramos el archivo y liberamos memoria
  155.     FileClose( h );
  156.     DestruirBuffers;
  157.   end;
  158.  
  159.   // cambiamos el archivo de nombre repetidas veces
  160.   Result := RenombrarFichero( NombreFichero, UltNomFich );
  161.  
  162.   // finalmente, borramos el archivo
  163.   if Result then Result := DeleteFile( UltNomFich );
  164.  
  165. end;
  166.  
  167. end.



Y ahora un ejemplo de llamada:



delphi
  1. uses
  2.   SecureDel;
  3.  
  4. ....
  5.  
  6. procedure TForm1.Button1Click(Sender: TObject);
  7. begin
  8.   if edFile.Text <> '' then
  9.       if FileExists(edFile.Text) then
  10.         if BorrarFichero(edFile.Text) then
  11.         begin
  12.             ShowMessage('¡Hecho!');
  13.             edFile.Clear;
  14.         end
  15.       else
  16.         showmessage('El archivo no existe');
  17. end;