# Native Code > برنامه نویسی در Delphi > مباحث عمومی دلفی و پاسکال >  الگوریتم رمزنگاری MD5

## younes-98

unit md5;

interface

type
  MD5Digest = array[0..15] of Byte;
  MD5State = array[0..3] of LongWord;
  MD5Buffer = array[0..63] of Byte;

  TMD5 = class
  private
    FState: MD5State;
    FCount: Int64;
    FBuffer: MD5Buffer;
  public
    constructor Create;
    procedure Update(const Input; Length: Cardinal);
    function Final: MD5Digest;
  end;

  
function MD5Message(const Message; Length: Cardinal): MD5Digest;
function MD5String(const S: string): MD5Digest;
function MD5File(const FileName: string): MD5Digest;

function MD5Print(const D: MD5Digest): string;


implementation

{$IFDEF MSWINDOWS}
uses
  Windows;
{$ENDIF}            


function ROL(X: LongWord; Count: Integer): LongWord;
{$IFDEF PUREPASCAL}
begin
  Result := (X shl Count) or (X shr (32 - Count));
end;
{$ELSE}
asm
        MOV     ECX,EDX
        ROL     EAX,CL
end;
{$ENDIF}


type
  MD5Iters = 0..63;

var
  k: array[MD5Iters] of Integer;
  T: array[MD5Iters] of LongWord;
  s: array[MD5Iters] of Integer;

procedure InitLUTs;
const
  A: array[0..15] of Integer =
    (
      7, 12, 17, 22,
      5,  9, 14, 20,
      4, 11, 16, 23,
      6, 10, 15, 21
    );
var
  I: Integer;
begin
  for I := 0 to 63 do
  begin
    case I of
      0..15: k[I] := I;
      16..31: k[I] := (5 * I + 1) and $f;
      32..47: k[I] := (3 * I + 5) and $f;
      48..63: k[I] := (7 * I) and $f;
    end;
    T[I] := Trunc(Abs(Sin(I + 1)) * $100000000);
    s[I] := A[I shr 2 and $c or I and $3];
  end;
end;

// MD5 basic transformation. Transforms state based on block.

procedure Transform(var State: MD5State; const Block);
var
  X: array[0..15] of LongWord absolute Block;
  a, b, c, d, i, f, temp: LongWord;
begin
  f := 0;
  a := State[0];
  b := State[1];
  c := State[2];
  d := State[3];
  for i := 0 to 63 do
  begin
    case i of
      0..15: f := d xor (b and (c xor d));
      16..31: f := c xor (d and (b xor c));
      32..47: f := b xor c xor d;
      48..63: f := c xor (b or (not d));
    end;
    temp := d;
    d := c;
    c := b;
    Inc(b, ROL(a + f + X[k[i]] + T[i], s[i]));
    a := temp;
  end;
  Inc(State[0], a);
  Inc(State[1], b);
  Inc(State[2], c);
  Inc(State[3], d);
end;


{ TMD5 }

constructor TMD5.Create;
begin
  FState[0] := $67452301;
  FState[1] := $efcdab89;
  FState[2] := $98badcfe;
  FState[3] := $10325476;
end;

type
  Bytes = array[0..0] of Byte;

procedure TMD5.Update(const Input; Length: Cardinal);
var
  I, Index, PartLen: Cardinal;
begin
  Index := FCount and $3f;
  Inc(FCount, Length);
  PartLen := 64 - Index;
  if Length >= PartLen then
  begin
    Move(Input, FBuffer[Index], PartLen);
    Transform(FState, FBuffer);
    I := PartLen;
    while I + 63 < Length do
    begin
      Transform(FState, Bytes(Input)[I]);
      Inc(I, 64);
    end;
    Index := 0;
  end
  else
    I := 0;
  Move(Bytes(Input)[I], FBuffer[Index], Length - I);
end;

function TMD5.Final: MD5Digest;
var
  BitLength: Int64;
  Padding: MD5Buffer;
  PadLen: Integer;
begin
  BitLength := FCount shl 3;
  PadLen := (119 - FCount and $3f) and $3f + 1;
  FillChar(Padding, PadLen, 0);
  Padding[0] := $80;
  Update(Padding, PadLen);
  Update(BitLength, SizeOf(Int64));
  Result := MD5Digest(FState);
  Free;
end;


// ----------------------------------------------------------------------------

function MD5Message(const Message; Length: Cardinal): MD5Digest;
begin
  with TMD5.Create do
    try
      Update(Message, Length);
      Result := Final;
    except
      Free;
      raise;
    end;
end;

function MD5String(const S: string): MD5Digest;
begin
  Result := MD5Message(Pointer(S)^, Length(S));
end;

function MD5File(const FileName: string): MD5Digest;
{$IFDEF MSWINDOWS}
var
  FileHandle: THandle;
  MapHandle: THandle;
  ViewPointer: Pointer;
{$ENDIF}
begin
  FillChar(Result, SizeOf(MD5Digest), 0);
{$IFDEF MSWINDOWS}
  FileHandle := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ or
    FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or
    FILE_FLAG_SEQUENTIAL_SCAN, 0);
  if FileHandle <> INVALID_HANDLE_VALUE then
    try
      MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil);
      if MapHandle <> 0 then
        try
          ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0);
          if ViewPointer <> nil then
            try
              Result := MD5Message(ViewPointer^, GetFileSize(FileHandle, nil));
            finally
              UnmapViewOfFile(ViewPointer);
            end;
        finally
          CloseHandle(MapHandle);
        end;
    finally
      CloseHandle(FileHandle);
    end;
{$ENDIF}
end;


function MD5Print(const D: MD5Digest): string;
const
  Digits: array[0..15] of Char =
    ('0','1','2','3','4','5','6','7','8','9','a','b','  c','d','e','f');
var
  I: Integer;
  TempStr: string[32];
begin
  TempStr := '';
  for I := 0 to 15 do
    TempStr := TempStr + Digits[D[I] shr 4] + Digits[D[I] and $f];
  Result := TempStr;
end;


initialization
  InitLUTs;

end.

----------


## Batman

با تشکر
دوست عزیز ممکنه طریقه استفاده از unit و همچنین اینکه چجوری باید چکش کرد رو توضیح بدید؟
ممنونم

----------


## younes-98

معرفی الگوریتم MD5

Hash چیست ؟
یک توضیح مختصر در مورد کد گزاری و روش های مختلف : 
روش های مختلفی برای کد گزاری وجود دارد مانند توابع و الگوریتم های Randomize و Hash و ... 
معمولا هدف اصلی از کد گزاری دو گزینه میباشد 
1- امنیت 
2- ایجاد کلید های منحصر بفرد 

در واقع این دو مورد پر کاربرد ترین موارد استفاده از کد گزاری میباشد
توضیح : 
برای ایجاد امنیت در برنامه های مختلف از روش های کد گزاری استفاده میشود ، برای مثال در ذخیره پسورد یوزر های سایتها
مثالی که برای ایجاد کلید های منحصر به فرد میشه زد در امضا های اینترنتی میباشد 
برای ایجاد امضا هایی که به صورت منحصر به فرد و بدون تکرار باشند از این روش ها استفاده میشود
برای معرفی Hash سعی میکنم با معرفی MD5 مفهوم اصلی Hash را عنوان کنم 

هش (Hash, Hash Code, Digest, Message Digest هم نامیده می شود) را می توان به صورت اثر انگشت دیجیتالی یک داده در نظر گرفت. با این روش شما می توانید رشته ای اندازه-ثابت (fixed length) از یک داده به دست آورید که با روش های ریاضی به صورت &quot;یک طرفه&quot; رمزنگاری شده است 
منظور از &quot;یک طرفه&quot; این مفهوم است که قابل برگشت نمیباشد 
برای مثال فرض کنید فرمول ما X+2 باشد ! و برای ورودی مانند 3 خروجی ما برابر 5 خواهد بود 
حال اگر شما 5 را در اختیار داشته باشید می توانید مقدار اولیه را به راحتی با فرمول معکوس Y-2 بدست آورید ! 
در روش های &quot;یک طرفه&quot; این امکان وجود ندارد ... 

کشف رشته اصلی از رشته هش آن (عملیات معکوس) به صورت کارا تقریبا غیر ممکن است. نکته دیگر اینکه هر داده یک رشته هش شده کاملا منحصر به فرد ایجاد می کند . البته ما داریم در مورد Hash به صورت حرفه ای بحث میکنیم ! در الگوریتم های ساده و آموزشی احتمال تکرار بسیار بالا میباشد ! اما همان طور که گفته شد ما در مورد الگوریتم های حرفه ای صحبت میکنیم ، که احتمال تکرار در آن وجود ندارد ( ما با معرفی الگوریتم حرفه ای MD5 هش را معرفی میکنیم ) 

در الگوریتم MD5 احتمال وجود تکرار و تصادف وجود ندارد و تمام مقادیر منحصر به فرد میباشد 
البته در مقاله ای احتمال یکی شدن رشته های هش دو رشته متفاوت در الگوریتم MD5 یک در 3.4028236692093846346337460743177e+38 عنوان شده بود ! که در واقع می توان گفت احتمال برابر 0 میباشد 
هنوز من جایی ندیدم که دو مقدار حاوی تکرار و تصادف و برای این الگوریتم عنوان کنند 

 این خواص ، هش کردن را به روشی کارا و ایده آل برای ذخیره سازی کلمات عبور در برنامه های شما تبدیل می کند. چرا؟ برای این که حتی اگر یک نفوذگر(Hacker) بتواند به سیستم و بانک اطلاعاتی شما نفوذ کند و بخشی از اطلاعات شما را به دست آورد (شامل کلمات عبور هش شده) نمی تواند کلمات عبور اولیه را از روی آن ها بازیابی کند. 


یکی از دو خصوصیت الگوریتم های HASHاینه که معکوس پذیر نیستند! دومی اینه که هرگز دو ورودی متفاوت به خروجی یکسان منجر نمی شوند. هر یک از این دو خصوصیت اگر نقض بشه می گیم الگوریتم شکسته!!! 


شناسایی اعضا با استفاده از Hash  : 
تا کنون نشان داده ایم که بازیابی کلمه عبور اصلی از روی رشته هش تقریبا غیر ممکن است ، خب چگونه برنامه های ما تشخیص دهند که کلمه عبور وارد شده توسط کاربر صحیح است ؟ به سادگی ! با تولید رشته هش کلمه عبور وارد شده توسط کاربر و مقایسه آن با رشته هش ذخیره شده در رکورد بانک اطلاعاتی مربوط به کاربر می توانید متوجه شوید که آیا دو رشته با هم برابرند یا نه 

Hash یک عمل خلاصه سازی (digest ) را روی جریان  ورودی انجام می دهد نه یک عمل رمز نگاری (encryption) . 
Encryption داده را از یک متن صریح (Clear text) به یک متن برمز در آورده تبدیل می کند (Cipher text). encryption ک عمل دو طرفه می باشد . که هرچه حجمClear text بیشتر باشد حجم Cipher text نیز بیشتر می شود. 


Hashe ها جریان داده ورودی را به یک خلاصه کوچک تبدیل می کنند. که این یک عمل یک طرفه(غیر قابل بازگشت) می باشد. و جریان داده ورودی آنها با هر حجمی که باشد خروجی یک مقدار ثابت میشود. 

این الگوریتم یک رشته با طول متفاوت را به عنوان ورودی می گیرد و یک &quot;خلاصه پیام MD5&quot; یا &quot;اثر انگشت&quot; با طول 128 بیت می سازد. 

برای مثال اگر شما این یک &quot;کلمه&quot; را به الگوریتم دهید ، و یا کل این خط را و یا کل این پاراگراف را ، در نهایت در هر 3 مورد خروجی 128 بیت میباشد 


برای مثال یکی از کاربرد های هش تشخیص درستی یک فایل Verifying file integrity میباشد 
برای مثال زمانی که یک فایل با حجم بالا را دانلود می نماییم می توانیم با به دست آوردن مقدار MD5 آن فایل توسط دستور md5sum و مقایسه آن با مقدار Md5 داده شده توسط سایت مورد نظر از درستی فایلمان اطمینان حاصل کنیم. 

از کاربرد های دیگر آن نشانه گذاری  اسناد به روش digitally (امضاهای digitally) میباشد 



Collision (تصادف) در  Hash 
البته معنی صحیح Collision &quot;تصادم&quot; و &quot;برخورد&quot; میباشد ! اما از اونجایی که سر کلاس &quot;تصادف&quot; گفته شده ما هم میگیم &quot;تصادف&quot; ... 

زمانی که مقدار  Hash  دو ورودی متفاوت یکسان باشند می گوییم Collision  رخ داده است. 
اما تا کنون هیچ موردی از Collision دیده نشده است  
( البته همان طور که در بالا گفته شد ما در مورد هش های حرفه ای بحث میکنیم ، نه الگوریتم های ساده آموزشی ... ) . 
این امر از این حقیقت ناشی می شود که تعداد مقادیر یک الگوریتم hash بسیار زیاد می باشند.برای مثال یک Hash 128 بیتی میتواند 3.4 x 1038 
مقدار ممکن داشته باشد.که معادل 340,282,366,920,938,463,463,374,607,431,768,211,45  6 میباشد. 


، محبوب ترین آنها که مورد استفاده برنامه نویسان هستند MD5 و SHA-1 می باشند. سیستم های قدیمی تر از( DES(Data Encryption Standard استفاده می کردند. این روش 56 بیتی دیگر یک روش قوی هش کردن محسوب نمی گردد. ، الگوریتم های قوی تری مانند SHA-256 و SHA-512 برای موارد خاص مانند امضاهای دیجیتالی توصیه می گردد ولی برای هش کردن کلمات عبوردر برنامه های امروزی SHA-1 هنوز سطح امنیت بسیار خوبی را فراهم می کند. 
SHA مخفف Secure hash algorithm میباشد 

البته در حال حاضر MD5 کاربرد زیادی پیدا کرده است ، و برای ذخیره رمز های عبور از آنها استفاده میشود ( برای سایت DpiGuide نیز از همین الگوریتم استفاده شده است ...! ) 

الگوریتم MD5 توسعه ای از الگوریتم MD4 می باشد با این تفاوت که MD5 کمی کندتر از MD4 عمل می کند اما در طراحی آن بسیار محافظه کارانه عمل شده است. 
MD5 به این دلیل طراحی شد که حس کردند MD4 به عنوان سرعت بالایی که داشت پذیرفته شده و از امنیت بالایی در شرایط بحرانی برخوردار نمی باشد. MD4 برای سرعت بالا طراحی شده ولی احتمال شکست آن در رمز کردنی موفق وجود دارد. MD5 کمی در سرعت کند شده با این تفاوت که بیشترین امنیت را داراست 

الگوریتم MD5 به تنهایی نیاز به یک بحث طولانی دارد ، که در صورتی که علاقه داشتید همینجا درخواست بدید تا در مورد اون هم بحث بشه 



سوالی که ممکن است برای شما به وجود بیاید این است که سایت هایی دیده اید که برای مثال مخصوص Crack کردن MD5 میباشد ! تا شما مقدار Hash شده را بدهید و مقدار اولیه را دریافت کنید ..! 
اما مگر گفته نشد که MD5 یک الگوریتم &quot;یک طرفه&quot; و غیر قابل برگشت میباشد ! پس این سایت ها به چه شکلی کار می کنند !؟ 
پاسخ : این سایت ها در واقع MD5 را Crack نمی کنند ، این سایت ها Database هایی از هش ها دارند 
برای مثال فرد سازنده وب سایت ( یک آدم بیکار ...! ) میاد از 0 تا 999 را هش می کند و داخل Database مقدار ورودی و خروجی را ذخیره میکند ! حال اگر هشی که شما به سایت میدهید در لیست اون باشه مقدار و از لیست خودش به شما میده  

مثال این می مونه که من نمی تونم ضرب کنم ! کل جدول ضرب و یک جا می نویسم ! و هر وقت شما سوال کنید ، اگر در جدول من بود به شما جواب و میدم ! 

نوشته شده توسط : احمد سمیعی

----------


## younes-98

شرمنده از اینکه دیر پاسخ دادم 
برای استفاده از این یونیت میتونید یک یونیت جدید ایجاد کنید بانام md5 و کد الگوریتم md5 را در آن کپی کنید.
در این یونیت چهار تابع اصلی و کاربردی وجود دارد که عبارتند از :
function MD5Message(const Message; Length: Cardinal): MD5Digest;
function MD5String(const S: string): MD5Digest;
function MD5File(const FileName: string): MD5Digest;
function MD5Print(const D: MD5Digest): string;

 

 یک مثال در محیط دلفی می تواند اینگونه باشد :

procedure TForm1.Button1Click(Sender: TObject);
var
  hold:MD5Digest;
begin
    hold:=MD5String('younes');
    Edit1.text:=MD5Print(hold);
end;

----------


## امید امرایی

با دلفی 2007 و 2009 که بنده تست کردم مشکل داشت. در هر دو

123456 = 11b4f806ba5e6b4ff53880fec21b0473

----------


## Batman

هر چی که وارد می کنم یه کد برمیگردونه.

یعنی تمامی کدهای برگردونده شده شبیه به همه

----------


## kianoosh59

متشکر........................................  ....................

----------


## SirMehdi

با سلام وتشکر
میشه راجب الگوریتم های دوطرفه هم اطلاعاتی بدین و یه نمونه معرفی کنین که تو دلفی جواب بده

----------


## vcldeveloper

> میشه راجب الگوریتم های دوطرفه هم اطلاعاتی بدین


تولید هش یک فرآیند یک طرفه هست؛ اگر شما دنبال چیزی می گردید که دوطرفه باشه، باید برید دنبال الگوریتم های رمزنگاری، نه تولید هش.

در عنوان این تاپیک هم به اشتباه گفته شده الگوریتم رمزنگاری MD5، باید گفته میشد الگوریتم تولید هش کد MD5.

----------


## Exception

ممنون از توضیحاتتون. فقط چند نکته:




> در الگوریتم MD5 احتمال وجود تکرار و تصادف وجود ندارد و تمام مقادیر منحصر به فرد میباشد 
> البته در مقاله ای احتمال یکی شدن رشته های هش دو رشته متفاوت در الگوریتم MD5 یک در 3.4028236692093846346337460743177e+38 عنوان شده بود ! که در واقع می توان گفت احتمال برابر 0 میباشد 
> هنوز من جایی ندیدم که دو مقدار حاوی تکرار و تصادف و برای این الگوریتم عنوان کنند


البته وجود داره چنین رشته هایی. اینجا رو ببینید: http://www.mathstat.dal.ca/~selinger/md5collision/
برای SHA1 هنوز پیدا نشده ولی انتظار میره بزودی بشه: http://valhenson.livejournal.com/42323.html




> سیستم های قدیمی تر از( DES(Data Encryption Standard استفاده می کردند. این روش 56 بیتی دیگر یک روش قوی هش کردن محسوب نمی گردد.


یک نکته کوچولو: DES ربطی به هش نداره!

----------

