diff --git a/lib/integrity/integrity.c b/lib/integrity/integrity.c index 01576c4d..a1326b0d 100644 --- a/lib/integrity/integrity.c +++ b/lib/integrity/integrity.c @@ -31,6 +31,8 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd, { int devfd, r; + log_dbg(cd, "Reading kernel dm-integrity metadata on %s.", device_path(device)); + devfd = device_open(cd, device, O_RDONLY); if(devfd < 0) return -EINVAL; @@ -71,8 +73,10 @@ int INTEGRITY_read_sb(struct crypt_device *cd, if (r) return r; - params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block; - params->tag_size = sb.integrity_tag_size; + if (params) { + params->sector_size = SECTOR_SIZE << sb.log2_sectors_per_block; + params->tag_size = sb.integrity_tag_size; + } if (flags) *flags = sb.flags; @@ -248,6 +252,9 @@ int INTEGRITY_create_dmd_device(struct crypt_device *cd, if (sb_flags & SB_FLAG_RECALCULATING) dmd->flags |= CRYPT_ACTIVATE_RECALCULATE; + if (sb_flags & SB_FLAG_INLINE) + dmd->flags |= (CRYPT_ACTIVATE_NO_JOURNAL | CRYPT_ACTIVATE_INLINE_MODE); + r = INTEGRITY_data_sectors(cd, INTEGRITY_metadata_device(cd), crypt_get_data_offset(cd) * SECTOR_SIZE, &dmd->size); if (r < 0) @@ -273,8 +280,9 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd, if (!single_segment(dmd) || tgt->type != DM_INTEGRITY) return -EINVAL; - log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d, provided sectors %" PRIu64".", - device_path(tgt->data_device), name, tgt->u.integrity.tag_size, dmd->size); + log_dbg(cd, "Trying to activate INTEGRITY device on top of %s, using name %s, tag size %d%s, provided sectors %" PRIu64".", + device_path(tgt->data_device), name, tgt->u.integrity.tag_size, + (sb_flags & SB_FLAG_INLINE) ? " (inline)" :"", dmd->size); r = create_or_reload_device(cd, name, type, dmd); @@ -298,6 +306,12 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd, return -ENOTSUP; } + if (r < 0 && (sb_flags & SB_FLAG_INLINE) && !dm_flags(cd, DM_INTEGRITY, &dmi_flags) && + !(dmi_flags & DM_INTEGRITY_INLINE_MODE_SUPPORTED)) { + log_err(cd, _("Kernel does not support dm-integrity inline mode.")); + return -ENOTSUP; + } + return r; } @@ -393,7 +407,9 @@ int INTEGRITY_format(struct crypt_device *cd, struct volume_key *integrity_key, struct volume_key *journal_crypt_key, struct volume_key *journal_mac_key, - uint64_t backing_device_sectors) + uint64_t backing_device_sectors, + uint32_t *sb_flags, + bool integrity_inline) { uint64_t dmi_flags; char reduced_device_name[70], tmp_name[64], tmp_uuid[40]; @@ -440,6 +456,9 @@ int INTEGRITY_format(struct crypt_device *cd, p_data_device = crypt_data_device(cd); } + if (integrity_inline) + dmdi.flags |= (CRYPT_ACTIVATE_NO_JOURNAL | CRYPT_ACTIVATE_INLINE_MODE); + r = dm_integrity_target_set(cd, tgt, 0, dmdi.size, p_metadata_device, p_data_device, crypt_get_integrity_tag_size(cd), data_offset_sectors, crypt_get_sector_size(cd), integrity_key, @@ -447,8 +466,8 @@ int INTEGRITY_format(struct crypt_device *cd, if (r < 0) goto err; - log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d.", - device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size); + log_dbg(cd, "Trying to format INTEGRITY device on top of %s, tmp name %s, tag size %d%s.", + device_path(tgt->data_device), tmp_name, tgt->u.integrity.tag_size, integrity_inline ? " (inline)" : ""); r = device_block_adjust(cd, tgt->data_device, DEV_EXCL, tgt->u.integrity.offset, NULL, NULL); if (r < 0 && (dm_flags(cd, DM_INTEGRITY, &dmi_flags) || !(dmi_flags & DM_INTEGRITY_SUPPORTED))) { @@ -469,6 +488,12 @@ int INTEGRITY_format(struct crypt_device *cd, goto err; r = dm_remove_device(cd, tmp_name, CRYPT_DEACTIVATE_FORCE); + if (r) + goto err; + + /* reload sb_flags from superblock (important for SB_FLAG_INLINE) */ + if (sb_flags) + r = INTEGRITY_read_sb(cd, NULL, sb_flags); err: dm_targets_free(cd, &dmdi); if (reduced_device) { diff --git a/lib/integrity/integrity.h b/lib/integrity/integrity.h index ddd37727..ff1293fa 100644 --- a/lib/integrity/integrity.h +++ b/lib/integrity/integrity.h @@ -9,6 +9,7 @@ #define _CRYPTSETUP_INTEGRITY_H #include +#include struct crypt_device; struct device; @@ -68,7 +69,9 @@ int INTEGRITY_format(struct crypt_device *cd, struct volume_key *integrity_key, struct volume_key *journal_crypt_key, struct volume_key *journal_mac_key, - uint64_t backing_device_sectors); + uint64_t backing_device_sectors, + uint32_t *sb_flags, + bool integrity_inline); int INTEGRITY_activate(struct crypt_device *cd, const char *name, diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 3379bca8..9ad6b4e1 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -703,6 +703,35 @@ int crypt_format_luks2_opal(struct crypt_device *cd, struct crypt_params_luks2 *params, struct crypt_params_hw_opal *opal_params); +/** + * Create (format) new integrity-protected device using integrity inline mode (HW sector tags). + * This can be used for @e INTEGRITY and @e LUKS2 with integrity protection + * + * @pre @e cd contains initialized and not formatted device context (device type must @b not be set) + * + * @param cd crypt device handle + * @param type type of device (optional params struct must be of this type) + * @param cipher (e.g. "aes") or @e NULL for @e INTEGRITY + * @param cipher_mode including IV specification (e.g. "xts-plain") or @e NULL for @e INTEGRITY + * @param uuid requested UUID or @e NULL if it should be generated + * @param volume_key pre-generated integrity/volume key (if needed) or @e NULL + * @param volume_key_size size of volume/integrity key in bytes. + * @param params crypt type specific parameters (see @link crypt-type @endlink) + * + * @returns @e 0 on success or negative errno value otherwise. + * + * @note Journal parameters must be set to zero in integrity part of @e params. + * Only tag_size, sector_size, buffer_sectors, integrity options should be set. + */ +int crypt_format_inline(struct crypt_device *cd, + const char *type, + const char *cipher, + const char *cipher_mode, + const char *uuid, + const char *volume_key, + size_t volume_key_size, + void *params); + /** * Set format compatibility flags. * diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index b33d5d39..3a54431a 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -193,4 +193,5 @@ CRYPTSETUP_2.8 { crypt_keyslot_context_init_by_vk_in_keyring; crypt_reencrypt_init_by_keyslot_context; crypt_get_old_volume_key_size; + crypt_format_inline; } CRYPTSETUP_2.7; diff --git a/lib/setup.c b/lib/setup.c index 72d58b29..a605b905 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -2200,7 +2200,8 @@ static int _crypt_format_luks2(struct crypt_device *cd, goto out; } } - r = INTEGRITY_format(cd, params ? params->integrity_params : NULL, integrity_key, NULL, NULL, 0); + r = INTEGRITY_format(cd, params ? params->integrity_params : NULL, + integrity_key, NULL, NULL, 0, NULL, false); if (r) log_err(cd, _("Cannot format integrity for device %s."), data_device_path(cd)); @@ -2658,7 +2659,7 @@ int crypt_format_luks2_opal(struct crypt_device *cd, * Create reduced dm-integrity device only if locking range size does * not match device size. */ - device_size_bytes != range_size_bytes ? range_size_bytes / SECTOR_SIZE : 0); + device_size_bytes != range_size_bytes ? range_size_bytes / SECTOR_SIZE : 0, NULL, false); if (r) log_err(cd, _("Cannot format integrity for device %s."), data_device_path(cd)); @@ -2940,7 +2941,8 @@ out: static int _crypt_format_integrity(struct crypt_device *cd, const char *uuid, struct crypt_params_integrity *params, - const char *integrity_key, size_t integrity_key_size) + const char *integrity_key, size_t integrity_key_size, + bool integrity_inline) { int r; uint32_t integrity_tag_size; @@ -3037,7 +3039,9 @@ static int _crypt_format_integrity(struct crypt_device *cd, } } - r = INTEGRITY_format(cd, params, ik, cd->u.integrity.journal_crypt_key, cd->u.integrity.journal_mac_key, 0); + r = INTEGRITY_format(cd, params, ik, cd->u.integrity.journal_crypt_key, + cd->u.integrity.journal_mac_key, 0, &cd->u.integrity.sb_flags, + integrity_inline); if (r) log_err(cd, _("Cannot format integrity for device %s."), mdata_device_path(cd)); @@ -3054,6 +3058,75 @@ out: return r; } +int crypt_format_inline(struct crypt_device *cd, + const char *type, + const char *cipher, + const char *cipher_mode, + const char *uuid, + const char *volume_key, + size_t volume_key_size, + void *params) +{ + const struct crypt_params_integrity *iparams; + struct device *idevice; + size_t sector_size, required_sector_size; + int r; + + if (!cd || !params) + return -EINVAL; + + if (cd->type) { + log_dbg(cd, "Context already formatted as %s.", cd->type); + return -EINVAL; + } + + log_dbg(cd, "Formatting device %s as type %s with inline tags.", mdata_device_path(cd) ?: "(none)", type); + + if (isINTEGRITY(type)) { + iparams = params; + idevice = crypt_metadata_device(cd); + required_sector_size = iparams->sector_size; + + /* Unused in standalone integrity */ + if (cipher || cipher_mode) + return -EINVAL; + } else { + log_err(cd, _("Unknown or unsupported device type %s requested."), type); + return -EINVAL; + } + + /* In inline mode journal will be never used, check that params are not set */ + if (iparams && (iparams->journal_size || iparams->journal_watermark || iparams->journal_commit_time || + iparams->interleave_sectors || iparams->journal_integrity || iparams->journal_integrity_key || + iparams->journal_integrity_key_size || iparams->journal_crypt || iparams->journal_crypt_key || + iparams->journal_integrity_key_size)) + return -EINVAL; + + /* Inline must use sectors size as hardware device */ + sector_size = device_block_size(cd, idevice); + if (!sector_size) + return -EINVAL; + + /* No autodetection, use device sector size */ + if (sector_size != required_sector_size) { + log_err(cd, _("Sector must be the same as device hardware sector (%zu bytes)."), sector_size); + return -EINVAL; + } + + if (isINTEGRITY(type)) + r = _crypt_format_integrity(cd, uuid, params, volume_key, volume_key_size, true); + else + r = -EINVAL; + + if (r < 0) { + crypt_set_null_type(cd); + crypt_free_volume_key(cd->volume_key); + cd->volume_key = NULL; + } + + return r; +} + static int _crypt_format(struct crypt_device *cd, const char *type, const char *cipher, @@ -3096,9 +3169,9 @@ static int _crypt_format(struct crypt_device *cd, else if (isVERITY(type)) r = _crypt_format_verity(cd, uuid, params); else if (isINTEGRITY(type)) - r = _crypt_format_integrity(cd, uuid, params, volume_key, volume_key_size); + r = _crypt_format_integrity(cd, uuid, params, volume_key, volume_key_size, false); else { - log_err(cd, _("Unknown crypt device type %s requested."), type); + log_err(cd, _("Unknown or unsupported device type %s requested."), type); r = -EINVAL; } diff --git a/man/integritysetup.8.adoc b/man/integritysetup.8.adoc index 26b957c1..02e095d5 100644 --- a/man/integritysetup.8.adoc +++ b/man/integritysetup.8.adoc @@ -155,6 +155,19 @@ because we don't have to write the data twice, but it is also less reliable, because if data corruption happens when the machine crashes, it may not be detected. +*--integrity-inline*:: +Store integrity tags to hardware sector integrity fields. +The device must support sectors with additional protection information +(PI, also known as DIF - data integrity field) of the requested size. +Another storage subsystem must not use the additional field +(the device must present a "nop" profile in the kernel). +Note that some devices must be reformatted at a low level to support +this option; for NVMe devices, see nvme(1) id-ns LBA profiles. ++ +No journal or bitmap is used in this mode. The device should operate +with native speed (without any overhead). +This option is available since the Linux kernel version 6.11. + *--integrity-key-file FILE*:: The file with the integrity key. diff --git a/src/integritysetup.c b/src/integritysetup.c index 2f2ea74f..4d38a845 100644 --- a/src/integritysetup.c +++ b/src/integritysetup.c @@ -112,11 +112,6 @@ static int action_format(void) { struct crypt_device *cd = NULL; struct crypt_params_integrity params = { - .journal_size = ARG_UINT64(OPT_JOURNAL_SIZE_ID), - .interleave_sectors = ARG_UINT32(OPT_INTERLEAVE_SECTORS_ID), - /* in bitmap mode we have to overload these values... */ - .journal_watermark = ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) ? ARG_UINT32(OPT_BITMAP_SECTORS_PER_BIT_ID) : ARG_UINT32(OPT_JOURNAL_WATERMARK_ID), - .journal_commit_time = ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) ? ARG_UINT32(OPT_BITMAP_FLUSH_TIME_ID) : ARG_UINT32(OPT_JOURNAL_COMMIT_TIME_ID), .buffer_sectors = ARG_UINT32(OPT_BUFFER_SECTORS_ID), .tag_size = ARG_UINT32(OPT_TAG_SIZE_ID), .sector_size = ARG_UINT32(OPT_SECTOR_SIZE_ID), @@ -133,22 +128,31 @@ static int action_format(void) } params.integrity = integrity; - if (ARG_SET(OPT_JOURNAL_INTEGRITY_ID)) { - r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_JOURNAL_INTEGRITY_ID), journal_integrity); - if (r < 0) { - log_err(_("No known integrity specification pattern detected.")); - return r; - } - params.journal_integrity = journal_integrity; - } + if (!ARG_SET(OPT_INTEGRITY_INLINE_ID)) { + params.journal_size = ARG_UINT64(OPT_JOURNAL_SIZE_ID); + params.interleave_sectors = ARG_UINT32(OPT_INTERLEAVE_SECTORS_ID); + /* in bitmap mode we have to overload these values... */ + params.journal_watermark = ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) ? ARG_UINT32(OPT_BITMAP_SECTORS_PER_BIT_ID) : ARG_UINT32(OPT_JOURNAL_WATERMARK_ID); + params.journal_commit_time = ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) ? ARG_UINT32(OPT_BITMAP_FLUSH_TIME_ID) : ARG_UINT32(OPT_JOURNAL_COMMIT_TIME_ID); - if (ARG_SET(OPT_JOURNAL_CRYPT_ID)) { - r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_JOURNAL_CRYPT_ID), journal_crypt); - if (r < 0) { - log_err(_("No known integrity specification pattern detected.")); - return r; + if (ARG_SET(OPT_JOURNAL_INTEGRITY_ID)) { + r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_JOURNAL_INTEGRITY_ID), journal_integrity); + if (r < 0) { + log_err(_("No known integrity specification pattern detected.")); + return r; + } + params.journal_integrity = journal_integrity; } - params.journal_crypt = journal_crypt; + + if (ARG_SET(OPT_JOURNAL_CRYPT_ID)) { + r = crypt_parse_hash_integrity_mode(ARG_STR(OPT_JOURNAL_CRYPT_ID), 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); @@ -196,13 +200,18 @@ static int action_format(void) if (ARG_SET(OPT_INTEGRITY_LEGACY_HMAC_ID)) crypt_set_compatibility(cd, CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC); - r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, integrity_key, params.integrity_key_size, ¶ms); + if (ARG_SET(OPT_INTEGRITY_INLINE_ID)) + r = crypt_format_inline(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, + integrity_key, params.integrity_key_size, ¶ms); + else + r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, + integrity_key, params.integrity_key_size, ¶ms); if (r < 0) /* FIXME: call wipe signatures again */ goto out; if (!ARG_SET(OPT_BATCH_MODE_ID) && !crypt_get_integrity_info(cd, ¶ms2)) - log_std(_("Formatted with tag size %u, internal integrity %s.\n"), - params2.tag_size, params2.integrity); + log_std(_("Formatted with tag size %u%s, internal integrity %s.\n"), + params2.tag_size, ARG_SET(OPT_INTEGRITY_INLINE_ID) ? " (inline hw tags)" : "", params2.integrity); if (!ARG_SET(OPT_NO_WIPE_ID)) { r = _wipe_data_device(cd, integrity_key); @@ -227,6 +236,7 @@ static int action_resize(void) uint64_t old_dev_size; char path[PATH_MAX]; char *backing_file = NULL; + uint32_t reactivate_flags; struct tools_progress_params prog_parms = { .frequency = ARG_UINT32(OPT_PROGRESS_FREQUENCY_ID), .batch_mode = ARG_SET(OPT_BATCH_MODE_ID), @@ -256,12 +266,14 @@ static int action_resize(void) if (r) goto out; - if (!new_dev_size) { - r = crypt_get_active_device(cd, action_argv[0], &cad); - if (r) - goto out; + r = crypt_get_active_device(cd, action_argv[0], &cad); + if (r) + goto out; + + reactivate_flags = CRYPT_ACTIVATE_REFRESH | (cad.flags & CRYPT_ACTIVATE_INLINE_MODE); + + if (!new_dev_size) new_dev_size = cad.size; - } if (new_dev_size > old_dev_size) { if (ARG_SET(OPT_WIPE_ID)) { @@ -279,8 +291,8 @@ static int action_resize(void) set_int_block(0); } else { log_dbg("Setting recalculate flag"); - r = crypt_activate_by_volume_key(cd, action_argv[0], NULL, 0, CRYPT_ACTIVATE_REFRESH | CRYPT_ACTIVATE_RECALCULATE); - + reactivate_flags |= CRYPT_ACTIVATE_RECALCULATE; + r = crypt_activate_by_volume_key(cd, action_argv[0], NULL, 0, reactivate_flags); if (r == -ENOTSUP) log_err(_("Setting recalculate flag is not supported, you may consider using --wipe instead.")); } @@ -482,7 +494,11 @@ static int action_status(void) 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) { + } + if (cad.flags & CRYPT_ACTIVATE_INLINE_MODE) { + log_std(" inline mode\n"); + } + if (cad.flags & CRYPT_ACTIVATE_NO_JOURNAL) { log_std(" journal: not active\n"); } else { log_std(" journal size: %" PRIu64 " [bytes]\n", ip.journal_size); @@ -753,6 +769,16 @@ int main(int argc, const char **argv) usage(popt_context, EXIT_FAILURE, _("Bitmap options can be used only in bitmap mode."), poptGetInvocationName(popt_context)); + if (ARG_SET(OPT_INTEGRITY_INLINE_ID) && (ARG_SET(OPT_INTEGRITY_BITMAP_MODE_ID) || + ARG_SET(OPT_JOURNAL_INTEGRITY_ID) || ARG_SET(OPT_JOURNAL_CRYPT_ID) || + ARG_SET(OPT_JOURNAL_WATERMARK_ID) || ARG_SET(OPT_JOURNAL_COMMIT_TIME_ID))) + usage(popt_context, EXIT_FAILURE, _("Inline mode cannot be combined with journal or bitmap options."), + poptGetInvocationName(popt_context)); + + if (ARG_SET(OPT_INTEGRITY_INLINE_ID) && ARG_SET(OPT_DATA_DEVICE_ID)) + usage(popt_context, EXIT_FAILURE, _("Inline mode cannot be combined with separate data device."), + poptGetInvocationName(popt_context)); + if (ARG_SET(OPT_CANCEL_DEFERRED_ID) && ARG_SET(OPT_DEFERRED_ID)) usage(popt_context, EXIT_FAILURE, _("Options --cancel-deferred and --deferred cannot be used at the same time."), diff --git a/src/integritysetup_arg_list.h b/src/integritysetup_arg_list.h index 41e96cf1..6bc6c484 100644 --- a/src/integritysetup_arg_list.h +++ b/src/integritysetup_arg_list.h @@ -34,6 +34,8 @@ ARG(OPT_INTEGRITY, 'I', POPT_ARG_STRING, N_("Data integrity algorithm"), NULL, C ARG(OPT_INTEGRITY_BITMAP_MODE, 'B', POPT_ARG_NONE, N_("Use bitmap to track changes and disable journal for integrity device"), NULL, CRYPT_ARG_BOOL, {}, {}) +ARG(OPT_INTEGRITY_INLINE, '\0', POPT_ARG_NONE, N_("Use inline integrity mode (HW sector tags)"), NULL, CRYPT_ARG_BOOL, {}, OPT_INTEGRITY_INLINE_ACTIONS) + ARG(OPT_INTEGRITY_KEY_FILE, '\0', POPT_ARG_STRING, N_("Read the integrity key from a file"), NULL, CRYPT_ARG_STRING, {}, {}) ARG(OPT_INTEGRITY_KEY_SIZE, '\0', POPT_ARG_STRING, N_("The size of the data integrity key"), N_("BITS"), CRYPT_ARG_UINT32, {}, {}) diff --git a/src/integritysetup_args.h b/src/integritysetup_args.h index 04ba6608..ef5be648 100644 --- a/src/integritysetup_args.h +++ b/src/integritysetup_args.h @@ -23,6 +23,7 @@ #define OPT_DEFERRED_ACTIONS { CLOSE_ACTION } #define OPT_DEVICE_SIZE_ACTIONS { RESIZE_ACTION } #define OPT_DISABLE_BLKID_ACTIONS { FORMAT_ACTION } +#define OPT_INTEGRITY_INLINE_ACTIONS { FORMAT_ACTION } #define OPT_INTEGRITY_RECALCULATE_ACTIONS { OPEN_ACTION } #define OPT_INTERLEAVE_SECTORS_ACTIONS { FORMAT_ACTION } #define OPT_JOURNAL_SIZE_ACTIONS { FORMAT_ACTION } diff --git a/src/utils_arg_names.h b/src/utils_arg_names.h index e189d935..a01419d3 100644 --- a/src/utils_arg_names.h +++ b/src/utils_arg_names.h @@ -62,6 +62,7 @@ #define OPT_INTEGRITY_BITMAP_MODE "integrity-bitmap-mode" #define OPT_INTEGRITY_KEY_FILE "integrity-key-file" #define OPT_INTEGRITY_KEY_SIZE "integrity-key-size" +#define OPT_INTEGRITY_INLINE "integrity-inline" #define OPT_INTEGRITY_LEGACY_PADDING "integrity-legacy-padding" #define OPT_INTEGRITY_LEGACY_HMAC "integrity-legacy-hmac" #define OPT_INTEGRITY_LEGACY_RECALC "integrity-legacy-recalculate"