Browse files

half-baked cascaded cipher support

  • Loading branch information...
1 parent 098bb11 commit 6ee09f358b7774eee6f3751a4df92b08903252e1 @bwalex committed Jul 2, 2011
Showing with 320 additions and 41 deletions.
  1. +130 −12 crypto-dev.c
  2. +4 −4 hdr.c
  3. +170 −19 tc-play.c
  4. +16 −6 tc-play.h
View
142 crypto-dev.c
@@ -159,36 +159,154 @@ tc_crypto_init(void)
return 0;
}
+static
int
-tc_encrypt(struct tc_crypto_algo *cipher, unsigned char *key,
+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) {
+ fprintf(stderr, "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;
- cipher_id = get_cryptodev_cipher_id(cipher);
- if (cipher_id < 0) {
- fprintf(stderr, "Cipher %s not found\n", cipher->name);
- return ENOENT;
+ 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) {
+ fprintf(stderr, "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 syscrypt(cipher_id, key, cipher->klen, iv, in, out, in_len, 1);
+ return 0;
}
int
-tc_decrypt(struct tc_crypto_algo *cipher, unsigned char *key,
+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;
- cipher_id = get_cryptodev_cipher_id(cipher);
- if (cipher_id < 0) {
- fprintf(stderr, "Cipher %s not found\n", cipher->name);
- return ENOENT;
+ 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.
+ */
+ 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) {
+ fprintf(stderr, "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 syscrypt(cipher_id, key, cipher->klen, iv, in, out, in_len, 0);
+ return 0;
}
int
View
8 hdr.c
@@ -43,7 +43,7 @@
#define HOST_TO_LE(n, v) v = htole ## n (v)
struct tchdr_dec *
-decrypt_hdr(struct tchdr_enc *ehdr, struct tc_crypto_algo *cipher,
+decrypt_hdr(struct tchdr_enc *ehdr, struct tc_cipher_chain *cipher_chain,
unsigned char *key)
{
struct tchdr_dec *dhdr;
@@ -57,7 +57,7 @@ decrypt_hdr(struct tchdr_enc *ehdr, struct tc_crypto_algo *cipher,
memset(iv, 0, sizeof(iv));
- error = tc_decrypt(cipher, key, iv, ehdr->enc,
+ error = tc_decrypt(cipher_chain, key, iv, ehdr->enc,
sizeof(struct tchdr_dec), (unsigned char *)dhdr);
if (error) {
fprintf(stderr, "Header decryption failed\n");
@@ -119,7 +119,7 @@ verify_hdr(struct tchdr_dec *hdr)
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,
+ struct tc_cipher_chain *cipher_chain, size_t sec_sz, size_t total_blocks,
off_t offset, size_t blocks, int hidden)
{
struct tchdr_enc *ehdr;
@@ -190,7 +190,7 @@ create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo,
HOST_TO_BE(32, dhdr->crc_dhdr);
memset(iv, 0, sizeof(iv));
- error = tc_encrypt(cipher, key, iv, (unsigned char *)dhdr,
+ error = tc_encrypt(cipher_chain, key, iv, (unsigned char *)dhdr,
sizeof(struct tchdr_dec), ehdr->enc);
if (error) {
fprintf(stderr, "Header encryption failed\n");
View
189 tc-play.c
@@ -51,7 +51,10 @@
/* Version of tc-play */
#define MAJ_VER 0
-#define MIN_VER 5
+#define MIN_VER 7
+
+static struct tc_crypto_algo *check_cipher(char *cipher);
+
/* Supported algorithms */
struct pbkdf_prf_algo pbkdf_prf_algos[] = {
@@ -75,6 +78,80 @@ struct tc_crypto_algo tc_crypto_algos[] = {
{ NULL, NULL, 0, 0 }
};
+char *valid_cipher_chains[][MAX_CIPHER_CHAINS] = {
+ { "AES-256-XTS", NULL },
+ { "TWOFISH-256-XTS", NULL },
+ { "SERPENT-256-XTS", NULL },
+ { "AES-256-XTS", "TWOFISH-256-XTS", NULL },
+ { "AES-256-XTS", "TWOFISH-256-XTS", "SERPENT-256-XTS", NULL },
+ { "SERPENT-256-XTS", "AES-256-XTS", NULL },
+ { "SERPENT-256-XTS", "TWOFISH-256-XTS", "AES-256-XTS", NULL },
+ { "TWOFISH-256-XTS", "SERPENT-256-XTS", NULL },
+ { NULL }
+};
+
+struct tc_cipher_chain *tc_cipher_chains[MAX_CIPHER_CHAINS];
+
+static
+void
+tc_build_cipher_chains(void)
+{
+ struct tc_cipher_chain *chain, *elem, *prev;
+ int i = 0;
+ int k;
+
+ while (valid_cipher_chains[i][0] != NULL) {
+ chain = NULL;
+ prev = NULL;
+ k = 0;
+
+ while (valid_cipher_chains[i][k] != NULL) {
+ if ((elem = alloc_safe_mem(sizeof(*elem))) == NULL) {
+ fprintf(stderr, "Error allocating memory for "
+ "cipher chain\n");
+ exit(1);
+ }
+
+ /* Initialize first element of chain */
+ if (chain == NULL) {
+ chain = elem;
+ elem->prev = NULL;
+ }
+
+ /* Populate previous element */
+ if (prev != NULL) {
+ prev->next = elem;
+ elem->prev = prev;
+ }
+
+ /* Assume we are the last element in the chain */
+ elem->next = NULL;
+
+ /* Initialize other fields */
+ elem->cipher = check_cipher(valid_cipher_chains[i][k]);
+ if (elem->cipher == NULL)
+ exit(1);
+
+ elem->key = NULL;
+
+ prev = elem;
+ ++k;
+ }
+
+ /* Store cipher chain */
+ tc_cipher_chains[i++] = chain;
+
+ /* Integrity check */
+ if (i >= MAX_CIPHER_CHAINS) {
+ fprintf(stderr, "FATAL: tc_cipher_chains is full!!\n");
+ exit(1);
+ }
+
+ /* Make sure array is NULL terminated */
+ tc_cipher_chains[i] = NULL;
+ }
+}
+
int
hex2key(char *hex, size_t key_len, unsigned char *key)
{
@@ -108,17 +185,29 @@ print_hex(unsigned char *buf, off_t start, size_t len)
void
print_info(struct tcplay_info *info)
{
+ struct tc_cipher_chain *cipher_chain;
+ int klen = 0;
+
printf("PBKDF2 PRF:\t\t%s\n", info->pbkdf_prf->name);
printf("PBKDF2 iterations:\t%d\n", info->pbkdf_prf->iteration_count);
- printf("Cipher:\t\t\t%s\n", info->cipher->name);
- printf("Key Length:\t\t%d bits\n", info->cipher->klen*8);
+
+ printf("Cipher:\t\t\t");
+ for (cipher_chain = info->cipher_chain;
+ cipher_chain != NULL;
+ cipher_chain = cipher_chain->next) {
+ printf("%s%c", cipher_chain->cipher->name,
+ (cipher_chain->next != NULL) ? ',' : '\n');
+ klen += cipher_chain->cipher->klen;
+ }
+
+ printf("Key Length:\t\t%d bits\n", klen*8);
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%d sectors\n", info->size);
}
struct tcplay_info *
-new_info(const char *dev, struct tc_crypto_algo *cipher,
+new_info(const char *dev, struct tc_cipher_chain *cipher_chain,
struct pbkdf_prf_algo *prf, struct tchdr_dec *hdr, off_t start)
{
struct tcplay_info *info;
@@ -130,17 +219,20 @@ new_info(const char *dev, struct tc_crypto_algo *cipher,
}
info->dev = dev;
- info->cipher = cipher;
+ info->cipher_chain = cipher_chain;
info->pbkdf_prf = prf;
info->start = start;
info->hdr = hdr;
info->size = hdr->sz_mk_scope / hdr->sec_sz; /* volume size */
info->skip = hdr->off_mk_scope / hdr->sec_sz; /* iv skip */
info->offset = hdr->off_mk_scope / hdr->sec_sz; /* block offset */
+#if 0
+ /* XXX: broken */
for (i = 0; i < cipher->klen; i++) {
sprintf(&info->key[i*2], "%02x", hdr->keys[i]);
}
+#endif
return info;
}
@@ -192,12 +284,12 @@ process_hdr(const char *dev, unsigned char *pass, int passlen,
print_hex(key, 0, MAX_KEYSZ);
#endif
- for (j = 0; !found && tc_crypto_algos[j].name != NULL; j++) {
+ for (j = 0; !found && tc_cipher_chains[j] != NULL; j++) {
#ifdef DEBUG
- printf("\nTrying cipher %s\n", tc_crypto_algos[j].name);
+ printf("\nTrying cipher chain %d\n", j);
#endif
- dhdr = decrypt_hdr(ehdr, &tc_crypto_algos[j], key);
+ dhdr = decrypt_hdr(ehdr, tc_cipher_chains[j], key);
if (dhdr == NULL) {
continue;
}
@@ -225,7 +317,7 @@ process_hdr(const char *dev, unsigned char *pass, int passlen,
if (!found)
return EINVAL;
- if ((info = new_info(dev, &tc_crypto_algos[j-1], &pbkdf_prf_algos[i-1],
+ if ((info = new_info(dev, tc_cipher_chains[j-1], &pbkdf_prf_algos[i-1],
dhdr, 0)) == NULL) {
return ENOMEM;
}
@@ -237,7 +329,7 @@ process_hdr(const char *dev, unsigned char *pass, int passlen,
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)
+ struct tc_cipher_chain *cipher_chain)
{
char *pass;
char *h_pass = NULL;
@@ -246,8 +338,8 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
struct tchdr_enc *ehdr, *hehdr;
int error, r;
- if (cipher == NULL)
- cipher = &tc_crypto_algos[0];
+ if (cipher_chain == NULL)
+ cipher_chain = tc_cipher_chains[0];
if (prf_algo == NULL)
prf_algo = &pbkdf_prf_algos[0];
@@ -367,7 +459,7 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
/* create encrypted headers */
ehdr = create_hdr(pass, (nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
- prf_algo, cipher, blksz, blocks, MIN_VOL_BLOCKS,
+ prf_algo, cipher_chain, blksz, blocks, MIN_VOL_BLOCKS,
blocks-MIN_VOL_BLOCKS, 0);
if (ehdr == NULL) {
fprintf(stderr, "Could not create header\n");
@@ -376,7 +468,8 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
if (hidden) {
hehdr = create_hdr(h_pass,
- (n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), prf_algo, cipher,
+ (n_hkeyfiles > 0)?MAX_PASSSZ:strlen(h_pass), prf_algo,
+ cipher_chain,
blksz, blocks, blocks - hidden_blocks, hidden_blocks, 1);
if (hehdr == NULL) {
fprintf(stderr, "Could not create hidden volume header\n");
@@ -419,7 +512,8 @@ dm_setup(const char *mapname, struct tcplay_info *info)
/* aes-cbc-essiv:sha256 7997f8af... 0 /dev/ad0s0a 8 */
/* iv off---^ block off--^ */
snprintf(params, 512, "%s %s %"PRIu64 " %s %"PRIu64,
- info->cipher->dm_crypt_str, info->key,
+ /* XXX: broken */
+ info->cipher_chain->cipher->dm_crypt_str, info->key,
info->skip, info->dev, info->offset);
#ifdef DEBUG
printf("Params: %s\n", params);
@@ -510,6 +604,62 @@ check_cipher(char *cipher)
}
static
+struct tc_cipher_chain *
+check_cipher_chain(char *cipher_chain)
+{
+ int i,k, found = 0, nciphers = 0, mismatch = 0;
+ char *ciphers[8];
+ char *token;
+
+ while ((token = strsep(&cipher_chain, ",")) != NULL)
+ ciphers[nciphers++] = token;
+
+ for (i = 0; valid_cipher_chains[i][0] != NULL; i++) {
+ mismatch = 0;
+
+ for (k = 0; (valid_cipher_chains[i][k] != NULL); k++) {
+ /*
+ * If there are more ciphers in the chain than in the
+ * ciphers[] variable this is not the right chain.
+ */
+ if (k == nciphers) {
+ mismatch = 1;
+ break;
+ }
+
+ if (strcmp(ciphers[k], valid_cipher_chains[i][k]) != 0)
+ mismatch = 1;
+ }
+
+ /*
+ * If all ciphers matched and there are exactly nciphers,
+ * then we found the right cipher chain.
+ */
+ if ((k == nciphers) && !mismatch) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ fprintf(stderr, "Valid cipher chains are:\n");
+ for (i = 0; valid_cipher_chains[i][0] != NULL; i++) {
+ for (k = 0; valid_cipher_chains[i][k] != NULL; k++) {
+ fprintf(stderr, "%s%c",
+ valid_cipher_chains[i][k],
+ (valid_cipher_chains[i][k+1] != NULL) ?
+ ',' : '\0');
+ }
+ fprintf(stderr, "\n");
+ }
+
+ return NULL;
+ }
+
+ return tc_cipher_chains[i];
+}
+
+static
struct pbkdf_prf_algo *
check_prf_algo(char *algo)
{
@@ -609,9 +759,10 @@ main(int argc, char *argv[])
int ch, error, error2, r = 0;
int sflag = 0, iflag = 0, mflag = 0, hflag = 0, cflag = 0, hidflag = 0;
struct pbkdf_prf_algo *prf = NULL;
- struct tc_crypto_algo *cipher = NULL;
+ struct tc_cipher_chain *cipher_chain = NULL;
size_t sz;
+ tc_build_cipher_chains();
tc_crypto_init();
atexit(check_and_purge_safe_mem);
@@ -632,9 +783,9 @@ main(int argc, char *argv[])
}
break;
case 'b':
- if (cipher != NULL)
+ if (cipher_chain != NULL)
usage();
- if ((cipher = check_cipher(optarg)) == NULL) {
+ if ((cipher_chain = check_cipher_chain(optarg)) == NULL) {
if (strcmp(optarg, "help") == 0)
exit(0);
else
@@ -700,7 +851,7 @@ main(int argc, char *argv[])
if (cflag) {
error = create_volume(dev, hidflag, keyfiles, nkeyfiles,
- h_keyfiles, n_hkeyfiles, prf, cipher);
+ h_keyfiles, n_hkeyfiles, prf, cipher_chain);
if (error) {
err(1, "could not create new volume on %s\n", dev);
}
View
22 tc-play.h
@@ -38,11 +38,13 @@
#define HDR_OFFSET_HIDDEN 65536
#define SALT_LEN 64
#define MIN_VOL_BLOCKS 256
+#define MAX_CIPHER_CHAINS 64
/* TrueCrypt Volume flags */
#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 {
@@ -57,6 +59,14 @@ struct tc_crypto_algo {
int ivlen;
};
+struct tc_cipher_chain {
+ struct tc_crypto_algo *cipher;
+ unsigned char *key;
+
+ struct tc_cipher_chain *prev;
+ struct tc_cipher_chain *next;
+};
+
struct tchdr_enc {
unsigned char salt[SALT_LEN]; /* Salt for PBKDF */
unsigned char enc[448]; /* Encrypted part of the header */
@@ -89,7 +99,7 @@ struct tchdr_dec {
struct tcplay_info {
const char *dev;
struct tchdr_dec *hdr;
- struct tc_crypto_algo *cipher;
+ struct tc_cipher_chain *cipher_chain;
struct pbkdf_prf_algo *pbkdf_prf;
char key[MAX_KEYSZ*2];
off_t start; /* Logical volume offset in table */
@@ -110,10 +120,10 @@ int write_mem(const char *dev, off_t offset, size_t blksz, void *mem, size_t byt
int read_passphrase(char *prompt, char *pass, size_t passlen);
int tc_crypto_init(void);
-int tc_encrypt(struct tc_crypto_algo *cipher, unsigned char *key,
+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_crypto_algo *cipher, unsigned char *key,
+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,
@@ -122,11 +132,11 @@ 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,
+ 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);
-struct tchdr_dec *decrypt_hdr(struct tchdr_enc *ehdr, struct tc_crypto_algo *cipher,
- unsigned char *key);
+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);
void *_alloc_safe_mem(size_t req_sz, const char *file, int line);

0 comments on commit 6ee09f3

Please sign in to comment.