概要

MD5は任意のデータ長から128bitのほぼ一意の128bitのハッシュ値を出力する関数である。電子署名やパスワードの保存、電子メールのSMTPサーバーのCRAM-MD5認証、ファイルの改ざんチェック等に用いられている。
本プログラムは、main関数の変数passで定義されている文字列からMD5ハッシュの値を計算し16進数で出力します。
ソースファイルの#define INFO_DISPをコメントアウトしない場合は、計算途中の詳細結果を出力します。
コマンドラインで動作します。

テスト環境

コンパイラ

Visual C++ 2013 Express 32bit/64bit
マルチバイト
プラットフォームツールセット Visual Studio 2013 - Windows XP (v120_xp)

実行環境

Windows 7 Enterprise Service Pack 1 64bit(Sandy Bridge-E)
Windows XP Professional Service Pack 3 32bit(Virtual Box上の仮想マシーン)

MD5のアルゴリズム

16byte単位に入力データーを加工(バディング)

MD5を計算する場合は、ブロック 512bit(16byte)を対象としているので、まず入力データ(メッセージ)を512bit単位(バディング)にする。
データーの最後に0x80を付加し、その後、必要なデーター帳になるまで0x00を繰り返し付加し最後に全体のデータ長64bitを付加して512bitにする。64byte以上のデータを対象とする場合は、64byteずつ処理を行い最後に0x80の付加やデーター長の付加を行う。以下にバディングの例を示す。
image1.svg

入力データーが64byteの場合

1ブロック目は入力データ64byteをそのまま使用する。ブロック含まれるデーターが56byte以上なので2ブロック目が必要となる。
2ブロック目は0バイト目に0x80、1バイト目から55バイト目までデータ長の調整のために0x00、56バイト目からメッセージ長をビット長で挿入する。

入力データーが62byteの場合

1ブロック目は入力データ62byteをそのまま使用する。ブロック含まれるデーターが56byte以上なので2ブロック目が必要となる。
62バイト目に0x80、それ以降は63バイト目までデータ長調整のために0x00を挿入する。
2ブロック目は0バイト目から55バイト目までデータ長の調整のために0x00、56バイト目からメッセージ長をビット長で挿入する。

入力データーが55byte以下の場合

1ブロック目は入力データ55byteをそのまま使用する。ブロック含まれるデーターが56byte未満なので2ブロック目は不要である。
データーの次に0x80、それ以降は55バイト目までデータ長調整のために0x00を挿入する。
56バイト目からメッセージ長をビット長で挿入する。

ハッシュ計算

64byteのデータを4byte(32bit)を1要素とする配列xに割り振ります。
image2.svg
4byteの変数a,b,c,dを以下の値で初期化します。
a = 0x67452301;
b = 0xefcdab89;
c = 0x98badcfe;
d = 0x10325476;
T[n]=429467296*abs(sin(n+1))によりn=0~63についてExcelやプログラムを使ってあらかじめ計算しておきテーブル化しておきます。

関数の定義

以下の関数を定義します。

F(x,y,z)=(x and y) or ( ( not x ) and z )
G(x,y,z)=(x and y) or (y and ( not z) )
H(x,y,z)=x xor y xor z
FF(a,b,c,d,x,s,ac){
        a += F(b,c,d)+x+ac;
        a = rotate(a,s);
        a += b;
        return a;
}
GG(a,b,c,d,x,s,ac){
        a += G(b,c,d)+x+ac;
        a = rotate(a,s);
        a += b;
        return a;
}
HH(a,b,c,d,x,s,ac){
        a += H(b,c,d)+x+ac;
        a = rotate(a,s);
        a += b;
        return a;
}
rotate関数はaをsビット分左へローテートします。

計算

a,b,c,dの変数の値をta,tb,tc,tdにコピーします。
以下の64個の関数の計算を行います。

ta = a;
tb = b;
tc = c;
td = d;

a=FF(a,b,c,d , x[0] , 7 , T[0]);        d=FF(d,a,b,c , x[1] , 12 , T[1]);       c=FF(c,d,a,b , x[2] , 17 , T[2]);       b=FF(b,c,d,a , x[3] , 22 , T[3]);
a=FF(a,b,c,d , x[4] , 7 , T[4]);        d=FF(d,a,b,c , x[5] , 12 , T[5]);       c=FF(c,d,a,b , x[6] , 17 , T[6]);       b=FF(b,c,d,a , x[7] , 22 , T[7]);
a=FF(a,b,c,d , x[8] , 7 , T[8]);        d=FF(d,a,b,c , x[9] , 12 , T[9]);       c=FF(c,d,a,b , x[10] , 17 , T[10]);     b=FF(b,c,d,a , x[11] , 22 , T[11]);
a=FF(a,b,c,d , x[12] , 7 , T[12]);      d=FF(d,a,b,c , x[13] , 12 , T[13]);     c=FF(c,d,a,b , x[14] , 17 , T[14]);     b=FF(b,c,d,a , x[15] , 22 , T[15]);
a=FF(a,b,c,d , x[1] , 5 , T[16]);       d=FF(d,a,b,c , x[6] , 9 , T[17]);       c=FF(c,d,a,b , x[11] , 14 , T[18]);     b=FF(b,c,d,a , x[20] , 20 , T[19]);
a=FF(a,b,c,d , x[5] , 5 , T[20]);       d=FF(d,a,b,c , x[10] , 9 , T[21]);      c=FF(c,d,a,b , x[15] , 14 , T[22]);     b=FF(b,c,d,a , x[4] , 20 , T[23]);
a=FF(a,b,c,d , x[9] , 5 , T[24]);       d=FF(d,a,b,c , x[14] , 9 , T[25]);      c=FF(c,d,a,b , x[3] , 14 , T[26]);      b=FF(b,c,d,a , x[8] , 20 , T[27]);
a=FF(a,b,c,d , x[13] , 5 , T[28]);      d=FF(d,a,b,c , x[2] , 9 , T[29]);       c=FF(c,d,a,b , x[7] , 14 , T[30]);      b=FF(b,c,d,a , x[12] , 20 , T[31]);
a=FF(a,b,c,d , x[5] , 4 , T[32]);       d=FF(d,a,b,c , x[8] , 11 , T[33]);      c=FF(c,d,a,b , x[11] , 16 , T[34]);     b=FF(b,c,d,a , x[14] , 23 , T[35]);
a=FF(a,b,c,d , x[1] , 4 , T[36]);       d=FF(d,a,b,c , x[4] , 11 , T[37]);      c=FF(c,d,a,b , x[7] , 16 , T[38]);      b=FF(b,c,d,a , x[10] , 23 , T[39]);
a=FF(a,b,c,d , x[13] , 4 , T[40]);      d=FF(d,a,b,c , x[0] , 11 , T[41]);      c=FF(c,d,a,b , x[3] , 16 , T[42]);      b=FF(b,c,d,a , x[6] , 23 , T[43]);
a=FF(a,b,c,d , x[9] , 4 , T[44]);       d=FF(d,a,b,c , x[12] , 11 , T[45]);     c=FF(c,d,a,b , x[15] , 16 , T[46]);     b=FF(b,c,d,a , x[2] , 23 , T[47]);
a=FF(a,b,c,d , x[0] , 6 , T[48]);       d=FF(d,a,b,c , x[7] , 10 , T[49]);      c=FF(c,d,a,b , x[14] , 15 , T[50]);     b=FF(b,c,d,a , x[5] , 21 , T[51]);
a=FF(a,b,c,d , x[12] , 6 , T[52]);      d=FF(d,a,b,c , x[3] , 10 , T[53]);      c=FF(c,d,a,b , x[10] , 15 , T[54]);     b=FF(b,c,d,a , x[1] , 21 , T[55]);
a=FF(a,b,c,d , x[8] , 6 , T[56]);       d=FF(d,a,b,c , x[15] , 10 , T[57]);     c=FF(c,d,a,b , x[6] , 15 , T[58]);      b=FF(b,c,d,a , x[13] , 21 , T[59]);
a=FF(a,b,c,d , x[4] , 6 , T[60]);       d=FF(d,a,b,c , x[11] , 10 , T[61]);     c=FF(c,d,a,b , x[2] , 15 , T[62]);      b=FF(b,c,d,a , x[9] , 21 , T[63]);


a += ta;
b += tb;
c += tc;
d += td;
a,b,c,dがハッシュ値になります。複数のブロックを処理する場合は、ブロックを移動して2.2計算を行います。

計算例

以下に入力文字列abcに対する計算例を記載しております。記載例は本プログラムでマクロ#define でINFO_DISPの定義を行ってコンパイルした場合の実行結果です。
上項では、FF,GG,HH,II関数の引数及び戻り値の代入先であるa,b,c,dが順番に変化しておりますが、以下の例ではa,b,c,dの値そのものを移動させることにより関数の引数等を順番に変化させております。 x[0]~x[15]がブロックの値、それ以降がFF,GG,HH,II関数の引数及びその計算結果を示しております。
最終行のmd5以降がハッシュの計算結果です。

----------------------------------------
x[ 0]=0x80636261; // 0x61 0x62 0x63 0x80
x[ 1]=0x00000000; // 0x00 0x00 0x00 0x00
x[ 2]=0x00000000; // 0x00 0x00 0x00 0x00
x[ 3]=0x00000000; // 0x00 0x00 0x00 0x00
x[ 4]=0x00000000; // 0x00 0x00 0x00 0x00
x[ 5]=0x00000000; // 0x00 0x00 0x00 0x00
x[ 6]=0x00000000; // 0x00 0x00 0x00 0x00
x[ 7]=0x00000000; // 0x00 0x00 0x00 0x00
x[ 8]=0x00000000; // 0x00 0x00 0x00 0x00
x[ 9]=0x00000000; // 0x00 0x00 0x00 0x00
x[10]=0x00000000; // 0x00 0x00 0x00 0x00
x[11]=0x00000000; // 0x00 0x00 0x00 0x00
x[12]=0x00000000; // 0x00 0x00 0x00 0x00
x[13]=0x00000000; // 0x00 0x00 0x00 0x00
x[14]=0x00000018; // 0x18 0x00 0x00 0x00
x[15]=0x00000000; // 0x00 0x00 0x00 0x00
n ,func, A        ,B         ,C         ,D         ,x[n]            ,S ,T[n]      ,ans
 0,FF  ,0x67452301,0xefcdab89,0x98badcfe,0x10325476,x[ 0]=0x80636261, 7,0xd76aa478,0xd6d117b4
 1,FF  ,0x10325476,0xd6d117b4,0xefcdab89,0x98badcfe,x[ 1]=0x00000000,12,0xe8c7b756,0x344a8432
 2,FF  ,0x98badcfe,0x344a8432,0xd6d117b4,0xefcdab89,x[ 2]=0x00000000,17,0x242070db,0x2f6fbd72
 3,FF  ,0xefcdab89,0x2f6fbd72,0x344a8432,0xd6d117b4,x[ 3]=0x00000000,22,0xc1bdceee,0x7ad956f2
 4,FF  ,0xd6d117b4,0x7ad956f2,0x2f6fbd72,0x344a8432,x[ 4]=0x00000000, 7,0xf57c0faf,0xc73741ef
 5,FF  ,0x344a8432,0xc73741ef,0x7ad956f2,0x2f6fbd72,x[ 5]=0x00000000,12,0x4787c62a,0x8bac3051
 6,FF  ,0x2f6fbd72,0x8bac3051,0xc73741ef,0x7ad956f2,x[ 6]=0x00000000,17,0xa8304613,0x207dc67b
 7,FF  ,0x7ad956f2,0x207dc67b,0x8bac3051,0xc73741ef,x[ 7]=0x00000000,22,0xfd469501,0x928d99f6
 8,FF  ,0xc73741ef,0x928d99f6,0x207dc67b,0x8bac3051,x[ 8]=0x00000000, 7,0x698098d8,0x854b3712
 9,FF  ,0x8bac3051,0x854b3712,0x928d99f6,0x207dc67b,x[ 9]=0x00000000,12,0x8b44f7af,0x74e2f284
10,FF  ,0x207dc67b,0x74e2f284,0x854b3712,0x928d99f6,x[10]=0x00000000,17,0xffff5bb1,0x3020401c
11,FF  ,0x928d99f6,0x3020401c,0x74e2f284,0x854b3712,x[11]=0x00000000,22,0x895cd7be,0x5ed49596
12,FF  ,0x854b3712,0x5ed49596,0x3020401c,0x74e2f284,x[12]=0x00000000, 7,0x6b901122,0xdda9b9a6
13,FF  ,0x74e2f284,0xdda9b9a6,0x5ed49596,0x3020401c,x[13]=0x00000000,12,0xfd987193,0xa1051895
14,FF  ,0x3020401c,0xa1051895,0xdda9b9a6,0x5ed49596,x[14]=0x00000018,17,0xa679438e,0xe396856b
15,FF  ,0x5ed49596,0xe396856b,0xa1051895,0xdda9b9a6,x[15]=0x00000000,22,0x49b40821,0x72aff2e0
16,GG  ,0xdda9b9a6,0x72aff2e0,0xe396856b,0xa1051895,x[ 1]=0x00000000, 5,0xf61e2562,0x3e9e9126
17,GG  ,0xa1051895,0x3e9e9126,0x72aff2e0,0xe396856b,x[ 6]=0x00000000, 9,0xc040b340,0x4a1d804e
18,GG  ,0xe396856b,0x4a1d804e,0x3e9e9126,0x72aff2e0,x[11]=0x00000000,14,0x265e5a51,0xe25e1652
19,GG  ,0x72aff2e0,0xe25e1652,0x4a1d804e,0x3e9e9126,x[ 0]=0x80636261,20,0xe9b6c7aa,0xb5b204e4
20,GG  ,0x3e9e9126,0xb5b204e4,0xe25e1652,0x4a1d804e,x[ 5]=0x00000000, 5,0xd62f105d,0x59a8ffda
21,GG  ,0x4a1d804e,0x59a8ffda,0xb5b204e4,0xe25e1652,x[10]=0x00000000, 9,0x02441453,0x6d002f1e
22,GG  ,0xe25e1652,0x6d002f1e,0x59a8ffda,0xb5b204e4,x[15]=0x00000000,14,0xd8a1e681,0xabfc7920
23,GG  ,0xb5b204e4,0xabfc7920,0x6d002f1e,0x59a8ffda,x[ 4]=0x00000000,20,0xe7d3fbc8,0x47092c07
24,GG  ,0x59a8ffda,0x47092c07,0xabfc7920,0x6d002f1e,x[ 9]=0x00000000, 5,0x21e1cde6,0xb7f268cf
25,GG  ,0x6d002f1e,0xb7f268cf,0x47092c07,0xabfc7920,x[14]=0x00000018, 9,0xc33707d6,0x09388eff
26,GG  ,0xabfc7920,0x09388eff,0xb7f268cf,0x47092c07,x[ 3]=0x00000000,14,0xf4d50d87,0xfe1623b1
27,GG  ,0x47092c07,0xfe1623b1,0x09388eff,0xb7f268cf,x[ 8]=0x00000000,20,0x455a14ed,0x786acb8f
28,GG  ,0xb7f268cf,0x786acb8f,0xfe1623b1,0x09388eff,x[13]=0x00000000, 5,0xa9e3e905,0x790a77fb
29,GG  ,0x09388eff,0x790a77fb,0x786acb8f,0xfe1623b1,x[ 2]=0x00000000, 9,0xfcefa3f8,0x9f47e4f8
30,GG  ,0xfe1623b1,0x9f47e4f8,0x790a77fb,0x786acb8f,x[ 7]=0x00000000,14,0x676f02d9,0xa62884aa
31,GG  ,0x786acb8f,0xa62884aa,0x9f47e4f8,0x790a77fb,x[12]=0x00000000,20,0x8d2a4c8a,0x726342d3
32,HH  ,0x790a77fb,0x726342d3,0xa62884aa,0x9f47e4f8,x[ 5]=0x00000000, 4,0xfffa3942,0xb3707ebf
33,HH  ,0x9f47e4f8,0xb3707ebf,0x726342d3,0xa62884aa,x[ 8]=0x00000000,11,0x8771f681,0x60127b2e
34,HH  ,0xa62884aa,0x60127b2e,0xb3707ebf,0x726342d3,x[11]=0x00000000,16,0x6d9d6122,0x8d212ff5
35,HH  ,0x726342d3,0x8d212ff5,0x60127b2e,0xb3707ebf,x[14]=0x00000018,23,0xfde5380c,0x3b0875c7
36,HH  ,0xb3707ebf,0x3b0875c7,0x8d212ff5,0x60127b2e,x[ 1]=0x00000000, 4,0xa4beea44,0x21b117b9
37,HH  ,0x60127b2e,0x21b117b9,0x3b0875c7,0x8d212ff5,x[ 4]=0x00000000,11,0x4bdecfa9,0x6e7429d5
38,HH  ,0x8d212ff5,0x6e7429d5,0x21b117b9,0x3b0875c7,x[ 7]=0x00000000,16,0xf6bb4b60,0x3575227e
39,HH  ,0x3b0875c7,0x3575227e,0x6e7429d5,0x21b117b9,x[10]=0x00000000,23,0xbebfbc70,0x5a2f5ea5
40,HH  ,0x21b117b9,0x5a2f5ea5,0x3575227e,0x6e7429d5,x[13]=0x00000000, 4,0x289b7ec6,0x11de1779
41,HH  ,0x6e7429d5,0x11de1779,0x5a2f5ea5,0x3575227e,x[ 0]=0x80636261,11,0xeaa127fa,0xfadcaa38
42,HH  ,0x3575227e,0xfadcaa38,0x11de1779,0x5a2f5ea5,x[ 3]=0x00000000,16,0xd4ef3085,0x31c465ca
43,HH  ,0x5a2f5ea5,0x31c465ca,0xfadcaa38,0x11de1779,x[ 6]=0x00000000,23,0x04881d05,0x4c6124f4
44,HH  ,0x11de1779,0x4c6124f4,0x31c465ca,0xfadcaa38,x[ 9]=0x00000000, 4,0xd9d4d039,0x7f2e507b
45,HH  ,0xfadcaa38,0x7f2e507b,0x4c6124f4,0x31c465ca,x[12]=0x00000000,11,0xe6db99e5,0x99d9679d
46,HH  ,0x31c465ca,0x99d9679d,0x7f2e507b,0x4c6124f4,x[15]=0x00000000,16,0x1fa27cf8,0x8fae6399
47,HH  ,0x4c6124f4,0x8fae6399,0x99d9679d,0x7f2e507b,x[ 2]=0x00000000,23,0xc4ac5665,0x7beb9700
48,II  ,0x7f2e507b,0x7beb9700,0x8fae6399,0x99d9679d,x[ 0]=0x80636261, 6,0xf4292244,0x7b201df8
49,II  ,0x99d9679d,0x7b201df8,0x7beb9700,0x8fae6399,x[ 7]=0x00000000,10,0x432aff97,0xf4e8e96e
50,II  ,0x8fae6399,0xf4e8e96e,0x7b201df8,0x7beb9700,x[14]=0x00000018,15,0xab9423a7,0xb298cefd
51,II  ,0x7beb9700,0xb298cefd,0xf4e8e96e,0x7b201df8,x[ 5]=0x00000000,21,0xfc93a039,0x8bf025c4
52,II  ,0x7b201df8,0x8bf025c4,0xb298cefd,0xf4e8e96e,x[12]=0x00000000, 6,0x655b59c3,0x06cc5e8a
53,II  ,0xf4e8e96e,0x06cc5e8a,0x8bf025c4,0xb298cefd,x[ 3]=0x00000000,10,0x8f0ccc92,0x5b0d97aa
54,II  ,0xb298cefd,0x5b0d97aa,0x06cc5e8a,0x8bf025c4,x[10]=0x00000000,15,0xffeff47d,0x7d632dd0
55,II  ,0x8bf025c4,0x7d632dd0,0x5b0d97aa,0x06cc5e8a,x[ 1]=0x00000000,21,0x85845dd1,0x3bfa2c27
56,II  ,0x06cc5e8a,0x3bfa2c27,0x7d632dd0,0x5b0d97aa,x[ 8]=0x00000000, 6,0x6fa87e4f,0x7f81cc35
57,II  ,0x5b0d97aa,0x7f81cc35,0x3bfa2c27,0x7d632dd0,x[15]=0x00000000,10,0xfe2ce6e0,0x094454ab
58,II  ,0x7d632dd0,0x094454ab,0x7f81cc35,0x3bfa2c27,x[ 6]=0x00000000,15,0xa3014314,0x4f9dbe3f
59,II  ,0x3bfa2c27,0x4f9dbe3f,0x094454ab,0x7f81cc35,x[13]=0x00000000,21,0x4e0811a1,0x7327d604
60,II  ,0x7f81cc35,0x7327d604,0x4f9dbe3f,0x094454ab,x[ 4]=0x00000000, 6,0xf7537e82,0x310ade8f
61,II  ,0x094454ab,0x310ade8f,0x7327d604,0x4f9dbe3f,x[11]=0x00000000,10,0xbd3af235,0x624d8cb2
62,II  ,0x4f9dbe3f,0x624d8cb2,0x310ade8f,0x7327d604,x[ 2]=0x00000000,15,0x2ad7d2bb,0xe484b9d8
63,II  ,0x7327d604,0xe484b9d8,0x624d8cb2,0x310ade8f,x[ 9]=0x00000000,21,0xeb86d391,0xc08226b3
abc
md5 900150983cd24fb0d6963f7d28e17f72

プログラムソースの概要

HASH_UINT128

128bitのハッシュ値及びメンバー関数を定義しています。
byte,DWORD(UINT32),UINT64でアクセスしやすいように共用体で定義しております。
ハッシュ計算中に使用するa,b,c,dはu32[0],u32[1],u32[2],u32[3]に割り当てています。

F,G,H,I,FF,GG,HH,II関数

ハッシュを計算するサブ関数です。protectedメンバとし、メンバー関数及び派生クラスのみにアクセスを許しています。

rotate関数

md5hash関数から呼び出されます。
FF,GG,HH,II関数を呼び出した後にa,b,c,dを移動させるために使用します。
ハッシュ値である128bit値を32bit左ローテートします。 protectedメンバとし、メンバー関数及び派生クラスのみにアクセスを許しています。

init関数

ハッシュ計算のa,b,c,dの初期値を設定します。md5hash関数を呼び出す前にあらかじめ呼び出しておく必要があります。

md5hash

引数msgで示され長さlenの文字列のMD5ハッシュ値を計算します。
この関数は、1つのデータに対して分割しながら複数回呼び出してハッシュ値を算出することができません。
あらかじめデータサイズがわかっており、メモリ上に展開しておくかファイルをメモリマップドファイルによりメモリアクセス可能として使用する必要があります。

hex関数

ハッシュ値を引数sで示されるアドレスへ16進数文字列に変換して保存します。

main関数

HASH_UINT128オブジェクトを作成し、変数passにMD5ハッシュを求める元の文字列のアドレスを保存し、md5hash関数を呼び出します。
hexメンバーによりハッシュの16進数文字列を作成し、標準出力にハッシュ値を出力します。

ソースコード

md5.cpp


#include <windows.h>
#include <stdio.h>

#define INFO_DISP       1       //      詳細情報が必要でない場合、この行をコメントアウトする。

/*
// _lrotl 関数がない環境で定義する。
// xを左へnビットローテートする
inline UINT32 _lrotl(UINT32 x,UINT32 n){
        return ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)));
}
*/

//以下は、windows.hをインクルードしない場合に定義してください。
/*
typedef unsigned long long UINT64;
typedef signed int INT32;
typedef unsigned int UINT32;
typedef unsigned char BYTE;
*/

union HASH_UINT128{
        UINT64  u64[2];
        UINT32  u32[4];
        BYTE    u8[16];
protected:
        UINT32 F(UINT32 x, UINT32 y, UINT32 z){
                return (x & y) | (~x & z);
        }
        UINT32 FF(UINT32 a, UINT32 b, UINT32 c, UINT32 d, UINT32 x, UINT32 s, UINT32 ac){
                a += F(b, c, d) + x + ac;
                a = _lrotl(a, s);
                a += b;
                return a;
        }
        UINT32 G(UINT32 x, UINT32 y, UINT32 z){
                return (x & z) | (y & (~z));
        }
        UINT32 GG(UINT32 a, UINT32 b, UINT32 c, UINT32 d, UINT32 x, UINT32 s, UINT32 ac){
                a += G(b, c, d) + x + ac;
                a = _lrotl(a, s);
                a += b;
                return a;
        }
        UINT32 H(UINT32 x, UINT32 y, UINT32 z){
                return x ^ y ^ z;
        }
        UINT32 HH(UINT32 a, UINT32 b, UINT32 c, UINT32 d, UINT32 x, UINT32 s, UINT32 ac){
                a += H(b, c, d) + x + ac;
                a = _lrotl(a, s);
                a += b;
                return a;
        }
        UINT32 I(UINT32 x, UINT32 y, UINT32 z){
                return y ^ (x | (~z));
        }
        UINT32 II(UINT32 a, UINT32 b, UINT32 c, UINT32 d, UINT32 x, UINT32 s, UINT32 ac){
                a += I(b, c, d) + x + ac;
                a = _lrotl(a, s);
                a += b;
                return a;
        }
        void rotate(void){
                UINT32 t = u32[3];
                u32[3] = u32[2];
                u32[2] = u32[1];
                u32[1] = u32[0];
                u32[0] = t;
        }
public:
        void init(void){
                u32[0] = 0x67452301;
                u32[1] = 0xefcdab89;
                u32[2] = 0x98badcfe;
                u32[3] = 0x10325476;
        }
        void hex(char* s){
                sprintf_s(s, 33, "%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x%0.2x", u8[0], u8[1], u8[2], u8[3], u8[4], u8[5], u8[6], u8[7], u8[8], u8[9], u8[10], u8[11], u8[12], u8[13], u8[14], u8[15]);
        }
        void md5hash(char* msg, INT32 len);
};

void HASH_UINT128::md5hash(char* msg, INT32 len){
        //      テーブル T[n-1]=429467296*fabs(sin(n)); // 2^32=429467296
        static UINT32 T[] = {
                0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, // 01~04
                0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, // 05~08
                0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, // 09~12
                0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, // 13~16
                0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, // 17~20
                0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, // 21~24
                0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, // 25~28
                0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, // 29~32
                0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, // 33~36
                0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, // 37~40
                0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, // 41~44
                0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, // 45~48
                0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, // 49~52
                0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, // 53~56
                0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, // 57~60
                0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391  // 61~64
        };

        UINT32 x_buf[64 / 4];
        BYTE* block_buf=(BYTE *)x_buf;
        UINT32* x;
        BYTE* block;

        int n;
        UINT32 temp[4];

        UINT32 & a = u32[0];
        UINT32 & b = u32[1];
        UINT32 & c = u32[2];
        UINT32 & d = u32[3];

        UINT32 FF_S[] = { 7, 12, 17, 22 };      //      ローテート数
        UINT32 GG_S[] = { 5,  9, 14, 20 };      //      ローテート数
        UINT32 HH_S[] = { 4, 11, 16, 23 };      //      ローテート数
        UINT32 II_S[] = { 6, 10, 15, 21 };      //      ローテート数
        
        INT64 org_len = len;
        int msg_sz;
        bool end = false;
        int old_sz=0;   //      前回のメッセージ長
        do{
                temp[0] = u32[0];
                temp[1] = u32[1];
                temp[2] = u32[2];
                temp[3] = u32[3];
                //      メッセージサイズの調整
        
                if (512/8 <= len){   //      512bit 対象
                        msg_sz = 512 / 8;
                        x = (UINT32*)msg;
                        block = (BYTE *)msg;
                        old_sz=512;
                }
                else{
                        x = x_buf;
                        block = block_buf;
                        UINT64* sz = (UINT64*)&x[14];
                        msg_sz = (int)len;
                        if (msg_sz){
                                for (n = 0; n < msg_sz; n++){
                                        block[n] = msg[n];
                                }
                                if (n < 512 / 8 - 8){ // 56byteより小さいので終了ブロックである。
                                        block[n++] = 0x80;
                                        for (; n < (512 / 8) - 8; n++){
                                                block[n] = 0;
                                        }
                                        *sz = org_len * 8;
                                        end=true;
                                }else{  //      56byteから63byteである 次のブロックで終了する
                                        n = msg_sz;
                                        block[n++] = 0x80;
                                        for (; n < 64; n++)
                                                block[n] = 0x00;
                                }
                        }else{  //      長さが0の場合 全部0で埋める 終了ブロックである。
                                if(old_sz==512){
                                        x[0]=0x80;
                                        n=1;
                                }else
                                        n=0;
                                for (; n < 14; n++){
                                        x[n] = 0;
                                }
                                *sz=org_len*8;
                                end = true;
                        }
                        old_sz=msg_sz;
                }
#ifdef INFO_DISP
                printf("----------------------------------------\n");
                for (n = 0; n < 16; n++){
                        printf("x[%2d]=0x%0.8x; // 0x%0.2x 0x%0.2x 0x%0.2x 0x%0.2x%\n", n, x[n], block[n * 4], block[n * 4 + 1], block[n * 4 + 2], block[n * 4 + 3]);
                }
                printf("n ,func, A        ,B         ,C         ,D         ,x[n]            ,S ,T[n]      ,ans\n");
#endif
                UINT32 xp;
                for (n = 0; n < 16; n++){
#ifdef INFO_DISP
                        printf("%2d,", n);
                        printf("FF  ,0x%0.8x,0x%0.8x,0x%0.8x,0x%0.8x,", a, b, c, d);
                        printf("x[%2d]=0x%0.8x,", n, x[n]);
                        printf("%2d,0x%0.8x,", FF_S[n % 4], T[n]);
#endif
                        a = FF(a, b, c, d, x[n], FF_S[n % 4], T[n]);
#ifdef INFO_DISP
                        printf("0x%0.8x\n", a);
#endif
                        rotate();
                }
                xp = 1;
                for (; n < 32; n++){
#ifdef INFO_DISP
                        printf("%2d,", n);
                        printf("GG  ,0x%0.8x,0x%0.8x,0x%0.8x,0x%0.8x,", a, b, c, d);
                        printf("x[%2d]=0x%0.8x,", xp, x[xp]);
                        printf("%2d,0x%0.8x,", GG_S[n % 4], T[n]);
#endif
                        a = GG(a, b, c, d, x[xp], GG_S[n % 4], T[n]);
#ifdef INFO_DISP
                        printf("0x%0.8x\n", a);
#endif
                        xp = (xp + 5) % 16;
                        rotate();
                }
                xp = 5;
                for (; n < 48; n++){
#ifdef INFO_DISP
                        printf("%2d,", n);
                        printf("HH  ,0x%0.8x,0x%0.8x,0x%0.8x,0x%0.8x,", a, b, c, d);
                        printf("x[%2d]=0x%0.8x,", xp, x[xp]);
                        printf("%2d,0x%0.8x,", HH_S[n % 4], T[n]);
#endif
                        a = HH(a, b, c, d, x[xp], HH_S[n % 4], T[n]);
#ifdef INFO_DISP
                        printf("0x%0.8x\n", a);
#endif
                        xp = (xp + 3) % 16;
                        rotate();
                }
                xp = 0;
                for (; n < 64; n++){
#ifdef INFO_DISP
                        printf("%2d,", n);
                        printf("II  ,0x%0.8x,0x%0.8x,0x%0.8x,0x%0.8x,", a, b, c, d);
                        printf("x[%2d]=0x%0.8x,", xp, x[xp]);
                        printf("%2d,0x%0.8x,", II_S[n % 4], T[n]);
#endif
                        a = II(a, b, c, d, x[xp], II_S[n % 4], T[n]);
#ifdef INFO_DISP
                        printf("0x%0.8x\n", a);
#endif
                        xp = (xp + 7) % 16;
                        rotate();
                }

                a += temp[0];
                b += temp[1];
                c += temp[2];
                d += temp[3];
                len -= msg_sz;
                msg += msg_sz;
        } while (0 <= len && end==false);
}

void main(void){
        HASH_UINT128 hash;
        char* pass = "abc";

        hash.init();
        hash.md5hash(pass, (int)strlen(pass));
        char hexs[36];
        hash.hex(hexs);
        printf("%s\nmd5 %s\n",pass,hexs);
}

実行ファイルとソースファイルのダウンロード(Visual C++ 2013 マルチバイトでコンパイル)