JavaScriptによるMD5の実装
================================================================================
Name : MessageDigest
In : [none]
Out : [none]
Note : メッセージダイジェスト
--------------------------------------------------------------------------------
Version : Ver1.0.0 | 2006/11/18 | 新規作成
--------------------------------------------------------------------------------
License : New BSD license
URL : www.kanasansoft.com
================================================================================
*/
/*--------------------------------------------------------------------------------
コンストラクタ
--------------------------------------------------------------------------------*/
function MessageDigest(){}
/*--------------------------------------------------------------------------------
定数
--------------------------------------------------------------------------------*/
MessageDigest.BY_STRING = "string";
MessageDigest.BY_ARRAY = "array";
///*--------------------------------------------------------------------------------
// バイト配列に変換する(内部関数)
//--------------------------------------------------------------------------------*/
//MessageDigest._changeParameterToByteArray
//= function(param){
//
// var rtn;
//
// switch(param.constructor){
// case Number:
// rtn = MessageDigest._changeNumberToByteArray(param);
// break;
// case String:
// rtn = MessageDigest._changeStringToByteArray(param);
// break;
// default:
// rtn = null;
// break;
// }
//
// return rtn;
//
//}
/*--------------------------------------------------------------------------------
数値をバイト配列に変換する(内部関数)
--------------------------------------------------------------------------------*/
MessageDigest._changeNumberToByteArray
= function(num){
//参照渡し破棄
var numbuf = Number(num);
var ary = [];
//下位桁より配列化
while(numbuf!=0){
ary . push(numbuf & 0xFF);
numbuf = numbuf >>> 8;
}
//バイトを反転
ary . reverse();
return ary;
}
/*--------------------------------------------------------------------------------
文字を文字コード配列に変換する(内部関数)
(2バイト以上の場合は1バイト毎)
--------------------------------------------------------------------------------*/
MessageDigest._changeStringToByteArray
= function(str){
var bytearray = [];
var strlen = str.length;
//上位ワードより配列化
for(var i=0;i<strlen;i++){
bytearray = bytearray.concat(
MessageDigest._changeNumberToByteArray(
str.charCodeAt(i)
)
);
}
return bytearray;
}
/*--------------------------------------------------------------------------------
ビットを回転する(内部関数)
--------------------------------------------------------------------------------*/
MessageDigest._rotateBit
= function(bit,max,num){
var mask = Math.pow(2,max)-1;
var buf = bit & mask;
if(false){
}else if(num>0){
return (( (buf << ( num)) | (buf >>> (max-num)) ) & mask);
}else if(num<0){
return (( (buf >>> (-num)) | (buf << (max+num)) ) & mask);
}else if(num==0){
return buf;
}
}
/*--------------------------------------------------------------------------------
MD5本体
--------------------------------------------------------------------------------*/
MessageDigest.MD5
= function(param,by){
//MessageDigest参照オブジェクトの作成
var MD = MessageDigest;
//バイト配列変換
var charArray = MD._changeStringToByteArray(param);
//バイト配列長と拡張バイト長の取得
var charLen = charArray.length;
var paddingLen = 512-((charLen*8+64)%512);
//拡張バイト補填
charArray = charArray.concat(
[ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ].slice(0,paddingLen/8)
);
//バイト長補填
var lenArray = MD._changeNumberToByteArray(charLen*8);
lenArray . reverse();
lenArray = lenArray.concat([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]).slice(0,8);
charArray = charArray.concat(lenArray);
//レジスタ(32ビット)の初期化
var wordA = 0x67452301;
var wordB = 0xefcdab89;
var wordC = 0x98badcfe;
var wordD = 0x10325476;
//[T]テーブルの作成
var table = MD.MD5._makeTable();
//バイト配列を64バイト単位で処理
var charLen64 = charArray.length;
for(var i=0;i<charLen64;i+=64){
//64バイトのデータを4バイト単位で格納
//(4バイトは下位より格納)
var numX = [];
for(var j=0;j<16;j++){
numX[j] = 0;
for(var k=0;k<4;k++){
numX[j] += charArray[i+j*4+k]*Math.pow(2,k*8);
}
}
//データ退避
var wordAA = wordA;
var wordBB = wordB;
var wordCC = wordC;
var wordDD = wordD;
//ハッシュ生成(Round 1)
wordA = MD.MD5._rogicRound1(wordA,wordB,wordC,wordD,numX[0] , 7,table[ 1]);
wordD = MD.MD5._rogicRound1(wordD,wordA,wordB,wordC,numX[1] ,12,table[ 2]);
wordC = MD.MD5._rogicRound1(wordC,wordD,wordA,wordB,numX[2] ,17,table[ 3]);
wordB = MD.MD5._rogicRound1(wordB,wordC,wordD,wordA,numX[3] ,22,table[ 4]);
wordA = MD.MD5._rogicRound1(wordA,wordB,wordC,wordD,numX[4] , 7,table[ 5]);
wordD = MD.MD5._rogicRound1(wordD,wordA,wordB,wordC,numX[5] ,12,table[ 6]);
wordC = MD.MD5._rogicRound1(wordC,wordD,wordA,wordB,numX[6] ,17,table[ 7]);
wordB = MD.MD5._rogicRound1(wordB,wordC,wordD,wordA,numX[7] ,22,table[ 8]);
wordA = MD.MD5._rogicRound1(wordA,wordB,wordC,wordD,numX[8] , 7,table[ 9]);
wordD = MD.MD5._rogicRound1(wordD,wordA,wordB,wordC,numX[9] ,12,table[10]);
wordC = MD.MD5._rogicRound1(wordC,wordD,wordA,wordB,numX[10],17,table[11]);
wordB = MD.MD5._rogicRound1(wordB,wordC,wordD,wordA,numX[11],22,table[12]);
wordA = MD.MD5._rogicRound1(wordA,wordB,wordC,wordD,numX[12], 7,table[13]);
wordD = MD.MD5._rogicRound1(wordD,wordA,wordB,wordC,numX[13],12,table[14]);
wordC = MD.MD5._rogicRound1(wordC,wordD,wordA,wordB,numX[14],17,table[15]);
wordB = MD.MD5._rogicRound1(wordB,wordC,wordD,wordA,numX[15],22,table[16]);
//ハッシュ生成(Round 2)
wordA = MD.MD5._rogicRound2(wordA,wordB,wordC,wordD,numX[1] , 5,table[17]);
wordD = MD.MD5._rogicRound2(wordD,wordA,wordB,wordC,numX[6] , 9,table[18]);
wordC = MD.MD5._rogicRound2(wordC,wordD,wordA,wordB,numX[11],14,table[19]);
wordB = MD.MD5._rogicRound2(wordB,wordC,wordD,wordA,numX[0] ,20,table[20]);
wordA = MD.MD5._rogicRound2(wordA,wordB,wordC,wordD,numX[5] , 5,table[21]);
wordD = MD.MD5._rogicRound2(wordD,wordA,wordB,wordC,numX[10], 9,table[22]);
wordC = MD.MD5._rogicRound2(wordC,wordD,wordA,wordB,numX[15],14,table[23]);
wordB = MD.MD5._rogicRound2(wordB,wordC,wordD,wordA,numX[4] ,20,table[24]);
wordA = MD.MD5._rogicRound2(wordA,wordB,wordC,wordD,numX[9] , 5,table[25]);
wordD = MD.MD5._rogicRound2(wordD,wordA,wordB,wordC,numX[14], 9,table[26]);
wordC = MD.MD5._rogicRound2(wordC,wordD,wordA,wordB,numX[3] ,14,table[27]);
wordB = MD.MD5._rogicRound2(wordB,wordC,wordD,wordA,numX[8] ,20,table[28]);
wordA = MD.MD5._rogicRound2(wordA,wordB,wordC,wordD,numX[13], 5,table[29]);
wordD = MD.MD5._rogicRound2(wordD,wordA,wordB,wordC,numX[2] , 9,table[30]);
wordC = MD.MD5._rogicRound2(wordC,wordD,wordA,wordB,numX[7] ,14,table[31]);
wordB = MD.MD5._rogicRound2(wordB,wordC,wordD,wordA,numX[12],20,table[32]);
//ハッシュ生成(Round 3)
wordA = MD.MD5._rogicRound3(wordA,wordB,wordC,wordD,numX[5] , 4,table[33]);
wordD = MD.MD5._rogicRound3(wordD,wordA,wordB,wordC,numX[8] ,11,table[34]);
wordC = MD.MD5._rogicRound3(wordC,wordD,wordA,wordB,numX[11],16,table[35]);
wordB = MD.MD5._rogicRound3(wordB,wordC,wordD,wordA,numX[14],23,table[36]);
wordA = MD.MD5._rogicRound3(wordA,wordB,wordC,wordD,numX[1] , 4,table[37]);
wordD = MD.MD5._rogicRound3(wordD,wordA,wordB,wordC,numX[4] ,11,table[38]);
wordC = MD.MD5._rogicRound3(wordC,wordD,wordA,wordB,numX[7] ,16,table[39]);
wordB = MD.MD5._rogicRound3(wordB,wordC,wordD,wordA,numX[10],23,table[40]);
wordA = MD.MD5._rogicRound3(wordA,wordB,wordC,wordD,numX[13], 4,table[41]);
wordD = MD.MD5._rogicRound3(wordD,wordA,wordB,wordC,numX[0] ,11,table[42]);
wordC = MD.MD5._rogicRound3(wordC,wordD,wordA,wordB,numX[3] ,16,table[43]);
wordB = MD.MD5._rogicRound3(wordB,wordC,wordD,wordA,numX[6] ,23,table[44]);
wordA = MD.MD5._rogicRound3(wordA,wordB,wordC,wordD,numX[9] , 4,table[45]);
wordD = MD.MD5._rogicRound3(wordD,wordA,wordB,wordC,numX[12],11,table[46]);
wordC = MD.MD5._rogicRound3(wordC,wordD,wordA,wordB,numX[15],16,table[47]);
wordB = MD.MD5._rogicRound3(wordB,wordC,wordD,wordA,numX[2] ,23,table[48]);
//ハッシュ生成(Round 4)
wordA = MD.MD5._rogicRound4(wordA,wordB,wordC,wordD,numX[0] , 6,table[49]);
wordD = MD.MD5._rogicRound4(wordD,wordA,wordB,wordC,numX[7] ,10,table[50]);
wordC = MD.MD5._rogicRound4(wordC,wordD,wordA,wordB,numX[14],15,table[51]);
wordB = MD.MD5._rogicRound4(wordB,wordC,wordD,wordA,numX[5] ,21,table[52]);
wordA = MD.MD5._rogicRound4(wordA,wordB,wordC,wordD,numX[12], 6,table[53]);
wordD = MD.MD5._rogicRound4(wordD,wordA,wordB,wordC,numX[3] ,10,table[54]);
wordC = MD.MD5._rogicRound4(wordC,wordD,wordA,wordB,numX[10],15,table[55]);
wordB = MD.MD5._rogicRound4(wordB,wordC,wordD,wordA,numX[1] ,21,table[56]);
wordA = MD.MD5._rogicRound4(wordA,wordB,wordC,wordD,numX[8] , 6,table[57]);
wordD = MD.MD5._rogicRound4(wordD,wordA,wordB,wordC,numX[15],10,table[58]);
wordC = MD.MD5._rogicRound4(wordC,wordD,wordA,wordB,numX[6] ,15,table[59]);
wordB = MD.MD5._rogicRound4(wordB,wordC,wordD,wordA,numX[13],21,table[60]);
wordA = MD.MD5._rogicRound4(wordA,wordB,wordC,wordD,numX[4] , 6,table[61]);
wordD = MD.MD5._rogicRound4(wordD,wordA,wordB,wordC,numX[11],10,table[62]);
wordC = MD.MD5._rogicRound4(wordC,wordD,wordA,wordB,numX[2] ,15,table[63]);
wordB = MD.MD5._rogicRound4(wordB,wordC,wordD,wordA,numX[9] ,21,table[64]);
//退避していたデータを加算
wordA += wordAA;
wordB += wordBB;
wordC += wordCC;
wordD += wordDD;
//32ビットへの丸め込み(レジスタのサイズ)
wordA = wordA & 0xffffffff;
wordB = wordB & 0xffffffff;
wordC = wordC & 0xffffffff;
wordD = wordD & 0xffffffff;
}
//各々を下位バイト順にした後(反転した後)、順に連結
var rtnArray = [];
var rtnA = MD._changeNumberToByteArray(wordA);
var rtnB = MD._changeNumberToByteArray(wordB);
var rtnC = MD._changeNumberToByteArray(wordC);
var rtnD = MD._changeNumberToByteArray(wordD);
rtnA.reverse();
rtnB.reverse();
rtnC.reverse();
rtnD.reverse();
rtnArray = rtnArray.concat(rtnA);
rtnArray = rtnArray.concat(rtnB);
rtnArray = rtnArray.concat(rtnC);
rtnArray = rtnArray.concat(rtnD);
//取得指定方法毎に戻り値処理
switch(by){
case MD.BY_ARRAY:
return rtnArray;
break;
case MD.BY_STRING:
default:
var rtnArrayLen = rtnArray.length;
var rtnString = "";
for(var i=0;i<rtnArrayLen;i++){
rtnString += ("00"+rtnArray[i].toString(16)).slice(-2);
}
return rtnString;
break;
}
}
/*--------------------------------------------------------------------------------
補助関数(内側)(内部関数)
--------------------------------------------------------------------------------*/
MessageDigest.MD5._rogicF = function(x,y,z){return ( ( x) & ( y) ) | ( (~x) & ( z) ) };
MessageDigest.MD5._rogicG = function(x,y,z){return ( ( x) & ( z) ) | ( ( y) & (~z) ) };
MessageDigest.MD5._rogicH = function(x,y,z){return ( x) ^ ( y) ^ ( z) };
MessageDigest.MD5._rogicI = function(x,y,z){return ( y) ^ ( ( x) | (~z) ) };
/*--------------------------------------------------------------------------------
補助関数(外側)(内部関数)
--------------------------------------------------------------------------------*/
MessageDigest.MD5._rogicRound1 = function(a,b,c,d,K,s,I){return b+MessageDigest._rotateBit((a+MessageDigest.MD5._rogicF(b,c,d)+K+I),32,s)};
MessageDigest.MD5._rogicRound2 = function(a,b,c,d,K,s,I){return b+MessageDigest._rotateBit((a+MessageDigest.MD5._rogicG(b,c,d)+K+I),32,s)};
MessageDigest.MD5._rogicRound3 = function(a,b,c,d,K,s,I){return b+MessageDigest._rotateBit((a+MessageDigest.MD5._rogicH(b,c,d)+K+I),32,s)};
MessageDigest.MD5._rogicRound4 = function(a,b,c,d,K,s,I){return b+MessageDigest._rotateBit((a+MessageDigest.MD5._rogicI(b,c,d)+K+I),32,s)};
/*--------------------------------------------------------------------------------
テーブル作成(内部関数)
--------------------------------------------------------------------------------*/
MessageDigest.MD5._makeTable
= function(){
var table = [];
for(var i=0;i<=64;i++){
table[i] = Math.floor(0xffffffff*Math.abs(Math.sin(i)));
}
return table;
}