1var crypt_keys=[]; 2var tag_enc="ENCRYPTED"; 3var tag_pt="SECRET"; 4var encryptForSubmitInUse=false; 5 6/* ahmetsacan: this causes the edit toolbar to break. we moved it into action.php */ 7/* addInitEvent(function() { return(decryptEditSetup()); }); */ 8 9// the function here is borrowed from an anonymous function in 10// lib/scripts/edit.js (initChangeCheck()). 11// This should be replaced with some way that a plugin can request 12// onSubmit handlers for a given form element 13function editFormOnSubmit() { 14 // begin plugin modified code 15 // need the following to avoid 'msg is not defined' error. I'mnot sure why 16 var msg="Unsaved changes will be lost [edt].\nReally continue?"; 17 if(encryptForSubmit()===false) { return(false); } 18 // end plugin modified code 19 var rc = changeCheck(msg); 20 if(window.event) { window.event.returnValue = rc; } 21 return rc; 22} 23 24function decryptEditSetup(msg) { 25 var editform=null, wikitext=null, hiddentext=null, preview=null; 26 if(!(editform=document.getElementById('dw__editform'))) { 27 // alert("no form dw__editform\n"); 28 return(true); 29 } 30 if(!(wikitext=document.getElementById('wiki__text'))) { 31 // alert("no wiki__text"); 32 return(false); 33 } 34 // if there is no preview button, then assume this is a 35 // "Recover draft" page, dont do anything. 36 if(!(preview=document.getElementById('edbtn__preview'))) { 37 return(false); 38 } 39 40 // create a hidden element with id 'wiki__text_submit' and 41 // name wikitext_edit (same as the wiki__text. move the real 42 // wikI__text element out of the form (so it is not submitted and 43 // any <SECRET> text left unencrypted 44 if(!(hiddentext=document.createElement('input'))) { 45 return(false); 46 } 47 hiddentext.setAttribute('id', 'wiki__text_submit'); 48 hiddentext.setAttribute('name', 'wikitext'); 49 hiddentext.setAttribute('type','hidden'); 50 editform.insertBefore(hiddentext,null); 51 editform.parentNode.insertBefore(wikitext,editform); 52 53 if(!(decryptButton=document.createElement('input'))) { 54 return(false); 55 } 56 decryptButton.setAttribute('id', 'decryptButton'); 57 decryptButton.setAttribute('name', 'decryptButton'); 58 decryptButton.setAttribute('type','Button'); 59 decryptButton.setAttribute('value','DecryptSecret'); 60 // decryptButton.setAttribute('onclick',decryptEditForm); 61 decryptButton.onclick=decryptEditForm; 62 decryptButton.setAttribute('class','button'); 63 decryptButton.setAttribute('className','button'); // required for IE 64 preview.parentNode.insertBefore(decryptButton,preview); 65 66 editform.onsubmit = function() {return editFormOnSubmit();}; 67 68 // the following is taken from lib/scripts/edit.js to make drafts work 69 locktimer.refresh = function(){ 70 var now = new Date(); 71 // refresh every minute only 72 if(now.getTime() - locktimer.lasttime.getTime() > 30*1000){ //FIXME decide on time 73 var params = 'call=lock&id='+encodeURIComponent(locktimer.pageid); 74 if(locktimer.draft){ 75 var dwform = $('dw__editform'); 76 // begin plugin modified code 77 if(encryptForSubmit()===false) { return(false); } 78 // end plugin modified code 79 params += '&prefix='+encodeURIComponent(dwform.elements.prefix.value); 80 params += '&wikitext='+encodeURIComponent(dwform.elements.wikitext.value); 81 params += '&suffix='+encodeURIComponent(dwform.elements.suffix.value); 82 params += '&date='+encodeURIComponent(dwform.elements.date.value); 83 } 84 locktimer.sack.runAJAX(params); 85 locktimer.lasttime = now; 86 } 87 }; 88} 89 90function encryptForSubmit() { 91 var wikitext=null, hiddentext=null; 92 // bad semaphore like protection to avoid multiple calls to this code 93 // at once (user pushing 'Submit' and draft save running, or multiple draft 94 // save. its not really safe 95 while(encryptForSubmitInUse!==false) { 96 // wish I had sleep here 97 } 98 encryptForSubmitInUse=true; 99 100 if(!(wikitext=document.getElementById('wiki__text'))) { 101 alert("failed to get wiki__text"); 102 encryptForSubmitInUse=false; return(false); 103 } 104 if(!(hiddentext=document.getElementById('wiki__text_submit'))) { 105 alert("failed to get wiki__text_submit"); 106 encryptForSubmitInUse=false; return(false); 107 } 108 var tosubmit=encryptMixedText(wikitext.value); 109 if(tosubmit===false) { encryptForSubmitInUse=false; return(false); } 110 hiddentext.value=tosubmit; 111 encryptForSubmitInUse=false; return(true); 112} 113 114function decryptEditForm() { 115 var elem=null, newtext=""; 116 if(!(elem=document.getElementById('wiki__text'))) { 117 // alert("no form wiki__text\n"); 118 return(true); 119 } 120 if((newtext=decryptMixedText(elem.value))===false) { 121 alert("failed to decrypt wiki__text"); 122 return(false); 123 } 124 elem.value=newtext; 125 return(true); 126} 127 128function setKeyFromAscii(pass) { 129 var s = encode_utf8(pass); 130 var i, kmd5e, kmd5o; 131 132 if (s.length == 1) { 133 s += s; 134 } 135 136 md5_init(); 137 for (i = 0; i < s.length; i += 2) { 138 md5_update(s.charCodeAt(i)); 139 } 140 md5_finish(); 141 kmd5e = byteArrayToHex(digestBits); 142 143 md5_init(); 144 for (i = 1; i < s.length; i += 2) { 145 md5_update(s.charCodeAt(i)); 146 } 147 md5_finish(); 148 kmd5o = byteArrayToHex(digestBits); 149 150 var hs = kmd5e + kmd5o; 151 key = hexToByteArray(hs); 152 hs = byteArrayToHex(key); 153 return(key); 154} 155 156function toggleElemVisibility(elemid) { 157 elem=document.getElementById(elemid); 158 if(elem.style.visibility=="visible") { 159 elem.style.visibility="hidden"; 160 elem.style.position="absolute"; 161 } else { 162 elem.style.visibility="visible"; 163 elem.style.position="relative"; 164 } 165} 166 167/* 168 this is called from <A HREF=> links to decrypt the inline html 169*/ 170function toggleCryptDiv(elemid,lock,ctext) { 171 var elem=null, atab=null, key="", ptext=""; 172 var ctStr="Decrypt Encrypted Text", ptStr="Hide Plaintext"; 173 elem=document.getElementById(elemid); 174 atag=document.getElementById(elemid + "_atag"); 175 if(elem===null || atag===null) { 176 alert("failed to find element id " + elemid); 177 } 178 if(atag.innerHTML==ptStr) { 179 // encrypt text (set back to ctext, and forget key) 180 elem.innerHTML=ctext; 181 atag.innerHTML=ctStr; 182 crypt_keys[lock]=undefined; 183 } else if (atag.innerHTML==ctStr) { 184 // decrypt text 185 if((ptext=verifyDecrypt(ctext,lock,false))===false) { 186 alert("unable to find key for lock " + lock); 187 return; 188 } 189 elem.innerHTML=ptext; 190 atag.innerHTML=ptStr; 191 // make it visible 192 elem.style.visibility="visible"; 193 elem.style.position="relative"; 194 } else { alert("Broken"); return; } 195} 196 197function getEncryptionKeyForLock(lock) { 198 // alert("crypt_keys[" + lock + "]=" + crypt_keys[lock] + "\n"); 199 if(undefined===crypt_keys[lock]) { 200 var x,y; 201 x=prompt("Enter passphrase key for lock " + lock); 202 if(x===null) { return(false); } 203 y=prompt("Verify passphrase key for lock " + lock); 204 if(y===null) { return(false); } 205 if(x!=y) { crypt_debug("passwords do not match\n"); return(false); } 206 crypt_debug("x=" + x + " y=" + y); 207 crypt_keys[lock]=x; 208 return(x); 209 } else { 210 return(crypt_keys[lock]); 211 } 212} 213var debugval=""; 214function crypt_debug(str) { 215 // document.getElementById("debug_field").value+=str + "\n"; 216 debugval+=str; 217} 218/* decrypt the text between <CRYPT> and </CRYPT> */ 219function decryptMixedText(x) { 220 var tag=tag_enc; 221 var ret="", key="", ctext=""; 222 var tagend=0, opentag=0, blockend=0, pos=0; 223 while((cur=x.indexOf("<" + tag,pos))!=-1) { 224 if((opentag_end=x.indexOf(">",cur))==-1) { 225 alert("unable to close to open tag"); return(false); 226 } 227 if((closetag=x.indexOf("</" + tag + ">",opentag_end))==-1) { 228 alert("unable to find close of " + tag + " tag"); return(false); 229 } 230 if(!(ctext=decryptBlock(x.substring(cur,closetag+tag.length+3),false))) { 231 return(false); 232 } 233 ret+=x.substring(pos,cur) + ctext; 234 pos=closetag+tag.length+3; 235 } 236 ret+=x.substring(pos); 237 return(ret); 238} 239 240function encryptMixedText(x) { 241 var tag=tag_pt; 242 var ret="", key="", ctext=""; 243 var tagend=0, opentag=0, blockend=0, pos=0; 244 while((cur=x.indexOf("<" + tag,pos))!=-1) { 245 if((opentag_end=x.indexOf(">",cur))==-1) { 246 alert("unable to close to open tag"); return(false); 247 } 248 if((closetag=x.indexOf("</" + tag + ">",opentag_end))==-1) { 249 x=x+"</" + tag + ">"; 250 // if there is no close tag, add one to the end. 251 closetag=x.indexOf("</" + tag + ">",opentag_end); 252 // alert("unable to find close of " + tag + " tag"); return(false); 253 } 254 if(!(ctext=encryptBlock(x.substring(cur,closetag+tag.length+3),false))) { 255 alert("failed to encrypt text"); 256 return(false); 257 } 258 ret+=x.substring(pos,cur) + ctext; 259 pos=closetag+tag.length+3; 260 } 261 ret+=x.substring(pos); 262 return(ret); 263} 264 265function verifyDecrypt(ctext,lock,key) { 266 var ptext=null; 267 if(undefined!==crypt_keys[lock]) { key=crypt_keys[lock]; } 268 if(key===false && (undefined===crypt_keys[lock])) { 269 var key=prompt("Enter passphrase for lock " + lock); 270 if(key===null) { return(false); } // user hit cancel 271 if(!(ptext=decryptTextString(ctext,key))) { 272 var pstr="Try again: Enter passphrase for lock " + lock; 273 while(null!==(key=prompt(pstr))) { 274 ptext=decryptTextString(ctext,key); 275 if(ptext) { 276 break; 277 } 278 } 279 if(key==null) { return(false); } // user hit cancel 280 } 281 crypt_keys[lock]=key; 282 } else { 283 var xkey=key; 284 if(key===false) { xkey=crypt_keys[lock]; } 285 if(!(ptext=decryptTextString(ctext,xkey))) { 286 if(key!==false) { alert("failed to decrypt with provided key"); } 287 return(false); 288 } 289 } 290 return(ptext); 291} 292function decryptBlock(data,key) { 293 var tagend=0, ptend=0, lock=null, ptext; 294 if((tagend=data.indexOf(">"))==-1) { 295 crypt_debug("no > in " + data); 296 return(false); 297 } 298 if((ptend=data.lastIndexOf("</"))==-1) { 299 crypt_debug(" no </ in " + data); 300 return(false); 301 } 302 lock=getTagAttr(data.substring(0,tagend+1),"LOCK"); 303 if(lock===null) { lock="default"; } 304 305 collapsed=getTagAttr(data.substring(0,tagend+1),"COLLAPSED"); 306 if(collapsed===null) { collapsed="0"; } 307 308 if(!(ptext=verifyDecrypt(data.substring(tagend+1,ptend),lock,key))) { 309 return(false); 310 } 311 return("<" + tag_pt + " LOCK=" + lock + " " + 312 "COLLAPSED=" + collapsed + ">" + ptext + "</" + tag_pt + ">"); 313} 314 315// for getTagAttr("<FOO ATTR=val>","ATTR"), return "val" 316function getTagAttr(opentag,attr) { 317 var loff=0; 318 if((loff=opentag.indexOf(attr + "=" ))!=-1) { 319 if((t=opentag.indexOf(" ",loff+attr.length+1))!=-1) { 320 return(opentag.substring(loff+attr.length+1,t)); 321 } else { 322 return(opentag.substring(loff+attr.length+1,opentag.length-1)); 323 } 324 } 325 return(null); 326} 327 328function encryptBlock(data,key) { 329 var tagend=0, ptend=0, lock=null, ctext; 330 if((tagend=data.indexOf(">"))==-1) { 331 crypt_debug("no > in " + data); 332 return(false); 333 } 334 if((ptend=data.lastIndexOf("</"))==-1) { 335 crypt_debug(" no </ in " + data); 336 return(false); 337 } 338 lock=getTagAttr(data.substring(0,tagend+1),"LOCK"); 339 if(lock===null) { lock="default"; } 340 341 collapsed=getTagAttr(data.substring(0,tagend+1),"COLLAPSED"); 342 if(collapsed===null) { collapased="0"; } 343 344 if(key===false) { 345 key=getEncryptionKeyForLock(lock); 346 if(key===false) { return(false); } 347 } 348 if(!(ctext=encryptTextString(data.substring(tagend+1,ptend),key))) { 349 return(false); 350 } 351 return("<ENCRYPTED LOCK=" + lock + " " + 352 "COLLAPSED=" + collapsed + ">" + ctext + "</ENCRYPTED>"); 353} 354 355 356/* encrypt the string in text with ascii key in akey 357 modified from Encrypt_Text to expect ascii key and take input params 358 and to return base64 encoded 359*/ 360function encryptTextString(ptext,akey) { 361 var v, i, ret, key; 362 var prefix = "##### Encrypted: decrypt with "; 363 prefix+="http://www.fourmilab.ch/javascrypt/\n"; 364 suffix = "##### End encrypted message\n"; 365 366 if (akey.length === 0) { 367 alert("Please specify a key with which to encrypt the message."); 368 return; 369 } 370 if (ptext.length === 0) { 371 alert("No plain text to encrypt!"); 372 return; 373 } 374 ret=""; 375 key=setKeyFromAscii(akey); 376 377 // addEntroptyTime eventually results in setting of global entropyData 378 // which is used by keyFromEntropy 379 addEntropyTime(); 380 prng = new AESprng(keyFromEntropy()); 381 var plaintext = encode_utf8(ptext); 382 383 // Compute MD5 sum of message text and add to header 384 385 md5_init(); 386 for (i = 0; i < plaintext.length; i++) { 387 md5_update(plaintext.charCodeAt(i)); 388 } 389 md5_finish(); 390 var header = ""; 391 for (i = 0; i < digestBits.length; i++) { 392 header += String.fromCharCode(digestBits[i]); 393 } 394 395 // Add message length in bytes to header 396 397 i = plaintext.length; 398 header += String.fromCharCode(i >>> 24); 399 header += String.fromCharCode(i >>> 16); 400 header += String.fromCharCode(i >>> 8); 401 header += String.fromCharCode(i & 0xFF); 402 403 /* The format of the actual message passed to rijndaelEncrypt 404 is: 405 Bytes Content 406 0-15 MD5 signature of plaintext 407 16-19 Length of plaintext, big-endian order 408 20-end Plaintext 409 410 Note that this message will be padded with zero bytes 411 to an integral number of AES blocks (blockSizeInBits / 8). 412 This does not include the initial vector for CBC 413 encryption, which is added internally by rijndaelEncrypt. 414 */ 415 416 var ct = rijndaelEncrypt(header + plaintext, key, "CBC"); 417 delete prng; 418 return(prefix + armour_base64(ct) + suffix); 419} 420 421function decryptTextString(ctext,akey) { 422 key=setKeyFromAscii(akey); 423 var ct=[]; 424 425 // remove line breaks 426 ct=disarm_base64(ctext); 427 var result=rijndaelDecrypt(ct,key,"CBC"); 428 var header=result.slice(0,20); 429 result=result.slice(20); 430 var dl=(header[16]<<24)|(header[17]<<16)|(header[18]<<8)|header[19]; 431 432 if((dl<0)||(dl>result.length)) { 433 // alert("Message (length "+result.length+") != expected (" + dl + ")"); 434 dl=result.length; 435 } 436 437 var i,plaintext=""; 438 md5_init(); 439 440 for(i=0;i<dl;i++) { 441 plaintext+=String.fromCharCode(result[i]); 442 md5_update(result[i]); 443 } 444 445 md5_finish(); 446 447 successful = true; 448 449 for(i=0;i<digestBits.length;i++) { 450 if(digestBits[i]!=header[i]) { 451 crypt_debug("Invalid decryption key."); 452 return(false); 453 } 454 } 455 return(decode_utf8(plaintext)); 456} 457 458// BEGIN: javascript/aes.js 459// Rijndael parameters -- Valid values are 128, 192, or 256 460 461var keySizeInBits = 256; 462var blockSizeInBits = 128; 463 464// 465// Note: in the following code the two dimensional arrays are indexed as 466// you would probably expect, as array[row][column]. The state arrays 467// are 2d arrays of the form state[4][Nb]. 468 469 470// The number of rounds for the cipher, indexed by [Nk][Nb] 471var roundsArray = [ undefined, undefined, undefined, undefined,[ undefined, undefined, undefined, undefined,10, undefined, 12, undefined, 14], undefined, 472 [ undefined, undefined, undefined, undefined, 12, undefined, 12, undefined, 14], undefined, 473 [ undefined, undefined, undefined, undefined, 14, undefined, 14, undefined, 14] ]; 474 475// The number of bytes to shift by in shiftRow, indexed by [Nb][row] 476var shiftOffsets = [ undefined, undefined, undefined, undefined,[ undefined,1, 2, 3], undefined,[ undefined,1, 2, 3], undefined,[ undefined,1, 3, 4] ]; 477 478// The round constants used in subkey expansion 479var Rcon = [ 4800x01, 0x02, 0x04, 0x08, 0x10, 0x20, 4810x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 4820xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 4830x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 4840xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 ]; 485 486// Precomputed lookup table for the SBox 487var SBox = [ 488 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 489118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 490114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 491216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 492235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 493179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 494190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 495249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 496188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 49723, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 498144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 499 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 500141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 501 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 502181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 503248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 504140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 505 22 ]; 506 507// Precomputed lookup table for the inverse SBox 508var SBoxInverse = [ 509 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 510251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 511233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 512250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 513109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 514204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 515 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247, 516228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2, 517193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220, 518234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173, 519 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29, 520 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75, 521198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168, 522 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81, 523127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160, 524224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97, 525 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 526125 ]; 527 528// This method circularly shifts the array left by the number of elements 529// given in its parameter. It returns the resulting array and is used for 530// the ShiftRow step. Note that shift() and push() could be used for a more 531// elegant solution, but they require IE5.5+, so I chose to do it manually. 532 533function cyclicShiftLeft(theArray, positions) { 534 var temp = theArray.slice(0, positions); 535 theArray = theArray.slice(positions).concat(temp); 536 return theArray; 537} 538 539// Cipher parameters ... do not change these 540var Nk = keySizeInBits / 32; 541var Nb = blockSizeInBits / 32; 542var Nr = roundsArray[Nk][Nb]; 543 544// Multiplies the element "poly" of GF(2^8) by x. See the Rijndael spec. 545 546function xtime(poly) { 547 poly <<= 1; 548 return ((poly & 0x100) ? (poly ^ 0x11B) : (poly)); 549} 550 551// Multiplies the two elements of GF(2^8) together and returns the result. 552// See the Rijndael spec, but should be straightforward: for each power of 553// the indeterminant that has a 1 coefficient in x, add y times that power 554// to the result. x and y should be bytes representing elements of GF(2^8) 555 556function mult_GF256(x, y) { 557 var bit, result = 0; 558 559 for (bit = 1; bit < 256; bit *= 2, y = xtime(y)) { 560 if (x & bit) { result ^= y; } 561 } 562 return result; 563} 564 565// Performs the substitution step of the cipher. State is the 2d array of 566// state information (see spec) and direction is string indicating whether 567// we are performing the forward substitution ("encrypt") or inverse 568// substitution (anything else) 569 570function byteSub(state, direction) { 571 var S; 572 if (direction == "encrypt") { S = SBox; } // Point S to the SBox we're using 573 else { S = SBoxInverse; } 574 for (var i = 0; i < 4; i++) { // Substitute for every byte in state 575 for (var j = 0; j < Nb; j++) { state[i][j] = S[state[i][j]]; } 576 } 577} 578 579// Performs the row shifting step of the cipher. 580 581function shiftRow(state, direction) { 582 for (var i=1; i<4; i++) { // Row 0 never shifts 583 if (direction == "encrypt") { 584 state[i] = cyclicShiftLeft(state[i], shiftOffsets[Nb][i]); 585 } else { 586 state[i] = cyclicShiftLeft(state[i], Nb - shiftOffsets[Nb][i]); 587 } 588 } 589 590} 591 592// Performs the column mixing step of the cipher. Most of these steps can 593// be combined into table lookups on 32bit values (at least for encryption) 594// to greatly increase the speed. 595 596function mixColumn(state, direction) { 597 var b = []; // Result of matrix multiplications 598 var i = 0; 599 for (var j = 0; j < Nb; j++) { // Go through each column... 600 for (i = 0; i < 4; i++) { // and for each row in the column... 601 if (direction == "encrypt") { 602 b[i] = mult_GF256(state[i][j], 2) ^ // perform mixing 603 mult_GF256(state[(i+1)%4][j], 3) ^ 604 state[(i+2)%4][j] ^ 605 state[(i+3)%4][j]; 606 } else { 607 b[i] = mult_GF256(state[i][j], 0xE) ^ 608 mult_GF256(state[(i+1)%4][j], 0xB) ^ 609 mult_GF256(state[(i+2)%4][j], 0xD) ^ 610 mult_GF256(state[(i+3)%4][j], 9); 611 } 612 } 613 for (i = 0; i < 4; i++) { // Place result back into column 614 state[i][j] = b[i]; 615 } 616 } 617} 618 619// Adds the current round key to the state information. Straightforward. 620 621function addRoundKey(state, roundKey) { 622 for (var j = 0; j < Nb; j++) { // Step through columns... 623 state[0][j] ^= (roundKey[j] & 0xFF); // and XOR 624 state[1][j] ^= ((roundKey[j]>>8) & 0xFF); 625 state[2][j] ^= ((roundKey[j]>>16) & 0xFF); 626 state[3][j] ^= ((roundKey[j]>>24) & 0xFF); 627 } 628} 629 630// This function creates the expanded key from the input (128/192/256-bit) 631// key. The parameter key is an array of bytes holding the value of the key. 632// The returned value is an array whose elements are the 32-bit words that 633// make up the expanded key. 634 635function keyExpansion(key) { 636 var expandedKey = []; 637 var temp; 638 639 // in case the key size or parameters were changed... 640 Nk = keySizeInBits / 32; 641 Nb = blockSizeInBits / 32; 642 Nr = roundsArray[Nk][Nb]; 643 644 for (var j=0; j < Nk; j++) { // Fill in input key first 645 expandedKey[j] = 646 (key[4*j]) | (key[4*j+1]<<8) | (key[4*j+2]<<16) | (key[4*j+3]<<24); 647 } 648 649 // Now walk down the rest of the array filling in expanded key bytes as 650 // per Rijndael's spec 651 for (j = Nk; j < Nb * (Nr + 1); j++) { // For each word of expanded key 652 temp = expandedKey[j - 1]; 653 if (j % Nk === 0) { 654 temp = ( (SBox[(temp>>8) & 0xFF]) | 655 (SBox[(temp>>16) & 0xFF]<<8) | 656 (SBox[(temp>>24) & 0xFF]<<16) | 657 (SBox[temp & 0xFF]<<24) ) ^ Rcon[Math.floor(j / Nk) - 1]; 658 } else if (Nk > 6 && j % Nk == 4) { 659 temp = (SBox[(temp>>24) & 0xFF]<<24) | 660 (SBox[(temp>>16) & 0xFF]<<16) | 661 (SBox[(temp>>8) & 0xFF]<<8) | 662 (SBox[temp & 0xFF]); 663 } 664 expandedKey[j] = expandedKey[j-Nk] ^ temp; 665 } 666 return expandedKey; 667} 668 669// Rijndael's round functions... 670 671function jcRound(state, roundKey) { 672 byteSub(state, "encrypt"); 673 shiftRow(state, "encrypt"); 674 mixColumn(state, "encrypt"); 675 addRoundKey(state, roundKey); 676} 677 678function inverseRound(state, roundKey) { 679 addRoundKey(state, roundKey); 680 mixColumn(state, "decrypt"); 681 shiftRow(state, "decrypt"); 682 byteSub(state, "decrypt"); 683} 684 685function finalRound(state, roundKey) { 686 byteSub(state, "encrypt"); 687 shiftRow(state, "encrypt"); 688 addRoundKey(state, roundKey); 689} 690 691function inverseFinalRound(state, roundKey){ 692 addRoundKey(state, roundKey); 693 shiftRow(state, "decrypt"); 694 byteSub(state, "decrypt"); 695} 696 697// encrypt is the basic encryption function. It takes parameters 698// block, an array of bytes representing a plaintext block, and expandedKey, 699// an array of words representing the expanded key previously returned by 700// keyExpansion(). The ciphertext block is returned as an array of bytes. 701 702function encrypt(block, expandedKey) { 703 var i; 704 if (!block || block.length*8 != blockSizeInBits) { return; } 705 if (!expandedKey) { return; } 706 707 block = packBytes(block); 708 addRoundKey(block, expandedKey); 709 for (i=1; i<Nr; i++) { jcRound(block, expandedKey.slice(Nb*i, Nb*(i+1))); } 710 finalRound(block, expandedKey.slice(Nb*Nr)); 711 return unpackBytes(block); 712} 713 714// decrypt is the basic decryption function. It takes parameters 715// block, an array of bytes representing a ciphertext block, and expandedKey, 716// an array of words representing the expanded key previously returned by 717// keyExpansion(). The decrypted block is returned as an array of bytes. 718 719function decrypt(block, expandedKey) { 720 var i; 721 if (!block || block.length*8 != blockSizeInBits) { return; } 722 if (!expandedKey) { return; } 723 724 block = packBytes(block); 725 inverseFinalRound(block, expandedKey.slice(Nb*Nr)); 726 for (i = Nr - 1; i>0; i--) { 727 inverseRound(block, expandedKey.slice(Nb*i, Nb*(i+1))); 728 } 729 addRoundKey(block, expandedKey); 730 return unpackBytes(block); 731} 732 733/* !NEEDED 734// This method takes a byte array (byteArray) and converts it to a string by 735// applying String.fromCharCode() to each value and concatenating the result. 736// The resulting string is returned. Note that this function SKIPS zero bytes 737// under the assumption that they are padding added in formatPlaintext(). 738// Obviously, do not invoke this method on raw data that can contain zero 739// bytes. It is really only appropriate for printable ASCII/Latin-1 740// values. Roll your own function for more robust functionality :) 741 742function byteArrayToString(byteArray) { 743 var result = ""; 744 for(var i=0; i<byteArray.length; i++) 745 if (byteArray[i] != 0) 746 result += String.fromCharCode(byteArray[i]); 747 return result; 748} 749*/ 750 751// This function takes an array of bytes (byteArray) and converts them 752// to a hexadecimal string. Array element 0 is found at the beginning of 753// the resulting string, high nibble first. Consecutive elements follow 754// similarly, for example [16, 255] --> "10ff". The function returns a 755// string. 756 757function byteArrayToHex(byteArray) { 758 var result = ""; 759 if (!byteArray) { return; } 760 for (var i=0; i<byteArray.length; i++) { 761 result += ((byteArray[i]<16) ? "0" : "") + byteArray[i].toString(16); 762 } 763 764 return result; 765} 766 767// This function converts a string containing hexadecimal digits to an 768// array of bytes. The resulting byte array is filled in the order the 769// values occur in the string, for example "10FF" --> [16, 255]. This 770// function returns an array. 771 772function hexToByteArray(hexString) { 773 var byteArray = []; 774 if (hexString.length % 2) { return; } // must have even length 775 if (hexString.indexOf("0x") === 0 || hexString.indexOf("0X") === 0) { 776 hexString = hexString.substring(2); 777 } 778 for (var i = 0; i<hexString.length; i += 2) { 779 byteArray[Math.floor(i/2)] = parseInt(hexString.slice(i, i+2), 16); 780 } 781 return byteArray; 782} 783 784// This function packs an array of bytes into the four row form defined by 785// Rijndael. It assumes the length of the array of bytes is divisible by 786// four. Bytes are filled in according to the Rijndael spec (starting with 787// column 0, row 0 to 3). This function returns a 2d array. 788 789function packBytes(octets) { 790 var state = []; 791 if (!octets || octets.length % 4) { return; } 792 793 state[0] = []; state[1] = []; 794 state[2] = []; state[3] = []; 795 for (var j=0; j<octets.length; j+= 4) { 796 state[0][j/4] = octets[j]; 797 state[1][j/4] = octets[j+1]; 798 state[2][j/4] = octets[j+2]; 799 state[3][j/4] = octets[j+3]; 800 } 801 return state; 802} 803 804// This function unpacks an array of bytes from the four row format preferred 805// by Rijndael into a single 1d array of bytes. It assumes the input "packed" 806// is a packed array. Bytes are filled in according to the Rijndael spec. 807// This function returns a 1d array of bytes. 808 809function unpackBytes(packed) { 810 var result = []; 811 for (var j=0; j<packed[0].length; j++) { 812 result[result.length] = packed[0][j]; 813 result[result.length] = packed[1][j]; 814 result[result.length] = packed[2][j]; 815 result[result.length] = packed[3][j]; 816 } 817 return result; 818} 819 820// This function takes a prospective plaintext (string or array of bytes) 821// and pads it with pseudorandom bytes if its length is not a multiple of the block 822// size. If plaintext is a string, it is converted to an array of bytes 823// in the process. The type checking can be made much nicer using the 824// instanceof operator, but this operator is not available until IE5.0 so I 825// chose to use the heuristic below. 826 827function formatPlaintext(plaintext) { 828 var bpb = blockSizeInBits / 8; // bytes per block 829 var i; 830 831 // if primitive string or String instance 832 if ((!((typeof plaintext == "object") && 833 ((typeof (plaintext[0])) == "number"))) && 834 ((typeof plaintext == "string") || plaintext.indexOf)) { 835 plaintext = plaintext.split(""); 836 // Unicode issues here (ignoring high byte) 837 for (i=0; i<plaintext.length; i++) { 838 plaintext[i] = plaintext[i].charCodeAt(0) & 0xFF; 839 } 840 } 841 842 i = plaintext.length % bpb; 843 if (i > 0) { 844 plaintext = plaintext.concat(getRandomBytes(bpb - i)); 845 } 846 847 return plaintext; 848} 849 850// Returns an array containing "howMany" random bytes. 851 852function getRandomBytes(howMany) { 853 var i, bytes = []; 854 855 for (i = 0; i < howMany; i++) { 856 bytes[i] = prng.nextInt(255); 857 } 858 return bytes; 859} 860 861// rijndaelEncrypt(plaintext, key, mode) 862// Encrypts the plaintext using the given key and in the given mode. 863// The parameter "plaintext" can either be a string or an array of bytes. 864// The parameter "key" must be an array of key bytes. If you have a hex 865// string representing the key, invoke hexToByteArray() on it to convert it 866// to an array of bytes. The third parameter "mode" is a string indicating 867// the encryption mode to use, either "ECB" or "CBC". If the parameter is 868// omitted, ECB is assumed. 869// 870// An array of bytes representing the cihpertext is returned. To convert 871// this array to hex, invoke byteArrayToHex() on it. 872 873function rijndaelEncrypt(plaintext, key, mode) { 874 var expandedKey, i, aBlock; 875 var bpb = blockSizeInBits / 8; // bytes per block 876 var ct; // ciphertext 877 878 if (!plaintext || !key) { return; } 879 if (key.length*8 != keySizeInBits) { return; } 880 if (mode == "CBC") { 881 ct = getRandomBytes(bpb); // get IV 882//dump("IV", byteArrayToHex(ct)); 883 } else { 884 mode = "ECB"; 885 ct = []; 886 } 887 888 // convert plaintext to byte array and pad with zeros if necessary. 889 plaintext = formatPlaintext(plaintext); 890 891 expandedKey = keyExpansion(key); 892 893 for (var block = 0; block < plaintext.length / bpb; block++) { 894 aBlock = plaintext.slice(block * bpb, (block + 1) * bpb); 895 if (mode == "CBC") { 896 for (i = 0; i < bpb; i++) { 897 aBlock[i] ^= ct[(block * bpb) + i]; 898 } 899 } 900 ct = ct.concat(encrypt(aBlock, expandedKey)); 901 } 902 903 return ct; 904} 905 906// rijndaelDecrypt(ciphertext, key, mode) 907// Decrypts the using the given key and mode. The parameter "ciphertext" 908// must be an array of bytes. The parameter "key" must be an array of key 909// bytes. If you have a hex string representing the ciphertext or key, 910// invoke hexToByteArray() on it to convert it to an array of bytes. The 911// parameter "mode" is a string, either "CBC" or "ECB". 912// 913// An array of bytes representing the plaintext is returned. To convert 914// this array to a hex string, invoke byteArrayToHex() on it. To convert it 915// to a string of characters, you can use byteArrayToString(). 916 917function rijndaelDecrypt(ciphertext, key, mode) { 918 var expandedKey; 919 var bpb = blockSizeInBits / 8; // bytes per block 920 var pt = []; // plaintext array 921 var aBlock; // a decrypted block 922 var block; // current block number 923 924 if (!ciphertext || !key || typeof ciphertext == "string") { return; } 925 if (key.length*8 != keySizeInBits) { return; } 926 if (!mode) { mode = "ECB"; } // assume ECB if mode omitted 927 928 expandedKey = keyExpansion(key); 929 930 // work backwards to accomodate CBC mode 931 for (block=(ciphertext.length / bpb)-1; block>0; block--) { 932 aBlock = 933 decrypt(ciphertext.slice(block*bpb,(block+1)*bpb), expandedKey); 934 if (mode == "CBC") { 935 for (var i=0; i<bpb; i++) { 936 pt[(block-1)*bpb + i] = aBlock[i] ^ ciphertext[(block-1)*bpb + i]; 937 } 938 } else { 939 pt = aBlock.concat(pt); 940 } 941 } 942 943 // do last block if ECB (skips the IV in CBC) 944 if (mode == "ECB") { 945 pt = decrypt(ciphertext.slice(0, bpb), expandedKey).concat(pt); 946 } 947 948 return pt; 949} 950 951// END: javascrypt/aes.js 952// BEGIN: javascrypt/entropy.js 953 954// Entropy collection utilities 955 956/* Start by declaring static storage and initialise 957 the entropy vector from the time we come through 958 here. */ 959 960var entropyData = []; // Collected entropy data 961var edlen = 0; // Keyboard array data length 962 963addEntropyTime(); // Start entropy collection with page load time 964ce(); // Roll milliseconds into initial entropy 965 966// Add a byte to the entropy vector 967 968function addEntropyByte(b) { 969 entropyData[edlen++] = b; 970} 971 972/* Capture entropy. When the user presses a key or performs 973 various other events for which we can request 974 notification, add the time in 255ths of a second to the 975 entropyData array. The name of the function is short 976 so it doesn't bloat the form object declarations in 977 which it appears in various "onXXX" events. */ 978 979function ce() { 980 addEntropyByte(Math.floor((((new Date()).getMilliseconds()) * 255) / 999)); 981} 982 983// Add a 32 bit quantity to the entropy vector 984 985function addEntropy32(w) { 986 var i; 987 988 for (i = 0; i < 4; i++) { 989 addEntropyByte(w & 0xFF); 990 w >>= 8; 991 } 992} 993 994/* Add the current time and date (milliseconds since the epoch, 995 truncated to 32 bits) to the entropy vector. */ 996 997function addEntropyTime() { 998 addEntropy32((new Date()).getTime()); 999} 1000/* Start collection of entropy from mouse movements. The 1001 argument specifies the number of entropy items to be 1002 obtained from mouse motion, after which mouse motion 1003 will be ignored. Note that you can re-enable mouse 1004 motion collection at any time if not already underway. */ 1005 1006var mouseMotionCollect = 0; 1007var oldMoveHandler; // For saving and restoring mouse move handler in IE4 1008 1009function mouseMotionEntropy(maxsamp) { 1010 if (mouseMotionCollect <= 0) { 1011 mouseMotionCollect = maxsamp; 1012 if ((document.implementation.hasFeature("Events", "2.0")) && 1013 document.addEventListener) { 1014 // Browser supports Document Object Model (DOM) 2 events 1015 document.addEventListener("mousemove", mouseMoveEntropy, false); 1016 } else { 1017 if (document.attachEvent) { 1018 // Internet Explorer 5 and above event model 1019 document.attachEvent("onmousemove", mouseMoveEntropy); 1020 } else { 1021 // Internet Explorer 4 event model 1022 oldMoveHandler = document.onmousemove; 1023 document.onmousemove = mouseMoveEntropy; 1024 } 1025 } 1026 //dump("Mouse enable", mouseMotionCollect); 1027 } 1028} 1029 1030/* Collect entropy from mouse motion events. Note that 1031 this is craftily coded to work with either DOM2 or Internet 1032 Explorer style events. Note that we don't use every successive 1033 mouse movement event. Instead, we XOR the three bytes collected 1034 from the mouse and use that to determine how many subsequent 1035 mouse movements we ignore before capturing the next one. */ 1036 1037var mouseEntropyTime = 0; // Delay counter for mouse entropy collection 1038 1039function mouseMoveEntropy(e) { 1040 if (!e) { 1041 e = window.event; // Internet Explorer event model 1042 } 1043 if (mouseMotionCollect > 0) { 1044 if (mouseEntropyTime-- <= 0) { 1045 addEntropyByte(e.screenX & 0xFF); 1046 addEntropyByte(e.screenY & 0xFF); 1047 ce(); 1048 mouseMotionCollect--; 1049 mouseEntropyTime = (entropyData[edlen - 3] ^ entropyData[edlen - 2] ^ 1050 entropyData[edlen - 1]) % 19; 1051 //dump("Mouse Move", byteArrayToHex(entropyData.slice(-3))); 1052 } 1053 if (mouseMotionCollect <= 0) { 1054 if (document.removeEventListener) { 1055 document.removeEventListener("mousemove", mouseMoveEntropy, false); 1056 } else if (document.detachEvent) { 1057 document.detachEvent("onmousemove", mouseMoveEntropy); 1058 } else { 1059 document.onmousemove = oldMoveHandler; 1060 } 1061 //dump("Spung!", 0); 1062 } 1063 } 1064} 1065 1066/* Compute a 32 byte key value from the entropy vector. 1067 We compute the value by taking the MD5 sum of the even 1068 and odd bytes respectively of the entropy vector, then 1069 concatenating the two MD5 sums. */ 1070 1071function keyFromEntropy() { 1072 var i, k = []; 1073 1074 if (edlen === 0) { 1075 alert("Blooie! Entropy vector void at call to keyFromEntropy."); 1076 } 1077 //dump("Entropy bytes", edlen); 1078 1079 md5_init(); 1080 for (i = 0; i < edlen; i += 2) { 1081 md5_update(entropyData[i]); 1082 } 1083 md5_finish(); 1084 for (i = 0; i < 16; i++) { 1085 k[i] = digestBits[i]; 1086 } 1087 1088 md5_init(); 1089 for (i = 1; i < edlen; i += 2) { 1090 md5_update(entropyData[i]); 1091 } 1092 md5_finish(); 1093 for (i = 0; i < 16; i++) { 1094 k[i + 16] = digestBits[i]; 1095 } 1096 1097 //dump("keyFromEntropy", byteArrayToHex(k)); 1098 return k; 1099} 1100// END: javascrypt/entropy.js 1101// BEGIN: javascrypt/aesprng.js 1102// AES based pseudorandom number generator 1103 1104/* Constructor. Called with an array of 32 byte (0-255) values 1105 containing the initial seed. */ 1106 1107function AESprng(seed) { 1108 this.key = []; 1109 this.key = seed; 1110 this.itext = hexToByteArray("9F489613248148F9C27945C6AE62EECA3E3367BB14064E4E6DC67A9F28AB3BD1"); 1111 this.nbytes = 0; // Bytes left in buffer 1112 1113 this.next = AESprng_next; 1114 this.nextbits = AESprng_nextbits; 1115 this.nextInt = AESprng_nextInt; 1116 this.round = AESprng_round; 1117 1118 /* Encrypt the initial text with the seed key 1119 three times, feeding the output of the encryption 1120 back into the key for the next round. */ 1121 1122 bsb = blockSizeInBits; 1123 blockSizeInBits = 256; 1124 var i, ct; 1125 for (i = 0; i < 3; i++) { 1126 this.key = rijndaelEncrypt(this.itext, this.key, "ECB"); 1127 } 1128 1129 /* Now make between one and four additional 1130 key-feedback rounds, with the number determined 1131 by bits from the result of the first three 1132 rounds. */ 1133 1134 var n = 1 + (this.key[3] & 2) + (this.key[9] & 1); 1135 for (i = 0; i < n; i++) { 1136 this.key = rijndaelEncrypt(this.itext, this.key, "ECB"); 1137 } 1138 blockSizeInBits = bsb; 1139} 1140 1141function AESprng_round() { 1142 bsb = blockSizeInBits; 1143 blockSizeInBits = 256; 1144 this.key = rijndaelEncrypt(this.itext, this.key, "ECB"); 1145 this.nbytes = 32; 1146 blockSizeInBits = bsb; 1147} 1148 1149// Return next byte from the generator 1150function AESprng_next() { 1151 if (this.nbytes <= 0) { 1152 this.round(); 1153 } 1154 return(this.key[--this.nbytes]); 1155} 1156 1157// Return n bit integer value (up to maximum integer size) 1158function AESprng_nextbits(n) { 1159 var i, w = 0, nbytes = Math.floor((n + 7) / 8); 1160 1161 for (i = 0; i < nbytes; i++) { 1162 w = (w << 8) | this.next(); 1163 } 1164 return w & ((1 << n) - 1); 1165} 1166 1167// Return integer between 0 and n inclusive 1168function AESprng_nextInt(n) { 1169 var p = 1, nb = 0; 1170 1171 // Determine smallest p, 2^p > n 1172 // nb = log_2 p 1173 1174 while (n >= p) { 1175 p <<= 1; 1176 nb++; 1177 } 1178 p--; 1179 1180 /* Generate values from 0 through n by first generating 1181 values v from 0 to (2^p)-1, then discarding any results v > n. 1182 For the rationale behind this (and why taking 1183 values mod (n + 1) is biased toward smaller values, see 1184 Ferguson and Schneier, "Practical Cryptography", 1185 ISBN 0-471-22357-3, section 10.8). */ 1186 1187 while (true) { 1188 var v = this.nextbits(nb) & p; 1189 1190 if (v <= n) { 1191 return v; 1192 } 1193 } 1194} 1195// END: javascrypt/aesprng.js 1196// BEGIN: javascrypt/lecuyer.js 1197/* 1198 L'Ecuyer's two-sequence generator with a Bays-Durham shuffle 1199 on the back-end. Schrage's algorithm is used to perform 1200 64-bit modular arithmetic within the 32-bit constraints of 1201 JavaScript. 1202 1203 Bays, C. and S. D. Durham. ACM Trans. Math. Software: 2 (1976) 1204 59-64. 1205 1206 L'Ecuyer, P. Communications of the ACM: 31 (1968) 742-774. 1207 1208 Schrage, L. ACM Trans. Math. Software: 5 (1979) 132-138. 1209 1210*/ 1211 1212// Schrage's modular multiplication algorithm 1213function uGen(old, a, q, r, m) { 1214 var t; 1215 1216 t = Math.floor(old / q); 1217 t = a * (old - (t * q)) - (t * r); 1218 return Math.round((t < 0) ? (t + m) : t); 1219} 1220 1221// Return next raw value 1222function LEnext() { 1223 var i; 1224 1225 this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); 1226 this.gen2 = uGen(this.gen2, 40692, 52774, 3791, 2147483399); 1227 1228 /* Extract shuffle table index from most significant part 1229 of the previous result. */ 1230 1231 i = Math.floor(this.state / 67108862); 1232 1233 // New state is sum of generators modulo one of their moduli 1234 1235 this.state = Math.round((this.shuffle[i] + this.gen2) % 2147483563); 1236 1237 // Replace value in shuffle table with generator 1 result 1238 1239 this.shuffle[i] = this.gen1; 1240 1241 return this.state; 1242} 1243 1244// Return next random integer between 0 and n inclusive 1245 1246function LEnint(n) { 1247 var p = 1; 1248 1249 // Determine smallest p, 2^p > n 1250 1251 while (n >= p) { 1252 p <<= 1; 1253 } 1254 p--; 1255 1256 /* Generate values from 0 through n by first masking 1257 values v from 0 to (2^p)-1, then discarding any results v > n. 1258 For the rationale behind this (and why taking 1259 values mod (n + 1) is biased toward smaller values, see 1260 Ferguson and Schneier, "Practical Cryptography", 1261 ISBN 0-471-22357-3, section 10.8). */ 1262 1263 while (true) { 1264 var v = this.next() & p; 1265 1266 if (v <= n) { 1267 return v; 1268 } 1269 } 1270} 1271 1272// Constructor. Called with seed value 1273function LEcuyer(s) { 1274 var i; 1275 1276 this.shuffle = []; 1277 this.gen1 = this.gen2 = (s & 0x7FFFFFFF); 1278 for (i = 0; i < 19; i++) { 1279 this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); 1280 } 1281 1282 // Fill the shuffle table with values 1283 1284 for (i = 0; i < 32; i++) { 1285 this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); 1286 this.shuffle[31 - i] = this.gen1; 1287 } 1288 this.state = this.shuffle[0]; 1289 this.next = LEnext; 1290 this.nextInt = LEnint; 1291} 1292// END: javascrypt/lecuyer.js 1293// BEGIN: javascrypt/md5.js 1294function array(n) { 1295 for (i = 0; i < n; i++) { 1296 this[i] = 0; 1297 } 1298 this.length = n; 1299} 1300 1301/* Some basic logical functions had to be rewritten because of a bug in 1302 * Javascript.. Just try to compute 0xffffffff >> 4 with it.. 1303 * Of course, these functions are slower than the original would be, but 1304 * at least, they work! 1305 */ 1306 1307function integer(n) { 1308 return n % (0xffffffff + 1); 1309} 1310 1311function shr(a, b) { 1312 a = integer(a); 1313 b = integer(b); 1314 if (a - 0x80000000 >= 0) { 1315 a = a % 0x80000000; 1316 a >>= b; 1317 a += 0x40000000 >> (b - 1); 1318 } else { 1319 a >>= b; 1320 } 1321 return a; 1322} 1323 1324function shl1(a) { 1325 a = a % 0x80000000; 1326 if (a & 0x40000000 == 0x40000000) { 1327 a -= 0x40000000; 1328 a *= 2; 1329 a += 0x80000000; 1330 } else { 1331 a *= 2; 1332 } 1333 return a; 1334} 1335 1336function shl(a, b) { 1337 a = integer(a); 1338 b = integer(b); 1339 for (var i = 0; i < b; i++) { 1340 a = shl1(a); 1341 } 1342 return a; 1343} 1344 1345function and(a, b) { 1346 a = integer(a); 1347 b = integer(b); 1348 var t1 = a - 0x80000000; 1349 var t2 = b - 0x80000000; 1350 if (t1 >= 0) { 1351 if (t2 >= 0) { 1352 return ((t1 & t2) + 0x80000000); 1353 } else { 1354 return (t1 & b); 1355 } 1356 } else { 1357 if (t2 >= 0) { 1358 return (a & t2); 1359 } else { 1360 return (a & b); 1361 } 1362 } 1363} 1364 1365function or(a, b) { 1366 a = integer(a); 1367 b = integer(b); 1368 var t1 = a - 0x80000000; 1369 var t2 = b - 0x80000000; 1370 if (t1 >= 0) { 1371 if (t2 >= 0) { 1372 return ((t1 | t2) + 0x80000000); 1373 } else { 1374 return ((t1 | b) + 0x80000000); 1375 } 1376 } else { 1377 if (t2 >= 0) { 1378 return ((a | t2) + 0x80000000); 1379 } else { 1380 return (a | b); 1381 } 1382 } 1383} 1384 1385function xor(a, b) { 1386 a = integer(a); 1387 b = integer(b); 1388 var t1 = a - 0x80000000; 1389 var t2 = b - 0x80000000; 1390 if (t1 >= 0) { 1391 if (t2 >= 0) { 1392 return (t1 ^ t2); 1393 } else { 1394 return ((t1 ^ b) + 0x80000000); 1395 } 1396 } else { 1397 if (t2 >= 0) { 1398 return ((a ^ t2) + 0x80000000); 1399 } else { 1400 return (a ^ b); 1401 } 1402 } 1403} 1404 1405function not(a) { 1406 a = integer(a); 1407 return 0xffffffff - a; 1408} 1409 1410/* Here begin the real algorithm */ 1411 1412var state = []; 1413var count = []; 1414 count[0] = 0; 1415 count[1] = 0; 1416var buffer = []; 1417var transformBuffer = []; 1418var digestBits = []; 1419 1420var S11 = 7; 1421var S12 = 12; 1422var S13 = 17; 1423var S14 = 22; 1424var S21 = 5; 1425var S22 = 9; 1426var S23 = 14; 1427var S24 = 20; 1428var S31 = 4; 1429var S32 = 11; 1430var S33 = 16; 1431var S34 = 23; 1432var S41 = 6; 1433var S42 = 10; 1434var S43 = 15; 1435var S44 = 21; 1436 1437function jcF(x, y, z) { 1438 return or(and(x, y), and(not(x), z)); 1439} 1440 1441function jcG(x, y, z) { 1442 return or(and(x, z), and(y, not(z))); 1443} 1444 1445function jcH(x, y, z) { 1446 return xor(xor(x, y), z); 1447} 1448 1449function jcI(x, y, z) { 1450 return xor(y ,or(x , not(z))); 1451} 1452 1453function rotateLeft(a, n) { 1454 return or(shl(a, n), (shr(a, (32 - n)))); 1455} 1456 1457function jcFF(a, b, c, d, x, s, ac) { 1458 a = a + jcF(b, c, d) + x + ac; 1459 a = rotateLeft(a, s); 1460 a = a + b; 1461 return a; 1462} 1463 1464function jcGG(a, b, c, d, x, s, ac) { 1465 a = a + jcG(b, c, d) + x + ac; 1466 a = rotateLeft(a, s); 1467 a = a + b; 1468 return a; 1469} 1470 1471function jcHH(a, b, c, d, x, s, ac) { 1472 a = a + jcH(b, c, d) + x + ac; 1473 a = rotateLeft(a, s); 1474 a = a + b; 1475 return a; 1476} 1477 1478function jcII(a, b, c, d, x, s, ac) { 1479 a = a + jcI(b, c, d) + x + ac; 1480 a = rotateLeft(a, s); 1481 a = a + b; 1482 return a; 1483} 1484 1485function transform(buf, offset) { 1486 var a = 0, b = 0, c = 0, d = 0; 1487 var x = transformBuffer; 1488 1489 a = state[0]; 1490 b = state[1]; 1491 c = state[2]; 1492 d = state[3]; 1493 1494 for (i = 0; i < 16; i++) { 1495 x[i] = and(buf[i * 4 + offset], 0xFF); 1496 for (j = 1; j < 4; j++) { 1497 x[i] += shl(and(buf[i * 4 + j + offset] ,0xFF), j * 8); 1498 } 1499 } 1500 1501 /* Round 1 */ 1502 a = jcFF( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 1503 d = jcFF( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 1504 c = jcFF( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 1505 b = jcFF( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 1506 a = jcFF( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 1507 d = jcFF( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 1508 c = jcFF( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 1509 b = jcFF( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 1510 a = jcFF( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 1511 d = jcFF( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 1512 c = jcFF( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 1513 b = jcFF( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 1514 a = jcFF( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 1515 d = jcFF( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 1516 c = jcFF( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 1517 b = jcFF( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 1518 1519 /* Round 2 */ 1520 a = jcGG( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 1521 d = jcGG( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 1522 c = jcGG( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 1523 b = jcGG( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 1524 a = jcGG( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 1525 d = jcGG( d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 1526 c = jcGG( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 1527 b = jcGG( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 1528 a = jcGG( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 1529 d = jcGG( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 1530 c = jcGG( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 1531 b = jcGG( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 1532 a = jcGG( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 1533 d = jcGG( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 1534 c = jcGG( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 1535 b = jcGG( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 1536 1537 /* Round 3 */ 1538 a = jcHH( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 1539 d = jcHH( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 1540 c = jcHH( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 1541 b = jcHH( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 1542 a = jcHH( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 1543 d = jcHH( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 1544 c = jcHH( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 1545 b = jcHH( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 1546 a = jcHH( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 1547 d = jcHH( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 1548 c = jcHH( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 1549 b = jcHH( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 1550 a = jcHH( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 1551 d = jcHH( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 1552 c = jcHH( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 1553 b = jcHH( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 1554 1555 /* Round 4 */ 1556 a = jcII( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 1557 d = jcII( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 1558 c = jcII( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 1559 b = jcII( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 1560 a = jcII( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 1561 d = jcII( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 1562 c = jcII( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 1563 b = jcII( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 1564 a = jcII( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 1565 d = jcII( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 1566 c = jcII( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 1567 b = jcII( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 1568 a = jcII( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 1569 d = jcII( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 1570 c = jcII( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 1571 b = jcII( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 1572 1573 state[0] += a; 1574 state[1] += b; 1575 state[2] += c; 1576 state[3] += d; 1577 1578} 1579 1580function md5_init() { 1581 count[0] = count[1] = 0; 1582 state[0] = 0x67452301; 1583 state[1] = 0xefcdab89; 1584 state[2] = 0x98badcfe; 1585 state[3] = 0x10325476; 1586 for (i = 0; i < digestBits.length; i++) { 1587 digestBits[i] = 0; 1588 } 1589} 1590 1591function md5_update(b) { 1592 var index, i; 1593 1594 index = and(shr(count[0],3) , 0x3F); 1595 if (count[0] < 0xFFFFFFFF - 7) { 1596 count[0] += 8; 1597 } else { 1598 count[1]++; 1599 count[0] -= 0xFFFFFFFF + 1; 1600 count[0] += 8; 1601 } 1602 buffer[index] = and(b, 0xff); 1603 if (index >= 63) { 1604 transform(buffer, 0); 1605 } 1606} 1607 1608function md5_finish() { 1609 var bits = []; 1610 var padding; 1611 var i = 0, index = 0, padLen = 0; 1612 1613 for (i = 0; i < 4; i++) { 1614 bits[i] = and(shr(count[0], (i * 8)), 0xFF); 1615 } 1616 for (i = 0; i < 4; i++) { 1617 bits[i + 4] = and(shr(count[1], (i * 8)), 0xFF); 1618 } 1619 index = and(shr(count[0], 3), 0x3F); 1620 padLen = (index < 56) ? (56 - index) : (120 - index); 1621 padding = []; 1622 padding[0] = 0x80; 1623 for (i = 0; i < padLen; i++) { 1624 md5_update(padding[i]); 1625 } 1626 for (i = 0; i < 8; i++) { 1627 md5_update(bits[i]); 1628 } 1629 1630 for (i = 0; i < 4; i++) { 1631 for (j = 0; j < 4; j++) { 1632 digestBits[i * 4 + j] = and(shr(state[i], (j * 8)) , 0xFF); 1633 } 1634 } 1635} 1636 1637/* End of the MD5 algorithm */ 1638// END: javascyprt/md5.js 1639// BEGIN: javscrypt/armour.js 1640 1641// Varieties of ASCII armour for binary data 1642 1643var maxLineLength = 64; // Maximum line length for armoured text 1644 1645/* Hexadecimal Armour 1646 1647 A message is encoded in Hexadecimal armour by expressing its 1648 bytes as a hexadecimal string which is prefixed by a sentinel 1649 of "?HX?" and suffixed by "?H", then broken into lines no 1650 longer than maxLineLength. Armoured messages use lower case 1651 letters for digits with decimal values of 0 through 15, but 1652 either upper or lower case letters are accepted when decoding 1653 a message. The hexadecimal to byte array interconversion 1654 routines in aes.js do most of the heavy lifting here. */ 1655 1656var hexSentinel = "?HX?", hexEndSentinel = "?H"; 1657 1658// Encode byte array in hexadecimal armour 1659 1660function armour_hex(b) { 1661 var h = hexSentinel + byteArrayToHex(b) + hexEndSentinel; 1662 var t = ""; 1663 while (h.length > maxLineLength) { 1664 //dump("h.length", h.length); 1665 t += h.substring(0, maxLineLength) + "\n"; 1666 h = h.substring(maxLineLength, h.length); 1667 } 1668 //dump("h.final_length", h.length); 1669 t += h + "\n"; 1670 return t; 1671} 1672 1673/* Decode string in hexadecimal armour to byte array. If the 1674 string supplied contains a start and/or end sentinel, 1675 only characters within the sentinels will be decoded. 1676 Non-hexadecimal digits are silently ignored, which 1677 automatically handles line breaks. We might want to 1678 diagnose invalid characters as opposed to ignoring them. */ 1679 1680function disarm_hex(s) { 1681 var hexDigits = "0123456789abcdefABCDEF"; 1682 var hs = "", i; 1683 1684 // Extract hexadecimal data between sentinels, if present 1685 if ((i = s.indexOf(hexSentinel)) >= 0) { 1686 s = s.substring(i + hexSentinel.length, s.length); 1687 } 1688 if ((i = s.indexOf(hexEndSentinel)) >= 0) { 1689 s = s.substring(0, i); 1690 } 1691 1692 // Assemble string of valid hexadecimal digits 1693 1694 for (i = 0; i < s.length; i++) { 1695 var c = s.charAt(i); 1696 if (hexDigits.indexOf(c) >= 0) { 1697 hs += c; 1698 } 1699 } 1700//dump("hs", hs); 1701 return hexToByteArray(hs); 1702} 1703 1704 /* Codegroup Armour 1705 Codegroup armour encodes a byte string into a sequence of five 1706 letter code groups like spies used in the good old days. The 1707 first group of a message is always "ZZZZZ" and the last "YYYYY"; 1708 the decoding process ignores any text outside these start and 1709 end sentinels. Bytes are encoded as two letters in the range 1710 "A" to "X", each encoding four bits of the byte. Encoding uses 1711 a pseudorandomly generated base letter and wraps around modulo 1712 24 to spread encoded letters evenly through the alphabet. (This 1713 refinement is purely aesthetic; the base letter sequence is 1714 identical for all messages and adds no security. If the message 1715 does not fill an even number of five letter groups, the last 1716 group is padded to five letters with "Z" characters, which are 1717 ignored when decoding. */ 1718 1719var acgcl, acgt, acgg; 1720 1721// Output next codegroup, flushing current line if it's full 1722 1723function armour_cg_outgroup() { 1724 if (acgcl.length > maxLineLength) { 1725 acgt += acgcl + "\n"; 1726 acgcl = ""; 1727 } 1728 if (acgcl.length > 0) { 1729 acgcl += " "; 1730 } 1731 acgcl += acgg; 1732 acgg = ""; 1733} 1734 1735/* Add a letter to the current codegroup, emitting it when 1736 it reaches five letters. */ 1737 1738function armour_cg_outletter(l) { 1739 if (acgg.length >= 5) { 1740 armour_cg_outgroup(); 1741 } 1742 acgg += l; 1743} 1744 1745var codegroupSentinel = "ZZZZZ"; 1746 1747function armour_codegroup(b) { 1748 var charBase = ("A").charCodeAt(0); 1749 1750 acgcl = codegroupSentinel; 1751 acgt = ""; 1752 acgg = ""; 1753 1754 var cgrng = new LEcuyer(0xbadf00d); 1755 for (i = 0; i < b.length; i++) { 1756 var r = cgrng.nextInt(23); 1757 armour_cg_outletter(String.fromCharCode(charBase + ((((b[i] >> 4) & 0xF)) + r) % 24)); 1758 r = cgrng.nextInt(23); 1759 armour_cg_outletter(String.fromCharCode(charBase + ((((b[i] & 0xF)) + r) % 24))); 1760 } 1761 delete cgrng; 1762 1763 // Generate nulls to fill final codegroup if required 1764 1765 while (acgg.length < 5) { 1766 armour_cg_outletter("Z"); 1767 } 1768 armour_cg_outgroup(); 1769 1770 // Append terminator group 1771 1772 acgg = "YYYYY"; 1773 armour_cg_outgroup(); 1774 1775 // Flush last line 1776 1777 acgt += acgcl + "\n"; 1778 1779 return acgt; 1780} 1781 1782var dcgs, dcgi; 1783 1784 /* Obtain next "significant" character from message. Characters 1785 other than letters are silently ignored; both lower and upper 1786 case letters are accepted. */ 1787 1788function disarm_cg_insig() { 1789 while (dcgi < dcgs.length) { 1790 var c = dcgs.charAt(dcgi++).toUpperCase(); 1791 if ((c >= "A") && (c <= "Z")) { 1792 //dump("c", c); 1793 return c; 1794 } 1795 } 1796 return ""; 1797} 1798 1799// Decode a message in codegroup armour 1800 1801function disarm_codegroup(s) { 1802 var b = []; 1803 var nz = 0, ba, bal = 0, c; 1804 1805 dcgs = s; 1806 dcgi = 0; 1807 1808 // Search for initial group of "ZZZZZ" 1809 1810 while (nz < 5) { 1811 c = disarm_cg_insig(); 1812 1813 if (c == "Z") { 1814 nz++; 1815 } else if (c === "") { 1816 nz = 0; 1817 break; 1818 } else { 1819 nz = 0; 1820 } 1821 } 1822 1823 if (nz === 0) { 1824 alert("No codegroup starting symbol found in message."); 1825 return ""; 1826 } 1827 1828 /* Decode letter pairs from successive groups 1829 and assemble into bytes. */ 1830 1831 var charBase = ("A").charCodeAt(0); 1832 var cgrng = new LEcuyer(0xbadf00d); 1833 for (nz = 0; nz < 2; ) { 1834 c = disarm_cg_insig(); 1835 //dump("c", c); 1836 1837 if ((c == "Y") || (c === "")) { 1838 break; 1839 } else if (c != "Z") { 1840 var r = cgrng.nextInt(23); 1841 var n = c.charCodeAt(0) - charBase; 1842 n = (n + (24 - r)) % 24; 1843 //dump("n", n); 1844 if (nz === 0) { 1845 ba = (n << 4); 1846 nz++; 1847 } else { 1848 ba |= n; 1849 b[bal++] = ba; 1850 nz = 0; 1851 } 1852 } 1853 } 1854 delete cgrng; 1855 1856 /* Ponder how we escaped from the decoder loop and 1857 issue any requisite warnings. */ 1858 1859 var kbo = " Attempting decoding with data received."; 1860 if (nz !== 0) { 1861 alert("Codegroup data truncated." + kbo); 1862 } else { 1863 if (c == "Y") { 1864 nz = 1; 1865 while (nz < 5) { 1866 c = disarm_cg_insig(); 1867 if (c != "Y") { 1868 break; 1869 } 1870 nz++; 1871 } 1872 if (nz != 5) { 1873 alert("Codegroup end group incomplete." + kbo); 1874 } 1875 } else { 1876 alert("Codegroup end group missing." + kbo); 1877 } 1878 } 1879 1880 return b; 1881} 1882 1883 /* Base64 Armour 1884 1885 Base64 armour encodes a byte array as described in RFC 1341. Sequences 1886 of three bytes are encoded into groups of four characters from a set 1887 of 64 consisting of the upper and lower case letters, decimal digits, 1888 and the special characters "+" and "/". If the input is not a multiple 1889 of three characters, the end of the message is padded with one or two 1890 "=" characters to indicate its actual length. We prefix the armoured 1891 message with "?b64" and append "?64b" to the end; if one or both 1892 of these sentinels are present, text outside them is ignored. You can 1893 suppress the generation of sentinels in armour by setting base64addsent 1894 false before calling armour_base64. */ 1895 1896 1897var base64code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 1898 base64sent = "?b64", base64esent = "?64b", base64addsent = true; 1899 1900function armour_base64(b) { 1901 var b64t = ""; 1902 var b64l = base64addsent ? base64sent : ""; 1903 1904 var i; 1905 for (i = 0; i <= b.length - 3; i += 3) { 1906 if ((b64l.length + 4) > maxLineLength) { 1907 b64t += b64l + "\n"; 1908 b64l = ""; 1909 } 1910 b64l += base64code.charAt(b[i] >> 2); 1911 b64l += base64code.charAt(((b[i] & 3) << 4) | (b[i + 1] >> 4)); 1912 b64l += base64code.charAt(((b[i + 1] & 0xF) << 2) | (b[i + 2] >> 6)); 1913 b64l += base64code.charAt(b[i + 2] & 0x3F); 1914 } 1915 1916 //dump("b.length", b.length); dump("i", i); dump("(b.length - i)", (b.length - i)); 1917 if ((b.length - i) == 1) { 1918 b64l += base64code.charAt(b[i] >> 2); 1919 b64l += base64code.charAt(((b[i] & 3) << 4)); 1920 b64l += "=="; 1921 } else if ((b.length - i) == 2) { 1922 b64l += base64code.charAt(b[i] >> 2); 1923 b64l += base64code.charAt(((b[i] & 3) << 4) | (b[i + 1] >> 4)); 1924 b64l += base64code.charAt(((b[i + 1] & 0xF) << 2)); 1925 b64l += "="; 1926 } 1927 1928 if ((b64l.length + 4) > maxLineLength) { 1929 b64t += b64l + "\n"; 1930 b64l = ""; 1931 } 1932 if (base64addsent) { 1933 b64l += base64esent; 1934 } 1935 b64t += b64l + "\n"; 1936 return b64t; 1937} 1938 1939function disarm_base64(s) { 1940 var b = []; 1941 var i = 0, j, c, shortgroup = 0, n = 0; 1942 var d = []; 1943 1944 if ((j = s.indexOf(base64sent)) >= 0) { 1945 s = s.substring(j + base64sent.length, s.length); 1946 } 1947 if ((j = s.indexOf(base64esent)) >= 0) { 1948 s = s.substring(0, j); 1949 } 1950 1951 /* Ignore any non-base64 characters before the encoded 1952 data stream and skip the type sentinel if present. */ 1953 1954 while (i < s.length) { 1955 if (base64code.indexOf(s.charAt(i)) != -1) { 1956 break; 1957 } 1958 i++; 1959 } 1960 1961 /* Decode the base64 data stream. The decoder is 1962 terminated by the end of the input string or 1963 the occurrence of the explicit end sentinel. */ 1964 1965 while (i < s.length) { 1966 for (j = 0; j < 4; ) { 1967 if (i >= s.length) { 1968 if (j > 0) { 1969 alert("Base64 cipher text truncated."); 1970 return b; 1971 } 1972 break; 1973 } 1974 c = base64code.indexOf(s.charAt(i)); 1975 if (c >= 0) { 1976 d[j++] = c; 1977 } else if (s.charAt(i) == "=") { 1978 d[j++] = 0; 1979 shortgroup++; 1980 } else if (s.substring(i, i + base64esent.length) == base64esent) { 1981 //dump("s.substring(i, i + base64esent.length)", s.substring(i, i + base64esent.length)); 1982 //dump("esent", i); 1983 i = s.length; 1984 continue; 1985 } else { 1986 //dump("s.substring(i, i + base64esent.length)", s.substring(i, i + base64esent.length)); 1987 //dump("usent", i); 1988 // Might improve diagnosis of improper character in else clause here 1989 } 1990 i++; 1991 } 1992 //dump("d0", d[0]); dump("d1", d[1]); dump("d2", d[2]); dump("d3", d[3]); 1993 //dump("shortgroup", shortgroup); 1994 //dump("n", n); 1995 if (j == 4) { 1996 b[n++] = ((d[0] << 2) | (d[1] >> 4)) & 0xFF; 1997 if (shortgroup < 2) { 1998 b[n++] = ((d[1] << 4) | (d[2] >> 2)) & 0xFF; 1999 //dump("(d[1] << 4) | (d[2] >> 2)", (d[1] << 4) | (d[2] >> 2)); 2000 if (shortgroup < 1) { 2001 b[n++] = ((d[2] << 6) | d[3]) & 0xFF; 2002 } 2003 } 2004 } 2005 } 2006 return b; 2007} 2008// END: javascrypt/armour.js 2009// BEGIN: javscrypt/utf-8.js 2010 2011/* Encoding and decoding of Unicode character strings as 2012 UTF-8 byte streams. */ 2013 2014// UNICODE_TO_UTF8 -- Encode Unicode argument string as UTF-8 return value 2015 2016function unicode_to_utf8(s) { 2017 var utf8 = ""; 2018 for (var n = 0; n < s.length; n++) { 2019 var c = s.charCodeAt(n); 2020 2021 if (c <= 0x7F) { 2022 // 0x00 - 0x7F: Emit as single byte, unchanged 2023 utf8 += String.fromCharCode(c); 2024 } else if ((c >= 0x80) && (c <= 0x7FF)) { 2025 // 0x80 - 0x7FF: Output as two byte code, 0xC0 in first byte 2026 // 0x80 in second byte 2027 utf8 += String.fromCharCode((c >> 6) | 0xC0); 2028 utf8 += String.fromCharCode((c & 0x3F) | 0x80); 2029 } else { 2030 // 0x800 - 0xFFFF: Output as three bytes, 0xE0 in first byte 2031 // 0x80 in second byte 2032 // 0x80 in third byte 2033 utf8 += String.fromCharCode((c >> 12) | 0xE0); 2034 utf8 += String.fromCharCode(((c >> 6) & 0x3F) | 0x80); 2035 utf8 += String.fromCharCode((c & 0x3F) | 0x80); 2036 } 2037 } 2038 return utf8; 2039} 2040 2041 // UTF8_TO_UNICODE -- Decode UTF-8 argument into Unicode string return value 2042 2043function utf8_to_unicode(utf8) { 2044 var s = "", i = 0, b1, b2; 2045 2046 while (i < utf8.length) { 2047 b1 = utf8.charCodeAt(i); 2048 if (b1 < 0x80) { // One byte code: 0x00 0x7F 2049 s += String.fromCharCode(b1); 2050 i++; 2051 } else if((b1 >= 0xC0) && (b1 < 0xE0)) { // Two byte code: 0x80 - 0x7FF 2052 b2 = utf8.charCodeAt(i + 1); 2053 s += String.fromCharCode(((b1 & 0x1F) << 6) | (b2 & 0x3F)); 2054 i += 2; 2055 } else { // Three byte code: 0x800 - 0xFFFF 2056 b2 = utf8.charCodeAt(i + 1); 2057 b3 = utf8.charCodeAt(i + 2); 2058 s += String.fromCharCode(((b1 & 0xF) << 12) | 2059 ((b2 & 0x3F) << 6) | (b3 & 0x3F)); 2060 i += 3; 2061 } 2062 } 2063 return s; 2064} 2065 2066 /* ENCODE_UTF8 -- Encode string as UTF8 only if it contains 2067 a character of 0x9D (Unicode OPERATING 2068 SYSTEM COMMAND) or a character greater 2069 than 0xFF. This permits all strings 2070 consisting exclusively of 8 bit 2071 graphic characters to be encoded as 2072 themselves. We choose 0x9D as the sentinel 2073 character as opposed to one of the more 2074 logical PRIVATE USE characters because 0x9D 2075 is not overloaded by the regrettable 2076 "Windows-1252" character set. Now such characters 2077 don't belong in JavaScript strings, but you never 2078 know what somebody is going to paste into a 2079 text box, so this choice keeps Windows-encoded 2080 strings from bloating to UTF-8 encoding. */ 2081 2082function encode_utf8(s) { 2083 var i, necessary = false; 2084 2085 for (i = 0; i < s.length; i++) { 2086 if ((s.charCodeAt(i) == 0x9D) || (s.charCodeAt(i) > 0xFF)) { 2087 necessary = true; 2088 break; 2089 } 2090 } 2091 if (!necessary) { 2092 return s; 2093 } 2094 return String.fromCharCode(0x9D) + unicode_to_utf8(s); 2095} 2096 2097/* DECODE_UTF8 -- Decode a string encoded with encode_utf8 2098 above. If the string begins with the 2099 sentinel character 0x9D (OPERATING 2100 SYSTEM COMMAND), then we decode the 2101 balance as a UTF-8 stream. Otherwise, 2102 the string is output unchanged, as 2103 it's guaranteed to contain only 8 bit 2104 characters excluding 0x9D. */ 2105 2106function decode_utf8(s) { 2107 if ((s.length > 0) && (s.charCodeAt(0) == 0x9D)) { 2108 return utf8_to_unicode(s.substring(1)); 2109 } 2110 return s; 2111} 2112// END: javscrypt/utf-8.js 2113