مقایسه فایل Hash شده در MD5 با SHA1

در این مقاله ما سعی کرده ایم که به یک سوال مشترک که در بین برنامه نویسان را در رابطه با Hashing وجود دارد پاسخ دهیم: چه مقدار زمان لازم است تا یک فایل موجود در دایرکتوری hash شود؟ اگر در داخل فولدر مورد نظر ما sub folderهایی وجود داشت، چطور این زمان محاسبه خواهد شد؟ آیا برای فایل هایی که از حجم کمی ( در حد MBs) برخوردار هستند سرعت کافی برای hash کردن آنها وجود دارد؟

مقایسه فایل Hash  شده در MD5  با SHA1

بطور کلی، هر گاه نیاز داشته باشیم که تغییراتی که در file system رخ میدهد را شناسایی کنیم از file system watcher که در .NET وجود دارد استفاده میکنیم. اما استفاده از این کلاس، اثرات جانبی بر روی برنامه میگذارد و هیچ مزیت بخصوصی نیز ندارد دلیل دیگری که برای استفاده نکردن از کلاس file system watcher وجود دارد این است که این کلاس محتویات داخل فایل ها را ایمن نگه نمیدارد و ممکن است اطلاعات داخل فایل از بین برود. بنابراین ما به این نتیجه رسیدیم که Hashing روش بهتری  برای انجام کارها می باشد.

در این مقاله ما سعی کرده ایم که به یک سوال مشترک که در بین برنامه نویسان را در رابطه با Hashing وجود دارد پاسخ دهیم: چه مقدار زمان لازم است تا یک فایل موجود در دایرکتوری hash شود؟ اگر در داخل فولدر  مورد نظر ما sub folderهایی وجود داشت، چطور این زمان محاسبه خواهد شد؟ آیا برای فایل هایی که از حجم کمی ( در حد MBs) برخوردار هستند سرعت کافی برای hash کردن آنها وجود  دارد؟ ما،  برای پاسخ به این سوالات برنامه ای نوشتیم و آن را بر روی 45 فایل که حجمی کمی از کل دایرکتوری برنامه را داشت ، اجرا کردیم. سرعت اجرای برنامه مناسب و قابل قبول بود و تقریبا 50-60 میلی ثانیه برای محاسبه hash کردن زمان برد و تقریبا با صرف همین زمان، داده ها را hash کرد.

استفاده از کد

ما با استفاده از کدهای زیر، تلاش کرد ه ایم که زمان hash کردن MD5 و SHA1  را محاسبه کنیم. در هر دو الگوریتم، زمان یکسانی برای hash  کردن محتویات فایل ها صرف شده است. توجه داشته باشید که ما در حال hash کردن محتویات اصلی فایل ها هستیم. از این پس، هر تغییری در محتویات فایل (حتی یک space یا تغییر  یک کاراکتر) به وجود آید، hash کل فایل تغییر خواهد کرد. با اینکه توجه به attributeهای فایل (مانند تاریخ آخرین تغییرات) مهم است اما در نتیجه عملیات hash تاثیری نخواهد داشت.

1.	public class DeploymentFile  
2.	{  
3.	    public string FilePath  
4.	    {  
5.	        get;  
6.	        set;  
7.	    }  
8.	    public bool IsFilePathValid   
9.	    {  
10.	        get;  
11.	        set;  
12.	    }  
13.	    public string HashedValue   
14.	    {  
15.	        get;  
16.	        set;  
17.	    }  
18.	    public bool IsFileModified   
19.	    {  
20.	        get;  
21.	        set;  
22.	    }  
23.	  
24.	    public DeploymentFile(string filePath)  
25.	    {  
26.	        FilePath = filePath;  
27.	        IsFilePathValid = true;  
28.	        IsFileModified = false;  
29.	        if (File.Exists(filePath))  
30.	            HashedValue = ComputeHashSHA(filePath);  
31.	        else  
32.	            IsFilePathValid = false;  
33.	    }  
34.	  
35.	    public bool IsExist(string FilePath)   
36.	    {  
37.	        return File.Exists(FilePath);  
38.	    }  
39.	  
40.	    //public string ComputeHashMD5(string filename)  
41.	    //{  
42.	    // using (var md5 = MD5.Create())  
43.	    // {  
44.	    // using (var stream = File.OpenRead(filename))  
45.	    // {  
46.	    // return (Encoding.Default.GetString(md5.ComputeHash(stream)));  
47.	    // }  
48.	    // }  
49.	    //}  
50.	  
51.	    public string ComputeHashSHA(string filename)   
52.	    {  
53.	        using(var sha = SHA1.Create())  
54.	        {  
55.	            using(var stream = File.OpenRead(filename))  
56.	            {  
57.	                return (Encoding.Default.GetString(sha.ComputeHash(stream)));  
58.	            }  
59.	        }  
60.	    }  
61.	}  

کدهایی که در زیر نمایش داده شده است کدهای مربوط به فرمی است که تمام کنترل ها در آن قرار دارند. شما باید به این نکته توجه داشته باشید که ما در کد زیر از یک زمان سنج برای محاسبه زمان hash کردن استفاده کرده ایم.

نکته مهم:  توجه داشته باشید که اگر یک message box در برنامه ظاهر شود. زمان سنج مدت زمانی که کاربر روی آن کلیک میکند و آن را می بندد را نیز محاسبه میکند. بنابراین برخی افراد ترجیح می دهند که message box را غیر فعال کنند تا مدت زمان دقیق تری محاسبه گردد.

Hide Shrink Copy Code

1.	public partialclass FileValidator: Form  
2.	{  
3.	    public FileValidator()   
4.	    {  
5.	        InitializeComponent();  
6.	    }  
7.	    List < DeploymentFile > DeployList;  
8.	    List < DeploymentFile > ValidationList;  
9.	    String filePath;  
10.	 
11.	 
12.	    #region ComputeHash  
13.	    private void ComputeHash_Click(object sender, EventArgs e)  
14.	    {  
15.	        DeployList = new List < DeploymentFile > ();  
16.	        foreach(var item in GetListOfFilesInDeployFolder())  
17.	        DeployList.Add(new DeploymentFile(item));  
18.	        FilesGrid.DataSource = DeployList;  
19.	    }  
20.	 
21.	 
22.	    #endregion ComputeHash  
23.	 
24.	    #region ValidateFileHash  
25.	    private void ValidateHash_Click(object sender, EventArgs e)  
26.	    {  
27.	  
28.	        Stopwatch stopwatch = new Stopwatch();  
29.	        // Begin timing.  
30.	        stopwatch.Start();  
31.	        bool Abort = false;  
32.	        List < string > filesList = GetListOfFilesInDeployFolder();  
33.	        ValidationList = new List < DeploymentFile > ();  
34.	        foreach(var item in DeployList)  
35.	        ValidationList.Add(new DeploymentFile(item.FilePath));  
36.	  
37.	        //If new files are not added or deleted  
38.	        for (int i = 0; i < ValidationList.Count; i++)   
39.	        {  
40.	            if (ValidationList.Count != filesList.Count) Abort = true;  
41.	            if (ValidationList[i].FilePath != filesList[i]) Abort = true;  
42.	        }  
43.	        //if all files are valid and exists in directory  
44.	        if (!Abort && ValidationList.Exists((x) => x.IsFilePathValid == false))  
45.	            Abort = true;  
46.	  
47.	        if (Abort)   
48.	        {  
49.	            //disable message box to calculate accrate execution time through stop watch.  
50.	            MessageBox.Show("Files/Folder structure changed or modified since last check");  
51.	        }  
52.	  
53.	        if (!Abort)  
54.	        {  
55.	            for (int i = 0; i < ValidationList.Count; i++)  
56.	                if (ValidationList[i].HashedValue != DeployList[i].HashedValue)   
57.	                {  
58.	                    ValidationList[i].IsFileModified = true;  
59.	                    Abort = true;  
60.	                }  
61.	        }  
62.	  
63.	        FilesGrid.DataSource = ValidationList;  
64.	  
65.	        stopwatch.Stop();  
66.	        label1.Text = "Time taken in Validation : " + stopwatch.Elapsed;  
67.	  
68.	    }  
69.	 
70.	    #endregion  
71.	  
72.	  
73.	    private List < string > GetListOfFilesInDeployFolder()  
74.	    {  
75.	        filePath = textBox1.Text;  
76.	        return Directory.GetFiles(@filePath, "*", SearchOption.AllDirectories).ToList();  
77.	    }  
78.	  
79.	  
80.	    private void FileValidator_Load(object sender, EventArgs e)  
81.	    {  
82.	        FilesGrid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;  
83.	    }  
84.	  
85.	  
86.	  
87.	}  

تصویر بالا زمانی که برای محاسبه و  صحت hash صرف شده است را نشان میدهد . اگر در مدت زمانی که عملیات محاسبه hash در حال انجام است ، تغییری ایجاد شود، این تغییرات در ستونی با نام IsFilemodified نمایش داده خواهد شد. همچنین ما ساختار فایل ها را ذخیره می کنیم و  سپس با ساختار فایل قبلی مقایسه می کنیم، هر تغییری در مسیر ذخیره فایل ها در ستون IsFilePathValid نمایش داده میشود.

نکات قابل توجه:

نکته دیگری که ما متوجه آن شدیم این است که هر دو الگوریتم  SHA1 و MD5 برای فایل های کم حجم، زمان یکسانی برای hash کردن، نیاز دارند. اگر تعداد فایل ها و حجم آنها افزایش یابد،  الگوریتم MD5 کارایی بیشتر نسبت به الگوریتم SHA1 دارد. با اینکه برنامه نویسان به الگوریتم SHA1 اعتماد بیشتری دارند اما از نظر ما الگوریتم MD5 بهتر است چرا که با استفاده از آن دیگر درگیر مشکلات امنیتی نخواهیم بود، ما بیشتر نگران یکپارچگی محتویات و اطلاعات درون فایلها هستیم. نمودار زیر چند نوع از الگوریتم های مربوط به hash کردن را نمایش میدهد.

آموزش سی شارپ

دانلود نسخه ی PDF این مطلب