1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345 |
- <!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>
|