Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / metrics / jint / sunspider / crypto-aes.js
1 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
2
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
16
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 */
21
22   state = AddRoundKey(state, w, 0, Nb);
23
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 */
32
33   state = SubBytes(state, Nb);
34   state = ShiftRows(state, Nb);
35   state = AddRoundKey(state, w, Nr, Nb);
36
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 }
43
44
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 }
55
56
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 }
71
72
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 }
93
94
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 }
105
106
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
111
112   var w = new Array(Nb*(Nr+1));
113   var temp = new Array(4);
114
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 */
121
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 */
141
142   return w;
143 }
144
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 }
151
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 }
159
160
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];
178
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] ]; 
191
192
193 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
194
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
204
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
214
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
220
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 */
228
229   // generate key schedule - an expansion of the key into distinct Key Rounds for each round
230   var keySchedule = KeyExpansion(key);
231
232   var blockCount = Math.ceil(plaintext.length/blockSize);
233   var ciphertext = new Array(blockCount);  // ciphertext as array of strings
234   
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 */
245
246     var cipherCntr = Cipher(counterBlock, keySchedule);  // -- encrypt counter block --
247     
248     // calculate length of final block:
249     var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1;
250
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
260
261     ciphertext[b] = escCtrlChars(ct);  // escape troublesome characters in ciphertext
262   }
263   /* END LOOP */
264
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);
271
272   // use '-' to separate blocks, use Array.join to concatenate arrays of strings for efficiency
273   return ctrTxt + '-' + ciphertext.join('-');
274 }
275
276
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
286
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
295
296   var keySchedule = KeyExpansion(key);
297
298   ciphertext = ciphertext.split('-');  // split ciphertext into array of block-length strings 
299
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 */
307
308   var plaintext = new Array(ciphertext.length-1);
309
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 */
319
320     var cipherCntr = Cipher(counterBlock, keySchedule);  // encrypt counter block
321
322     ciphertext[b] = unescCtrlChars(ciphertext[b]);
323
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
334
335     plaintext[b-1] = pt;  // b-1 'cos no initial nonce block in plaintext
336   }
337   /* END LOOP */
338
339   return plaintext.join('');
340 }
341
342 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
343
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
347
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 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
352
353 /*
354  * if escCtrlChars()/unescCtrlChars() still gives problems, use encodeBase64()/decodeBase64() instead
355  */
356 var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
357
358 function encodeBase64(str) {  // http://tools.ietf.org/html/rfc4648
359    var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
360    
361    str = encodeUTF8(str);  // encode multi-byte chars into UTF-8 for byte-array
362
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++);
368       
369       bits = o1<<16 | o2<<8 | o3;
370       
371       h1 = bits>>18 & 0x3f;
372       h2 = bits>>12 & 0x3f;
373       h3 = bits>>6 & 0x3f;
374       h4 = bits & 0x3f;
375       
376       // end of string? index to '=' in b64
377       if (isNaN(o3)) h4 = 64;
378       if (isNaN(o2)) h3 = 64;
379       
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 */
384    
385    return enc;
386 }
387
388 function decodeBase64(str) {
389    var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
390
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++));
397       
398       bits = h1<<18 | h2<<12 | h3<<6 | h4;
399       
400       o1 = bits>>16 & 0xff;
401       o2 = bits>>8 & 0xff;
402       o3 = bits & 0xff;
403       
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 */
409
410    return decodeUTF8(enc);  // decode UTF-8 byte-array back to Unicode
411 }
412
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 }
428
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 }
444
445
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 }
453
454 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
455
456
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.";
490
491 var password = "O Romeo, Romeo! wherefore art thou Romeo?";
492
493 var cipherText = AESEncryptCtr(plainText, password, 256);
494 var decryptedText = AESDecryptCtr(cipherText, password, 256);