2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/types.h>
31 #if defined(__DragonFly__)
32 #include <sys/diskslice.h>
33 #elif defined(__linux__)
35 #include <sys/ioctl.h>
38 #include <sys/select.h>
50 read_to_safe_mem(const char *file, off_t offset, size_t *sz)
56 if ((fd = open(file, O_RDONLY)) < 0) {
57 tc_log(1, "Error opening file %s\n", file);
61 if ((mem = alloc_safe_mem(*sz)) == NULL) {
62 tc_log(1, "Error allocating memory\n");
66 if ((lseek(fd, offset, SEEK_SET) < 0)) {
67 tc_log(1, "Error seeking on file %s\n", file);
71 if ((r = read(fd, mem, *sz)) <= 0) {
72 tc_log(1, "Error reading from file %s\n", file);
88 static size_t get_random_total_bytes = 0;
89 static size_t get_random_read_bytes = 0;
93 get_random_summary(void)
97 pct_done = (1.0 * get_random_read_bytes) /
98 (1.0 * get_random_total_bytes) * 100.0;
99 tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done);
103 get_random(unsigned char *buf, size_t len)
109 struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */
112 if ((fd = open("/dev/random", O_RDONLY)) < 0) {
113 tc_log(1, "Error opening /dev/random\n");
117 summary_fn = get_random_summary;
118 get_random_total_bytes = len;
120 /* Get random data in 16-byte chunks */
123 get_random_read_bytes = rd;
128 if ((r = read(fd, buf+rd, sz)) < 0) {
129 tc_log(1, "Error reading from /dev/random(%d): %s\n",
130 fd, strerror(errno));
136 nanosleep(&ts, NULL);
145 static size_t secure_erase_total_bytes = 0;
146 static size_t secure_erase_erased_bytes = 0;
150 secure_erase_summary(void)
154 pct_done = (1.0 * secure_erase_erased_bytes) /
155 (1.0 * secure_erase_total_bytes) * 100.0;
156 tc_log(0, "Securely erasing, %.0f%% done.\n", pct_done);
160 secure_erase(const char *dev, size_t bytes, size_t blksz)
164 char buf[ERASE_BUFFER_SIZE];
168 if (blksz > MAX_BLKSZ) {
169 tc_log(1, "blksz > MAX_BLKSZ\n");
173 if ((fd_rand = open("/dev/urandom", O_RDONLY)) < 0) {
174 tc_log(1, "Error opening /dev/urandom\n");
178 if ((fd = open(dev, O_WRONLY)) < 0) {
180 tc_log(1, "Error opening %s\n", dev);
184 summary_fn = secure_erase_summary;
185 secure_erase_total_bytes = bytes;
187 sz = ERASE_BUFFER_SIZE;
188 while (erased < bytes) {
189 secure_erase_erased_bytes = erased;
190 /* Switch to block size when not much is remaining */
191 if ((bytes - erased) <= ERASE_BUFFER_SIZE)
194 if ((r = read(fd_rand, buf, sz)) < 0) {
195 tc_log(1, "Error reading from /dev/urandom\n");
202 if (r < (ssize_t)blksz)
205 if ((w = write(fd, buf, r)) < 0) {
206 tc_log(1, "Error writing to %s\n", dev);
224 #if defined(__DragonFly__)
226 get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
228 struct partinfo pinfo;
231 if ((fd = open(dev, O_RDONLY)) < 0) {
232 tc_log(1, "Error opening %s\n", dev);
236 memset(&pinfo, 0, sizeof(struct partinfo));
238 if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
243 *blocks = pinfo.media_blocks;
244 *bsize = pinfo.media_blksize;
249 #elif defined(__linux__)
251 get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
257 if ((fd = open(dev, O_RDONLY)) < 0) {
258 tc_log(1, "Error opening %s\n", dev);
262 if ((ioctl(fd, BLKSSZGET, &blocksz)) < 0) {
267 if ((ioctl(fd, BLKGETSIZE64, &nbytes)) < 0) {
272 *blocks = (size_t)(nbytes / blocksz);
273 *bsize = (size_t)(blocksz);
281 write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem,
284 unsigned char *mem_buf = NULL;
290 /* Align to block sizes */
291 internal_off = offset % blksz;
293 printf("offset: %"PRIu64", internal offset: %"PRIu64"\n",
294 (uint64_t)offset, (uint64_t)internal_off);
296 offset = (offset/blksz) * blksz;
298 if ((internal_off + bytes) > blksz) {
299 tc_log(1, "This should never happen: internal_off + bytes > "
300 "blksz (write_to_disk)\n");
304 if ((bytes < blksz) || (internal_off != 0)) {
306 if ((mem_buf = read_to_safe_mem(dev, offset, &sz)) == NULL) {
307 tc_log(1, "Error buffering data on "
308 "write_to_disk(%s)\n", dev);
312 memcpy(mem_buf + internal_off, mem, bytes);
315 if ((fd = open(dev, O_WRONLY)) < 0) {
316 tc_log(1, "Error opening device %s\n", dev);
320 if ((lseek(fd, offset, SEEK_SET) < 0)) {
321 tc_log(1, "Error seeking on device %s\n", dev);
326 if ((w = write(fd, (mem_buf != NULL) ? mem_buf : mem, bytes)) <= 0) {
327 tc_log(1, "Error writing to device %s\n", dev);
335 free_safe_mem(mem_buf);
340 read_passphrase(const char *prompt, char *pass, size_t passlen, time_t timeout)
342 struct termios termios_old, termios_new;
346 int fd, r = 0, cfd = 0, nready;
348 if ((fd = open("/dev/tty", O_RDONLY)) == -1) {
356 memset(pass, 0, passlen);
358 tcgetattr(fd, &termios_old);
359 memcpy(&termios_new, &termios_old, sizeof(termios_new));
360 termios_new.c_lflag &= ~ECHO;
361 tcsetattr(fd, TCSAFLUSH, &termios_new);
364 memset(&to, 0, sizeof(to));
369 nready = select(fd + 1, &fds, NULL, NULL, &to);
376 n = read(fd, pass, passlen-1);
378 pass[n-1] = '\0'; /* Strip trailing \n */
387 tcsetattr(fd, TCSAFLUSH, &termios_old);