SRCS+= tcplay_api.c tcplay.c crc32.c safe_mem.c \
+ crypto.c generic_xts.c humanize.c pbkdf2-openssl.c \
io.c crypto-dev.c hdr.c
INCS+= tcplay_api.h
*/
#include <stdlib.h>
+#include <stdint.h>
#include "crc32.h"
uint32_t crc32_tab[] = {
uint32_t crc32(const void *buf, size_t size);
-uint32_t crc32_intermediate(uint32_t crc, uint8_t d);
\ No newline at end of file
+uint32_t crc32_intermediate(uint32_t crc, uint8_t d);
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include <openssl/evp.h>
+#include <stdio.h>
-#include "crc32.h"
#include "tcplay.h"
static
static
int
-syscrypt(int cipher, unsigned char *key, size_t klen, unsigned char *iv,
+get_cryptodev_cipher_id(struct tc_crypto_algo *cipher)
+{
+ if (strcmp(cipher->name, "AES-128-XTS") == 0)
+ return CRYPTO_AES_XTS;
+ else if (strcmp(cipher->name, "AES-256-XTS") == 0)
+ return CRYPTO_AES_XTS;
+ else if (strcmp(cipher->name, "TWOFISH-128-XTS") == 0)
+ return CRYPTO_TWOFISH_XTS;
+ else if (strcmp(cipher->name, "TWOFISH-256-XTS") == 0)
+ return CRYPTO_TWOFISH_XTS;
+ else if (strcmp(cipher->name, "SERPENT-128-XTS") == 0)
+ return CRYPTO_SERPENT_XTS;
+ else if (strcmp(cipher->name, "SERPENT-256-XTS") == 0)
+ return CRYPTO_SERPENT_XTS;
+ else
+ return -1;
+}
+
+int
+syscrypt(struct tc_crypto_algo *cipher, unsigned char *key, size_t klen, unsigned char *iv,
unsigned char *in, unsigned char *out, size_t len, int do_encrypt)
{
struct session_op session;
struct crypt_op cryp;
+ int cipher_id;
int cryptodev_fd = -1, fd = -1;
+ cipher_id = get_cryptodev_cipher_id(cipher);
+ if (cipher_id < 0) {
+ tc_log(1, "Cipher %s not found\n",
+ cipher->name);
+ return ENOENT;
+ }
+
if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
perror("Could not open /dev/crypto");
goto err;
goto err;
}
memset(&session, 0, sizeof(session));
- session.cipher = cipher;
+ session.cipher = cipher_id;
session.key = (caddr_t) key;
session.keylen = klen;
if (ioctl(fd, CIOCGSESSION, &session) == -1) {
return (-1);
}
-static
-int
-get_cryptodev_cipher_id(struct tc_crypto_algo *cipher)
-{
- if (strcmp(cipher->name, "AES-128-XTS") == 0)
- return CRYPTO_AES_XTS;
- else if (strcmp(cipher->name, "AES-256-XTS") == 0)
- return CRYPTO_AES_XTS;
- else if (strcmp(cipher->name, "TWOFISH-128-XTS") == 0)
- return CRYPTO_TWOFISH_XTS;
- else if (strcmp(cipher->name, "TWOFISH-256-XTS") == 0)
- return CRYPTO_TWOFISH_XTS;
- else if (strcmp(cipher->name, "SERPENT-128-XTS") == 0)
- return CRYPTO_SERPENT_XTS;
- else if (strcmp(cipher->name, "SERPENT-256-XTS") == 0)
- return CRYPTO_SERPENT_XTS;
- else
- return -1;
-}
-
int
tc_crypto_init(void)
{
int allowed;
- OpenSSL_add_all_algorithms();
-
allowed = getallowsoft();
if (allowed == 0)
setallowsoft(1);
return 0;
}
-int
-tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain,
- unsigned char *key)
-{
- int total_key_bytes, used_key_bytes;
- struct tc_cipher_chain *dummy_chain;
-
- /*
- * We need to determine the total key bytes as the key locations
- * depend on it.
- */
- total_key_bytes = 0;
- for (dummy_chain = cipher_chain;
- dummy_chain != NULL;
- dummy_chain = dummy_chain->next) {
- total_key_bytes += dummy_chain->cipher->klen;
- }
-
- /*
- * Now we need to get prepare the keys, as the keys are in
- * forward order with respect to the cipher cascade, but
- * the actual decryption is in reverse cipher cascade order.
- */
- used_key_bytes = 0;
- for (dummy_chain = cipher_chain;
- dummy_chain != NULL;
- dummy_chain = dummy_chain->next) {
- dummy_chain->key = alloc_safe_mem(dummy_chain->cipher->klen);
- if (dummy_chain->key == NULL) {
- tc_log(1, "tc_decrypt: Could not allocate key "
- "memory\n");
- return ENOMEM;
- }
-
- /* XXX: here we assume XTS operation! */
- memcpy(dummy_chain->key,
- key + used_key_bytes/2,
- dummy_chain->cipher->klen/2);
- memcpy(dummy_chain->key + dummy_chain->cipher->klen/2,
- key + (total_key_bytes/2) + used_key_bytes/2,
- dummy_chain->cipher->klen/2);
-
- /* Remember how many key bytes we've seen */
- used_key_bytes += dummy_chain->cipher->klen;
- }
-
- return 0;
-}
-
-int
-tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
- unsigned char *iv,
- unsigned char *in, int in_len, unsigned char *out)
-{
- int cipher_id;
- int err;
-
- if ((err = tc_cipher_chain_populate_keys(cipher_chain, key)))
- return err;
-
-#ifdef DEBUG
- printf("tc_encrypt: starting chain\n");
-#endif
-
- /*
- * Now process the actual decryption, in forward cascade order.
- */
- for (;
- cipher_chain != NULL;
- cipher_chain = cipher_chain->next) {
- cipher_id = get_cryptodev_cipher_id(cipher_chain->cipher);
- if (cipher_id < 0) {
- tc_log(1, "Cipher %s not found\n",
- cipher_chain->cipher->name);
- return ENOENT;
- }
-
-#ifdef DEBUG
- printf("tc_encrypt: Currently using cipher %s\n",
- cipher_chain->cipher->name);
-#endif
-
- err = syscrypt(cipher_id, cipher_chain->key,
- cipher_chain->cipher->klen, iv, in, out, in_len, 1);
-
- /* Deallocate this key, since we won't need it anymore */
- free_safe_mem(cipher_chain->key);
-
- if (err != 0)
- return err;
-
- /* Set next input buffer as current output buffer */
- in = out;
- }
-
- return 0;
-}
-
-int
-tc_decrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
- unsigned char *iv,
- unsigned char *in, int in_len, unsigned char *out)
-{
- int cipher_id;
- int err;
-
- if ((err = tc_cipher_chain_populate_keys(cipher_chain, key)))
- return err;
-
-#ifdef DEBUG
- printf("tc_decrypt: starting chain!\n");
-#endif
-
- /*
- * Now process the actual decryption, in reverse cascade order; so
- * first find the last element in the chain.
- */
- for (; cipher_chain->next != NULL; cipher_chain = cipher_chain->next)
- ;
- for (;
- cipher_chain != NULL;
- cipher_chain = cipher_chain->prev) {
- cipher_id = get_cryptodev_cipher_id(cipher_chain->cipher);
- if (cipher_id < 0) {
- tc_log(1, "Cipher %s not found\n",
- cipher_chain->cipher->name);
- return ENOENT;
- }
-
-#ifdef DEBUG
- printf("tc_decrypt: Currently using cipher %s\n",
- cipher_chain->cipher->name);
-#endif
-
- err = syscrypt(cipher_id, cipher_chain->key,
- cipher_chain->cipher->klen, iv, in, out, in_len, 0);
-
- /* Deallocate this key, since we won't need it anymore */
- free_safe_mem(cipher_chain->key);
-
- if (err != 0)
- return err;
-
- /* Set next input buffer as current output buffer */
- in = out;
- }
-
- 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) {
- tc_log(1, "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) {
- tc_log(1, "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) {
- tc_log(1, "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;
-}
*/
#include <sys/types.h>
#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/sysctl.h>
-#include <crypto/cryptodev.h>
+#include <inttypes.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include <openssl/evp.h>
+#include <stdio.h>
#include "crc32.h"
#include "tcplay.h"
-static
-int
-getallowsoft(void)
-{
- int old;
- size_t olen;
-
- olen = sizeof(old);
-
- if (sysctlbyname("kern.cryptodevallowsoft", &old, &olen, NULL, 0) < 0) {
- perror("accessing sysctl kern.cryptodevallowsoft failed");
- }
-
- return old;
-}
-
-static
-void
-setallowsoft(int new)
-{
- int old;
- size_t olen, nlen;
-
- olen = nlen = sizeof(new);
-
- if (sysctlbyname("kern.cryptodevallowsoft", &old, &olen, &new, nlen) < 0) {
- perror("accessing sysctl kern.cryptodevallowsoft failed");
- }
-}
-
-static
-int
-syscrypt(int cipher, unsigned char *key, size_t klen, unsigned char *iv,
- unsigned char *in, unsigned char *out, size_t len, int do_encrypt)
-{
- struct session_op session;
- struct crypt_op cryp;
- int cryptodev_fd = -1, fd = -1;
-
- if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
- perror("Could not open /dev/crypto");
- goto err;
- }
- if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) {
- perror("CRIOGET failed");
- goto err;
- }
- memset(&session, 0, sizeof(session));
- session.cipher = cipher;
- session.key = (caddr_t) key;
- session.keylen = klen;
- if (ioctl(fd, CIOCGSESSION, &session) == -1) {
- perror("CIOCGSESSION failed");
- goto err;
- }
- memset(&cryp, 0, sizeof(cryp));
- cryp.ses = session.ses;
- cryp.op = do_encrypt ? COP_ENCRYPT : COP_DECRYPT;
- cryp.flags = 0;
- cryp.len = len;
- cryp.src = (caddr_t) in;
- cryp.dst = (caddr_t) out;
- cryp.iv = (caddr_t) iv;
- cryp.mac = 0;
- if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
- perror("CIOCCRYPT failed");
- goto err;
- }
- if (ioctl(fd, CIOCFSESSION, &session.ses) == -1) {
- perror("CIOCFSESSION failed");
- goto err;
- }
- close(fd);
- close(cryptodev_fd);
- return (0);
-
-err:
- if (fd != -1)
- close(fd);
- if (cryptodev_fd != -1)
- close(cryptodev_fd);
- return (-1);
-}
-
-static
-int
-get_cryptodev_cipher_id(struct tc_crypto_algo *cipher)
-{
- if (strcmp(cipher->name, "AES-128-XTS") == 0)
- return CRYPTO_AES_XTS;
- else if (strcmp(cipher->name, "AES-256-XTS") == 0)
- return CRYPTO_AES_XTS;
- else if (strcmp(cipher->name, "TWOFISH-128-XTS") == 0)
- return CRYPTO_TWOFISH_XTS;
- else if (strcmp(cipher->name, "TWOFISH-256-XTS") == 0)
- return CRYPTO_TWOFISH_XTS;
- else if (strcmp(cipher->name, "SERPENT-128-XTS") == 0)
- return CRYPTO_SERPENT_XTS;
- else if (strcmp(cipher->name, "SERPENT-256-XTS") == 0)
- return CRYPTO_SERPENT_XTS;
- else
- return -1;
-}
-
-int
-tc_crypto_init(void)
-{
- int allowed;
-
- OpenSSL_add_all_algorithms();
-
- allowed = getallowsoft();
- if (allowed == 0)
- setallowsoft(1);
-
- return 0;
-}
-
int
tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain,
unsigned char *key)
}
int
+tc_cipher_chain_free_keys(struct tc_cipher_chain *cipher_chain)
+{
+ for (; cipher_chain != NULL; cipher_chain = cipher_chain->next) {
+ if (cipher_chain->key != NULL) {
+ free_safe_mem(cipher_chain->key);
+ cipher_chain->key = NULL;
+ }
+ }
+
+ return 0;
+}
+
+int
tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
unsigned char *iv,
unsigned char *in, int in_len, unsigned char *out)
{
- int cipher_id;
+ struct tc_cipher_chain *chain_start;
int err;
+ chain_start = cipher_chain;
+
if ((err = tc_cipher_chain_populate_keys(cipher_chain, key)))
return err;
for (;
cipher_chain != NULL;
cipher_chain = cipher_chain->next) {
- cipher_id = get_cryptodev_cipher_id(cipher_chain->cipher);
- if (cipher_id < 0) {
- tc_log(1, "Cipher %s not found\n",
- cipher_chain->cipher->name);
- return ENOENT;
- }
-
#ifdef DEBUG
printf("tc_encrypt: Currently using cipher %s\n",
cipher_chain->cipher->name);
#endif
- err = syscrypt(cipher_id, cipher_chain->key,
+ err = syscrypt(cipher_chain->cipher, cipher_chain->key,
cipher_chain->cipher->klen, iv, in, out, in_len, 1);
/* Deallocate this key, since we won't need it anymore */
free_safe_mem(cipher_chain->key);
+ cipher_chain->key = NULL;
- if (err != 0)
+ if (err != 0) {
+ tc_cipher_chain_free_keys(chain_start);
return err;
+ }
/* Set next input buffer as current output buffer */
in = out;
}
+ tc_cipher_chain_free_keys(chain_start);
+
return 0;
}
unsigned char *iv,
unsigned char *in, int in_len, unsigned char *out)
{
- int cipher_id;
+ struct tc_cipher_chain *chain_start;
int err;
+ chain_start = cipher_chain;
+
if ((err = tc_cipher_chain_populate_keys(cipher_chain, key)))
return err;
for (;
cipher_chain != NULL;
cipher_chain = cipher_chain->prev) {
- cipher_id = get_cryptodev_cipher_id(cipher_chain->cipher);
- if (cipher_id < 0) {
- tc_log(1, "Cipher %s not found\n",
- cipher_chain->cipher->name);
- return ENOENT;
- }
-
#ifdef DEBUG
printf("tc_decrypt: Currently using cipher %s\n",
cipher_chain->cipher->name);
#endif
- err = syscrypt(cipher_id, cipher_chain->key,
+ err = syscrypt(cipher_chain->cipher, cipher_chain->key,
cipher_chain->cipher->klen, iv, in, out, in_len, 0);
/* Deallocate this key, since we won't need it anymore */
free_safe_mem(cipher_chain->key);
+ cipher_chain->key = NULL;
- if (err != 0)
+ if (err != 0) {
+ tc_cipher_chain_free_keys(chain_start);
return err;
+ }
/* Set next input buffer as current output buffer */
in = out;
}
- 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;
- }
+ tc_cipher_chain_free_keys(chain_start);
return 0;
}
return ENOMEM;
}
- pl = strlen(pass);
+ pl = strlen((char *)pass);
memset(pass+pl, 0, MAX_PASSSZ-pl);
if ((kpool = alloc_safe_mem(KPOOL_SZ)) == NULL) {
--- /dev/null
+/*
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (C) 2011, Alex Hornung
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "tcplay.h"
+#include "generic_xts.h"
+
+
+
+static int
+xts_reinit(struct xts_ctx *ctx, u_int64_t blocknum)
+{
+ u_int i;
+
+ /*
+ * Prepare tweak as E_k2(IV). IV is specified as LE representation
+ * of a 64-bit block number which we allow to be passed in directly.
+ */
+ for (i = 0; i < XTS_IVSIZE; i++) {
+ ctx->tweak[i] = blocknum & 0xff;
+ blocknum >>= 8;
+ }
+ /* Last 64 bits of IV are always zero */
+ bzero(ctx->tweak + XTS_IVSIZE, XTS_IVSIZE);
+
+ return ctx->encrypt_fn(ctx->ctx2, ctx->blk_sz, ctx->tweak, ctx->tweak);
+}
+
+static int
+xts_crypt(struct xts_ctx *ctx, u_int8_t *data, u_int do_encrypt)
+{
+ u_int8_t block[XTS_MAX_BLOCKSIZE];
+ u_int i, carry_in, carry_out;
+ int err;
+
+ for (i = 0; i < ctx->blk_sz; i++)
+ block[i] = data[i] ^ ctx->tweak[i];
+
+ if (do_encrypt)
+ err = ctx->encrypt_fn(ctx->ctx1, ctx->blk_sz, block, data);
+ else
+ err = ctx->decrypt_fn(ctx->ctx1, ctx->blk_sz, block, data);
+
+ if (err)
+ goto out;
+
+ for (i = 0; i < ctx->blk_sz; i++)
+ data[i] ^= ctx->tweak[i];
+
+ /* Exponentiate tweak */
+ carry_in = 0;
+ for (i = 0; i < ctx->blk_sz; i++) {
+ carry_out = ctx->tweak[i] & 0x80;
+ ctx->tweak[i] = (ctx->tweak[i] << 1) | (carry_in ? 1 : 0);
+ carry_in = carry_out;
+ }
+ if (carry_in)
+ ctx->tweak[0] ^= XTS_ALPHA;
+
+out:
+ bzero(block, sizeof(block));
+ return err;
+}
+
+int
+xts_init(struct xts_ctx *ctx, void *arg1, void *arg2, set_key_fn _set_key_fn,
+ zero_key_fn _zero_key_fn, encrypt_decrypt_fn _encrypt_fn,
+ encrypt_decrypt_fn _decrypt_fn, u_int blk_sz, u_int8_t *key, int len)
+{
+ int err;
+
+ if (len != 32 && len != 64)
+ return -1;
+
+ ctx->blk_sz = blk_sz;
+ ctx->encrypt_fn = _encrypt_fn;
+ ctx->decrypt_fn = _decrypt_fn;
+ ctx->set_key_fn = _set_key_fn;
+ ctx->zero_key_fn = _zero_key_fn;
+
+ err = ctx->set_key_fn(&ctx->ctx1, arg1, arg2, key, len * 4);
+ if (err)
+ return -1;
+
+ err = ctx->set_key_fn(&ctx->ctx2, arg1, arg2, key + (len / 2),
+ len * 4);
+ if (err) {
+ ctx->zero_key_fn(&ctx->ctx1);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+xts_encrypt(struct xts_ctx *ctx, u_int8_t *data, size_t len, uint8_t *iv)
+{
+ uint64_t sector = *((uint64_t *)iv);
+ int err;
+
+ if ((len % ctx->blk_sz) != 0)
+ return -1;
+
+ err = xts_reinit(ctx, sector);
+ if (err)
+ return err;
+
+ while (len > 0) {
+ err = xts_crypt(ctx, data, 1);
+ if (err)
+ return -1;
+
+ data += ctx->blk_sz;
+ len -= ctx->blk_sz;
+ }
+
+ return err;
+}
+
+int
+xts_decrypt(struct xts_ctx *ctx, u_int8_t *data, size_t len, uint8_t *iv)
+{
+ uint64_t sector = *((uint64_t *)iv);
+ int err;
+
+ if ((len % ctx->blk_sz) != 0)
+ return -1;
+
+ err = xts_reinit(ctx, sector);
+ if (err)
+ return err;
+
+ while (len > 0) {
+ err = xts_crypt(ctx, data, 0);
+ if (err)
+ return -1;
+
+ data += ctx->blk_sz;
+ len -= ctx->blk_sz;
+ }
+
+ return err;
+}
+
+int
+xts_uninit(struct xts_ctx *ctx)
+{
+ ctx->zero_key_fn(&ctx->ctx1);
+ ctx->zero_key_fn(&ctx->ctx2);
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2008, Damien Miller
+ * Copyright (C) 2011, Alex Hornung
+ *
+ * Permission to use, copy, and modify this software with or without fee
+ * is hereby granted, provided that this entire notice is included in
+ * all copies of any software which is or includes a copy or
+ * modification of this software.
+ * You may use this code under the GNU public license if you so wish. Please
+ * contribute changes back to the authors under this freer than GPL license
+ * so that we may further the use of strong encryption without limitations to
+ * all.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
+ * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
+ * PURPOSE.
+ */
+
+#include <inttypes.h>
+#define XTS_MAX_BLOCKSIZE 16
+#define XTS_IVSIZE 8
+#define XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */
+
+typedef int (*encrypt_decrypt_fn)(void *, size_t, const uint8_t *, uint8_t *);
+typedef int (*set_key_fn)(void **, void *, void *, const uint8_t *, int);
+typedef int (*zero_key_fn)(void **);
+
+
+struct xts_ctx {
+ encrypt_decrypt_fn encrypt_fn;
+ encrypt_decrypt_fn decrypt_fn;
+ set_key_fn set_key_fn;
+ zero_key_fn zero_key_fn;
+
+ void *ctx1;
+ void *ctx2;
+ uint8_t tweak[XTS_MAX_BLOCKSIZE];
+ uint32_t blk_sz;
+};
+
+int xts_init(struct xts_ctx *ctxp, void *arg1, void *arg2, set_key_fn set_key_fn,
+ zero_key_fn zero_key_fn, encrypt_decrypt_fn encrypt_fn,
+ encrypt_decrypt_fn decrypt_fn, uint32_t blk_sz, uint8_t *key, int len);
+int xts_encrypt(struct xts_ctx *ctx, uint8_t *data, size_t len, uint8_t *iv);
+int xts_decrypt(struct xts_ctx *ctx, uint8_t *data, size_t len, uint8_t *iv);
+int xts_uninit(struct xts_ctx *ctxp);
+
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#include <sys/types.h>
+
+#if defined(__DragonFly__)
#include <sys/endian.h>
+#elif defined(__linux__)
+#include <endian.h>
+#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <inttypes.h>
#include <string.h>
#include "crc32.h"
create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo,
struct tc_cipher_chain *cipher_chain, size_t sec_sz,
size_t total_blocks __unused,
- off_t offset, size_t blocks, int hidden)
+ off_t offset, size_t blocks, int hidden, struct tchdr_enc **backup_hdr)
{
- struct tchdr_enc *ehdr;
+ struct tchdr_enc *ehdr, *ehdr_backup;
struct tchdr_dec *dhdr;
- unsigned char *key;
+ unsigned char *key, *key_backup;
unsigned char iv[128];
int error;
+ key = key_backup = NULL;
+ dhdr = NULL;
+ ehdr = ehdr_backup = NULL;
+
+ if (backup_hdr != NULL)
+ *backup_hdr = NULL;
+
if ((dhdr = (struct tchdr_dec *)alloc_safe_mem(sizeof(*dhdr))) == NULL) {
tc_log(1, "could not allocate safe dhdr memory\n");
- return NULL;
+ goto error;
}
if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) {
tc_log(1, "could not allocate safe ehdr memory\n");
- return NULL;
+ goto error;
+ }
+
+ if ((ehdr_backup = (struct tchdr_enc *)alloc_safe_mem
+ (sizeof(*ehdr_backup))) == NULL) {
+ tc_log(1, "could not allocate safe ehdr_backup memory\n");
+ goto error;
}
if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
tc_log(1, "could not allocate safe key memory\n");
- return NULL;
+ goto error;
+ }
+
+ if ((key_backup = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
+ tc_log(1, "could not allocate safe backup key memory\n");
+ goto error;
}
if ((error = get_random(ehdr->salt, sizeof(ehdr->salt))) != 0) {
tc_log(1, "could not get salt\n");
- return NULL;
+ goto error;
+ }
+
+ if ((error = get_random(ehdr_backup->salt, sizeof(ehdr_backup->salt)))
+ != 0) {
+ tc_log(1, "could not get salt for backup header\n");
+ goto error;
}
- error = pbkdf2(pass, passlen,
+ error = pbkdf2(prf_algo, (char *)pass, passlen,
ehdr->salt, sizeof(ehdr->salt),
- prf_algo->iteration_count,
- prf_algo->name, MAX_KEYSZ, key);
+ MAX_KEYSZ, key);
if (error) {
tc_log(1, "could not derive key\n");
- return NULL;
+ goto error;
+ }
+
+ error = pbkdf2(prf_algo, (char *)pass, passlen,
+ ehdr_backup->salt, sizeof(ehdr_backup->salt),
+ MAX_KEYSZ, key_backup);
+ if (error) {
+ tc_log(1, "could not derive backup key\n");
+ goto error;
}
memset(dhdr, 0, sizeof(*dhdr));
if ((error = get_random(dhdr->keys, sizeof(dhdr->keys))) != 0) {
tc_log(1, "could not get key random bits\n");
- return NULL;
+ goto error;
}
memcpy(dhdr->tc_str, "TRUE", 4);
sizeof(struct tchdr_dec), ehdr->enc);
if (error) {
tc_log(1, "Header encryption failed\n");
- free_safe_mem(dhdr);
- return NULL;
+ goto error;
}
+ memset(iv, 0, sizeof(iv));
+ error = tc_encrypt(cipher_chain, key_backup, iv,
+ (unsigned char *)dhdr,
+ sizeof(struct tchdr_dec), ehdr_backup->enc);
+ if (error) {
+ tc_log(1, "Backup header encryption failed\n");
+ goto error;
+ }
+
+ free_safe_mem(key);
+ free_safe_mem(key_backup);
free_safe_mem(dhdr);
+
+ if (backup_hdr != NULL)
+ *backup_hdr = ehdr_backup;
+ else
+ free_safe_mem(ehdr_backup);
+
return ehdr;
+ /* NOT REACHED */
+
+error:
+ if (key)
+ free_safe_mem(key);
+ if (key_backup)
+ free_safe_mem(key_backup);
+ if (dhdr)
+ free_safe_mem(dhdr);
+ if (ehdr)
+ free_safe_mem(ehdr);
+ if (ehdr_backup)
+ free_safe_mem(ehdr_backup);
+
+ return NULL;
}
--- /dev/null
+/*
+ * 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "humanize.h"
+
+static const char prefixes[] = " KMGTPE";
+int
+_humanize_number(char *buf, size_t bufsz, uint64_t num)
+{
+ const char *prefixp;
+ int ret;
+ uint64_t i, d;
+
+ prefixp = prefixes;
+ i = num;
+ d = 0;
+
+ while ((i > 1024) && (*prefixp != '\0')) {
+ d = (i % 1024)/10;
+ i /= 1024;
+ ++prefixp;
+ }
+
+ if (d > 0)
+ ret = snprintf(buf, bufsz, "%"PRIu64".%"PRIu64" %c",
+ i, d, *prefixp);
+ else
+ ret = snprintf(buf, bufsz, "%"PRIu64" %c", i, *prefixp);
+
+
+ if ((ret < 0) || ((size_t)ret >= bufsz)) {
+ errno = ENOMEM;
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+int
+_dehumanize_number(const char *buf, uint64_t *dest)
+{
+ char *endptr;
+ uint64_t n, n_check, d;
+ uint64_t multiplier;
+ size_t len;
+
+ if (*buf == '\0') {
+ errno = EINVAL;
+ return -1;
+ }
+
+ len = strlen(buf);
+ if (tolower(buf[len-1]) == 'b')
+ --len;
+
+ multiplier = 1;
+
+ switch (tolower(buf[len-1])) {
+ case 'y':
+ multiplier *= 1024;
+ case 'z':
+ multiplier *= 1024;
+ case 'e':
+ multiplier *= 1024;
+ case 'p':
+ multiplier *= 1024;
+ case 't':
+ multiplier *= 1024;
+ case 'g':
+ multiplier *= 1024;
+ case 'm':
+ multiplier *= 1024;
+ case 'k':
+ multiplier *= 1024;
+ break;
+ default:
+ /*
+ * only set error if string ends in a character that
+ * is not a valid unit.
+ */
+ if (isalpha(buf[len-1])) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ d = 0;
+ n = n_check = strtoull(buf, &endptr, 10);
+ if (endptr) {
+ if ((*endptr != '.') && (*endptr != '\0') &&
+ (*endptr != ' ') && (endptr != &buf[len-1])) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (*endptr == '.') {
+ d = strtoull(endptr+1, &endptr, 10);
+ if (endptr && (*endptr != '\0') &&
+ (*endptr != ' ') &&
+ (endptr != &buf[len-1])) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ }
+
+ if (d != 0) {
+ while (d < 100)
+ d *= 10;
+
+ while (d > 1000)
+ d /= 10;
+ }
+
+ d *= (multiplier/1024);
+ n *= multiplier;
+
+ if ((uint64_t)(n/multiplier) != n_check) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ n += d;
+ *dest = n;
+
+ return 0;
+}
+
+#ifdef __TEST_HUMANIZE__
+
+#include <assert.h>
+int main(int argc, char *argv[])
+{
+ char buf[1024];
+ uint64_t n, out;
+ int err;
+
+ if (argc < 3)
+ return -1;
+
+ n = strtoull(argv[1], NULL, 10);
+
+ err = _humanize_number(buf, 1024, n);
+ assert(err == 0);
+
+ err = _dehumanize_number(buf, &out);
+ assert(err == 0);
+
+ printf("Converting: %"PRIu64" => %s => %"PRIu64"\n", n, buf, out);
+
+ err = _dehumanize_number(argv[2], &out);
+ assert (err == 0);
+
+ printf("Converting: %s => %"PRIu64"\n", argv[2], out);
+
+ return 0;
+}
+
+#endif
* SUCH DAMAGE.
*/
-#define TC_OK 0
-#define TC_ERR -1
-
-typedef struct tc_api_opts {
- /* Common fields */
- char *tc_device;
- char *tc_passphrase;
- const char **tc_keyfiles;
-
- /* Fields for mapping */
- char *tc_map_name;
- int tc_password_retries;
- int tc_interactive_prompt;
- unsigned long tc_prompt_timeout;
-
- /* Fields for creation */
- char *tc_cipher;
- char *tc_prf_hash;
- char *tc_cipher_hidden;
- char *tc_prf_hash_hidden;
- size_t tc_size_hidden_in_blocks;
- char *tc_passphrase_hidden;
- const char **tc_keyfiles_hidden;
-} tc_api_opts;
-
-int tc_api_init(int verbose);
-int tc_api_uninit(void);
-int tc_api_create_volume(tc_api_opts *api_opts);
-int tc_api_map_volume(tc_api_opts *api_opts);
-int tc_api_unmap_volume(tc_api_opts *api_opts);
-int tc_api_check_cipher(tc_api_opts *api_opts);
-int tc_api_check_prf_hash(tc_api_opts *api_opts);
-const char *tc_api_get_error_msg(void);
-const char *tc_api_get_summary(void);
+int _humanize_number(char *buf, size_t bufsz, uint64_t num);
+int _dehumanize_number(const char *buf, uint64_t *dest);
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#include <sys/types.h>
+#if defined(__DragonFly__)
#include <sys/diskslice.h>
+#elif defined(__linux__)
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#endif
#include <sys/uio.h>
#include <sys/select.h>
#include <errno.h>
return NULL;
}
+static size_t get_random_total_bytes = 0;
+static size_t get_random_read_bytes = 0;
+
+static
+void
+get_random_summary(void)
+{
+ float pct_done;
+
+ pct_done = (1.0 * get_random_read_bytes) /
+ (1.0 * get_random_total_bytes) * 100.0;
+ tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done);
+}
+
int
get_random(unsigned char *buf, size_t len)
{
int fd;
ssize_t r;
size_t rd = 0;
+ size_t sz;
struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */
return -1;
}
+ summary_fn = get_random_summary;
+ get_random_total_bytes = len;
+
+ /* Get random data in 16-byte chunks */
+ sz = 16;
while (rd < len) {
- if ((r = read(fd, buf+rd, len-rd)) < 0) {
- tc_log(1, "Error reading from /dev/random\n");
+ get_random_read_bytes = rd;
+
+ if ((len - rd) < sz)
+ sz = (len - rd);
+
+ if ((r = read(fd, buf+rd, sz)) < 0) {
+ tc_log(1, "Error reading from /dev/random(%d): %s\n",
+ fd, strerror(errno));
close(fd);
+ summary_fn = NULL;
return -1;
}
rd += r;
}
close(fd);
+ summary_fn = NULL;
+
return 0;
}
return 0;
}
+#if defined(__DragonFly__)
int
get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
{
close(fd);
return 0;
}
+#elif defined(__linux__)
+int
+get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
+{
+ uint64_t nbytes;
+ int blocksz;
+ int fd;
+
+ if ((fd = open(dev, O_RDONLY)) < 0) {
+ tc_log(1, "Error opening %s\n", dev);
+ return -1;
+ }
+
+ if ((ioctl(fd, BLKSSZGET, &blocksz)) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ if ((ioctl(fd, BLKGETSIZE64, &nbytes)) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ *blocks = (size_t)(nbytes / blocksz);
+ *bsize = (size_t)(blocksz);
+
+ close(fd);
+ return 0;
+}
+#endif
int
-write_mem(const char *dev, off_t offset, size_t blksz __unused, void *mem,
+write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem,
size_t bytes)
{
+ unsigned char *mem_buf = NULL;
ssize_t w;
+ size_t sz;
+ off_t internal_off;
int fd;
+ /* Align to block sizes */
+ internal_off = offset % blksz;
+#ifdef DEBUG
+ printf("offset: %"PRIu64", internal offset: %"PRIu64"\n",
+ (uint64_t)offset, (uint64_t)internal_off);
+#endif
+ offset = (offset/blksz) * blksz;
+
+ if ((internal_off + bytes) > blksz) {
+ tc_log(1, "This should never happen: internal_off + bytes > "
+ "blksz (write_to_disk)\n");
+ return -1;
+ }
+
+ if ((bytes < blksz) || (internal_off != 0)) {
+ sz = blksz;
+ if ((mem_buf = read_to_safe_mem(dev, offset, &sz)) == NULL) {
+ tc_log(1, "Error buffering data on "
+ "write_to_disk(%s)\n", dev);
+ return -1;
+ }
+
+ memcpy(mem_buf + internal_off, mem, bytes);
+ }
+
if ((fd = open(dev, O_WRONLY)) < 0) {
tc_log(1, "Error opening device %s\n", dev);
return -1;
return -1;
}
- if ((w = write(fd, mem, bytes)) <= 0) {
+ if ((w = write(fd, (mem_buf != NULL) ? mem_buf : mem, bytes)) <= 0) {
tc_log(1, "Error writing to device %s\n", dev);
close(fd);
return -1;
}
close(fd);
+
+ if (mem_buf != NULL)
+ free_safe_mem(mem_buf);
return 0;
}
* SUCH DAMAGE.
*/
-#define TC_OK 0
-#define TC_ERR -1
+#include <errno.h>
+#include <openssl/evp.h>
-typedef struct tc_api_opts {
- /* Common fields */
- char *tc_device;
- char *tc_passphrase;
- const char **tc_keyfiles;
+#include "tcplay.h"
- /* Fields for mapping */
- char *tc_map_name;
- int tc_password_retries;
- int tc_interactive_prompt;
- unsigned long tc_prompt_timeout;
- /* Fields for creation */
- char *tc_cipher;
- char *tc_prf_hash;
- char *tc_cipher_hidden;
- char *tc_prf_hash_hidden;
- size_t tc_size_hidden_in_blocks;
- char *tc_passphrase_hidden;
- const char **tc_keyfiles_hidden;
-} tc_api_opts;
+int
+pbkdf2(struct pbkdf_prf_algo *hash, const char *pass, int passlen,
+ const unsigned char *salt, int saltlen,
+ int keylen, unsigned char *out)
+{
+ const EVP_MD *md;
+ int r;
-int tc_api_init(int verbose);
-int tc_api_uninit(void);
-int tc_api_create_volume(tc_api_opts *api_opts);
-int tc_api_map_volume(tc_api_opts *api_opts);
-int tc_api_unmap_volume(tc_api_opts *api_opts);
-int tc_api_check_cipher(tc_api_opts *api_opts);
-int tc_api_check_prf_hash(tc_api_opts *api_opts);
-const char *tc_api_get_error_msg(void);
-const char *tc_api_get_summary(void);
+ OpenSSL_add_all_algorithms();
+
+ md = EVP_get_digestbyname(hash->name);
+ if (md == NULL) {
+ tc_log(1, "Hash %s not found\n", hash->name);
+ return ENOENT;
+ }
+ r = PKCS5_PBKDF2_HMAC(pass, passlen, salt, saltlen,
+ hash->iteration_count, md, keylen, out);
+
+ if (r == 0) {
+ tc_log(1, "Error in PBKDF2\n");
+ return EINVAL;
+ }
+
+ return 0;
+}
* 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>
char *tc_prf_hash;
char *tc_cipher_hidden;
char *tc_prf_hash_hidden;
- size_t tc_size_hidden_in_blocks;
+ size_t tc_size_hidden_in_bytes;
char *tc_passphrase_hidden;
const char **tc_keyfiles_hidden;
} tc_api_opts;
.Fa tc_keyfiles
respectively.
If
-.Fa tc_size_hidden_in_blocks
+.Fa tc_size_hidden_in_bytes
is not zero, a hidden volume of the given size will be created, using
the cipher specified by
.Fa tc_cipher_hidden
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <machine/inttypes.h>
+
+#if defined(__linux__)
+#define _GNU_SOURCE /* for asprintf */
+#endif
+
#include <sys/types.h>
+
+#if defined(__DragonFly__)
#include <sys/param.h>
+#endif
+
#include <stdio.h>
#include <stdlib.h>
+#include <stdarg.h>
+#include <inttypes.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <err.h>
#include <time.h>
+#if defined(__linux__)
+#include <libdevmapper.h>
+#include <uuid/uuid.h>
+#elif defined(__DragonFly__)
#include <libdm.h>
-#include <libutil.h>
+#include <uuid.h>
+#endif
#include "crc32.h"
#include "tcplay.h"
+#include "humanize.h"
/* XXX TODO:
void
tc_log(int is_err, const char *fmt, ...)
{
- __va_list ap;
+ va_list ap;
FILE *fp;
if (is_err)
else
fp = stdout;
- __va_start(ap, fmt);
+ va_start(ap, fmt);
vsnprintf(tc_internal_log_buffer, LOG_BUFFER_SZ, fmt, ap);
- if (tc_internal_verbose)
- vfprintf(fp, fmt, ap);
+ va_end(ap);
- __va_end(ap);
+ if (tc_internal_verbose)
+ fprintf(fp, "%s", tc_internal_log_buffer);
}
/* Supported algorithms */
printf("CRC Key Data:\t\t%#x\n", info->hdr->crc_keys);
printf("Sector size:\t\t%d\n", info->hdr->sec_sz);
printf("Volume size:\t\t%zu sectors\n", info->size);
+#if 0
+ /* Don't print this; it's always 0 and is rather confusing */
+ printf("Volume offset:\t\t%"PRIu64"\n", (uint64_t)info->start);
+#endif
+ printf("IV offset:\t\t%"PRIu64"\n", (uint64_t)info->skip);
+ printf("Block offset:\t\t%"PRIu64"\n", (uint64_t)info->offset);
}
static
new_info(const char *dev, struct tc_cipher_chain *cipher_chain,
struct pbkdf_prf_algo *prf, struct tchdr_dec *hdr, off_t start)
{
+ struct tc_cipher_chain *chain_start;
struct tcplay_info *info;
int i;
int error;
+ chain_start = cipher_chain;
+
if ((info = (struct tcplay_info *)alloc_safe_mem(sizeof(*info))) == NULL) {
tc_log(1, "could not allocate safe info memory\n");
return NULL;
cipher_chain->key[i]);
}
+ tc_cipher_chain_free_keys(chain_start);
+
return info;
}
printf("Salt: ");
print_hex(ehdr->salt, 0, sizeof(ehdr->salt));
#endif
- error = pbkdf2(pass, passlen,
+ error = pbkdf2(&pbkdf_prf_algos[i], (char *)pass, passlen,
ehdr->salt, sizeof(ehdr->salt),
- pbkdf_prf_algos[i].iteration_count,
- pbkdf_prf_algos[i].name, MAX_KEYSZ, key);
+ MAX_KEYSZ, key);
if (error) {
tc_log(1, "pbkdf failed for algorithm %s\n",
pbkdf_prf_algos[i].name);
+ free_safe_mem(key);
return EINVAL;
}
if (dhdr == NULL) {
tc_log(1, "hdr decryption failed for cipher "
"chain %d\n", j);
+ free_safe_mem(key);
return EINVAL;
}
if (verify_hdr(dhdr)) {
#ifdef DEBUG
- printf("tc_str: %.4s, tc_ver: %zd, tc_min_ver: %zd, "
+ printf("tc_str: %.4s, tc_ver: %d, tc_min_ver: %d, "
"crc_keys: %d, sz_vol: %"PRIu64", "
"off_mk_scope: %"PRIu64", sz_mk_scope: %"PRIu64", "
"flags: %d, sec_sz: %d crc_dhdr: %d\n",
if ((info = new_info(dev, tc_cipher_chains[j-1], &pbkdf_prf_algos[i-1],
dhdr, 0)) == NULL) {
+ free_safe_mem(dhdr);
return ENOMEM;
}
*pinfo = info;
+
return 0;
}
const char *h_keyfiles[], int n_hkeyfiles, struct pbkdf_prf_algo *prf_algo,
struct tc_cipher_chain *cipher_chain, struct pbkdf_prf_algo *h_prf_algo,
struct tc_cipher_chain *h_cipher_chain, char *passphrase,
- char *h_passphrase, size_t hidden_blocks_in, int interactive)
+ char *h_passphrase, size_t size_hidden_bytes_in, int interactive)
{
char *pass, *pass_again;
char *h_pass = NULL;
char buf[1024];
size_t blocks, blksz, hidden_blocks = 0;
- struct tchdr_enc *ehdr, *hehdr = NULL;
- int64_t tmp;
- int error, r;
+ struct tchdr_enc *ehdr, *hehdr;
+ struct tchdr_enc *ehdr_backup, *hehdr_backup;
+ uint64_t tmp;
+ int error, r, ret;
+
+ pass = h_pass = pass_again = NULL;
+ ehdr = hehdr = NULL;
+ ehdr_backup = hehdr_backup = NULL;
+ ret = -1; /* Default to returning error */
if (cipher_chain == NULL)
cipher_chain = tc_cipher_chains[0];
return -1;
}
- if (blocks <= MIN_VOL_BLOCKS) {
+ if ((blocks*blksz) <= MIN_VOL_BYTES) {
tc_log(1, "Cannot create volumes on devices with less "
- "than %d blocks/sectors\n", MIN_VOL_BLOCKS);
+ "than %d bytes\n", MIN_VOL_BYTES);
return -1;
}
if (((pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) ||
((pass_again = alloc_safe_mem(MAX_PASSSZ)) == NULL)) {
tc_log(1, "could not allocate safe passphrase memory\n");
- return -1;
+ goto out;
}
if ((error = read_passphrase("Passphrase: ", pass, MAX_PASSSZ, 0) ||
(read_passphrase("Repeat passphrase: ", pass_again,
MAX_PASSSZ, 0)))) {
tc_log(1, "could not read passphrase\n");
- return -1;
+ goto out;
}
if (strcmp(pass, pass_again) != 0) {
tc_log(1, "Passphrases don't match\n");
- return -1;
+ goto out;
}
free_safe_mem(pass_again);
+ pass_again = NULL;
} else {
/* In batch mode, use provided passphrase */
if ((pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) {
tc_log(1, "could not allocate safe "
"passphrase memory");
- return -1;
+ goto out;
}
if (passphrase != NULL)
if (nkeyfiles > 0) {
/* Apply keyfiles to 'pass' */
- if ((error = apply_keyfiles(pass, MAX_PASSSZ, keyfiles,
- nkeyfiles))) {
+ if ((error = apply_keyfiles((unsigned char *)pass, MAX_PASSSZ,
+ keyfiles, nkeyfiles))) {
tc_log(1, "could not apply keyfiles\n");
+ goto out;
}
}
((pass_again = alloc_safe_mem(MAX_PASSSZ)) == NULL)) {
tc_log(1, "could not allocate safe "
"passphrase memory\n");
- return -1;
+ goto out;
}
if ((error = read_passphrase("Passphrase for hidden volume: ",
(read_passphrase("Repeat passphrase: ", pass_again,
MAX_PASSSZ, 0)))) {
tc_log(1, "could not read passphrase\n");
- return -1;
+ goto out;
}
if (strcmp(h_pass, pass_again) != 0) {
tc_log(1, "Passphrases for hidden volume don't "
"match\n");
- return -1;
+ goto out;
}
free_safe_mem(pass_again);
+ pass_again = NULL;
} else {
/* In batch mode, use provided passphrase */
if ((h_pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) {
tc_log(1, "could not allocate safe "
"passphrase memory");
- return -1;
+ goto out;
}
if (h_passphrase != NULL)
if (n_hkeyfiles > 0) {
/* Apply keyfiles to 'h_pass' */
- if ((error = apply_keyfiles(h_pass, MAX_PASSSZ, h_keyfiles,
- n_hkeyfiles))) {
+ if ((error = apply_keyfiles((unsigned char *)h_pass,
+ MAX_PASSSZ, h_keyfiles, n_hkeyfiles))) {
tc_log(1, "could not apply keyfiles\n");
- return -1;
+ goto out;
}
}
if (interactive) {
hidden_blocks = 0;
} else {
- hidden_blocks = hidden_blocks_in;
+ hidden_blocks = size_hidden_bytes_in/blksz;
if (hidden_blocks == 0) {
tc_log(1, "hidden_blocks to create volume "
"cannot be zero!\n");
- return -1;
+ goto out;
+ }
+
+ if (size_hidden_bytes_in >=
+ (blocks*blksz) - MIN_VOL_BYTES) {
+ tc_log(1, "Hidden volume needs to be "
+ "smaller than the outer volume\n");
+ goto out;
}
}
/* This only happens in interactive mode */
while (hidden_blocks == 0) {
- if ((r = humanize_number(buf, strlen("XXX MB"),
- (int64_t)(blocks * blksz), "B", 0, 0)) < 0) {
+ if ((r = _humanize_number(buf, sizeof(buf),
+ (uint64_t)(blocks * blksz))) < 0) {
sprintf(buf, "%zu bytes", (blocks * blksz));
}
printf("The total volume size of %s is %s (bytes)\n", dev, buf);
memset(buf, 0, sizeof(buf));
- printf("Size of hidden volume (e.g. 127M): ");
+ printf("Size of hidden volume (e.g. 127M): ");
fflush(stdout);
if ((fgets(buf, sizeof(buf), stdin)) == NULL) {
tc_log(1, "Could not read from stdin\n");
- return -1;
+ goto out;
}
/* get rid of trailing newline */
buf[strlen(buf)-1] = '\0';
- if ((error = dehumanize_number(buf,
+ if ((error = _dehumanize_number(buf,
&tmp)) != 0) {
tc_log(1, "Could not interpret input: %s\n", buf);
- return -1;
+ continue;
}
- hidden_blocks = (size_t)tmp;
- hidden_blocks /= blksz;
- if (hidden_blocks >= blocks - MIN_VOL_BLOCKS) {
+ if (tmp >= (blocks*blksz) - MIN_VOL_BYTES) {
tc_log(1, "Hidden volume needs to be "
"smaller than the outer volume\n");
hidden_blocks = 0;
continue;
}
+
+ hidden_blocks = (size_t)tmp;
+ hidden_blocks /= blksz;
}
}
fflush(stdout);
if ((fgets(buf, sizeof(buf), stdin)) == NULL) {
tc_log(1, "Could not read from stdin\n");
- return -1;
+ goto out;
}
if ((buf[0] != 'y') && (buf[0] != 'Y')) {
tc_log(1, "User cancelled action(s)\n");
- return -1;
+ goto out;
}
}
+ tc_log(0, "Securely erasing the volume...\nThis process may take "
+ "some time depending on the size of the volume\n");
+
/* erase volume */
if ((error = secure_erase(dev, blocks * blksz, blksz)) != 0) {
tc_log(1, "could not securely erase device %s\n", dev);
- return -1;
+ goto out;
}
+ tc_log(0, "Creating volume headers...\nDepending on your system, this "
+ "process may take a few minutes as it uses true random data which "
+ "might take a while to refill\n");
+
/* create encrypted headers */
- ehdr = create_hdr(pass, (nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
- prf_algo, cipher_chain, blksz, blocks, MIN_VOL_BLOCKS,
- blocks-MIN_VOL_BLOCKS, 0);
+ ehdr = create_hdr((unsigned char *)pass,
+ (nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
+ prf_algo, cipher_chain, blksz, blocks, VOL_RSVD_BYTES_START/blksz,
+ blocks - (MIN_VOL_BYTES/blksz), 0, &ehdr_backup);
if (ehdr == NULL) {
tc_log(1, "Could not create header\n");
- return -1;
+ goto out;
}
if (hidden) {
- hehdr = create_hdr(h_pass,
+ hehdr = create_hdr((unsigned char *)h_pass,
(n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), h_prf_algo,
h_cipher_chain,
- blksz, blocks, blocks - hidden_blocks, hidden_blocks, 1);
+ blksz, blocks,
+ blocks - (VOL_RSVD_BYTES_END/blksz) - hidden_blocks,
+ hidden_blocks, 1, &hehdr_backup);
if (hehdr == NULL) {
tc_log(1, "Could not create hidden volume header\n");
- return -1;
+ goto out;
}
}
- if ((error = write_mem(dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) {
+ tc_log(0, "Writing volume headers to disk...\n");
+
+ if ((error = write_to_disk(dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) {
tc_log(1, "Could not write volume header to device\n");
- return -1;
+ goto out;
+ }
+
+ /* Write backup header; it's offset is relative to the end */
+ if ((error = write_to_disk(dev, (blocks*blksz - BACKUP_HDR_OFFSET_END),
+ blksz, ehdr_backup, sizeof(*ehdr_backup))) != 0) {
+ tc_log(1, "Could not write backup volume header to device\n");
+ goto out;
}
if (hidden) {
- if ((error = write_mem(dev, HDR_OFFSET_HIDDEN, blksz, hehdr,
+ if ((error = write_to_disk(dev, HDR_OFFSET_HIDDEN, blksz, hehdr,
sizeof(*hehdr))) != 0) {
tc_log(1, "Could not write hidden volume header to "
"device\n");
- return -1;
+ goto out;
+ }
+
+ /* Write backup hidden header; offset is relative to end */
+ if ((error = write_to_disk(dev,
+ (blocks*blksz - BACKUP_HDR_HIDDEN_OFFSET_END), blksz,
+ hehdr_backup, sizeof(*hehdr_backup))) != 0) {
+ tc_log(1, "Could not write backup hidden volume "
+ "header to device\n");
+ goto out;
}
}
- return 0;
+ /* Everything went ok */
+ tc_log(0, "All done!\n");
+
+ ret = 0;
+
+out:
+ if (pass)
+ free_safe_mem(pass);
+ if (h_pass)
+ free_safe_mem(h_pass);
+ if (pass_again)
+ free_safe_mem(pass_again);
+ if (ehdr)
+ free_safe_mem(ehdr);
+ if (hehdr)
+ free_safe_mem(hehdr);
+ if (ehdr_backup)
+ free_safe_mem(ehdr_backup);
+ if (hehdr_backup)
+ free_safe_mem(hehdr_backup);
+
+ return ret;
}
static
char *h_pass;
int error, error2 = 0;
size_t sz;
+ size_t blocks, blksz;
+
+ if ((error = get_disk_info(dev, &blocks, &blksz)) != 0) {
+ tc_log(1, "could not get disk information\n");
+ return NULL;
+ }
- info = NULL;
if (retries < 1)
retries = 1;
+ info = NULL;
+
+ ehdr = NULL;
+ pass = h_pass = NULL;
+
while ((info == NULL) && retries-- > 0)
{
- h_pass = NULL;
- ehdr = NULL;
- hehdr = NULL;
+ pass = h_pass = NULL;
+ ehdr = hehdr = NULL;
+ info = hinfo = NULL;
if ((pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) {
tc_log(1, "could not allocate safe passphrase memory\n");
- return NULL;
+ goto out;
}
if (interactive) {
if ((error = read_passphrase("Passphrase: ", pass,
MAX_PASSSZ, timeout))) {
tc_log(1, "could not read passphrase\n");
- return NULL;
+ /* XXX: handle timeout differently? */
+ goto out;
}
} else {
/* In batch mode, use provided passphrase */
if (nkeyfiles > 0) {
/* Apply keyfiles to 'pass' */
- if ((error = apply_keyfiles(pass, MAX_PASSSZ, keyfiles,
- nkeyfiles))) {
+ if ((error = apply_keyfiles((unsigned char *)pass, MAX_PASSSZ,
+ keyfiles, nkeyfiles))) {
tc_log(1, "could not apply keyfiles");
- return NULL;
+ goto out;
}
}
if (protect_hidden) {
if ((h_pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) {
tc_log(1, "could not allocate safe passphrase memory\n");
- return NULL;
+ goto out;
}
if (interactive) {
"Passphrase for hidden volume: ", h_pass,
MAX_PASSSZ, timeout))) {
tc_log(1, "could not read passphrase\n");
- return NULL;
+ goto out;
}
} else {
/* In batch mode, use provided passphrase */
if (n_hkeyfiles > 0) {
/* Apply keyfiles to 'pass' */
- if ((error = apply_keyfiles(h_pass, MAX_PASSSZ, h_keyfiles,
- n_hkeyfiles))) {
+ if ((error = apply_keyfiles((unsigned char *)h_pass, MAX_PASSSZ,
+ h_keyfiles, n_hkeyfiles))) {
tc_log(1, "could not apply keyfiles");
- return NULL;
+ goto out;
}
}
}
- sz = HDRSZ;
+ /* Always read blksz-sized chunks */
+ sz = blksz;
+
ehdr = (struct tchdr_enc *)read_to_safe_mem((sflag) ? sys_dev : dev,
(sflag) ? HDR_OFFSET_SYS : 0, &sz);
if (ehdr == NULL) {
tc_log(1, "error read hdr_enc: %s", dev);
- return NULL;
+ goto out;
}
if (!sflag) {
- sz = HDRSZ;
+ /* Always read blksz-sized chunks */
+ sz = blksz;
+
hehdr = (struct tchdr_enc *)read_to_safe_mem(dev,
HDR_OFFSET_HIDDEN, &sz);
if (hehdr == NULL) {
tc_log(1, "error read hdr_enc: %s", dev);
- return NULL;
+ goto out;
}
} else {
hehdr = NULL;
}
- error = process_hdr(dev, pass, (nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
+ error = process_hdr(dev, (unsigned char *)pass,
+ (nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
ehdr, &info);
/*
*/
if (hehdr && (error || protect_hidden)) {
if (error) {
- error2 = process_hdr(dev, pass,
+ error2 = process_hdr(dev, (unsigned char *)pass,
(nkeyfiles > 0)?MAX_PASSSZ:strlen(pass), hehdr,
&info);
} else if (protect_hidden) {
- error2 = process_hdr(dev, h_pass,
+ error2 = process_hdr(dev, (unsigned char *)h_pass,
(n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), hehdr,
&hinfo);
}
if ((protect_hidden && (error || error2)) ||
(error && error2)) {
tc_log(1, "Incorrect password or not a TrueCrypt volume\n");
- info = NULL;
- hinfo = NULL;
+
+ if (info) {
+ if (info->hdr)
+ free_safe_mem(info->hdr);
+ free_safe_mem(info);
+ info = NULL;
+ }
+ if (hinfo) {
+ if (hinfo->hdr)
+ free_safe_mem(hinfo->hdr);
+ free_safe_mem(hinfo);
+ hinfo = NULL;
+ }
/* Try again (or finish) */
free_safe_mem(pass);
- if (h_pass)
+ pass = NULL;
+
+ if (h_pass) {
free_safe_mem(h_pass);
- if (ehdr)
+ h_pass = NULL;
+ }
+ if (ehdr) {
free_safe_mem(ehdr);
- if (hehdr)
+ ehdr = NULL;
+ }
+ if (hehdr) {
free_safe_mem(hehdr);
+ hehdr = NULL;
+ }
continue;
}
if (protect_hidden) {
if (adjust_info(info, hinfo) != 0) {
tc_log(1, "Could not protect hidden volume\n");
- return NULL;
+ if (info) {
+ if (info->hdr)
+ free_safe_mem(info->hdr);
+ free_safe_mem(info);
+ }
+ info = NULL;
+
+ if (hinfo->hdr)
+ free_safe_mem(hinfo->hdr);
+ free_safe_mem(hinfo);
+ hinfo = NULL;
+ goto out;
}
+
+ if (hinfo->hdr)
+ free_safe_mem(hinfo->hdr);
+ free_safe_mem(hinfo);
+ hinfo = NULL;
}
}
+out:
+ if (hinfo)
+ free_safe_mem(hinfo);
+ if (pass)
+ free_safe_mem(pass);
+ if (h_pass)
+ free_safe_mem(h_pass);
+ if (ehdr)
+ free_safe_mem(ehdr);
+ if (hehdr)
+ free_safe_mem(hehdr);
+
return info;
}
if (info != NULL) {
if (interactive)
print_info(info);
+ if (info->hdr)
+ free_safe_mem(info->hdr);
+ free_safe_mem(info);
+
+ return 0;
+ /* NOT REACHED */
}
- return (info != NULL) ? 0 : -1;
+ return -1;
}
int
if ((error = dm_setup(map_name, info)) != 0) {
tc_log(1, "Could not set up mapping %s\n", map_name);
+ if (info->hdr)
+ free_safe_mem(info->hdr);
+ free_safe_mem(info);
return -1;
}
if (interactive)
- printf("All ok!");
+ printf("All ok!\n");
+
+ free_safe_mem(info);
return 0;
}
char *uu;
char *uu_stack[64];
int uu_stack_idx;
+#if defined(__DragonFly__)
uint32_t status;
- int ret = 0;
+#endif
+ int r, ret = 0;
int j;
off_t start, offset;
char dev[PATH_MAX];
char map[PATH_MAX];
+ uint32_t cookie;
+
+ dm_udev_set_sync_support(1);
if ((params = alloc_safe_mem(512)) == NULL) {
tc_log(1, "could not allocate safe parameters memory");
for (j= 0; cipher_chain != NULL;
cipher_chain = cipher_chain->prev, j++) {
+
+ cookie = 0;
+
/* aes-cbc-essiv:sha256 7997f8af... 0 /dev/ad0s0a 8 */
/* iv off---^ block off--^ */
snprintf(params, 512, "%s %s %"PRIu64 " %s %"PRIu64,
cipher_chain->cipher->dm_crypt_str, cipher_chain->dm_key,
- info->skip, dev, offset);
+ (uint64_t)info->skip, dev, (uint64_t)offset);
#ifdef DEBUG
printf("Params: %s\n", params);
#endif
goto out;
}
+#if defined(__linux__)
+ uuid_generate(info->uuid);
+ if ((uu = malloc(1024)) == NULL) {
+ tc_log(1, "uuid_unparse memory failed\n");
+ ret = -1;
+ goto out;
+ }
+ uuid_unparse(info->uuid, uu);
+#elif defined(__DragonFly__)
uuid_create(&info->uuid, &status);
if (status != uuid_s_ok) {
tc_log(1, "uuid_create failed\n");
ret = -1;
goto out;
}
+#endif
if ((dm_task_set_uuid(dmt, uu)) == 0) {
free(uu);
goto out;
}
+ if ((dm_task_set_cookie(dmt, &cookie, 0)) == 0) {
+ tc_log(1, "dm_task_set_cookie failed\n");
+ ret = -1;
+ goto out;
+ }
+
if ((dm_task_run(dmt)) == 0) {
+ dm_udev_wait(cookie);
tc_log(1, "dm_task_task_run failed\n");
ret = -1;
goto out;
}
if ((dm_task_get_info(dmt, &dmi)) == 0) {
+ dm_udev_wait(cookie);
tc_log(1, "dm_task_get info failed\n");
- /* XXX: probably do more than just erroring out... */
ret = -1;
goto out;
}
+ dm_udev_wait(cookie);
+
asprintf(&uu_stack[uu_stack_idx++], "%s", map);
offset = 0;
sprintf(dev, "/dev/mapper/%s.%d", mapname, j);
dm_task_destroy(dmt);
+ dm_task_update_nodes();
}
out:
printf("Unrolling dm changes! j = %d (%s)\n", j-1,
uu_stack[j-1]);
#endif
- if ((ret = dm_remove_device(uu_stack[--j])) != 0) {
+ if ((r = dm_remove_device(uu_stack[--j])) != 0) {
tc_log(1, "Tried to unroll dm changes, "
"giving up.\n");
break;
/* Version of tcplay */
#define MAJ_VER 0
-#define MIN_VER 8
+#define MIN_VER 9
#define MAX_BLKSZ 4096
#define MAX_KFILE_SZ 1048576 /* 1 MB */
#define MAX_KEYFILES 256
#define HDR_OFFSET_HIDDEN 65536
+#define BACKUP_HDR_HIDDEN_OFFSET_END 65536
+#define BACKUP_HDR_OFFSET_END 131072
#define SALT_LEN 64
-#define MIN_VOL_BLOCKS 256
+#define VOL_RSVD_BYTES_START (256*512) /* Reserved bytes at vol. start */
+#define VOL_RSVD_BYTES_END (256*512) /* Reserved bytes at vol. end */
+#define MIN_VOL_BYTES (VOL_RSVD_BYTES_START + VOL_RSVD_BYTES_END)
+
#define MAX_CIPHER_CHAINS 64
#define DEFAULT_RETRIES 3
#define ERASE_BUFFER_SIZE 4*1024*1024 /* 4 MB */
#define DEBUG 1
#endif
+#include <inttypes.h>
+
+#if defined(__DragonFly__)
#include <uuid.h>
+#elif defined(__linux__)
+#include <uuid/uuid.h>
+#endif
struct pbkdf_prf_algo {
const char *name;
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 write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem,
+ size_t bytes);
int read_passphrase(const char *prompt, char *pass, size_t passlen,
time_t timeout);
int tc_crypto_init(void);
int tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain,
unsigned char *key);
+int tc_cipher_chain_free_keys(struct tc_cipher_chain *cipher_chain);
int tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
unsigned char *iv,
unsigned char *in, int in_len, unsigned char *out);
int tc_decrypt(struct tc_cipher_chain *cipher_chain, 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);
+
+/* The following two are platform dependent */
+int syscrypt(struct tc_crypto_algo *cipher, unsigned char *key, size_t klen,
+ unsigned char *iv, unsigned char *in, unsigned char *out, size_t len,
+ int do_encrypt);
+int pbkdf2(struct pbkdf_prf_algo *hash, const char *pass, int passlen,
+ const unsigned char *salt, int saltlen,
+ 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_cipher_chain *cipher_chain,
size_t sec_sz, size_t total_blocks,
- off_t offset, size_t blocks, int hidden);
+ off_t offset, size_t blocks, int hidden,
+ struct tchdr_enc **backup_hdr);
struct tchdr_dec *decrypt_hdr(struct tchdr_enc *ehdr,
struct tc_cipher_chain *cipher_chain, unsigned char *key);
int verify_hdr(struct tchdr_dec *hdr);
int nkeyfiles, const char *h_keyfiles[], int n_hkeyfiles,
struct pbkdf_prf_algo *prf_algo, struct tc_cipher_chain *cipher_chain,
struct pbkdf_prf_algo *h_prf_algo, struct tc_cipher_chain *h_cipher_chain,
- char *passphrase, char *h_passphrase, size_t hidden_blocks_in,
+ char *passphrase, char *h_passphrase, size_t hidden_bytes_in,
int interactive);
int info_volume(const char *device, int sflag, const char *sys_dev,
int protect_hidden, const char *keyfiles[], int nkeyfiles,
#define free_safe_mem(x) \
_free_safe_mem(x, __FILE__, __LINE__)
+
+#define __unused __attribute__((__unused__))
create_hidden = 0;
- if (api_opts->tc_size_hidden_in_blocks > 0) {
+ if (api_opts->tc_size_hidden_in_bytes > 0) {
create_hidden = 1;
for (n_hkeyfiles = 0; (n_hkeyfiles < MAX_KEYFILES) &&
(api_opts->tc_keyfiles_hidden != NULL) &&
check_prf_algo(api_opts->tc_prf_hash_hidden, 1),
check_cipher_chain(api_opts->tc_cipher_hidden, 1),
api_opts->tc_passphrase, api_opts->tc_passphrase_hidden,
- api_opts->tc_size_hidden_in_blocks, 0 /* non-interactive */);
+ api_opts->tc_size_hidden_in_bytes, 0 /* non-interactive */);
return (err) ? TC_ERR : TC_OK;
}
char *tc_prf_hash;
char *tc_cipher_hidden;
char *tc_prf_hash_hidden;
- size_t tc_size_hidden_in_blocks;
+ size_t tc_size_hidden_in_bytes;
char *tc_passphrase_hidden;
const char **tc_keyfiles_hidden;
} tc_api_opts;
api_opts.tc_passphrase = "apitest2";
api_opts.tc_keyfiles = NULL;
api_opts.tc_keyfiles_hidden = NULL;
- api_opts.tc_size_hidden_in_blocks = 12000;
+ api_opts.tc_size_hidden_in_bytes = 12000*512;
api_opts.tc_passphrase_hidden = "apihidden";
api_opts.tc_cipher = "AES-256-XTS,TWOFISH-256-XTS,SERPENT-256-XTS";
api_opts.tc_cipher_hidden = "SERPENT-256-XTS,TWOFISH-256-XTS";
SRCS= main.c
SRCS+= tcplay.c crc32.c safe_mem.c io.c crypto-dev.c hdr.c
+SRCS+= crypto.c generic_xts.c humanize.c pbkdf2-openssl.c
LDADD= -lcrypto -ldm -lprop -lutil
DPADD= ${LIBCRYPTO} ${LIBDM} ${LIBPROP} ${LIBUTIL}
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
+
#include <sys/types.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
-#include <err.h>
#include <time.h>
-#include <libutil.h>
#include "tcplay.h"
+#ifndef SIGINFO
+#define SIGINFO SIGUSR1
+#endif
+
static
void
sig_handler(int sig)