MD5 是一個固定產生長度為 128-bit 摘要(Digest)的 密碼雜湊函数(CHF)。
MD5 光看它的名字,大概知道它是第5代利用 Merkle–Damgård 架構的 CHF 演算法。MD5 在 1991 年提出,原來的目的就是取代 MD4 成為新一代的 CHF。但是後來已被證明被破解,故已不再推薦使用。
請注意,破解的意思不是指我們可以從 Digest 回推原始訊息,而且可以找到碰撞。MD5 在數秒內可以被一般的家用電腦找出碰撞,可以說是被破解了。有興趣的人可自行搜尋關鍵字「王小云」。
不過呢,如果只是要檢查資料完整性,MD5 速度快又有效,所以依然常被用來檢查 2 筆資料是否一致。也可延伸做用 MD5 來檢查系統裡是否有重複照片或檔案。
所以我最被在雀魂遊戲中(請參考「前言」),看到的麻將 MD5 碼,就是表示:該局遊戲的牌一開始就已洗好了,中途不會偷換牌改變摸到的牌。有意思的是,雀魂並沒有公布 MD5 是如何生成的(或我沒查到),也許跟牌一點關係都沒有,只是當下的時間也有可能,哈哈。
以下利用 Ruby 的 OpenSSL 來做簡單的例子:
require 'openssl'
# abcdefg 跟 abcdefi 只差一個字母,但 digest 長得完全不一樣
OpenSSL::Digest::MD5.new('abcdefg')
=> #<OpenSSL::Digest::MD5: 7ac66c0f148de9519b8bd264312c4d64>
OpenSSL::Digest::MD5.new('abcdefi')
=> #<OpenSSL::Digest::MD5: e06a414fbde4670101eccbb61865b6d9>
md5 = OpenSSL::Digest::MD5.new
# update 跟 << 是一樣的,都是接上字串,比較是不是跟一開始的 abcdefg 產生的 digest 一樣呢?
md5.update 'abcdef'
=> #<OpenSSL::Digest::MD5: e80b5017098950fc58aad83c8c14978e>
md5 << 'g'
=> #<OpenSSL::Digest::MD5: 7ac66c0f148de9519b8bd264312c4d64>
# 通常都可以選擇要用 16進位(hex)或是 base64 表示
md5.hexdigest
# "7ac66c0f148de9519b8bd264312c4d64"
md5.base64digest
# "esZsDxSN6VGbi9JkMSxNZA=="