summaryrefslogtreecommitdiffstats
path: root/build/pgo/js-input/crypto-otp.html
diff options
context:
space:
mode:
Diffstat (limited to 'build/pgo/js-input/crypto-otp.html')
-rw-r--r--build/pgo/js-input/crypto-otp.html1344
1 files changed, 1344 insertions, 0 deletions
diff --git a/build/pgo/js-input/crypto-otp.html b/build/pgo/js-input/crypto-otp.html
new file mode 100644
index 000000000..f6e1ca295
--- /dev/null
+++ b/build/pgo/js-input/crypto-otp.html
@@ -0,0 +1,1344 @@
+<!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" /> &nbsp; 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 &ldquo;Generate&rdquo; 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();" />
+&nbsp;
+<input type="button" value=" Clear " onclick="document.getElementById('onetime').pad.value = '';" />
+&nbsp;
+<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 &ldquo;0&rdquo; through &ldquo;9&rdquo;.
+ <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
+&ldquo;Mixed&nbsp;case&rdquo; 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 &ldquo;telephone test&rdquo;: 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, &ldquo;<tt>-</tt>&rdquo;, 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 &ldquo;<tt>-</tt>&rdquo;, 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 &ldquo;User-defined&rdquo;,
+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 &ldquo;history log&rdquo;
+
+ or &ldquo;cache&rdquo; 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 &ldquo;<tt>file:</tt>&rdquo; 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&hellip;.
+</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 &ldquo;View Source&rdquo;
+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&ndash;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>
+