js/src/devtools/jint/sunspider/crypto-aes.js

branch
TOR_BUG_9701
changeset 12
7540298fafa1
equal deleted inserted replaced
-1:000000000000 0:bb7b25ccce9e
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);

mercurial