Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3 /*
4 * AES Cipher function: encrypt 'input' with Rijndael algorithm
5 *
6 * takes byte-array 'input' (16 bytes)
7 * 2D byte-array key schedule 'w' (Nr+1 x Nb bytes)
8 *
9 * applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage
10 *
11 * returns byte-array encrypted value (16 bytes)
12 */
13 function Cipher(input, w) { // main Cipher function [§5.1]
14 var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
15 var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
17 var state = [[],[],[],[]]; // initialise 4xNb byte-array 'state' with input [§3.4]
18 for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i];
20 state = AddRoundKey(state, w, 0, Nb);
22 for (var round=1; round<Nr; round++) {
23 state = SubBytes(state, Nb);
24 state = ShiftRows(state, Nb);
25 state = MixColumns(state, Nb);
26 state = AddRoundKey(state, w, round, Nb);
27 }
29 state = SubBytes(state, Nb);
30 state = ShiftRows(state, Nb);
31 state = AddRoundKey(state, w, Nr, Nb);
33 var output = new Array(4*Nb); // convert state to 1-d array before returning [§3.4]
34 for (var i=0; i<4*Nb; i++) output[i] = state[i%4][Math.floor(i/4)];
35 return output;
36 }
39 function SubBytes(s, Nb) { // apply SBox to state S [§5.1.1]
40 for (var r=0; r<4; r++) {
41 for (var c=0; c<Nb; c++) s[r][c] = Sbox[s[r][c]];
42 }
43 return s;
44 }
47 function ShiftRows(s, Nb) { // shift row r of state S left by r bytes [§5.1.2]
48 var t = new Array(4);
49 for (var r=1; r<4; r++) {
50 for (var c=0; c<4; c++) t[c] = s[r][(c+r)%Nb]; // shift into temp copy
51 for (var c=0; c<4; c++) s[r][c] = t[c]; // and copy back
52 } // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
53 return s; // see fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
54 }
57 function MixColumns(s, Nb) { // combine bytes of each col of state S [§5.1.3]
58 for (var c=0; c<4; c++) {
59 var a = new Array(4); // 'a' is a copy of the current column from 's'
60 var b = new Array(4); // 'b' is a•{02} in GF(2^8)
61 for (var i=0; i<4; i++) {
62 a[i] = s[i][c];
63 b[i] = s[i][c]&0x80 ? s[i][c]<<1 ^ 0x011b : s[i][c]<<1;
64 }
65 // a[n] ^ b[n] is a•{03} in GF(2^8)
66 s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3
67 s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3
68 s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3
69 s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3
70 }
71 return s;
72 }
75 function AddRoundKey(state, w, rnd, Nb) { // xor Round Key into state S [§5.1.4]
76 for (var r=0; r<4; r++) {
77 for (var c=0; c<Nb; c++) state[r][c] ^= w[rnd*4+c][r];
78 }
79 return state;
80 }
83 function KeyExpansion(key) { // generate Key Schedule (byte-array Nr+1 x Nb) from Key [§5.2]
84 var Nb = 4; // block size (in words): no of columns in state (fixed at 4 for AES)
85 var Nk = key.length/4 // key length (in words): 4/6/8 for 128/192/256-bit keys
86 var Nr = Nk + 6; // no of rounds: 10/12/14 for 128/192/256-bit keys
88 var w = new Array(Nb*(Nr+1));
89 var temp = new Array(4);
91 for (var i=0; i<Nk; i++) {
92 var r = [key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]];
93 w[i] = r;
94 }
96 for (var i=Nk; i<(Nb*(Nr+1)); i++) {
97 w[i] = new Array(4);
98 for (var t=0; t<4; t++) temp[t] = w[i-1][t];
99 if (i % Nk == 0) {
100 temp = SubWord(RotWord(temp));
101 for (var t=0; t<4; t++) temp[t] ^= Rcon[i/Nk][t];
102 } else if (Nk > 6 && i%Nk == 4) {
103 temp = SubWord(temp);
104 }
105 for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t];
106 }
108 return w;
109 }
111 function SubWord(w) { // apply SBox to 4-byte word w
112 for (var i=0; i<4; i++) w[i] = Sbox[w[i]];
113 return w;
114 }
116 function RotWord(w) { // rotate 4-byte word w left by one byte
117 w[4] = w[0];
118 for (var i=0; i<4; i++) w[i] = w[i+1];
119 return w;
120 }
123 // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [§5.1.1]
124 var Sbox = [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
125 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
126 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
127 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
128 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
129 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
130 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
131 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
132 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
133 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
134 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
135 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
136 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
137 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
138 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
139 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
141 // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [§5.2]
142 var Rcon = [ [0x00, 0x00, 0x00, 0x00],
143 [0x01, 0x00, 0x00, 0x00],
144 [0x02, 0x00, 0x00, 0x00],
145 [0x04, 0x00, 0x00, 0x00],
146 [0x08, 0x00, 0x00, 0x00],
147 [0x10, 0x00, 0x00, 0x00],
148 [0x20, 0x00, 0x00, 0x00],
149 [0x40, 0x00, 0x00, 0x00],
150 [0x80, 0x00, 0x00, 0x00],
151 [0x1b, 0x00, 0x00, 0x00],
152 [0x36, 0x00, 0x00, 0x00] ];
155 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
157 /*
158 * Use AES to encrypt 'plaintext' with 'password' using 'nBits' key, in 'Counter' mode of operation
159 * - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
160 * for each block
161 * - outputblock = cipher(counter, key)
162 * - cipherblock = plaintext xor outputblock
163 */
164 function AESEncryptCtr(plaintext, password, nBits) {
165 if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
167 // for this example script, generate the key by applying Cipher to 1st 16/24/32 chars of password;
168 // for real-world applications, a more secure approach would be to hash the password e.g. with SHA-1
169 var nBytes = nBits/8; // no bytes in key
170 var pwBytes = new Array(nBytes);
171 for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
172 var key = Cipher(pwBytes, KeyExpansion(pwBytes));
173 key = key.concat(key.slice(0, nBytes-16)); // key is now 16/24/32 bytes long
175 // initialise counter block (NIST SP800-38A §B.2): millisecond time-stamp for nonce in 1st 8 bytes,
176 // block counter in 2nd 8 bytes
177 var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
178 var counterBlock = new Array(blockSize); // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
179 var nonce = (new Date("2000-01-01")).getTime(); // milliseconds since 1-Jan-1970;
180 // fixed for repeatability
182 // encode nonce in two stages to cater for JavaScript 32-bit limit on bitwise ops
183 for (var i=0; i<4; i++) counterBlock[i] = (nonce >>> i*8) & 0xff;
184 for (var i=0; i<4; i++) counterBlock[i+4] = (nonce/0x100000000 >>> i*8) & 0xff;
186 // generate key schedule - an expansion of the key into distinct Key Rounds for each round
187 var keySchedule = KeyExpansion(key);
189 var blockCount = Math.ceil(plaintext.length/blockSize);
190 var ciphertext = new Array(blockCount); // ciphertext as array of strings
192 for (var b=0; b<blockCount; b++) {
193 // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
194 // again done in two stages for 32-bit ops
195 for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff;
196 for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8)
198 var cipherCntr = Cipher(counterBlock, keySchedule); // -- encrypt counter block --
200 // calculate length of final block:
201 var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1;
203 var ct = '';
204 for (var i=0; i<blockLength; i++) { // -- xor plaintext with ciphered counter byte-by-byte --
205 var plaintextByte = plaintext.charCodeAt(b*blockSize+i);
206 var cipherByte = plaintextByte ^ cipherCntr[i];
207 ct += String.fromCharCode(cipherByte);
208 }
209 // ct is now ciphertext for this block
211 ciphertext[b] = escCtrlChars(ct); // escape troublesome characters in ciphertext
212 }
214 // convert the nonce to a string to go on the front of the ciphertext
215 var ctrTxt = '';
216 for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]);
217 ctrTxt = escCtrlChars(ctrTxt);
219 // use '-' to separate blocks, use Array.join to concatenate arrays of strings for efficiency
220 return ctrTxt + '-' + ciphertext.join('-');
221 }
224 /*
225 * Use AES to decrypt 'ciphertext' with 'password' using 'nBits' key, in Counter mode of operation
226 *
227 * for each block
228 * - outputblock = cipher(counter, key)
229 * - cipherblock = plaintext xor outputblock
230 */
231 function AESDecryptCtr(ciphertext, password, nBits) {
232 if (!(nBits==128 || nBits==192 || nBits==256)) return ''; // standard allows 128/192/256 bit keys
234 var nBytes = nBits/8; // no bytes in key
235 var pwBytes = new Array(nBytes);
236 for (var i=0; i<nBytes; i++) pwBytes[i] = password.charCodeAt(i) & 0xff;
237 var pwKeySchedule = KeyExpansion(pwBytes);
238 var key = Cipher(pwBytes, pwKeySchedule);
239 key = key.concat(key.slice(0, nBytes-16)); // key is now 16/24/32 bytes long
241 var keySchedule = KeyExpansion(key);
243 ciphertext = ciphertext.split('-'); // split ciphertext into array of block-length strings
245 // recover nonce from 1st element of ciphertext
246 var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
247 var counterBlock = new Array(blockSize);
248 var ctrTxt = unescCtrlChars(ciphertext[0]);
249 for (var i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i);
251 var plaintext = new Array(ciphertext.length-1);
253 for (var b=1; b<ciphertext.length; b++) {
254 // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
255 for (var c=0; c<4; c++) counterBlock[15-c] = ((b-1) >>> c*8) & 0xff;
256 for (var c=0; c<4; c++) counterBlock[15-c-4] = ((b/0x100000000-1) >>> c*8) & 0xff;
258 var cipherCntr = Cipher(counterBlock, keySchedule); // encrypt counter block
260 ciphertext[b] = unescCtrlChars(ciphertext[b]);
262 var pt = '';
263 for (var i=0; i<ciphertext[b].length; i++) {
264 // -- xor plaintext with ciphered counter byte-by-byte --
265 var ciphertextByte = ciphertext[b].charCodeAt(i);
266 var plaintextByte = ciphertextByte ^ cipherCntr[i];
267 pt += String.fromCharCode(plaintextByte);
268 }
269 // pt is now plaintext for this block
271 plaintext[b-1] = pt; // b-1 'cos no initial nonce block in plaintext
272 }
274 return plaintext.join('');
275 }
277 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
279 function escCtrlChars(str) { // escape control chars which might cause problems handling ciphertext
280 return str.replace(/[\0\t\n\v\f\r\xa0'"!-]/g, function(c) { return '!' + c.charCodeAt(0) + '!'; });
281 } // \xa0 to cater for bug in Firefox; include '-' to leave it free for use as a block marker
283 function unescCtrlChars(str) { // unescape potentially problematic control characters
284 return str.replace(/!\d\d?\d?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });
285 }
286 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
288 /*
289 * if escCtrlChars()/unescCtrlChars() still gives problems, use encodeBase64()/decodeBase64() instead
290 */
291 var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
293 function encodeBase64(str) { // http://tools.ietf.org/html/rfc4648
294 var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
296 str = encodeUTF8(str); // encode multi-byte chars into UTF-8 for byte-array
298 do { // pack three octets into four hexets
299 o1 = str.charCodeAt(i++);
300 o2 = str.charCodeAt(i++);
301 o3 = str.charCodeAt(i++);
303 bits = o1<<16 | o2<<8 | o3;
305 h1 = bits>>18 & 0x3f;
306 h2 = bits>>12 & 0x3f;
307 h3 = bits>>6 & 0x3f;
308 h4 = bits & 0x3f;
310 // end of string? index to '=' in b64
311 if (isNaN(o3)) h4 = 64;
312 if (isNaN(o2)) h3 = 64;
314 // use hexets to index into b64, and append result to encoded string
315 enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
316 } while (i < str.length);
318 return enc;
319 }
321 function decodeBase64(str) {
322 var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
324 do { // unpack four hexets into three octets using index points in b64
325 h1 = b64.indexOf(str.charAt(i++));
326 h2 = b64.indexOf(str.charAt(i++));
327 h3 = b64.indexOf(str.charAt(i++));
328 h4 = b64.indexOf(str.charAt(i++));
330 bits = h1<<18 | h2<<12 | h3<<6 | h4;
332 o1 = bits>>16 & 0xff;
333 o2 = bits>>8 & 0xff;
334 o3 = bits & 0xff;
336 if (h3 == 64) enc += String.fromCharCode(o1);
337 else if (h4 == 64) enc += String.fromCharCode(o1, o2);
338 else enc += String.fromCharCode(o1, o2, o3);
339 } while (i < str.length);
341 return decodeUTF8(enc); // decode UTF-8 byte-array back to Unicode
342 }
344 function encodeUTF8(str) { // encode multi-byte string into utf-8 multiple single-byte characters
345 str = str.replace(
346 /[\u0080-\u07ff]/g, // U+0080 - U+07FF = 2-byte chars
347 function(c) {
348 var cc = c.charCodeAt(0);
349 return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); }
350 );
351 str = str.replace(
352 /[\u0800-\uffff]/g, // U+0800 - U+FFFF = 3-byte chars
353 function(c) {
354 var cc = c.charCodeAt(0);
355 return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); }
356 );
357 return str;
358 }
360 function decodeUTF8(str) { // decode utf-8 encoded string back into multi-byte characters
361 str = str.replace(
362 /[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
363 function(c) {
364 var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f;
365 return String.fromCharCode(cc); }
366 );
367 str = str.replace(
368 /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
369 function(c) {
370 var cc = (c.charCodeAt(0)&0x0f)<<12 | (c.charCodeAt(1)&0x3f<<6) | c.charCodeAt(2)&0x3f;
371 return String.fromCharCode(cc); }
372 );
373 return str;
374 }
377 function byteArrayToHexStr(b) { // convert byte array to hex string for displaying test vectors
378 var s = '';
379 for (var i=0; i<b.length; i++) s += b[i].toString(16) + ' ';
380 return s;
381 }
383 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
386 var plainText = "ROMEO: But, soft! what light through yonder window breaks?\n\
387 It is the east, and Juliet is the sun.\n\
388 Arise, fair sun, and kill the envious moon,\n\
389 Who is already sick and pale with grief,\n\
390 That thou her maid art far more fair than she:\n\
391 Be not her maid, since she is envious;\n\
392 Her vestal livery is but sick and green\n\
393 And none but fools do wear it; cast it off.\n\
394 It is my lady, O, it is my love!\n\
395 O, that she knew she were!\n\
396 She speaks yet she says nothing: what of that?\n\
397 Her eye discourses; I will answer it.\n\
398 I am too bold, 'tis not to me she speaks:\n\
399 Two of the fairest stars in all the heaven,\n\
400 Having some business, do entreat her eyes\n\
401 To twinkle in their spheres till they return.\n\
402 What if her eyes were there, they in her head?\n\
403 The brightness of her cheek would shame those stars,\n\
404 As daylight doth a lamp; her eyes in heaven\n\
405 Would through the airy region stream so bright\n\
406 That birds would sing and think it were not night.\n\
407 See, how she leans her cheek upon her hand!\n\
408 O, that I were a glove upon that hand,\n\
409 That I might touch that cheek!\n\
410 JULIET: Ay me!\n\
411 ROMEO: She speaks:\n\
412 O, speak again, bright angel! for thou art\n\
413 As glorious to this night, being o'er my head\n\
414 As is a winged messenger of heaven\n\
415 Unto the white-upturned wondering eyes\n\
416 Of mortals that fall back to gaze on him\n\
417 When he bestrides the lazy-pacing clouds\n\
418 And sails upon the bosom of the air.";
420 var password = "O Romeo, Romeo! wherefore art thou Romeo?";
422 var cipherText = AESEncryptCtr(plainText, password, 256);
423 var decryptedText = AESDecryptCtr(cipherText, password, 256);
425 assertEq(plainText, decryptedText);