TCRYPT: properly wipe all buffers; use prefix for all functions.
authorMilan Broz <gmazyland@gmail.com>
Mon, 10 Dec 2012 15:36:22 +0000 (16:36 +0100)
committerMilan Broz <gmazyland@gmail.com>
Mon, 10 Dec 2012 15:36:22 +0000 (16:36 +0100)
lib/setup.c
lib/tcrypt/tcrypt.c

index fd65e8f..5e01f99 100644 (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);
        }
 }
index 0e7872a..b1ebd05 100644 (file)
@@ -163,9 +163,9 @@ static struct tcrypt_algs tcrypt_cipher[] = {
 {}
 };
 
 {}
 };
 
-static int hdr_from_disk(struct tcrypt_phdr *hdr,
-                        struct crypt_params_tcrypt *params,
-                        int kdf_index, int cipher_index)
+static int TCRYPT_hdr_from_disk(struct tcrypt_phdr *hdr,
+                               struct crypt_params_tcrypt *params,
+                               int kdf_index, int cipher_index)
 {
        uint32_t crc32;
        size_t size;
 {
        uint32_t crc32;
        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 *r = (uint32_t*)&buf[4];
 {
        uint32_t *l = (uint32_t*)&buf[0];
        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,
                                   const char *key, char *buf)
 {
 static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg,
                                   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;
 
        assert(bs == 2*sizeof(uint32_t));
        int i, j, r;
 
        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);
        for (i = 0; i < TCRYPT_HDR_LEN; i += bs) {
                memcpy(iv_old, &buf[i], bs);
        memcpy(iv, &key[alg->iv_offset], alg->iv_size);
        for (i = 0; i < TCRYPT_HDR_LEN; 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],
                                          bs, NULL, 0);
                r = crypt_cipher_decrypt(cipher, &buf[i], &buf[i],
                                          bs, NULL, 0);
-               blowfish_le(&buf[i]);
+               TCRYPT_swab_le(&buf[i]);
                if (r < 0)
                        break;
                for (j = 0; j < bs; j++)
                if (r < 0)
                        break;
                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,
-                    char *out_key, const char *key)
+static void TCRYPT_copy_key(struct tcrypt_alg *alg, const char *mode,
+                            char *out_key, const char *key)
 {
        int ks2;
        if (!strncmp(mode, "xts", 3)) {
 {
        int ks2;
        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,
-                          const char *key,struct tcrypt_phdr *hdr)
+static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode,
+                                  const char *key,struct tcrypt_phdr *hdr)
 {
        char backend_key[TCRYPT_HDR_KEY_LEN];
        char iv[TCRYPT_HDR_IV_LEN] = {};
 {
        char backend_key[TCRYPT_HDR_KEY_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))
                iv[alg->iv_size - 1] = 1;
        else if (!strncmp(mode, "cbc", 3)) {
        if (!strncmp(mode, "lrw", 3))
                iv[alg->iv_size - 1] = 1;
        else if (!strncmp(mode, "cbc", 3)) {
-               remove_whitening(buf, &key[8]);
+               TCRYPT_remove_whitening(buf, &key[8]);
                if (!strcmp(alg->name, "blowfish_le"))
                        return decrypt_blowfish_le_cbc(alg, key, buf);
                memcpy(iv, &key[alg->iv_offset], alg->iv_size);
        }
 
                if (!strcmp(alg->name, "blowfish_le"))
                        return decrypt_blowfish_le_cbc(alg, key, buf);
                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,
                              backend_key, alg->key_size);
        r = crypt_cipher_init(&cipher, alg->name, mode_name,
                              backend_key, alg->key_size);
-       memset(backend_key, 0, sizeof(backend_key));
-       if (r < 0)
-               return r;
-
-       r = crypt_cipher_decrypt(cipher, buf, buf, TCRYPT_HDR_LEN, iv, alg->iv_size);
-       crypt_cipher_destroy(cipher);
+       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(iv, 0, TCRYPT_HDR_IV_LEN);
        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.
  * Backend doesn't provide this, so implement it here directly using ECB.
  */
  * For chanined ciphers and CBC mode we need "outer" decryption.
  * Backend doesn't provide this, so implement it here directly using ECB.
  */
-static int decrypt_hdr_cbci(struct tcrypt_algs *ciphers,
-                            const char *key, struct tcrypt_phdr *hdr)
+static int TCRYPT_decrypt_cbci(struct tcrypt_algs *ciphers,
+                               const char *key, struct tcrypt_phdr *hdr)
 {
        struct crypt_cipher *cipher[ciphers->chain_count];
        unsigned int bs = ciphers->cipher[0].iv_size;
 {
        struct crypt_cipher *cipher[ciphers->chain_count];
        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;
        int r = -EINVAL;
 
        unsigned int i, j;
        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])
                        crypt_cipher_destroy(cipher[j]);
 
                if (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,
-                       const char *key, int legacy_modes)
+static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
+                              const char *key, int legacy_modes)
 {
        struct tcrypt_phdr hdr2;
        int i, j, r = -EINVAL;
 {
        struct tcrypt_phdr hdr2;
        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);
 
                if (!strncmp(tcrypt_cipher[i].mode, "cbci", 4))
                memcpy(&hdr2.e, &hdr->e, TCRYPT_HDR_LEN);
 
                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--) {
                        if (!tcrypt_cipher[i].cipher[j].name)
                                continue;
                else for (j = tcrypt_cipher[i].chain_count - 1; j >= 0 ; j--) {
                        if (!tcrypt_cipher[i].cipher[j].name)
                                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);
                        if (r < 0)
                                break;
                                            tcrypt_cipher[i].mode, key, &hdr2);
                        if (r < 0)
                                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)) {
                        log_dbg("TCRYPT: Signature magic detected.");
                        memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN);
                if (!strncmp(hdr2.d.magic, TCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) {
                        log_dbg("TCRYPT: Signature magic detected.");
                        memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN);
-                       memset(&hdr2.e, 0, TCRYPT_HDR_LEN);
                        r = i;
                        break;
                }
                r = -EPERM;
        }
 
                        r = i;
                        break;
                }
                r = -EPERM;
        }
 
+       memset(&hdr2, 0, sizeof(hdr2));
        return r;
 }
 
        return r;
 }
 
-static int pool_keyfile(struct crypt_device *cd,
-                       unsigned char pool[TCRYPT_KEY_POOL_LEN],
-                       const char *keyfile)
+static int TCRYPT_pool_keyfile(struct crypt_device *cd,
+                               unsigned char pool[TCRYPT_KEY_POOL_LEN],
+                               const char *keyfile)
 {
        unsigned char data[TCRYPT_KEYFILE_LEN];
        int i, j, fd, data_size;
 {
        unsigned char data[TCRYPT_KEYFILE_LEN];
        int i, j, fd, data_size;
@@ -481,7 +486,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
 
        /* Calculate pool content from keyfiles */
        for (i = 0; i < params->keyfiles_count; i++) {
 
        /* Calculate pool content from keyfiles */
        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)
                        goto out;
        }
                if (r < 0)
                        goto out;
        }
@@ -506,7 +511,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
                        break;
 
                /* Decrypt header */
                        break;
 
                /* Decrypt header */
-               r = decrypt_hdr(cd, hdr, key, legacy_modes);
+               r = TCRYPT_decrypt_hdr(cd, hdr, key, legacy_modes);
                if (r == -ENOENT) {
                        skipped++;
                        continue;
                if (r == -ENOENT) {
                        skipped++;
                        continue;
@@ -521,7 +526,7 @@ static int TCRYPT_init_hdr(struct crypt_device *cd,
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
-       r = hdr_from_disk(hdr, params, i, r);
+       r = TCRYPT_hdr_from_disk(hdr, params, i, r);
        if (!r) {
                log_dbg("TCRYPT: Header version: %d, req. %d, sector %d"
                        ", mk_offset %" PRIu64 ", hidden_size %" PRIu64
        if (!r) {
                log_dbg("TCRYPT: Header version: %d, req. %d, sector %d"
                        ", 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);
 
        close(devfd);
                r = TCRYPT_init_hdr(cd, hdr, params);
 
        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;
 
        for (i = 0; tcrypt_cipher[i].chain_count; i++)
                return NULL;
 
        for (i = 0; tcrypt_cipher[i].chain_count; i++)
-               if (!strcmp(tcrypt_cipher[i].long_name, params->cipher) &&
-                   !strcmp(tcrypt_cipher[i].mode, params->mode))
+               if (!strcmp(tcrypt_cipher[i].long_name, cipher) &&
+                   !strcmp(tcrypt_cipher[i].mode, mode))
                    return &tcrypt_cipher[i];
 
        return NULL;
                    return &tcrypt_cipher[i];
 
        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)
                return -EINVAL;
 
        if (!algs)
                return -EINVAL;
 
@@ -672,7 +679,8 @@ int TCRYPT_activate(struct crypt_device *cd,
                snprintf(cipher, sizeof(cipher), "%s-%s",
                         algs->cipher[i-1].name, algs->mode);
 
                snprintf(cipher, sizeof(cipher), "%s-%s",
                         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) {
                        snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d",
 
                if (algs->chain_count != i) {
                        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)
 {
        struct crypt_dm_active_device dmd = {};
                      const char *base_uuid, int index)
 {
        struct crypt_dm_active_device dmd = {};
@@ -741,11 +749,11 @@ int TCRYPT_deactivate(struct crypt_device *cd, const char *name)
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
-       r = remove_one(cd, name, dmd.uuid, 1);
+       r = TCRYPT_remove_one(cd, name, dmd.uuid, 1);
        if (r < 0)
                goto out;
 
        if (r < 0)
                goto out;
 
-       r = remove_one(cd, name, dmd.uuid, 2);
+       r = TCRYPT_remove_one(cd, name, dmd.uuid, 2);
        if (r < 0)
                goto out;
 out:
        if (r < 0)
                goto 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,
-                     const char *base_uuid, int index,
-                     size_t *key_size, char *cipher, uint64_t *data_offset,
-                     struct device **device)
+static int TCRYPT_status_one(struct crypt_device *cd, const char *name,
+                             const char *base_uuid, int index,
+                             size_t *key_size, char *cipher,
+                             uint64_t *data_offset, struct device **device)
 {
        struct crypt_dm_active_device dmd = {};
        char dm_name[PATH_MAX], *c;
 {
        struct crypt_dm_active_device dmd = {};
        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 tcrypt_phdr *tcrypt_hdr)
 {
                        struct crypt_params_tcrypt *tcrypt_params,
                        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_hdr, 0, sizeof(*tcrypt_hdr));
 
        memset(tcrypt_params, 0, sizeof(*tcrypt_params));
        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;
 
        strncpy(cipher, dmd->u.crypt.cipher, MAX_CIPHER_LEN);
        tcrypt_hdr->d.mk_offset = dmd->u.crypt.offset * SECTOR_SIZE;
 
        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, '-'))) {
-               *mode = '\0';
-               tcrypt_params->mode = strdup(++mode);
-       }
-       tcrypt_params->key_size = dmd->u.crypt.vk->keylength;
+       key_size = dmd->u.crypt.vk->keylength;
+       r = TCRYPT_status_one(cd, name, dmd->uuid, 1, &key_size,
+                             cipher, &tcrypt_hdr->d.mk_offset, device);
+       if (!r)
+               r = TCRYPT_status_one(cd, name, dmd->uuid, 2, &key_size,
+                                     cipher, &tcrypt_hdr->d.mk_offset, device);
+
+       if (r < 0 && r != -ENODEV)
+               return r;
 
 
-       if (!status_one(cd, name, dmd->uuid, 1, &tcrypt_params->key_size,
-                       cipher, &tcrypt_hdr->d.mk_offset, device))
-               status_one(cd, name, dmd->uuid, 2, &tcrypt_params->key_size,
-                          cipher, &tcrypt_hdr->d.mk_offset, device);
+       algs = TCRYPT_get_algs(cipher, mode);
+       if (!algs || key_size != algs->chain_key_size)
+               return -EINVAL;
 
 
-       tcrypt_params->cipher = strdup(cipher);
+       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)
                return -EINVAL;
 
        if (!algs)
                return -EINVAL;
 
@@ -896,8 +917,8 @@ int TCRYPT_get_volume_key(struct crypt_device *cd,
                return -ENOMEM;
 
        for (i = 0, key_index = 0; i < algs->chain_count; i++) {
                return -ENOMEM;
 
        for (i = 0, key_index = 0; i < algs->chain_count; i++) {
-               copy_key(&algs->cipher[i], algs->mode,
-                        &(*vk)->key[key_index], hdr->d.keys);
+               TCRYPT_copy_key(&algs->cipher[i], algs->mode,
+                               &(*vk)->key[key_index], hdr->d.keys);
                key_index += algs->cipher[i].key_size;
        }
 
                key_index += algs->cipher[i].key_size;
        }