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