1 /** 2 * @namespace AES-256 encryption and associated modes 3 * @author Anonymized 4 * @description 5 * <p>Implementation of AES on 256 bit keys.</p> 6 * @requires encoding 7 */ 8 var aes = 9 { 10 Stables: (function() 11 { 12 var a256 = function() 13 { 14 return [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 15 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 17 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 18 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 19 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 20 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 21 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 22 }, 23 24 t5 = function(){return [a256(), a256(), a256(), a256(), a256()]}, 25 encTable = t5(), decTable = t5(), 26 sbox = encTable[4], sboxInv = decTable[4], 27 i = 0, x = 0, xInv = 0, x2 = 0, x4 = 0, x8 = 0, 28 tEnc = 0, tDec = 0, s = 0, d = a256(), th = a256(); 29 30 for(i=0; i < 256; i++) 31 th[((d[i & 255] = i<<1 ^ (i>>7)*283)^i) & 255] = i; 32 33 for(x=xInv=0; !sbox[x&255]; x^=(!x2?1:x2), xInv=th[xInv&255], xInv=(!xInv?1:xInv)) 34 { 35 s = xInv ^ xInv<<1 ^ xInv<<2 ^ xInv<<3 ^ xInv<<4; 36 s = s>>8 ^ s&255 ^ 99; 37 sbox[x&255] = s; sboxInv[s&255] = x; 38 39 x8 = d[(x4 = d[(x2 = d[x&255])&255])&255]; 40 tDec = x8*0x1010101 ^ x4*0x10001 ^ x2*0x101 ^ x*0x1010100; 41 tEnc = d[s&255]*0x101 ^ s*0x1010100; 42 43 for (i=0; i<4; i++) 44 { 45 encTable[i&3][x&255] = tEnc = tEnc<<24 ^ tEnc>>>8; 46 decTable[i&3][s&255] = tDec = tDec<<24 ^ tDec>>>8; 47 } 48 } 49 50 return [encTable, decTable]; 51 })(), 52 53 key: (function() 54 { 55 var a = function(){ return [ 56 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 57 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 58 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 59 ]}; 60 return [a(),a()]; 61 })(), 62 63 /** Set the key to use for encryption and decryption. 64 * @param {string} key ASCII key (32 bytes long) 65 */ 66 setKey: function(key) 67 { 68 var pad = function(s){var s=s+'';while(s.length<64) s+="0"; return s}, 69 key = this._blockGen(pad(key),true), i = 0, j = 0, 70 k = [0,0,0,0,0,0,0,0], block = [0,0,0,0]; 71 72 for(i=0; i<2; i++) 73 { 74 block = key.gen(); 75 for(j=0; j<4; j++) k[(4*i+j)&7] = block[j&3]; 76 } 77 78 this._setKey(k); 79 }, 80 81 _setKey: function(key) 82 { 83 var i = 0, j = 0, rcon = 1, tmp = 0, 84 encKey = this.key[0], 85 decKey = this.key[1], 86 decTable = this.Stables[1], 87 sbox = this.Stables[0][4]; 88 89 for(i = 0; i < 60; i++) 90 { 91 if(i < 8) 92 { 93 encKey[i & 63] = key[i & 7]; 94 continue; 95 } 96 97 tmp = encKey[(i-1) & 63]; 98 if(!(i%4)) 99 { 100 tmp = sbox[tmp>>>24 & 255]<<24 101 ^ sbox[tmp>>16 & 255]<<16 102 ^ sbox[tmp>>8 & 255]<<8 103 ^ sbox[tmp & 255]; 104 105 if(!(i%8)) 106 { 107 tmp = tmp<<8 ^ tmp>>>24 ^ rcon<<24; 108 rcon = rcon<<1 ^ (rcon>>7)*283; 109 } 110 } 111 112 encKey[i & 63] = encKey[(i-8) & 63] ^ tmp; 113 } 114 115 for(j = 0; i>0; j++, i--) 116 { 117 tmp = encKey[(!(j&3) ? i-4 : i)&63]; 118 119 decKey[j & 63] = 120 (i<=4 || j<4) ? tmp : 121 decTable[0][sbox[tmp>>>24 & 255] & 255] ^ 122 decTable[1][sbox[tmp>>16 & 255] & 255] ^ 123 decTable[2][sbox[tmp>>8 & 255] & 255] ^ 124 decTable[3][sbox[tmp & 255] & 255]; 125 } 126 }, 127 128 /** Internal AES block function. 129 * @param {number array[4]} input array of four 32-bit words to process 130 * @param {boolean} dir false for encryption, true for decryption 131 * @returns {number array[8]} result of the encryption 132 */ 133 _aes: function(input, dir) 134 { 135 var key = this.key[(!dir ? 0 : 1) & 1], 136 a = input[0] ^ key[0], 137 b = input[(!dir ? 1 : 3) & 3] ^ key[1], 138 c = input[2] ^ key[2], 139 d = input[(!dir ? 3 : 1) & 3] ^ key[3], 140 a2 = 0, b2 = 0, c2 = 0, i = 0, kIndex = 4, 141 out = [0, 0, 0, 0], 142 table = this.Stables[(!dir ? 0 : 1 ) & 1], 143 t0 = table[0], t1 = table[1], t2 = table[2], 144 t3 = table[3], sbox = table[4]; 145 146 for(i = 0; i < 13; i++) 147 { 148 a2 = t0[a>>>24 & 255] ^ t1[b>>16 & 255] ^ t2[c>>8 & 255] ^ t3[d & 255] ^ key[kIndex & 63]; 149 b2 = t0[b>>>24 & 255] ^ t1[c>>16 & 255] ^ t2[d>>8 & 255] ^ t3[a & 255] ^ key[(kIndex + 1) & 63]; 150 c2 = t0[c>>>24 & 255] ^ t1[d>>16 & 255] ^ t2[a>>8 & 255] ^ t3[b & 255] ^ key[(kIndex + 2) & 63]; 151 d = t0[d>>>24 & 255] ^ t1[a>>16 & 255] ^ t2[b>>8 & 255] ^ t3[c & 255] ^ key[(kIndex + 3) & 63]; 152 kIndex += 4; a = a2; b = b2; c = c2; 153 } 154 155 for(i = 0; i < 4; i++) 156 { 157 out[(!dir ? i : (3&-i)) & 3] = 158 sbox[a>>>24 & 255]<<24 ^ 159 sbox[b>>16 & 255]<<16 ^ 160 sbox[c>>8 & 255]<<8 ^ 161 sbox[d & 255] ^ 162 key[kIndex++ & 63]; 163 a2=a; a=b; b=c; c=d; d=a2; 164 } 165 166 return out; 167 }, 168 169 /** Block generator function, with PKCS#5 support for padding. 170 * @private 171 * @param {string} s input string to process in blocks 172 * @param {boolean} dir false for encryption, true for decryption (no padding) 173 * @returns {blocks:number,gen:()->number array[4]} A record containing the number of blocks and the block generating function 174 */ 175 _blockGen: function(s, dir) 176 { 177 var s = s+'', len = s.length, block = 0, i = 0, e = len&15, 178 blocks = (dir?0:1)+(!e?0:1)+(len>>4), pad = (blocks<<4)-len, 179 180 gen = function() 181 { 182 var res = [0,0,0,0], i = 0, j = 0, 183 m = 0, base = block++ << 4, tmp = 0; 184 185 for(i = 0; i < 4; i++) 186 { 187 for(tmp = 0, j = base+4*i, m = j+4; j < m; j++) 188 tmp = (tmp<<8)+encoding.a2b(s[(j>>>0)%s.length]); 189 res[i&3] = tmp; 190 } 191 return res; 192 }; 193 194 if(!dir) for(i=0; i<pad; i++) s += encoding.b2a(pad); 195 else while(!!(e++%16)) s += "\x00"; 196 197 return {blocks: blocks, gen: gen}; 198 }, 199 200 /** Output processing. By default, returns an ASCII string. 201 * @private 202 * @param {number array[4]} block internal block to output 203 * @param {boolean} last true if this is the last block, false otherwise 204 * @returns {string} ASCII string representing the input block. Will unpad if this is the last block. 205 */ 206 _output: function(block, last) 207 { 208 var res = "", i = 0, j = 0, c = 0, pad = 16; 209 210 if(last) pad -= 1+block[3]&255; 211 212 for(i=0; i < 4; i++) 213 for(c = block[i&3], j=0; j<4 && res.length <= pad; j++) 214 res += encoding.b2a(c >> (24-8*j)); 215 216 return res; 217 }, 218 219 _xor4: function(x,y) 220 { 221 return [x[0]^y[0], x[1]^y[1], x[2]^y[2], x[3]^y[3]]; 222 }, 223 224 /** CBC mode encryption and decryption using AES. 225 * @param {string} s input plaintext or ciphertext (ASCII string) 226 * @param {string} iv initial vector of the encryption, a 16 bytes ASCII string 227 * @param {boolean} dir false for encryption, true for encryption 228 * @returns {string} result as an ASCII string 229 */ 230 CBC: function(s, iv, dir) 231 { 232 var i = 0, res = "", last = false, 233 input = this._blockGen(s, dir), 234 iv = this._blockGen(iv, true).gen(), 235 block = [0,0,0,0], 236 xor = this._xor4; 237 238 for(i=0; i<input.blocks; i++) 239 { 240 block = input.gen(); 241 242 if(!dir) 243 { 244 iv = this._aes(xor(iv,block), false); 245 res += this._output(iv, false); 246 } 247 else 248 { 249 res += this._output(xor(iv, this._aes(block,true)), i+1 == input.blocks); 250 iv = block; 251 } 252 } 253 254 return res; 255 }, 256 257 /** Authenticated encryption in CCM mode (provides ciphertext integrity). 258 * @param {string} s input plaintext (ASCII string) 259 * @param {string} iv Random initialization vector, 16 byte ASCII string 260 * @param {string} adata Optional authentication data (not secret but integrity protected) 261 * @param {number} tlen tag length in bytes (2 to 16) - high values make it harder to tamper with the ciphertext 262 * @return {string} the encrypted data, an ASCII string 263 */ 264 CCM_encrypt: function(s, iv2, adata, tlen) 265 { 266 var tlen = (tlen<4 || tlen>16 || !!(tlen&1)) ? 8 : tlen, 267 s=s+'', sl=s.length, ol=sl>>3, L=0, i=0, iv = '', 268 tag = '', res = {data:'', tag:''}; 269 270 for(L=2; L<4 && !!(ol>>>8*L); L++); 271 for(iv2+='';iv2.length < 16; iv2+="\x00"); 272 for(i=0; i<iv2.length; i++){ iv += iv2[i]; if(i>13-L) break } 273 274 tag = this._ccmTag(s, iv, adata, tlen, L); 275 res = this._ctrMode(s, iv, tag, tlen, L); 276 277 return res.data + res.tag; 278 }, 279 280 /** Decryption in CCM mode. 281 * @param {string} s input ciphertext 282 * @param {string} iv random initialization vector (ASCII string) 283 * @param {string} adata Optional authenticated data (ASCII) 284 * @param {number} tlen tag length in bytes 285 * @return {valid:bolean,data:string} Object containing the decrypted data and authentication status 286 */ 287 CCM_decrypt: function(s, iv2, adata, tlen) 288 { 289 var tlen = (tlen<4 || tlen>16 || !!(tlen&1)) ? 8 : tlen, 290 s=s+'', sl=s.length, c = '', ol=(sl-tlen)>>3, L=0, 291 i=0, res = {data:'',tag:''}, tag = '', iv = ''; 292 293 for(i=0; i<s.length; i++) 294 { 295 if(i < sl-tlen) c += s[i]; 296 else tag += s[i]; 297 } 298 299 for(L=2; L<4 && !!(ol>>>8*L); L++); 300 for(iv2+='';iv2.length < 16; iv2+="\x00"); 301 for(i=0; i<iv2.length; i++){ iv += iv2[i]; if(i>13-L) break } 302 303 res = this._ctrMode(c, iv, tag, tlen, L); 304 s = this._ccmTag(res.data, iv, adata, tlen, L); 305 306 return {valid: s==res.tag, data: res.data}; 307 }, 308 309 _ccmTag: function(s, iv, adata, tlen, L) 310 { 311 var i=0, s=s+'', sl=s.length, xor = this._xor4, c = [0,0,0,0], 312 ad = (function(x){var x=x+'', n=x.length, c=function(n){ 313 return encoding.b2a(n)}; if(!n) return x; if(n<=0xFEFF) 314 return c(n>>16)+c(n&255)+x; return "\xff\xfe"+c(n>>>24)+ 315 c(n>>16&255)+c(n>>8&255)+c(n&255)+x})(adata), res = '', T = '', 316 p = this._blockGen(s, true), q = this._blockGen(ad, true); 317 318 mac = encoding.b2a(((adata==''?0:1)<<6) | (((tlen-2)>>1)<<3) | (L-1))+iv; 319 for(i=15-mac.length; i>=0; i--) mac += encoding.b2a(i>3?0:sl>>>8*i); 320 c = this._aes(this._blockGen(mac,true).gen(), false); 321 322 if(!!ad) // Additional data 323 for(i=0; i<q.blocks; i++) c = this._aes(xor(c, q.gen()), false); 324 for(i=0; i<p.blocks; i++) c = this._aes(xor(c, p.gen()), false); 325 326 T = this._output(c, false); 327 for(i=0; i<T.length; i++) 328 { 329 res += T[i]; 330 if(i+1 == tlen) break; 331 } 332 333 return res; 334 }, 335 336 _ctrMode: function(s, iv, tag, tlen, L) 337 { 338 var ctr = this._blockGen(encoding.b2a(L-1)+iv, true).gen(), tag0=tag, 339 xor = this._xor4, res = "", D = this._blockGen(s, true), sl=s.length, 340 tag = xor(this._blockGen(tag, true).gen(), this._aes(ctr, false)), 341 ts = '', i = 0, c = "", j = 0; 342 343 c = this._output(tag, false); 344 for(i=0; i<c.length; i++){ ts+=c[i]; if(i+1==tlen) break; } 345 346 for (i=0; i<D.blocks; i++) 347 { 348 ctr[3]++; 349 c = this._output(xor(D.gen(), this._aes(ctr, false)), false); 350 for(j=0; j<c.length; j++) 351 { 352 res += c[j]; 353 if(res.length == sl) break; 354 } 355 } 356 357 return {tag:ts, data:res}; 358 } 359 }; 360 361