md5算法實現

md5算法的具體步驟見RFC1321(http://www.ietf.org/rfc/rfc1321.txt)
這裏說一下具體實現時,應該注意的地方:
1.注意數據存儲格式
其實,在官方文檔中已經提到過這個,但是沒注意,現把它摘抄如下;
   In this document a "word" is a 32-bit quantity and a "byte" is an
   eight-bit quantity. A sequence of bits can be interpreted in a
   natural manner as a sequence of bytes, where each consecutive group
   of eight bits is interpreted as a byte with the high-order (most
   significant) bit of each byte listed first. Similarly, a sequence of
   bytes can be interpreted as a sequence of 32-bit words, where each
   consecutive group of four bytes is interpreted as a word with the
   low-order (least significant) byte given first.
翻譯過來,就是說在md5算法中一個字節內是按MSB存儲的,在一個字內是按LSB存儲的。
例如:00010111 11011001 11100011 10101100(msb)
按照文檔中的規定,每個字節是按MSB存儲的,則寫成十六進制如下:
0x17 d9 e3 ac
而在一個字,即32位裏,是按高字節序存儲的,所以最終的存儲值如下:
0xace3d917
另外,在填充長度時,兩個字也是按LSB存儲,每個字內是按上面所說的存儲,具體原文如下:
   A 64-bit representation of b (the length of the message before the
   padding bits were added) is appended to the result of the previous
   step. In the unlikely event that b is greater than 2^64, then only
   the low-order 64 bits of b are used. (These bits are appended as two
   32-bit words and appended low-order word first in accordance with the
   previous conventions.)
2.迭代時,數據存儲格式
雖然官方文檔規定了數據該怎樣存儲,但是在真正實現時,就連官方給的DEMO也沒有完全遵守。以至於自己實現md5算法時,算出來的結果總是不對。
md5實現時,分3步:
第一步,分割輸入數據,填充數據和長度。
在這一步,原生的數據和填充的數據(0x80 00 00 ...)是按高字節序存儲的。而填充的長度須按上面所說的規定存儲,即字節內MSB,字內LSB,雙字LSB。
第二步,初始化4字緩存
文檔中寫的是按LSB存儲,但是真正初始化是卻是按MSB存儲的。
第三步,4*16迭代
在迭代中,傳進來的X[i]是需要進行LSB轉換的,也就是把原來存儲的MSB數據轉換成LSB(第一步是原生數據加填充數據(MSB)+長度填充(LSB),現在需要把全部數據再次進行LSB轉換,長度填充相當於轉換了兩次)
第四步,輸出結果
輸出的結構,需要進行LSB轉換,就是把4字緩存中每個字進行LSB轉換,然後輸出的結果纔是正確的。

還有,就是要注意T表的計算,雖然文檔中給出了具體的計算公式(2^32*abs(sin(i))),但是還是建議直接通過一個數組預先給出,因爲這個計算如果處理的不好,會有精度誤差,導致最後結果錯誤,並且這個還與系統類型,編譯器版本,CPU類型和所用語言有關。我想這也是官方的DEMO爲了程序的可移植性和穩定性,採用的也是預先給出T表值,而沒有現用現算的原因吧。像這次實現MD5,有一個人用Java實現的,結果沒有碰到這個問題,而我用C語言實現,這個問題就出現了...

具體實現見github:http://github.com/wengpingbo/md5-demo


P.S.關於LSB,MSB,Big Endian,Little Endian

來源:http://www.eygle.com/digest/2007/01/whats_mean_endian.html

一、引子
  在各種計算機體系結構中,對於字節、字等的存儲機制有所不同,因而引發了
計算機通信領域中一個很重要的問題,即通信雙方交流的信息單元(比特、字節、
字、雙字等等)應該以什麼樣的順序進行傳送。如果不達成一致的規則,通信雙方
將無法進行正確的編/譯碼從而導致通信失敗。目前在各種體系的計算機中通常採
用的字節存儲機制主要有兩種:
big-edian和little-endian。本文簡要描述這兩種存儲機制的來歷、特點和區別。
  
  爲了敘述方便,下面先對本文中將要用到的兩個術語做簡單的定義。
  1、MSB
  MSB是Most Significant Bit/Byte的首字母縮寫,通常譯爲最重要的位或者最
重要的字節。它通常用來表明在一個bit序列(如一個byte是8個bit組成的一個序
列)或者一個byte序列(如word是兩個byte組成的一個序列)中對整個序列取值影
響最大的那個bit/byte。
  2、LSB
  LSB是Least Significant Bit/Byte的首字母縮寫,通常譯爲最不重要的位或
者最不重要的字節。它通常用來表明在一個bit序列(如一個byte是8個bit組成的
一個序列)或者一個byte序列(如word是兩個byte組成的一個序列)中對整個序
列取值影響最小的那個bit/byte。


二、endian的由來
  1、Definition
  endian: The ordering of bytes in a multi-byte number.
定義:在計算機系統體系結構中用來描述在多字節數中各個字節的存儲順序。


  2、Etymology
  The term comes from Swift's "Gulliver's Travels" via the famous paper
"On Holy Wars and a Plea for Peace" by Danny Cohen, USC/ISI IEN 137,
1980-04-01.
  The Lilliputians, being very small, had correspondingly small political
problems. The Big-Endian and Little-Endian parties debated over whether
soft-boiled eggs should be opened at the big end or the little end.[From:
Free On-Line Dictionary Of Computing or Jargon File]
  詞源:據Jargon File記載,endian這個詞來源於Jonathan
Swift在1726年寫的諷刺小說 "Gulliver's Travels"(《格利佛遊記》)。該小說
在描述Gulliver暢遊小人國時碰到了如下的一個場景。在小人國裏的小人因爲非常
小(身高6英寸)所以總是碰到一些意想不到的問題。有一次因爲對水煮蛋該從大的
一端(Big-End)剝開還是小的一端(Little-End)剝開的爭論而引發了一場戰爭,
並形成了兩支截然對立的隊伍:支持從Big-End剝開的人Swift就稱作Big-Endians
而支持從Little-End剝開的人就稱作Little-Endians……(後綴ian表明的就是支持
某種觀點的人:-)。Endian這個詞由此而來。
  
  1980年,Danny Cohen在其著名的論文"On Holy Wars and a Plea for Peace"
中爲了平息一場關於在消息中字節該以什麼樣的順序進行傳送的爭論而引用了該詞。
該文中,Cohen非常形象貼切地把支持從一個消息序列的MSB開始傳送的那夥人叫做
Big-Endians,支持從LSB開始傳送的相對應地叫做Little-Endians。此後Endian這
個詞便隨着這篇論文而被廣爲採用。


三、各種endian
  1、big-endian
  A computer architecture in which, within a given multi-byte numeric
representation, the most significant byte has the lowest address (the
word is stored "big-end-first").  
Most processors, including the IBM 370 family, the PDP-10, the
Motorola microprocessor families, and most of the various RISC designs
current in mid-1993, are big-endian. [From: Free On-Line Dictionary Of
Computing or Jargon File]
  big-endian:計算機體系結構中一種描述多字節存儲順序的術語,在這種機制
中最重要字節(MSB)存放在最低端的地址上。採用這種機制的處理器有IBM3700系
列、PDP-10、Mortolora微處理器系列和絕大多數的RISC處理器。


+----------+
| 0x34 |<-- 0x00000021
+----------+
| 0x12 |<-- 0x00000020
+----------+
圖1:雙字節數0x1234以big-endian的方式存在起始地址0x00000020中


  在Big-Endian中,對於bit序列中的序號編排方式如下(以雙字節數0x8B8A爲
例):
bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+----------------------------------------+
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+----------------------------------------+
^ 0x8B 0x8A ^
MSB LSB
圖2:Big-Endian的bit序列編碼方式


  注1:通常在TCP/IP協議棧所說的網絡序(Network Order)就是遵循Big-Endian
規則。在TCP/IP網絡通信中,通信雙方把消息按照如圖2的方式進行編碼,然後按
從MSB(Bit0)到LSB的順序在網絡上傳送。
  2、little-endian
   A computer architecture in which, within a given
16- or 32-bit word,bytes at lower addresses have lower significance (the
word is stored "little-end-first"). The PDP-11 and VAX families of
computers and Intel microprocessors and a lot of communications and
networking hardware are little-endian.
  The term is sometimes used to describe the ordering of units other
than bytes; most often, bits within a byte. [From: Free On-Line Dictionary
Of Computing or Jargon File]
  little-endian:計算機體系結構中一種描述多字節存儲順序的術語,在這種機
制中最不重要字節(LSB)存放在最低端的地址上。採用這種機制的處理器有PDP-11、
VAX、Intel系列微處理器和一些網絡通信設備。該術語除了描述多字節存儲順序外
還常常用來描述一個字節中各個比特的排放次序。


+----------+
| 0x12 |<-- 0x00000021
+----------+
| 0x34 |<-- 0x00000020
+----------+
  圖3:雙字節數0x1234以little-endian的方式存在起始地址0x00000020中


  在Little-Endian中,對於bit序列中的序號編排和Big-Endian剛好相反,其方
式如下(以雙字節數0x8B8A爲例):


bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+-----------------------------------------+
val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
+-----------------------------------------+
^ 0x8B 0x8A ^
MSB LSB
圖4:Little-Endian的bit序列編碼方式


  注2:通常我們說的主機序(Host Order)就是遵循Little-Endian規則。所以
當兩臺主機之間要通過TCP/IP協議進行通信的時候就需要調用相應的函數進行主機
序(Little-Endian)和網絡序(Big-Endian)的轉換。
注3:正因爲這兩種機制對於同一bit序列的序號編排方式恰恰相反,所以《現
代英漢詞典》中對MSB的翻譯爲“最高有效位”欠妥,故本文定義爲“最重要的bit
/byte”。


  3、middle-endian:
   Neither big-endian nor little-endian. Used of
perverse byte orders such as 3-4-1-2 or 2-1-4-3, occasionally found in
the packed decimal formats of some minicomputer manufacturers.[From:
Free On-Line Dictionary Of Computing or Jargon File]
  middle-endian:除了big-endian和little-endian之外的多字節存儲順序就是
middle-endian,比如以4個字節爲例:象以3-4-1-2或者2-1-4-3這樣的順序存儲的
就是middle-endian。這種存儲順序偶爾會在一些小型機體系中的十進制數的壓縮格
式中出現。
四、收尾
  要詳細解釋這兩種編碼順序已經超出本文所涉及的內容,如果你有興趣的話可
以參考上面提及的Danny Cohen的論文("On Holy Wars and a Plea for Peace"),
該論文詳細的描述了這兩種編碼順序的歷史、所基於的數學理論和各自擁護者爭論
的焦點等知識,絕對可以大飽你打破沙鍋問到底的內心需要。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章