diff --git a/blake.js b/blake.js --- a/blake.js +++ b/blake.js @@ -1,6 +1,5 @@ // https://tools.ietf.org/html/rfc7693 -const MASK=0xffffffff; const BLOCK_LEN=64; const IV=[0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19]; @@ -92,17 +91,19 @@ function blake2s(data,outputLen=32,key=[ return h.digest(); } -let msg=str2utf8("abc"); -let longMsg=str2utf8("0123456789.10.456789.20.456789.30.456789.40.456789.50.456789.60.456789.70.456789.80.456789.90.456789"); -let key=str2utf8("zoqpiz"); -let longKey=str2utf8("zoqpizjutyclcmkamzhhmhvchxjtefjy"); -console.log(bytes2hex(blake2s(msg,16))=="aa4938119b1dc7b87cbad0ffd200d0ae"); -console.log(bytes2hex(blake2s(msg,20))=="5ae3b99be29b01834c3b508521ede60438f8de17"); -console.log(bytes2hex(blake2s(msg,28))=="0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55"); -console.log(bytes2hex(blake2s(msg))=="508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"); -console.log(bytes2hex(blake2s(longMsg))=="59a44e5e417d07fb382505ee7e67c23e0d476d354abc81899960bcab677beee1"); -console.log(bytes2hex(blake2s(msg,32,key))=="0da0b6a54e8f294b60bb25c572700166ddb9d124257ff36f9f43f18b844adf9f"); -console.log(bytes2hex(blake2s(msg,32,longKey))=="09ef85c9942bebdeb866c6ade769220fd9b851aead642017f6d59bf7e2a32037"); -console.log(bytes2hex(blake2s([]))=="69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9"); -console.log(bytes2hex(blake2s(longMsg.slice(0,64)))=="70484f89974551454d596350dda8af2aa6f0811b527549b9ecfe7adede063753"); -console.log(bytes2hex(blake2s(longMsg.slice(0,65)))=="af14d4f74947bbde734d0e3015c667cc80676efe4349be235be8046e9e45e0ae"); +function testBlake(){ + let msg=str2utf8("abc"); + let longMsg=str2utf8("0123456789.10.456789.20.456789.30.456789.40.456789.50.456789.60.456789.70.456789.80.456789.90.456789"); + let key=str2utf8("zoqpiz"); + let longKey=str2utf8("zoqpizjutyclcmkamzhhmhvchxjtefjy"); + console.log(bytes2hex(blake2s(msg,16))=="aa4938119b1dc7b87cbad0ffd200d0ae"); + console.log(bytes2hex(blake2s(msg,20))=="5ae3b99be29b01834c3b508521ede60438f8de17"); + console.log(bytes2hex(blake2s(msg,28))=="0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55"); + console.log(bytes2hex(blake2s(msg))=="508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"); + console.log(bytes2hex(blake2s(longMsg))=="59a44e5e417d07fb382505ee7e67c23e0d476d354abc81899960bcab677beee1"); + console.log(bytes2hex(blake2s(msg,32,key))=="0da0b6a54e8f294b60bb25c572700166ddb9d124257ff36f9f43f18b844adf9f"); + console.log(bytes2hex(blake2s(msg,32,longKey))=="09ef85c9942bebdeb866c6ade769220fd9b851aead642017f6d59bf7e2a32037"); + console.log(bytes2hex(blake2s([]))=="69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9"); + console.log(bytes2hex(blake2s(longMsg.slice(0,64)))=="70484f89974551454d596350dda8af2aa6f0811b527549b9ecfe7adede063753"); + console.log(bytes2hex(blake2s(longMsg.slice(0,65)))=="af14d4f74947bbde734d0e3015c667cc80676efe4349be235be8046e9e45e0ae"); +} diff --git a/chacha.js b/chacha.js --- a/chacha.js +++ b/chacha.js @@ -1,47 +1,88 @@ -MASK=0xffffffff; - -function int2bytes(x){ - var res=new Array(4); - for(var i=0;i<4;i++){ - res[i]=x&0xff; - x>>>=8; - } - return res; -} +// https://tools.ietf.org/html/rfc7539 function lrot(x,shift){ return (x<>>(32-shift))&MASK; } -function quarterRound(arr,ia,ib,ic,id){ - var a=arr[ia], b=arr[ib], c=arr[ic], d=arr[id]; +function createNonce(){ + let nonce=new Uint8Array(12); + window.crypto.getRandomValues(nonce); + return nonce; +} + +function Chacha20(key,nonce){ + if(nonce===undefined){ + let nonce=createNonce(); + } + nonce=bytes2int32s(nonce); + key=bytes2int32s(key); + + this._state=[ + 0x61707865,0x3320646e,0x79622d32,0x6b206574, + key[0],key[1],key[2],key[3], + key[4],key[5],key[6],key[7], + 0,nonce[0],nonce[1],nonce[2] + ]; + this._buffer=[]; +} + +Chacha20.prototype.setPos=function(pos){ + this._state[12]=pos; + this._buffer=[]; +} + +Chacha20.prototype.getByte=function(){ + if(this._buffer.length==0){ + this._buffer=int32s2bytes(this._computeBlock()); + } + return this._buffer.shift(); +}; + +Chacha20.prototype._quarterRound=function(arr,ia,ib,ic,id){ + let a=arr[ia], b=arr[ib], c=arr[ic], d=arr[id]; a=(a+b)&MASK; d=lrot(d^a,16); c=(c+d)&MASK; b=lrot(b^c,12); a=(a+b)&MASK; d=lrot(d^a,8); c=(c+d)&MASK; b=lrot(b^c,7); arr[ia]=a; arr[ib]=b; arr[ic]=c; arr[id]=d; +}; + +Chacha20.prototype._computeBlock=function(){ + let state=this._state.slice(); + + for(let i=0;i<10;i++){ // 10 double rounds + // column round + this._quarterRound(state,0,4,8,12); + this._quarterRound(state,1,5,9,13); + this._quarterRound(state,2,6,10,14); + this._quarterRound(state,3,7,11,15); + // diagonal round + this._quarterRound(state,0,5,10,15); + this._quarterRound(state,1,6,11,12); + this._quarterRound(state,2,7,8,13); + this._quarterRound(state,3,4,9,14); + } + + return state.map((xi,i)=>(xi+this._state[i])&MASK); +}; + +Chacha20.prototype._incrementPos=function(){ + this._state[12]=(this._state[12]+1)&MASK; +}; + +function encrypt(message,key){ + let nonce=Date.now(); + let nonce0=nonce; + let hashedKey=blake2s(str2bytes(key)); + message=str2bytes(message); } -function chacha(key,nonce,position){ - var x=input.slice(); - - for(var i=0;i<10;i++){ - // column round - quarterRound(x,0,4,8,12); - quarterRound(x,1,5,9,13); - quarterRound(x,2,6,10,14); - quarterRound(x,3,7,11,15); - // diagonal round - quarterRound(x,0,5,10,15); - quarterRound(x,1,6,11,12); - quarterRound(x,2,7,8,13); - quarterRound(x,3,4,9,14); - } - - return x.map((xi,i)=>(xi+input[i])&MASK); +function testChacha(){ + let key=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]; + let nonce=[0,0,0,9,0,0,0,74,0,0,0,0]; + let cipher=new Chacha20(key,nonce); + cipher.setPos(1); + let output=cipher._computeBlock().map(x=>(x>>>0).toString(16).padStart(8,"0")); + let example=["e4e7f110","15593bd1","1fdd0f50","c47120a3","c7f4d1c7","0368c033","9aaa2204","4e6cd4c3","466482d2","09aa9f07","05d7c214","a2028bd9","d19c12b5","b94e16de","e883d0cb","4e3c50a2"]; + console.log(output.every((x,i)=>x==example[i])); } - -function encrypt(message,key){ - var nonce=Date.now(); - var nonce0=nonce; -} diff --git a/util.js b/util.js --- a/util.js +++ b/util.js @@ -1,3 +1,5 @@ +const MASK=0xffffffff; + function bytes2int32(arr){ return arr.reduce((acc,b,i)=>acc|b<<(i*8)); }