xref: /plugin/dokucrypt3/crypto_low-level.js (revision 97c734d516051c5b55fc0c340717b771d97a295d)
1// This file describes a flat low-level programming interface for encryption and decryption.
2
3function setKeyFromAscii(pass) {
4  var s = encode_utf8(pass);
5  var i, kmd5e, kmd5o;
6
7  if (s.length == 1) {
8    s += s;
9  }
10
11  md5_init();
12  for (i = 0; i < s.length; i += 2) {
13    md5_update(s.charCodeAt(i));
14  }
15  md5_finish();
16  kmd5e = byteArrayToHex(digestBits);
17
18  md5_init();
19  for (i = 1; i < s.length; i += 2) {
20    md5_update(s.charCodeAt(i));
21  }
22  md5_finish();
23  kmd5o = byteArrayToHex(digestBits);
24
25  var hs = kmd5e + kmd5o;
26  key =  hexToByteArray(hs);
27  hs = byteArrayToHex(key);
28  return(key);
29}
30
31// BEGIN: javascript/aes.js
32// Rijndael parameters --  Valid values are 128, 192, or 256
33
34var keySizeInBits = 256;
35var blockSizeInBits = 128;
36
37//
38// Note: in the following code the two dimensional arrays are indexed as
39//       you would probably expect, as array[row][column]. The state arrays
40//       are 2d arrays of the form state[4][Nb].
41
42
43// The number of rounds for the cipher, indexed by [Nk][Nb]
44var roundsArray = [ undefined, undefined, undefined, undefined,[ undefined, undefined, undefined, undefined,10, undefined, 12, undefined, 14], undefined,
45                        [ undefined, undefined, undefined, undefined, 12, undefined, 12, undefined, 14], undefined,
46                        [ undefined, undefined, undefined, undefined, 14, undefined, 14, undefined, 14] ];
47
48// The number of bytes to shift by in shiftRow, indexed by [Nb][row]
49var shiftOffsets = [ undefined, undefined, undefined, undefined,[ undefined,1, 2, 3], undefined,[ undefined,1, 2, 3], undefined,[ undefined,1, 3, 4] ];
50
51// The round constants used in subkey expansion
52var Rcon = [
530x01, 0x02, 0x04, 0x08, 0x10, 0x20,
540x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
550xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
560x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
570xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ];
58
59// Precomputed lookup table for the SBox
60var SBox = [
61 99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171,
62118, 202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164,
63114, 192, 183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113,
64216,  49,  21,   4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226,
65235,  39, 178, 117,   9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214,
66179,  41, 227,  47, 132,  83, 209,   0, 237,  32, 252, 177,  91, 106, 203,
67190,  57,  74,  76,  88, 207, 208, 239, 170, 251,  67,  77,  51, 133,  69,
68249,   2, 127,  80,  60, 159, 168,  81, 163,  64, 143, 146, 157,  56, 245,
69188, 182, 218,  33,  16, 255, 243, 210, 205,  12,  19, 236,  95, 151,  68,
7023,  196, 167, 126,  61, 100,  93,  25, 115,  96, 129,  79, 220,  34,  42,
71144, 136,  70, 238, 184,  20, 222,  94,  11, 219, 224,  50,  58,  10,  73,
72  6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121, 231, 200,  55, 109,
73141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8, 186, 120,  37,
74 46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138, 112,  62,
75181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158, 225,
76248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
77140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,
78 22 ];
79
80// Precomputed lookup table for the inverse SBox
81var SBoxInverse = [
82 82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215,
83251, 124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222,
84233, 203,  84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66,
85250, 195,  78,   8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73,
86109, 139, 209,  37, 114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92,
87204,  93, 101, 182, 146, 108, 112,  72,  80, 253, 237, 185, 218,  94,  21,
88 70,  87, 167, 141, 157, 132, 144, 216, 171,   0, 140, 188, 211,  10, 247,
89228,  88,   5, 184, 179,  69,   6, 208,  44,  30, 143, 202,  63,  15,   2,
90193, 175, 189,   3,   1,  19, 138, 107,  58, 145,  17,  65,  79, 103, 220,
91234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116,  34, 231, 173,
92 53, 133, 226, 249,  55, 232,  28, 117, 223, 110,  71, 241,  26, 113,  29,
93 41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27, 252,  86,  62,  75,
94198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,  31, 221, 168,
95 51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,  96,  81,
96127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239, 160,
97224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97,
98 23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12,
99125 ];
100
101// This method circularly shifts the array left by the number of elements
102// given in its parameter. It returns the resulting array and is used for
103// the ShiftRow step. Note that shift() and push() could be used for a more
104// elegant solution, but they require IE5.5+, so I chose to do it manually.
105
106function cyclicShiftLeft(theArray, positions) {
107  var temp = theArray.slice(0, positions);
108  theArray = theArray.slice(positions).concat(temp);
109  return theArray;
110}
111
112// Cipher parameters ... do not change these
113var Nk = keySizeInBits / 32;
114var Nb = blockSizeInBits / 32;
115var Nr = roundsArray[Nk][Nb];
116
117// Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec.
118
119function xtime(poly) {
120  poly <<= 1;
121  return ((poly & 0x100) ? (poly ^ 0x11B) : (poly));
122}
123
124// Multiplies the two elements of GF(2^8) together and returns the result.
125// See the Rijndael spec, but should be straightforward: for each power of
126// the indeterminant that has a 1 coefficient in x, add y times that power
127// to the result. x and y should be bytes representing elements of GF(2^8)
128
129function mult_GF256(x, y) {
130  var bit, result = 0;
131
132  for (bit = 1; bit < 256; bit *= 2, y = xtime(y)) {
133    if (x & bit) { result ^= y; }
134  }
135  return result;
136}
137
138// Performs the substitution step of the cipher.  State is the 2d array of
139// state information (see spec) and direction is string indicating whether
140// we are performing the forward substitution ("encrypt") or inverse
141// substitution (anything else)
142
143function byteSub(state, direction) {
144  var S;
145  if (direction == "encrypt") { S = SBox; } // Point S to the SBox we're using
146  else { S = SBoxInverse; }
147  for (var i = 0; i < 4; i++) { // Substitute for every byte in state
148    for (var j = 0; j < Nb; j++) { state[i][j] = S[state[i][j]]; }
149  }
150}
151
152// Performs the row shifting step of the cipher.
153
154function shiftRow(state, direction) {
155  for (var i=1; i<4; i++) {             // Row 0 never shifts
156    if (direction == "encrypt") {
157       state[i] = cyclicShiftLeft(state[i], shiftOffsets[Nb][i]);
158    } else {
159       state[i] = cyclicShiftLeft(state[i], Nb - shiftOffsets[Nb][i]);
160    }
161  }
162
163}
164
165// Performs the column mixing step of the cipher. Most of these steps can
166// be combined into table lookups on 32bit values (at least for encryption)
167// to greatly increase the speed.
168
169function mixColumn(state, direction) {
170  var b = [];                            // Result of matrix multiplications
171  var i = 0;
172  for (var j = 0; j < Nb; j++) {         // Go through each column...
173    for (i = 0; i < 4; i++) {        // and for each row in the column...
174      if (direction == "encrypt") {
175        b[i] = mult_GF256(state[i][j], 2) ^          // perform mixing
176               mult_GF256(state[(i+1)%4][j], 3) ^
177               state[(i+2)%4][j] ^
178               state[(i+3)%4][j];
179      } else {
180        b[i] = mult_GF256(state[i][j], 0xE) ^
181               mult_GF256(state[(i+1)%4][j], 0xB) ^
182               mult_GF256(state[(i+2)%4][j], 0xD) ^
183               mult_GF256(state[(i+3)%4][j], 9);
184      }
185    }
186    for (i = 0; i < 4; i++) {        // Place result back into column
187      state[i][j] = b[i];
188    }
189  }
190}
191
192// Adds the current round key to the state information. Straightforward.
193
194function addRoundKey(state, roundKey) {
195  for (var j = 0; j < Nb; j++) {                 // Step through columns...
196    state[0][j] ^= (roundKey[j] & 0xFF);         // and XOR
197    state[1][j] ^= ((roundKey[j]>>8) & 0xFF);
198    state[2][j] ^= ((roundKey[j]>>16) & 0xFF);
199    state[3][j] ^= ((roundKey[j]>>24) & 0xFF);
200  }
201}
202
203// This function creates the expanded key from the input (128/192/256-bit)
204// key. The parameter key is an array of bytes holding the value of the key.
205// The returned value is an array whose elements are the 32-bit words that
206// make up the expanded key.
207
208function keyExpansion(key) {
209  var expandedKey = [];
210  var temp;
211
212  // in case the key size or parameters were changed...
213  Nk = keySizeInBits / 32;
214  Nb = blockSizeInBits / 32;
215  Nr = roundsArray[Nk][Nb];
216
217  for (var j=0; j < Nk; j++) {   // Fill in input key first
218    expandedKey[j] =
219      (key[4*j]) | (key[4*j+1]<<8) | (key[4*j+2]<<16) | (key[4*j+3]<<24);
220  }
221
222  // Now walk down the rest of the array filling in expanded key bytes as
223  // per Rijndael's spec
224  for (j = Nk; j < Nb * (Nr + 1); j++) {    // For each word of expanded key
225    temp = expandedKey[j - 1];
226    if (j % Nk === 0) {
227      temp = ( (SBox[(temp>>8) & 0xFF]) |
228               (SBox[(temp>>16) & 0xFF]<<8) |
229               (SBox[(temp>>24) & 0xFF]<<16) |
230               (SBox[temp & 0xFF]<<24) ) ^ Rcon[Math.floor(j / Nk) - 1];
231    } else if (Nk > 6 && j % Nk == 4) {
232      temp = (SBox[(temp>>24) & 0xFF]<<24) |
233             (SBox[(temp>>16) & 0xFF]<<16) |
234             (SBox[(temp>>8) & 0xFF]<<8) |
235             (SBox[temp & 0xFF]);
236    }
237    expandedKey[j] = expandedKey[j-Nk] ^ temp;
238  }
239  return expandedKey;
240}
241
242// Rijndael's round functions...
243
244function jcRound(state, roundKey) {
245  byteSub(state, "encrypt");
246  shiftRow(state, "encrypt");
247  mixColumn(state, "encrypt");
248  addRoundKey(state, roundKey);
249}
250
251function inverseRound(state, roundKey) {
252  addRoundKey(state, roundKey);
253  mixColumn(state, "decrypt");
254  shiftRow(state, "decrypt");
255  byteSub(state, "decrypt");
256}
257
258function finalRound(state, roundKey) {
259  byteSub(state, "encrypt");
260  shiftRow(state, "encrypt");
261  addRoundKey(state, roundKey);
262}
263
264function inverseFinalRound(state, roundKey){
265  addRoundKey(state, roundKey);
266  shiftRow(state, "decrypt");
267  byteSub(state, "decrypt");
268}
269
270// encrypt is the basic encryption function. It takes parameters
271// block, an array of bytes representing a plaintext block, and expandedKey,
272// an array of words representing the expanded key previously returned by
273// keyExpansion(). The ciphertext block is returned as an array of bytes.
274
275function encrypt(block, expandedKey) {
276  var i;
277  if (!block || block.length*8 != blockSizeInBits) { return; }
278  if (!expandedKey) { return; }
279
280  block = packBytes(block);
281  addRoundKey(block, expandedKey);
282  for (i=1; i<Nr; i++) { jcRound(block, expandedKey.slice(Nb*i, Nb*(i+1))); }
283  finalRound(block, expandedKey.slice(Nb*Nr));
284  return unpackBytes(block);
285}
286
287// decrypt is the basic decryption function. It takes parameters
288// block, an array of bytes representing a ciphertext block, and expandedKey,
289// an array of words representing the expanded key previously returned by
290// keyExpansion(). The decrypted block is returned as an array of bytes.
291
292function decrypt(block, expandedKey) {
293  var i;
294  if (!block || block.length*8 != blockSizeInBits) { return; }
295  if (!expandedKey) { return; }
296
297  block = packBytes(block);
298  inverseFinalRound(block, expandedKey.slice(Nb*Nr));
299  for (i = Nr - 1; i>0; i--) {
300    inverseRound(block, expandedKey.slice(Nb*i, Nb*(i+1)));
301  }
302  addRoundKey(block, expandedKey);
303  return unpackBytes(block);
304}
305
306/* !NEEDED
307// This method takes a byte array (byteArray) and converts it to a string by
308// applying String.fromCharCode() to each value and concatenating the result.
309// The resulting string is returned. Note that this function SKIPS zero bytes
310// under the assumption that they are padding added in formatPlaintext().
311// Obviously, do not invoke this method on raw data that can contain zero
312// bytes. It is really only appropriate for printable ASCII/Latin-1
313// values. Roll your own function for more robust functionality :)
314
315function byteArrayToString(byteArray) {
316  var result = "";
317  for(var i=0; i<byteArray.length; i++)
318    if (byteArray[i] != 0)
319      result += String.fromCharCode(byteArray[i]);
320  return result;
321}
322*/
323
324// This function takes an array of bytes (byteArray) and converts them
325// to a hexadecimal string. Array element 0 is found at the beginning of
326// the resulting string, high nibble first. Consecutive elements follow
327// similarly, for example [16, 255] --> "10ff". The function returns a
328// string.
329
330function byteArrayToHex(byteArray) {
331  var result = "";
332  if (!byteArray) { return; }
333  for (var i=0; i<byteArray.length; i++) {
334    result += ((byteArray[i]<16) ? "0" : "") + byteArray[i].toString(16);
335  }
336
337  return result;
338}
339
340// This function converts a string containing hexadecimal digits to an
341// array of bytes. The resulting byte array is filled in the order the
342// values occur in the string, for example "10FF" --> [16, 255]. This
343// function returns an array.
344
345function hexToByteArray(hexString) {
346  var byteArray = [];
347  if (hexString.length % 2) { return; } // must have even length
348  if (hexString.indexOf("0x") === 0 || hexString.indexOf("0X") === 0) {
349    hexString = hexString.substring(2);
350  }
351  for (var i = 0; i<hexString.length; i += 2) {
352    byteArray[Math.floor(i/2)] = parseInt(hexString.slice(i, i+2), 16);
353  }
354  return byteArray;
355}
356
357// This function packs an array of bytes into the four row form defined by
358// Rijndael. It assumes the length of the array of bytes is divisible by
359// four. Bytes are filled in according to the Rijndael spec (starting with
360// column 0, row 0 to 3). This function returns a 2d array.
361
362function packBytes(octets) {
363  var state = [];
364  if (!octets || octets.length % 4) { return; }
365
366  state[0] = []; state[1] = [];
367  state[2] = []; state[3] = [];
368  for (var j=0; j<octets.length; j+= 4) {
369    state[0][j/4] = octets[j];
370    state[1][j/4] = octets[j+1];
371    state[2][j/4] = octets[j+2];
372    state[3][j/4] = octets[j+3];
373  }
374  return state;
375}
376
377// This function unpacks an array of bytes from the four row format preferred
378// by Rijndael into a single 1d array of bytes. It assumes the input "packed"
379// is a packed array. Bytes are filled in according to the Rijndael spec.
380// This function returns a 1d array of bytes.
381
382function unpackBytes(packed) {
383  var result = [];
384  for (var j=0; j<packed[0].length; j++) {
385    result[result.length] = packed[0][j];
386    result[result.length] = packed[1][j];
387    result[result.length] = packed[2][j];
388    result[result.length] = packed[3][j];
389  }
390  return result;
391}
392
393// This function takes a prospective plaintext (string or array of bytes)
394// and pads it with pseudorandom bytes if its length is not a multiple of the block
395// size. If plaintext is a string, it is converted to an array of bytes
396// in the process. The type checking can be made much nicer using the
397// instanceof operator, but this operator is not available until IE5.0 so I
398// chose to use the heuristic below.
399
400function formatPlaintext(plaintext) {
401  var bpb = blockSizeInBits / 8;               // bytes per block
402  var i;
403
404  // if primitive string or String instance
405  if ((!((typeof plaintext == "object") &&
406        ((typeof (plaintext[0])) == "number"))) &&
407      ((typeof plaintext == "string") || plaintext.indexOf)) {
408    plaintext = plaintext.split("");
409    // Unicode issues here (ignoring high byte)
410    for (i=0; i<plaintext.length; i++) {
411      plaintext[i] = plaintext[i].charCodeAt(0) & 0xFF;
412    }
413  }
414
415  i = plaintext.length % bpb;
416  if (i > 0) {
417    plaintext = plaintext.concat(getRandomBytes(bpb - i));
418  }
419
420  return plaintext;
421}
422
423// Returns an array containing "howMany" random bytes.
424
425function getRandomBytes(howMany) {
426  var i, bytes = [];
427
428  for (i = 0; i < howMany; i++) {
429    bytes[i] = prng.nextInt(255);
430  }
431  return bytes;
432}
433
434// rijndaelEncrypt(plaintext, key, mode)
435// Encrypts the plaintext using the given key and in the given mode.
436// The parameter "plaintext" can either be a string or an array of bytes.
437// The parameter "key" must be an array of key bytes. If you have a hex
438// string representing the key, invoke hexToByteArray() on it to convert it
439// to an array of bytes. The third parameter "mode" is a string indicating
440// the encryption mode to use, either "ECB" or "CBC". If the parameter is
441// omitted, ECB is assumed.
442//
443// An array of bytes representing the cihpertext is returned. To convert
444// this array to hex, invoke byteArrayToHex() on it.
445
446function rijndaelEncrypt(plaintext, key, mode) {
447  var expandedKey, i, aBlock;
448  var bpb = blockSizeInBits / 8;          // bytes per block
449  var ct;                                 // ciphertext
450
451  if (!plaintext || !key) { return; }
452  if (key.length*8 != keySizeInBits) { return; }
453  if (mode == "CBC") {
454    ct = getRandomBytes(bpb);             // get IV
455//dump("IV", byteArrayToHex(ct));
456  } else {
457    mode = "ECB";
458    ct = [];
459  }
460
461  // convert plaintext to byte array and pad with zeros if necessary.
462  plaintext = formatPlaintext(plaintext);
463
464  expandedKey = keyExpansion(key);
465
466  for (var block = 0; block < plaintext.length / bpb; block++) {
467    aBlock = plaintext.slice(block * bpb, (block + 1) * bpb);
468    if (mode == "CBC") {
469      for (i = 0; i < bpb; i++) {
470        aBlock[i] ^= ct[(block * bpb) + i];
471      }
472    }
473    ct = ct.concat(encrypt(aBlock, expandedKey));
474  }
475
476  return ct;
477}
478
479// rijndaelDecrypt(ciphertext, key, mode)
480// Decrypts the using the given key and mode. The parameter "ciphertext"
481// must be an array of bytes. The parameter "key" must be an array of key
482// bytes. If you have a hex string representing the ciphertext or key,
483// invoke hexToByteArray() on it to convert it to an array of bytes. The
484// parameter "mode" is a string, either "CBC" or "ECB".
485//
486// An array of bytes representing the plaintext is returned. To convert
487// this array to a hex string, invoke byteArrayToHex() on it. To convert it
488// to a string of characters, you can use byteArrayToString().
489
490function rijndaelDecrypt(ciphertext, key, mode) {
491  var expandedKey;
492  var bpb = blockSizeInBits / 8;          // bytes per block
493  var pt = [];                   // plaintext array
494  var aBlock;                             // a decrypted block
495  var block;                              // current block number
496
497  if (!ciphertext || !key || typeof ciphertext == "string") { return; }
498  if (key.length*8 != keySizeInBits) { return; }
499  if (!mode) { mode = "ECB"; } // assume ECB if mode omitted
500
501  expandedKey = keyExpansion(key);
502
503  // work backwards to accomodate CBC mode
504  for (block=(ciphertext.length / bpb)-1; block>0; block--) {
505    aBlock =
506     decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey);
507    if (mode == "CBC") {
508      for (var i=0; i<bpb; i++) {
509        pt[(block-1)*bpb + i] = aBlock[i] ^ ciphertext[(block-1)*bpb + i];
510      }
511    } else {
512      pt = aBlock.concat(pt);
513    }
514  }
515
516  // do last block if ECB (skips the IV in CBC)
517  if (mode == "ECB") {
518    pt = decrypt(ciphertext.slice(0, bpb), expandedKey).concat(pt);
519  }
520
521  return pt;
522}
523
524// END: javascrypt/aes.js
525// BEGIN: javascrypt/entropy.js
526
527//  Entropy collection utilities
528
529/* Start by declaring static storage and initialise
530   the entropy vector from the time we come through
531   here. */
532
533var entropyData = []; // Collected entropy data
534var edlen = 0;        // Keyboard array data length
535
536addEntropyTime();     // Start entropy collection with page load time
537ce();                 // Roll milliseconds into initial entropy
538
539//  Add a byte to the entropy vector
540
541function addEntropyByte(b) {
542  entropyData[edlen++] = b;
543}
544
545/*  Capture entropy.  When the user presses a key or performs
546  various other events for which we can request
547  notification, add the time in 255ths of a second to the
548  entropyData array.  The name of the function is short
549  so it doesn't bloat the form object declarations in
550  which it appears in various "onXXX" events.  */
551
552function ce() {
553  addEntropyByte(Math.floor((((new Date()).getMilliseconds()) * 255) / 999));
554}
555
556//  Add a 32 bit quantity to the entropy vector
557
558function addEntropy32(w) {
559  var i;
560
561  for (i = 0; i < 4; i++) {
562    addEntropyByte(w & 0xFF);
563    w >>= 8;
564  }
565}
566
567/*  Add the current time and date (milliseconds since the epoch,
568    truncated to 32 bits) to the entropy vector.  */
569
570function addEntropyTime() {
571  addEntropy32((new Date()).getTime());
572}
573/*  Start collection of entropy from mouse movements. The
574  argument specifies the  number of entropy items to be
575  obtained from mouse motion, after which mouse motion
576  will be ignored.  Note that you can re-enable mouse
577  motion collection at any time if not already underway.  */
578
579var mouseMotionCollect = 0;
580var oldMoveHandler;    // For saving and restoring mouse move handler in IE4
581
582function mouseMotionEntropy(maxsamp) {
583  if (mouseMotionCollect <= 0) {
584    mouseMotionCollect = maxsamp;
585    if ((document.implementation.hasFeature("Events", "2.0")) &&
586        document.addEventListener) {
587      //  Browser supports Document Object Model (DOM) 2 events
588      document.addEventListener("mousemove", mouseMoveEntropy, false);
589    } else {
590      if (document.attachEvent) {
591        //  Internet Explorer 5 and above event model
592        document.attachEvent("onmousemove", mouseMoveEntropy);
593      } else {
594        //  Internet Explorer 4 event model
595        oldMoveHandler = document.onmousemove;
596        document.onmousemove = mouseMoveEntropy;
597      }
598    }
599    //dump("Mouse enable", mouseMotionCollect);
600  }
601}
602
603/*  Collect entropy from mouse motion events.  Note that
604  this is craftily coded to work with either DOM2 or Internet
605  Explorer style events.  Note that we don't use every successive
606  mouse movement event.  Instead, we XOR the three bytes collected
607  from the mouse and use that to determine how many subsequent
608  mouse movements we ignore before capturing the next one.  */
609
610var mouseEntropyTime = 0;      // Delay counter for mouse entropy collection
611
612function mouseMoveEntropy(e) {
613  if (!e) {
614    e = window.event;      // Internet Explorer event model
615  }
616  if (mouseMotionCollect > 0) {
617    if (mouseEntropyTime-- <= 0) {
618      addEntropyByte(e.screenX & 0xFF);
619      addEntropyByte(e.screenY & 0xFF);
620      ce();
621      mouseMotionCollect--;
622      mouseEntropyTime = (entropyData[edlen - 3] ^ entropyData[edlen - 2] ^
623                          entropyData[edlen - 1]) % 19;
624      //dump("Mouse Move", byteArrayToHex(entropyData.slice(-3)));
625    }
626    if (mouseMotionCollect <= 0) {
627      if (document.removeEventListener) {
628        document.removeEventListener("mousemove", mouseMoveEntropy, false);
629      } else if (document.detachEvent) {
630        document.detachEvent("onmousemove", mouseMoveEntropy);
631      } else {
632        document.onmousemove = oldMoveHandler;
633      }
634      //dump("Spung!", 0);
635    }
636  }
637}
638
639/*  Compute a 32 byte key value from the entropy vector.
640  We compute the value by taking the MD5 sum of the even
641  and odd bytes respectively of the entropy vector, then
642  concatenating the two MD5 sums.  */
643
644function keyFromEntropy() {
645  var i, k = [];
646
647  if (edlen === 0) {
648    alert("Blooie!  Entropy vector void at call to keyFromEntropy.");
649  }
650  //dump("Entropy bytes", edlen);
651
652  md5_init();
653  for (i = 0; i < edlen; i += 2) {
654    md5_update(entropyData[i]);
655  }
656  md5_finish();
657  for (i = 0; i < 16; i++) {
658    k[i] = digestBits[i];
659  }
660
661  md5_init();
662  for (i = 1; i < edlen; i += 2) {
663    md5_update(entropyData[i]);
664  }
665  md5_finish();
666  for (i = 0; i < 16; i++) {
667    k[i + 16] = digestBits[i];
668  }
669
670  //dump("keyFromEntropy", byteArrayToHex(k));
671  return k;
672}
673// END: javascrypt/entropy.js
674// BEGIN: javascrypt/aesprng.js
675//  AES based pseudorandom number generator
676
677/*  Constructor.  Called with an array of 32 byte (0-255) values
678  containing the initial seed.  */
679
680function AESprng(seed) {
681  this.key = [];
682  this.key = seed;
683  this.itext = hexToByteArray("9F489613248148F9C27945C6AE62EECA3E3367BB14064E4E6DC67A9F28AB3BD1");
684  this.nbytes = 0;          // Bytes left in buffer
685
686  this.next = AESprng_next;
687  this.nextbits = AESprng_nextbits;
688  this.nextInt = AESprng_nextInt;
689  this.round = AESprng_round;
690
691  /*  Encrypt the initial text with the seed key
692      three times, feeding the output of the encryption
693      back into the key for the next round.  */
694
695  bsb = blockSizeInBits;
696  blockSizeInBits = 256;
697  var i, ct;
698  for (i = 0; i < 3; i++) {
699    this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
700  }
701
702  /*  Now make between one and four additional
703      key-feedback rounds, with the number determined
704      by bits from the result of the first three
705      rounds.  */
706
707  var n = 1 + (this.key[3] & 2) + (this.key[9] & 1);
708  for (i = 0; i < n; i++) {
709    this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
710  }
711  blockSizeInBits = bsb;
712}
713
714function AESprng_round() {
715  bsb = blockSizeInBits;
716  blockSizeInBits = 256;
717  this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
718  this.nbytes = 32;
719  blockSizeInBits = bsb;
720}
721
722//  Return next byte from the generator
723function AESprng_next() {
724  if (this.nbytes <= 0) {
725    this.round();
726  }
727  return(this.key[--this.nbytes]);
728}
729
730//  Return n bit integer value (up to maximum integer size)
731function AESprng_nextbits(n) {
732  var i, w = 0, nbytes = Math.floor((n + 7) / 8);
733
734  for (i = 0; i < nbytes; i++) {
735    w = (w << 8) | this.next();
736  }
737  return w & ((1 << n) - 1);
738}
739
740//  Return integer between 0 and n inclusive
741function AESprng_nextInt(n) {
742  var p = 1, nb = 0;
743
744  //  Determine smallest p,  2^p > n
745  //  nb = log_2 p
746
747  while (n >= p) {
748    p <<= 1;
749    nb++;
750  }
751  p--;
752
753  /*  Generate values from 0 through n by first generating
754      values v from 0 to (2^p)-1, then discarding any results v > n.
755      For the rationale behind this (and why taking
756      values mod (n + 1) is biased toward smaller values, see
757      Ferguson and Schneier, "Practical Cryptography",
758      ISBN 0-471-22357-3, section 10.8).  */
759
760  while (true) {
761    var v = this.nextbits(nb) & p;
762
763    if (v <= n) {
764      return v;
765    }
766  }
767}
768// END: javascrypt/aesprng.js
769// BEGIN: javascrypt/lecuyer.js
770/*
771   L'Ecuyer's two-sequence generator with a Bays-Durham shuffle
772  on the back-end.  Schrage's algorithm is used to perform
773  64-bit modular arithmetic within the 32-bit constraints of
774  JavaScript.
775
776  Bays, C. and S. D. Durham.  ACM Trans. Math. Software: 2 (1976)
777    59-64.
778
779  L'Ecuyer, P.  Communications of the ACM: 31 (1968) 742-774.
780
781  Schrage, L.  ACM Trans. Math. Software: 5 (1979) 132-138.
782
783*/
784
785// Schrage's modular multiplication algorithm
786function uGen(old, a, q, r, m) {
787  var t;
788
789  t = Math.floor(old / q);
790  t = a * (old - (t * q)) - (t * r);
791  return Math.round((t < 0) ? (t + m) : t);
792}
793
794// Return next raw value
795function LEnext() {
796  var i;
797
798  this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563);
799  this.gen2 = uGen(this.gen2, 40692, 52774, 3791, 2147483399);
800
801  /* Extract shuffle table index from most significant part
802     of the previous result. */
803
804  i = Math.floor(this.state / 67108862);
805
806  // New state is sum of generators modulo one of their moduli
807
808  this.state = Math.round((this.shuffle[i] + this.gen2) % 2147483563);
809
810  // Replace value in shuffle table with generator 1 result
811
812  this.shuffle[i] = this.gen1;
813
814  return this.state;
815}
816
817//  Return next random integer between 0 and n inclusive
818
819function LEnint(n) {
820  var p = 1;
821
822  //  Determine smallest p,  2^p > n
823
824  while (n >= p) {
825    p <<= 1;
826  }
827  p--;
828
829  /*  Generate values from 0 through n by first masking
830    values v from 0 to (2^p)-1, then discarding any results v > n.
831  For the rationale behind this (and why taking
832  values mod (n + 1) is biased toward smaller values, see
833  Ferguson and Schneier, "Practical Cryptography",
834  ISBN 0-471-22357-3, section 10.8).  */
835
836    while (true) {
837      var v = this.next() & p;
838
839      if (v <= n) {
840      return v;
841    }
842  }
843}
844
845//  Constructor.  Called with seed value
846function LEcuyer(s) {
847  var i;
848
849  this.shuffle = [];
850  this.gen1 = this.gen2 = (s & 0x7FFFFFFF);
851  for (i = 0; i < 19; i++) {
852    this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563);
853  }
854
855  // Fill the shuffle table with values
856
857  for (i = 0; i < 32; i++) {
858    this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563);
859    this.shuffle[31 - i] = this.gen1;
860  }
861  this.state = this.shuffle[0];
862  this.next = LEnext;
863  this.nextInt = LEnint;
864}
865// END:  javascrypt/lecuyer.js
866// BEGIN: javascrypt/md5.js
867function array(n) {
868    for (i = 0; i < n; i++) {
869        this[i] = 0;
870    }
871    this.length = n;
872}
873
874/* Some basic logical functions had to be rewritten because of a bug in
875 * Javascript.. Just try to compute 0xffffffff >> 4 with it..
876 * Of course, these functions are slower than the original would be, but
877 * at least, they work!
878 */
879
880function integer(n) {
881    return n % (0xffffffff + 1);
882}
883
884function shr(a, b) {
885    a = integer(a);
886    b = integer(b);
887    if (a - 0x80000000 >= 0) {
888        a = a % 0x80000000;
889        a >>= b;
890        a += 0x40000000 >> (b - 1);
891    } else {
892        a >>= b;
893    }
894    return a;
895}
896
897function shl1(a) {
898    a = a % 0x80000000;
899    if (a & 0x40000000 == 0x40000000) {
900        a -= 0x40000000;
901        a *= 2;
902        a += 0x80000000;
903    } else {
904        a *= 2;
905    }
906    return a;
907}
908
909function shl(a, b) {
910    a = integer(a);
911    b = integer(b);
912    for (var i = 0; i < b; i++) {
913        a = shl1(a);
914    }
915    return a;
916}
917
918function and(a, b) {
919    a = integer(a);
920    b = integer(b);
921    var t1 = a - 0x80000000;
922    var t2 = b - 0x80000000;
923    if (t1 >= 0) {
924        if (t2 >= 0) {
925            return ((t1 & t2) + 0x80000000);
926        } else {
927            return (t1 & b);
928        }
929    } else {
930        if (t2 >= 0) {
931            return (a & t2);
932        } else {
933            return (a & b);
934        }
935    }
936}
937
938function or(a, b) {
939    a = integer(a);
940    b = integer(b);
941    var t1 = a - 0x80000000;
942    var t2 = b - 0x80000000;
943    if (t1 >= 0) {
944        if (t2 >= 0) {
945            return ((t1 | t2) + 0x80000000);
946        } else {
947            return ((t1 | b) + 0x80000000);
948        }
949    } else {
950        if (t2 >= 0) {
951            return ((a | t2) + 0x80000000);
952        } else {
953            return (a | b);
954        }
955    }
956}
957
958function xor(a, b) {
959  a = integer(a);
960  b = integer(b);
961  var t1 = a - 0x80000000;
962  var t2 = b - 0x80000000;
963  if (t1 >= 0) {
964    if (t2 >= 0) {
965      return (t1 ^ t2);
966    } else {
967      return ((t1 ^ b) + 0x80000000);
968    }
969  } else {
970    if (t2 >= 0) {
971      return ((a ^ t2) + 0x80000000);
972    } else {
973      return (a ^ b);
974    }
975  }
976}
977
978function not(a) {
979  a = integer(a);
980  return 0xffffffff - a;
981}
982
983/* Here begin the real algorithm */
984
985var state = [];
986var count = [];
987    count[0] = 0;
988    count[1] = 0;
989var buffer = [];
990var transformBuffer = [];
991var digestBits = [];
992
993var S11 = 7;
994var S12 = 12;
995var S13 = 17;
996var S14 = 22;
997var S21 = 5;
998var S22 = 9;
999var S23 = 14;
1000var S24 = 20;
1001var S31 = 4;
1002var S32 = 11;
1003var S33 = 16;
1004var S34 = 23;
1005var S41 = 6;
1006var S42 = 10;
1007var S43 = 15;
1008var S44 = 21;
1009
1010function jcF(x, y, z) {
1011  return or(and(x, y), and(not(x), z));
1012}
1013
1014function jcG(x, y, z) {
1015  return or(and(x, z), and(y, not(z)));
1016}
1017
1018function jcH(x, y, z) {
1019  return xor(xor(x, y), z);
1020}
1021
1022function jcI(x, y, z) {
1023  return xor(y ,or(x , not(z)));
1024}
1025
1026function rotateLeft(a, n) {
1027  return or(shl(a, n), (shr(a, (32 - n))));
1028}
1029
1030function jcFF(a, b, c, d, x, s, ac) {
1031  a = a + jcF(b, c, d) + x + ac;
1032  a = rotateLeft(a, s);
1033  a = a + b;
1034  return a;
1035}
1036
1037function jcGG(a, b, c, d, x, s, ac) {
1038  a = a + jcG(b, c, d) + x + ac;
1039  a = rotateLeft(a, s);
1040  a = a + b;
1041  return a;
1042}
1043
1044function jcHH(a, b, c, d, x, s, ac) {
1045  a = a + jcH(b, c, d) + x + ac;
1046  a = rotateLeft(a, s);
1047  a = a + b;
1048  return a;
1049}
1050
1051function jcII(a, b, c, d, x, s, ac) {
1052  a = a + jcI(b, c, d) + x + ac;
1053  a = rotateLeft(a, s);
1054  a = a + b;
1055  return a;
1056}
1057
1058function transform(buf, offset) {
1059  var a = 0, b = 0, c = 0, d = 0;
1060  var x = transformBuffer;
1061
1062  a = state[0];
1063  b = state[1];
1064  c = state[2];
1065  d = state[3];
1066
1067  for (i = 0; i < 16; i++) {
1068    x[i] = and(buf[i * 4 + offset], 0xFF);
1069    for (j = 1; j < 4; j++) {
1070      x[i] += shl(and(buf[i * 4 + j + offset] ,0xFF), j * 8);
1071    }
1072  }
1073
1074  /* Round 1 */
1075  a = jcFF( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
1076  d = jcFF( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
1077  c = jcFF( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
1078  b = jcFF( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
1079  a = jcFF( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
1080  d = jcFF( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
1081  c = jcFF( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
1082  b = jcFF( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
1083  a = jcFF( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
1084  d = jcFF( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
1085  c = jcFF( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
1086  b = jcFF( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
1087  a = jcFF( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
1088  d = jcFF( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
1089  c = jcFF( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
1090  b = jcFF( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
1091
1092  /* Round 2 */
1093  a = jcGG( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
1094  d = jcGG( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
1095  c = jcGG( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
1096  b = jcGG( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
1097  a = jcGG( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
1098  d = jcGG( d, a, b, c, x[10], S22,  0x2441453); /* 22 */
1099  c = jcGG( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
1100  b = jcGG( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
1101  a = jcGG( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
1102  d = jcGG( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
1103  c = jcGG( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
1104  b = jcGG( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
1105  a = jcGG( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
1106  d = jcGG( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
1107  c = jcGG( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
1108  b = jcGG( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
1109
1110  /* Round 3 */
1111  a = jcHH( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
1112  d = jcHH( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
1113  c = jcHH( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
1114  b = jcHH( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
1115  a = jcHH( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
1116  d = jcHH( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
1117  c = jcHH( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
1118  b = jcHH( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
1119  a = jcHH( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
1120  d = jcHH( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
1121  c = jcHH( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
1122  b = jcHH( b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
1123  a = jcHH( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
1124  d = jcHH( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
1125  c = jcHH( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
1126  b = jcHH( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
1127
1128  /* Round 4 */
1129  a = jcII( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
1130  d = jcII( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
1131  c = jcII( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
1132  b = jcII( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
1133  a = jcII( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
1134  d = jcII( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
1135  c = jcII( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
1136  b = jcII( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
1137  a = jcII( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
1138  d = jcII( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
1139  c = jcII( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
1140  b = jcII( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
1141  a = jcII( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
1142  d = jcII( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
1143  c = jcII( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
1144  b = jcII( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
1145
1146  state[0] += a;
1147  state[1] += b;
1148  state[2] += c;
1149  state[3] += d;
1150
1151}
1152
1153function md5_init() {
1154  count[0] = count[1] = 0;
1155  state[0] = 0x67452301;
1156  state[1] = 0xefcdab89;
1157  state[2] = 0x98badcfe;
1158  state[3] = 0x10325476;
1159  for (i = 0; i < digestBits.length; i++) {
1160    digestBits[i] = 0;
1161  }
1162}
1163
1164function md5_update(b) {
1165  var index, i;
1166
1167  index = and(shr(count[0],3) , 0x3F);
1168  if (count[0] < 0xFFFFFFFF - 7) {
1169    count[0] += 8;
1170  } else {
1171    count[1]++;
1172    count[0] -= 0xFFFFFFFF + 1;
1173    count[0] += 8;
1174  }
1175  buffer[index] = and(b, 0xff);
1176  if (index  >= 63) {
1177    transform(buffer, 0);
1178  }
1179}
1180
1181function md5_finish() {
1182  var bits = [];
1183  var padding;
1184  var i = 0, index = 0, padLen = 0;
1185
1186  for (i = 0; i < 4; i++) {
1187    bits[i] = and(shr(count[0], (i * 8)), 0xFF);
1188  }
1189  for (i = 0; i < 4; i++) {
1190    bits[i + 4] = and(shr(count[1], (i * 8)), 0xFF);
1191  }
1192  index = and(shr(count[0], 3), 0x3F);
1193  padLen = (index < 56) ? (56 - index) : (120 - index);
1194  padding = [];
1195  padding[0] = 0x80;
1196  for (i = 0; i < padLen; i++) {
1197    md5_update(padding[i]);
1198  }
1199  for (i = 0; i < 8; i++) {
1200  md5_update(bits[i]);
1201  }
1202
1203  for (i = 0; i < 4; i++) {
1204    for (j = 0; j < 4; j++) {
1205      digestBits[i * 4 + j] = and(shr(state[i], (j * 8)) , 0xFF);
1206    }
1207  }
1208}
1209
1210/* End of the MD5 algorithm */
1211// END: javascyprt/md5.js
1212// BEGIN: javscrypt/armour.js
1213
1214//  Varieties of ASCII armour for binary data
1215
1216var maxLineLength = 64; // Maximum line length for armoured text
1217
1218/* Hexadecimal Armour
1219
1220   A message is encoded in Hexadecimal armour by expressing its
1221   bytes as a hexadecimal string which is prefixed by a sentinel
1222   of "?HX?" and suffixed by "?H", then broken into lines no
1223   longer than maxLineLength.  Armoured messages use lower case
1224   letters for digits with decimal values of 0 through 15, but
1225   either upper or lower case letters are accepted when decoding
1226   a message.  The hexadecimal to byte array interconversion
1227   routines in aes.js do most of the heavy lifting here.  */
1228
1229var hexSentinel = "?HX?", hexEndSentinel = "?H";
1230
1231//  Encode byte array in hexadecimal armour
1232
1233function armour_hex(b) {
1234  var h = hexSentinel + byteArrayToHex(b) + hexEndSentinel;
1235  var t = "";
1236  while (h.length > maxLineLength) {
1237    //dump("h.length", h.length);
1238    t += h.substring(0, maxLineLength) + "\n";
1239    h = h.substring(maxLineLength, h.length);
1240  }
1241  //dump("h.final_length", h.length);
1242  t += h + "\n";
1243  return t;
1244}
1245
1246/* Decode string in hexadecimal armour to byte array.  If the
1247   string supplied contains a start and/or end sentinel,
1248   only characters within the sentinels will be decoded.
1249   Non-hexadecimal digits are silently ignored, which
1250   automatically handles line breaks.  We might want to
1251   diagnose invalid characters as opposed to ignoring them.  */
1252
1253function disarm_hex(s) {
1254  var hexDigits = "0123456789abcdefABCDEF";
1255  var hs = "", i;
1256
1257  //  Extract hexadecimal data between sentinels, if present
1258  if ((i = s.indexOf(hexSentinel)) >= 0) {
1259    s = s.substring(i + hexSentinel.length, s.length);
1260  }
1261  if ((i = s.indexOf(hexEndSentinel)) >= 0) {
1262    s = s.substring(0, i);
1263  }
1264
1265  //  Assemble string of valid hexadecimal digits
1266
1267  for (i = 0; i < s.length; i++) {
1268    var c = s.charAt(i);
1269    if (hexDigits.indexOf(c) >= 0) {
1270      hs += c;
1271    }
1272  }
1273//dump("hs", hs);
1274  return hexToByteArray(hs);
1275}
1276
1277  /*  Codegroup Armour
1278      Codegroup armour encodes a byte string into a sequence of five
1279  letter code groups like spies used in the good old days.  The
1280  first group of a message is always "ZZZZZ" and the last "YYYYY";
1281  the decoding process ignores any text outside these start and
1282  end sentinels.  Bytes are encoded as two letters in the range
1283  "A" to "X", each encoding four bits of the byte.  Encoding uses
1284  a pseudorandomly generated base letter and wraps around modulo
1285  24 to spread encoded letters evenly through the alphabet.  (This
1286  refinement is purely aesthetic; the base letter sequence is
1287  identical for all messages and adds no security.  If the message
1288  does not fill an even number of five letter groups, the last
1289  group is padded to five letters with "Z" characters, which are
1290  ignored when decoding.  */
1291
1292var acgcl, acgt, acgg;
1293
1294// Output next codegroup, flushing current line if it's full
1295
1296function armour_cg_outgroup() {
1297  if (acgcl.length > maxLineLength) {
1298    acgt += acgcl + "\n";
1299    acgcl = "";
1300  }
1301  if (acgcl.length > 0) {
1302    acgcl += " ";
1303  }
1304  acgcl += acgg;
1305  acgg = "";
1306}
1307
1308/* Add a letter to the current codegroup, emitting it when
1309   it reaches five letters.  */
1310
1311function armour_cg_outletter(l) {
1312  if (acgg.length >= 5) {
1313    armour_cg_outgroup();
1314  }
1315  acgg += l;
1316}
1317
1318var codegroupSentinel = "ZZZZZ";
1319
1320function armour_codegroup(b) {
1321  var charBase = ("A").charCodeAt(0);
1322
1323  acgcl = codegroupSentinel;
1324  acgt = "";
1325  acgg = "";
1326
1327  var cgrng = new LEcuyer(0xbadf00d);
1328  for (i = 0; i < b.length; i++) {
1329    var r = cgrng.nextInt(23);
1330    armour_cg_outletter(String.fromCharCode(charBase + ((((b[i] >> 4) & 0xF)) + r) % 24));
1331    r = cgrng.nextInt(23);
1332    armour_cg_outletter(String.fromCharCode(charBase + ((((b[i] & 0xF)) + r) % 24)));
1333  }
1334  delete cgrng;
1335
1336  //  Generate nulls to fill final codegroup if required
1337
1338  while (acgg.length < 5) {
1339    armour_cg_outletter("Z");
1340  }
1341  armour_cg_outgroup();
1342
1343  //  Append terminator group
1344
1345  acgg = "YYYYY";
1346  armour_cg_outgroup();
1347
1348  //  Flush last line
1349
1350  acgt += acgcl + "\n";
1351
1352  return acgt;
1353}
1354
1355var dcgs, dcgi;
1356
1357  /*  Obtain next "significant" character from message.  Characters
1358    other than letters are silently ignored; both lower and upper
1359    case letters are accepted.  */
1360
1361function disarm_cg_insig() {
1362  while (dcgi < dcgs.length) {
1363    var c = dcgs.charAt(dcgi++).toUpperCase();
1364    if ((c >= "A") && (c <= "Z")) {
1365      //dump("c", c);
1366      return c;
1367    }
1368  }
1369  return "";
1370}
1371
1372// Decode a message in codegroup armour
1373
1374function disarm_codegroup(s) {
1375  var b = [];
1376  var nz = 0, ba, bal = 0, c;
1377
1378  dcgs = s;
1379  dcgi = 0;
1380
1381  //  Search for initial group of "ZZZZZ"
1382
1383  while (nz < 5) {
1384    c = disarm_cg_insig();
1385
1386    if (c == "Z") {
1387      nz++;
1388    } else if (c === "") {
1389      nz = 0;
1390      break;
1391    } else {
1392      nz = 0;
1393    }
1394  }
1395
1396  if (nz === 0) {
1397      alert("No codegroup starting symbol found in message.");
1398      return "";
1399  }
1400
1401  /*  Decode letter pairs from successive groups
1402      and assemble into bytes.  */
1403
1404  var charBase = ("A").charCodeAt(0);
1405  var cgrng = new LEcuyer(0xbadf00d);
1406  for (nz = 0; nz < 2; ) {
1407    c = disarm_cg_insig();
1408    //dump("c", c);
1409
1410    if ((c == "Y") || (c === "")) {
1411      break;
1412    } else if (c != "Z") {
1413      var r = cgrng.nextInt(23);
1414      var n = c.charCodeAt(0) - charBase;
1415      n = (n + (24 - r)) % 24;
1416      //dump("n", n);
1417      if (nz === 0) {
1418        ba = (n << 4);
1419        nz++;
1420      } else {
1421        ba |= n;
1422        b[bal++] = ba;
1423        nz = 0;
1424      }
1425    }
1426  }
1427  delete cgrng;
1428
1429  /*  Ponder how we escaped from the decoder loop and
1430      issue any requisite warnings.  */
1431
1432  var kbo = "  Attempting decoding with data received.";
1433  if (nz !== 0) {
1434    alert("Codegroup data truncated." + kbo);
1435  } else {
1436    if (c == "Y") {
1437      nz = 1;
1438      while (nz < 5) {
1439        c = disarm_cg_insig();
1440        if (c != "Y") {
1441          break;
1442        }
1443        nz++;
1444      }
1445      if (nz != 5) {
1446        alert("Codegroup end group incomplete." + kbo);
1447      }
1448    } else {
1449      alert("Codegroup end group missing." + kbo);
1450    }
1451  }
1452
1453  return b;
1454}
1455
1456    /*  Base64 Armour
1457
1458  Base64 armour encodes a byte array as described in RFC 1341.  Sequences
1459  of three bytes are encoded into groups of four characters from a set
1460  of 64 consisting of the upper and lower case letters, decimal digits,
1461  and the special characters "+" and "/".  If the input is not a multiple
1462  of three characters, the end of the message is padded with one or two
1463  "=" characters to indicate its actual length.  We prefix the armoured
1464  message with "?b64" and append "?64b" to the end; if one or both
1465  of these sentinels are present, text outside them is ignored.  You can
1466  suppress the generation of sentinels in armour by setting base64addsent
1467  false before calling armour_base64.  */
1468
1469
1470var base64code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
1471  base64sent = "?b64", base64esent = "?64b", base64addsent = true;
1472
1473function armour_base64(b) {
1474  var b64t = "";
1475  var b64l = base64addsent ? base64sent : "";
1476
1477  var i;
1478  for (i = 0; i <= b.length - 3; i += 3) {
1479    if ((b64l.length + 4) > maxLineLength) {
1480      b64t += b64l + "\n";
1481      b64l = "";
1482    }
1483    b64l += base64code.charAt(b[i] >> 2);
1484    b64l += base64code.charAt(((b[i] & 3) << 4) | (b[i + 1] >> 4));
1485    b64l += base64code.charAt(((b[i + 1] & 0xF) << 2) | (b[i + 2] >> 6));
1486    b64l += base64code.charAt(b[i + 2] & 0x3F);
1487  }
1488
1489  //dump("b.length", b.length);  dump("i", i); dump("(b.length - i)", (b.length - i));
1490  if ((b.length - i) == 1) {
1491    b64l += base64code.charAt(b[i] >> 2);
1492    b64l += base64code.charAt(((b[i] & 3) << 4));
1493    b64l += "==";
1494  } else if ((b.length - i) == 2) {
1495    b64l += base64code.charAt(b[i] >> 2);
1496    b64l += base64code.charAt(((b[i] & 3) << 4) | (b[i + 1] >> 4));
1497    b64l += base64code.charAt(((b[i + 1] & 0xF) << 2));
1498    b64l += "=";
1499  }
1500
1501  if ((b64l.length + 4) > maxLineLength) {
1502    b64t += b64l + "\n";
1503    b64l = "";
1504  }
1505  if (base64addsent) {
1506    b64l += base64esent;
1507  }
1508  b64t += b64l + "\n";
1509  return b64t;
1510}
1511
1512function disarm_base64(s) {
1513  var b = [];
1514  var i = 0, j, c, shortgroup = 0, n = 0;
1515  var d = [];
1516
1517  if ((j = s.indexOf(base64sent)) >= 0) {
1518    s = s.substring(j + base64sent.length, s.length);
1519  }
1520  if ((j = s.indexOf(base64esent)) >= 0) {
1521    s = s.substring(0, j);
1522  }
1523
1524  /*  Ignore any non-base64 characters before the encoded
1525      data stream and skip the type sentinel if present.  */
1526
1527  while (i < s.length) {
1528    if (base64code.indexOf(s.charAt(i)) != -1) {
1529      break;
1530    }
1531    i++;
1532  }
1533
1534  /*  Decode the base64 data stream.  The decoder is
1535      terminated by the end of the input string or
1536      the occurrence of the explicit end sentinel.  */
1537
1538  while (i < s.length) {
1539    for (j = 0; j < 4; ) {
1540      if (i >= s.length) {
1541        if (j > 0) {
1542          alert("Base64 cipher text truncated.");
1543          return b;
1544        }
1545        break;
1546      }
1547      c = base64code.indexOf(s.charAt(i));
1548      if (c >= 0) {
1549        d[j++] = c;
1550      } else if (s.charAt(i) == "=") {
1551        d[j++] = 0;
1552        shortgroup++;
1553      } else if (s.substring(i, i + base64esent.length) == base64esent) {
1554        //dump("s.substring(i, i + base64esent.length)", s.substring(i, i + base64esent.length));
1555        //dump("esent", i);
1556        i = s.length;
1557        continue;
1558      } else {
1559        //dump("s.substring(i, i + base64esent.length)", s.substring(i, i + base64esent.length));
1560        //dump("usent", i);
1561        // Might improve diagnosis of improper character in else clause here
1562      }
1563      i++;
1564    }
1565    //dump("d0", d[0]); dump("d1", d[1]); dump("d2", d[2]); dump("d3", d[3]);
1566    //dump("shortgroup", shortgroup);
1567    //dump("n", n);
1568    if (j == 4) {
1569      b[n++] = ((d[0] << 2) | (d[1] >> 4)) & 0xFF;
1570      if (shortgroup < 2) {
1571        b[n++] = ((d[1] << 4) | (d[2] >> 2)) & 0xFF;
1572        //dump("(d[1] << 4) | (d[2] >> 2)", (d[1] << 4) | (d[2] >> 2));
1573        if (shortgroup < 1) {
1574          b[n++] = ((d[2] << 6) | d[3]) & 0xFF;
1575        }
1576      }
1577    }
1578  }
1579  return b;
1580}
1581// END: javascrypt/armour.js
1582// BEGIN: javscrypt/utf-8.js
1583
1584/*  Encoding and decoding of Unicode character strings as
1585    UTF-8 byte streams.  */
1586
1587//  UNICODE_TO_UTF8  --  Encode Unicode argument string as UTF-8 return value
1588
1589function unicode_to_utf8(s) {
1590  var utf8 = "";
1591  for (var n = 0; n < s.length; n++) {
1592    var c = s.charCodeAt(n);
1593
1594    if (c <= 0x7F) {
1595      //  0x00 - 0x7F:  Emit as single byte, unchanged
1596      utf8 += String.fromCharCode(c);
1597    } else if ((c >= 0x80) && (c <= 0x7FF)) {
1598      //  0x80 - 0x7FF:  Output as two byte code, 0xC0 in first byte
1599      //  0x80 in second byte
1600      utf8 += String.fromCharCode((c >> 6) | 0xC0);
1601      utf8 += String.fromCharCode((c & 0x3F) | 0x80);
1602    } else {
1603      // 0x800 - 0xFFFF:  Output as three bytes, 0xE0 in first byte
1604      // 0x80 in second byte
1605      // 0x80 in third byte
1606      utf8 += String.fromCharCode((c >> 12) | 0xE0);
1607      utf8 += String.fromCharCode(((c >> 6) & 0x3F) | 0x80);
1608      utf8 += String.fromCharCode((c & 0x3F) | 0x80);
1609    }
1610  }
1611  return utf8;
1612}
1613
1614    //  UTF8_TO_UNICODE  --  Decode UTF-8 argument into Unicode string return value
1615
1616function utf8_to_unicode(utf8) {
1617  var s = "", i = 0, b1, b2;
1618
1619  while (i < utf8.length) {
1620    b1 = utf8.charCodeAt(i);
1621    if (b1 < 0x80) {      // One byte code: 0x00 0x7F
1622      s += String.fromCharCode(b1);
1623      i++;
1624    } else if((b1 >= 0xC0) && (b1 < 0xE0)) {  // Two byte code: 0x80 - 0x7FF
1625      b2 = utf8.charCodeAt(i + 1);
1626      s += String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F));
1627      i += 2;
1628    } else {            // Three byte code: 0x800 - 0xFFFF
1629      b2 = utf8.charCodeAt(i + 1);
1630      b3 = utf8.charCodeAt(i + 2);
1631      s += String.fromCharCode(((b1 & 0xF) << 12) |
1632              ((b2 & 0x3F) << 6) | (b3 & 0x3F));
1633      i += 3;
1634    }
1635  }
1636  return s;
1637}
1638
1639    /*  ENCODE_UTF8  --  Encode string as UTF8 only if it contains
1640       a character of 0x9D (Unicode OPERATING
1641       SYSTEM COMMAND) or a character greater
1642       than 0xFF.  This permits all strings
1643       consisting exclusively of 8 bit
1644       graphic characters to be encoded as
1645       themselves.  We choose 0x9D as the sentinel
1646       character as opposed to one of the more
1647       logical PRIVATE USE characters because 0x9D
1648       is not overloaded by the regrettable
1649       "Windows-1252" character set.  Now such characters
1650       don't belong in JavaScript strings, but you never
1651       know what somebody is going to paste into a
1652       text box, so this choice keeps Windows-encoded
1653       strings from bloating to UTF-8 encoding.  */
1654
1655function encode_utf8(s) {
1656  var i, necessary = false;
1657
1658  for (i = 0; i < s.length; i++) {
1659    if ((s.charCodeAt(i) == 0x9D) || (s.charCodeAt(i) > 0xFF)) {
1660      necessary = true;
1661      break;
1662    }
1663  }
1664  if (!necessary) {
1665    return s;
1666  }
1667  return String.fromCharCode(0x9D) + unicode_to_utf8(s);
1668}
1669
1670/*  DECODE_UTF8  --  Decode a string encoded with encode_utf8
1671    above.  If the string begins with the
1672    sentinel character 0x9D (OPERATING
1673    SYSTEM COMMAND), then we decode the
1674    balance as a UTF-8 stream.  Otherwise,
1675    the string is output unchanged, as
1676    it's guaranteed to contain only 8 bit
1677    characters excluding 0x9D.  */
1678
1679function decode_utf8(s) {
1680  if ((s.length > 0) && (s.charCodeAt(0) == 0x9D)) {
1681    return utf8_to_unicode(s.substring(1));
1682  }
1683  return s;
1684}
1685