tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

crypto-aes.html (18687B)


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