var sbox,isbox,rcon,mix,imix,forge=require("./forge");function registerAlgorithm(e,r){forge.cipher.registerAlgorithm(e,function(){return new forge.aes.Algorithm(e,r)})}require("./cipher"),require("./cipherModes"),require("./util"),module.exports=forge.aes=forge.aes||{},forge.aes.startEncrypting=function(e,r,i,t){var o=_createCipher({key:e,output:i,decrypt:!1,mode:t});return o.start(r),o},forge.aes.createEncryptionCipher=function(e,r){return _createCipher({key:e,output:null,decrypt:!1,mode:r})},forge.aes.startDecrypting=function(e,r,i,t){var o=_createCipher({key:e,output:i,decrypt:!0,mode:t});return o.start(r),o},forge.aes.createDecryptionCipher=function(e,r){return _createCipher({key:e,output:null,decrypt:!0,mode:r})},forge.aes.Algorithm=function(e,r){init||initialize();var i=this;i.name=e,i.mode=new r({blockSize:16,cipher:{encrypt:function(e,r){return _updateBlock(i._w,e,r,!1)},decrypt:function(e,r){return _updateBlock(i._w,e,r,!0)}}}),i._init=!1},forge.aes.Algorithm.prototype.initialize=function(e){if(!this._init){var r,i=e.key;if("string"==typeof i&&(16===i.length||24===i.length||32===i.length))i=forge.util.createBuffer(i);else if(forge.util.isArray(i)&&(16===i.length||24===i.length||32===i.length)){r=i,i=forge.util.createBuffer();for(var t=0;t<r.length;++t)i.putByte(r[t])}if(!forge.util.isArray(i)){r=i,i=[];var o=r.length();if(16===o||24===o||32===o){o>>>=2;for(var t=0;t<o;++t)i.push(r.getInt32())}}if(!forge.util.isArray(i)||4!==i.length&&6!==i.length&&8!==i.length)throw Error("Invalid key parameter.");var n=-1!==["CFB","OFB","CTR","GCM"].indexOf(this.mode.name);this._w=_expandKey(i,e.decrypt&&!n),this._init=!0}},forge.aes._expandKey=function(e,r){return init||initialize(),_expandKey(e,r)},forge.aes._updateBlock=_updateBlock,registerAlgorithm("AES-ECB",forge.cipher.modes.ecb),registerAlgorithm("AES-CBC",forge.cipher.modes.cbc),registerAlgorithm("AES-CFB",forge.cipher.modes.cfb),registerAlgorithm("AES-OFB",forge.cipher.modes.ofb),registerAlgorithm("AES-CTR",forge.cipher.modes.ctr),registerAlgorithm("AES-GCM",forge.cipher.modes.gcm);var init=!1,Nb=4;function initialize(){init=!0,rcon=[0,1,2,4,8,16,32,64,128,27,54];for(var e=Array(256),r=0;r<128;++r)e[r]=r<<1,e[r+128]=r+128<<1^283;sbox=Array(256),isbox=Array(256),mix=[,,,,],imix=[,,,,];for(var r=0;r<4;++r)mix[r]=Array(256),imix[r]=Array(256);for(var i,t,o,n,a,f,c,s=0,g=0,r=0;r<256;++r){n=(n=g^g<<1^g<<2^g<<3^g<<4)>>8^255&n^99,sbox[s]=n,isbox[n]=s,a=e[n],i=e[s],t=e[i],o=e[t],f=a<<24^n<<16^n<<8^(n^a),c=(i^t^o)<<24^(s^o)<<16^(s^t^o)<<8^(s^i^o);for(var u=0;u<4;++u)mix[u][s]=f,imix[u][n]=c,f=f<<24|f>>>8,c=c<<24|c>>>8;0===s?s=g=1:(s=i^e[e[e[i^o]]],g^=e[e[g]])}}function _expandKey(e,r){for(var i,t=e.slice(0),o=1,n=t.length,a=Nb*(n+6+1),f=n;f<a;++f)i=t[f-1],f%n==0?(i=sbox[i>>>16&255]<<24^sbox[i>>>8&255]<<16^sbox[255&i]<<8^sbox[i>>>24]^rcon[o]<<24,o++):n>6&&f%n==4&&(i=sbox[i>>>24]<<24^sbox[i>>>16&255]<<16^sbox[i>>>8&255]<<8^sbox[255&i]),t[f]=t[f-n]^i;if(r){var c,s=imix[0],g=imix[1],u=imix[2],l=imix[3],p=t.slice(0);a=t.length;for(var f=0,h=a-Nb;f<a;f+=Nb,h-=Nb)if(0===f||f===a-Nb)p[f]=t[h],p[f+1]=t[h+3],p[f+2]=t[h+2],p[f+3]=t[h+1];else for(var m=0;m<Nb;++m)c=t[h+m],p[f+(3&-m)]=s[sbox[c>>>24]]^g[sbox[c>>>16&255]]^u[sbox[c>>>8&255]]^l[sbox[255&c]];t=p}return t}function _updateBlock(e,r,i,t){var o,n,a,f,c,s,g,u,l,p,h,m,x=e.length/4-1;t?(o=imix[0],n=imix[1],a=imix[2],f=imix[3],c=isbox):(o=mix[0],n=mix[1],a=mix[2],f=mix[3],c=sbox),s=r[0]^e[0],g=r[t?3:1]^e[1],u=r[2]^e[2],l=r[t?1:3]^e[3];for(var y=3,d=1;d<x;++d)p=o[s>>>24]^n[g>>>16&255]^a[u>>>8&255]^f[255&l]^e[++y],h=o[g>>>24]^n[u>>>16&255]^a[l>>>8&255]^f[255&s]^e[++y],m=o[u>>>24]^n[l>>>16&255]^a[s>>>8&255]^f[255&g]^e[++y],l=o[l>>>24]^n[s>>>16&255]^a[g>>>8&255]^f[255&u]^e[++y],s=p,g=h,u=m;i[0]=c[s>>>24]<<24^c[g>>>16&255]<<16^c[u>>>8&255]<<8^c[255&l]^e[++y],i[t?3:1]=c[g>>>24]<<24^c[u>>>16&255]<<16^c[l>>>8&255]<<8^c[255&s]^e[++y],i[2]=c[u>>>24]<<24^c[l>>>16&255]<<16^c[s>>>8&255]<<8^c[255&g]^e[++y],i[t?1:3]=c[l>>>24]<<24^c[s>>>16&255]<<16^c[g>>>8&255]<<8^c[255&u]^e[++y]}function _createCipher(e){var r,i="AES-"+((e=e||{}).mode||"CBC").toUpperCase(),t=(r=e.decrypt?forge.cipher.createDecipher(i,e.key):forge.cipher.createCipher(i,e.key)).start;return r.start=function(e,i){var o=null;i instanceof forge.util.ByteBuffer&&(o=i,i={}),(i=i||{}).output=o,i.iv=e,t.call(r,i)},r}