accum.js 4.4 KB
Newer Older
6
cloud  
6360c489aee4323e88771a44 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
/* basic entropy accumulator */
var accum = (function() {

    var pool,    // randomness pool
        time,    // start timestamp
        last;    // last step timestamp

    /* initialize with default pool */
    function init() {
        pool = [];
        time = new Date().getTime();
        last = time;
        // use Math.random
        pool.push((Math.random() * 0xffffffff)|0);
        // use current time
        pool.push(time|0);
    }

    /* perform one step */
    function step() {
        if (!to)
            return;
        if (pool.length >= 255) { // stop at 255 values (1 more is added on fetch)
            stop();
            return;
        }
        var now = new Date().getTime();
        // use actual time difference
        pool.push(now-last);
        // always compute, occasionally use Math.random
        var rnd = (Math.random() * 0xffffffff)|0;
        if (now % 2)
            pool[pool.length-1] += rnd;
        last = now;
        to = setTimeout(step, 100+Math.random()*512); // use hypothetical time difference
    }

    var to = null;

    /* starts accumulating */
    function start() {
        if (to) return;
        to = setTimeout(step, 100+Math.random()*512);
        if (console.log)
            console.log("bcrypt-isaac: collecting entropy...");
        // install collectors
        if (typeof window !== 'undefined' && window && window.addEventListener)
            window.addEventListener("load", loadCollector, false),
            window.addEventListener("mousemove", mouseCollector, false),
            window.addEventListener("touchmove", touchCollector, false);
        else if (typeof document !== 'undefined' && document && document.attachEvent)
            document.attachEvent("onload", loadCollector),
            document.attachEvent("onmousemove", mouseCollector);
    }

    /* stops accumulating */
    function stop() {
        if (!to) return;
        clearTimeout(to); to = null;
        // uninstall collectors
        if (typeof window !== 'undefined' && window && window.removeEventListener)
            window.removeEventListener("load", loadCollector, false),
            window.removeEventListener("mousemove", mouseCollector, false),
            window.removeEventListener("touchmove", touchCollector, false);
        else if (typeof document !== 'undefined' && document && document.detachEvent)
            document.detachEvent("onload", loadCollector),
            document.detachEvent("onmousemove", mouseCollector);
    }

    /* fetches the randomness pool */
    function fetch() {
        // add overall time difference
        pool.push((new Date().getTime()-time)|0);
        var res = pool;
        init();
        if (console.log)
            console.log("bcrypt-isaac: using "+res.length+"/256 samples of entropy");
        // console.log(res);
        return res;
    }

    /* adds the current time to the top of the pool */
    function addTime() {
        pool[pool.length-1] += new Date().getTime() - time;
    }

    /* page load collector */
    function loadCollector() {
        if (!to || pool.length >= 255)
            return;
        pool.push(0);
        addTime();
    }

    /* mouse events collector */
    function mouseCollector(ev) {
        if (!to || pool.length >= 255)
            return;
        try {
            var x = ev.x || ev.clientX || ev.offsetX || 0,
                y = ev.y || ev.clientY || ev.offsetY || 0;
            if (x != 0 || y != 0)
                pool[pool.length-1] += ((x-mouseCollector.last[0]) ^ (y-mouseCollector.last[1])),
                addTime(),
                mouseCollector.last = [x,y];
        } catch (e) {}
    }
    mouseCollector.last = [0,0];

    /* touch events collector */
    function touchCollector(ev) {
        if (!to || pool.length >= 255)
            return;
        try {
            var touch = ev.touches[0] || ev.changedTouches[0];
            var x = touch.pageX || touch.clientX || 0,
                y = touch.pageY || touch.clientY || 0;
            if (x != 0 || y != 0)
                pool[pool.length-1] += (x-touchCollector.last[0]) ^ (y-touchCollector.last[1]),
                addTime(),
                touchCollector.last = [x,y];
        } catch (e) {}
    }
    touchCollector.last = [0,0];

    init();
    return {
        "start": start,
        "stop": stop,
        "fetch": fetch
    }

})();