Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   ¿Como funciona MD5? (https://www.clubdelphi.com/foros/showthread.php?t=84279)

danielmj 30-09-2013 16:59:36

¿Como funciona MD5?
 
Hola, estoy pensando en implementar mi aplicacion con la comprobacion de archivo corrupto usando MD5. ¿Pero como funciona esto?
Ojo, no pido que me digais como hacerlo, sino que me orienteis si es posible claro. Por ejemplo:

¿Que pasos se darian a partir de pasarle a esa funcion un archivo "x"? generaria alguna cadena alfanumerica que contenga la informacion de ese archivo y luego que? con que se compara para saber si el archivo esta o no corrupto?

Perdonad pero nunca he usado esto y estoy super perdido y lo que encuentro en google gira en torno a la encriptacion de datos pero yo pretendo otra cosa ¿no?

Saludos y gracias.

nlsgarcia 30-09-2013 18:10:35

danielmj,

Cita:

...implementar mi aplicación con la comprobación de archivo corrupto usando MD5. ¿Pero como funciona esto?...
Revisa estos links:
Cita:

MD5 : http://es.wikipedia.org/wiki/MD5

Calculate MD5 Checksum for a File or String from Delphi : http://delphi.about.com/b/2011/03/04...rom-delphi.htm

File MD5 checksum : http://stackoverflow.com/questions/4...e-md5-checksum

Delphi – MD5: the MessageDigest_5 unit has been there since Delphi 2007 : http://wiert.me/2009/12/11/delphi-md...e-delphi-2007/

Hash-Alogrithm: MD4, MD5, RipeMD160, SHA1, Haval (128-256) : http://delphi.icm.edu.pl/ftp/d20free/cipher.zip
Espero sea útil :)

Nelson.

luisgutierrezb 30-09-2013 19:48:40

A grandes razgos, consigues una unidad que calcule el MD5, las que eh visto, manejan archivos, solo le pasas la ubicacion y te regresan el MD5, despues lo conviertes a hexadecimal, generalmente la unidad tambien trae la conversion, y listo! ya tienes ese hash, para checarlo, pues sacas otro hash y que sean iguales...

mamcx 30-09-2013 20:55:56

No la ubicacion del archivo. El archivo completo.

danielmj 30-09-2013 20:56:08

gracias luisgutierrezb, estoy ahora mismo leyendo y mirando informacion sobre esto. En cuanto a tu respuesta, me ha servido para tener una idea mas general pero concreta. Espero aclararme.

Saludos.

danielmj 30-09-2013 20:58:30

Hola mancx, imagino que te refieres a la ruta completa+nombre de archivo, al menos eso es lo que yo suponia, de otra forma aun sabiendo la ubicacion del archivo, no tendrá el nombre de este. Bueno, veremos a ver como se me da esto del hash!

saludos y gracias.

danielmj 30-09-2013 21:36:43

Buenas, encontré esta unidad en la pagina de seoane:

Código Delphi [-]


unit Hashes;

interface

uses Windows, SysUtils, Classes;

type
  THashAlgorithm = (haMD5, haSHA1);

function CalcHash(Stream: TStream; Algorithm: THashAlgorithm): string; overload;
function CalcHash(Archivo: string; Algorithm: THashAlgorithm): string; overload;
function CalcHash2(Str: string; Algorithm: THashAlgorithm): string;

implementation

type
  HCRYPTPROV = ULONG;
  PHCRYPTPROV = ^HCRYPTPROV;
  HCRYPTKEY = ULONG;
  PHCRYPTKEY = ^HCRYPTKEY;
  HCRYPTHASH = ULONG;
  PHCRYPTHASH = ^HCRYPTHASH;
  LPAWSTR = PAnsiChar;
  ALG_ID = ULONG;

const
  CRYPT_NEWKEYSET = $00000008;
  PROV_RSA_FULL = 1;
  CALG_MD5 = $00008003;
  CALG_SHA1  = $00008004;
  HP_HASHVAL = $0002;

function CryptAcquireContext(phProv: PHCRYPTPROV;
  pszContainer: LPAWSTR;
  pszProvider: LPAWSTR;
  dwProvType: DWORD;
  dwFlags: DWORD): BOOL; stdcall;
  external ADVAPI32 name 'CryptAcquireContextA';

function CryptCreateHash(hProv: HCRYPTPROV;
  Algid: ALG_ID;
  hKey: HCRYPTKEY;
  dwFlags: DWORD;
  phHash: PHCRYPTHASH): BOOL; stdcall;
  external ADVAPI32 name 'CryptCreateHash';

function CryptHashData(hHash: HCRYPTHASH;
  const pbData: PBYTE;
  dwDataLen: DWORD;
  dwFlags: DWORD): BOOL; stdcall;
  external ADVAPI32 name 'CryptHashData';

function CryptGetHashParam(hHash: HCRYPTHASH;
  dwParam: DWORD;
  pbData: PBYTE;
  pdwDataLen: PDWORD;
  dwFlags: DWORD): BOOL; stdcall;
  external ADVAPI32 name 'CryptGetHashParam';

function CryptDestroyHash(hHash: HCRYPTHASH): BOOL; stdcall;
  external ADVAPI32 name 'CryptDestroyHash';

function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): BOOL; stdcall;
  external ADVAPI32 name 'CryptReleaseContext';

function CalcHash(Stream: TStream; Algorithm: THashAlgorithm): string; overload;
var
  hProv: HCRYPTPROV;
  hHash: HCRYPTHASH;
  Buffer: PByte;
  BytesRead: DWORD;
  Algid: ALG_ID;
  Data: array[1..20] of Byte;
  DataLen: DWORD;
  Success: BOOL;
  i: integer;
begin
  Result:= EmptyStr;
  Success := CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL, 0);
  if (not Success) then
    if GetLastError() = DWORD(NTE_BAD_KEYSET) then
      Success := CryptAcquireContext(@hProv, nil, nil, PROV_RSA_FULL,
        CRYPT_NEWKEYSET);
  if Success then
  begin
    if Algorithm = haMD5 then
    begin
      Algid:= CALG_MD5;
      Datalen:= 16
    end else
    begin
      Algid:= CALG_SHA1;
      Datalen:= 20;
    end;
    if CryptCreateHash(hProv, Algid, 0, 0, @hHash) then
    begin
      GetMem(Buffer,10*1024);
      try
        while  TRUE do
        begin
          BytesRead:= Stream.Read(Buffer^, 10*1024);
          if (BytesRead = 0) then
          begin
            if (CryptGetHashParam(hHash, HP_HASHVAL, @Data, @DataLen, 0)) then
              for i := 1 to DataLen do
                Result := Result + LowerCase(IntToHex(Integer(Data[i]), 2));
            break;
          end;
          if (not CryptHashData(hHash, Buffer, BytesRead, 0)) then
            break;
        end;
      finally
        FreeMem(Buffer);
      end;
      CryptDestroyHash(hHash);
    end;
    CryptReleaseContext(hProv, 0);
  end;
end;

function CalcHash(Archivo: string; Algorithm: THashAlgorithm): string; overload;
var
  Stream: TFileStream;
begin
  Result:= EmptyStr;
  if FileExists(Archivo) then
  try
    Stream:= TFileStream.Create(Archivo,fmOpenRead or fmShareDenyWrite);
    try
      Result:= CalcHash(Stream,Algorithm);
    finally
      Stream.Free;
    end;
  except end;
end;

function CalcHash2(Str: string; Algorithm: THashAlgorithm): string;
var
  Stream: TStringStream;
begin
  Result:= EmptyStr;
  Stream:= TStringStream.Create(Str);
  try
    Result:= CalcHash(Stream,Algorithm);
  finally
    Stream.Free;
  end;
end;

end.

Y hago la llamada con el siguiente codigo:

Código Delphi [-]
  if openDialog1.Execute then
    edit1.Text:= openDialog1.FileName;
    edit2.Text:= (CalcHash2(edit1.Text,haSHA1));

Devolviendome el siguiente valor alfanumerico/hex: "6dd7123776aaac7aa289b68ec03cccfeecd405d3"

Mi pregunta es ¿Ese sería el hash del archivo dado o sería el hash del contenido TEdit, tomado como cadena de texto? Espero haberme explicado.
Y por otra parte, si tengo un archivo de por ejemplo 10 Gb y lo corto con la aplicación hacha, ¿sería correcto obetener el hash del primer archivo
cortado .001? Y una vez unido de nuevo el archivo, ¿con que hash lo comparo para saber si se ha unido correctamente con el obtenido del archivo .001
y archivo unido?

Saludos y gracias de antemano.
[/color]

mamcx 30-09-2013 23:03:04

Como rayos vas a saber que:

Cita:

C:\\Archivo.txt
esta corrupto evaluando solo C:\\Archivo.txt? Se debe es hacer hash del archivo completo, no de su nombre o ubicación, de su contenido.

http://stackoverflow.com/questions/9...algorithm-work

http://www.makeuseof.com/tag/md5-has...ogy-explained/

Esto significa que el nombre del archivo no importa. Si archivo.zip y archivo.txt tienen el mismo contenido, el HASH dará igual.

Un hash es una función en un solo sentido que da como resultado la misma salida en base a la misma entrada, pero no se puede derivar en base a la salida cual fue la entrada.

Ten en cuenta que si haces un hash de un archivo de 5 Gigas y no tienes la precaución de procesar el archivo por batches usando un stream, cargaras los 5GB en memoria...

nlsgarcia 30-09-2013 23:26:46

mamcx,

Cita:

Empezado por mamcx
...Como rayos vas a saber que...

:D

Nelson.

nlsgarcia 01-10-2013 05:32:59

danielmj,

Cita:

Empezado por danielmj
...encontré esta unidad en la pagina de Seoane (Calcular hash md5)...

Revisa este código:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ClipBrd, StrUtils, ComCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Edit1: TEdit;
    ProgressBar1: TProgressBar;
    Timer1: TTimer;
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses Hashes; // Implementa la unidad de cálculo de Hash Md5 de Seoane http://delphi.jmrds.com/?q=node/11

// Inicialización de componentes.
procedure TForm1.FormCreate(Sender: TObject);
begin
   ProgressBar1.Min := 1;
   ProgressBar1.Max := 100;
   Timer1.Interval := 100;
   Timer1.Enabled := False;
   Label1.Visible := False;
end;

// Control Visual de Ejecución del Hash MD5 de un Archivo
procedure TForm1.Timer1Timer(Sender: TObject);
begin

   if ProgressBar1.Position = 100 then
      ProgressBar1.Position := 0;

   ProgressBar1.StepBy(1);

end;

// Cálculo del Hash MD5 de un Archivo (No importa el tamaño)
procedure TForm1.Button1Click(Sender: TObject);
var
   openDialog : TOpenDialog;
   AuxStr : String;
   TI, TF: TDateTime;
   Hour, Min, Sec, MSec: Word;
   MsgTime : String;

begin

   openDialog := TOpenDialog.Create(self);
   openDialog.InitialDir := GetCurrentDir;
   openDialog.Options := [ofFileMustExist];
   openDialog.Filter := 'All Files|*.*|';
   openDialog.FilterIndex := 1;

   if openDialog.Execute then
   begin

      Timer1.Enabled := True;
      Label1.Visible := True;
      Button1.Enabled := False;
      Button2.Enabled := False;
      Button3.Enabled := False;

      TI := Now;
      AuxStr := 'MD5 de ' + openDialog.FileName + ' = ' + CheckSum(openDialog.FileName);
      TF := Now - TI;
      DecodeTime(TF, Hour, Min, Sec, MSec);

      ListBox1.Items.Add(AuxStr);
      if ListBox1.ScrollWidth < ListBox1.Canvas.TextWidth(AuxStr) then
         ListBox1.ScrollWidth := ListBox1.Canvas.TextWidth(AuxStr) + 120;

      Timer1.Enabled := False;
      ProgressBar1.Position := 0;
      Label1.Visible := False;
      Button1.Enabled := True;
      Button2.Enabled := True;
      Button3.Enabled := True;

      MsgTime := Format('Tiempo de cálculo de MD5 %.2d:%.2d:%.2d:%.3d',[Hour,Min,Sec,MSec]);
      MessageDlg(MsgTime,mtinformation,[mbok],0);

   end
   else
      ShowMessage('No se seleciono ningún archivo para cálculo de MD5');

   openDialog.Free;

end;

// Cálculo del Hash MD5 de un String
procedure TForm1.Button2Click(Sender: TObject);
var
   AuxStr : String;

begin

   AuxStr := 'MD5 de ' + Edit1.Text + ' = ' + StrCheckSum(Edit1.Text);
   ListBox1.Items.Add(AuxStr);
   if ListBox1.ScrollWidth < ListBox1.Canvas.TextWidth(AuxStr) then
      ListBox1.ScrollWidth := ListBox1.Canvas.TextWidth(AuxStr) + 120;

end;

// Resetea el Form
procedure TForm1.Button3Click(Sender: TObject);
begin
   ListBox1.Clear;
   Edit1.Text := EmptyStr;
end;

// Copia Hash MD5 a Clipboard
procedure TForm1.ListBox1Click(Sender: TObject);
begin
   Clipboard.AsText := AnsiRightStr(ListBox1.Items.Strings[ListBox1.ItemIndex],32);
end;

end.
El código anterior es una implementación de la rutina de Calcular hash md5 de la Web de Seoane, como se muestra en la siguiente imagen:



El ejemplo esta disponible en el siguiente link: http://terawiki.clubdelphi.com/Delph...wnload=MD5.rar

Espero sea útil :)

Nelson

duilioisola 01-10-2013 18:45:58

Hay dos funciones en la unidad de Seoane.
A CalcHash le pasas la ruta y nombre del archivo y te devuelve su Hash.
CalcHash2 calcula el Hash de un string.

Código Delphi [-]
function CalcHash(Archivo: string; Algorithm: THashAlgorithm): string; overload;
var
  Stream: TFileStream;
begin
  Result:= EmptyStr;
  if FileExists(Archivo) then
  try
    Stream:= TFileStream.Create(Archivo,fmOpenRead or fmShareDenyWrite);
    try
      Result:= CalcHash(Stream,Algorithm);
    finally
      Stream.Free;
    end;
  except end;
end;

Por lo que tu código debe quedar así:
Código Delphi [-]
  if OpenDialog1.Execute then
    Edit1.Text:= OpenDialog1.FileName;
    Edit2.Text:= CalcHash(Edit1.Text, haSHA1);

danielmj 01-10-2013 21:25:51

Hola duilioisola, es cierto justo después de escribir el mensaje en el foro, seguía mirandome la función y vi esto que comentas. Gracias por el apunte.
De hecho hice una prueba que no sé si será correcta o no, lo que hice fue calcular el hash de una imagen jpg y luego la misma imagen abrirla con photoshop editar sus niveles, guardarla y volver a calcular el hash, y pude comprobar como eran distintos uno de otro, por lo que he supuesto que es un ejemplo valido de archivo "corrupto" en el sentido de tener dos hash diferentes sobre el mismo archivo. ¿sería valido el ejemplo?

Un saludo.

nlsgarcia 02-10-2013 14:24:40

danielmj,

Cita:

Empezado por danielmj
...¿sería válido el ejemplo?...

En términos relativos, la modificación de una archivo por cualquier medio es válida a los fines de verificación de funciones hash.

Espero sea útil :)

Nelson.

danielmj 02-10-2013 15:01:50

Muchas gracias nlsgarcia y buen avatar!
Saludos.


La franja horaria es GMT +2. Ahora son las 17:02:37.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi