Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

major refactoring, bugfixes

* Code has now been split up into several different files to improve
  readability.

* The usage() message has been updated.

* Version bumped to 0.5.

* Fixes in the safe_mem purging
  • Loading branch information...
commit dedd95cae4febde7882783c6dda8ec2573e4b56a 1 parent 72a5221
@bwalex authored
Showing with 881 additions and 772 deletions.
  1. +1 −1  Makefile
  2. +178 −0 crypto.c
  3. +202 −0 hdr.c
  4. +248 −0 io.c
  5. +172 −0 safe_mem.c
  6. +44 −752 tc-play.c
  7. +36 −19 tc-play.h
View
2  Makefile
@@ -1,4 +1,4 @@
all:
- gcc -O0 -Wall -g tc-play.c crc32.c openssl/openssl/libcrypto.a -o tc-play -ldevmapper -lprop -lutil
+ gcc -O0 -Wall -g tc-play.c crc32.c safe_mem.c io.c crypto.c hdr.c openssl/openssl/libcrypto.a -o tc-play -ldevmapper -lprop -lutil
clean:
rm -f tc-play tc-play.core *.o ktrace.out
View
178 crypto.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <errno.h>
+#include <string.h>
+#include <openssl/evp.h>
+
+#include "crc32.h"
+#include "tc-play.h"
+
+int
+tc_crypto_init(void)
+{
+ OpenSSL_add_all_algorithms();
+
+ return 0;
+}
+
+int
+tc_encrypt(const char *cipher_name, unsigned char *key, unsigned char *iv,
+ unsigned char *in, int in_len, unsigned char *out)
+{
+ const EVP_CIPHER *evp;
+ EVP_CIPHER_CTX ctx;
+ int outl, tmplen;
+
+ evp = EVP_get_cipherbyname(cipher_name);
+ if (evp == NULL) {
+ printf("Cipher %s not found\n", cipher_name);
+ return ENOENT;
+ }
+
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_EncryptInit(&ctx, evp, key, iv);
+ EVP_EncryptUpdate(&ctx, out, &outl, in, in_len);
+ EVP_EncryptFinal(&ctx, out + outl, &tmplen);
+
+ return 0;
+}
+
+int
+tc_decrypt(const char *cipher_name, unsigned char *key, unsigned char *iv,
+ unsigned char *in, int in_len, unsigned char *out)
+{
+ const EVP_CIPHER *evp;
+ EVP_CIPHER_CTX ctx;
+ int outl, tmplen;
+
+ evp = EVP_get_cipherbyname(cipher_name);
+ if (evp == NULL) {
+ printf("Cipher %s not found\n", cipher_name);
+ return ENOENT;
+ }
+
+ EVP_CIPHER_CTX_init(&ctx);
+ EVP_DecryptInit(&ctx, evp, key, iv);
+ EVP_DecryptUpdate(&ctx, out, &outl, in, in_len);
+ EVP_DecryptFinal(&ctx, out + outl, &tmplen);
+
+ return 0;
+}
+
+int
+pbkdf2(const char *pass, int passlen, const unsigned char *salt, int saltlen,
+ int iter, const char *hash_name, int keylen, unsigned char *out)
+{
+ const EVP_MD *md;
+ int r;
+
+ md = EVP_get_digestbyname(hash_name);
+ if (md == NULL) {
+ printf("Hash %s not found\n", hash_name);
+ return ENOENT;
+ }
+ r = PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, md,
+ keylen, out);
+
+ if (r == 0) {
+ printf("Error in PBKDF2\n");
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+int
+apply_keyfiles(unsigned char *pass, size_t pass_memsz, const char *keyfiles[],
+ int nkeyfiles)
+{
+ int pl, k;
+ unsigned char *kpool;
+ unsigned char *kdata;
+ int kpool_idx;
+ size_t i, kdata_sz;
+ uint32_t crc;
+
+ if (pass_memsz < MAX_PASSSZ) {
+ fprintf(stderr, "Not enough memory for password manipluation\n");
+ return ENOMEM;
+ }
+
+ pl = strlen(pass);
+ memset(pass+pl, 0, MAX_PASSSZ-pl);
+
+ if ((kpool = alloc_safe_mem(KPOOL_SZ)) == NULL) {
+ fprintf(stderr, "Error allocating memory for keyfile pool\n");
+ return ENOMEM;
+ }
+
+ memset(kpool, 0, KPOOL_SZ);
+
+ for (k = 0; k < nkeyfiles; k++) {
+#ifdef DEBUG
+ printf("Loading keyfile %s into kpool\n", keyfiles[k]);
+#endif
+ kpool_idx = 0;
+ crc = ~0U;
+ kdata_sz = MAX_KFILE_SZ;
+
+ if ((kdata = read_to_safe_mem(keyfiles[k], 0, &kdata_sz)) == NULL) {
+ fprintf(stderr, "Error reading keyfile %s content\n",
+ keyfiles[k]);
+ free_safe_mem(kpool);
+ return EIO;
+ }
+
+ for (i = 0; i < kdata_sz; i++) {
+ crc = crc32_intermediate(crc, kdata[i]);
+
+ kpool[kpool_idx++] += (unsigned char)(crc >> 24);
+ kpool[kpool_idx++] += (unsigned char)(crc >> 16);
+ kpool[kpool_idx++] += (unsigned char)(crc >> 8);
+ kpool[kpool_idx++] += (unsigned char)(crc);
+
+ /* Wrap around */
+ if (kpool_idx == KPOOL_SZ)
+ kpool_idx = 0;
+ }
+
+ free_safe_mem(kdata);
+ }
+
+#ifdef DEBUG
+ printf("Applying kpool to passphrase\n");
+#endif
+ /* Apply keyfile pool to passphrase */
+ for (i = 0; i < KPOOL_SZ; i++)
+ pass[i] += kpool[i];
+
+ free_safe_mem(kpool);
+
+ return 0;
+}
View
202 hdr.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "crc32.h"
+#include "tc-play.h"
+
+/* Endianess macros */
+#define BE_TO_HOST(n, v) v = be ## n ## toh(v)
+#define LE_TO_HOST(n, v) v = le ## n ## toh(v)
+#define HOST_TO_BE(n, v) v = htobe ## n (v)
+#define HOST_TO_LE(n, v) v = htole ## n (v)
+
+struct tchdr_dec *
+decrypt_hdr(struct tchdr_enc *ehdr, char *algo, unsigned char *key)
+{
+ struct tchdr_dec *dhdr;
+ unsigned char iv[128];
+ int error;
+
+ if ((dhdr = alloc_safe_mem(sizeof(struct tchdr_dec))) == NULL) {
+ fprintf(stderr, "Error allocating safe tchdr_dec memory\n");
+ return NULL;
+ }
+
+ memset(iv, 0, sizeof(iv));
+
+ error = tc_decrypt(algo, key, iv, ehdr->enc, sizeof(struct tchdr_dec),
+ (unsigned char *)dhdr);
+ if (error) {
+ fprintf(stderr, "Header decryption failed\n");
+ free_safe_mem(dhdr);
+ return NULL;
+ }
+
+ BE_TO_HOST(16, dhdr->tc_ver);
+ LE_TO_HOST(16, dhdr->tc_min_ver);
+ BE_TO_HOST(32, dhdr->crc_keys);
+ BE_TO_HOST(64, dhdr->vol_ctime);
+ BE_TO_HOST(64, dhdr->hdr_ctime);
+ BE_TO_HOST(64, dhdr->sz_hidvol);
+ BE_TO_HOST(64, dhdr->sz_vol);
+ BE_TO_HOST(64, dhdr->off_mk_scope);
+ BE_TO_HOST(64, dhdr->sz_mk_scope);
+ BE_TO_HOST(32, dhdr->flags);
+ BE_TO_HOST(32, dhdr->sec_sz);
+ BE_TO_HOST(32, dhdr->crc_dhdr);
+
+ return dhdr;
+}
+
+int
+verify_hdr(struct tchdr_dec *hdr)
+{
+ uint32_t crc;
+
+ if (memcmp(hdr->tc_str, TC_SIG, sizeof(hdr->tc_str)) != 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Signature mismatch\n");
+#endif
+ return 0;
+ }
+
+ crc = crc32((void *)&hdr->keys, 256);
+ if (crc != hdr->crc_keys) {
+#ifdef DEBUG
+ fprintf(stderr, "CRC32 mismatch (crc_keys)\n");
+#endif
+ return 0;
+ }
+
+ switch(hdr->tc_ver) {
+ case 1:
+ case 2:
+ /* Unsupported header version */
+ fprintf(stderr, "Header version %d unsupported\n", hdr->tc_ver);
+ return 0;
+
+ case 3:
+ case 4:
+ hdr->sec_sz = 512;
+ break;
+ }
+
+ return 1;
+}
+
+struct tchdr_enc *
+create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo,
+ struct tc_crypto_algo *cipher, size_t sec_sz, size_t total_blocks,
+ off_t offset, size_t blocks, int hidden)
+{
+ struct tchdr_enc *ehdr;
+ struct tchdr_dec *dhdr;
+ unsigned char *key;
+ unsigned char iv[128];
+ int error;
+
+ if ((dhdr = (struct tchdr_dec *)alloc_safe_mem(sizeof(*dhdr))) == NULL) {
+ fprintf(stderr, "could not allocate safe dhdr memory\n");
+ return NULL;
+ }
+
+ if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) {
+ fprintf(stderr, "could not allocate safe ehdr memory\n");
+ return NULL;
+ }
+
+ if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
+ fprintf(stderr, "could not allocate safe key memory\n");
+ return NULL;
+ }
+
+ if ((error = get_random(ehdr->salt, sizeof(ehdr->salt))) != 0) {
+ fprintf(stderr, "could not get salt\n");
+ return NULL;
+ }
+
+ error = pbkdf2(pass, passlen,
+ ehdr->salt, sizeof(ehdr->salt),
+ prf_algo->iteration_count,
+ prf_algo->name, MAX_KEYSZ, key);
+ if (error) {
+ fprintf(stderr, "could not derive key\n");
+ return NULL;
+ }
+
+ memset(dhdr, 0, sizeof(*dhdr));
+
+ if ((error = get_random(dhdr->keys, sizeof(dhdr->keys))) != 0) {
+ fprintf(stderr, "could not get key random bits\n");
+ return NULL;
+ }
+
+ memcpy(dhdr->tc_str, "TRUE", 4);
+ dhdr->tc_ver = 5;
+ dhdr->tc_min_ver = 7;
+ dhdr->crc_keys = crc32((void *)&dhdr->keys, 256);
+ dhdr->sz_vol = blocks * sec_sz;
+ if (hidden)
+ dhdr->sz_hidvol = dhdr->sz_vol;
+ dhdr->off_mk_scope = offset * sec_sz;
+ dhdr->sz_mk_scope = blocks * sec_sz;
+ dhdr->sec_sz = sec_sz;
+ dhdr->flags = 0;
+
+ HOST_TO_BE(16, dhdr->tc_ver);
+ HOST_TO_LE(16, dhdr->tc_min_ver);
+ HOST_TO_BE(32, dhdr->crc_keys);
+ HOST_TO_BE(64, dhdr->sz_vol);
+ HOST_TO_BE(64, dhdr->sz_hidvol);
+ HOST_TO_BE(64, dhdr->off_mk_scope);
+ HOST_TO_BE(64, dhdr->sz_mk_scope);
+ HOST_TO_BE(32, dhdr->sec_sz);
+ HOST_TO_BE(32, dhdr->flags);
+
+ dhdr->crc_dhdr = crc32((void *)dhdr, 188);
+ HOST_TO_BE(32, dhdr->crc_dhdr);
+
+ memset(iv, 0, sizeof(iv));
+ error = tc_encrypt(cipher->name, key, iv, (unsigned char *)dhdr,
+ sizeof(struct tchdr_dec), ehdr->enc);
+ if (error) {
+ fprintf(stderr, "Header encryption failed\n");
+ free_safe_mem(dhdr);
+ return NULL;
+ }
+
+ free_safe_mem(dhdr);
+ return ehdr;
+}
View
248 io.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <sys/diskslice.h>
+#include <sys/uio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "tc-play.h"
+
+void *
+read_to_safe_mem(const char *file, off_t offset, size_t *sz)
+{
+ void *mem = NULL;
+ ssize_t r;
+ int fd;
+
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ fprintf(stderr, "Error opening file %s\n", file);
+ return NULL;
+ }
+
+ if ((mem = alloc_safe_mem(*sz)) == NULL) {
+ fprintf(stderr, "Error allocating memory\n");
+ goto out;
+ }
+
+ if ((lseek(fd, offset, SEEK_SET) < 0)) {
+ fprintf(stderr, "Error seeking on file %s\n", file);
+ goto m_err;
+ }
+
+ if ((r = read(fd, mem, *sz)) <= 0) {
+ fprintf(stderr, "Error reading from file %s\n", file);
+ goto m_err;
+ }
+
+out:
+ *sz = r;
+ close(fd);
+ return mem;
+ /* NOT REACHED */
+
+m_err:
+ free_safe_mem(mem);
+ close(fd);
+ return NULL;
+}
+
+int
+get_random(unsigned char *buf, size_t len)
+{
+ int fd;
+ ssize_t r;
+ size_t rd = 0;
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */
+
+
+ if ((fd = open("/dev/random", O_RDONLY)) < 0) {
+ fprintf(stderr, "Error opening /dev/random\n");
+ return -1;
+ }
+
+ while (rd < len) {
+ if ((r = read(fd, buf+rd, len-rd)) < 0) {
+ fprintf(stderr, "Error reading from /dev/random\n");
+ close(fd);
+ return -1;
+ }
+ rd += r;
+ nanosleep(&ts, NULL);
+ }
+
+ close(fd);
+ return 0;
+}
+
+int
+secure_erase(const char *dev, size_t bytes, size_t blksz)
+{
+ size_t erased = 0;
+ int fd_rand, fd;
+ char buf[MAX_BLKSZ];
+ ssize_t r, w;
+
+ if (blksz > MAX_BLKSZ) {
+ fprintf(stderr, "blksz > MAX_BLKSZ\n");
+ return -1;
+ }
+
+ if ((fd_rand = open("/dev/urandom", O_RDONLY)) < 0) {
+ fprintf(stderr, "Error opening /dev/urandom\n");
+ return -1;
+ }
+
+ if ((fd = open(dev, O_WRONLY)) < 0) {
+ close(fd_rand);
+ fprintf(stderr, "Error opening %s\n", dev);
+ return -1;
+ }
+
+ while (erased < bytes) {
+ if ((r = read(fd_rand, buf, blksz)) < 0) {
+ fprintf(stderr, "Error reading from /dev/urandom\n");
+ close(fd);
+ close(fd_rand);
+ return -1;
+ }
+
+ if (r < blksz)
+ continue;
+
+ if ((w = write(fd, buf, blksz)) < 0) {
+ fprintf(stderr, "Error writing to %s\n", dev);
+ close(fd);
+ close(fd_rand);
+ return -1;
+ }
+
+ erased += (size_t)w;
+ }
+
+ close(fd);
+ close(fd_rand);
+
+ return 0;
+}
+
+int
+get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
+{
+ struct partinfo pinfo;
+ int fd;
+
+ if ((fd = open(dev, O_RDONLY)) < 0) {
+ fprintf(stderr, "Error opening %s\n", dev);
+ return -1;
+ }
+
+ memset(&pinfo, 0, sizeof(struct partinfo));
+
+ if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ *blocks = pinfo.media_blocks;
+ *bsize = pinfo.media_blksize;
+
+ close(fd);
+ return 0;
+}
+
+int
+write_mem(const char *dev, off_t offset, size_t blksz, void *mem, size_t bytes)
+{
+ ssize_t w;
+ int fd;
+
+ if ((fd = open(dev, O_WRONLY)) < 0) {
+ fprintf(stderr, "Error opening device %s\n", dev);
+ return -1;
+ }
+
+ if ((lseek(fd, offset, SEEK_SET) < 0)) {
+ fprintf(stderr, "Error seeking on device %s\n", dev);
+ close(fd);
+ return -1;
+ }
+
+ if ((w = write(fd, mem, bytes)) <= 0) {
+ fprintf(stderr, "Error writing to device %s\n", dev);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+int
+read_passphrase(char *prompt, char *pass, size_t passlen)
+{
+ struct termios termios_old, termios_new;
+ ssize_t n;
+ int fd, r = 0, cfd = 0;
+
+ if ((fd = open("/dev/tty", O_RDONLY)) == -1) {
+ fd = STDIN_FILENO;
+ cfd = 1;
+ }
+
+ printf(prompt);
+ fflush(stdout);
+
+ memset(pass, 0, passlen);
+
+ tcgetattr(fd, &termios_old);
+ memcpy(&termios_new, &termios_old, sizeof(termios_new));
+ termios_new.c_lflag &= ~ECHO;
+ tcsetattr(fd, TCSAFLUSH, &termios_new);
+
+ n = read(fd, pass, passlen-1);
+ if (n > 0) {
+ pass[n-1] = '\0'; /* Strip trailing \n */
+ } else {
+ r = EIO;
+ }
+
+ if (cfd)
+ close(fd);
+
+ tcsetattr(fd, TCSAFLUSH, &termios_old);
+ putchar('\n');
+
+ return r;
+}
View
172 safe_mem.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+struct safe_mem_hdr {
+ struct safe_mem_hdr *prev;
+ struct safe_mem_hdr *next;
+ struct safe_mem_tail *tail;
+ const char *file;
+ int line;
+ size_t alloc_sz;
+ char sig[8]; /* SAFEMEM */
+};
+
+struct safe_mem_tail {
+ char sig[8]; /* SAFEMEM */
+};
+
+static struct safe_mem_hdr *safe_mem_hdr_first = NULL;
+
+void *
+_alloc_safe_mem(size_t req_sz, const char *file, int line)
+{
+ struct safe_mem_hdr *hdr, *hdrp;
+ struct safe_mem_tail *tail;
+ size_t alloc_sz;
+ void *mem, *user_mem;
+
+ alloc_sz = req_sz + sizeof(*hdr) + sizeof(*tail);
+ if ((mem = malloc(alloc_sz)) == NULL)
+ return NULL;
+
+ if (mlock(mem, alloc_sz) < 0) {
+ free(mem);
+ return NULL;
+ }
+
+ memset(mem, 0, alloc_sz);
+
+ hdr = (struct safe_mem_hdr *)mem;
+ tail = (struct safe_mem_tail *)(mem + alloc_sz - sizeof(*tail));
+ user_mem = mem + sizeof(*hdr);
+
+ strcpy(hdr->sig, "SAFEMEM");
+ strcpy(tail->sig, "SAFEMEM");
+ hdr->tail = tail;
+ hdr->alloc_sz = alloc_sz;
+ hdr->file = file;
+ hdr->line = line;
+ hdr->next = NULL;
+
+ if (safe_mem_hdr_first == NULL) {
+ safe_mem_hdr_first = hdr;
+ } else {
+ hdrp = safe_mem_hdr_first;
+ while (hdrp->next != NULL)
+ hdrp = hdrp->next;
+ hdr->prev = hdrp;
+ hdrp->next = hdr;
+ }
+
+ return user_mem;
+}
+
+void
+_free_safe_mem(void *mem, const char *file, int line)
+{
+ struct safe_mem_hdr *hdr;
+ struct safe_mem_tail *tail;
+ size_t alloc_sz;
+
+ mem -= sizeof(*hdr);
+ hdr = (struct safe_mem_hdr *)mem;
+ tail = (struct safe_mem_tail *)(mem + hdr->alloc_sz - sizeof(*tail));
+
+#ifdef DEBUG
+ fprintf(stderr, "freeing safe_mem (hdr): %#lx (%s:%d)\n",
+ (unsigned long)(void *)hdr, hdr->file, hdr->line);
+#endif
+
+ if (hdr->alloc_sz == 0) {
+ fprintf(stderr, "BUG: double-free at %s:%d !!!\n", file, line);
+ return;
+ }
+
+ /* Integrity checks */
+ if ((memcmp(hdr->sig, "SAFEMEM\0", 8) != 0) ||
+ (memcmp(tail->sig, "SAFEMEM\0", 8) != 0)) {
+ fprintf(stderr, "BUG: safe_mem buffer under- or overflow at "
+ "%s:%d !!!\n", file, line);
+ return;
+ }
+
+ if (safe_mem_hdr_first == NULL) {
+ fprintf(stderr, "BUG: safe_mem list should not be empty at "
+ "%s:%d !!!\n", file, line);
+ return;
+ }
+
+ if (hdr->prev != NULL)
+ hdr->prev->next = hdr->next;
+ if (hdr->next != NULL)
+ hdr->next->prev = hdr->prev;
+ if (safe_mem_hdr_first == hdr)
+ safe_mem_hdr_first = hdr->next;
+
+ alloc_sz = hdr->alloc_sz;
+ memset(mem, 0xFF, alloc_sz);
+ memset(mem, 0, alloc_sz);
+
+ free(mem);
+}
+
+void
+check_and_purge_safe_mem(void)
+{
+ struct safe_mem_hdr *hdr;
+ void *mem;
+ int ok;
+
+ if (safe_mem_hdr_first == NULL)
+ return;
+
+ hdr = safe_mem_hdr_first;
+ while ((hdr = safe_mem_hdr_first) != NULL) {
+ if ((hdr->alloc_sz > 0) &&
+ (memcmp(hdr->sig, "SAFEMEM\0", 8) == 0) &&
+ (memcmp(hdr->tail->sig, "SAFEMEM\0", 8) == 0))
+ ok = 1;
+ else
+ ok = 0;
+
+#ifdef DEBUG
+ fprintf(stderr, "un-freed safe_mem: %#lx (%s:%d) [integrity=%s]\n",
+ (unsigned long)(void *)hdr, hdr->file, hdr->line,
+ ok? "ok" : "failed");
+#endif
+ mem = hdr;
+ mem += sizeof(*hdr);
+ _free_safe_mem(mem, "check_and_purge_safe_mem", 0);
+ }
+}
View
796 tc-play.c
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>. All rights reserved.
+ * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -11,9 +12,6 @@
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
- * 3. Neither the name of The DragonFly Project nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific, prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -29,85 +27,31 @@
* SUCH DAMAGE.
*/
#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/uio.h>
-#include <sys/endian.h>
-#include <sys/diskslice.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <err.h>
-#include <uuid.h>
-#include <termios.h>
#include <errno.h>
#include <time.h>
#include <libdevmapper.h>
#include <libutil.h>
-#include <openssl/evp.h>
#include "crc32.h"
#include "tc-play.h"
-#define alloc_safe_mem(x) \
- _alloc_safe_mem(x, __FILE__, __LINE__)
-
-#define free_safe_mem(x) \
- _free_safe_mem(x, __FILE__, __LINE__)
-
/* XXX TODO:
* - LRW-benbi support? needs further work in dm-crypt and even opencrypto
* - secure buffer review (i.e: is everything that needs it using secure mem?)
* - mlockall? (at least MCL_FUTURE, which is the only one we support)
- * - replace err(...) with r = 1; fprintf(); goto out;
- */
-
-#if 0
-otc_str: TRUE, tc_ver: 5, tc_min_ver: 7, crc_keys: 1146105393, sz_vol: 133955584, off_mk_scope: 131072, sz_mk_scope: 133955584, flags: 0, sec_sz: 512 crc_dhdr: -1501829203
-mtc_str: TRUE, tc_ver: 5, tc_min_ver: 1792, crc_keys: 2079567247, sz_vol: 16777216, off_mk_scope: 131072, sz_mk_scope: 16646144, flags: 0, sec_sz: 512 crc_dhdr: -82517198
-
-
-
-
-/* Volume times:
- * return wxDateTime ((time_t) (volumeTime / 1000ULL / 1000 / 10 - 134774ULL * 24 * 3600));
*/
-#define VOLTIME_TO_TIME(volumeTime) \
- ((time_t)(volumeTime / 1000ULL / 1000 / 10 - 134774ULL * 24 * 3600))
-
-/*
-Hi, dm-params:
-0 261632 crypt aes-xts-plain64 0 256 /dev/loop0 256
-
-Hi, dm-params: 0 261632 crypt aes-xts-plain64 0 256 /dev/loop0 256
- 256 = off_mk_scope / sec_sz!
- 261632 = sz_mk_scope / sec_sz!
-
- aes-cbc-essiv:sha256 7997f8af... 0 /dev/ad0s0a 8
- iv off---^ block off--^
-
-Volume "/home/alex/tc-play/tctest.container" has been mounted.
-*/
-
-#endif
/* Version of tc-play */
#define MAJ_VER 0
-#define MIN_VER 3
-
-/* Comment out to disable debug info */
-/* #define DEBUG 1 */
-
-/* Endianess macros */
-#define BE_TO_HOST(n, v) v = be ## n ## toh(v)
-#define LE_TO_HOST(n, v) v = le ## n ## toh(v)
-#define HOST_TO_BE(n, v) v = htobe ## n (v)
-#define HOST_TO_LE(n, v) v = htole ## n (v)
-
+#define MIN_VER 5
/* Supported algorithms */
struct pbkdf_prf_algo pbkdf_prf_algos[] = {
@@ -154,515 +98,6 @@ print_hex(unsigned char *buf, off_t start, size_t len)
}
#endif
-static struct safe_mem_hdr *safe_mem_hdr_first = NULL;
-
-void *
-_alloc_safe_mem(size_t req_sz, const char *file, int line)
-{
- struct safe_mem_hdr *hdr, *hdrp;
- struct safe_mem_tail *tail;
- size_t alloc_sz;
- void *mem, *user_mem;
-
- alloc_sz = req_sz + sizeof(*hdr) + sizeof(*tail);
- if ((mem = malloc(alloc_sz)) == NULL)
- return NULL;
-
- if (mlock(mem, alloc_sz) < 0) {
- free(mem);
- return NULL;
- }
-
- memset(mem, 0, alloc_sz);
-
- hdr = (struct safe_mem_hdr *)mem;
- tail = (struct safe_mem_tail *)(mem + alloc_sz - sizeof(*tail));
- user_mem = mem + sizeof(*hdr);
-
- strcpy(hdr->sig, "SAFEMEM");
- strcpy(tail->sig, "SAFEMEM");
- hdr->tail = tail;
- hdr->alloc_sz = alloc_sz;
- hdr->file = file;
- hdr->line = line;
-
- if (safe_mem_hdr_first == NULL) {
- safe_mem_hdr_first = hdr;
- } else {
- hdrp = safe_mem_hdr_first;
- while (hdrp->next != NULL)
- hdrp = hdrp->next;
- hdr->prev = hdrp;
- hdrp->next = hdr;
- }
-
- return user_mem;
-}
-
-void
-_free_safe_mem(void *mem, const char *file, int line)
-{
- struct safe_mem_hdr *hdr;
- struct safe_mem_tail *tail;
- size_t alloc_sz;
-
- mem -= sizeof(*hdr);
- hdr = (struct safe_mem_hdr *)mem;
- tail = (struct safe_mem_tail *)(mem + hdr->alloc_sz - sizeof(*tail));
-
- if (hdr->alloc_sz == 0) {
- fprintf(stderr, "BUG: double-free at %s:%d !!!\n", file, line);
- exit(1);
- }
-
- /* Integrity checks */
- if ((memcmp(hdr->sig, "SAFEMEM\0", 8) != 0) ||
- (memcmp(tail->sig, "SAFEMEM\0", 8) != 0)) {
- fprintf(stderr, "BUG: safe_mem buffer under- or overflow at "
- "%s:%d !!!\n", file, line);
- exit(1);
- }
-
- if (safe_mem_hdr_first == NULL) {
- fprintf(stderr, "BUG: safe_mem list should not be empty at "
- "%s:%d !!!\n", file, line);
- exit(1);
- }
-
- if (hdr->prev != NULL)
- hdr->prev->next = hdr->next;
- if (hdr->next != NULL)
- hdr->next->prev = hdr->prev;
- if (safe_mem_hdr_first == hdr)
- safe_mem_hdr_first = hdr->next;
-
- alloc_sz = hdr->alloc_sz;
- memset(mem, 0xFF, alloc_sz);
- memset(mem, 0, alloc_sz);
-
- free(mem);
-}
-
-void
-check_and_purge_safe_mem(void)
-{
- struct safe_mem_hdr *hdr, *hdrp;
- int ok;
-
- if (safe_mem_hdr_first == NULL)
- return;
-
- hdr = safe_mem_hdr_first;
- while (hdr != NULL) {
- if ((hdr->alloc_sz > 0) &&
- (memcmp(hdr->sig, "SAFEMEM\0", 8) == 0) &&
- (memcmp(hdr->tail->sig, "SAFEMEM\0", 8) == 0))
- ok = 1;
- else
- ok = 0;
-
-#ifdef DEBUG
- fprintf(stderr, "un-freed safe_mem: %#lx (%s:%d) [integrity=%s]\n",
- (unsigned long)(void *)hdr, hdr->file, hdr->line,
- ok? "ok" : "failed");
-#endif
- hdrp = hdr;
- hdr = hdr->next;
- free_safe_mem(hdrp);
- }
-}
-
-void *
-read_to_safe_mem(const char *file, off_t offset, size_t *sz)
-{
- void *mem = NULL;
- ssize_t r;
- int fd;
-
- if ((fd = open(file, O_RDONLY)) < 0) {
- fprintf(stderr, "Error opening file %s\n", file);
- return NULL;
- }
-
- if ((mem = alloc_safe_mem(*sz)) == NULL) {
- fprintf(stderr, "Error allocating memory\n");
- goto out;
- }
-
- if ((lseek(fd, offset, SEEK_SET) < 0)) {
- fprintf(stderr, "Error seeking on file %s\n", file);
- goto m_err;
- }
-
- if ((r = read(fd, mem, *sz)) <= 0) {
- fprintf(stderr, "Error reading from file %s\n", file);
- goto m_err;
- }
-
-out:
- *sz = r;
- close(fd);
- return mem;
- /* NOT REACHED */
-
-m_err:
- free_safe_mem(mem);
- close(fd);
- return NULL;
-}
-
-int
-get_random(unsigned char *buf, size_t len)
-{
- int fd;
- ssize_t r;
- size_t rd = 0;
- struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */
-
-
- if ((fd = open("/dev/random", O_RDONLY)) < 0) {
- fprintf(stderr, "Error opening /dev/random\n");
- return -1;
- }
-
- while (rd < len) {
- if ((r = read(fd, buf+rd, len-rd)) < 0) {
- fprintf(stderr, "Error reading from /dev/random\n");
- close(fd);
- return -1;
- }
- rd += r;
- nanosleep(&ts, NULL);
- }
-
- close(fd);
- return 0;
-}
-
-int
-secure_erase(const char *dev, size_t bytes, size_t blksz)
-{
- size_t erased = 0;
- int fd_rand, fd;
- char buf[MAX_BLKSZ];
- ssize_t r, w;
-
- if (blksz > MAX_BLKSZ) {
- fprintf(stderr, "blksz > MAX_BLKSZ\n");
- return -1;
- }
-
- if ((fd_rand = open("/dev/urandom", O_RDONLY)) < 0) {
- fprintf(stderr, "Error opening /dev/urandom\n");
- return -1;
- }
-
- if ((fd = open(dev, O_WRONLY)) < 0) {
- close(fd_rand);
- fprintf(stderr, "Error opening %s\n", dev);
- return -1;
- }
-
- while (erased < bytes) {
- if ((r = read(fd_rand, buf, blksz)) < 0) {
- fprintf(stderr, "Error reading from /dev/urandom\n");
- close(fd);
- close(fd_rand);
- return -1;
- }
-
- if (r < blksz)
- continue;
-
- if ((w = write(fd, buf, blksz)) < 0) {
- fprintf(stderr, "Error writing to %s\n", dev);
- close(fd);
- close(fd_rand);
- return -1;
- }
-
- erased += (size_t)w;
- }
-
- close(fd);
- close(fd_rand);
-
- return 0;
-}
-
-int
-get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
-{
- struct partinfo pinfo;
- int fd;
-
- if ((fd = open(dev, O_RDONLY)) < 0) {
- fprintf(stderr, "Error opening %s\n", dev);
- return -1;
- }
-
- memset(&pinfo, 0, sizeof(struct partinfo));
-
- if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
- close(fd);
- return -1;
- }
-
- *blocks = pinfo.media_blocks;
- *bsize = pinfo.media_blksize;
-
- close(fd);
- return 0;
-}
-
-int
-tc_encrypt(const char *cipher_name, unsigned char *key, unsigned char *iv,
- unsigned char *in, int in_len, unsigned char *out)
-{
- const EVP_CIPHER *evp;
- EVP_CIPHER_CTX ctx;
- int outl, tmplen;
-
- evp = EVP_get_cipherbyname(cipher_name);
- if (evp == NULL) {
- printf("Cipher %s not found\n", cipher_name);
- return ENOENT;
- }
-
- EVP_CIPHER_CTX_init(&ctx);
- EVP_EncryptInit(&ctx, evp, key, iv);
- EVP_EncryptUpdate(&ctx, out, &outl, in, in_len);
- EVP_EncryptFinal(&ctx, out + outl, &tmplen);
-
- return 0;
-}
-
-int
-tc_decrypt(const char *cipher_name, unsigned char *key, unsigned char *iv,
- unsigned char *in, int in_len, unsigned char *out)
-{
- const EVP_CIPHER *evp;
- EVP_CIPHER_CTX ctx;
- int outl, tmplen;
-
- evp = EVP_get_cipherbyname(cipher_name);
- if (evp == NULL) {
- printf("Cipher %s not found\n", cipher_name);
- return ENOENT;
- }
-
- EVP_CIPHER_CTX_init(&ctx);
- EVP_DecryptInit(&ctx, evp, key, iv);
- EVP_DecryptUpdate(&ctx, out, &outl, in, in_len);
- EVP_DecryptFinal(&ctx, out + outl, &tmplen);
-
- return 0;
-}
-
-int
-pbkdf2(const char *pass, int passlen, const unsigned char *salt, int saltlen,
- int iter, const char *hash_name, int keylen, unsigned char *out)
-{
- const EVP_MD *md;
- int r;
-
- md = EVP_get_digestbyname(hash_name);
- if (md == NULL) {
- printf("Hash %s not found\n", hash_name);
- return ENOENT;
- }
- r = PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen, iter, md,
- keylen, out);
-
- if (r == 0) {
- printf("Error in PBKDF2\n");
- return EINVAL;
- }
-
- return 0;
-}
-
-int
-read_passphrase(char *prompt, char *pass, size_t passlen)
-{
- struct termios termios_old, termios_new;
- ssize_t n;
- int fd, r = 0, cfd = 0;
-
- if ((fd = open("/dev/tty", O_RDONLY)) == -1) {
- fd = STDIN_FILENO;
- cfd = 1;
- }
-
- printf(prompt);
- fflush(stdout);
-
- memset(pass, 0, passlen);
-
- tcgetattr(fd, &termios_old);
- memcpy(&termios_new, &termios_old, sizeof(termios_new));
- termios_new.c_lflag &= ~ECHO;
- tcsetattr(fd, TCSAFLUSH, &termios_new);
-
- n = read(fd, pass, passlen-1);
- if (n > 0) {
- pass[n-1] = '\0'; /* Strip trailing \n */
- } else {
- r = EIO;
- }
-
- if (cfd)
- close(fd);
-
- tcsetattr(fd, TCSAFLUSH, &termios_old);
- putchar('\n');
-
- return r;
-}
-
-struct tchdr_dec *
-decrypt_hdr(struct tchdr_enc *ehdr, char *algo, unsigned char *key)
-{
- struct tchdr_dec *dhdr;
- unsigned char iv[128];
- int error;
-
- if ((dhdr = alloc_safe_mem(sizeof(struct tchdr_dec))) == NULL) {
- fprintf(stderr, "Error allocating safe tchdr_dec memory\n");
- return NULL;
- }
-
- memset(iv, 0, sizeof(iv));
-
- error = tc_decrypt(algo, key, iv, ehdr->enc, sizeof(struct tchdr_dec),
- (unsigned char *)dhdr);
- if (error) {
- fprintf(stderr, "Header decryption failed\n");
- free_safe_mem(dhdr);
- return NULL;
- }
-
- BE_TO_HOST(16, dhdr->tc_ver);
- LE_TO_HOST(16, dhdr->tc_min_ver);
- BE_TO_HOST(32, dhdr->crc_keys);
- BE_TO_HOST(64, dhdr->vol_ctime);
- BE_TO_HOST(64, dhdr->hdr_ctime);
- BE_TO_HOST(64, dhdr->sz_hidvol);
- BE_TO_HOST(64, dhdr->sz_vol);
- BE_TO_HOST(64, dhdr->off_mk_scope);
- BE_TO_HOST(64, dhdr->sz_mk_scope);
- BE_TO_HOST(32, dhdr->flags);
- BE_TO_HOST(32, dhdr->sec_sz);
- BE_TO_HOST(32, dhdr->crc_dhdr);
-
- return dhdr;
-}
-
-int
-verify_hdr(struct tchdr_dec *hdr)
-{
- uint32_t crc;
-
- if (memcmp(hdr->tc_str, TC_SIG, sizeof(hdr->tc_str)) != 0) {
-#ifdef DEBUG
- fprintf(stderr, "Signature mismatch\n");
-#endif
- return 0;
- }
-
- crc = crc32((void *)&hdr->keys, 256);
- if (crc != hdr->crc_keys) {
-#ifdef DEBUG
- fprintf(stderr, "CRC32 mismatch (crc_keys)\n");
-#endif
- return 0;
- }
-
- switch(hdr->tc_ver) {
- case 1:
- case 2:
- /* Unsupported header version */
- fprintf(stderr, "Header version %d unsupported\n", hdr->tc_ver);
- return 0;
-
- case 3:
- case 4:
- hdr->sec_sz = 512;
- break;
- }
-
- return 1;
-}
-
-int
-apply_keyfiles(unsigned char *pass, size_t pass_memsz, const char *keyfiles[],
- int nkeyfiles)
-{
- int pl, k;
- unsigned char *kpool;
- unsigned char *kdata;
- int kpool_idx;
- size_t i, kdata_sz;
- uint32_t crc;
-
- if (pass_memsz < MAX_PASSSZ) {
- fprintf(stderr, "Not enough memory for password manipluation\n");
- return ENOMEM;
- }
-
- pl = strlen(pass);
- memset(pass+pl, 0, MAX_PASSSZ-pl);
-
- if ((kpool = alloc_safe_mem(KPOOL_SZ)) == NULL) {
- fprintf(stderr, "Error allocating memory for keyfile pool\n");
- return ENOMEM;
- }
-
- memset(kpool, 0, KPOOL_SZ);
-
- for (k = 0; k < nkeyfiles; k++) {
-#ifdef DEBUG
- printf("Loading keyfile %s into kpool\n", keyfiles[k]);
-#endif
- kpool_idx = 0;
- crc = ~0U;
- kdata_sz = MAX_KFILE_SZ;
-
- if ((kdata = read_to_safe_mem(keyfiles[k], 0, &kdata_sz)) == NULL) {
- fprintf(stderr, "Error reading keyfile %s content\n",
- keyfiles[k]);
- free_safe_mem(kpool);
- return EIO;
- }
-
- for (i = 0; i < kdata_sz; i++) {
- crc = crc32_intermediate(crc, kdata[i]);
-
- kpool[kpool_idx++] += (unsigned char)(crc >> 24);
- kpool[kpool_idx++] += (unsigned char)(crc >> 16);
- kpool[kpool_idx++] += (unsigned char)(crc >> 8);
- kpool[kpool_idx++] += (unsigned char)(crc);
-
- /* Wrap around */
- if (kpool_idx == KPOOL_SZ)
- kpool_idx = 0;
- }
-
- free_safe_mem(kdata);
- }
-
-#ifdef DEBUG
- printf("Applying kpool to passphrase\n");
-#endif
- /* Apply keyfile pool to passphrase */
- for (i = 0; i < KPOOL_SZ; i++)
- pass[i] += kpool[i];
-
- free_safe_mem(kpool);
-
- return 0;
-}
-
void
print_info(struct tcplay_info *info)
{
@@ -793,118 +228,6 @@ process_hdr(const char *dev, unsigned char *pass, int passlen,
}
int
-write_hdr(const char *dev, off_t offset, size_t blksz, struct tchdr_enc *hdr)
-{
- ssize_t w;
- int fd;
-
- if ((fd = open(dev, O_WRONLY)) < 0) {
- fprintf(stderr, "Error opening device %s\n", dev);
- return -1;
- }
-
- if ((lseek(fd, offset, SEEK_SET) < 0)) {
- fprintf(stderr, "Error seeking on device %s\n", dev);
- close(fd);
- return -1;
- }
-
- if ((w = write(fd, hdr, sizeof(*hdr))) <= 0) {
- fprintf(stderr, "Error writing to device %s\n", dev);
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-struct tchdr_enc *
-create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo,
- struct tc_crypto_algo *cipher, size_t sec_sz, size_t total_blocks,
- off_t offset, size_t blocks, int hidden)
-{
- struct tchdr_enc *ehdr;
- struct tchdr_dec *dhdr;
- unsigned char *key;
- unsigned char iv[128];
- int error;
-
- if ((dhdr = (struct tchdr_dec *)alloc_safe_mem(sizeof(*dhdr))) == NULL) {
- fprintf(stderr, "could not allocate safe dhdr memory\n");
- return NULL;
- }
-
- if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) {
- fprintf(stderr, "could not allocate safe ehdr memory\n");
- return NULL;
- }
-
- if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
- fprintf(stderr, "could not allocate safe key memory\n");
- return NULL;
- }
-
- if ((error = get_random(ehdr->salt, sizeof(ehdr->salt))) != 0) {
- fprintf(stderr, "could not get salt\n");
- return NULL;
- }
-
- error = pbkdf2(pass, passlen,
- ehdr->salt, sizeof(ehdr->salt),
- prf_algo->iteration_count,
- prf_algo->name, MAX_KEYSZ, key);
- if (error) {
- fprintf(stderr, "could not derive key\n");
- return NULL;
- }
-
- memset(dhdr, 0, sizeof(*dhdr));
-
- if ((error = get_random(dhdr->keys, sizeof(dhdr->keys))) != 0) {
- fprintf(stderr, "could not get key random bits\n");
- return NULL;
- }
-
- memcpy(dhdr->tc_str, "TRUE", 4);
- dhdr->tc_ver = 5;
- dhdr->tc_min_ver = 7;
- dhdr->crc_keys = crc32((void *)&dhdr->keys, 256);
- dhdr->sz_vol = blocks * sec_sz;
- if (hidden)
- dhdr->sz_hidvol = dhdr->sz_vol;
- dhdr->off_mk_scope = offset * sec_sz;
- dhdr->sz_mk_scope = blocks * sec_sz;
- dhdr->sec_sz = sec_sz;
- dhdr->flags = 0;
-
- HOST_TO_BE(16, dhdr->tc_ver);
- HOST_TO_LE(16, dhdr->tc_min_ver);
- HOST_TO_BE(32, dhdr->crc_keys);
- HOST_TO_BE(64, dhdr->sz_vol);
- HOST_TO_BE(64, dhdr->sz_hidvol);
- HOST_TO_BE(64, dhdr->off_mk_scope);
- HOST_TO_BE(64, dhdr->sz_mk_scope);
- HOST_TO_BE(32, dhdr->sec_sz);
- HOST_TO_BE(32, dhdr->flags);
-
- dhdr->crc_dhdr = crc32((void *)dhdr, 188);
- HOST_TO_BE(32, dhdr->crc_dhdr);
-
- memset(iv, 0, sizeof(iv));
- error = tc_encrypt(cipher->name, key, iv, (unsigned char *)dhdr,
- sizeof(struct tchdr_dec), ehdr->enc);
- if (error) {
- fprintf(stderr, "Header encryption failed\n");
- free_safe_mem(dhdr);
- return NULL;
- }
-
- free_safe_mem(dhdr);
- return ehdr;
-}
-
-int
create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles,
const char *h_keyfiles[], int n_hkeyfiles, struct pbkdf_prf_algo *prf_algo,
struct tc_crypto_algo *cipher)
@@ -1054,13 +377,14 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
}
}
- if ((error = write_hdr(dev, 0, blksz, ehdr)) != 0) {
+ if ((error = write_mem(dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) {
fprintf(stderr, "Could not write volume header to device\n");
return -1;
}
if (hidden) {
- if ((error = write_hdr(dev, HDR_OFFSET_HIDDEN, blksz, hehdr)) != 0) {
+ if ((error = write_mem(dev, HDR_OFFSET_HIDDEN, blksz, hehdr,
+ sizeof(*hehdr))) != 0) {
fprintf(stderr, "Could not write hidden volume header to "
"device\n");
return -1;
@@ -1210,34 +534,38 @@ usage(void)
fprintf(stderr,
"Usage: tc-play <command> [options]\n"
"Valid commands and its arguments are:\n"
- " -c\n"
- "\t Creates a new TC volume on the device specified by -d\n"
- " -i\n"
- "\t Gives information about the TC volume specified by -d\n"
- " -m <mapping name>\n"
- "\t Creates a dm-crypt mapping for the device specified by -d\n"
- "Valid options and its arguments are:\n"
- " -a <pbkdf prf algorithm>\n"
- "\t specifies which hashing function to use for the PBKDF password derivation\n"
- "\t when creating a new volume. To see valid options, specify -a help.\n"
- " -b <cipher>\n"
- "\t specifies which cipher to use when creating a new TC volume.\n"
+ " -c, --create\n"
+ "\t Creates a new TC volume on the device specified by -d or --device\n"
+ " -i, --info\n"
+ "\t Gives information about the TC volume specified by -d or --device\n"
+ " -m <mapping name>, --map=<mapping name>\n"
+ "\t Creates a dm-crypt mapping with the given name for the device\n"
+ "\t specified by -d or --device\n"
+ "\nValid options and its arguments for 'create' are:\n"
+ " -a <pbkdf prf algorithm>, --pbkdf-prf=<pbkdf prf algorithm>\n"
+ "\t specifies which hashing function to use for the PBKDF password\n"
+ "\t derivation\n"
+ "\t when creating a new volume. To see valid options, specify -a help\n"
+ " -b <cipher>, --cipher=<cipher>\n"
+ "\t specifies which cipher to use when creating a new TC volume\n"
"\t To see valid options, specify -a help\n"
- " -d <device path>\n"
- "\t specifies the path to the volume to operate on (e.g. /dev/da0s1)\n"
- " -s <disk path>\n"
+ " -g, --hidden\n"
+ "\t specifies that the newly created volume will contain a hidden volume\n"
+ "\nValid options and its arguments for 'info' and 'map' are:\n"
+ " -e, --protect-hidden\n"
+ "\t protect a hidden volume when mounting the outer volume\n"
+ " -s <disk path>, --system-encryption=<disk path>\n"
"\t specifies that the disk (e.g. /dev/da0) is using system encryption\n"
- " -k <key file>\n"
+ "\nValid options and its arguments common to all commands are:\n"
+ " -d <device path>, --device=<device path>\n"
+ "\t specifies the path to the volume to operate on (e.g. /dev/da0s1)\n"
+ " -k <key file>, --keyfile=<key file>\n"
"\t specifies a key file to use for the password derivation, can appear\n"
- "\t multiple times.\n"
- " -e\n"
- "\t protect a hidden volume when mounting the outer volume\n"
- " -f <key file>\n"
- "\t specifies a key file to use for the hidden volume password derivation.\n"
- "\t This option is only valid in combination with -e\n"
- " -g\n"
- "\t specifies that the newly created volume will contain a hidden volume.\n"
- "\t Option is only valid when creating a new TC volume\n"
+ "\t multiple times\n"
+ " -f <key file>, --keyfile-hidden=<key file>\n"
+ "\t specifies a key file to use for the hidden volume password derivation\n"
+ "\t This option is only valid in combination with -e, --protect-hidden\n"
+ "\t or -g, --hidden\n"
);
exit(1);
@@ -1255,6 +583,8 @@ static struct option longopts[] = {
{ "protect-hidden", no_argument, NULL, 'e' },
{ "device", required_argument, NULL, 'd' },
{ "system-encryption", required_argument, NULL, 's' },
+ { "version", no_argument, NULL, 'v' },
+ { "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 },
};
@@ -1276,13 +606,14 @@ main(int argc, char *argv[])
struct tc_crypto_algo *cipher = NULL;
size_t sz;
- OpenSSL_add_all_algorithms();
+ tc_crypto_init();
atexit(check_and_purge_safe_mem);
nkeyfiles = 0;
n_hkeyfiles = 0;
- while ((ch = getopt_long(argc, argv, "a:b:cd:ef:ik:m:s:v", longopts, NULL)) != -1) {
+ while ((ch = getopt_long(argc, argv, "a:b:cd:efgh:ik:m:s:v", longopts,
+ NULL)) != -1) {
switch(ch) {
case 'a':
if (prf != NULL)
@@ -1365,8 +696,7 @@ main(int argc, char *argv[])
error = create_volume(dev, hidflag, keyfiles, nkeyfiles,
h_keyfiles, n_hkeyfiles, prf, cipher);
if (error) {
- fprintf(stderr, "could not create new volume on %s\n", dev);
- exit(1);
+ err(1, "could not create new volume on %s\n", dev);
}
exit(0);
/* NOT REACHED */
@@ -1425,25 +755,6 @@ main(int argc, char *argv[])
hehdr = NULL;
}
-#if 0
- if ((error = process_hdr(dev, pass, (nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
- ehdr, &info)) != 0) {
- if (hehdr) {
- if ((error = process_hdr(dev, pass, (nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
- hehdr, &info)) != 0) {
- free_safe_mem(hehdr);
- r = 1;
- fprintf(stderr, "Incorrect password or not a TrueCrypt volume\n");
- goto out;
- }
- } else {
- r = 1;
- fprintf(stderr, "Incorrect password or not a TrueCrypt volume\n");
- goto out;
- }
- }
-#endif
-
error = process_hdr(dev, pass, (nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
ehdr, &info);
@@ -1461,14 +772,12 @@ main(int argc, char *argv[])
if ((hflag && (error || error2)) || /* We need both to protect a h. vol */
(error && error2)) {
- fprintf(stderr, "Incorrect password or not a TrueCrypt volume\n");
- goto out;
+ errx(1, "Incorrect password or not a TrueCrypt volume\n");
}
if (hflag) {
if (adjust_info(info, hinfo) != 0) {
- fprintf(stderr, "Could not protected hidden volume\n");
- goto out;
+ errx(1, "Could not protected hidden volume\n");
}
}
@@ -1476,27 +785,10 @@ main(int argc, char *argv[])
print_info(info);
} else if (mflag) {
if ((error = dm_setup(map_name, info)) != 0) {
- fprintf(stderr, "could not set up dm-crypt mapping");
- goto out;
+ err(1, "could not set up dm-crypt mapping");
}
printf("All ok!");
}
-out:
- free_safe_mem(ehdr);
- if (hehdr)
- free_safe_mem(hehdr);
- free_safe_mem(pass);
- if (h_pass)
- free_safe_mem(h_pass);
- if (info) {
- free_safe_mem(info->hdr);
- free_safe_mem(info);
- }
- if (hinfo) {
- free_safe_mem(hinfo->hdr);
- free_safe_mem(hinfo);
- }
-
return r;
}
View
55 tc-play.h
@@ -1,8 +1,6 @@
/*
- * Copyright (c) 2011 The DragonFly Project. All rights reserved.
- *
- * This code is derived from software contributed to The DragonFly Project
- * by Alex Hornung <ahornung@gmail.com>
+ * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -14,9 +12,6 @@
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
- * 3. Neither the name of The DragonFly Project nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific, prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
@@ -48,6 +43,7 @@
#define TC_VOLFLAG_SYSTEM 0x01 /* system encryption */
#define TC_VOLFLAG_INPLACE 0x02 /* non-system in-place-encrypted volume */
+#include <uuid.h>
struct pbkdf_prf_algo {
char *name;
@@ -106,16 +102,37 @@ struct tcplay_info {
uuid_t uuid;
};
-struct safe_mem_hdr {
- struct safe_mem_hdr *prev;
- struct safe_mem_hdr *next;
- struct safe_mem_tail *tail;
- const char *file;
- int line;
- size_t alloc_sz;
- char sig[8]; /* SAFEMEM */
-};
+void *read_to_safe_mem(const char *file, off_t offset, size_t *sz);
+int get_random(unsigned char *buf, size_t len);
+int secure_erase(const char *dev, size_t bytes, size_t blksz);
+int get_disk_info(const char *dev, size_t *blocks, size_t *bsize);
+int write_mem(const char *dev, off_t offset, size_t blksz, void *mem, size_t bytes);
+int read_passphrase(char *prompt, char *pass, size_t passlen);
-struct safe_mem_tail {
- char sig[8]; /* SAFEMEM */
-};
+int tc_crypto_init(void);
+int tc_encrypt(const char *cipher_name, unsigned char *key, unsigned char *iv,
+ unsigned char *in, int in_len, unsigned char *out);
+int tc_decrypt(const char *cipher_name, unsigned char *key, unsigned char *iv,
+ unsigned char *in, int in_len, unsigned char *out);
+int pbkdf2(const char *pass, int passlen, const unsigned char *salt, int saltlen,
+ int iter, const char *hash_name, int keylen, unsigned char *out);
+int apply_keyfiles(unsigned char *pass, size_t pass_memsz, const char *keyfiles[],
+ int nkeyfiles);
+
+struct tchdr_enc *create_hdr(unsigned char *pass, int passlen,
+ struct pbkdf_prf_algo *prf_algo, struct tc_crypto_algo *cipher,
+ size_t sec_sz, size_t total_blocks,
+ off_t offset, size_t blocks, int hidden);
+struct tchdr_dec *decrypt_hdr(struct tchdr_enc *ehdr, char *algo,
+ unsigned char *key);
+int verify_hdr(struct tchdr_dec *hdr);
+
+void *_alloc_safe_mem(size_t req_sz, const char *file, int line);
+void _free_safe_mem(void *mem, const char *file, int line);
+void check_and_purge_safe_mem(void);
+
+#define alloc_safe_mem(x) \
+ _alloc_safe_mem(x, __FILE__, __LINE__)
+
+#define free_safe_mem(x) \
+ _free_safe_mem(x, __FILE__, __LINE__)
Please sign in to comment.
Something went wrong with that request. Please try again.