aboutsummaryrefslogtreecommitdiffstats
path: root/backend/node_modules/bcryptjs/src/bcrypt/prng/accum.js
blob: 025d5c8df9867f3a25259b2740151738a93f161e (plain) (blame)
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
    }

})();