]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/random.c
d401e7e0181eccbe1f7a58b099cdbb64402f2c7c
[plan9front.git] / sys / src / 9 / port / random.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "../port/error.h"
7
8 #include        <libsec.h>
9
10 /* machine specific hardware random number generator */
11 void (*hwrandbuf)(void*, ulong) = nil;
12
13 static struct
14 {
15         QLock;
16         Chachastate;
17 } *rs;
18
19 typedef struct Seedbuf Seedbuf;
20 struct Seedbuf
21 {
22         ulong           randomcount;
23         uchar           buf[64];
24         uchar           nbuf;
25         uchar           next;
26         ushort          bits;
27
28         SHA2_512state   ds;
29 };
30
31 static void
32 randomsample(Ureg*, Timer *t)
33 {
34         Seedbuf *s = t->ta;
35
36         if(s->randomcount == 0 || s->nbuf >= sizeof(s->buf))
37                 return;
38         s->bits = (s->bits<<2) ^ s->randomcount;
39         s->randomcount = 0;
40         if(++s->next < 8/2)
41                 return;
42         s->next = 0;
43         s->buf[s->nbuf++] ^= s->bits;
44 }
45
46 static void
47 randomseed(void*)
48 {
49         Seedbuf *s;
50
51         s = secalloc(sizeof(Seedbuf));
52
53         if(hwrandbuf != nil)
54                 (*hwrandbuf)(s->buf, sizeof(s->buf));
55
56         /* Frequency close but not equal to HZ */
57         up->tns = (vlong)(MS2HZ+3)*1000000LL;
58         up->tmode = Tperiodic;
59         up->tt = nil;
60         up->ta = s;
61         up->tf = randomsample;
62         timeradd(up);
63         while(s->nbuf < sizeof(s->buf)){
64                 if(++s->randomcount <= 100000)
65                         continue;
66                 if(anyhigher())
67                         sched();
68         }
69         timerdel(up);
70
71         sha2_512(s->buf, sizeof(s->buf), s->buf, &s->ds);
72         setupChachastate(rs, s->buf, 32, s->buf+32, 12, 20);
73         qunlock(rs);
74
75         secfree(s);
76
77         pexit("", 1);
78 }
79
80 void
81 randominit(void)
82 {
83         rs = secalloc(sizeof(*rs));
84         qlock(rs);      /* randomseed() unlocks once seeded */
85         kproc("randomseed", randomseed, nil);
86 }
87
88 ulong
89 randomread(void *p, ulong n)
90 {
91         Chachastate c;
92         ulong b;
93
94         if(n == 0)
95                 return 0;
96
97         if(hwrandbuf != nil)
98                 (*hwrandbuf)(p, n);
99
100         /* copy chacha state and advance block counter */
101         qlock(rs);
102         c = *rs;
103         b = rs->input[12];
104         rs->input[12] += (n + ChachaBsize-1)/ChachaBsize;
105         if(rs->input[12] < b) rs->input[13]++;
106         qunlock(rs);
107
108         /* encrypt the buffer, can fault */
109         chacha_encrypt((uchar*)p, n, &c);
110
111         /* prevent state leakage */
112         memset(&c, 0, sizeof(c));
113
114         return n;
115 }
116
117 /* used by fastrand() */
118 void
119 genrandom(uchar *p, int n)
120 {
121         randomread(p, n);
122 }