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