mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-27 10:50:35 +00:00
1345 lines
43 KiB
HTML
1345 lines
43 KiB
HTML
<!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".includes(useed.charAt(i))) {
|
|
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>
|
|
|