static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg, const char *key, char *buf) { 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)); r = crypt_cipher_init(&cipher, "blowfish", "ecb", &key[alg->key_offset], alg->key_size); if (r < 0) return r; memcpy(iv, &key[alg->iv_offset], alg->iv_size); for (i = 0; i < TCRYPT_HDR_LEN; i += bs) { memcpy(iv_old, &buf[i], bs); TCRYPT_swab_le(&buf[i]); r = crypt_cipher_decrypt(cipher, &buf[i], &buf[i], bs, NULL, 0); TCRYPT_swab_le(&buf[i]); if (r < 0) break; for (j = 0; j < bs; j++) buf[i + j] ^= iv[j]; memcpy(iv, iv_old, bs); } crypt_cipher_destroy(cipher); crypt_memzero(iv, bs); crypt_memzero(iv_old, bs); return r; }
/* * For chanined ciphers and CBC mode we need "outer" decryption. * Backend doesn't provide this, so implement it here directly using ECB. */ 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; char *buf = (char*)&hdr->e, iv[bs], iv_old[bs]; unsigned int i, j; int r = -EINVAL; TCRYPT_remove_whitening(buf, &key[8]); memcpy(iv, &key[ciphers->cipher[0].iv_offset], bs); /* Initialize all ciphers in chain in ECB mode */ for (j = 0; j < ciphers->chain_count; j++) cipher[j] = NULL; for (j = 0; j < ciphers->chain_count; j++) { r = crypt_cipher_init(&cipher[j], ciphers->cipher[j].name, "ecb", &key[ciphers->cipher[j].key_offset], ciphers->cipher[j].key_size); if (r < 0) goto out; } /* Implements CBC with chained ciphers in loop inside */ for (i = 0; i < TCRYPT_HDR_LEN; i += bs) { memcpy(iv_old, &buf[i], bs); for (j = ciphers->chain_count; j > 0; j--) { r = crypt_cipher_decrypt(cipher[j - 1], &buf[i], &buf[i], bs, NULL, 0); if (r < 0) goto out; } for (j = 0; j < bs; j++) buf[i + j] ^= iv[j]; memcpy(iv, iv_old, bs); } out: for (j = 0; j < ciphers->chain_count; j++) if (cipher[j]) crypt_cipher_destroy(cipher[j]); crypt_memzero(iv, bs); crypt_memzero(iv_old, bs); return r; }
static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr, const char *key, uint32_t flags) { struct tcrypt_phdr hdr2; int i, j, r = -EINVAL; for (i = 0; tcrypt_cipher[i].chain_count; i++) { if (!(flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_cipher[i].legacy) continue; log_dbg("TCRYPT: trying cipher %s-%s", tcrypt_cipher[i].long_name, tcrypt_cipher[i].mode); memcpy(&hdr2.e, &hdr->e, TCRYPT_HDR_LEN); if (!strncmp(tcrypt_cipher[i].mode, "cbci", 4)) 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; r = TCRYPT_decrypt_hdr_one(&tcrypt_cipher[i].cipher[j], tcrypt_cipher[i].mode, key, &hdr2); if (r < 0) break; } if (r < 0) { log_dbg("TCRYPT: returned error %d, skipped.", r); if (r == -ENOTSUP) break; r = -ENOENT; continue; } 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); r = i; break; } if ((flags & CRYPT_TCRYPT_VERA_MODES) && !strncmp(hdr2.d.magic, VCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) { log_dbg("TCRYPT: Signature magic detected (Veracrypt)."); memcpy(&hdr->e, &hdr2.e, TCRYPT_HDR_LEN); r = i; break; } r = -EPERM; } crypt_memzero(&hdr2, sizeof(hdr2)); return r; }
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 mode_name[MAX_CIPHER_LEN]; struct crypt_cipher *cipher; char *c, *buf = (char*)&hdr->e; int r; /* Remove IV if present */ strncpy(mode_name, mode, MAX_CIPHER_LEN); c = strchr(mode_name, '-'); if (c) *c = '\0'; if (!strncmp(mode, "lrw", 3)) iv[alg->iv_size - 1] = 1; else if (!strncmp(mode, "cbc", 3)) { 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); } TCRYPT_copy_key(alg, mode, backend_key, key); r = crypt_cipher_init(&cipher, alg->name, mode_name, 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); } crypt_memzero(backend_key, sizeof(backend_key)); crypt_memzero(iv, TCRYPT_HDR_IV_LEN); return r; }
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; uint32_t crc; log_dbg("TCRYPT: using keyfile %s.", keyfile); fd = open(keyfile, O_RDONLY); if (fd < 0) { log_err(cd, _("Failed to open key file.\n")); return -EIO; } /* FIXME: add while */ data_size = read(fd, data, TCRYPT_KEYFILE_LEN); close(fd); if (data_size < 0) { log_err(cd, _("Error reading keyfile %s.\n"), keyfile); return -EIO; } for (i = 0, j = 0, crc = ~0U; i < data_size; i++) { crc = crypt_crc32(crc, &data[i], 1); pool[j++] += (unsigned char)(crc >> 24); pool[j++] += (unsigned char)(crc >> 16); pool[j++] += (unsigned char)(crc >> 8); pool[j++] += (unsigned char)(crc); j %= TCRYPT_KEY_POOL_LEN; } crypt_memzero(&crc, sizeof(crc)); crypt_memzero(data, TCRYPT_KEYFILE_LEN); return 0; }
/* * A simple call to lseek(3) might not be possible for some inputs (e.g. * reading from a pipe), so this function instead reads of up to BUFSIZ bytes * at a time until the specified number of bytes. It returns -1 on read error * or when it reaches EOF before the requested number of bytes have been * discarded. */ static int keyfile_seek(int fd, uint64_t bytes) { char tmp[BUFSIZ]; size_t next_read; ssize_t bytes_r; off64_t r; r = lseek64(fd, bytes, SEEK_CUR); if (r > 0) return 0; if (r < 0 && errno != ESPIPE) return -1; while (bytes > 0) { /* figure out how much to read */ next_read = bytes > sizeof(tmp) ? sizeof(tmp) : (size_t)bytes; bytes_r = read(fd, tmp, next_read); if (bytes_r < 0) { if (errno == EINTR) continue; crypt_memzero(tmp, sizeof(tmp)); /* read error */ return -1; } if (bytes_r == 0) /* EOF */ break; bytes -= bytes_r; } crypt_memzero(tmp, sizeof(tmp)); return bytes == 0 ? 0 : -1; }
/* Check that kernel supports requested cipher by decryption of one sector */ static int LUKS_check_cipher(struct luks_phdr *hdr, struct crypt_device *ctx) { int r; struct volume_key *empty_key; char buf[SECTOR_SIZE]; log_dbg("Checking if cipher %s-%s is usable.", hdr->cipherName, hdr->cipherMode); empty_key = crypt_alloc_volume_key(hdr->keyBytes, NULL); if (!empty_key) return -ENOMEM; r = LUKS_decrypt_from_storage(buf, sizeof(buf), hdr->cipherName, hdr->cipherMode, empty_key, 0, ctx); crypt_free_volume_key(empty_key); crypt_memzero(buf, sizeof(buf)); return r; }
/* Check that kernel supports requested cipher by decryption of one sector */ int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *cipher, const char *cipher_mode) { int r; struct volume_key *empty_key; char buf[SECTOR_SIZE]; log_dbg("Checking if cipher %s-%s is usable.", cipher, cipher_mode); empty_key = crypt_alloc_volume_key(keylength, NULL); if (!empty_key) return -ENOMEM; /* No need to get KEY quality random but it must avoid known weak keys. */ r = crypt_random_get(ctx, empty_key->key, empty_key->keylength, CRYPT_RND_NORMAL); if (!r) r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx); crypt_free_volume_key(empty_key); crypt_memzero(buf, sizeof(buf)); return r; }
/* This routine should do some just basic recovery for known problems. */ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx) { struct luks_phdr temp_phdr; const unsigned char *sector = (const unsigned char*)phdr; struct volume_key *vk; uint64_t PBKDF2_per_sec = 1; int i, bad, r, need_write = 0; if (phdr->keyBytes != 16 && phdr->keyBytes != 32 && phdr->keyBytes != 64) { log_err(ctx, _("Non standard key size, manual repair required.\n")); return -EINVAL; } /* cryptsetup 1.0 did not align to 4k, cannot repair this one */ if (phdr->keyblock[0].keyMaterialOffset < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) { log_err(ctx, _("Non standard keyslots alignment, manual repair required.\n")); return -EINVAL; } vk = crypt_alloc_volume_key(phdr->keyBytes, NULL); log_verbose(ctx, _("Repairing keyslots.\n")); log_dbg("Generating second header with the same parameters for check."); /* cipherName, cipherMode, hashSpec, uuid are already null terminated */ /* payloadOffset - cannot check */ r = LUKS_generate_phdr(&temp_phdr, vk, phdr->cipherName, phdr->cipherMode, phdr->hashSpec,phdr->uuid, LUKS_STRIPES, phdr->payloadOffset, 0, 1, &PBKDF2_per_sec, 1, ctx); if (r < 0) { log_err(ctx, _("Repair failed.")); goto out; } for(i = 0; i < LUKS_NUMKEYS; ++i) { if (phdr->keyblock[i].active == LUKS_KEY_ENABLED) { log_dbg("Skipping repair for active keyslot %i.", i); continue; } bad = 0; if (phdr->keyblock[i].keyMaterialOffset != temp_phdr.keyblock[i].keyMaterialOffset) { log_err(ctx, _("Keyslot %i: offset repaired (%u -> %u).\n"), i, (unsigned)phdr->keyblock[i].keyMaterialOffset, (unsigned)temp_phdr.keyblock[i].keyMaterialOffset); phdr->keyblock[i].keyMaterialOffset = temp_phdr.keyblock[i].keyMaterialOffset; bad = 1; } if (phdr->keyblock[i].stripes != temp_phdr.keyblock[i].stripes) { log_err(ctx, _("Keyslot %i: stripes repaired (%u -> %u).\n"), i, (unsigned)phdr->keyblock[i].stripes, (unsigned)temp_phdr.keyblock[i].stripes); phdr->keyblock[i].stripes = temp_phdr.keyblock[i].stripes; bad = 1; } /* Known case - MSDOS partition table signature */ if (i == 6 && sector[0x1fe] == 0x55 && sector[0x1ff] == 0xaa) { log_err(ctx, _("Keyslot %i: bogus partition signature.\n"), i); bad = 1; } if(bad) { log_err(ctx, _("Keyslot %i: salt wiped.\n"), i); phdr->keyblock[i].active = LUKS_KEY_DISABLED; memset(&phdr->keyblock[i].passwordSalt, 0x00, LUKS_SALTSIZE); phdr->keyblock[i].passwordIterations = 0; } if (bad) need_write = 1; } if (need_write) { log_verbose(ctx, _("Writing LUKS header to disk.\n")); r = LUKS_write_phdr(phdr, ctx); } out: crypt_free_volume_key(vk); crypt_memzero(&temp_phdr, sizeof(temp_phdr)); return r; }
int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx) { struct device *device = crypt_metadata_device(ctx); struct luks_phdr hdr; int r = 0, devfd = -1; ssize_t hdr_size; ssize_t buffer_size; char *buffer = NULL; r = LUKS_read_phdr(&hdr, 1, 0, ctx); if (r) return r; hdr_size = LUKS_device_sectors(hdr.keyBytes) << SECTOR_SHIFT; buffer_size = size_round_up(hdr_size, crypt_getpagesize()); buffer = crypt_safe_alloc(buffer_size); if (!buffer || hdr_size < LUKS_ALIGN_KEYSLOTS || hdr_size > buffer_size) { r = -ENOMEM; goto out; } log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes).", sizeof(hdr), hdr_size - LUKS_ALIGN_KEYSLOTS); log_dbg("Output backup file size: %zu bytes.", buffer_size); devfd = device_open(device, O_RDONLY); if(devfd == -1) { log_err(ctx, _("Device %s is not a valid LUKS device.\n"), device_path(device)); r = -EINVAL; goto out; } if (read_blockwise(devfd, device_block_size(device), buffer, hdr_size) < hdr_size) { r = -EIO; goto out; } close(devfd); /* Wipe unused area, so backup cannot contain old signatures */ if (hdr.keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS) memset(buffer + sizeof(hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(hdr)); devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR); if (devfd == -1) { if (errno == EEXIST) log_err(ctx, _("Requested header backup file %s already exists.\n"), backup_file); else log_err(ctx, _("Cannot create header backup file %s.\n"), backup_file); r = -EINVAL; goto out; } if (write(devfd, buffer, buffer_size) < buffer_size) { log_err(ctx, _("Cannot write header backup file %s.\n"), backup_file); r = -EIO; goto out; } close(devfd); r = 0; out: if (devfd != -1) close(devfd); crypt_memzero(&hdr, sizeof(hdr)); crypt_safe_free(buffer); return r; }
static int TCRYPT_init_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr, struct crypt_params_tcrypt *params) { unsigned char pwd[TCRYPT_KEY_POOL_LEN] = {}; size_t passphrase_size; char *key; unsigned int i, skipped = 0; int r = -EPERM; if (posix_memalign((void*)&key, crypt_getpagesize(), TCRYPT_HDR_KEY_LEN)) return -ENOMEM; if (params->keyfiles_count) passphrase_size = TCRYPT_KEY_POOL_LEN; else passphrase_size = params->passphrase_size; if (params->passphrase_size > TCRYPT_KEY_POOL_LEN) { log_err(cd, _("Maximum TCRYPT passphrase length (%d) exceeded.\n"), TCRYPT_KEY_POOL_LEN); goto out; } /* Calculate pool content from keyfiles */ for (i = 0; i < params->keyfiles_count; i++) { r = TCRYPT_pool_keyfile(cd, pwd, params->keyfiles[i]); if (r < 0) goto out; } /* If provided password, combine it with pool */ for (i = 0; i < params->passphrase_size; i++) pwd[i] += params->passphrase[i]; for (i = 0; tcrypt_kdf[i].name; i++) { if (!(params->flags & CRYPT_TCRYPT_LEGACY_MODES) && tcrypt_kdf[i].legacy) continue; if (!(params->flags & CRYPT_TCRYPT_VERA_MODES) && tcrypt_kdf[i].veracrypt) continue; /* Derive header key */ log_dbg("TCRYPT: trying KDF: %s-%s-%d.", tcrypt_kdf[i].name, tcrypt_kdf[i].hash, tcrypt_kdf[i].iterations); r = crypt_pbkdf(tcrypt_kdf[i].name, tcrypt_kdf[i].hash, (char*)pwd, passphrase_size, hdr->salt, TCRYPT_HDR_SALT_LEN, key, TCRYPT_HDR_KEY_LEN, tcrypt_kdf[i].iterations); if (r < 0 && crypt_hash_size(tcrypt_kdf[i].hash) < 0) { log_verbose(cd, _("PBKDF2 hash algorithm %s not available, skipping.\n"), tcrypt_kdf[i].hash); continue; } if (r < 0) break; /* Decrypt header */ r = TCRYPT_decrypt_hdr(cd, hdr, key, params->flags); if (r == -ENOENT) { skipped++; r = -EPERM; } if (r != -EPERM) break; } if ((r < 0 && r != -EPERM && skipped && skipped == i) || r == -ENOTSUP) { log_err(cd, _("Required kernel crypto interface not available.\n")); #ifdef ENABLE_AF_ALG log_err(cd, _("Ensure you have algif_skcipher kernel module loaded.\n")); #endif } if (r < 0) goto out; r = TCRYPT_hdr_from_disk(hdr, params, i, r); if (!r) { log_dbg("TCRYPT: Magic: %s, Header version: %d, req. %d, sector %d" ", mk_offset %" PRIu64 ", hidden_size %" PRIu64 ", volume size %" PRIu64, tcrypt_kdf[i].veracrypt ? VCRYPT_HDR_MAGIC : TCRYPT_HDR_MAGIC, (int)hdr->d.version, (int)hdr->d.version_tc, (int)hdr->d.sector_size, hdr->d.mk_offset, hdr->d.hidden_volume_size, hdr->d.volume_size); log_dbg("TCRYPT: Header cipher %s-%s, key size %zu", params->cipher, params->mode, params->key_size); } out: crypt_memzero(pwd, TCRYPT_KEY_POOL_LEN); if (key) crypt_memzero(key, TCRYPT_HDR_KEY_LEN); free(key); return r; }