| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> |
| <title>One-Time Pad Generator</title> |
| <meta name="description" content="JavaScript One-Time Pad Generator" /> |
| <meta name="author" content="John Walker" /> |
| <meta name="keywords" content="one, time, pad, generator, onetime, cryptography, JavaScript" /> |
| <style type="text/css"> |
| a:link, a:visited { |
| background-color: inherit; |
| color: rgb(0%, 0%, 80%); |
| text-decoration: none; |
| } |
| |
| a:hover { |
| background-color: rgb(30%, 30%, 100%); |
| color: rgb(100%, 100%, 100%); |
| } |
| |
| a:active { |
| color: rgb(100%, 0%, 0%); |
| background-color: rgb(30%, 30%, 100%); |
| } |
| |
| a.i:link, a.i:visited, a.i:hover { |
| background-color: inherit; |
| color: inherit; |
| text-decoration: none; |
| } |
| |
| body { |
| margin-left: 15%; |
| margin-right: 10%; |
| background-color: #FFFFFF; |
| color: #000000; |
| } |
| |
| body.jsgen { |
| margin-left: 5%; |
| margin-right: 5%; |
| } |
| |
| dt { |
| margin-top: 0.5em; |
| } |
| |
| img.button { |
| border: 0px; |
| vertical-align: middle; |
| } |
| |
| img.keyicon { |
| vertical-align: bottom; |
| } |
| |
| p, dd, li { |
| text-align: justify; |
| } |
| |
| p.centre { |
| text-align: center; |
| } |
| |
| table.r { |
| float: right; |
| } |
| |
| table.c { |
| background-color: #E0E0E0; |
| color: #000000; |
| margin-left: auto; |
| margin-right: auto; |
| } |
| |
| td.c { |
| text-align: center; |
| } |
| |
| textarea { |
| background-color: #FFFFD0; |
| color: #000000; |
| } |
| </style> |
| <script type="text/javascript"> |
| //<![CDATA[ |
| |
| loadTime = (new Date()).getTime(); |
| |
| /* |
| |
| L'Ecuyer's two-sequence generator with a Bays-Durham shuffle |
| on the back-end. Schrage's algorithm is used to perform |
| 64-bit modular arithmetic within the 32-bit constraints of |
| JavaScript. |
| |
| Bays, C. and S. D. Durham. ACM Trans. Math. Software: 2 (1976) |
| 59-64. |
| |
| L'Ecuyer, P. Communications of the ACM: 31 (1968) 742-774. |
| |
| Schrage, L. ACM Trans. Math. Software: 5 (1979) 132-138. |
| |
| */ |
| |
| function uGen(old, a, q, r, m) { // Schrage's modular multiplication algorithm |
| var t; |
| |
| t = Math.floor(old / q); |
| t = a * (old - (t * q)) - (t * r); |
| return Math.round((t < 0) ? (t + m) : t); |
| } |
| |
| function LEnext() { // Return next raw value |
| var i; |
| |
| this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); |
| this.gen2 = uGen(this.gen2, 40692, 52774, 3791, 2147483399); |
| |
| /* Extract shuffle table index from most significant part |
| of the previous result. */ |
| |
| i = Math.floor(this.state / 67108862); |
| |
| // New state is sum of generators modulo one of their moduli |
| |
| this.state = Math.round((this.shuffle[i] + this.gen2) % 2147483563); |
| |
| // Replace value in shuffle table with generator 1 result |
| |
| this.shuffle[i] = this.gen1; |
| |
| return this.state; |
| } |
| |
| // Return next random integer between 0 and n inclusive |
| |
| function LEnint(n) { |
| return Math.floor(this.next() / (1 + 2147483562 / (n + 1))); |
| } |
| |
| // Constructor. Called with seed value |
| |
| function LEcuyer(s) { |
| var i; |
| |
| this.shuffle = new Array(32); |
| this.gen1 = this.gen2 = (s & 0x7FFFFFFF); |
| for (i = 0; i < 19; i++) { |
| this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); |
| } |
| |
| // Fill the shuffle table with values |
| |
| for (i = 0; i < 32; i++) { |
| this.gen1 = uGen(this.gen1, 40014, 53668, 12211, 2147483563); |
| this.shuffle[31 - i] = this.gen1; |
| } |
| this.state = this.shuffle[0]; |
| this.next = LEnext; |
| this.nextInt = LEnint; |
| } |
| |
| function sepchar() { |
| if (rsep) { |
| var seps = "!#$%&()*+,-./:;<=>?@[]^_{|}~"; |
| return seps.charAt(sepran.nextInt(seps.length - 1)); |
| } |
| return "-"; |
| } |
| |
| /* |
| * md5.jvs 1.0b 27/06/96 |
| * |
| * Javascript implementation of the RSA Data Security, Inc. MD5 |
| * Message-Digest Algorithm. |
| * |
| * Copyright (c) 1996 Henri Torgemane. All Rights Reserved. |
| * |
| * Permission to use, copy, modify, and distribute this software |
| * and its documentation for any purposes and without |
| * fee is hereby granted provided that this copyright notice |
| * appears in all copies. |
| * |
| * Of course, this soft is provided "as is" without express or implied |
| * warranty of any kind. |
| |
| This version contains some trivial reformatting modifications |
| by John Walker. |
| |
| */ |
| |
| function array(n) { |
| for (i = 0; i < n; i++) { |
| this[i] = 0; |
| } |
| this.length = n; |
| } |
| |
| /* Some basic logical functions had to be rewritten because of a bug in |
| * Javascript.. Just try to compute 0xffffffff >> 4 with it.. |
| * Of course, these functions are slower than the original would be, but |
| * at least, they work! |
| */ |
| |
| function integer(n) { |
| return n % (0xffffffff + 1); |
| } |
| |
| function shr(a, b) { |
| a = integer(a); |
| b = integer(b); |
| if (a - 0x80000000 >= 0) { |
| a = a % 0x80000000; |
| a >>= b; |
| a += 0x40000000 >> (b - 1); |
| } else { |
| a >>= b; |
| } |
| return a; |
| } |
| |
| function shl1(a) { |
| a = a % 0x80000000; |
| if (a & 0x40000000 == 0x40000000) { |
| a -= 0x40000000; |
| a *= 2; |
| a += 0x80000000; |
| } else { |
| a *= 2; |
| } |
| return a; |
| } |
| |
| function shl(a, b) { |
| a = integer(a); |
| b = integer(b); |
| for (var i = 0; i < b; i++) { |
| a = shl1(a); |
| } |
| return a; |
| } |
| |
| function and(a, b) { |
| a = integer(a); |
| b = integer(b); |
| var t1 = a - 0x80000000; |
| var t2 = b - 0x80000000; |
| if (t1 >= 0) { |
| if (t2 >= 0) { |
| return ((t1 & t2) + 0x80000000); |
| } else { |
| return (t1 & b); |
| } |
| } else { |
| if (t2 >= 0) { |
| return (a & t2); |
| } else { |
| return (a & b); |
| } |
| } |
| } |
| |
| function or(a, b) { |
| a = integer(a); |
| b = integer(b); |
| var t1 = a - 0x80000000; |
| var t2 = b - 0x80000000; |
| if (t1 >= 0) { |
| if (t2 >= 0) { |
| return ((t1 | t2) + 0x80000000); |
| } else { |
| return ((t1 | b) + 0x80000000); |
| } |
| } else { |
| if (t2 >= 0) { |
| return ((a | t2) + 0x80000000); |
| } else { |
| return (a | b); |
| } |
| } |
| } |
| |
| function xor(a, b) { |
| a = integer(a); |
| b = integer(b); |
| var t1 = a - 0x80000000; |
| var t2 = b - 0x80000000; |
| if (t1 >= 0) { |
| if (t2 >= 0) { |
| return (t1 ^ t2); |
| } else { |
| return ((t1 ^ b) + 0x80000000); |
| } |
| } else { |
| if (t2 >= 0) { |
| return ((a ^ t2) + 0x80000000); |
| } else { |
| return (a ^ b); |
| } |
| } |
| } |
| |
| function not(a) { |
| a = integer(a); |
| return 0xffffffff - a; |
| } |
| |
| /* Here begin the real algorithm */ |
| |
| var state = new array(4); |
| var count = new array(2); |
| count[0] = 0; |
| count[1] = 0; |
| var buffer = new array(64); |
| var transformBuffer = new array(16); |
| var digestBits = new array(16); |
| |
| var S11 = 7; |
| var S12 = 12; |
| var S13 = 17; |
| var S14 = 22; |
| var S21 = 5; |
| var S22 = 9; |
| var S23 = 14; |
| var S24 = 20; |
| var S31 = 4; |
| var S32 = 11; |
| var S33 = 16; |
| var S34 = 23; |
| var S41 = 6; |
| var S42 = 10; |
| var S43 = 15; |
| var S44 = 21; |
| |
| function F(x, y, z) { |
| return or(and(x, y), and(not(x), z)); |
| } |
| |
| function G(x, y, z) { |
| return or(and(x, z), and(y, not(z))); |
| } |
| |
| function H(x, y, z) { |
| return xor(xor(x, y), z); |
| } |
| |
| function I(x, y, z) { |
| return xor(y ,or(x , not(z))); |
| } |
| |
| function rotateLeft(a, n) { |
| return or(shl(a, n), (shr(a, (32 - n)))); |
| } |
| |
| function FF(a, b, c, d, x, s, ac) { |
| a = a + F(b, c, d) + x + ac; |
| a = rotateLeft(a, s); |
| a = a + b; |
| return a; |
| } |
| |
| function GG(a, b, c, d, x, s, ac) { |
| a = a + G(b, c, d) + x + ac; |
| a = rotateLeft(a, s); |
| a = a + b; |
| return a; |
| } |
| |
| function HH(a, b, c, d, x, s, ac) { |
| a = a + H(b, c, d) + x + ac; |
| a = rotateLeft(a, s); |
| a = a + b; |
| return a; |
| } |
| |
| function II(a, b, c, d, x, s, ac) { |
| a = a + I(b, c, d) + x + ac; |
| a = rotateLeft(a, s); |
| a = a + b; |
| return a; |
| } |
| |
| function transform(buf, offset) { |
| var a = 0, b = 0, c = 0, d = 0; |
| var x = transformBuffer; |
| |
| a = state[0]; |
| b = state[1]; |
| c = state[2]; |
| d = state[3]; |
| |
| for (i = 0; i < 16; i++) { |
| x[i] = and(buf[i * 4 + offset], 0xFF); |
| for (j = 1; j < 4; j++) { |
| x[i] += shl(and(buf[i * 4 + j + offset] ,0xFF), j * 8); |
| } |
| } |
| |
| /* Round 1 */ |
| a = FF( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ |
| d = FF( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ |
| c = FF( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ |
| b = FF( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ |
| a = FF( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ |
| d = FF( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ |
| c = FF( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ |
| b = FF( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ |
| a = FF( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ |
| d = FF( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ |
| c = FF( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ |
| b = FF( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ |
| a = FF( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ |
| d = FF( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ |
| c = FF( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ |
| b = FF( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ |
| |
| /* Round 2 */ |
| a = GG( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ |
| d = GG( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ |
| c = GG( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ |
| b = GG( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ |
| a = GG( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ |
| d = GG( d, a, b, c, x[10], S22, 0x2441453); /* 22 */ |
| c = GG( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ |
| b = GG( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ |
| a = GG( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ |
| d = GG( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ |
| c = GG( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ |
| b = GG( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ |
| a = GG( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ |
| d = GG( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ |
| c = GG( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ |
| b = GG( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ |
| |
| /* Round 3 */ |
| a = HH( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ |
| d = HH( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ |
| c = HH( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ |
| b = HH( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ |
| a = HH( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ |
| d = HH( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ |
| c = HH( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ |
| b = HH( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ |
| a = HH( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ |
| d = HH( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ |
| c = HH( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ |
| b = HH( b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ |
| a = HH( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ |
| d = HH( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ |
| c = HH( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ |
| b = HH( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ |
| |
| /* Round 4 */ |
| a = II( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ |
| d = II( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ |
| c = II( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ |
| b = II( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ |
| a = II( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ |
| d = II( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ |
| c = II( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ |
| b = II( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ |
| a = II( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ |
| d = II( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ |
| c = II( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ |
| b = II( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ |
| a = II( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ |
| d = II( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ |
| c = II( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ |
| b = II( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ |
| |
| state[0] += a; |
| state[1] += b; |
| state[2] += c; |
| state[3] += d; |
| |
| } |
| |
| function init() { |
| count[0] = count[1] = 0; |
| state[0] = 0x67452301; |
| state[1] = 0xefcdab89; |
| state[2] = 0x98badcfe; |
| state[3] = 0x10325476; |
| for (i = 0; i < digestBits.length; i++) { |
| digestBits[i] = 0; |
| } |
| } |
| |
| function update(b) { |
| var index, i; |
| |
| index = and(shr(count[0],3) , 0x3F); |
| if (count[0] < 0xFFFFFFFF - 7) { |
| count[0] += 8; |
| } else { |
| count[1]++; |
| count[0] -= 0xFFFFFFFF + 1; |
| count[0] += 8; |
| } |
| buffer[index] = and(b, 0xff); |
| if (index >= 63) { |
| transform(buffer, 0); |
| } |
| } |
| |
| function finish() { |
| var bits = new array(8); |
| var padding; |
| var i = 0, index = 0, padLen = 0; |
| |
| for (i = 0; i < 4; i++) { |
| bits[i] = and(shr(count[0], (i * 8)), 0xFF); |
| } |
| for (i = 0; i < 4; i++) { |
| bits[i + 4] = and(shr(count[1], (i * 8)), 0xFF); |
| } |
| index = and(shr(count[0], 3), 0x3F); |
| padLen = (index < 56) ? (56 - index) : (120 - index); |
| padding = new array(64); |
| padding[0] = 0x80; |
| for (i = 0; i < padLen; i++) { |
| update(padding[i]); |
| } |
| for (i = 0; i < 8; i++) { |
| update(bits[i]); |
| } |
| |
| for (i = 0; i < 4; i++) { |
| for (j = 0; j < 4; j++) { |
| digestBits[i * 4 + j] = and(shr(state[i], (j * 8)) , 0xFF); |
| } |
| } |
| } |
| |
| /* End of the MD5 algorithm */ |
| |
| function gen() { |
| window.status = "Generating..."; |
| document.getElementById('onetime').pad.value = ""; |
| |
| lower = document.getElementById('onetime').textcase.selectedIndex == 0; |
| upper = document.getElementById('onetime').textcase.selectedIndex == 1; |
| mixed = document.getElementById('onetime').textcase.selectedIndex == 2; |
| rsep = document.getElementById('onetime').rsep.checked; |
| if (!(numeric = document.getElementById('onetime').keytype[0].checked)) { |
| english = document.getElementById('onetime').keytype[1].checked; |
| gibberish = document.getElementById('onetime').keytype[3].checked; |
| } |
| clockseed = document.getElementById('onetime').seedy[0].checked |
| makesig = document.getElementById('onetime').dosig.checked; |
| npass = document.getElementById('onetime').nkeys.value; |
| pw_length = Math.round(document.getElementById('onetime').klength.value); |
| sep = document.getElementById('onetime').sep.value; |
| linelen = document.getElementById('onetime').linelen.value; |
| // 01234567890123456789012345678901 |
| charcodes = " " + |
| "!\"#$%&'()*+,-./0123456789:;<=>?" + |
| "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + |
| "`abcdefghijklmnopqrstuvwxyz{|}~"; |
| |
| if (clockseed) { |
| var n, j, ran0; |
| |
| /* Obtain seed from the clock. To reduce the likelihood |
| of the seed being guessed, we create the seed by combining |
| the time of the request with the time the page was loaded, |
| then use that composite value to seed an auxiliary generator |
| which is cycled between one and 32 times based on the time |
| derived initial seed, with the output of the generator fed |
| back into the seed we use to generate the pad. */ |
| |
| seed = Math.round((new Date()).getTime() % Math.pow(2, 31)); |
| ran0 = new LEcuyer((seed ^ Math.round(loadTime % Math.pow(2, 31))) & 0x7FFFFFFF); |
| for (j = 0; j < (5 + ((seed >> 3) & 0xF)); j++) { |
| n = ran0.nextInt(31); |
| } |
| while (n-- >= 0) { |
| seed = ((seed << 11) | (seed >>> (32 - 11))) ^ ran0.next(); |
| } |
| seed &= 0x7FFFFFFF; |
| document.getElementById('onetime').seeder.value = seed; |
| } else { |
| var useed, seedNum; |
| |
| /* Obtain seed from user specification. If the seed is a |
| decimal number, use it as-is. If it contains any |
| non-numeric characters, construct a hash code and |
| use that as the seed. */ |
| |
| useed = document.getElementById('onetime').seeder.value; |
| seedNum = true; |
| for (i = 0; i < useed.length; i++) { |
| if ("0123456789".indexOf(useed.charAt(i)) == -1) { |
| seedNum = false; |
| break; |
| } |
| } |
| if (seedNum) { |
| seed = Math.round(Math.floor(document.getElementById('onetime').seeder.value) % Math.pow(2, 31)); |
| document.getElementById('onetime').seeder.value = seed; |
| } else { |
| var s, t, iso, hex; |
| |
| iso = ""; |
| hex = "0123456789ABCDEF"; |
| for (i = 32; i < 256; i++) { |
| if (i < 127 || i >= 160) { |
| // Why not "s = i.toString(16);"? Doesn't work in Netscape 3.0 |
| iso += "%" + hex.charAt(i >> 4) + hex.charAt(i & 0xF); |
| } |
| } |
| iso = unescape(iso); |
| s = 0; |
| for (i = 0; i < useed.length; i++) { |
| t = iso.indexOf(useed.charAt(i)); |
| if (t < 0) { |
| t = 17; |
| } |
| s = 0x7FFFFFFF & (((s << 5) | (s >> (32 - 5))) ^ t); |
| } |
| seed = s; |
| } |
| } |
| ran1 = new LEcuyer(seed); |
| ran2 = new LEcuyer(seed); |
| if (rsep) { |
| /* Use a separate random generator for separators |
| so that results are the same for a given seed |
| for both choices of separators. */ |
| sepran = new LEcuyer(seed); |
| } |
| |
| ndig = 1; |
| j = 10; |
| while (npass >= j) { |
| ndig++; |
| j *= 10; |
| } |
| pw_item = pw_length + (sep > 0 ? (pw_length / sep) : 0); |
| pw_item += ndig + 5; |
| j = pw_item * 3; |
| if (j < 132) { |
| j = 132; |
| } |
| npline = Math.floor(linelen / pw_item); |
| if (npline < 1) { |
| npline = 0; |
| } |
| v = ""; |
| md5v = ""; |
| lineno = 0; |
| if (!numeric) { |
| letters = "abcdefghijklmnopqrstuvwxyz"; |
| if (upper) { |
| letters = letters.toUpperCase(); |
| } |
| if (english) { |
| |
| // Frequency of English digraphs (from D. Edwards 1/27/66) |
| |
| frequency = new Array( |
| new Array(4, 20, 28, 52, 2, 11, 28, 4, 32, 4, 6, 62, |
| 23, 167, 2, 14, 0, 83, 76, 127, 7, 25, 8, 1, |
| 9, 1), /* aa - az */ |
| |
| new Array(13, 0, 0, 0, 55, 0, 0, 0, 8, 2, 0, 22, 0, 0, |
| 11, 0, 0, 15, 4, 2, 13, 0, 0, 0, 15, 0), /* ba - bz */ |
| |
| new Array(32, 0, 7, 1, 69, 0, 0, 33, 17, 0, 10, 9, 1, |
| 0, 50, 3, 0, 10, 0, 28, 11, 0, 0, 0, 3, 0), /* ca - cz */ |
| |
| new Array(40, 16, 9, 5, 65, 18, 3, 9, 56, 0, 1, 4, 15, |
| 6, 16, 4, 0, 21, 18, 53, 19, 5, 15, 0, 3, 0), /* da - dz */ |
| |
| new Array(84, 20, 55, 125, 51, 40, 19, 16, 50, 1, 4, |
| 55, 54, 146, 35, 37, 6, 191, 149, 65, 9, 26, |
| 21, 12, 5, 0), /* ea - ez */ |
| |
| new Array(19, 3, 5, 1, 19, 21, 1, 3, 30, 2, 0, 11, 1, |
| 0, 51, 0, 0, 26, 8, 47, 6, 3, 3, 0, 2, 0), /* fa - fz */ |
| |
| new Array(20, 4, 3, 2, 35, 1, 3, 15, 18, 0, 0, 5, 1, |
| 4, 21, 1, 1, 20, 9, 21, 9, 0, 5, 0, 1, 0), /* ga - gz */ |
| |
| new Array(101, 1, 3, 0, 270, 5, 1, 6, 57, 0, 0, 0, 3, |
| 2, 44, 1, 0, 3, 10, 18, 6, 0, 5, 0, 3, 0), /* ha - hz */ |
| |
| new Array(40, 7, 51, 23, 25, 9, 11, 3, 0, 0, 2, 38, |
| 25, 202, 56, 12, 1, 46, 79, 117, 1, 22, 0, |
| 4, 0, 3), /* ia - iz */ |
| |
| new Array(3, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, |
| 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0), /* ja - jz */ |
| |
| new Array(1, 0, 0, 0, 11, 0, 0, 0, 13, 0, 0, 0, 0, 2, |
| 0, 0, 0, 0, 6, 2, 1, 0, 2, 0, 1, 0), /* ka - kz */ |
| |
| new Array(44, 2, 5, 12, 62, 7, 5, 2, 42, 1, 1, 53, 2, |
| 2, 25, 1, 1, 2, 16, 23, 9, 0, 1, 0, 33, 0), /* la - lz */ |
| |
| new Array(52, 14, 1, 0, 64, 0, 0, 3, 37, 0, 0, 0, 7, |
| 1, 17, 18, 1, 2, 12, 3, 8, 0, 1, 0, 2, 0), /* ma - mz */ |
| |
| new Array(42, 10, 47, 122, 63, 19, 106, 12, 30, 1, 6, |
| 6, 9, 7, 54, 7, 1, 7, 44, 124, 6, 1, 15, 0, |
| 12, 0), /* na - nz */ |
| |
| new Array(7, 12, 14, 17, 5, 95, 3, 5, 14, 0, 0, 19, |
| 41, 134, 13, 23, 0, 91, 23, 42, 55, 16, 28, |
| 0, 4, 1), /* oa - oz */ |
| |
| new Array(19, 1, 0, 0, 37, 0, 0, 4, 8, 0, 0, 15, 1, 0, |
| 27, 9, 0, 33, 14, 7, 6, 0, 0, 0, 0, 0), /* pa - pz */ |
| |
| new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0), /* qa - qz */ |
| |
| new Array(83, 8, 16, 23, 169, 4, 8, 8, 77, 1, 10, 5, |
| 26, 16, 60, 4, 0, 24, 37, 55, 6, 11, 4, 0, |
| 28, 0), /* ra - rz */ |
| |
| new Array(65, 9, 17, 9, 73, 13, 1, 47, 75, 3, 0, 7, |
| 11, 12, 56, 17, 6, 9, 48, 116, 35, 1, 28, 0, |
| 4, 0), /* sa - sz */ |
| |
| new Array(57, 22, 3, 1, 76, 5, 2, 330, 126, 1, 0, 14, |
| 10, 6, 79, 7, 0, 49, 50, 56, 21, 2, 27, 0, |
| 24, 0), /* ta - tz */ |
| |
| new Array(11, 5, 9, 6, 9, 1, 6, 0, 9, 0, 1, 19, 5, 31, |
| 1, 15, 0, 47, 39, 31, 0, 3, 0, 0, 0, 0), /* ua - uz */ |
| |
| new Array(7, 0, 0, 0, 72, 0, 0, 0, 28, 0, 0, 0, 0, 0, |
| 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0), /* va - vz */ |
| |
| new Array(36, 1, 1, 0, 38, 0, 0, 33, 36, 0, 0, 4, 1, |
| 8, 15, 0, 0, 0, 4, 2, 0, 0, 1, 0, 0, 0), /* wa - wz */ |
| |
| new Array(1, 0, 2, 0, 0, 1, 0, 0, 3, 0, 0, 0, 0, 0, 1, |
| 5, 0, 0, 0, 3, 0, 0, 1, 0, 0, 0), /* xa - xz */ |
| |
| new Array(14, 5, 4, 2, 7, 12, 12, 6, 10, 0, 0, 3, 7, |
| 5, 17, 3, 0, 4, 16, 30, 0, 0, 5, 0, 0, 0), /* ya - yz */ |
| |
| new Array(1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) /* za - zz */ ); |
| |
| // This MUST be equal to the sum of the equivalent rows above. |
| |
| row_sums = new Array( |
| 796, 160, 284, 401, 1276, 262, 199, 539, 777, |
| 16, 39, 351, 243, 751, 662, 181, 17, 683, |
| 662, 968, 248, 115, 180, 17, 162, 5 |
| ); |
| |
| // Frequencies of starting characters. |
| |
| start_freq = new Array( |
| 1299, 425, 725, 271, 375, 470, 93, 223, 1009, |
| 24, 20, 355, 379, 319, 823, 618, 21, 317, |
| 962, 1991, 271, 104, 516, 6, 16, 14 |
| ); |
| |
| // This MUST be equal to the sum of all elements in the above array. |
| |
| total_sum = 11646; |
| } |
| if (gibberish) { |
| gibber = "abcdefghijklmnopqrstuvwxyz" + |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + |
| "0123456789" + |
| "!#$%&()*+,-./:;<=>?@[]^_{|}~"; |
| if (upper) { |
| /* Convert to upper case, leaving two copies of the |
| alphabet for two reasons: first, to favour letters |
| over gnarl, and second, to change only the letter case |
| when the mode is selected. */ |
| gibber = gibber.toUpperCase(); |
| } else if (lower) { |
| gibber = gibber.toLowerCase(); |
| } |
| } |
| } |
| for (line = 1; line <= npass; line++) { |
| password = ""; |
| if (numeric) { |
| for (nchars = 0; nchars < pw_length; nchars++) { |
| if ((sep > 0) && ((nchars % sep) == 0) && (nchars > 0)) { |
| password += sepchar(); |
| } |
| password += ran1.nextInt(9); |
| } |
| } else if (!english) { |
| for (nchars = 0; nchars < pw_length; nchars++) { |
| if ((sep > 0) && ((nchars % sep) == 0) && (nchars > 0)) { |
| password += sepchar(); |
| } |
| if (gibberish) { |
| password += gibber.charAt(ran1.nextInt(gibber.length - 1)); |
| } else { |
| password += letters.charAt(ran1.nextInt(25)); |
| } |
| } |
| } else { |
| position = ran1.nextInt(total_sum - 1); |
| for (row_position = 0, j = 0; position >= row_position; |
| row_position += start_freq[j], j++) { |
| continue; |
| } |
| |
| password = letters.charAt(i = j - 1); |
| nch = 1; |
| for (nchars = pw_length - 1; nchars; --nchars) { |
| |
| // Now find random position within the row. |
| |
| position = ran1.nextInt(row_sums[i] - 1); |
| for (row_position = 0, j = 0; |
| position >= row_position; |
| row_position += frequency[i][j], j++) { |
| } |
| |
| if ((sep > 0) && ((nch % sep) == 0)) { |
| password += sepchar(); |
| } |
| nch++; |
| password += letters.charAt(i = j - 1); |
| } |
| } |
| |
| if ((!numeric) && (!gibberish) && mixed) { |
| var pwm = ''; |
| var j; |
| for (j = 0; j < password.length; j++) { |
| pwm += ran2.nextInt(1) ? (password.charAt(j)) : (password.charAt(j).toUpperCase()); |
| } |
| password = pwm; |
| } |
| |
| /* If requested, calculate the MD5 signature for this key and |
| and save for later appending to the results. */ |
| |
| if (makesig) { |
| var n, m, hex = "0123456789ABCDEF"; |
| |
| init(); |
| for (m = 0; m < password.length; m++) { |
| update(32 + charcodes.indexOf(password.charAt(m))); |
| } |
| finish(); |
| |
| for (n = 0; n < 16; n++) { |
| md5v += hex.charAt(digestBits[n] >> 4); |
| md5v += hex.charAt(digestBits[n] & 0xF); |
| } |
| md5v += "\n"; |
| } |
| |
| aline = "" + line; |
| while (aline.length < ndig) { |
| aline = " " + aline; |
| } |
| v += aline + ") " + password; |
| |
| if ((++lineno) >= npline) { |
| v += "\n"; |
| lineno = 0; |
| } else { |
| v += " "; |
| } |
| } |
| |
| if (makesig) { |
| v += "\n---------- MD5 Signatures ----------\n" + md5v; |
| } |
| |
| document.getElementById('onetime').pad.value = v; |
| window.status = "Done."; |
| } |
| |
| function loadHandler() { |
| for (var i = 0; i < 25; i++) { |
| gen(); |
| } |
| }; |
| |
| //]]> |
| </script> |
| |
| </head> |
| |
| <body class="jsgen" onload="loadHandler();"> |
| |
| <h1><img src="key.gif" class="keyicon" alt="" |
| width="40" height="40" /> One-Time Pad Generator</h1> |
| |
| <p> |
| This page, which requires that your browser support JavaScript |
| (see <a href="#why"><cite>Why JavaScript</cite></a> below), |
| generates one-time pads or password lists in a variety of |
| forms. It is based a high-quality pseudorandom sequence |
| generator, which can be seeded either from the current date |
| and time, or from a seed you provide. Fill in the form below |
| to select the format of the pad and press “Generate” to |
| create the pad in the text box. You can then copy and paste |
| the generated pad into another window to use as you wish. |
| Each of the labels on the request form is linked to a description |
| of that parameter. |
| </p> |
| |
| <form id="onetime" action="#" onsubmit="return false;"> |
| |
| <p class="centre"> |
| <b>Output:</b> |
| <a href="#NumberOfKeys">Number of keys</a>: <input type="text" name="nkeys" value="20" size="4" maxlength="12" /> |
| <a href="#LineLength">Line length</a>: <input type="text" name="linelen" value="48" size="3" maxlength="12" /> |
| <br /> |
| <b>Format:</b> |
| <a href="#KeyLength">Key length</a>: <input type="text" name="klength" value="8" size="3" maxlength="12" /> |
| <a href="#GroupLength">Group length</a>: <input type="text" name="sep" value="4" size="2" maxlength="12" /> |
| |
| <br /> |
| <b>Composition:</b> |
| <a href="#KeyText">Key text</a>: <input type="radio" name="keytype" /> Numeric |
| <input type="radio" name="keytype" /> Word-like |
| <input type="radio" name="keytype" checked="checked" /> Alphabetic |
| <input type="radio" name="keytype" /> Gibberish |
| <br /> |
| <a href="#LetterCase">Letters:</a> |
| <select size="i" name="textcase"> |
| |
| <option value="1" selected="selected">Lower case</option> |
| <option value="2">Upper case</option> |
| <option value="3">Mixed case</option> |
| </select> |
| |
| <input type="checkbox" name="rsep" /> <a href="#RandomSep">Random separators</a> |
| <input type="checkbox" name="dosig" /> <a href="#Signatures">Include signatures</a> |
| |
| <br /> |
| <b><a href="#Seed">Seed:</a></b> |
| <input type="radio" name="seedy" checked="checked" /> From clock |
| <input type="radio" name="seedy" /> User-defined: |
| <input type="text" name="seeder" value="" size="12" maxlength="128" |
| onchange="document.getElementById('onetime').seedy[1].checked=true;" /> |
| <br /> |
| <input type="button" value=" Generate " onclick="gen();" /> |
| |
| <input type="button" value=" Clear " onclick="document.getElementById('onetime').pad.value = '';" /> |
| |
| <input type="button" value=" Select " onclick="document.getElementById('onetime').pad.select();" /><br /> |
| <textarea name="pad" rows="12" cols="72"> |
| |
| Uh, oh. It appears your browser either does not support |
| JavaScript or that JavaScript has been disabled. You'll |
| have to replace your browser with one supporting JavaScript |
| (or enable it, if that's the problem) before you can use |
| this page. |
| </textarea> |
| </p> |
| |
| </form> |
| |
| <script type="text/javascript"> |
| //<![CDATA[ |
| // Clear out "sorry, no JavaScript" message from text box. |
| document.getElementById('onetime').pad.value = ""; |
| //]]> |
| </script> |
| |
| <h2><a name="details">Details</a></h2> |
| |
| <p> |
| Each of the fields in the one-time pad request form is described |
| below. |
| </p> |
| |
| <h3><a name="output">Output</a></h3> |
| |
| <h4><a name="NumberOfKeys">Number of keys</a></h4> |
| |
| <p> |
| Enter the number of keys you'd like to generate. If you generate |
| more than fit in the results text box, you can use the scroll |
| bar to view the additional lines. |
| </p> |
| |
| <h4><a name="LineLength">Line length</a></h4> |
| |
| <p> |
| Lines in the output will be limited to the given length (or contain |
| only one key if the line length is less than required for a single |
| key). If the line length is greater than the width of the results |
| box, you can use the horizontal scroll bar to view the rest of the |
| line. Enter <tt>0</tt> to force one key per line; this is handy |
| when you're preparing a list of keys to be read by a computer program. |
| </p> |
| |
| <h3><a name="format">Format</a></h3> |
| |
| <h4><a name="KeyLength">Key length</a></h4> |
| |
| <p> |
| Each key will contain this number of characters, not counting |
| separators between groups. |
| </p> |
| |
| <h4><a name="GroupLength">Group length</a></h4> |
| |
| <p> |
| If a nonzero value is entered in this field, the key will be broken |
| into groups of the given number of characters by separators. Humans |
| find it easier to read and remember sequences of characters when |
| divided into groups of five or fewer characters. |
| </p> |
| |
| <h3><a name="composition">Composition</a></h3> |
| |
| <h4><a name="KeyText">Key text</a></h4> |
| |
| <p> |
| This set of radio buttons lets you select the character set used in |
| the keys. The alternatives are listed in order of |
| increasing security. |
| </p> |
| |
| <blockquote> |
| <dl> |
| <dt><b>Numeric</b></dt> |
| <dd>Keys contain only the decimal digits “0” through “9”. |
| <em>Least secure.</em></dd> |
| |
| <dt><b>Word-like</b></dt> |
| <dd>Keys are composed of alphabetic characters which obey the |
| digraph statistics of English text. Such keys contain |
| sequences of vowels and consonants familiar to speakers |
| of Western languages, and are therefore usually easier to |
| memorise but, for a given key length, are less secure than |
| purely random letters.</dd> |
| |
| <dt><b>Alphabetic</b></dt> |
| <dd>Keys consist of letters of the alphabet chosen at random. |
| Each character has an equal probability of being one of |
| the 26 letters.</dd> |
| |
| <dt><b>Gibberish</b></dt> |
| <dd>Keys use most of the printable ASCII character set, excluding |
| only characters frequently used for quoting purposes. This |
| option provides the greatest security for a given key length, |
| but most people find keys like this difficult to memorise or |
| even transcribe from a printed pad. If a human is in the loop, |
| it's often better to use a longer alphabetic or word-like key. |
| <em>Most secure.</em></dd> |
| </dl> |
| |
| </blockquote> |
| |
| <h4><a name="LetterCase">Letters</a></h4> |
| |
| <p> |
| The case of letters in keys generated with Word-like, Alphabetic, and |
| Gibberish key text will be as chosen. Most people find it easier to |
| read lower case letters than all capitals, but for some applications |
| (for example, where keys must be scanned optically by hardware that |
| only recognises capital letters), capitals are required. Selecting |
| “Mixed case” creates keys with a mix of upper- and |
| lower-case letters; such keys are more secure than those with uniform |
| letter case, but do not pass the “telephone test”: you |
| can't read them across a (hopefully secure) voice link without having |
| to indicate whether each letter is or is not a capital. |
| </p> |
| |
| <h4><a name="RandomSep">Random separators</a></h4> |
| |
| <p> |
| When the <a href="#KeyLength">Key length</a> is longer than |
| a nonzero <a href="#GroupLength">Group length</a> specification, |
| the key is divided into sequences of the given group length |
| by separator characters. By default, a hyphen, “<tt>-</tt>”, is used |
| to separate groups. If you check this box, separators will be |
| chosen at random among punctuation marks generally acceptable |
| for applications such as passwords. If you're generating passwords |
| for a computer system, random separators dramatically increase |
| the difficulty of guessing passwords by exhaustive search. |
| </p> |
| |
| <h4><a name="Signatures">Include signatures</a></h4> |
| |
| <p> |
| |
| When this box is checked, at the end of the list of keys, preceded by |
| a line beginning with ten dashes “<tt>-</tt>”, the 128 bit MD5 signature of |
| each key is given, one per line, with signatures expressed as 32 |
| hexadecimal digits. Key signatures can be used to increase security |
| when keys are used to control access to computer systems or databases. |
| Instead of storing a copy of the keys, the computer stores their |
| signatures. When the user enters a key, its signature is computed |
| with the same MD5 algorithm used to generate it initially, and the key |
| is accepted only if the signature matches. Since discovering |
| a key which will generate a given signature is believed to be |
| computationally prohibitive, even if the list of signatures stored on |
| the computer is compromised, that information will not permit an |
| intruder to deduce a valid key. |
| </p> |
| |
| <p> |
| Signature calculation is a computationally intense process for which |
| JavaScript is not ideally suited; be patient while signatures are |
| generated, especially if your computer has modest |
| processing speed. |
| </p> |
| |
| <p> |
| For signature-based validation to be secure, it is essential |
| the original keys be long enough to prohibit discovery of matching |
| signatures by exhaustive search. Suppose, for example, one used |
| four digit numeric keys, as used for Personal Identification |
| Numbers (PINs) by many credit card systems. Since only 10,000 |
| different keys exist, one could simply compute the signatures of |
| every possible key from 0000 through 9999, permitting an attacker who |
| came into possession of the table of signatures to recover the |
| keys by a simple lookup process. For maximum security, keys must |
| contain at least as much information as the 128 bit signatures |
| computed from them. This implies a minimum key length (not counting |
| non-random separator characters) for the various key formats as |
| follows: |
| </p> |
| |
| <table class="c" border="border" cellpadding="4"> |
| <tr><th>Key Composition</th> <th>Minimum Characters</th></tr> |
| |
| <tr><td>Numeric</td> <td class="c">39</td></tr> |
| <tr><td>Word-like</td> <td class="c">30</td></tr> |
| <tr><td>Alphabetic</td> <td class="c">28</td></tr> |
| <tr><td>Gibberish</td> <td class="c">20</td></tr> |
| </table> |
| |
| <p> |
| It should be noted that for many practical applications there is no |
| need for anything approaching 128-bit security. The guidelines above |
| apply only in the case where maximum protection in the event of |
| undetected compromise of key signatures occurs. In many |
| cases, much shorter keys are acceptable, especially when it is assumed |
| that a compromise of the system's password or signature database would |
| be only part of a much more serious subversion of all resources |
| on the system. |
| </p> |
| |
| <h3><a name="Seed">Seed</a></h3> |
| |
| <p> |
| The <em>seed</em> is the starting value which determines all |
| subsequent values in the pseudorandom sequence used to generate |
| the one-time pad. Given the seed, the pad can be reproduced. The |
| seed is a 31-bit number which can be derived from the date and |
| time at which the one-time pad was requested, or from a |
| user-defined seed value. If the user-defined seed consists |
| entirely of decimal digits, it is used directly as the seed, |
| modulo 2<sup>31</sup>; if a string containing non-digit characters |
| is entered, it is used to compute a <em>hash code</em> which is |
| used to seed the generator. |
| |
| </p> |
| |
| <p> |
| When the clock is used to create the seed, the seed value is entered |
| in the User-defined box to allow you, by checking “User-defined”, |
| to produce additional pads with the same seed. |
| </p> |
| |
| <h2><a name="why">Why JavaScript?</a></h2> |
| |
| <p> |
| At first glance, JavaScript may seem an odd choice for programming |
| a page such as this. The one-time pad generator program is rather |
| large and complicated, and downloading it to your browser takes longer |
| than would be required for a Java applet or to transfer a |
| one-time pad generated by a CGI program on the Web server. I chose |
| JavaScript for two reasons: <em>security</em> and <em>transparency</em>. |
| |
| </p> |
| |
| <p> |
| <b>Security.</b> |
| The sole reason for the existence of one-time pads is to |
| provide a source of information known only to people to whom |
| they have been distributed in a secure manner. This means |
| the generation process cannot involve any link whose security |
| is suspect. If the pad were generated on a Web server and |
| transmitted to you, it would have to pass over the |
| Internet, where any intermediate site might make a copy |
| of your pad before you even received it. Even if some |
| mechanism such as encryption could absolutely prevent the |
| pad's being intercepted, you'd still have no way to be sure |
| the site generating the pad didn't keep a copy |
| in a file, conveniently tagged with your Internet address. |
| </p> |
| |
| <p> |
| In order to have any degree of security, it is essential |
| that the pad be generated on <em>your</em> computer, without |
| involving any transmission or interaction with other |
| sites on the Internet. A Web browser with JavaScript makes |
| this possible, since the generation program embedded in this |
| page runs entirely on your own computer and does not |
| transmit anything over the Internet. Its output appears |
| only in the text box, allowing you to cut and paste it |
| to another application. From there on, its security is |
| up to you. |
| </p> |
| |
| <p> |
| Security is never absolute. A one-time pad generated with |
| this page might be compromised in a variety of ways, including |
| the following: |
| |
| </p> |
| |
| <ul> |
| <li> Your Web browser and/or JavaScript interpreter may |
| contain bugs or deliberate security violations |
| which report activity on your computer back to some |
| other Internet site.</li> |
| |
| <li> Some other applet running on another page of your |
| browser, perhaps without your being aware of its |
| existence, is spying on other windows.</li> |
| |
| <li> Some other application running on your computer |
| may have compromised your system's security and |
| be snooping on your activity.</li> |
| |
| <li> Your Web browser may be keeping a “history log” |
| |
| or “cache” of data you generate. Somebody may |
| come along later and recover a copy of the pad |
| from that log.</li> |
| |
| <li> The implementation of this page may contain a bug |
| or deliberate error which makes its output |
| predictable. This is why <a href="#trans"><cite>transparency</cite></a>, |
| discussed below, is essential.</li> |
| |
| <li> Your computer's security may have been compromised |
| physically; when's the last time you checked that a |
| bug that transmits your keystrokes and/or screen |
| contents to that white van parked down the street |
| wasn't lurking inside your computer cabinet?</li> |
| </ul> |
| |
| <p> |
| One can whip oneself into a fine fever of paranoia worrying about |
| things like this. One way to rule out the most probable risks |
| is to download a copy of the generator page and run it |
| from a “<tt>file:</tt>” URL on a computer which has no network |
| connection whatsoever and is located in a secure location |
| under your control. And look very carefully at any files |
| created by your Web browser. You may find the most interesting |
| things squirreled away there…. |
| </p> |
| |
| <p> |
| <b><a name="trans">Transparency</a>.</b> |
| Any security-related tool is only as good as its design |
| and implementation. <em>Transparency</em> means that, in |
| essence, all the moving parts are visible so you can judge |
| for yourself whether the tool merits your confidence. In |
| the case of a program, this means that source code must |
| be available, and that you can verify that the program |
| you're running corresponds to the source code provided. |
| |
| </p> |
| |
| <p> |
| The very nature of JavaScript achieves this transparency. |
| The program is embedded into this actual Web page; to |
| examine it you need only use your browser's “View Source” |
| facility, or save the page into a file on your computer |
| and read it with a text editor. JavaScript's being |
| an interpreted language eliminates the risk of your running |
| a program different from the purported source code: with |
| an interpreted language what you read is what you run. |
| </p> |
| |
| <p> |
| Transparency is important even if you don't know enough about |
| programming or security to determine whether the program |
| contains any flaws. The very fact that it can be examined |
| by anybody allows those with the required expertise to pass |
| judgment, and you can form your own conclusions based on |
| their analysis. |
| </p> |
| |
| <h2>Credits</h2> |
| |
| <p> |
| |
| The pseudorandom sequence generator is based on L'Ecuyer's |
| two-sequence generator as described in |
| <cite>Communications of the ACM</cite>, Vol. 31 (1968), page 742. |
| A Bays-Durham shuffle is used to guard against regularities |
| lurking in L'Ecuyer's algorithm; see |
| <cite>ACM Transactions on Mathematical Software</cite>, Vol. 2 (1976) |
| pages 59–64 for details. |
| </p> |
| |
| <p> |
| The JavaScript implementation of the |
| <a href="http://www.ietf.org/rfc/rfc1321.txt"><b>MD5 message-digest algorithm</b></a> |
| was developed by Henri Torgemane; please view the source code of this |
| page to examine the code, including the copyright notice and |
| conditions of use. The MD5 algorithm was developed by Ron Rivest. |
| </p> |
| |
| <p /> |
| |
| <hr /> |
| |
| <p /> |
| |
| <table class="r"> |
| <tr><td align="center"> |
| <a class="i" href="http://validator.w3.org/check?uri=referer"><img |
| class="button" |
| src="valid-xhtml10.png" |
| alt="Valid XHTML 1.0" height="31" width="88" /></a> |
| </td></tr> |
| </table> |
| |
| <address> |
| by <a href="/">John Walker</a><br /> |
| May 26, 1997<br /> |
| |
| Updated: November 2006 |
| </address> |
| |
| <p class="centre"> |
| <em>This document is in the public domain.</em> |
| </p> |
| </body> |
| </html> |
| |