/* 多数決関数を利用した鍵管理 Created by Osaka(2013/4/24) 多数決関数で分散した鍵x、y、zについて それらを2つづつを連結し、新たな鍵列(連結鍵)xy、yz、zxを作成 この鍵列の先頭に次のような16バイトを付加する 第1バイトのビット列はnnnnnxxxで、 nは任意のビット、xxxは、3つの鍵の組み合わせ 第2バイトからは鍵列16進列のMD5を示す 課題 任意長の主となる副鍵(サーバー管理)への対応 乱数列生成 http://eddie.keddy.ne.jp/change/random.htm */ var BitArray=require('bit-array'); var Stochator=require('./stochator'); var crypto=require('crypto'); //256個の乱数、key128文字に対応 var rd=new Array(209,192,123,68,26,25,188,235,79,116,12,154,107,30,174,106,134,49,187,248,5,29,210,100,230,111,179,153,78,135,48,197,183,253,39,145,43,200,16,60,99,15,92,37,101,115,176,242,59,160,19,250,207,93,241,141,212,220,118,7,173,103,0,87,244,75,3,41,72,226,58,112,89,84,157,28,238,71,131,201,129,249,80,62,8,181,86,205,224,17,162,85,255,70,185,54,105,61,55,219,74,6,195,27,38,56,137,91,214,148,1,245,110,204,42,218,65,23,125,182,52,50,166,152,2,46,136,32,223,189,158,171,178,169,128,234,104,217,35,51,202,18,232,151,20,9,130,243,95,186,53,57,150,227,194,191,172,47,221,117,156,31,236,64,159,67,231,233,132,120,180,147,33,216,251,69,161,167,143,199,228,122,82,11,4,21,140,155,83,73,170,36,203,121,133,77,146,239,184,109,88,24,196,213,211,215,13,138,126,247,81,252,127,76,124,144,165,168,177,98,119,240,175,198,225,190,66,222,149,102,45,193,22,246,108,113,97,44,164,14,208,63,34,229,10,114,139,254,206,40,90,96,94,163,142,237); /* var rr=""; for(var i=0;i<rd.length;i++){ var v=rd[i].toString(16); if(v.length==1)v="0"+v; rr+=v; } console.log(rd.length+"\n"+rr+"\n"+rr.length); */ var HEX_DIGIT=new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"); var BIT_DIGIT=new Array("0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"); var keybits=64; var rand2=new Stochator({ kind: "integer", min: 0, max: 1 }, Boolean); var rand3=new Stochator({ kind: "integer", min: 0, max: 2 }, "triple"); var keystr="大坂哲司fujimic江東区青海1-1-20ダイバーシティ19F"; var d1=string2hex(keystr);//主鍵 var keybits=d1.length*4;//キーのビット長 console.log(keystr+"\nstring2hex:"+d1+"\nlength="+keybits+" "+keystr.length); d1=hex2bit(d1); console.log("bit="+d1) D1=new BitArray(keybits); for(var i=0;i<keybits;i++)if(d1.charAt(i)=='1')D1.set(i,true); console.log("\n") /* var d2=string2hex("多数決関"); console.log("string2hex:"+d2); d2=hex2bit(d2); */ //var D2=getRandBitset(keybits);//ランダムな主となる副鍵 var D2=getRandData(keystr.length);//サーバーが管理している主となる副鍵 console.log("set="+D2.toString()); var x=generateKey(D1, D2);//主鍵bs(ユーザー管理)、副鍵a1(サーバー管理)から多数決関数に合致する2鍵a2、a3を求める var a2=x[0],a3=x[1]; console.log("k:" +D1.toString()); console.log("x:" +D2.toString()); console.log("y:" +a2.toString()); console.log("z:" +a3.toString()); b123=majority(D2, a2, a3);//多数決関数で、副鍵から主鍵を求める console.log("f:" +b123.toString()); console.log("\n") st=hex2string(bit2hex(b123.toString())); console.log("st:"+st); //秘密分散用に、鍵の連結を行う(連結鍵) var xy=keyjoin("110",D2,a2); var yz=keyjoin("011",a2,a3); var zx=keyjoin("101",a3,D2); console.log("\nxy:"+xy); console.log("yz:"+yz); //連結鍵2組から副鍵3個を求める var data1=getKeyData(xy); var data2=getKeyData(yz); var data=new Array(3); if(data1[0])data[0]=data1[0]; if(data1[1])data[1]=data1[1]; if(data1[2])data[2]=data1[2]; if(data2[0])data[0]=data2[0]; if(data2[1])data[1]=data2[1]; if(data2[2])data[2]=data2[2]; b123=majority(data[0], data[1], data[2]);//多数決関数で、副鍵から主鍵を求める console.log("F:" +b123.toString()); st=hex2string(bit2hex(b123.toString())); console.log("ST:"+st); console.log("\nyz:"+yz); console.log("zx:"+zx); var data1=getKeyData(yz); var data2=getKeyData(zx); var data=new Array(3); if(data1[0])data[0]=data1[0]; if(data1[1])data[1]=data1[1]; if(data1[2])data[2]=data1[2]; if(data2[0])data[0]=data2[0]; if(data2[1])data[1]=data2[1]; if(data2[2])data[2]=data2[2]; b123=majority(data[0], data[1], data[2]);//多数決関数で、副鍵から主鍵を求める console.log("F:" +b123.toString()); st=hex2string(bit2hex(b123.toString())); console.log("ST:"+st); //----------------------------------------------------------------------------- //バイト数値を16進、2進で現わす function byte2bit(num){ //console.log("byte2bit "+num); var h=HEX_DIGIT[((num>>8)>>4) & 0xF] + HEX_DIGIT[(num>>8) & 0xF]; h += HEX_DIGIT[(num>>4) & 0xF] + HEX_DIGIT[num & 0xF]; var b=BIT_DIGIT[((num>>8)>>4) & 0xF] + BIT_DIGIT[(num>>8) & 0xF]; b += BIT_DIGIT[(num>>4) & 0xF] + BIT_DIGIT[num & 0xF]; console.log(num + "h="+h+":b="+b); } //ユニコード16進コード列をビット列に変換 function hex2bit(d){ //console.log("hex2="+d); d=d.toLowerCase(); var s=""; for(var i=0;i<d.length;i++){ var c=d.charAt(i); s+=BIT_DIGIT[getCNUM(c)]; } return s; } //ユニコード16進コード列をビットセットに変換 function hex2bitset(d){ //console.log("hex2="+d); d=d.toLowerCase(); var s=""; for(var i=0;i<d.length;i++){ var c=d.charAt(i); s+=BIT_DIGIT[getCNUM(c)]; } var D=new BitArray(s.length); for(var i=0;i<s.length;i++)if(s.charAt(i)=='1')D.set(i,true); return D; } //ビット列をユニコード16進コード列に変換 function bit2hex(d){ //console.log("bit2="+d); var s=""; for(var i=0;i<d.length;i+=8){ var c1=d.charAt(i+0)=='1'?8:0; var c2=d.charAt(i+1)=='1'?4:0; var c3=d.charAt(i+2)=='1'?2:0; var c4=d.charAt(i+3)=='1'?1:0; var c5=d.charAt(i+4)=='1'?8:0; var c6=d.charAt(i+5)=='1'?4:0; var c7=d.charAt(i+6)=='1'?2:0; var c8=d.charAt(i+7)=='1'?1:0; c1=c1+c2+c3+c4;if(c1<10)c1=""+c1;else{c1+=87;c1=String.fromCharCode(c1);} c2=c5+c6+c7+c8;if(c2<10)c2=""+c2;else{c2+=87;c2=String.fromCharCode(c2);} s+=c1+c2; } return s; } //文字列をユニコード16進コード列に変換 function string2hex(s){ var d=""; for(var i=0;i<s.length;i++){ D=s.charCodeAt(i).toString(16); if(D.length==2)d+="00"+D; else d+=D; } return d; } //ユニコード16進コード列を文字列に変換 function hex2string(s){ s=s.toLowerCase(); var d=""; var st=""; for(var i=0;i<s.length;i+=4){ var c1=getCNUM(s.charAt(i+0)); var c2=getCNUM(s.charAt(i+1)); var c3=getCNUM(s.charAt(i+2)); var c4=getCNUM(s.charAt(i+3)); // var cc=c1*(16*16*16)+c2*(16*16)+c3*16+c4; var cc=c1*4096+c2*256+c3*16+c4; st+=String.fromCharCode(cc); } return st; } //0-9a-fを数字にする function getCNUM(s){ if(s>="0"&&s<="9")return s-"0"; else{ var c=s.charCodeAt(0); return (c-87);//c-97+10 } } //2つの鍵b1(主鍵)、b2(副鍵)から多数決関数に合致する2つの副鍵a2、a3を生成 function generateKey(b1, b2){ var a2=new BitArray(keybits); var a3=new BitArray(keybits); for(var i=0;i<keybits;i++){ //b1(0) = majority(b2(1),a2(0),a3(0)) if(!b1.get(i)&&b2.get(i)){ a2.set(i,false); a3.set(i,false); } //b1(1) = majority(b2(0),a2(1),a3(1)) else if(b1.get(i)&&!b2.get(i)){ a2.set(i,true); a3.set(i,true); } //b1(0) = majority(b2(0),a2(0),a3(0)), majority(b2(0),a2(0),a3(1)), majority(b2(0),a2(1),a3(0)) else if(!b1.get(i)&&!b2.get(i)){ var v=rand3.triple(); switch (v){ case 0 : a2.set(i,false); a3.set(i,false); break; case 1 : a2.set(i,false); a3.set(i,true); break; case 2 : a2.set(i,true); a3.set(i,false); break; } } //b1(1) = majority(b2(1),a2(0),a3(1)), majority(b2(1),a2(1),a3(0)), majority(b2(1),a2(1),a3(1)) else if(b1.get(i)&&b2.get(i)){ var v=rand3.triple(); switch (v){ case 0 : a2.set(i,false); a3.set(i,true); break; case 1 : a2.set(i,true); a3.set(i,false); break; case 2 : a2.set(i,true); a3.set(i,true); break; } } } return [a2,a3]; } //BitSetの多数決関数 majority(x, y, z)=((x&y) | (y&z) | (z&x)) function majority(x, y, z){ b12=x.copy(); b12.and (y); b23=y.copy(); b23.and (z); b31=z.copy(); b31.and (x); b23.or(b31); b123=b12.copy(); b123.or(b23); return b123; } //指定したビット数のビット列を求める function getRandBit(num){ var s=""; for(var i=0;i<num;i++){ if(rand2.next())s+="1"; else s+="0"; } return s; } //サーバー管理の乱数列から指定した長さの乱数列を得る function getRandData(num){ num=num+num; var rr=""; for(var i=0;i<num;i++){ var v=rd[i].toString(16); if(v.length==1)v="0"+v; rr+=v; } return hex2bitset(rr); } //指定したビット数のビット列を求める function getRandBitset(num){ var s=""; for(var i=0;i<num;i++){ if(rand2.next())s+="1"; else s+="0"; } var D=new BitArray(num); for(var i=0;i<num;i++)if(s.charAt(i)=='1')D.set(i,true); return D; } //鍵a、bの連結+付加情報(連結鍵と言う) function keyjoin(mode,a,b){ a=bit2hex(a.toString()); b=bit2hex(b.toString()); var info=getRandBitset(8); if(mode.charAt(0)=='1') info.set(0,true); else info.set(0,false); if(mode.charAt(1)=='1') info.set(1,true); else info.set(1,false); if(mode.charAt(2)=='1') info.set(2,true); else info.set(2,false); info=bit2hex(info.toString()); //console.log("info="+info); info=a+info+b; var digest=md5_hex(info); //console.log("digest="+digest); return info+digest; } //文字列のmd5を計算 function md5_hex(src){ var md5=crypto.createHash("md5"); md5.update(src, 'utf8'); return md5.digest('hex'); } //連結鍵から鍵を求める function getKeyData(d){ var k=keybits/8*2; var s=d.substring(0,k*2+2); var c=d.substring(k*2+2); var digest=md5_hex(s); //console.log("Digest="+digest); if(digest==c){ var s1=s.substring(0,k); s1=hex2bitset(s1); var s2=s.substring(k+2); s2=hex2bitset(s2); var info=s.substring(k,k+2); info=hex2bit(info); if(info.indexOf("110")==0)return [s1,s2,null]; else if(info.indexOf("011")==0)return [null,s1,s2]; else if(info.indexOf("101")==0)return [s2,null,s1]; else{ console.log("infodata is broken!!"); return [null,null,null]; } } else{ console.log("key is broken!!"); return [null,null,null]; } } function bin2hex(s){ // http://kevin.vanzonneveld.net // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + bugfixed by: Onno Marsman // + bugfixed by: Linuxworld // + improved by: ntoniazzi (http://phpjs.org/functions/bin2hex:361#comment_177616) // * example 1: bin2hex('Kev'); // * returns 1: '4b6576' // * example 2: bin2hex(String.fromCharCode(0x00)); // * returns 2: '00' var i, l, o = "", n; s += ""; for (i = 0, l = s.length; i < l; i++) { n = s.charCodeAt(i).toString(16) o += n.length < 2 ? "0" + n : n; } return o; } /* How to program hex2bin in Javascript? http://stackoverflow.com/questions/7695450/how-to-program-hex2bin-in-javascript */ function hex2bin(hex){ var bytes = [], str; for(var i=0; i< hex.length-1; i+=2) bytes.push(parseInt(hex.substr(i, 2), 16)); return String.fromCharCode.apply(String, bytes); } function fileSaveContents( filename , str ){ var fs = require("fs"); var fileContent = ""; var fd = fs.openSync(filename, "w"); fs.writeSync(fd, str, 0, "ascii"); fs.closeSync(fd); return fileContent; } function fileGetContents( filename ){ var fs = require("fs"); var fileContent = ""; var stat = fs.statSync(filename); var fd = fs.openSync(filename, "r"); var bytes = fs.readSync(fd, stat.size, 0, "ascii"); fileContent += bytes[0]; fs.closeSync(fd); return fileContent; }