﻿// Entropy collection utilities
/* Start by declaring static storage and initialise
the entropy vector from the time we come through
here. */
var entropyData = new Array(); // Collected entropy data
var edlen = 0; // Keyboard array data length
addEntropyTime(); // Start entropy collection with page load time
ce(); // Roll milliseconds into initial entropy
// Add a byte to the entropy vector
function addEntropyByte(b) {
    entropyData[edlen++] = b;
}
/* Capture entropy. When the user presses a key or performs
various other events for which we can request
notification, add the time in 255ths of a second to the
entropyData array. The name of the function is short
so it doesn't bloat the form object declarations in
which it appears in various "onXXX" events. */
function ce() {
    addEntropyByte(Math.floor((((new Date).getMilliseconds()) * 255) / 999));
}
// Add a 32 bit quantity to the entropy vector
function addEntropy32(w) {
    var i;
    for (i = 0; i < 4; i++) {
        addEntropyByte(w & 0xFF);
        w >>= 8;
    }
}
/* Add the current time and date (milliseconds since the epoch,
truncated to 32 bits) to the entropy vector. */
function addEntropyTime() {
    addEntropy32((new Date()).getTime());
}
/* Start collection of entropy from mouse movements. The
argument specifies the number of entropy items to be
obtained from mouse motion, after which mouse motion
will be ignored. Note that you can re-enable mouse
motion collection at any time if not already underway. */
var mouseMotionCollect = 0;
var oldMoveHandler; // For saving and restoring mouse move handler in IE4
function mouseMotionEntropy(maxsamp) {
    if (mouseMotionCollect <= 0) {
        mouseMotionCollect = maxsamp;
        if ((document.implementation.hasFeature("Events", "2.0")) &&
document.addEventListener) {
            // Browser supports Document Object Model (DOM) 2 events
            document.addEventListener("mousemove", mouseMoveEntropy, false);
        } else {
            if (document.attachEvent) {
                // Internet Explorer 5 and above event model
                document.attachEvent("onmousemove", mouseMoveEntropy);
            } else {
                // Internet Explorer 4 event model
                oldMoveHandler = document.onmousemove;
                document.onmousemove = mouseMoveEntropy;
            }
        }
        //dump("Mouse enable", mouseMotionCollect);
    }
}
/* Collect entropy from mouse motion events. Note that
this is craftily coded to work with either DOM2 or Internet
Explorer style events. Note that we don't use every successive
mouse movement event. Instead, we XOR the three bytes collected
from the mouse and use that to determine how many subsequent
mouse movements we ignore before capturing the next one. */
var mouseEntropyTime = 0; // Delay counter for mouse entropy collection
function mouseMoveEntropy(e) {
    if (!e) {
        e = window.event; // Internet Explorer event model
    }
    if (mouseMotionCollect > 0) {
        if (mouseEntropyTime-- <= 0) {
            addEntropyByte(e.screenX & 0xFF);
            addEntropyByte(e.screenY & 0xFF);
            ce();
            mouseMotionCollect--;
            mouseEntropyTime = (entropyData[edlen - 3] ^ entropyData[edlen - 2] ^
entropyData[edlen - 1]) % 19;
            //dump("Mouse Move", byteArrayToHex(entropyData.slice(-3)));
        }
        if (mouseMotionCollect <= 0) {
            if (document.removeEventListener) {
                document.removeEventListener("mousemove", mouseMoveEntropy, false);
            } else if (document.detachEvent) {
                document.detachEvent("onmousemove", mouseMoveEntropy);
            } else {
                document.onmousemove = oldMoveHandler;
            }
            //dump("Spung!", 0);
        }
    }
}
/* Compute a 32 byte key value from the entropy vector.
We compute the value by taking the MD5 sum of the even
and odd bytes respectively of the entropy vector, then
concatenating the two MD5 sums. */
function keyFromEntropy() {
    var i, k = new Array(32);
    if (edlen == 0) {
        alert("Blooie! Entropy vector void at call to keyFromEntropy.");
    }
    //dump("Entropy bytes", edlen);
    md5_init();
    for (i = 0; i < edlen; i += 2) {
        md5_update(entropyData[i]);
    }
    md5_finish();
    for (i = 0; i < 16; i++) {
        k[i] = digestBits[i];
    }
    md5_init();
    for (i = 1; i < edlen; i += 2) {
        md5_update(entropyData[i]);
    }
    md5_finish();
    for (i = 0; i < 16; i++) {
        k[i + 16] = digestBits[i];
    }
    //dump("keyFromEntropy", byteArrayToHex(k));
    return k;
} 
