MD5 的應用 來源:石頭閒語

MD5 是什麼

簡單地說, MD5 是一種單向字串雜湊演算,其可將你所給予的任何長度字串, 使用 MD5 雜湊演算法,得出一個長度為 256 位元 ( 32 個字元) 的計算結果, 以下以鍵值稱之。

舉例來說,你將 "ROCK" 這個字串,使用 MD5 演算的話,就會得到一個 256 位元的計算結果,以字元型式表示的話,則如同下行:

MD5 ("ROCK") = afeb717aa2a101f7f64840e0be38c171

MD5 的其他說明條列如下:

  1. 固定的字串內容必定會得出一個固定的鍵值,而非每次都算出不同的。
  2. 這是一個單向的雜湊演算,意味著,它雖可每次都將同樣的字串內容,算 出同樣的鍵值,但它無法從鍵值反推算出原本的字串內容。
  3. 不同字串內容所演算出來的鍵值,有可能相同,但根據統計,重覆的機率 小於百萬分之一,以重覆率來說,是相當好的演算法。
  4. 演算速度快,對硬體的要求很低。
  5. 它可以演算任意長度的字串內容,而且能得出固定長度的鍵值。
  6. 就算字串內容只相差一個字,它也能算出完全不同的鍵值。
  7. 鍵值長達 256 位元,而且可接受任何長度的字串,就密碼的安全性來講,比過去常用的 DES 編碼法還好。 DES 編碼法,只能接受 8 個字元長度的字串,產生的鍵值只有 56 位元。

就最後兩項,舉個例子來驗證,如下:

MD5 ("ROCK") = afeb717aa2a101f7f64840e0be38c171
MD5 ("RACK") = 1ece4bad0efe8b897c6e7f8bd101759f
MD5 ("ROCKY") = 6cd910740cbbbbd0f55238a93fba157d
MD5 ("Rock'S saying") = 7dca0df0dfa7f76b652e53daa4852640

最後要提的是, MD5 演算法,是由 RSA Data Security, Inc 公司所提出的。

如何取得 MD5 函數庫

本人使用的 MD5 函數庫,是取自 RSA Data Security 公司網站上,提供公開下載的版本,它只提供 C 語言原始碼,不過不必擔心編譯的問題,根據我的測試,只要是 32位元的 C 語言編譯器,都可以順利編譯,也沒有作業系統平台的問題。

Ps. 我試過 gcc (win32, linux 及 freebsd) 及 borland c++ 5.0 (win32)

可以點取下列連結下載:

此外,在某些作業系統中,例如 Freebsd ,由於內定採用 MD5 作為帳號密碼的編碼演算法,因此在系統中已內建 MD5 函數庫,不須另外安裝。

當你取得 RSA 的 MD5 原始碼後,可以直接 make ,如果一切順利,就會得到一個名叫 md5 的工具,這個工具,可以用來演算指定的檔案內容或特定字串的鍵值。

這個工具非常好用,我略加說明使用方式。

如果你是要演算檔案內容的鍵值,只要在指令 md5 後,直接加上檔案名稱做為參數即可,例如: md5 abc.zip 。你可以用它來檢查兩個同名檔案是否相同,另外有些 FTP 站台,也會提供每個檔案的 md5 值,供使用者在下載後,檢查下載檔的內容是否正確或遭修改。

若是要演算特定字串的鍵值,則在要加上 -s 選項,再緊跟著字串內容,字串內容可以用引號括起,例如: md5 -sROCK 。本文上節所舉的幾個例子,都是用這個工具算的。

如果想知道更多關於 MD5 演算法的內容,可閱讀該檔中所附的相關文件,例如其中的 rfc1321.txt 。

在程式中呼叫 MD5

在 RSA 提供的原始版本的 Makefile 中,只是產生一個名叫 md5 的工具,並不會產生一個 archive (static library) ,為了方便在 C/C++ 語言程式中,引用 MD5 函數,因此在我整理的原始碼中,我修改了 Makefile ,增加了兩個 label ,以產生 archive 並安裝到指定目錄。

用 make archive 建立一個檔名為 libmd5.a 的 archive 檔,並使用 make install 安裝。

Q:安裝到什麼地方?

A:Archive: $PREFIX/lib
Header files: $PREFIX/include/md5
PREFIX 的預設值為: /usr

Q:如何在 C/C++ 語言程式中引用 md5c.c 中的函數?

A:你可以閱讀原本的 mddriver.c ,如果你覺得太複雜, 也可以閱讀我所提供的 md5_example.c 。
基本上,你只要引入一個 header files: md5.h 即可, 在編譯程式時,則須告知 linker 將 libmd5.a 連結進來, 通常是為 cc 或 gcc 加上參數 -lmd5 。

這裡提供一組函數,它們將原本 mddriver.c 中的 MD5 演算函數,包裝在一起,以方便使用,觀看原始碼 [ md5ap.h & md5ap.c ]。

同時我也寫了一段程式碼,去測試 md5ap.c ,這個測試程式的內容不長,作用類似 RSA MD5 原始碼所提供的 md5 工具,當指令後加上一個參數時,將此參數視為普通字串,並算出其鍵值,而沒有加上參數時,則會從 stdin 設備中讀取字串內容,並將字串內容列出後,再顯示其鍵值。 觀看這個測試程式的原始碼 [ test_md5ap.c ]

應用一:儲存密碼

這是 MD5 最常被使用的用途。

首先,我們將新使用者所輸入的密碼字串內容 (術語稱為明碼,也就是編碼前的密碼) ,傳給 MD5 演算函數算出暗碼 (編碼後的密碼) ,之後我們將該暗碼,連同使用者 ID 及其他資料一併存入資料庫中。

例如使用者帳號為 rock ,密碼為 iloverock ,儲存在資料庫中的帳號資料格式及內容如下:

rock:85782f5e159d638811a7a8a7fa318754:Sh Yunchen:shirock@pchome.com.tw

第二個欄位儲存的,就是暗碼。

稍後,當使用者欲再簽入時,先以使用者 ID 為鍵值,自資料庫中讀取帳號資料,再將使用者輸入的明碼,同樣地傳給 MD5 演算函數得出一結果,將此結果與帳號資料中的暗碼比對是否完全相符。

暗碼的產生,可以使用前述 md5ap.c 中的 md5() 。

應用二:資料查核

這是 MD5 另一種常見的應用,一般用在網路檔案傳輸上,當使用者下傳回檔案後,可用 md5 (前述所說的那個 md5 工具) 去算出一個鍵值,將此鍵值與檔案來源站台,所提供的鍵值比對,如果相同,就可以證明使用者下傳的檔案,和原始檔案是相同的,沒有在傳輸過程中遭修改。

檔案在傳輸過程中遭修改的可能性有:

  1. 網路異常或雜訊干擾
  2. 病毒感染

使用這個方法,就可以證明檔案沒有問題,這遠比安裝所謂的網路防毒軟體方便,因為防毒軟體可能誤判,而且只能檢查檔案是否遭感染,卻無法檢查檔案內容是否正確無誤。

而在電子郵件愈來愈普及之後,又沿生了一種 MD5 的應用,使用它來阻擋垃圾信件。

大致做法是:

  1. 接收信件的同時,將信件的本文部份 (body) ,透過 MD5 去計算,例如使用 md5ap.c 中的 md5_filter() ,得到一個鍵值。
    Ps. 沒有必要包含信件的標頭部份 (header)
  2. 從信件鍵值資料庫中,搜尋此鍵值。找不到就跳到第三步,找到則跳到第四步。
  3. 未找到此鍵值,表示這信件的內容,是第一次接收到,將鍵值及計數值 (初值 1) 存入信件鍵值資料庫。再跳到第七步。
  4. 若找到了,表示這信件的內容,以前已經收過了。
  5. 接著檢查計數值是否超過上限 (這上限自定) ,如果超過了,我們就中止接收這封信,結束。
  6. 如果未超過上限,將計數值加一後,再存回信件鍵值資料庫。
  7. 將所接收到的信件內容,儲存起來,完成收信動作。

以虛擬碼表示如下:

open connect as fh

do {
  read line
  save mail header
} while end of mail header

do {
  read line
  md5 filter & save mail body
} while end of mail

final md5 filter and get a key

select key from mail-key database

if not found then
  store key and count value
else
  if the count not up then limit then
    inc count
    store key and count
  else
    deny this mail
    close connect
  end if
end if

store thie mail
close connect

事實上,我們也可以將上述方法,用在文件管理上,減少重複檔案。

小恐龍工作坊 提供