PDA

View Full Version : آموزش: Hash کردن یک رشته و چگونگی مقایسه آن



raha1234567
دوشنبه 18 مرداد 1389, 00:29 صبح
Hash کردن به معنای تولید کدی منحصربه فرد و یکتا و غیرقابل بازگشت برای یک رشته است )بدین معنا که نمی توان فهمید کد تولید شده نتیجه چه رشته ای است) از این رو داده های مهم در جداول پایگاه داده یا هرجای دیگر باید Hash شوند تا در صورت نفوذ هکرها به پایگاه داده نتوانند به محتوای ان داده پی ببرند.
یکی از این داده های مهم که حتما باید Hash شود Password کاربران است .
برای Hash کردن داده در .Net الگوریتمی با نام MD5 برای این کار در نظر گرفته شده است .
الگوریتم MD5 به تولید بایتهایی از رشته داده شده می پردازد در این مقاله سعی خواهم کرد به چگونگی استفاده از این الگوریتم بپردازم.
فرض من این است که پایگاه داده ای در SQL Server با نام Test1 و جدولی به نام users که دارای دو فیلد username و userpassword است داریم برای ساخت جدول از دستور زیر استفاده کنید.





create table users(username varchar(50) primary key,userpassword varbinary(50))


همانگونه که می بینید فیلدی را که می خواهید کد Hash در آن ذخیره شود باید از نوع varbinary باشد.
همچنین فرمی با دو کنترل Textbox به نامهای txtusername و txtpassword به همراه یک کنترل button داریم در این فرم کاربر می تواند username و password خود را وارد کند و برنامه آنرا در جدول users ذخیره می کند البته پسورد کاربر hash می شود.
برای استفاده از الگوریتم های Hashing در ابتدا فضای نام System.Security.Cryptography را به برنامه اضافه کنید.
حال ما تابعی به نام Hash را می نویسیم ،کار این تابع گرفتن یک رشته و دادن یک مقدار Hash است. این مقدار آرایه ای از بایتها است.






VB.NET


Private Function hash(ByVal str As String) As Byte()


Dim crypt As New MD5CryptoServiceProvider()


Dim bytes() As Byte


bytes = System.Text.ASCIIEncoding.ASCII.GetBytes(str)


Return crypt.ComputeHash(bytes)


End Function








C#.NET


private Byte[] hash(string str)


{


MD5CryptoServiceProvider crypt=new MD5CryptoServiceProvider();


Byte[] bytes;


bytes=System.Text.ASCIIEncoding.ASCII.GetBytes(str );


return crypt.ComputeHash(bytes);


}



حال به مثال خود برمی گردیم .
در ابتدا متغیرهای زیر را به صورت سراسری تعریف کنید:





VB.NET


Private con As SqlConnection


Private com As SqlCommand








C#.NET


private SqlConnection con;


private SqlCommand com;




در رویداد Load فرم دستورات زیر را بنویسید






VB.NET


con = New SqlConnection


con.ConnectionString = "Data Source=.;Initial Catalog=Test1;Integrated Security=true"








C#.NET


con = new SqlConnection();


con.ConnectionString = "Data Source=.;Initial Catalog=Test1;Integrated Security=True";



در رویداد click کنترل Button دستورات زیر را بنویسید:






VB.NET


Dim hashvalue() As Byte


hashvalue = hash(txtpassword.Text)


con.Open()


com = New SqlCommand


com.Connection = con


com.CommandText = "insert into users values(@username,@userpassword)"


com.Parameters.AddWithValue("@username", txtusername.Text)


com.Parameters.AddWithValue("@userpassword", hashvalue)


com.ExecuteNonQuery()


con.Close()








C#.NET


byte[] hashvalue;


hashvalue = hash(txtpassword.Text);


con.Open();


com = new SqlCommand();


com.Connection = con;


com.CommandText = "insert into users values(@username,@userpassword)";


com.Parameters.AddWithValue("@username", txtusername.Text);


com.Parameters.AddWithValue("@userpassword", hashvalue);


com.ExecuteNonQuery();


con.Close();



حالا برنامه را اجرا کنید . و در فرم username و password هایی را وارد کنید.
اگر به SQL Server رفته و نتیجه دستور زیر را ببینید:


select *from users



می بینید که فیلد passowrd به صورت مجموعه ای از بایتها ذخیره شده است که این مجموعه کاملا unique است.
تا اینجا ما نحوه چگونگی تولید و ذخیره یک رشته hash مانند password را گفتیم از اینجا به بعد به تکمیل مقاله فرم Login در ابتدای برنامه و چگونگی مقایسه دو مقدار hash می پردازیم بهتر است در ابتدا این مقاله را در آدرس زیر بخوانید:
winlin.epage.ir/fa/module.content_Page.25-05.html (http://winlin.epage.ir/fa/module.content_Page.25-05.html)
حالا فرض کنید که در ابتدای پروژه یا برنامه خود فرم Login دارید که کار این فرم گرفتن username و پسورد کاربر و در صورت تائید ، وارد شدن به برنامه است
اما در این باره برنامه باید username و password کاربر را در فرم Login گرفته و password وارد شده را hash کرده و با password ذخیره شده مقایسه کند در صورتی که مساوی بود اجازه ورود بدهد.
اما نکته وجود دارد و آن اینکه برای مقایسه دو مجموعه بایت نمی توان ار علامت = استفاده کرد بلکه باید انها را بایت به بایت خواند و هربایت را به تنهایی مقایسه کرد .
حالا فرم Login خود را بسازید (پیش فرض ما همان فرم Login است که قبلا گفته ایم)
برای مقایسه دو مجموعه از بایت تابعی به نام comparetwobytes نوشتیم آنرا به برنامه خود اضافه کنید:






VB.NET


Private Function comparetwobytes(ByVal tmphash As Byte(), ByVal tmpnewhash As Byte()) As Boolean


Dim bEqual As Boolean = False


If tmpnewhash.Length = tmphash.Length Then


Dim i As Integer


Do While (i < tmpnewhash.Length) AndAlso (tmpnewhash(i) = tmphash(i))


i += 1


Loop


If i = tmpnewhash.Length Then


bEqual = True


End If


End If


Return bEqual


End Function








C#.NET


private Boolean comparetwobytes(Byte[] tmphash, Byte[] tmpnewhash)


{


bool bEqual = false;


if (tmpnewhash.Length == tmphash.Length)


{


int i = 0;


while ((i < tmpnewhash.Length) && (tmpnewhash[i] == tmphash[i]))


{


i += 1;


}


if (i == tmpnewhash.Length)


{


bEqual = true;


}


}


return bEqual;


}






توجه کنید تابع hash نیز باید به قسمت کدنویسی فرم Login نیز اضافه کنید
حالا در رویداد click کنترل Ok دستورات زیر را بنویسید





VB.NET


Dim hashvalue As Byte()


hashvalue = hash(PasswordTextBox.Text)


com = New SqlCommand


con.Open()


com.Connection = con


com.CommandText = "select * from users"


Dim reader As SqlDataReader


reader = com.ExecuteReader


Dim value As Boolean = False


While reader.Read


If UsernameTextBox.Text = reader.GetString(0) And comparetwobytes(reader.GetValue(1), hashvalue) = True Then


value = True


Exit While


End If


End While


If value Then


MessageBox.Show("نام کاربری و رمز ورودی صحیح است")


Else


MessageBox.Show("نام کاربری یا رمز ورودی اشتباه است")


End If


con.Close()







C#.NET


Byte[] hashvalue;


hashvalue = hash(PasswordTextBox.Text);


com=new SqlCommand();


con.Open();


com.Connection = con;


com.CommandText = "select * from users";


SqlDataReader reader = com.ExecuteReader();


Boolean value = false;


while (reader.Read())


{


if ((UsernameTextBox.Text == reader.GetString(0)) && (comparetwobytes((byte[])reader.GetValue(1), hashvalue)))


{


value = true;


break;


}


}


if (value)


MessageBox.Show("نام کاربری و رمز ورودی صحیح است");


else


MessageBox.Show("نام کاربری یا رمز ورودی اشتباه است");


con.Close();