crypto-otp.html (43991B)
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 3 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 4 <head> 5 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> 6 <title>One-Time Pad Generator</title> 7 <meta name="description" content="JavaScript One-Time Pad Generator" /> 8 <meta name="author" content="John Walker" /> 9 <meta name="keywords" content="one, time, pad, generator, onetime, cryptography, JavaScript" /> 10 <style type="text/css"> 11 a:link, a:visited { 12 background-color: inherit; 13 color: rgb(0%, 0%, 80%); 14 text-decoration: none; 15 } 16 17 a:hover { 18 background-color: rgb(30%, 30%, 100%); 19 color: rgb(100%, 100%, 100%); 20 } 21 22 a:active { 23 color: rgb(100%, 0%, 0%); 24 background-color: rgb(30%, 30%, 100%); 25 } 26 27 a.i:link, a.i:visited, a.i:hover { 28 background-color: inherit; 29 color: inherit; 30 text-decoration: none; 31 } 32 33 body { 34 margin-left: 15%; 35 margin-right: 10%; 36 background-color: #FFFFFF; 37 color: #000000; 38 } 39 40 body.jsgen { 41 margin-left: 5%; 42 margin-right: 5%; 43 } 44 45 dt { 46 margin-top: 0.5em; 47 } 48 49 img.button { 50 border: 0px; 51 vertical-align: middle; 52 } 53 54 img.keyicon { 55 vertical-align: bottom; 56 } 57 58 p, dd, li { 59 text-align: justify; 60 } 61 62 p.centre { 63 text-align: center; 64 } 65 66 table.r { 67 float: right; 68 } 69 70 table.c { 71 background-color: #E0E0E0; 72 color: #000000; 73 margin-left: auto; 74 margin-right: auto; 75 } 76 77 td.c { 78 text-align: center; 79 } 80 81 textarea { 82 background-color: #FFFFD0; 83 color: #000000; 84 } 85 </style> 86 <script type="text/javascript"> 87 //<![CDATA[ 88 89 loadTime = (new Date()).getTime(); 90 91 /* 92 93 L'Ecuyer's two-sequence generator with a Bays-Durham shuffle 94 on the back-end. Schrage's algorithm is used to perform 95 64-bit modular arithmetic within the 32-bit constraints of 96 JavaScript. 97 98 Bays, C. and S. D. Durham. ACM Trans. Math. Software: 2 (1976) 99 59-64. 100 101 L'Ecuyer, P. Communications of the ACM: 31 (1968) 742-774. 102 103 Schrage, L. ACM Trans. Math. Software: 5 (1979) 132-138. 104 105 */ 106 107 function uGen(old, a, q, r, m) { // Schrage's modular multiplication algorithm 108 var t; 109 110 t = Math.floor(old / q); 111 t = a * (old - (t * q)) - (t * r); 112 return Math.round((t < 0) ? (t + m) : t); 113 } 114 115 function LEnext() { // Return next raw value 116 var i; 117 118 this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); 119 this.gen2 = uGen(this.gen2, 40692, 52774, 3791, 2147483399); 120 121 /* Extract shuffle table index from most significant part 122 of the previous result. */ 123 124 i = Math.floor(this.state / 67108862); 125 126 // New state is sum of generators modulo one of their moduli 127 128 this.state = Math.round((this.shuffle[i] + this.gen2) % 2147483563); 129 130 // Replace value in shuffle table with generator 1 result 131 132 this.shuffle[i] = this.gen1; 133 134 return this.state; 135 } 136 137 // Return next random integer between 0 and n inclusive 138 139 function LEnint(n) { 140 return Math.floor(this.next() / (1 + 2147483562 / (n + 1))); 141 } 142 143 // Constructor. Called with seed value 144 145 function LEcuyer(s) { 146 var i; 147 148 this.shuffle = new Array(32); 149 this.gen1 = this.gen2 = (s & 0x7FFFFFFF); 150 for (i = 0; i < 19; i++) { 151 this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); 152 } 153 154 // Fill the shuffle table with values 155 156 for (i = 0; i < 32; i++) { 157 this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); 158 this.shuffle[31 - i] = this.gen1; 159 } 160 this.state = this.shuffle[0]; 161 this.next = LEnext; 162 this.nextInt = LEnint; 163 } 164 165 function sepchar() { 166 if (rsep) { 167 var seps = "!#$%&()*+,-./:;<=>?@[]^_{|}~"; 168 return seps.charAt(sepran.nextInt(seps.length - 1)); 169 } 170 return "-"; 171 } 172 173 /* 174 * md5.jvs 1.0b 27/06/96 175 * 176 * Javascript implementation of the RSA Data Security, Inc. MD5 177 * Message-Digest Algorithm. 178 * 179 * Copyright (c) 1996 Henri Torgemane. All Rights Reserved. 180 * 181 * Permission to use, copy, modify, and distribute this software 182 * and its documentation for any purposes and without 183 * fee is hereby granted provided that this copyright notice 184 * appears in all copies. 185 * 186 * Of course, this soft is provided "as is" without express or implied 187 * warranty of any kind. 188 189 This version contains some trivial reformatting modifications 190 by John Walker. 191 192 */ 193 194 function array(n) { 195 for (i = 0; i < n; i++) { 196 this[i] = 0; 197 } 198 this.length = n; 199 } 200 201 /* Some basic logical functions had to be rewritten because of a bug in 202 * Javascript.. Just try to compute 0xffffffff >> 4 with it.. 203 * Of course, these functions are slower than the original would be, but 204 * at least, they work! 205 */ 206 207 function integer(n) { 208 return n % (0xffffffff + 1); 209 } 210 211 function shr(a, b) { 212 a = integer(a); 213 b = integer(b); 214 if (a - 0x80000000 >= 0) { 215 a = a % 0x80000000; 216 a >>= b; 217 a += 0x40000000 >> (b - 1); 218 } else { 219 a >>= b; 220 } 221 return a; 222 } 223 224 function shl1(a) { 225 a = a % 0x80000000; 226 if (a & 0x40000000 == 0x40000000) { 227 a -= 0x40000000; 228 a *= 2; 229 a += 0x80000000; 230 } else { 231 a *= 2; 232 } 233 return a; 234 } 235 236 function shl(a, b) { 237 a = integer(a); 238 b = integer(b); 239 for (var i = 0; i < b; i++) { 240 a = shl1(a); 241 } 242 return a; 243 } 244 245 function and(a, b) { 246 a = integer(a); 247 b = integer(b); 248 var t1 = a - 0x80000000; 249 var t2 = b - 0x80000000; 250 if (t1 >= 0) { 251 if (t2 >= 0) { 252 return ((t1 & t2) + 0x80000000); 253 } else { 254 return (t1 & b); 255 } 256 } else { 257 if (t2 >= 0) { 258 return (a & t2); 259 } else { 260 return (a & b); 261 } 262 } 263 } 264 265 function or(a, b) { 266 a = integer(a); 267 b = integer(b); 268 var t1 = a - 0x80000000; 269 var t2 = b - 0x80000000; 270 if (t1 >= 0) { 271 if (t2 >= 0) { 272 return ((t1 | t2) + 0x80000000); 273 } else { 274 return ((t1 | b) + 0x80000000); 275 } 276 } else { 277 if (t2 >= 0) { 278 return ((a | t2) + 0x80000000); 279 } else { 280 return (a | b); 281 } 282 } 283 } 284 285 function xor(a, b) { 286 a = integer(a); 287 b = integer(b); 288 var t1 = a - 0x80000000; 289 var t2 = b - 0x80000000; 290 if (t1 >= 0) { 291 if (t2 >= 0) { 292 return (t1 ^ t2); 293 } else { 294 return ((t1 ^ b) + 0x80000000); 295 } 296 } else { 297 if (t2 >= 0) { 298 return ((a ^ t2) + 0x80000000); 299 } else { 300 return (a ^ b); 301 } 302 } 303 } 304 305 function not(a) { 306 a = integer(a); 307 return 0xffffffff - a; 308 } 309 310 /* Here begin the real algorithm */ 311 312 var state = new array(4); 313 var count = new array(2); 314 count[0] = 0; 315 count[1] = 0; 316 var buffer = new array(64); 317 var transformBuffer = new array(16); 318 var digestBits = new array(16); 319 320 var S11 = 7; 321 var S12 = 12; 322 var S13 = 17; 323 var S14 = 22; 324 var S21 = 5; 325 var S22 = 9; 326 var S23 = 14; 327 var S24 = 20; 328 var S31 = 4; 329 var S32 = 11; 330 var S33 = 16; 331 var S34 = 23; 332 var S41 = 6; 333 var S42 = 10; 334 var S43 = 15; 335 var S44 = 21; 336 337 function F(x, y, z) { 338 return or(and(x, y), and(not(x), z)); 339 } 340 341 function G(x, y, z) { 342 return or(and(x, z), and(y, not(z))); 343 } 344 345 function H(x, y, z) { 346 return xor(xor(x, y), z); 347 } 348 349 function I(x, y, z) { 350 return xor(y ,or(x , not(z))); 351 } 352 353 function rotateLeft(a, n) { 354 return or(shl(a, n), (shr(a, (32 - n)))); 355 } 356 357 function FF(a, b, c, d, x, s, ac) { 358 a = a + F(b, c, d) + x + ac; 359 a = rotateLeft(a, s); 360 a = a + b; 361 return a; 362 } 363 364 function GG(a, b, c, d, x, s, ac) { 365 a = a + G(b, c, d) + x + ac; 366 a = rotateLeft(a, s); 367 a = a + b; 368 return a; 369 } 370 371 function HH(a, b, c, d, x, s, ac) { 372 a = a + H(b, c, d) + x + ac; 373 a = rotateLeft(a, s); 374 a = a + b; 375 return a; 376 } 377 378 function II(a, b, c, d, x, s, ac) { 379 a = a + I(b, c, d) + x + ac; 380 a = rotateLeft(a, s); 381 a = a + b; 382 return a; 383 } 384 385 function transform(buf, offset) { 386 var a = 0, b = 0, c = 0, d = 0; 387 var x = transformBuffer; 388 389 a = state[0]; 390 b = state[1]; 391 c = state[2]; 392 d = state[3]; 393 394 for (i = 0; i < 16; i++) { 395 x[i] = and(buf[i * 4 + offset], 0xFF); 396 for (j = 1; j < 4; j++) { 397 x[i] += shl(and(buf[i * 4 + j + offset] ,0xFF), j * 8); 398 } 399 } 400 401 /* Round 1 */ 402 a = FF( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 403 d = FF( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 404 c = FF( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 405 b = FF( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 406 a = FF( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 407 d = FF( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 408 c = FF( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 409 b = FF( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 410 a = FF( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 411 d = FF( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 412 c = FF( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 413 b = FF( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 414 a = FF( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 415 d = FF( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 416 c = FF( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 417 b = FF( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 418 419 /* Round 2 */ 420 a = GG( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 421 d = GG( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 422 c = GG( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 423 b = GG( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 424 a = GG( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 425 d = GG( d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 426 c = GG( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 427 b = GG( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 428 a = GG( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 429 d = GG( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 430 c = GG( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 431 b = GG( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 432 a = GG( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 433 d = GG( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 434 c = GG( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 435 b = GG( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 436 437 /* Round 3 */ 438 a = HH( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 439 d = HH( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 440 c = HH( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 441 b = HH( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 442 a = HH( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 443 d = HH( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 444 c = HH( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 445 b = HH( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 446 a = HH( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 447 d = HH( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 448 c = HH( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 449 b = HH( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 450 a = HH( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 451 d = HH( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 452 c = HH( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 453 b = HH( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 454 455 /* Round 4 */ 456 a = II( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 457 d = II( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 458 c = II( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 459 b = II( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 460 a = II( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 461 d = II( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 462 c = II( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 463 b = II( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 464 a = II( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 465 d = II( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 466 c = II( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 467 b = II( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 468 a = II( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 469 d = II( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 470 c = II( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 471 b = II( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 472 473 state[0] += a; 474 state[1] += b; 475 state[2] += c; 476 state[3] += d; 477 478 } 479 480 function init() { 481 count[0] = count[1] = 0; 482 state[0] = 0x67452301; 483 state[1] = 0xefcdab89; 484 state[2] = 0x98badcfe; 485 state[3] = 0x10325476; 486 for (i = 0; i < digestBits.length; i++) { 487 digestBits[i] = 0; 488 } 489 } 490 491 function update(b) { 492 var index, i; 493 494 index = and(shr(count[0],3) , 0x3F); 495 if (count[0] < 0xFFFFFFFF - 7) { 496 count[0] += 8; 497 } else { 498 count[1]++; 499 count[0] -= 0xFFFFFFFF + 1; 500 count[0] += 8; 501 } 502 buffer[index] = and(b, 0xff); 503 if (index >= 63) { 504 transform(buffer, 0); 505 } 506 } 507 508 function finish() { 509 var bits = new array(8); 510 var padding; 511 var i = 0, index = 0, padLen = 0; 512 513 for (i = 0; i < 4; i++) { 514 bits[i] = and(shr(count[0], (i * 8)), 0xFF); 515 } 516 for (i = 0; i < 4; i++) { 517 bits[i + 4] = and(shr(count[1], (i * 8)), 0xFF); 518 } 519 index = and(shr(count[0], 3), 0x3F); 520 padLen = (index < 56) ? (56 - index) : (120 - index); 521 padding = new array(64); 522 padding[0] = 0x80; 523 for (i = 0; i < padLen; i++) { 524 update(padding[i]); 525 } 526 for (i = 0; i < 8; i++) { 527 update(bits[i]); 528 } 529 530 for (i = 0; i < 4; i++) { 531 for (j = 0; j < 4; j++) { 532 digestBits[i * 4 + j] = and(shr(state[i], (j * 8)) , 0xFF); 533 } 534 } 535 } 536 537 /* End of the MD5 algorithm */ 538 539 function gen() { 540 window.status = "Generating..."; 541 document.getElementById('onetime').pad.value = ""; 542 543 lower = document.getElementById('onetime').textcase.selectedIndex == 0; 544 upper = document.getElementById('onetime').textcase.selectedIndex == 1; 545 mixed = document.getElementById('onetime').textcase.selectedIndex == 2; 546 rsep = document.getElementById('onetime').rsep.checked; 547 if (!(numeric = document.getElementById('onetime').keytype[0].checked)) { 548 english = document.getElementById('onetime').keytype[1].checked; 549 gibberish = document.getElementById('onetime').keytype[3].checked; 550 } 551 clockseed = document.getElementById('onetime').seedy[0].checked 552 makesig = document.getElementById('onetime').dosig.checked; 553 npass = document.getElementById('onetime').nkeys.value; 554 pw_length = Math.round(document.getElementById('onetime').klength.value); 555 sep = document.getElementById('onetime').sep.value; 556 linelen = document.getElementById('onetime').linelen.value; 557 // 01234567890123456789012345678901 558 charcodes = " " + 559 "!\"#$%&'()*+,-./0123456789:;<=>?" + 560 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + 561 "`abcdefghijklmnopqrstuvwxyz{|}~"; 562 563 if (clockseed) { 564 var n, j, ran0; 565 566 /* Obtain seed from the clock. To reduce the likelihood 567 of the seed being guessed, we create the seed by combining 568 the time of the request with the time the page was loaded, 569 then use that composite value to seed an auxiliary generator 570 which is cycled between one and 32 times based on the time 571 derived initial seed, with the output of the generator fed 572 back into the seed we use to generate the pad. */ 573 574 seed = Math.round((new Date()).getTime() % Math.pow(2, 31)); 575 ran0 = new LEcuyer((seed ^ Math.round(loadTime % Math.pow(2, 31))) & 0x7FFFFFFF); 576 for (j = 0; j < (5 + ((seed >> 3) & 0xF)); j++) { 577 n = ran0.nextInt(31); 578 } 579 while (n-- >= 0) { 580 seed = ((seed << 11) | (seed >>> (32 - 11))) ^ ran0.next(); 581 } 582 seed &= 0x7FFFFFFF; 583 document.getElementById('onetime').seeder.value = seed; 584 } else { 585 var useed, seedNum; 586 587 /* Obtain seed from user specification. If the seed is a 588 decimal number, use it as-is. If it contains any 589 non-numeric characters, construct a hash code and 590 use that as the seed. */ 591 592 useed = document.getElementById('onetime').seeder.value; 593 seedNum = true; 594 for (i = 0; i < useed.length; i++) { 595 if (!"0123456789".includes(useed.charAt(i))) { 596 seedNum = false; 597 break; 598 } 599 } 600 if (seedNum) { 601 seed = Math.round(Math.floor(document.getElementById('onetime').seeder.value) % Math.pow(2, 31)); 602 document.getElementById('onetime').seeder.value = seed; 603 } else { 604 var s, t, iso, hex; 605 606 iso = ""; 607 hex = "0123456789ABCDEF"; 608 for (i = 32; i < 256; i++) { 609 if (i < 127 || i >= 160) { 610 // Why not "s = i.toString(16);"? Doesn't work in Netscape 3.0 611 iso += "%" + hex.charAt(i >> 4) + hex.charAt(i & 0xF); 612 } 613 } 614 iso = unescape(iso); 615 s = 0; 616 for (i = 0; i < useed.length; i++) { 617 t = iso.indexOf(useed.charAt(i)); 618 if (t < 0) { 619 t = 17; 620 } 621 s = 0x7FFFFFFF & (((s << 5) | (s >> (32 - 5))) ^ t); 622 } 623 seed = s; 624 } 625 } 626 ran1 = new LEcuyer(seed); 627 ran2 = new LEcuyer(seed); 628 if (rsep) { 629 /* Use a separate random generator for separators 630 so that results are the same for a given seed 631 for both choices of separators. */ 632 sepran = new LEcuyer(seed); 633 } 634 635 ndig = 1; 636 j = 10; 637 while (npass >= j) { 638 ndig++; 639 j *= 10; 640 } 641 pw_item = pw_length + (sep > 0 ? (pw_length / sep) : 0); 642 pw_item += ndig + 5; 643 j = pw_item * 3; 644 if (j < 132) { 645 j = 132; 646 } 647 npline = Math.floor(linelen / pw_item); 648 if (npline < 1) { 649 npline = 0; 650 } 651 v = ""; 652 md5v = ""; 653 lineno = 0; 654 if (!numeric) { 655 letters = "abcdefghijklmnopqrstuvwxyz"; 656 if (upper) { 657 letters = letters.toUpperCase(); 658 } 659 if (english) { 660 661 // Frequency of English digraphs (from D. Edwards 1/27/66) 662 663 frequency = new Array( 664 new Array(4, 20, 28, 52, 2, 11, 28, 4, 32, 4, 6, 62, 665 23, 167, 2, 14, 0, 83, 76, 127, 7, 25, 8, 1, 666 9, 1), /* aa - az */ 667 668 new Array(13, 0, 0, 0, 55, 0, 0, 0, 8, 2, 0, 22, 0, 0, 669 11, 0, 0, 15, 4, 2, 13, 0, 0, 0, 15, 0), /* ba - bz */ 670 671 new Array(32, 0, 7, 1, 69, 0, 0, 33, 17, 0, 10, 9, 1, 672 0, 50, 3, 0, 10, 0, 28, 11, 0, 0, 0, 3, 0), /* ca - cz */ 673 674 new Array(40, 16, 9, 5, 65, 18, 3, 9, 56, 0, 1, 4, 15, 675 6, 16, 4, 0, 21, 18, 53, 19, 5, 15, 0, 3, 0), /* da - dz */ 676 677 new Array(84, 20, 55, 125, 51, 40, 19, 16, 50, 1, 4, 678 55, 54, 146, 35, 37, 6, 191, 149, 65, 9, 26, 679 21, 12, 5, 0), /* ea - ez */ 680 681 new Array(19, 3, 5, 1, 19, 21, 1, 3, 30, 2, 0, 11, 1, 682 0, 51, 0, 0, 26, 8, 47, 6, 3, 3, 0, 2, 0), /* fa - fz */ 683 684 new Array(20, 4, 3, 2, 35, 1, 3, 15, 18, 0, 0, 5, 1, 685 4, 21, 1, 1, 20, 9, 21, 9, 0, 5, 0, 1, 0), /* ga - gz */ 686 687 new Array(101, 1, 3, 0, 270, 5, 1, 6, 57, 0, 0, 0, 3, 688 2, 44, 1, 0, 3, 10, 18, 6, 0, 5, 0, 3, 0), /* ha - hz */ 689 690 new Array(40, 7, 51, 23, 25, 9, 11, 3, 0, 0, 2, 38, 691 25, 202, 56, 12, 1, 46, 79, 117, 1, 22, 0, 692 4, 0, 3), /* ia - iz */ 693 694 new Array(3, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 695 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0), /* ja - jz */ 696 697 new Array(1, 0, 0, 0, 11, 0, 0, 0, 13, 0, 0, 0, 0, 2, 698 0, 0, 0, 0, 6, 2, 1, 0, 2, 0, 1, 0), /* ka - kz */ 699 700 new Array(44, 2, 5, 12, 62, 7, 5, 2, 42, 1, 1, 53, 2, 701 2, 25, 1, 1, 2, 16, 23, 9, 0, 1, 0, 33, 0), /* la - lz */ 702 703 new Array(52, 14, 1, 0, 64, 0, 0, 3, 37, 0, 0, 0, 7, 704 1, 17, 18, 1, 2, 12, 3, 8, 0, 1, 0, 2, 0), /* ma - mz */ 705 706 new Array(42, 10, 47, 122, 63, 19, 106, 12, 30, 1, 6, 707 6, 9, 7, 54, 7, 1, 7, 44, 124, 6, 1, 15, 0, 708 12, 0), /* na - nz */ 709 710 new Array(7, 12, 14, 17, 5, 95, 3, 5, 14, 0, 0, 19, 711 41, 134, 13, 23, 0, 91, 23, 42, 55, 16, 28, 712 0, 4, 1), /* oa - oz */ 713 714 new Array(19, 1, 0, 0, 37, 0, 0, 4, 8, 0, 0, 15, 1, 0, 715 27, 9, 0, 33, 14, 7, 6, 0, 0, 0, 0, 0), /* pa - pz */ 716 717 new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 718 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0), /* qa - qz */ 719 720 new Array(83, 8, 16, 23, 169, 4, 8, 8, 77, 1, 10, 5, 721 26, 16, 60, 4, 0, 24, 37, 55, 6, 11, 4, 0, 722 28, 0), /* ra - rz */ 723 724 new Array(65, 9, 17, 9, 73, 13, 1, 47, 75, 3, 0, 7, 725 11, 12, 56, 17, 6, 9, 48, 116, 35, 1, 28, 0, 726 4, 0), /* sa - sz */ 727 728 new Array(57, 22, 3, 1, 76, 5, 2, 330, 126, 1, 0, 14, 729 10, 6, 79, 7, 0, 49, 50, 56, 21, 2, 27, 0, 730 24, 0), /* ta - tz */ 731 732 new Array(11, 5, 9, 6, 9, 1, 6, 0, 9, 0, 1, 19, 5, 31, 733 1, 15, 0, 47, 39, 31, 0, 3, 0, 0, 0, 0), /* ua - uz */ 734 735 new Array(7, 0, 0, 0, 72, 0, 0, 0, 28, 0, 0, 0, 0, 0, 736 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0), /* va - vz */ 737 738 new Array(36, 1, 1, 0, 38, 0, 0, 33, 36, 0, 0, 4, 1, 739 8, 15, 0, 0, 0, 4, 2, 0, 0, 1, 0, 0, 0), /* wa - wz */ 740 741 new Array(1, 0, 2, 0, 0, 1, 0, 0, 3, 0, 0, 0, 0, 0, 1, 742 5, 0, 0, 0, 3, 0, 0, 1, 0, 0, 0), /* xa - xz */ 743 744 new Array(14, 5, 4, 2, 7, 12, 12, 6, 10, 0, 0, 3, 7, 745 5, 17, 3, 0, 4, 16, 30, 0, 0, 5, 0, 0, 0), /* ya - yz */ 746 747 new Array(1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) /* za - zz */ ); 749 750 // This MUST be equal to the sum of the equivalent rows above. 751 752 row_sums = new Array( 753 796, 160, 284, 401, 1276, 262, 199, 539, 777, 754 16, 39, 351, 243, 751, 662, 181, 17, 683, 755 662, 968, 248, 115, 180, 17, 162, 5 756 ); 757 758 // Frequencies of starting characters. 759 760 start_freq = new Array( 761 1299, 425, 725, 271, 375, 470, 93, 223, 1009, 762 24, 20, 355, 379, 319, 823, 618, 21, 317, 763 962, 1991, 271, 104, 516, 6, 16, 14 764 ); 765 766 // This MUST be equal to the sum of all elements in the above array. 767 768 total_sum = 11646; 769 } 770 if (gibberish) { 771 gibber = "abcdefghijklmnopqrstuvwxyz" + 772 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + 773 "0123456789" + 774 "!#$%&()*+,-./:;<=>?@[]^_{|}~"; 775 if (upper) { 776 /* Convert to upper case, leaving two copies of the 777 alphabet for two reasons: first, to favour letters 778 over gnarl, and second, to change only the letter case 779 when the mode is selected. */ 780 gibber = gibber.toUpperCase(); 781 } else if (lower) { 782 gibber = gibber.toLowerCase(); 783 } 784 } 785 } 786 for (line = 1; line <= npass; line++) { 787 password = ""; 788 if (numeric) { 789 for (nchars = 0; nchars < pw_length; nchars++) { 790 if ((sep > 0) && ((nchars % sep) == 0) && (nchars > 0)) { 791 password += sepchar(); 792 } 793 password += ran1.nextInt(9); 794 } 795 } else if (!english) { 796 for (nchars = 0; nchars < pw_length; nchars++) { 797 if ((sep > 0) && ((nchars % sep) == 0) && (nchars > 0)) { 798 password += sepchar(); 799 } 800 if (gibberish) { 801 password += gibber.charAt(ran1.nextInt(gibber.length - 1)); 802 } else { 803 password += letters.charAt(ran1.nextInt(25)); 804 } 805 } 806 } else { 807 position = ran1.nextInt(total_sum - 1); 808 for (row_position = 0, j = 0; position >= row_position; 809 row_position += start_freq[j], j++) { 810 continue; 811 } 812 813 password = letters.charAt(i = j - 1); 814 nch = 1; 815 for (nchars = pw_length - 1; nchars; --nchars) { 816 817 // Now find random position within the row. 818 819 position = ran1.nextInt(row_sums[i] - 1); 820 for (row_position = 0, j = 0; 821 position >= row_position; 822 row_position += frequency[i][j], j++) { 823 } 824 825 if ((sep > 0) && ((nch % sep) == 0)) { 826 password += sepchar(); 827 } 828 nch++; 829 password += letters.charAt(i = j - 1); 830 } 831 } 832 833 if ((!numeric) && (!gibberish) && mixed) { 834 var pwm = ''; 835 var j; 836 for (j = 0; j < password.length; j++) { 837 pwm += ran2.nextInt(1) ? (password.charAt(j)) : (password.charAt(j).toUpperCase()); 838 } 839 password = pwm; 840 } 841 842 /* If requested, calculate the MD5 signature for this key and 843 and save for later appending to the results. */ 844 845 if (makesig) { 846 var n, m, hex = "0123456789ABCDEF"; 847 848 init(); 849 for (m = 0; m < password.length; m++) { 850 update(32 + charcodes.indexOf(password.charAt(m))); 851 } 852 finish(); 853 854 for (n = 0; n < 16; n++) { 855 md5v += hex.charAt(digestBits[n] >> 4); 856 md5v += hex.charAt(digestBits[n] & 0xF); 857 } 858 md5v += "\n"; 859 } 860 861 aline = "" + line; 862 while (aline.length < ndig) { 863 aline = " " + aline; 864 } 865 v += aline + ") " + password; 866 867 if ((++lineno) >= npline) { 868 v += "\n"; 869 lineno = 0; 870 } else { 871 v += " "; 872 } 873 } 874 875 if (makesig) { 876 v += "\n---------- MD5 Signatures ----------\n" + md5v; 877 } 878 879 document.getElementById('onetime').pad.value = v; 880 window.status = "Done."; 881 } 882 883 function loadHandler() { 884 for (var i = 0; i < 25; i++) { 885 gen(); 886 } 887 }; 888 889 //]]> 890 </script> 891 892 </head> 893 894 <body class="jsgen" onload="loadHandler();"> 895 896 <h1><img src="key.gif" class="keyicon" alt="" 897 width="40" height="40" /> One-Time Pad Generator</h1> 898 899 <p> 900 This page, which requires that your browser support JavaScript 901 (see <a href="#why"><cite>Why JavaScript</cite></a> below), 902 generates one-time pads or password lists in a variety of 903 forms. It is based a high-quality pseudorandom sequence 904 generator, which can be seeded either from the current date 905 and time, or from a seed you provide. Fill in the form below 906 to select the format of the pad and press “Generate” to 907 create the pad in the text box. You can then copy and paste 908 the generated pad into another window to use as you wish. 909 Each of the labels on the request form is linked to a description 910 of that parameter. 911 </p> 912 913 <form id="onetime" action="#" onsubmit="return false;"> 914 915 <p class="centre"> 916 <b>Output:</b> 917 <a href="#NumberOfKeys">Number of keys</a>: <input type="text" name="nkeys" value="20" size="4" maxlength="12" /> 918 <a href="#LineLength">Line length</a>: <input type="text" name="linelen" value="48" size="3" maxlength="12" /> 919 <br /> 920 <b>Format:</b> 921 <a href="#KeyLength">Key length</a>: <input type="text" name="klength" value="8" size="3" maxlength="12" /> 922 <a href="#GroupLength">Group length</a>: <input type="text" name="sep" value="4" size="2" maxlength="12" /> 923 924 <br /> 925 <b>Composition:</b> 926 <a href="#KeyText">Key text</a>: <input type="radio" name="keytype" /> Numeric 927 <input type="radio" name="keytype" /> Word-like 928 <input type="radio" name="keytype" checked="checked" /> Alphabetic 929 <input type="radio" name="keytype" /> Gibberish 930 <br /> 931 <a href="#LetterCase">Letters:</a> 932 <select size="i" name="textcase"> 933 934 <option value="1" selected="selected">Lower case</option> 935 <option value="2">Upper case</option> 936 <option value="3">Mixed case</option> 937 </select> 938 939 <input type="checkbox" name="rsep" /> <a href="#RandomSep">Random separators</a> 940 <input type="checkbox" name="dosig" /> <a href="#Signatures">Include signatures</a> 941 942 <br /> 943 <b><a href="#Seed">Seed:</a></b> 944 <input type="radio" name="seedy" checked="checked" /> From clock 945 <input type="radio" name="seedy" /> User-defined: 946 <input type="text" name="seeder" value="" size="12" maxlength="128" 947 onchange="document.getElementById('onetime').seedy[1].checked=true;" /> 948 <br /> 949 <input type="button" value=" Generate " onclick="gen();" /> 950 951 <input type="button" value=" Clear " onclick="document.getElementById('onetime').pad.value = '';" /> 952 953 <input type="button" value=" Select " onclick="document.getElementById('onetime').pad.select();" /><br /> 954 <textarea name="pad" rows="12" cols="72"> 955 956 Uh, oh. It appears your browser either does not support 957 JavaScript or that JavaScript has been disabled. You'll 958 have to replace your browser with one supporting JavaScript 959 (or enable it, if that's the problem) before you can use 960 this page. 961 </textarea> 962 </p> 963 964 </form> 965 966 <script type="text/javascript"> 967 //<![CDATA[ 968 // Clear out "sorry, no JavaScript" message from text box. 969 document.getElementById('onetime').pad.value = ""; 970 //]]> 971 </script> 972 973 <h2><a name="details">Details</a></h2> 974 975 <p> 976 Each of the fields in the one-time pad request form is described 977 below. 978 </p> 979 980 <h3><a name="output">Output</a></h3> 981 982 <h4><a name="NumberOfKeys">Number of keys</a></h4> 983 984 <p> 985 Enter the number of keys you'd like to generate. If you generate 986 more than fit in the results text box, you can use the scroll 987 bar to view the additional lines. 988 </p> 989 990 <h4><a name="LineLength">Line length</a></h4> 991 992 <p> 993 Lines in the output will be limited to the given length (or contain 994 only one key if the line length is less than required for a single 995 key). If the line length is greater than the width of the results 996 box, you can use the horizontal scroll bar to view the rest of the 997 line. Enter <tt>0</tt> to force one key per line; this is handy 998 when you're preparing a list of keys to be read by a computer program. 999 </p> 1000 1001 <h3><a name="format">Format</a></h3> 1002 1003 <h4><a name="KeyLength">Key length</a></h4> 1004 1005 <p> 1006 Each key will contain this number of characters, not counting 1007 separators between groups. 1008 </p> 1009 1010 <h4><a name="GroupLength">Group length</a></h4> 1011 1012 <p> 1013 If a nonzero value is entered in this field, the key will be broken 1014 into groups of the given number of characters by separators. Humans 1015 find it easier to read and remember sequences of characters when 1016 divided into groups of five or fewer characters. 1017 </p> 1018 1019 <h3><a name="composition">Composition</a></h3> 1020 1021 <h4><a name="KeyText">Key text</a></h4> 1022 1023 <p> 1024 This set of radio buttons lets you select the character set used in 1025 the keys. The alternatives are listed in order of 1026 increasing security. 1027 </p> 1028 1029 <blockquote> 1030 <dl> 1031 <dt><b>Numeric</b></dt> 1032 <dd>Keys contain only the decimal digits “0” through “9”. 1033 <em>Least secure.</em></dd> 1034 1035 <dt><b>Word-like</b></dt> 1036 <dd>Keys are composed of alphabetic characters which obey the 1037 digraph statistics of English text. Such keys contain 1038 sequences of vowels and consonants familiar to speakers 1039 of Western languages, and are therefore usually easier to 1040 memorise but, for a given key length, are less secure than 1041 purely random letters.</dd> 1042 1043 <dt><b>Alphabetic</b></dt> 1044 <dd>Keys consist of letters of the alphabet chosen at random. 1045 Each character has an equal probability of being one of 1046 the 26 letters.</dd> 1047 1048 <dt><b>Gibberish</b></dt> 1049 <dd>Keys use most of the printable ASCII character set, excluding 1050 only characters frequently used for quoting purposes. This 1051 option provides the greatest security for a given key length, 1052 but most people find keys like this difficult to memorise or 1053 even transcribe from a printed pad. If a human is in the loop, 1054 it's often better to use a longer alphabetic or word-like key. 1055 <em>Most secure.</em></dd> 1056 </dl> 1057 1058 </blockquote> 1059 1060 <h4><a name="LetterCase">Letters</a></h4> 1061 1062 <p> 1063 The case of letters in keys generated with Word-like, Alphabetic, and 1064 Gibberish key text will be as chosen. Most people find it easier to 1065 read lower case letters than all capitals, but for some applications 1066 (for example, where keys must be scanned optically by hardware that 1067 only recognises capital letters), capitals are required. Selecting 1068 “Mixed case” creates keys with a mix of upper- and 1069 lower-case letters; such keys are more secure than those with uniform 1070 letter case, but do not pass the “telephone test”: you 1071 can't read them across a (hopefully secure) voice link without having 1072 to indicate whether each letter is or is not a capital. 1073 </p> 1074 1075 <h4><a name="RandomSep">Random separators</a></h4> 1076 1077 <p> 1078 When the <a href="#KeyLength">Key length</a> is longer than 1079 a nonzero <a href="#GroupLength">Group length</a> specification, 1080 the key is divided into sequences of the given group length 1081 by separator characters. By default, a hyphen, “<tt>-</tt>”, is used 1082 to separate groups. If you check this box, separators will be 1083 chosen at random among punctuation marks generally acceptable 1084 for applications such as passwords. If you're generating passwords 1085 for a computer system, random separators dramatically increase 1086 the difficulty of guessing passwords by exhaustive search. 1087 </p> 1088 1089 <h4><a name="Signatures">Include signatures</a></h4> 1090 1091 <p> 1092 1093 When this box is checked, at the end of the list of keys, preceded by 1094 a line beginning with ten dashes “<tt>-</tt>”, the 128 bit MD5 signature of 1095 each key is given, one per line, with signatures expressed as 32 1096 hexadecimal digits. Key signatures can be used to increase security 1097 when keys are used to control access to computer systems or databases. 1098 Instead of storing a copy of the keys, the computer stores their 1099 signatures. When the user enters a key, its signature is computed 1100 with the same MD5 algorithm used to generate it initially, and the key 1101 is accepted only if the signature matches. Since discovering 1102 a key which will generate a given signature is believed to be 1103 computationally prohibitive, even if the list of signatures stored on 1104 the computer is compromised, that information will not permit an 1105 intruder to deduce a valid key. 1106 </p> 1107 1108 <p> 1109 Signature calculation is a computationally intense process for which 1110 JavaScript is not ideally suited; be patient while signatures are 1111 generated, especially if your computer has modest 1112 processing speed. 1113 </p> 1114 1115 <p> 1116 For signature-based validation to be secure, it is essential 1117 the original keys be long enough to prohibit discovery of matching 1118 signatures by exhaustive search. Suppose, for example, one used 1119 four digit numeric keys, as used for Personal Identification 1120 Numbers (PINs) by many credit card systems. Since only 10,000 1121 different keys exist, one could simply compute the signatures of 1122 every possible key from 0000 through 9999, permitting an attacker who 1123 came into possession of the table of signatures to recover the 1124 keys by a simple lookup process. For maximum security, keys must 1125 contain at least as much information as the 128 bit signatures 1126 computed from them. This implies a minimum key length (not counting 1127 non-random separator characters) for the various key formats as 1128 follows: 1129 </p> 1130 1131 <table class="c" border="border" cellpadding="4"> 1132 <tr><th>Key Composition</th> <th>Minimum Characters</th></tr> 1133 1134 <tr><td>Numeric</td> <td class="c">39</td></tr> 1135 <tr><td>Word-like</td> <td class="c">30</td></tr> 1136 <tr><td>Alphabetic</td> <td class="c">28</td></tr> 1137 <tr><td>Gibberish</td> <td class="c">20</td></tr> 1138 </table> 1139 1140 <p> 1141 It should be noted that for many practical applications there is no 1142 need for anything approaching 128-bit security. The guidelines above 1143 apply only in the case where maximum protection in the event of 1144 undetected compromise of key signatures occurs. In many 1145 cases, much shorter keys are acceptable, especially when it is assumed 1146 that a compromise of the system's password or signature database would 1147 be only part of a much more serious subversion of all resources 1148 on the system. 1149 </p> 1150 1151 <h3><a name="Seed">Seed</a></h3> 1152 1153 <p> 1154 The <em>seed</em> is the starting value which determines all 1155 subsequent values in the pseudorandom sequence used to generate 1156 the one-time pad. Given the seed, the pad can be reproduced. The 1157 seed is a 31-bit number which can be derived from the date and 1158 time at which the one-time pad was requested, or from a 1159 user-defined seed value. If the user-defined seed consists 1160 entirely of decimal digits, it is used directly as the seed, 1161 modulo 2<sup>31</sup>; if a string containing non-digit characters 1162 is entered, it is used to compute a <em>hash code</em> which is 1163 used to seed the generator. 1164 1165 </p> 1166 1167 <p> 1168 When the clock is used to create the seed, the seed value is entered 1169 in the User-defined box to allow you, by checking “User-defined”, 1170 to produce additional pads with the same seed. 1171 </p> 1172 1173 <h2><a name="why">Why JavaScript?</a></h2> 1174 1175 <p> 1176 At first glance, JavaScript may seem an odd choice for programming 1177 a page such as this. The one-time pad generator program is rather 1178 large and complicated, and downloading it to your browser takes longer 1179 than would be required for a Java applet or to transfer a 1180 one-time pad generated by a CGI program on the Web server. I chose 1181 JavaScript for two reasons: <em>security</em> and <em>transparency</em>. 1182 1183 </p> 1184 1185 <p> 1186 <b>Security.</b> 1187 The sole reason for the existence of one-time pads is to 1188 provide a source of information known only to people to whom 1189 they have been distributed in a secure manner. This means 1190 the generation process cannot involve any link whose security 1191 is suspect. If the pad were generated on a Web server and 1192 transmitted to you, it would have to pass over the 1193 Internet, where any intermediate site might make a copy 1194 of your pad before you even received it. Even if some 1195 mechanism such as encryption could absolutely prevent the 1196 pad's being intercepted, you'd still have no way to be sure 1197 the site generating the pad didn't keep a copy 1198 in a file, conveniently tagged with your Internet address. 1199 </p> 1200 1201 <p> 1202 In order to have any degree of security, it is essential 1203 that the pad be generated on <em>your</em> computer, without 1204 involving any transmission or interaction with other 1205 sites on the Internet. A Web browser with JavaScript makes 1206 this possible, since the generation program embedded in this 1207 page runs entirely on your own computer and does not 1208 transmit anything over the Internet. Its output appears 1209 only in the text box, allowing you to cut and paste it 1210 to another application. From there on, its security is 1211 up to you. 1212 </p> 1213 1214 <p> 1215 Security is never absolute. A one-time pad generated with 1216 this page might be compromised in a variety of ways, including 1217 the following: 1218 1219 </p> 1220 1221 <ul> 1222 <li> Your Web browser and/or JavaScript interpreter may 1223 contain bugs or deliberate security violations 1224 which report activity on your computer back to some 1225 other Internet site.</li> 1226 1227 <li> Some other applet running on another page of your 1228 browser, perhaps without your being aware of its 1229 existence, is spying on other windows.</li> 1230 1231 <li> Some other application running on your computer 1232 may have compromised your system's security and 1233 be snooping on your activity.</li> 1234 1235 <li> Your Web browser may be keeping a “history log” 1236 1237 or “cache” of data you generate. Somebody may 1238 come along later and recover a copy of the pad 1239 from that log.</li> 1240 1241 <li> The implementation of this page may contain a bug 1242 or deliberate error which makes its output 1243 predictable. This is why <a href="#trans"><cite>transparency</cite></a>, 1244 discussed below, is essential.</li> 1245 1246 <li> Your computer's security may have been compromised 1247 physically; when's the last time you checked that a 1248 bug that transmits your keystrokes and/or screen 1249 contents to that white van parked down the street 1250 wasn't lurking inside your computer cabinet?</li> 1251 </ul> 1252 1253 <p> 1254 One can whip oneself into a fine fever of paranoia worrying about 1255 things like this. One way to rule out the most probable risks 1256 is to download a copy of the generator page and run it 1257 from a “<tt>file:</tt>” URL on a computer which has no network 1258 connection whatsoever and is located in a secure location 1259 under your control. And look very carefully at any files 1260 created by your Web browser. You may find the most interesting 1261 things squirreled away there…. 1262 </p> 1263 1264 <p> 1265 <b><a name="trans">Transparency</a>.</b> 1266 Any security-related tool is only as good as its design 1267 and implementation. <em>Transparency</em> means that, in 1268 essence, all the moving parts are visible so you can judge 1269 for yourself whether the tool merits your confidence. In 1270 the case of a program, this means that source code must 1271 be available, and that you can verify that the program 1272 you're running corresponds to the source code provided. 1273 1274 </p> 1275 1276 <p> 1277 The very nature of JavaScript achieves this transparency. 1278 The program is embedded into this actual Web page; to 1279 examine it you need only use your browser's “View Source” 1280 facility, or save the page into a file on your computer 1281 and read it with a text editor. JavaScript's being 1282 an interpreted language eliminates the risk of your running 1283 a program different from the purported source code: with 1284 an interpreted language what you read is what you run. 1285 </p> 1286 1287 <p> 1288 Transparency is important even if you don't know enough about 1289 programming or security to determine whether the program 1290 contains any flaws. The very fact that it can be examined 1291 by anybody allows those with the required expertise to pass 1292 judgment, and you can form your own conclusions based on 1293 their analysis. 1294 </p> 1295 1296 <h2>Credits</h2> 1297 1298 <p> 1299 1300 The pseudorandom sequence generator is based on L'Ecuyer's 1301 two-sequence generator as described in 1302 <cite>Communications of the ACM</cite>, Vol. 31 (1968), page 742. 1303 A Bays-Durham shuffle is used to guard against regularities 1304 lurking in L'Ecuyer's algorithm; see 1305 <cite>ACM Transactions on Mathematical Software</cite>, Vol. 2 (1976) 1306 pages 59–64 for details. 1307 </p> 1308 1309 <p> 1310 The JavaScript implementation of the 1311 <a href="http://www.ietf.org/rfc/rfc1321.txt"><b>MD5 message-digest algorithm</b></a> 1312 was developed by Henri Torgemane; please view the source code of this 1313 page to examine the code, including the copyright notice and 1314 conditions of use. The MD5 algorithm was developed by Ron Rivest. 1315 </p> 1316 1317 <p /> 1318 1319 <hr /> 1320 1321 <p /> 1322 1323 <table class="r"> 1324 <tr><td align="center"> 1325 <a class="i" href="http://validator.w3.org/check?uri=referer"><img 1326 class="button" 1327 src="valid-xhtml10.png" 1328 alt="Valid XHTML 1.0" height="31" width="88" /></a> 1329 </td></tr> 1330 </table> 1331 1332 <address> 1333 by <a href="/">John Walker</a><br /> 1334 May 26, 1997<br /> 1335 1336 Updated: November 2006 1337 </address> 1338 1339 <p class="centre"> 1340 <em>This document is in the public domain.</em> 1341 </p> 1342 </body> 1343 </html>