~ubuntu-branches/ubuntu/quantal/enigmail/quantal-security

« back to all changes in this revision

Viewing changes to mozilla/build/pgo/js-input/crypto-aes.html

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2013-09-13 16:02:15 UTC
  • mfrom: (0.12.16)
  • Revision ID: package-import@ubuntu.com-20130913160215-u3g8nmwa0pdwagwc
Tags: 2:1.5.2-0ubuntu0.12.10.1
* New upstream release v1.5.2 for Thunderbird 24

* Build enigmail using a stripped down Thunderbird 17 build system, as it's
  now quite difficult to build the way we were doing previously, with the
  latest Firefox build system
* Add debian/patches/no_libxpcom.patch - Don't link against libxpcom, as it
  doesn't exist anymore (but exists in the build system)
* Add debian/patches/use_sdk.patch - Use the SDK version of xpt.py and
  friends
* Drop debian/patches/ipc-pipe_rename.diff (not needed anymore)
* Drop debian/patches/makefile_depth.diff (not needed anymore)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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>