Fri Dec 6 14:43:18 2019 UTC ()
Teach `rndctl -L' to update the seed file, not just delete it.

The seed file is updated by entering the old seed into the system and
then hashing the old seed together with data from /dev/urandom, and
writing it atomically with write-to-temporary/rename-to-permanent.

This way, interruption by crash or power loss does not obliterate
your persistent entropy (unless it causes file system corruption).


(riastradh)
diff -r1.3 -r1.4 src/sbin/rndctl/Makefile
diff -r0 -r1.1 src/sbin/rndctl/namespace.h
diff -r1.22 -r1.23 src/sbin/rndctl/rndctl.8
diff -r1.30 -r1.31 src/sbin/rndctl/rndctl.c

cvs diff -r1.3 -r1.4 src/sbin/rndctl/Makefile (expand / switch to unified diff)

--- src/sbin/rndctl/Makefile 2019/10/13 07:28:13 1.3
+++ src/sbin/rndctl/Makefile 2019/12/06 14:43:18 1.4
@@ -1,8 +1,20 @@ @@ -1,8 +1,20 @@
1# $NetBSD: Makefile,v 1.3 2019/10/13 07:28:13 mrg Exp $ 1# $NetBSD: Makefile,v 1.4 2019/12/06 14:43:18 riastradh Exp $
2 2
3PROG= rndctl 3PROG= rndctl
4MAN= rndctl.8 4MAN= rndctl.8
5 5
6COPTS.rndctl.c+= ${GCC_NO_STRINGOP_TRUNCATION} 6COPTS.rndctl.c+= ${GCC_NO_STRINGOP_TRUNCATION}
7 7
 8SRCS+= rndctl.c
 9
 10# Hack: libc does not export public SHA-3 symbols, so we'll just copy
 11# them here statically.
 12.PATH: ${NETBSDSRCDIR}/common/lib/libc/hash/sha3
 13
 14# Hack for namespace.h in sha3.c.
 15CPPFLAGS+= -I${.CURDIR}
 16
 17SRCS+= sha3.c
 18SRCS+= keccak.c
 19
8.include <bsd.prog.mk> 20.include <bsd.prog.mk>

File Added: src/sbin/rndctl/namespace.h
/* dummy for sha3.c */

cvs diff -r1.22 -r1.23 src/sbin/rndctl/rndctl.8 (expand / switch to unified diff)

--- src/sbin/rndctl/rndctl.8 2014/08/10 17:13:02 1.22
+++ src/sbin/rndctl/rndctl.8 2019/12/06 14:43:18 1.23
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1.\" $NetBSD: rndctl.8,v 1.22 2014/08/10 17:13:02 wiz Exp $ 1.\" $NetBSD: rndctl.8,v 1.23 2019/12/06 14:43:18 riastradh Exp $
2.\" 2.\"
3.\" Copyright (c) 1997 Michael Graff 3.\" Copyright (c) 1997 Michael Graff
4.\" All rights reserved. 4.\" All rights reserved.
5.\" 5.\"
6.\" Redistribution and use in source and binary forms, with or without 6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions 7.\" modification, are permitted provided that the following conditions
8.\" are met: 8.\" are met:
9.\" 1. Redistributions of source code must retain the above copyright 9.\" 1. Redistributions of source code must retain the above copyright
10.\" notice, this list of conditions and the following disclaimer. 10.\" notice, this list of conditions and the following disclaimer.
11.\" 2. Redistributions in binary form must reproduce the above copyright 11.\" 2. Redistributions in binary form must reproduce the above copyright
12.\" notice, this list of conditions and the following disclaimer in the 12.\" notice, this list of conditions and the following disclaimer in the
13.\" documentation and/or other materials provided with the distribution. 13.\" documentation and/or other materials provided with the distribution.
14.\" 3. The name of the author may not be used to endorse or promote products 14.\" 3. The name of the author may not be used to endorse or promote products
@@ -68,29 +68,33 @@ is altered or displayed. @@ -68,29 +68,33 @@ is altered or displayed.
68This is mutually exclusive with 68This is mutually exclusive with
69.Fl t . 69.Fl t .
70.It Fl E 70.It Fl E
71Disable entropy estimation from the collected timing information for 71Disable entropy estimation from the collected timing information for
72the given device name or device type. 72the given device name or device type.
73If collection is still enabled, timing information is still 73If collection is still enabled, timing information is still
74collected and mixed into the internal entropy pool, 74collected and mixed into the internal entropy pool,
75but no entropy is assumed to be present. 75but no entropy is assumed to be present.
76.It Fl e 76.It Fl e
77Enable entropy estimation using the collected timing information 77Enable entropy estimation using the collected timing information
78for the given device name or device type. 78for the given device name or device type.
79.It Fl L 79.It Fl L
80Load saved entropy from file 80Load saved entropy from file
81.Ar save-file , 81.Ar save-file
82which will be overwritten and deleted before the entropy is loaded into 82and overwrite it with a seed derived by hashing it together with output
83the kernel. 83from
 84.Pa /dev/urandom
 85so that the new seed has at least as much entropy as either the old
 86seed had or the system already has.
 87If interrupted, either the old seed or the new seed will be in place.
84.It Fl l 88.It Fl l
85List all sources, or, if the 89List all sources, or, if the
86.Fl t 90.Fl t
87or 91or
88.Fl d 92.Fl d
89flags are specified, only those specified by the 93flags are specified, only those specified by the
90.Ar devtype 94.Ar devtype
91or 95or
92.Ar devname 96.Ar devname
93specified. 97specified.
94.It Fl S 98.It Fl S
95Save entropy pool to file 99Save entropy pool to file
96.Ar save-file . 100.Ar save-file .

cvs diff -r1.30 -r1.31 src/sbin/rndctl/rndctl.c (expand / switch to unified diff)

--- src/sbin/rndctl/rndctl.c 2015/04/13 22:18:50 1.30
+++ src/sbin/rndctl/rndctl.c 2019/12/06 14:43:18 1.31
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: rndctl.c,v 1.30 2015/04/13 22:18:50 riastradh Exp $ */ 1/* $NetBSD: rndctl.c,v 1.31 2019/12/06 14:43:18 riastradh Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1997 Michael Graff. 4 * Copyright (c) 1997 Michael Graff.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -23,34 +23,35 @@ @@ -23,34 +23,35 @@
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE. 29 * SUCH DAMAGE.
30 */ 30 */
31#include <sys/cdefs.h> 31#include <sys/cdefs.h>
32#include <sys/types.h> 32#include <sys/types.h>
33#include <sha1.h> 33#include <sha1.h>
34 34
35#ifndef lint 35#ifndef lint
36__RCSID("$NetBSD: rndctl.c,v 1.30 2015/04/13 22:18:50 riastradh Exp $"); 36__RCSID("$NetBSD: rndctl.c,v 1.31 2019/12/06 14:43:18 riastradh Exp $");
37#endif 37#endif
38 38
39 39
40#include <sys/types.h> 40#include <sys/types.h>
41#include <sys/ioctl.h> 41#include <sys/ioctl.h>
42#include <sys/param.h> 42#include <sys/param.h>
43#include <sys/rndio.h> 43#include <sys/rndio.h>
 44#include <sys/sha3.h>
44 45
45#include <stdio.h> 46#include <stdio.h>
46#include <stdlib.h> 47#include <stdlib.h>
47#include <unistd.h> 48#include <unistd.h>
48#include <fcntl.h> 49#include <fcntl.h>
49#include <errno.h> 50#include <errno.h>
50#include <err.h> 51#include <err.h>
51#include <paths.h> 52#include <paths.h>
52#include <string.h> 53#include <string.h>
53 54
54typedef struct { 55typedef struct {
55 const char *a_name; 56 const char *a_name;
56 u_int32_t a_type; 57 u_int32_t a_type;
@@ -117,131 +118,247 @@ find_name(u_int32_t type) @@ -117,131 +118,247 @@ find_name(u_int32_t type)
117 a = source_types; 118 a = source_types;
118 119
119 while (a->a_name != NULL) { 120 while (a->a_name != NULL) {
120 if (type == a->a_type) 121 if (type == a->a_type)
121 return (a->a_name); 122 return (a->a_name);
122 a++; 123 a++;
123 } 124 }
124 125
125 warnx("device type %u unknown", type); 126 warnx("device type %u unknown", type);
126 return ("???"); 127 return ("???");
127} 128}
128 129
129static void 130static void
130do_save(const char *const filename) 131do_save(const char *filename, const void *extra, size_t nextra,
 132 uint32_t extraentropy)
131{ 133{
132 int est1, est2; 134 char tmp[PATH_MAX];
133 rndpoolstat_t rp; 135 uint32_t systementropy;
 136 uint8_t buf[32];
 137 SHAKE128_CTX shake128;
134 rndsave_t rs; 138 rndsave_t rs;
135 SHA1_CTX s; 139 SHA1_CTX s;
136 140 ssize_t nread, nwrit;
137 int fd; 141 int fd;
138 142
139 fd = open(_PATH_URANDOM, O_RDONLY, 0644); 143 /* Paranoia: Avoid stack memory disclosure. */
140 if (fd < 0) { 144 memset(&rs, 0, sizeof rs);
141 err(1, "device open"); 
142 } 
143 
144 if (ioctl(fd, RNDGETPOOLSTAT, &rp) < 0) { 
145 err(1, "ioctl(RNDGETPOOLSTAT)"); 
146 } 
147 145
148 est1 = rp.curentropy; 146 /* Format the temporary file name. */
 147 if (snprintf(tmp, sizeof tmp, "%s.tmp", filename) >= PATH_MAX)
 148 errx(1, "path too long");
149 149
150 if (read(fd, rs.data, sizeof(rs.data)) != sizeof(rs.data)) { 150 /* Open /dev/urandom. */
151 err(1, "entropy read"); 151 if ((fd = open(_PATH_URANDOM, O_RDONLY)) == -1)
152 } 152 err(1, "device open");
153 153
154 if (ioctl(fd, RNDGETPOOLSTAT, &rp) < 0) { 154 /* Find how much entropy is in the pool. */
155 err(1, "ioctl(RNDGETPOOLSTAT)"); 155 if (ioctl(fd, RNDGETENTCNT, &systementropy) == -1)
156 } 156 err(1, "ioctl(RNDGETENTCNT)");
 157
 158 /* Read some data from /dev/urandom. */
 159 if ((size_t)(nread = read(fd, buf, sizeof buf)) != sizeof buf) {
 160 if (nread == -1)
 161 err(1, "read");
 162 else
 163 errx(1, "truncated read");
 164 }
 165
 166 /* Close /dev/urandom; we're done with it. */
 167 if (close(fd) == -1)
 168 warn("close");
 169 fd = -1; /* paranoia */
157 170
158 est2 = rp.curentropy; 171 /*
 172 * Hash what we read together with the extra input to generate
 173 * the seed data.
 174 */
 175 SHAKE128_Init(&shake128);
 176 SHAKE128_Update(&shake128, buf, sizeof buf);
 177 SHAKE128_Update(&shake128, extra, nextra);
 178 SHAKE128_Final(rs.data, sizeof(rs.data), &shake128);
 179 explicit_memset(&shake128, 0, sizeof shake128); /* paranoia */
159 180
160 if (est1 - est2 < 0) { 181 /*
161 rs.entropy = 0; 182 * Report an upper bound on the min-entropy of the seed data.
162 } else { 183 * We take the larger of the system entropy and the extra
163 rs.entropy = est1 - est2; 184 * entropy -- the system state and the extra input may or may
164 } 185 * not be independent, so we can't add them -- and clamp to the
 186 * size of the data.
 187 */
 188 systementropy = MIN(systementropy,
 189 MIN(sizeof(buf), UINT32_MAX/NBBY)*NBBY);
 190 extraentropy = MIN(extraentropy, MIN(nextra, UINT32_MAX/NBBY)*NBBY);
 191 rs.entropy = MIN(MAX(systementropy, extraentropy),
 192 MIN(sizeof(rs.data), UINT32_MAX/NBBY)*NBBY);
165 193
 194 /*
 195 * Compute the checksum on the 32-bit entropy count, in host
 196 * byte order (XXX this means it is not portable across
 197 * different-endian platforms!), followed by the seed data.
 198 */
166 SHA1Init(&s); 199 SHA1Init(&s);
167 SHA1Update(&s, (uint8_t *)&rs.entropy, sizeof(rs.entropy)); 200 SHA1Update(&s, (const uint8_t *)&rs.entropy, sizeof(rs.entropy));
168 SHA1Update(&s, rs.data, sizeof(rs.data)); 201 SHA1Update(&s, rs.data, sizeof(rs.data));
169 SHA1Final(rs.digest, &s); 202 SHA1Final(rs.digest, &s);
 203 explicit_memset(&s, 0, sizeof s); /* paranoia */
170 204
171 close(fd); 205 /*
172 unlink(filename); 206 * Write it to a temporary file and sync it before we commit.
173 fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0600); 207 * This way either the old seed or the new seed is completely
174 if (fd < 0) { 208 * written in the expected location on disk even if the system
175 err(1, "output open"); 209 * crashes as long as the file system doesn't get corrupted too
176 } 210 * badly.
177 211 *
178 if (write(fd, &rs, sizeof(rs)) != sizeof(rs)) { 212 * If interrupted after this point and the temporary file is
179 unlink(filename); 213 * disclosed, no big deal -- either the pool was predictable to
180 fsync_range(fd, FDATASYNC|FDISKSYNC, (off_t)0, (off_t)0); 214 * begin with in which case we're hosed either way, or we've
181 err(1, "write"); 215 * just revealed some output which is not a problem.
182 } 216 */
183 fsync_range(fd, FDATASYNC|FDISKSYNC, (off_t)0, (off_t)0); 217 if ((fd = open(tmp, O_CREAT|O_TRUNC|O_WRONLY, 0600)) == -1)
184 close(fd); 218 err(1, "open seed file to save");
 219 if ((size_t)(nwrit = write(fd, &rs, sizeof rs)) != sizeof rs) {
 220 int error = errno;
 221 if (unlink(tmp) == -1)
 222 warn("unlink");
 223 if (nwrit == -1)
 224 errc(1, error, "write");
 225 else
 226 errx(1, "truncated write");
 227 }
 228 explicit_memset(&rs, 0, sizeof rs); /* paranoia */
 229 if (fsync_range(fd, FDATASYNC|FDISKSYNC, 0, 0) == -1) {
 230 int error = errno;
 231 if (unlink(tmp) == -1)
 232 warn("unlink");
 233 errc(1, error, "fsync_range");
 234 }
 235 if (close(fd) == -1)
 236 warn("close");
 237
 238 /* Rename it over the original file to commit. */
 239 if (rename(tmp, filename) == -1)
 240 err(1, "rename");
185} 241}
186 242
187static void 243static void
188do_load(const char *const filename) 244do_load(const char *filename)
189{ 245{
190 int fd; 246 char tmp[PATH_MAX];
191 rndsave_t rs, rszero; 247 int fd_seed, fd_random;
 248 rndsave_t rs;
192 rnddata_t rd; 249 rnddata_t rd;
 250 ssize_t nread, nwrit;
193 SHA1_CTX s; 251 SHA1_CTX s;
194 uint8_t digest[SHA1_DIGEST_LENGTH]; 252 uint8_t digest[SHA1_DIGEST_LENGTH];
195 253
196 fd = open(filename, O_RDWR, 0600); 254 /*
197 if (fd < 0) { 255 * The order of operations is important here:
198 err(1, "input open"); 256 *
199 } 257 * 1. Load the old seed.
200 258 * 2. Feed the old seed into the kernel.
201 unlink(filename); 259 * 3. Generate and write a new seed.
 260 * 4. Erase the old seed.
 261 *
 262 * This follows the procedure in
 263 *
 264 * Niels Ferguson, Bruce Schneier, and Tadayoshi Kohno,
 265 * _Cryptography Engineering_, Wiley, 2010, Sec. 9.6.2
 266 * `Update Seed File'.
 267 *
 268 * There is a race condition: If another process generates a
 269 * key from /dev/urandom after step (2) but before step (3),
 270 * and if the machine crashes before step (3), an adversary who
 271 * can read the disk after the crash can probably guess the
 272 * complete state of the entropy pool and thereby predict the
 273 * key.
 274 *
 275 * There's not much we can do here without some kind of
 276 * systemwide lock on /dev/urandom and without introducing an
 277 * opportunity for a crash to wipe out the entropy altogether.
 278 * To avoid this race, you should ensure that any key
 279 * generation happens _after_ `rndctl -L' has completed.
 280 */
202 281
203 if (read(fd, &rs, sizeof(rs)) != sizeof(rs)) { 282 /* Format the temporary file name. */
204 err(1, "read"); 283 if (snprintf(tmp, sizeof tmp, "%s.tmp", filename) >= PATH_MAX)
 284 errx(1, "path too long");
 285
 286 /* 1. Load the old seed. */
 287 if ((fd_seed = open(filename, O_RDWR)) == -1)
 288 err(1, "open seed file to load");
 289 if ((size_t)(nread = read(fd_seed, &rs, sizeof rs)) != sizeof rs) {
 290 if (nread == -1)
 291 err(1, "read seed");
 292 else
 293 errx(1, "seed too short");
205 } 294 }
206 295
207 memset(&rszero, 0, sizeof(rszero)); 296 /* Verify its checksum. */
208 if (pwrite(fd, &rszero, sizeof(rszero), (off_t)0) != sizeof(rszero)) 
209 err(1, "overwrite"); 
210 fsync_range(fd, FDATASYNC|FDISKSYNC, (off_t)0, (off_t)0); 
211 close(fd); 
212 
213 SHA1Init(&s); 297 SHA1Init(&s);
214 SHA1Update(&s, (uint8_t *)&rs.entropy, sizeof(rs.entropy)); 298 SHA1Update(&s, (const uint8_t *)&rs.entropy, sizeof(rs.entropy));
215 SHA1Update(&s, rs.data, sizeof(rs.data)); 299 SHA1Update(&s, rs.data, sizeof(rs.data));
216 SHA1Final(digest, &s); 300 SHA1Final(digest, &s);
217 301 if (!consttime_memequal(digest, rs.digest, sizeof(digest))) {
218 if (memcmp(digest, rs.digest, sizeof(digest))) { 302 /*
219 errx(1, "bad digest"); 303 * If the checksum doesn't match, doesn't hurt to feed
 304 * the seed in anyway, but act as though it has zero
 305 * entropy in case it was corrupted with predictable
 306 * garbage.
 307 */
 308 warnx("bad checksum");
 309 rs.entropy = 0;
220 } 310 }
221 311
 312 /* Format the ioctl request. */
222 rd.len = MIN(sizeof(rd.data), sizeof(rs.data)); 313 rd.len = MIN(sizeof(rd.data), sizeof(rs.data));
223 rd.entropy = rs.entropy; 314 rd.entropy = rs.entropy;
224 memcpy(rd.data, rs.data, MIN(sizeof(rd.data), sizeof(rs.data))); 315 memcpy(rd.data, rs.data, rd.len);
 316 explicit_memset(&rs, 0, sizeof rs); /* paranoia */
225 317
226 fd = open(_PATH_URANDOM, O_RDWR, 0644); 318 /* 2. Feed the old seed into the kernel. */
227 if (fd < 0) { 319 if ((fd_random = open(_PATH_URANDOM, O_WRONLY)) == -1)
228 err(1, "device open"); 320 err(1, "open /dev/urandom");
229 } 321 if (ioctl(fd_random, RNDADDDATA, &rd) == -1)
 322 err(1, "RNDADDDATA");
 323 if (close(fd_random) == -1)
 324 warn("close /dev/urandom");
 325 fd_random = -1; /* paranoia */
230 326
231 if (ioctl(fd, RNDADDDATA, &rd) < 0) { 327 /*
232 err(1, "ioctl"); 328 * 3. Generate and write a new seed. Note that we hash the old
 329 * seed together with whatever /dev/urandom returns in do_save.
 330 * Why? After RNDADDDATA, the input may not be distributed
 331 * immediately to /dev/urandom.
 332 */
 333 do_save(filename, rd.data, rd.len, rd.entropy);
 334 explicit_memset(&rd, 0, sizeof rd); /* paranoia */
 335
 336 /*
 337 * 4. Erase the old seed. Only effective if we're on a
 338 * fixed-address file system like ffs -- doesn't help to erase
 339 * the data on lfs, but doesn't hurt either. No need to unlink
 340 * because do_save will have already overwritten it.
 341 */
 342 memset(&rs, 0, sizeof rs);
 343 if ((size_t)(nwrit = pwrite(fd_seed, &rs, sizeof rs, 0)) !=
 344 sizeof rs) {
 345 if (nwrit == -1)
 346 err(1, "overwrite old seed");
 347 else
 348 errx(1, "truncated overwrite");
233 } 349 }
234 close(fd); 350 if (fsync_range(fd_seed, FDATASYNC|FDISKSYNC, 0, 0) == -1)
 351 err(1, "fsync_range");
235} 352}
236 353
237static void 354static void
238do_ioctl(rndctl_t *rctl) 355do_ioctl(rndctl_t *rctl)
239{ 356{
240 int fd; 357 int fd;
241 int res; 358 int res;
242 359
243 fd = open(_PATH_URANDOM, O_RDONLY, 0644); 360 fd = open(_PATH_URANDOM, O_RDONLY, 0644);
244 if (fd < 0) 361 if (fd < 0)
245 err(1, "open"); 362 err(1, "open");
246 363
247 res = ioctl(fd, RNDCTL, rctl); 364 res = ioctl(fd, RNDCTL, rctl);
@@ -387,26 +504,29 @@ do_stats(void) @@ -387,26 +504,29 @@ do_stats(void)
387 504
388 close(fd); 505 close(fd);
389} 506}
390 507
391int 508int
392main(int argc, char **argv) 509main(int argc, char **argv)
393{ 510{
394 rndctl_t rctl; 511 rndctl_t rctl;
395 int ch, cmd, lflag, mflag, sflag; 512 int ch, cmd, lflag, mflag, sflag;
396 u_int32_t type; 513 u_int32_t type;
397 char name[16]; 514 char name[16];
398 const char *filename = NULL; 515 const char *filename = NULL;
399 516
 517 if (SHA3_Selftest() != 0)
 518 errx(1, "SHA-3 self-test failed");
 519
400 rctl.mask = 0; 520 rctl.mask = 0;
401 rctl.flags = 0; 521 rctl.flags = 0;
402 522
403 cmd = 0; 523 cmd = 0;
404 lflag = 0; 524 lflag = 0;
405 mflag = 0; 525 mflag = 0;
406 sflag = 0; 526 sflag = 0;
407 type = 0xff; 527 type = 0xff;
408 528
409 while ((ch = getopt(argc, argv, "CES:L:celt:d:sv")) != -1) { 529 while ((ch = getopt(argc, argv, "CES:L:celt:d:sv")) != -1) {
410 switch (ch) { 530 switch (ch) {
411 case 'C': 531 case 'C':
412 rctl.flags |= RND_FLAG_NO_COLLECT; 532 rctl.flags |= RND_FLAG_NO_COLLECT;
@@ -472,27 +592,27 @@ main(int argc, char **argv) @@ -472,27 +592,27 @@ main(int argc, char **argv)
472 argc -= optind; 592 argc -= optind;
473 argv += optind; 593 argv += optind;
474 594
475 /* 595 /*
476 * No leftover non-option arguments. 596 * No leftover non-option arguments.
477 */ 597 */
478 if (argc > 0) 598 if (argc > 0)
479 usage(); 599 usage();
480 600
481 /* 601 /*
482 * Save. 602 * Save.
483 */ 603 */
484 if (cmd == 'S') { 604 if (cmd == 'S') {
485 do_save(filename); 605 do_save(filename, NULL, 0, 0);
486 exit(0); 606 exit(0);
487 } 607 }
488 608
489 /* 609 /*
490 * Load. 610 * Load.
491 */ 611 */
492 if (cmd == 'L') { 612 if (cmd == 'L') {
493 do_load(filename); 613 do_load(filename);
494 exit(0); 614 exit(0);
495 } 615 }
496 616
497 /* 617 /*
498 * Cannot list and modify at the same time. 618 * Cannot list and modify at the same time.