// FIXME: move this to tools and handle EINTR static int _read_mk(const char *file, char **key, int keysize) { int fd; if (keysize <= 0 || keysize > MAX_KEY_SIZE) { log_err(_("Invalid key size.")); return -EINVAL; } *key = crypt_safe_alloc(keysize); if (!*key) return -ENOMEM; fd = open(file, O_RDONLY); if (fd == -1) { log_err(_("Cannot read keyfile %s."), file); goto fail; } if ((read(fd, *key, keysize) != keysize)) { log_err(_("Cannot read %d bytes from keyfile %s."), keysize, file); close(fd); goto fail; } close(fd); return 0; fail: crypt_safe_free(*key); *key = NULL; return -EINVAL; }
/* Try to open a particular key slot */ static int LUKS_open_key(unsigned int keyIndex, const char *password, size_t passwordLen, struct luks_phdr *hdr, struct volume_key *vk, struct crypt_device *ctx) { crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex); struct volume_key *derived_key; char *AfKey; size_t AFEKSize; int r; log_dbg("Trying to open key slot %d [%s].", keyIndex, dbg_slot_state(ki)); if (ki < CRYPT_SLOT_ACTIVE) return -ENOENT; derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL); if (!derived_key) return -ENOMEM; assert(vk->keylength == hdr->keyBytes); AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE; AfKey = crypt_safe_alloc(AFEKSize); if (!AfKey) { r = -ENOMEM; goto out; } r = crypt_pbkdf("pbkdf2", hdr->hashSpec, password, passwordLen, hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE, derived_key->key, hdr->keyBytes, hdr->keyblock[keyIndex].passwordIterations); if (r < 0) goto out; log_dbg("Reading key slot %d area.", keyIndex); r = LUKS_decrypt_from_storage(AfKey, AFEKSize, hdr->cipherName, hdr->cipherMode, derived_key, hdr->keyblock[keyIndex].keyMaterialOffset, ctx); if (r < 0) goto out; r = AF_merge(AfKey,vk->key,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec); if (r < 0) goto out; r = LUKS_verify_volume_key(hdr, vk); if (!r) log_verbose(ctx, _("Key slot %d unlocked.\n"), keyIndex); out: crypt_safe_free(AfKey); crypt_free_volume_key(derived_key); return r; }
static int _read_keys(char **integrity_key, struct crypt_params_integrity *params) { char *int_key = NULL, *journal_integrity_key = NULL, *journal_crypt_key = NULL; int r; if (integrity_key && opt_integrity_key_file) { r = _read_mk(opt_integrity_key_file, &int_key, opt_integrity_key_size); if (r < 0) return r; params->integrity_key_size = opt_integrity_key_size; } if (opt_journal_integrity_key_file) { r = _read_mk(opt_journal_integrity_key_file, &journal_integrity_key, opt_journal_integrity_key_size); if (r < 0) { crypt_safe_free(int_key); return r; } params->journal_integrity_key = journal_integrity_key; params->journal_integrity_key_size = opt_journal_integrity_key_size; } if (opt_journal_crypt_key_file) { r = _read_mk(opt_journal_crypt_key_file, &journal_crypt_key, opt_journal_crypt_key_size); if (r < 0) { crypt_safe_free(int_key); crypt_safe_free(journal_integrity_key); return r; } params->journal_crypt_key = journal_crypt_key; params->journal_crypt_key_size = opt_journal_crypt_key_size; } if (integrity_key) *integrity_key = int_key; return 0; }
int LUKS_set_key(unsigned int keyIndex, const char *password, size_t passwordLen, struct luks_phdr *hdr, struct volume_key *vk, uint32_t iteration_time_ms, uint64_t *PBKDF2_per_sec, struct crypt_device *ctx) { struct volume_key *derived_key; char *AfKey = NULL; size_t AFEKSize; uint64_t PBKDF2_temp; int r; if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) { log_err(ctx, _("Key slot %d active, purge first.\n"), keyIndex); return -EINVAL; } /* LUKS keyslot has always at least 4000 stripes accoding to specification */ if(hdr->keyblock[keyIndex].stripes < 4000) { log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?\n"), keyIndex); return -EINVAL; } log_dbg("Calculating data for key slot %d", keyIndex); r = crypt_benchmark_kdf(ctx, "pbkdf2", hdr->hashSpec, "foo", 3, "bar", 3, PBKDF2_per_sec); if (r < 0) { log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"), hdr->hashSpec); return r; } /* * Avoid floating point operation * Final iteration count is at least LUKS_SLOT_ITERATIONS_MIN */ PBKDF2_temp = (*PBKDF2_per_sec / 2) * (uint64_t)iteration_time_ms; PBKDF2_temp /= 1024; if (PBKDF2_temp > UINT32_MAX) PBKDF2_temp = UINT32_MAX; hdr->keyblock[keyIndex].passwordIterations = at_least((uint32_t)PBKDF2_temp, LUKS_SLOT_ITERATIONS_MIN); log_dbg("Key slot %d use %" PRIu32 " password iterations.", keyIndex, hdr->keyblock[keyIndex].passwordIterations); derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL); if (!derived_key) return -ENOMEM; r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE, CRYPT_RND_SALT); if (r < 0) goto out; r = crypt_pbkdf("pbkdf2", hdr->hashSpec, password, passwordLen, hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE, derived_key->key, hdr->keyBytes, hdr->keyblock[keyIndex].passwordIterations); if (r < 0) goto out; /* * AF splitting, the masterkey stored in vk->key is split to AfKey */ assert(vk->keylength == hdr->keyBytes); AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE; AfKey = crypt_safe_alloc(AFEKSize); if (!AfKey) { r = -ENOMEM; goto out; } log_dbg("Using hash %s for AF in key slot %d, %d stripes", hdr->hashSpec, keyIndex, hdr->keyblock[keyIndex].stripes); r = AF_split(vk->key,AfKey,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec); if (r < 0) goto out; log_dbg("Updating key slot %d [0x%04x] area.", keyIndex, hdr->keyblock[keyIndex].keyMaterialOffset << 9); /* Encryption via dm */ r = LUKS_encrypt_to_storage(AfKey, AFEKSize, hdr->cipherName, hdr->cipherMode, derived_key, hdr->keyblock[keyIndex].keyMaterialOffset, ctx); if (r < 0) goto out; /* Mark the key as active in phdr */ r = LUKS_keyslot_set(hdr, (int)keyIndex, 1); if (r < 0) goto out; r = LUKS_write_phdr(hdr, ctx); if (r < 0) goto out; r = 0; out: crypt_safe_free(AfKey); crypt_free_volume_key(derived_key); return r; }
int LUKS_hdr_restore( const char *backup_file, struct luks_phdr *hdr, struct crypt_device *ctx) { struct device *device = crypt_metadata_device(ctx); int r = 0, devfd = -1, diff_uuid = 0; ssize_t buffer_size = 0; char *buffer = NULL, msg[200]; struct luks_phdr hdr_file; r = LUKS_read_phdr_backup(backup_file, &hdr_file, 0, ctx); if (r == -ENOENT) return r; if (!r) buffer_size = LUKS_device_sectors(hdr_file.keyBytes) << SECTOR_SHIFT; if (r || buffer_size < LUKS_ALIGN_KEYSLOTS) { log_err(ctx, _("Backup file doesn't contain valid LUKS header.\n")); r = -EINVAL; goto out; } buffer = crypt_safe_alloc(buffer_size); if (!buffer) { r = -ENOMEM; goto out; } devfd = open(backup_file, O_RDONLY); if (devfd == -1) { log_err(ctx, _("Cannot open header backup file %s.\n"), backup_file); r = -EINVAL; goto out; } if (read(devfd, buffer, buffer_size) < buffer_size) { log_err(ctx, _("Cannot read header backup file %s.\n"), backup_file); r = -EIO; goto out; } close(devfd); r = LUKS_read_phdr(hdr, 0, 0, ctx); if (r == 0) { log_dbg("Device %s already contains LUKS header, checking UUID and offset.", device_path(device)); if(hdr->payloadOffset != hdr_file.payloadOffset || hdr->keyBytes != hdr_file.keyBytes) { log_err(ctx, _("Data offset or key size differs on device and backup, restore failed.\n")); r = -EINVAL; goto out; } if (memcmp(hdr->uuid, hdr_file.uuid, UUID_STRING_L)) diff_uuid = 1; } if (snprintf(msg, sizeof(msg), _("Device %s %s%s"), device_path(device), r ? _("does not contain LUKS header. Replacing header can destroy data on that device.") : _("already contains LUKS header. Replacing header will destroy existing keyslots."), diff_uuid ? _("\nWARNING: real device header has different UUID than backup!") : "") < 0) { r = -ENOMEM; goto out; } if (!crypt_confirm(ctx, msg)) { r = -EINVAL; goto out; } log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes) to device %s.", sizeof(*hdr), buffer_size - LUKS_ALIGN_KEYSLOTS, device_path(device)); devfd = device_open(device, O_RDWR); if (devfd == -1) { if (errno == EACCES) log_err(ctx, _("Cannot write to device %s, permission denied.\n"), device_path(device)); else log_err(ctx, _("Cannot open device %s.\n"), device_path(device)); r = -EINVAL; goto out; } if (write_blockwise(devfd, device_block_size(device), buffer, buffer_size) < buffer_size) { r = -EIO; goto out; } close(devfd); /* Be sure to reload new data */ r = LUKS_read_phdr(hdr, 1, 0, ctx); out: if (devfd != -1) close(devfd); crypt_safe_free(buffer); 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; }
int LUKS_set_key(unsigned int keyIndex, const char *password, size_t passwordLen, struct luks_phdr *hdr, struct volume_key *vk, struct crypt_device *ctx) { struct volume_key *derived_key; char *AfKey = NULL; size_t AFEKSize; struct crypt_pbkdf_type *pbkdf; int r; if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) { log_err(ctx, _("Key slot %d active, purge first."), keyIndex); return -EINVAL; } /* LUKS keyslot has always at least 4000 stripes according to specification */ if(hdr->keyblock[keyIndex].stripes < 4000) { log_err(ctx, _("Key slot %d material includes too few stripes. Header manipulation?"), keyIndex); return -EINVAL; } log_dbg("Calculating data for key slot %d", keyIndex); pbkdf = crypt_get_pbkdf(ctx); r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength); if (r < 0) return r; assert(pbkdf->iterations); /* * Final iteration count is at least LUKS_SLOT_ITERATIONS_MIN */ hdr->keyblock[keyIndex].passwordIterations = at_least(pbkdf->iterations, LUKS_SLOT_ITERATIONS_MIN); log_dbg("Key slot %d use %" PRIu32 " password iterations.", keyIndex, hdr->keyblock[keyIndex].passwordIterations); derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL); if (!derived_key) return -ENOMEM; r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE, CRYPT_RND_SALT); if (r < 0) goto out; r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen, hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE, derived_key->key, hdr->keyBytes, hdr->keyblock[keyIndex].passwordIterations, 0, 0); if (r < 0) goto out; /* * AF splitting, the masterkey stored in vk->key is split to AfKey */ assert(vk->keylength == hdr->keyBytes); AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE; AfKey = crypt_safe_alloc(AFEKSize); if (!AfKey) { r = -ENOMEM; goto out; } log_dbg("Using hash %s for AF in key slot %d, %d stripes", hdr->hashSpec, keyIndex, hdr->keyblock[keyIndex].stripes); r = AF_split(vk->key,AfKey,vk->keylength,hdr->keyblock[keyIndex].stripes,hdr->hashSpec); if (r < 0) goto out; log_dbg("Updating key slot %d [0x%04x] area.", keyIndex, hdr->keyblock[keyIndex].keyMaterialOffset << 9); /* Encryption via dm */ r = LUKS_encrypt_to_storage(AfKey, AFEKSize, hdr->cipherName, hdr->cipherMode, derived_key, hdr->keyblock[keyIndex].keyMaterialOffset, ctx); if (r < 0) goto out; /* Mark the key as active in phdr */ r = LUKS_keyslot_set(hdr, (int)keyIndex, 1); if (r < 0) goto out; r = LUKS_write_phdr(hdr, ctx); if (r < 0) goto out; r = 0; out: crypt_safe_free(AfKey); crypt_free_volume_key(derived_key); return r; }
static int action_format(int arg) { struct crypt_device *cd = NULL; struct crypt_params_integrity params = { .journal_size = opt_journal_size, .interleave_sectors = opt_interleave_sectors, /* in bitmap mode we have to overload these values... */ .journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark, .journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time, .buffer_sectors = opt_buffer_sectors, .tag_size = opt_tag_size, .sector_size = opt_sector_size ?: SECTOR_SIZE, }; char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN]; char *integrity_key = NULL, *msg = NULL; int r; size_t signatures; if (opt_integrity) { r = crypt_parse_hash_integrity_mode(opt_integrity, integrity); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.integrity = integrity; } if (opt_journal_integrity) { r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.journal_integrity = journal_integrity; } if (opt_journal_crypt) { r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.journal_crypt = journal_crypt; } r = _read_keys(&integrity_key, ¶ms); if (r) goto out; r = crypt_init_data_device(&cd, action_argv[0], opt_data_device); if (r < 0) goto out; r = asprintf(&msg, _("This will overwrite data on %s irrevocably."), action_argv[0]); if (r == -1) { r = -ENOMEM; goto out; } r = yesDialog(msg, _("Operation aborted.\n")) ? 0 : -EINVAL; free(msg); if (r < 0) goto out; r = tools_detect_signatures(action_argv[0], 0, &signatures); if (r < 0) goto out; /* Signature candidates found */ if (signatures && ((r = tools_wipe_all_signatures(action_argv[0])) < 0)) goto out; r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, ¶ms); if (r < 0) /* FIXME: call wipe signatures again */ goto out; if (!opt_batch_mode) log_std(_("Formatted with tag size %u, internal integrity %s.\n"), opt_tag_size, opt_integrity); if (!opt_no_wipe) r = _wipe_data_device(cd, integrity_key); out: crypt_safe_free(integrity_key); crypt_safe_free(CONST_CAST(void*)params.journal_integrity_key); crypt_safe_free(CONST_CAST(void*)params.journal_crypt_key); crypt_free(cd); return r; } static int action_open(int arg) { struct crypt_device *cd = NULL; struct crypt_params_integrity params = { /* in bitmap mode we have to overload these values... */ .journal_watermark = opt_integrity_bitmap ? opt_bitmap_sectors_per_bit : opt_journal_watermark, .journal_commit_time = opt_integrity_bitmap ? opt_bitmap_flush_time : opt_journal_commit_time, .buffer_sectors = opt_buffer_sectors, }; uint32_t activate_flags = 0; char integrity[MAX_CIPHER_LEN], journal_integrity[MAX_CIPHER_LEN], journal_crypt[MAX_CIPHER_LEN]; char *integrity_key = NULL; int r; if (opt_integrity) { r = crypt_parse_hash_integrity_mode(opt_integrity, integrity); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.integrity = integrity; } if (opt_journal_integrity) { r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.journal_integrity = journal_integrity; } if (opt_journal_crypt) { r = crypt_parse_hash_integrity_mode(opt_journal_crypt, journal_crypt); if (r < 0) { log_err(_("No known integrity specification pattern detected.")); return r; } params.journal_crypt = journal_crypt; } if (opt_integrity_nojournal || opt_integrity_bitmap) activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL; if (opt_integrity_recovery) activate_flags |= CRYPT_ACTIVATE_RECOVERY; if (opt_integrity_bitmap) activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP; if (opt_integrity_recalculate) activate_flags |= CRYPT_ACTIVATE_RECALCULATE; r = _read_keys(&integrity_key, ¶ms); if (r) goto out; if ((r = crypt_init_data_device(&cd, action_argv[0], opt_data_device))) goto out; r = crypt_load(cd, CRYPT_INTEGRITY, ¶ms); if (r) goto out; r = crypt_activate_by_volume_key(cd, action_argv[1], integrity_key, opt_integrity_key_size, activate_flags); out: crypt_safe_free(integrity_key); crypt_safe_free(CONST_CAST(void*)params.journal_integrity_key); crypt_safe_free(CONST_CAST(void*)params.journal_crypt_key); crypt_free(cd); return r; } static int action_close(int arg) { struct crypt_device *cd = NULL; int r; r = crypt_init_by_name(&cd, action_argv[0]); if (r == 0) r = crypt_deactivate(cd, action_argv[0]); crypt_free(cd); return r; } static int action_status(int arg) { crypt_status_info ci; struct crypt_active_device cad; struct crypt_params_integrity ip = {}; struct crypt_device *cd = NULL; char *backing_file; const char *device, *metadata_device; int path = 0, r = 0; /* perhaps a path, not a dm device name */ if (strchr(action_argv[0], '/')) path = 1; ci = crypt_status(NULL, action_argv[0]); switch (ci) { case CRYPT_INVALID: r = -EINVAL; break; case CRYPT_INACTIVE: if (path) log_std("%s is inactive.\n", action_argv[0]); else log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]); r = -ENODEV; break; case CRYPT_ACTIVE: case CRYPT_BUSY: if (path) log_std("%s is active%s.\n", action_argv[0], ci == CRYPT_BUSY ? " and is in use" : ""); else log_std("%s/%s is active%s.\n", crypt_get_dir(), action_argv[0], ci == CRYPT_BUSY ? " and is in use" : ""); r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL); if (r < 0) goto out; log_std(" type: %s\n", crypt_get_type(cd) ?: "n/a"); r = crypt_get_active_device(cd, action_argv[0], &cad); if (r < 0) goto out; r = crypt_get_integrity_info(cd, &ip); if (r < 0) goto out; log_std(" tag size: %u\n", ip.tag_size); log_std(" integrity: %s\n", ip.integrity ?: "(none)"); device = crypt_get_device_name(cd); metadata_device = crypt_get_metadata_device_name(cd); log_std(" device: %s%s\n", device, metadata_device ? " (detached)" : ""); if (crypt_loop_device(device)) { backing_file = crypt_loop_backing_file(device); log_std(" loop: %s\n", backing_file); free(backing_file); } if (metadata_device) { log_std(" metadata device: %s\n", metadata_device); if (crypt_loop_device(metadata_device)) { backing_file = crypt_loop_backing_file(metadata_device); log_std(" loop: %s\n", backing_file); free(backing_file); } } log_std(" sector size: %u bytes\n", crypt_get_sector_size(cd)); log_std(" interleave sectors: %u\n", ip.interleave_sectors); log_std(" size: %" PRIu64 " sectors\n", cad.size); log_std(" mode: %s%s\n", cad.flags & CRYPT_ACTIVATE_READONLY ? "readonly" : "read/write", cad.flags & CRYPT_ACTIVATE_RECOVERY ? " recovery" : ""); log_std(" failures: %" PRIu64 "\n", crypt_get_active_integrity_failures(cd, action_argv[0])); if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL_BITMAP) { log_std(" bitmap 512-byte sectors per bit: %u\n", ip.journal_watermark); log_std(" bitmap flush interval: %u ms\n", ip.journal_commit_time); } if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) { log_std(" journal: not active\n"); } else { log_std(" journal size: %" PRIu64 " bytes\n", ip.journal_size); log_std(" journal watermark: %u%%\n", ip.journal_watermark); log_std(" journal commit time: %u ms\n", ip.journal_commit_time); if (ip.journal_integrity) log_std(" journal integrity MAC: %s\n", ip.journal_integrity); if (ip.journal_crypt) log_std(" journal encryption: %s\n", ip.journal_crypt); } } out: crypt_free(cd); if (r == -ENOTSUP) r = 0; return r; return -EINVAL; } static int action_dump(int arg) { struct crypt_device *cd = NULL; struct crypt_params_integrity params = {}; int r; if ((r = crypt_init(&cd, action_argv[0]))) return r; r = crypt_load(cd, CRYPT_INTEGRITY, ¶ms); if (!r) crypt_dump(cd); crypt_free(cd); return r; } static struct action_type { const char *type; int (*handler)(int); int required_action_argc; const char *arg_desc; const char *desc; } action_types[] = { { "format", action_format, 1, N_("<integrity_device>"),N_("format device") }, { "open", action_open, 2, N_("<integrity_device> <name>"),N_("open device as <name>") }, { "close", action_close, 1, N_("<name>"),N_("close device (deactivate and remove mapping)") }, { "status", action_status, 1, N_("<name>"),N_("show active device status") }, { "dump", action_dump, 1, N_("<integrity_device>"),N_("show on-disk information") }, { NULL, NULL, 0, NULL, NULL } }; static void help(poptContext popt_context, enum poptCallbackReason reason __attribute__((unused)), struct poptOption *key, const char *arg __attribute__((unused)), void *data __attribute__((unused))) { struct action_type *action; if (key->shortName == '?') { log_std("%s %s\n", PACKAGE_INTEGRITY, PACKAGE_VERSION); poptPrintHelp(popt_context, stdout, 0); log_std(_("\n" "<action> is one of:\n")); for(action = action_types; action->type; action++) log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc)); log_std(_("\n" "<name> is the device to create under %s\n" "<integrity_device> is the device containing data with integrity tags\n"), crypt_get_dir()); log_std(_("\nDefault compiled-in dm-integrity parameters:\n" "\tTag size: %u bytes, Checksum algorithm: %s\n"), DEFAULT_TAG_SIZE, DEFAULT_ALG_NAME); exit(EXIT_SUCCESS); } else usage(popt_context, EXIT_SUCCESS, NULL, NULL); } static int run_action(struct action_type *action) { int r; log_dbg("Running command %s.", action->type); r = action->handler(0); show_status(r); return translate_errno(r); }
static int backup_luks_headers(struct reenc_ctx *rc) { struct crypt_device *cd = NULL; struct crypt_params_luks1 params = {0}; char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN]; char *old_key = NULL; size_t old_key_size; int r; log_dbg("Creating LUKS header backup for device %s.", rc->device); if ((r = crypt_init(&cd, rc->device)) || (r = crypt_load(cd, CRYPT_LUKS1, NULL))) goto out; crypt_set_confirm_callback(cd, NULL, NULL); if ((r = crypt_header_backup(cd, CRYPT_LUKS1, rc->header_file_org))) goto out; log_verbose(_("LUKS header backup of device %s created.\n"), rc->device); /* For decrypt, new header will be fake one, so we are done here. */ if (rc->reencrypt_mode == DECRYPT) goto out; if ((r = create_empty_header(rc->header_file_new, rc->header_file_org, crypt_get_data_offset(cd)))) goto out; params.hash = opt_hash ?: DEFAULT_LUKS1_HASH; params.data_alignment = crypt_get_data_offset(cd); params.data_alignment += ROUND_SECTOR(opt_reduce_size); params.data_device = rc->device; if (opt_cipher) { r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode); if (r < 0) { log_err(_("No known cipher specification pattern detected.\n")); goto out; } } if (opt_keep_key) { log_dbg("Keeping key from old header."); old_key_size = crypt_get_volume_key_size(cd); old_key = crypt_safe_alloc(old_key_size); if (!old_key) { r = -ENOMEM; goto out; } r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, old_key, &old_key_size, rc->p[rc->keyslot].password, rc->p[rc->keyslot].passwordLen); if (r < 0) goto out; } r = create_new_header(rc, opt_cipher ? cipher : crypt_get_cipher(cd), opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd), crypt_get_uuid(cd), old_key, opt_key_size ? opt_key_size / 8 : crypt_get_volume_key_size(cd), ¶ms); out: crypt_free(cd); crypt_safe_free(old_key); if (r) log_err(_("Creation of LUKS backup headers failed.\n")); return r; }
int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile, char **key, size_t *key_size_read, uint64_t keyfile_offset, size_t keyfile_size_max, uint32_t flags) { int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0; int r = -EINVAL, newline; char *pass = NULL; size_t buflen, i; uint64_t file_read_size; struct stat st; if (!key || !key_size_read) return -EINVAL; *key = NULL; *key_size_read = 0; fd = keyfile ? open(keyfile, O_RDONLY) : STDIN_FILENO; if (fd < 0) { log_err(cd, _("Failed to open key file.")); return -EINVAL; } if (isatty(fd)) { log_err(cd, _("Cannot read keyfile from a terminal.")); r = -EINVAL; goto out_err; } /* If not requested otherwise, we limit input to prevent memory exhaustion */ if (keyfile_size_max == 0) { keyfile_size_max = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1; unlimited_read = 1; /* use 4k for buffer (page divisor but avoid huge pages) */ buflen = 4096 - sizeof(struct safe_allocation); } else buflen = keyfile_size_max; regular_file = 0; if (keyfile) { if (stat(keyfile, &st) < 0) { log_err(cd, _("Failed to stat key file.")); goto out_err; } if (S_ISREG(st.st_mode)) { regular_file = 1; file_read_size = (uint64_t)st.st_size; if (keyfile_offset > file_read_size) { log_err(cd, _("Cannot seek to requested keyfile offset.")); goto out_err; } file_read_size -= keyfile_offset; /* known keyfile size, alloc it in one step */ if (file_read_size >= (uint64_t)keyfile_size_max) buflen = keyfile_size_max; else if (file_read_size) buflen = file_read_size; } } pass = crypt_safe_alloc(buflen); if (!pass) { log_err(cd, _("Out of memory while reading passphrase.")); goto out_err; } /* Discard keyfile_offset bytes on input */ if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) { log_err(cd, _("Cannot seek to requested keyfile offset.")); goto out_err; } for (i = 0, newline = 0; i < keyfile_size_max; i += char_read) { if (i == buflen) { buflen += 4096; pass = crypt_safe_realloc(pass, buflen); if (!pass) { log_err(cd, _("Out of memory while reading passphrase.")); r = -ENOMEM; goto out_err; } } if (flags & CRYPT_KEYFILE_STOP_EOL) { /* If we should stop on newline, we must read the input * one character at the time. Otherwise we might end up * having read some bytes after the newline, which we * promised not to do. */ char_to_read = 1; } else { /* char_to_read = min(keyfile_size_max - i, buflen - i) */ char_to_read = keyfile_size_max < buflen ? keyfile_size_max - i : buflen - i; } char_read = read_buffer(fd, &pass[i], char_to_read); if (char_read < 0) { log_err(cd, _("Error reading passphrase.")); r = -EPIPE; goto out_err; } if (char_read == 0) break; /* Stop on newline only if not requested read from keyfile */ if ((flags & CRYPT_KEYFILE_STOP_EOL) && pass[i] == '\n') { newline = 1; pass[i] = '\0'; break; } } /* Fail if piped input dies reading nothing */ if (!i && !regular_file && !newline) { log_dbg("Nothing read on input."); r = -EPIPE; goto out_err; } /* Fail if we exceeded internal default (no specified size) */ if (unlimited_read && i == keyfile_size_max) { log_err(cd, _("Maximum keyfile size exceeded.")); goto out_err; } if (!unlimited_read && i != keyfile_size_max) { log_err(cd, _("Cannot read requested amount of data.")); goto out_err; } *key = pass; *key_size_read = i; r = 0; out_err: if (fd != STDIN_FILENO) close(fd); if (r) crypt_safe_free(pass); return r; }