Message Digest Algorithm-MD5 爲計算機安全領域普遍使用的一種散列函數,用於確保信息傳輸完整一致,是計算機普遍使用的雜湊算法之一。利用 MD5 算法來進行文件校驗的方案被大量應用於軟件下載站、論壇數據庫、系統文件安全等方面。 算法
MD5 的典型應用是一致性驗證,對一段信息(Message)產生信息摘要(Message-Digest),以防止信息被篡改。例如機密資料的檢驗,下載文件的檢驗,明文密碼的加密等。 數據庫
本文介紹一款基於 Perl 實現的批量文件的 MD5 自動化校驗工具,支持不一樣文件夾下的批量文件的 MD5 值自動化校驗,並返回校驗結果。 安全
適用範圍 函數
此工具能夠應用於軟件正式發佈先後文件的完整一致性驗證和批量文件的 MD5 值讀取。 工具
實際案例分析 測試
IBM CSTL DSA(Dynamic System Analysis)項目組的每一個軟件發佈週期內,在軟件正式版本發佈到 IBM 官網以前,DSA 測試人員需進行軟件的完整一致性驗證。 網站
初始人工方法驗證步驟: ui
1)使用 MD5 讀寫工具逐條手動輸入原始文件路徑,並手動輸入讀取結果至本地文檔。 加密
2)使用該讀寫工具逐條手動輸入待比較文件路徑,並手動輸入讀取結果至本地文檔。 spa
3)人工對比原始文件和待比較文件 MD5 值,並手動記錄分析結果。
缺點:步驟多,效率低,且準確度難以保證,易受軟件測試人員影響。
分析人工方法步驟的缺點,採用 Perl Digest::MD5 模塊,將初始方法中需人工完成的部分自動化,減小操做步驟,下降人爲因素影響,從而提升效率並保證測試準確度。
採用自動化方法驗證步驟:
優勢:操做簡單,效率高,準確度高,自動化執行並分析結果,不受測試人員影響。
兩種方法對比結論:採用腳本語言或模塊完成當前工做中繁瑣的操做和數據分析,提升工做效率。
當前版本侷限性
1)Windows 環境需預安裝 Perl,Linux 環境可直接執行腳本文件。
2)此工具當前版本最大支持 4 組(5 次用戶輸入)不一樣文件夾下 MD5 值自動化校驗;
3)此工具當前版本不支持文件名檢測匹配,僅基於文件的惟一 MD5 值檢測匹配。
使用 Perl 模塊介紹
此工具採用了 Perl 的 Digest::MD5 模塊,該模塊能夠從 CPAN 網站上直接下載。詳細文檔可參考 Digest::MD5 詳細介紹(CPAN)。
此處介紹一種比較方便的模塊安裝方法:
ppm install Digest::MD5
代碼解讀
1, 工具執行第一步提示用戶輸入待讀取和比較的源文件夾所在的路徑並作如下斷定:
a,若輸入源文件夾路徑不存在或文件夾爲空,提示用戶輸入無效並繼續輸入;
b,若連續 3 次輸入無效,提示用戶輸入無效並自動退出;
c,若工具斷定輸入源文件夾有效,提示用戶輸入待比較文件夾路徑。
sub INPUT_FOLDER { print "Please input the original binary folder path!\n"; chomp( $folder_path = <STDIN> ); if ( -e $folder_path ) { #輸入文件夾路徑存在性斷定 my @dir_files = <$folder_path/*>; if (@dir_files) { #輸入文件夾非空性斷定 push @ori_folder, $folder_path; opendir DH, $folder_path || die "Can't open @ori_folder!"; @ori_file = readdir DH; splice( @ori_file, 0, 2 ); @ori_file = sort @ori_file; &BANNER; &INPUT_ANOTHER_FOLDER; }
2, 工具執行第二步提示用戶輸入待比較文件夾路徑(最大支持 4 次輸入)並作如下斷定:
a, 若輸入文件夾不存在,忽略這次輸入並返回斷定結果;
b, 若輸入文件夾爲空,忽略這次輸入並返回斷定結果;
c, 若輸入文件夾文件數目不等於源文件夾內文件數目,忽略此輸入並返回斷定結果;
d, 若輸入文件夾存在且文件數目等於源文件夾內數目文件,執行 MD5 讀取對比代碼段。
sub INPUT_ANOTHER_FOLDER { $h++; print "Press Q to quit the tool!\n"; print "Press C to end input and start to compare MD5 value!\n"; print "Please input another folder path compare with the original folder:\n"; while (<STDIN>) { chomp $_; if (/^q$/i) { exit; } elsif (/^c$/i) { if ( $h == 2 ) { &BANNER; print "There should be at least 2 folders to be compared!\n"; $h--; &INPUT_ANOTHER_FOLDER; } else { &BANNER; &FOLDER_ESTIMATE; } } else { push @com_folder, $_; if ( $h == 5 ) { #程序設定最大隻能同時比較 5 個路徑下面的文件 &BANNER; print "You have entered 5 folders to be compared!\n"; &FOLDER_ESTIMATE; } else { &BANNER; &INPUT_ANOTHER_FOLDER; } } } }
#待比較文件夾存在性斷定 foreach (@com_folder) { if ( -e $_ ) { push @folder_exist, $_; } else { push @folder_not_exist, $_; } } #待比較文件夾非空性斷定 foreach (@folder_exist) { my @dir_files = <$_/*>; if (@dir_files) { push @folder_not_empty, $_; } else { push @folder_empty, $_; } } #待比較文件夾內文件數目斷定 foreach (@folder_not_empty) { opendir DH, $_ || die "Can't open @folder_not_empty!"; @com_file = readdir DH; splice( @com_file, 0, 2 ); @com_file = sort @com_file; my $file_count = @com_file; if ( $file_count == @ori_file ) { push @folder_equal, $_; } else { push @folder_not_equal, $_; } }
3,工具執行第三步逐一遍歷讀取並存儲用戶輸入文件夾內全部文件的 MD5 值。
sub MD5_COM { print "Start to read and compare the input folder binary MD5 value, Please wait...\n\n"; #批量讀取初始文件夾內全部文件 MD5 值 foreach (@ori_file) { my $file = "$folder_path\\$_"; open( FILE, $file ) || die "Can't open '$file':$!"; binmode(FILE); my $md5 = Digest::MD5->new; map { $md5->add($_) } <FILE>; close(FILE); push @ori_array, "$file\n", $md5->hexdigest . "\n"; } #將 MD5 值及發生的錯誤信息打印輸出到日誌文件 open RESULT, ">MD5.log"; print RESULT "@folder_not_exist are not exist!\n" if @folder_not_exist; print RESULT "@folder_empty have no files!\n" if @folder_empty; print RESULT "@folder_not_equal have the wrong file numbers!\n" if @folder_not_equal; print RESULT "Original folder:\n", @ori_array, "$line\n";
4, 工具執行第四步終端顯示校驗統計結果並存儲至日誌文件。
sub Com_folder1 { #讀取第一個待比較文件夾內全部文件 MD5 值 opendir DH, $folder_equal[0] || die "Can't open @folder_equal!"; @com_file = readdir DH; splice( @com_file, 0, 2 ); @com_file = sort @com_file; foreach (@com_file) { my $file = "$folder_equal[0]\\$_"; open( FILE, $file ) || die "Can't open '$file':$!"; binmode(FILE); my $md5 = Digest::MD5->new; map { $md5->add($_) } <FILE>; close(FILE); push @com_array1, "$file\n", $md5->hexdigest . "\n"; } #屏幕輸出 MD5 值比對結果並保存到日誌文件 my $pass_count = 0; my $fail_count = 0; for ( my $n = 0 ; $n < $#ori_array ; $n += 2 ) { if ( $ori_array[ $n + 1 ] eq $com_array1[ $n + 1 ] ) { $pass_count++; } else { $fail_count++; } } my $total = $pass_count + $fail_count; print "\nCompare the MD5 value of:\n\n"; print "$folder_equal[0]\t$folder_path\t"; print "PASS $pass_count\tFAIL $fail_count\tTotal $total\n\n"; }