diff --git a/blake.js b/blake.js --- a/blake.js +++ b/blake.js @@ -1,108 +1,100 @@ -import {str2utf8} from "./util.js"; +// https://tools.ietf.org/html/rfc7693 const MASK=0xffffffff; const BLOCK_LEN=64; const IV=[0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19]; -const SIGMA=[ - [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], - [14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3], - [11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4], - [7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8], - [9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13], - [2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9], - [12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11], - [13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10], - [6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5], - [10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0] -]; +function padEnd(arr,length,val=0){ + return arr.concat((new Array(length-arr.length)).fill(0)); +} function rrot(x,shift){ return ((x>>>shift)|(x<<(32-shift)))&MASK; } -function g(arr,ia,ib,ic,id,x,y){ - let a=arr[ia], b=arr[ib], c=arr[ic], d=arr[id]; - // console.log(">> "+[a,b,c,d,x,y].map(x=>(x>>>0).toString(16))); - a=(a+b+x)&MASK; d=rrot(d^a,16); - // console.log([a,d].map(x=>(x>>>0).toString(16))); - c=(c+d)&MASK; b=rrot(b^c,12); - // console.log([c,b].map(x=>(x>>>0).toString(16))); - a=(a+b+y)&MASK; d=rrot(d^a,8); - // console.log([a,d].map(x=>(x>>>0).toString(16))); - c=(c+d)&MASK; b=rrot(b^c,7); - // console.log([c,b].map(x=>(x>>>0).toString(16))); - // console.log("<< "+[a,b,c,d].map(x=>(x>>>0).toString(16))); - arr[ia]=a; arr[ib]=b; arr[ic]=c; arr[id]=d; +function BLAKE2S(outputLen=32,key=[]){ + this._buffer=[]; + this._dataLen=0; + this._outputLen=outputLen; + + this._state=IV.slice(); + this._state[0]^=0x01010000^(key.length<<8)^this._outputLen; + + if(key.length>0){this.update(padEnd(key,BLOCK_LEN,0));} } -function f(state,data,offset,last){ - console.log("... "+data.map(x=>(x>>>0).toString(16))); - let v=state.concat(IV); - v[12]^=offset&MASK; - v[13]^=0; // !! offset>>>32 +BLAKE2S.prototype.update=function(data){ + for(let i=0;i<data.length;i++){ + if(this._buffer.length<BLOCK_LEN){ + this._buffer.push(data[i]); + this._dataLen++; + } + else{ + this._compress(false); + this._buffer=[]; + } + } +}; + +BLAKE2S.prototype.digest=function(){ + this._buffer=padEnd(this._buffer,BLOCK_LEN,0); + this._compress(true); + return int32s2bytes(this._state).slice(0,this._outputLen); +}; + +BLAKE2S.prototype._compress=function(last){ + const SIGMA=[ + [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], + [14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3], + [11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4], + [7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8], + [9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13], + [2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9], + [12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11], + [13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10], + [6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5], + [10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0] + ]; + let v=this._state.concat(IV); + v[12]^=this._dataLen&MASK; + v[13]^=(this._dataLen/0x100000000)&MASK; if(last){v[14]^=MASK;} + let data=bytes2int32s(this._buffer); for(let i=0;i<10;i++){ - console.log(i+": "+(v.map(x=>(x>>>0).toString(16))).join(" ")); let perm=SIGMA[i%10]; - g(v,0,4,8,12,data[perm[0]],data[perm[1]]); - g(v,1,5,9,13,data[perm[2]],data[perm[3]]); - g(v,2,6,10,14,data[perm[4]],data[perm[5]]); - g(v,3,7,11,15,data[perm[6]],data[perm[7]]); + this._mix(v,0,4,8,12,data[perm[0]],data[perm[1]]); + this._mix(v,1,5,9,13,data[perm[2]],data[perm[3]]); + this._mix(v,2,6,10,14,data[perm[4]],data[perm[5]]); + this._mix(v,3,7,11,15,data[perm[6]],data[perm[7]]); - g(v,0,5,10,15,data[perm[8]],data[perm[9]]); - g(v,1,6,11,12,data[perm[10]],data[perm[11]]); - g(v,2,7,8,13,data[perm[12]],data[perm[13]]); - g(v,3,4,9,14,data[perm[14]],data[perm[15]]); + this._mix(v,0,5,10,15,data[perm[8]],data[perm[9]]); + this._mix(v,1,6,11,12,data[perm[10]],data[perm[11]]); + this._mix(v,2,7,8,13,data[perm[12]],data[perm[13]]); + this._mix(v,3,4,9,14,data[perm[14]],data[perm[15]]); } - for(let i=0;i<8;i++){ - state[i]^=v[i]^v[i+8]; - } -} - -function blake2s(data,dataLen,keyLen=0,outputLen=32){ - let state=IV.slice(); - state[0]^=0x01010000^(keyLen<<8)^outputLen; - - if(data.length>1){ - for(let i=0;i<data.length-1;i++){f(state,data[i],(i+1)*BLOCK_LEN,false);} - } - - if(keyLen==0){f(state,data[data.length-1],dataLen,true);} - else{f(state,data[data.length-1],dataLen+BLOCK_LEN,true);} - - return state.slice(0,outputLen); + this._state=this._state.map((x,i)=>x^v[i]^v[i+8]); } -function bytes2int32(arr){ - return arr.reduce((acc,b,i)=>acc|b<<(i*8)); -} - -function bytes2int32s(arr){ - let res=[]; - for(let i=0;i<arr.length;i+=4){ - res.push(bytes2int32(arr.slice(i,4))); - } - return res; -} +BLAKE2S.prototype._mix=function(arr,ia,ib,ic,id,x,y){ + let a=arr[ia], b=arr[ib], c=arr[ic], d=arr[id]; + a=(a+b+x)&MASK; d=rrot(d^a,16); + c=(c+d)&MASK; b=rrot(b^c,12); + a=(a+b+y)&MASK; d=rrot(d^a,8); + c=(c+d)&MASK; b=rrot(b^c,7); + arr[ia]=a; arr[ib]=b; arr[ic]=c; arr[id]=d; +}; -function int322bytes(x){ - let res=[]; - for(let i=0;i<4;i++){ - res.push(x&0xff); - x>>>=8; - } - return res; -} - -function int32s2bytes(arr){ - return arr.map(int322bytes).reduce((acc,bytes)=>acc.concat(bytes)); +function blake2s(data,outputLen=32,key=[]){ + let h=new BLAKE2S(outputLen,key); + for(let i=0;i<data.length;i+=BLOCK_LEN){h.update(data.slice(i,i+BLOCK_LEN));} + return h.digest(); } let msg=[97,98,99]; -let data=[bytes2int32s(msg).concat(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)]; -//console.log(int32s2bytes(blake2s(data,msg.length)).map(x=>x.toString(16)).join(" ")); -console.log(int32s2bytes(blake2s(data,msg.length,outputLen=16)).map(x=>x.toString(16)).join(" ")); +console.log(bytes2hex(blake2s(msg,msg.length,0,16))=="aa4938119b1dc7b87cbad0ffd200d0ae"); +console.log(bytes2hex(blake2s(msg,msg.length,0,20))=="5ae3b99be29b01834c3b508521ede60438f8de17"); +console.log(bytes2hex(blake2s(msg,msg.length,0,28))=="0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55"); +console.log(bytes2hex(blake2s(msg,msg.length))=="508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"); diff --git a/chacha.js b/chacha.js --- a/chacha.js +++ b/chacha.js @@ -1,5 +1,3 @@ -// https://tools.ietf.org/html/rfc7693 - MASK=0xffffffff; function int2bytes(x){ diff --git a/crypto.html b/crypto.html --- a/crypto.html +++ b/crypto.html @@ -1,8 +1,8 @@ <!DOCTYPE html> <html> <head> - <!--<script type="text/javascript" src="util.js" />--> - <script type="module" src="blake.js" /> + <script type="text/javascript" src="util.js"></script> + <script type="text/javascript" src="blake.js"></script> </head> <body> <script type="text/javascript"> diff --git a/util.js b/util.js --- a/util.js +++ b/util.js @@ -1,4 +1,33 @@ -export function str2utf8(s){ +function bytes2int32(arr){ + return arr.reduce((acc,b,i)=>acc|b<<(i*8)); +} + +function bytes2int32s(arr){ + let res=[]; + for(let i=0;i<arr.length;i+=4){ + res.push(bytes2int32(arr.slice(i,i+4))); + } + return res; +} + +function int322bytes(x){ + let res=[]; + for(let i=0;i<4;i++){ + res.push(x&0xff); + x>>>=8; + } + return res; +} + +function int32s2bytes(arr){ + return arr.map(int322bytes).reduce((acc,bytes)=>acc.concat(bytes)); +} + +function bytes2hex(arr){ + return arr.map(x=>x.toString(16).padStart(2,"0")).join(""); +} + +function str2utf8(s){ let res=[]; let c=s.codePointAt(0); for(let i=0;c!==undefined;i++,c=s.codePointAt(i)){ @@ -23,7 +52,7 @@ export function str2utf8(s){ return res; } -console.log(str2utf8("$").map(x=>x.toString(16))); +/*console.log(str2utf8("$").map(x=>x.toString(16))); console.log(str2utf8("ยข").map(x=>x.toString(16))); console.log(str2utf8("โฌ").map(x=>x.toString(16))); -console.log(str2utf8("๐").map(x=>x.toString(16))); +console.log(str2utf8("๐").map(x=>x.toString(16)));*/