TCRYPT: properly wipe all buffers; use prefix for all functions.

This commit is contained in:
Milan Broz
2012-12-10 16:36:22 +01:00
parent e8d09733d4
commit 549ab64358
2 changed files with 85 additions and 62 deletions

View File

@@ -1424,6 +1424,8 @@ void crypt_free(struct crypt_device *cd)
} }
free(cd->type); free(cd->type);
/* Some structures can contain keys (TCRYPT), wipe it */
memset(cd, 0, sizeof(*cd));
free(cd); free(cd);
} }
} }

View File

@@ -163,9 +163,9 @@ static struct tcrypt_algs tcrypt_cipher[] = {
{} {}
}; };
static int hdr_from_disk(struct tcrypt_phdr *hdr, static int TCRYPT_hdr_from_disk(struct tcrypt_phdr *hdr,
struct crypt_params_tcrypt *params, struct crypt_params_tcrypt *params,
int kdf_index, int cipher_index) int kdf_index, int cipher_index)
{ {
uint32_t crc32; uint32_t crc32;
size_t size; size_t size;
@@ -223,7 +223,7 @@ static int hdr_from_disk(struct tcrypt_phdr *hdr,
/* /*
* Kernel implements just big-endian version of blowfish, hack it here * Kernel implements just big-endian version of blowfish, hack it here
*/ */
static void blowfish_le(char *buf) static void TCRYPT_swab_le(char *buf)
{ {
uint32_t *l = (uint32_t*)&buf[0]; uint32_t *l = (uint32_t*)&buf[0];
uint32_t *r = (uint32_t*)&buf[4]; uint32_t *r = (uint32_t*)&buf[4];
@@ -234,9 +234,9 @@ static void blowfish_le(char *buf)
static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg, static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg,
const char *key, char *buf) const char *key, char *buf)
{ {
char iv[alg->iv_size], iv_old[alg->iv_size];
struct crypt_cipher *cipher = NULL;
int bs = alg->iv_size; int bs = alg->iv_size;
char iv[bs], iv_old[bs];
struct crypt_cipher *cipher = NULL;
int i, j, r; int i, j, r;
assert(bs == 2*sizeof(uint32_t)); assert(bs == 2*sizeof(uint32_t));
@@ -249,10 +249,10 @@ static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg,
memcpy(iv, &key[alg->iv_offset], alg->iv_size); memcpy(iv, &key[alg->iv_offset], alg->iv_size);
for (i = 0; i < TCRYPT_HDR_LEN; i += bs) { for (i = 0; i < TCRYPT_HDR_LEN; i += bs) {
memcpy(iv_old, &buf[i], bs); memcpy(iv_old, &buf[i], bs);
blowfish_le(&buf[i]); TCRYPT_swab_le(&buf[i]);
r = crypt_cipher_decrypt(cipher, &buf[i], &buf[i], r = crypt_cipher_decrypt(cipher, &buf[i], &buf[i],
bs, NULL, 0); bs, NULL, 0);
blowfish_le(&buf[i]); TCRYPT_swab_le(&buf[i]);
if (r < 0) if (r < 0)
break; break;
for (j = 0; j < bs; j++) for (j = 0; j < bs; j++)
@@ -261,10 +261,12 @@ static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg,
} }
crypt_cipher_destroy(cipher); crypt_cipher_destroy(cipher);
memset(iv, 0, bs);
memset(iv_old, 0, bs);
return r; return r;
} }
static void remove_whitening(char *buf, const char *key) static void TCRYPT_remove_whitening(char *buf, const char *key)
{ {
int j; int j;
@@ -272,8 +274,8 @@ static void remove_whitening(char *buf, const char *key)
buf[j] ^= key[j % 8]; buf[j] ^= key[j % 8];
} }
static void copy_key(struct tcrypt_alg *alg, const char *mode, static void TCRYPT_copy_key(struct tcrypt_alg *alg, const char *mode,
char *out_key, const char *key) char *out_key, const char *key)
{ {
int ks2; int ks2;
if (!strncmp(mode, "xts", 3)) { if (!strncmp(mode, "xts", 3)) {
@@ -289,8 +291,8 @@ static void copy_key(struct tcrypt_alg *alg, const char *mode,
} }
} }
static int decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode, static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode,
const char *key,struct tcrypt_phdr *hdr) const char *key,struct tcrypt_phdr *hdr)
{ {
char backend_key[TCRYPT_HDR_KEY_LEN]; char backend_key[TCRYPT_HDR_KEY_LEN];
char iv[TCRYPT_HDR_IV_LEN] = {}; char iv[TCRYPT_HDR_IV_LEN] = {};
@@ -308,22 +310,23 @@ static int decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode,
if (!strncmp(mode, "lrw", 3)) if (!strncmp(mode, "lrw", 3))
iv[alg->iv_size - 1] = 1; iv[alg->iv_size - 1] = 1;
else if (!strncmp(mode, "cbc", 3)) { else if (!strncmp(mode, "cbc", 3)) {
remove_whitening(buf, &key[8]); TCRYPT_remove_whitening(buf, &key[8]);
if (!strcmp(alg->name, "blowfish_le")) if (!strcmp(alg->name, "blowfish_le"))
return decrypt_blowfish_le_cbc(alg, key, buf); return decrypt_blowfish_le_cbc(alg, key, buf);
memcpy(iv, &key[alg->iv_offset], alg->iv_size); memcpy(iv, &key[alg->iv_offset], alg->iv_size);
} }
copy_key(alg, mode, backend_key, key); TCRYPT_copy_key(alg, mode, backend_key, key);
r = crypt_cipher_init(&cipher, alg->name, mode_name, r = crypt_cipher_init(&cipher, alg->name, mode_name,
backend_key, alg->key_size); backend_key, alg->key_size);
if (!r) {
r = crypt_cipher_decrypt(cipher, buf, buf, TCRYPT_HDR_LEN,
iv, alg->iv_size);
crypt_cipher_destroy(cipher);
}
memset(backend_key, 0, sizeof(backend_key)); memset(backend_key, 0, sizeof(backend_key));
if (r < 0) memset(iv, 0, TCRYPT_HDR_IV_LEN);
return r;
r = crypt_cipher_decrypt(cipher, buf, buf, TCRYPT_HDR_LEN, iv, alg->iv_size);
crypt_cipher_destroy(cipher);
return r; return r;
} }
@@ -331,8 +334,8 @@ static int decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode,
* For chanined ciphers and CBC mode we need "outer" decryption. * For chanined ciphers and CBC mode we need "outer" decryption.
* Backend doesn't provide this, so implement it here directly using ECB. * Backend doesn't provide this, so implement it here directly using ECB.
*/ */
static int decrypt_hdr_cbci(struct tcrypt_algs *ciphers, static int TCRYPT_decrypt_cbci(struct tcrypt_algs *ciphers,
const char *key, struct tcrypt_phdr *hdr) const char *key, struct tcrypt_phdr *hdr)
{ {
struct crypt_cipher *cipher[ciphers->chain_count]; struct crypt_cipher *cipher[ciphers->chain_count];
unsigned int bs = ciphers->cipher[0].iv_size; unsigned int bs = ciphers->cipher[0].iv_size;
@@ -340,7 +343,7 @@ static int decrypt_hdr_cbci(struct tcrypt_algs *ciphers,
unsigned int i, j; unsigned int i, j;
int r = -EINVAL; int r = -EINVAL;
remove_whitening(buf, &key[8]); TCRYPT_remove_whitening(buf, &key[8]);
memcpy(iv, &key[ciphers->cipher[0].iv_offset], bs); memcpy(iv, &key[ciphers->cipher[0].iv_offset], bs);
@@ -373,11 +376,13 @@ out:
if (cipher[j]) if (cipher[j])
crypt_cipher_destroy(cipher[j]); crypt_cipher_destroy(cipher[j]);
memset(iv, 0, bs);
memset(iv_old, 0, bs);
return r; return r;
} }
static int decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr, static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
const char *key, int legacy_modes) const char *key, int legacy_modes)
{ {
struct tcrypt_phdr hdr2; struct tcrypt_phdr hdr2;
int i, j, r = -EINVAL; int i, j, r = -EINVAL;
@@ -391,11 +396,11 @@ static int decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
memcpy(&hdr2.e, &hdr->e, TCRYPT_HDR_LEN); memcpy(&hdr2.e, &hdr->e, TCRYPT_HDR_LEN);
if (!strncmp(tcrypt_cipher[i].mode, "cbci", 4)) if (!strncmp(tcrypt_cipher[i].mode, "cbci", 4))
r = decrypt_hdr_cbci(&tcrypt_cipher[i], key, &hdr2); r = TCRYPT_decrypt_cbci(&tcrypt_cipher[i], key, &hdr2);
else for (j = tcrypt_cipher[i].chain_count - 1; j >= 0 ; j--) { else for (j = tcrypt_cipher[i].chain_count - 1; j >= 0 ; j--) {
if (!tcrypt_cipher[i].cipher[j].name) if (!tcrypt_cipher[i].cipher[j].name)
continue; continue;
r = decrypt_hdr_one(&tcrypt_cipher[i].cipher[j], r = TCRYPT_decrypt_hdr_one(&tcrypt_cipher[i].cipher[j],
tcrypt_cipher[i].mode, key, &hdr2); tcrypt_cipher[i].mode, key, &hdr2);
if (r < 0) if (r < 0)
break; break;
@@ -412,19 +417,19 @@ static int decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
if (!strncmp(hdr2.d.magic, TCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) { if (!strncmp(hdr2.d.magic, TCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) {
log_dbg("TCRYPT: Signature magic detected."); log_dbg("TCRYPT: Signature magic detected.");
memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN); memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN);
memset(&hdr2.e, 0, TCRYPT_HDR_LEN);
r = i; r = i;
break; break;
} }
r = -EPERM; r = -EPERM;
} }
memset(&hdr2, 0, sizeof(hdr2));
return r; return r;
} }
static int pool_keyfile(struct crypt_device *cd, static int TCRYPT_pool_keyfile(struct crypt_device *cd,
unsigned char pool[TCRYPT_KEY_POOL_LEN], unsigned char pool[TCRYPT_KEY_POOL_LEN],
const char *keyfile) const char *keyfile)
{ {
unsigned char data[TCRYPT_KEYFILE_LEN]; unsigned char data[TCRYPT_KEYFILE_LEN];
int i, j, fd, data_size; int i, j, fd, data_size;
@@ -481,7 +486,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
/* Calculate pool content from keyfiles */ /* Calculate pool content from keyfiles */
for (i = 0; i < params->keyfiles_count; i++) { for (i = 0; i < params->keyfiles_count; i++) {
r = pool_keyfile(cd, pwd, params->keyfiles[i]); r = TCRYPT_pool_keyfile(cd, pwd, params->keyfiles[i]);
if (r < 0) if (r < 0)
goto out; goto out;
} }
@@ -506,7 +511,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
break; break;
/* Decrypt header */ /* Decrypt header */
r = decrypt_hdr(cd, hdr, key, legacy_modes); r = TCRYPT_decrypt_hdr(cd, hdr, key, legacy_modes);
if (r == -ENOENT) { if (r == -ENOENT) {
skipped++; skipped++;
continue; continue;
@@ -521,7 +526,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
if (r < 0) if (r < 0)
goto out; goto out;
r = hdr_from_disk(hdr, params, i, r); r = TCRYPT_hdr_from_disk(hdr, params, i, r);
if (!r) { if (!r) {
log_dbg("TCRYPT: Header version: %d, req. %d, sector %d" log_dbg("TCRYPT: Header version: %d, req. %d, sector %d"
", mk_offset %" PRIu64 ", hidden_size %" PRIu64 ", mk_offset %" PRIu64 ", hidden_size %" PRIu64
@@ -585,19 +590,21 @@ int TCRYPT_read_phdr(struct crypt_device *cd,
r = TCRYPT_init_hdr(cd, hdr, params); r = TCRYPT_init_hdr(cd, hdr, params);
close(devfd); close(devfd);
if (r < 0)
memset(hdr, 0, sizeof (*hdr));
return r; return r;
} }
static struct tcrypt_algs *get_algs(struct crypt_params_tcrypt *params) static struct tcrypt_algs *TCRYPT_get_algs(const char *cipher, const char *mode)
{ {
int i; int i;
if (!params->cipher || !params->mode) if (!cipher || !mode)
return NULL; return NULL;
for (i = 0; tcrypt_cipher[i].chain_count; i++) for (i = 0; tcrypt_cipher[i].chain_count; i++)
if (!strcmp(tcrypt_cipher[i].long_name, params->cipher) && if (!strcmp(tcrypt_cipher[i].long_name, cipher) &&
!strcmp(tcrypt_cipher[i].mode, params->mode)) !strcmp(tcrypt_cipher[i].mode, mode))
return &tcrypt_cipher[i]; return &tcrypt_cipher[i];
return NULL; return NULL;
@@ -641,7 +648,7 @@ int TCRYPT_activate(struct crypt_device *cd,
return -ENOTSUP; return -ENOTSUP;
} }
algs = get_algs(params); algs = TCRYPT_get_algs(params->cipher, params->mode);
if (!algs) if (!algs)
return -EINVAL; return -EINVAL;
@@ -672,7 +679,8 @@ int TCRYPT_activate(struct crypt_device *cd,
snprintf(cipher, sizeof(cipher), "%s-%s", snprintf(cipher, sizeof(cipher), "%s-%s",
algs->cipher[i-1].name, algs->mode); algs->cipher[i-1].name, algs->mode);
copy_key(&algs->cipher[i-1], algs->mode, dmd.u.crypt.vk->key, hdr->d.keys); TCRYPT_copy_key(&algs->cipher[i-1], algs->mode,
dmd.u.crypt.vk->key, hdr->d.keys);
if (algs->chain_count != i) { if (algs->chain_count != i) {
snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d", snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d",
@@ -704,7 +712,7 @@ int TCRYPT_activate(struct crypt_device *cd,
return r; return r;
} }
static int remove_one(struct crypt_device *cd, const char *name, static int TCRYPT_remove_one(struct crypt_device *cd, const char *name,
const char *base_uuid, int index) const char *base_uuid, int index)
{ {
struct crypt_dm_active_device dmd = {}; struct crypt_dm_active_device dmd = {};
@@ -741,11 +749,11 @@ int TCRYPT_deactivate(struct crypt_device *cd, const char *name)
if (r < 0) if (r < 0)
goto out; goto out;
r = remove_one(cd, name, dmd.uuid, 1); r = TCRYPT_remove_one(cd, name, dmd.uuid, 1);
if (r < 0) if (r < 0)
goto out; goto out;
r = remove_one(cd, name, dmd.uuid, 2); r = TCRYPT_remove_one(cd, name, dmd.uuid, 2);
if (r < 0) if (r < 0)
goto out; goto out;
out: out:
@@ -753,10 +761,10 @@ out:
return (r == -ENODEV) ? 0 : r; return (r == -ENODEV) ? 0 : r;
} }
static int status_one(struct crypt_device *cd, const char *name, static int TCRYPT_status_one(struct crypt_device *cd, const char *name,
const char *base_uuid, int index, const char *base_uuid, int index,
size_t *key_size, char *cipher, uint64_t *data_offset, size_t *key_size, char *cipher,
struct device **device) uint64_t *data_offset, struct device **device)
{ {
struct crypt_dm_active_device dmd = {}; struct crypt_dm_active_device dmd = {};
char dm_name[PATH_MAX], *c; char dm_name[PATH_MAX], *c;
@@ -801,7 +809,10 @@ int TCRYPT_init_by_name(struct crypt_device *cd, const char *name,
struct crypt_params_tcrypt *tcrypt_params, struct crypt_params_tcrypt *tcrypt_params,
struct tcrypt_phdr *tcrypt_hdr) struct tcrypt_phdr *tcrypt_hdr)
{ {
char cipher[MAX_CIPHER_LEN * 4], *mode; struct tcrypt_algs *algs;
char cipher[MAX_CIPHER_LEN * 4], mode[MAX_CIPHER_LEN], *tmp;
size_t key_size;
int r;
memset(tcrypt_params, 0, sizeof(*tcrypt_params)); memset(tcrypt_params, 0, sizeof(*tcrypt_params));
memset(tcrypt_hdr, 0, sizeof(*tcrypt_hdr)); memset(tcrypt_hdr, 0, sizeof(*tcrypt_hdr));
@@ -809,19 +820,29 @@ int TCRYPT_init_by_name(struct crypt_device *cd, const char *name,
tcrypt_hdr->d.mk_offset = dmd->u.crypt.offset * SECTOR_SIZE; tcrypt_hdr->d.mk_offset = dmd->u.crypt.offset * SECTOR_SIZE;
strncpy(cipher, dmd->u.crypt.cipher, MAX_CIPHER_LEN); strncpy(cipher, dmd->u.crypt.cipher, MAX_CIPHER_LEN);
tmp = strchr(cipher, '-');
if (!tmp)
return -EINVAL;
*tmp = '\0';
strncpy(mode, ++tmp, MAX_CIPHER_LEN);
if ((mode = strchr(cipher, '-'))) { key_size = dmd->u.crypt.vk->keylength;
*mode = '\0'; r = TCRYPT_status_one(cd, name, dmd->uuid, 1, &key_size,
tcrypt_params->mode = strdup(++mode); cipher, &tcrypt_hdr->d.mk_offset, device);
} if (!r)
tcrypt_params->key_size = dmd->u.crypt.vk->keylength; r = TCRYPT_status_one(cd, name, dmd->uuid, 2, &key_size,
cipher, &tcrypt_hdr->d.mk_offset, device);
if (!status_one(cd, name, dmd->uuid, 1, &tcrypt_params->key_size, if (r < 0 && r != -ENODEV)
cipher, &tcrypt_hdr->d.mk_offset, device)) return r;
status_one(cd, name, dmd->uuid, 2, &tcrypt_params->key_size,
cipher, &tcrypt_hdr->d.mk_offset, device);
tcrypt_params->cipher = strdup(cipher); algs = TCRYPT_get_algs(cipher, mode);
if (!algs || key_size != algs->chain_key_size)
return -EINVAL;
tcrypt_params->key_size = algs->chain_key_size;
tcrypt_params->cipher = algs->long_name;
tcrypt_params->mode = algs->mode;
return 0; return 0;
} }
@@ -887,7 +908,7 @@ int TCRYPT_get_volume_key(struct crypt_device *cd,
return -ENOTSUP; return -ENOTSUP;
} }
algs = get_algs(params); algs = TCRYPT_get_algs(params->cipher, params->mode);
if (!algs) if (!algs)
return -EINVAL; return -EINVAL;
@@ -896,8 +917,8 @@ int TCRYPT_get_volume_key(struct crypt_device *cd,
return -ENOMEM; return -ENOMEM;
for (i = 0, key_index = 0; i < algs->chain_count; i++) { for (i = 0, key_index = 0; i < algs->chain_count; i++) {
copy_key(&algs->cipher[i], algs->mode, TCRYPT_copy_key(&algs->cipher[i], algs->mode,
&(*vk)->key[key_index], hdr->d.keys); &(*vk)->key[key_index], hdr->d.keys);
key_index += algs->cipher[i].key_size; key_index += algs->cipher[i].key_size;
} }