/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

/*
 * Implementation of the AES-GCM Encryption/Authentication
 *
 * Some restrictions..
 * 1. Only for use with AES
 * 2. Returned tag is always 128-bits. Truncate at your own risk.
 * 3. The order of function calls must follow some rules
 *
 * Typical sequence of calls..
 * 1. call GCM_init
 * 2. call GCM_add_header any number of times, as long as length of header is multiple of 16 bytes (block size)
 * 3. call GCM_add_header one last time with any length of header
 * 4. call GCM_add_cipher any number of times, as long as length of cipher/plaintext is multiple of 16 bytes
 * 5. call GCM_add_cipher one last time with any length of cipher/plaintext
 * 6. call GCM_finish to extract the tag.
 *
 * See http://www.mindspring.com/~dmcgrew/gcm-nist-6.pdf
 */

var GCM = function() {
	this.table=new Array(128);
	for (var i=0;i<128;i++)
		this.table[i]=new Array(4);  /* 2k bytes */
	this.stateX=[];
	this.Y_0=[];
	this.counter=0;
	this.lenA=[];
	this.lenC=[];
	this.status=0;
	this.a=new AES();
};

GCM.prototype={

	precompute: function(H)
	{
		var i,j,c;
		var b=[];

		for (i=j=0;i<4;i++,j+=4)
		{
			b[0]=H[j]; b[1]=H[j+1]; b[2]=H[j+2]; b[3]=H[j+3];
			this.table[0][i]=GCM.pack(b);
		}
		for (i=1;i<128;i++)
		{
			c=0;
			for (j=0;j<4;j++)
			{
				this.table[i][j]=c|(this.table[i-1][j])>>>1;
				c=this.table[i-1][j]<<31;
			}
			if (c!==0) this.table[i][0]^=0xE1000000; /* irreducible polynomial */
		}
	},

	gf2mul: function()
	{ /* gf2m mul - Z=H*X mod 2^128 */
		var i,j,m,k;
		var P=[];
		var c;
		var b=[];

		P[0]=P[1]=P[2]=P[3]=0;
		j=8; m=0;
		for (i=0;i<128;i++)
		{
			c=(this.stateX[m]>>>(--j))&1;
			if (c!==0) for (k=0;k<4;k++) P[k]^=this.table[i][k];
			if (j===0)
			{
				j=8; m++;
				if (m==16) break;
			}
		}
		for (i=j=0;i<4;i++,j+=4)
		{
			b=GCM.unpack(P[i]);
			this.stateX[j]=b[0]; this.stateX[j+1]=b[1]; this.stateX[j+2]=b[2]; this.stateX[j+3]=b[3];
		}
	},

	wrap: function()
	{ /* Finish off GHASH */
		var i,j;
		var F=[];
		var L=[];
		var b=[];

/* convert lengths from bytes to bits */
		F[0]=(this.lenA[0]<<3)|(this.lenA[1]&0xE0000000)>>>29;
		F[1]=this.lenA[1]<<3;
		F[2]=(this.lenC[0]<<3)|(this.lenC[1]&0xE0000000)>>>29;
		F[3]=this.lenC[1]<<3;
		for (i=j=0;i<4;i++,j+=4)
		{
			b=GCM.unpack(F[i]);
			L[j]=b[0]; L[j+1]=b[1]; L[j+2]=b[2]; L[j+3]=b[3];
		}
		for (i=0;i<16;i++) this.stateX[i]^=L[i];
		this.gf2mul();
	},

/* Initialize GCM mode */
	init: function(key,niv,iv)
	{ /* iv size niv is usually 12 bytes (96 bits). AES key size nk can be 16,24 or 32 bytes */
		var i;
		var H=[];
		var b=[];

		for (i=0;i<16;i++) {H[i]=0; this.stateX[i]=0;}

		this.a.init(ROM.ECB,key,iv);
		this.a.ecb_encrypt(H);     /* E(K,0) */
		this.precompute(H);

		this.lenA[0]=this.lenC[0]=this.lenA[1]=this.lenC[1]=0;
		if (niv==12)
		{
			for (i=0;i<12;i++) this.a.f[i]=iv[i];
			b=GCM.unpack(1);
			this.a.f[12]=b[0]; this.a.f[13]=b[1]; this.a.f[14]=b[2]; this.a.f[15]=b[3];  /* initialise IV */
			for (i=0;i<16;i++) this.Y_0[i]=this.a.f[i];
		}
		else
		{
			this.status=ROM.GCM_ACCEPTING_CIPHER;
			this.ghash(iv,niv); /* GHASH(H,0,IV) */
			this.wrap();
			for (i=0;i<16;i++) {this.a.f[i]=this.stateX[i];this.Y_0[i]=this.a.f[i];this.stateX[i]=0;}
			this.lenA[0]=this.lenC[0]=this.lenA[1]=this.lenC[1]=0;
		}
		this.status=ROM.GCM_ACCEPTING_HEADER;
	},

/* Add Header data - included but not encrypted */
	add_header: function(header,len)
	{ /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */
		var i,j=0;
		if (this.status!=ROM.GCM_ACCEPTING_HEADER) return false;

		while (j<len)
		{
			for (i=0;i<16 && j<len;i++)
			{
				this.stateX[i]^=header[j++];
				this.lenA[1]++; this.lenA[1]|=0; if (this.lenA[1]===0) this.lenA[0]++;
			}
			this.gf2mul();
		}
		if (len%16!==0) this.status=ROM.GCM_ACCEPTING_CIPHER;
		return true;
	},

	ghash: function(plain,len)
	{
		var i,j=0;

		if (this.status==ROM.GCM_ACCEPTING_HEADER) this.status=ROM.GCM_ACCEPTING_CIPHER;
		if (this.status!=ROM.GCM_ACCEPTING_CIPHER) return false;

		while (j<len)
		{
			for (i=0;i<16 && j<len;i++)
			{
				this.stateX[i]^=plain[j++];
				this.lenC[1]++; this.lenC[1]|=0; if (this.lenC[1]===0) this.lenC[0]++;
			}
			this.gf2mul();
		}
		if (len%16!==0) this.status=ROM.GCM_NOT_ACCEPTING_MORE;
		return true;
	},

/* Add Plaintext - included and encrypted */
	add_plain: function(plain,len)
	{
		var i,j=0;
		var B=[];
		var b=[];
		var cipher=[];

		if (this.status==ROM.GCM_ACCEPTING_HEADER) this.status=ROM.GCM_ACCEPTING_CIPHER;
		if (this.status!=ROM.GCM_ACCEPTING_CIPHER) return cipher;

		while (j<len)
		{

			b[0]=this.a.f[12]; b[1]=this.a.f[13]; b[2]=this.a.f[14]; b[3]=this.a.f[15];
			this.counter=GCM.pack(b);
			this.counter++;
			b=GCM.unpack(this.counter);
			this.a.f[12]=b[0]; this.a.f[13]=b[1]; this.a.f[14]=b[2]; this.a.f[15]=b[3]; /* increment counter */
			for (i=0;i<16;i++) B[i]=this.a.f[i];
			this.a.ecb_encrypt(B);        /* encrypt it  */

			for (i=0;i<16 && j<len;i++)
			{
				cipher[j]=(plain[j]^B[i]);
				this.stateX[i]^=cipher[j++];
				this.lenC[1]++; this.lenC[1]|=0; if (this.lenC[1]===0) this.lenC[0]++;
			}
			this.gf2mul();
		}
		if (len%16!==0) this.status=ROM.GCM_NOT_ACCEPTING_MORE;
		return cipher;
	},

/* Add Ciphertext - decrypts to plaintext */
	add_cipher: function(cipher,len)
	{
		var i,j=0;
		var B=[];
		var b=[];
		var plain=[];

		if (this.status==ROM.GCM_ACCEPTING_HEADER) this.status=ROM.GCM_ACCEPTING_CIPHER;
		if (this.status!=ROM.GCM_ACCEPTING_CIPHER) return plain;

		while (j<len)
		{
			b[0]=this.a.f[12]; b[1]=this.a.f[13]; b[2]=this.a.f[14]; b[3]=this.a.f[15];
			this.counter=GCM.pack(b);
			this.counter++;
			b=GCM.unpack(this.counter);
			this.a.f[12]=b[0]; this.a.f[13]=b[1]; this.a.f[14]=b[2]; this.a.f[15]=b[3]; /* increment counter */
			for (i=0;i<16;i++) B[i]=this.a.f[i];
			this.a.ecb_encrypt(B);        /* encrypt it  */
			for (i=0;i<16 && j<len;i++)
			{
				plain[j]=(cipher[j]^B[i]);
				this.stateX[i]^=cipher[j++];
				this.lenC[1]++; this.lenC[1]|=0; if (this.lenC[1]===0) this.lenC[0]++;
			}
			this.gf2mul();
		}
		if (len%16!==0) this.status=ROM.GCM_NOT_ACCEPTING_MORE;
		return plain;
	},

/* Finish and extract Tag */
	finish: function(extract)
	{ /* Finish off GHASH and extract tag (MAC) */
		var i;
		var tag=[];

		this.wrap();
/* extract tag */
		if (extract)
		{
			this.a.ecb_encrypt(this.Y_0);        /* E(K,Y0) */
			for (i=0;i<16;i++) this.Y_0[i]^=this.stateX[i];
			for (i=0;i<16;i++) {tag[i]=this.Y_0[i];this.Y_0[i]=this.stateX[i]=0;}
		}
		this.status=ROM.GCM_FINISHED;
		this.a.end();
		return tag;
	}

};

GCM.pack= function(b)
{ /* pack 4 bytes into a 32-bit Word */
		return (((b[0])&0xff)<<24)|((b[1]&0xff)<<16)|((b[2]&0xff)<<8)|(b[3]&0xff);
};

GCM.unpack=function(a)
{ /* unpack bytes from a word */
	var b=[];
	b[3]=(a&0xff);
	b[2]=((a>>>8)&0xff);
	b[1]=((a>>>16)&0xff);
	b[0]=((a>>>24)&0xff);
	return b;
};

GCM.hex2bytes=function(s)
{
	var len = s.length;
	var data = [];
	for (var i = 0; i < len; i += 2)
		data[i / 2] = parseInt(s.substr(i,2),16);

	return data;
};
