AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
random.c
Go to the documentation of this file.
1
13
14#include <core/system.h>
15#include <core/string.h>
16#include <core/arch.h>
17#include <dev/dev.h>
18#include <dev/random.h>
19#include <fs/posix.h>
20
21#include <memdev.h>
22
23#define ROTL(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
24#define QR(a, b, c, d) ( \
25 a += b, d ^= a, d = ROTL(d, 16), \
26 c += d, b ^= c, b = ROTL(b, 12), \
27 a += b, d ^= a, d = ROTL(d, 8), \
28 c += d, b ^= c, b = ROTL(b, 7))
29
31static void chacha20_block(const uint32_t in[16], uint32_t out[16])
32{
33 uint32_t x[16];
34
35 for (int i = 0; i < 16; ++i)
36 x[i] = in[i];
37
38 for (int i = 0; i < 10; ++i) {
39 QR(x[0], x[4], x[ 8], x[12]);
40 QR(x[1], x[5], x[ 9], x[13]);
41 QR(x[2], x[6], x[10], x[14]);
42 QR(x[3], x[7], x[11], x[15]);
43 QR(x[0], x[5], x[10], x[15]);
44 QR(x[1], x[6], x[11], x[12]);
45 QR(x[2], x[7], x[ 8], x[13]);
46 QR(x[3], x[4], x[ 9], x[14]);
47 }
48
49 for (int i = 0; i < 16; ++i)
50 out[i] = x[i] + in[i];
51}
52
53/* ChaCha20's state: the constant "expand 32-byte k", the key (words 4 to
54 * 11), a counter (12, 13) and a nonce (14, 15) */
55static uint32_t state[16] = {
56 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
57};
58
59static uint32_t pool[8];
60static unsigned pool_i;
61
69{
70 pool[pool_i++ % 8] ^= value;
71}
72
74static void random_stir(void)
75{
78
79 for (int i = 0; i < 8; ++i) {
80 state[4 + i] ^= pool[i];
81 pool[i] = 0;
82 }
83
84 state[14] ^= (uint32_t) (arch_cycles() >> 8);
85}
86
93void random_get(void *_buf, size_t len)
94{
95 uint8_t *buf = _buf;
96 uint32_t block[16];
97
99
100 while (len) {
101 chacha20_block(state, block);
102
103 if (!++state[12])
104 ++state[13];
105
106 size_t n = MIN(len, sizeof(block));
107 memcpy(buf, block, n);
108 buf += n;
109 len -= n;
110 }
111
112 /* a new key, so that what was given can't be found again from the
113 * state */
114 chacha20_block(state, block);
115
116 if (!++state[12])
117 ++state[13];
118
119 for (int i = 0; i < 8; ++i)
120 state[4 + i] = block[i];
121
122 memset(block, 0, sizeof(block));
123}
124
126static ssize_t randomdev_read(struct devid *dd __unused, off_t offset __unused, struct iobuf *io)
127{
128 uint8_t buf[256];
129 size_t size = io->resid, done = 0;
130
131 while (done < size) {
132 size_t len = MIN(size - done, sizeof(buf));
133 random_get(buf, len);
134
135 ssize_t r = iobuf_out(io, buf, len);
136
137 if (r < 0) {
138 memset(buf, 0, sizeof(buf));
139 return done ? (ssize_t) done : r;
140 }
141
142 done += r;
143
144 if ((size_t) r < len)
145 break;
146 }
147
148 memset(buf, 0, sizeof(buf));
149 return done;
150}
151
153static ssize_t randomdev_write(struct devid *dd __unused, off_t offset __unused, struct iobuf *io)
154{
155 uint8_t buf[256];
156 size_t size = io->resid, done = 0;
157
158 while (done < size) {
159 ssize_t len = iobuf_in(io, buf, MIN(size - done, sizeof(buf)));
160
161 if (len <= 0)
162 return done ? (ssize_t) done : len;
163
164 for (ssize_t i = 0; i < len; ++i)
165 random_add((uint32_t) buf[i] << (8 * ((done + i) % 4)));
166
167 done += len;
168 }
169
170 return done;
171}
172
173struct dev randomdev = {
174 .read = randomdev_read,
175 .write = randomdev_write,
176
177 .fops = {
178 .open = posix_file_open,
179 .read = posix_file_read,
180 .write = posix_file_write,
181 .close = posix_file_close,
182
183 .can_read = __vfs_can_always,
184 .can_write = __vfs_can_always,
185 .eof = __vfs_eof_never,
186 },
187};
#define MIN(a, b)
Definition system.h:11
ssize_t iobuf_out(struct iobuf *io, const void *src, size_t n)
Copies bytes from the kernel into the iobuf's buffer, and moves past them.
Definition iobuf.c:115
ssize_t iobuf_in(struct iobuf *io, void *dst, size_t n)
Copies bytes from the iobuf's buffer into the kernel, and moves past them.
Definition iobuf.c:135
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
struct dev randomdev
Definition random.c:173
int posix_file_open(struct file *file)
Finishes opening a file: with O_TRUNC, a regular file is truncated to 0 bytes.
Definition open.c:17
int posix_file_close(struct file *file)
Closes an open file by dropping its reference to its vnode.
Definition close.c:15
ssize_t posix_file_read(struct file *file, struct iobuf *io)
Reads from an open file at its offset, and moves the offset past what was read.
Definition read.c:29
ssize_t posix_file_write(struct file *file, struct iobuf *io)
Writes to an open file at its offset, and moves the offset past what was written.
Definition write.c:25
static uint32_t pool[8]
Definition random.c:59
static uint32_t state[16]
Definition random.c:55
#define QR(a, b, c, d)
Definition random.c:24
static void chacha20_block(const uint32_t in[16], uint32_t out[16])
Computes one ChaCha20 block (20 rounds) of the state in, into out.
Definition random.c:31
static ssize_t randomdev_read(struct devid *dd, off_t offset, struct iobuf *io)
Reads random bytes, a buffer at a time; the buffer is wiped after.
Definition random.c:126
static unsigned pool_i
Definition random.c:60
static void random_stir(void)
Mixes the pool, and the time, into the key, and empties the pool.
Definition random.c:74
void random_add(uint32_t value)
Stirs a value into the pool, which goes into the next key.
Definition random.c:68
static ssize_t randomdev_write(struct devid *dd, off_t offset, struct iobuf *io)
Stirs what is written into the pool.
Definition random.c:153
void random_get(void *_buf, size_t len)
Fills a buffer with random bytes.
Definition random.c:93
unsigned int uint32_t
Definition stddef.h:22
unsigned char uint8_t
Definition stddef.h:20
A device driver: its operations, any of which may be NULL.
Definition dev.h:28
Which device: its kind (S_IFCHR or S_IFBLK) and numbers.
Definition dev.h:21
An iobuf.
Definition iobuf.h:35
size_t resid
Definition iobuf.h:38
uint64_t arch_rtime_ns(void)
Reads the monotonic clock, which starts at boot.
Definition timer.c:56
uint64_t arch_cycles(void)
Reads a counter that changes as fast as the CPU runs, which the kernel uses as a source of randomness...
Definition timer.c:82
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10