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