JScriptでMD5ハッシュ

これもあまり使い道はないが・・・。

いや、書く事に意義がある(`・ω・´)

先人さんがいらっしゃったので、所々参考にさせてもらいました。。。。。

スクリプトの為、非常にパフォーマンスが悪いです。

というか、とりあえず正しく動けばいいと思って書いたので

パフォーマンスの最適化をやっていない。

コードも美しくないが、とりあえず。

 

RFC読みながら制作期間2日くらいかな?

 

MD5.zip
JScriptでMD5ハッシュ
MD5.zip
zip ( 圧縮 ) ファイル 2.5 KB

 

以下コード

/* MD5 (RFC 1321) */
var MD5 = function(){};
MD5._ToWord = function(data, startIndex)
{
    return    (data[startIndex  ]    ) |
            (data[startIndex+1]<< 8) |
            (data[startIndex+2]<<16) |
            (data[startIndex+3]<<24);
};

MD5._F = function(x, y, z){ return (x & y) | (~x & z); };
MD5._G = function(x, y, z){ return (x & z) | (y & ~z); };
MD5._H = function(x, y, z){ return x ^ y ^ z; };
MD5._I = function(x, y, z){ return y ^ (x | ~z); };
MD5._Regular = function(n){ while (n < 0) n += 4294967296; while (n > 4294967295) n -= 4294967296; return n; };
MD5._RoundParam = [
    [ 0,  7, 0xd76aa478, MD5._F],
    [ 1, 12, 0xe8c7b756, MD5._F],
    [ 2, 17, 0x242070db, MD5._F],
    [ 3, 22, 0xc1bdceee, MD5._F],
    [ 4,  7, 0xf57c0faf, MD5._F],
    [ 5, 12, 0x4787c62a, MD5._F],
    [ 6, 17, 0xa8304613, MD5._F],
    [ 7, 22, 0xfd469501, MD5._F],
    [ 8,  7, 0x698098d8, MD5._F],
    [ 9, 12, 0x8b44f7af, MD5._F],
    [10, 17, 0xffff5bb1, MD5._F],
    [11, 22, 0x895cd7be, MD5._F],
    [12,  7, 0x6b901122, MD5._F],
    [13, 12, 0xfd987193, MD5._F],
    [14, 17, 0xa679438e, MD5._F],
    [15, 22, 0x49b40821, MD5._F],
    [ 1,  5, 0xf61e2562, MD5._G],
    [ 6,  9, 0xc040b340, MD5._G],
    [11, 14, 0x265e5a51, MD5._G],
    [ 0, 20, 0xe9b6c7aa, MD5._G],
    [ 5,  5, 0xd62f105d, MD5._G],
    [10,  9, 0x02441453, MD5._G],
    [15, 14, 0xd8a1e681, MD5._G],
    [ 4, 20, 0xe7d3fbc8, MD5._G],
    [ 9,  5, 0x21e1cde6, MD5._G],
    [14,  9, 0xc33707d6, MD5._G],
    [ 3, 14, 0xf4d50d87, MD5._G],
    [ 8, 20, 0x455a14ed, MD5._G],
    [13,  5, 0xa9e3e905, MD5._G],
    [ 2,  9, 0xfcefa3f8, MD5._G],
    [ 7, 14, 0x676f02d9, MD5._G],
    [12, 20, 0x8d2a4c8a, MD5._G],
    [ 5,  4, 0xfffa3942, MD5._H],
    [ 8, 11, 0x8771f681, MD5._H],
    [11, 16, 0x6d9d6122, MD5._H],
    [14, 23, 0xfde5380c, MD5._H],
    [ 1,  4, 0xa4beea44, MD5._H],
    [ 4, 11, 0x4bdecfa9, MD5._H],
    [ 7, 16, 0xf6bb4b60, MD5._H],
    [10, 23, 0xbebfbc70, MD5._H],
    [13,  4, 0x289b7ec6, MD5._H],
    [ 0, 11, 0xeaa127fa, MD5._H],
    [ 3, 16, 0xd4ef3085, MD5._H],
    [ 6, 23, 0x04881d05, MD5._H],
    [ 9,  4, 0xd9d4d039, MD5._H],
    [12, 11, 0xe6db99e5, MD5._H],
    [15, 16, 0x1fa27cf8, MD5._H],
    [ 2, 23, 0xc4ac5665, MD5._H],
    [ 0,  6, 0xf4292244, MD5._I],
    [ 7, 10, 0x432aff97, MD5._I],
    [14, 15, 0xab9423a7, MD5._I],
    [ 5, 21, 0xfc93a039, MD5._I],
    [12,  6, 0x655b59c3, MD5._I],
    [ 3, 10, 0x8f0ccc92, MD5._I],
    [10, 15, 0xffeff47d, MD5._I],
    [ 1, 21, 0x85845dd1, MD5._I],
    [ 8,  6, 0x6fa87e4f, MD5._I],
    [15, 10, 0xfe2ce6e0, MD5._I],
    [ 6, 15, 0xa3014314, MD5._I],
    [13, 21, 0x4e0811a1, MD5._I],
    [ 4,  6, 0xf7537e82, MD5._I],
    [11, 10, 0xbd3af235, MD5._I],
    [ 2, 15, 0x2ad7d2bb, MD5._I],
    [ 9, 21, 0xeb86d391, MD5._I]
];

MD5._Round = function(wordBuf, X, p)
{
    var a = wordBuf[0];
    var b = wordBuf[1];
    var c = wordBuf[2];
    var d = wordBuf[3];
    // [abcd k s i]
    var word = a + (p[3](b,c,d)) + X[p[0]] + p[2];
    wordBuf[0] = MD5._Regular(b + MD5._Regular(((word<<p[1]) | (word>>>(32-p[1])))));
};
MD5.GetHashFromData = function(data)
{
    var dataLength = data.length;

    // (512 * n) + 448bitにする為のパディングデータを生成
    var padLength = (dataLength % 64);
    padLength = (padLength < 56) ? (56 - padLength) : (120 - padLength);
    var padData = [];
    padData.push(0x80);
    for(var i = 1; i < padLength; i++) padData.push(0x00);
    // 512bit長にする為、残りの64bitはデータ長の下位64bitを追加(単位bit)
    var bitDataLength = dataLength * 8; // to bit length
    for(var i = 0 ; i < 4 ; i++)
    {
        padData.push((bitDataLength >> (i*8)) & 0xff);
    }
    // uint32の範囲を超えるとシフトができないので、除算でシフトさせる
    if(bitDataLength >= 0x100000000)
    {
        bitDataLength = parseInt(bitDataLength / 0x100000000);
        for(var i = 0 ; i < 4 ; i++)
        {
            padData.push((bitDataLength >> (i*8)) & 0xff);
        }
    }
    else
    {
        for(var i = 0 ; i < 4 ; i++)
        {
            padData.push(0x00);
        }
    }


    for(var i = 0 ; i < padData.length ; i++)
        data.push(padData[i]);
    var len = data.length;

    // ワードバッファを初期化
    var wordBuf = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476];
    
    var abcd = [0,0,0,0];

    // 16ワード(64byte=512bit)ずつ処理
    for(k = 0; k < len; k += 64)
    {
        // 16ワード作成
        var word16 = [];
        for(var i = 0; i < 16; i++) word16.push(MD5._ToWord(data, i*4+k));

        // wordBufをコピー
        for(var i = 0; i < 4; i++) abcd[i] = wordBuf[i];

        // ハッシュ取得(64回ローテーション)
        for(var j = 0; j < 64; j++)
        {
            MD5._Round(abcd, word16, MD5._RoundParam[j]);
            var tmp = abcd[0];
            abcd[0] = abcd[3];
            abcd[3] = abcd[2];
            abcd[2] = abcd[1];
            abcd[1] = tmp;
        }
        for(var j = 0; j < 4; j++)
        {
            wordBuf[j] += MD5._Regular(abcd[j]);
            wordBuf[j] = MD5._Regular(wordBuf[j]);
        }
    }

    var out="";
    for(var i = 0 ; i < 4; i++)
    {
        for(j = 0; j < 4; j++)
        {
            var c = wordBuf[i]>>(8*j)&0xFF;
            out += "0123456789abcdef".charAt((c>>4) & 0xf);
            out += "0123456789abcdef".charAt(c & 0xf);
        }
    }
    return out;
};

// 文字列をbyte配列に変換する補助関数(簡易)
function ToBinary(s)
{
    var ret = [];
    for(var i = 0; i < s.length; i++)
        ret.push(s.charCodeAt(i));
    return ret;
}
// テストコード
// RFCのテストスイート
// MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
// MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
// MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
// MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
// MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
// MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f
// MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a

test();

function test()
{
if(MD5.GetHashFromData(
    ToBinary(""))
    != "d41d8cd98f00b204e9800998ecf8427e")
{ WScript.Echo("Test1失敗"); return; }

if(MD5.GetHashFromData(
    ToBinary("a"))
    != "0cc175b9c0f1b6a831c399e269772661")
{ WScript.Echo("Test2失敗"); return; }

if(MD5.GetHashFromData(
    ToBinary("abc"))
    != "900150983cd24fb0d6963f7d28e17f72")
{ WScript.Echo("Test3失敗"); return; }

if(MD5.GetHashFromData(
    ToBinary("message digest"))
    != "f96b697d7cb7938d525a2f31aaf161d0")
{ WScript.Echo("Test4失敗"); return; }

if(MD5.GetHashFromData(
    ToBinary("abcdefghijklmnopqrstuvwxyz"))
    != "c3fcd3d76192e4007dfb496cca67e13b")
{ WScript.Echo("Test5失敗"); return; }

if(MD5.GetHashFromData(
    ToBinary("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"))
    != "d174ab98d277d9f5a5611c2c9f419d9f")
{ WScript.Echo("Test6失敗"); return; }

if(MD5.GetHashFromData(
    ToBinary("12345678901234567890123456789012345678901234567890123456789012345678901234567890"))
    != "57edf4a22be3c955ac49da2e2107b67a")
{ WScript.Echo("Test7失敗"); return; }

WScript.Echo("成功");
}

 

 

2010.08.27