Files @ bcd08758ec7c
Branch filter:

Location: CryptoJS/src/chacha.js

Laman
testing blake
// https://tools.ietf.org/html/rfc7539

function lrot(x,shift){
	return (x<<shift|x>>>(32-shift))&MASK;
}

function createNonce(){
	let nonce=new Uint8Array(12);
	window.crypto.getRandomValues(nonce);
	return nonce;
}

export 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 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]));
}