diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 955aab27..f36e5cf3 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -957,6 +957,9 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd, /** create keyslot with new volume key and assign it to current dm-crypt segment */ #define CRYPT_VOLUME_KEY_SET (1 << 1) +/** Assign key to first matching digest before creating new digest */ +#define CRYPT_VOLUME_KEY_DIGEST_REUSE (1 << 2) + /** * Add key slot using provided key. * diff --git a/lib/luks2/luks2.h b/lib/luks2/luks2.h index a66250fa..e1080f0c 100644 --- a/lib/luks2/luks2.h +++ b/lib/luks2/luks2.h @@ -281,6 +281,10 @@ void json_segment_remove_flag(json_object *jobj_segment, const char *flag); /* * Generic LUKS2 digest */ +int LUKS2_digest_any_matching(struct crypt_device *cd, + struct luks2_hdr *hdr, + const struct volume_key *vk); + int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment); int LUKS2_digest_verify_by_segment(struct crypt_device *cd, diff --git a/lib/luks2/luks2_digest.c b/lib/luks2/luks2_digest.c index 246903ce..115cefb9 100644 --- a/lib/luks2/luks2_digest.c +++ b/lib/luks2/luks2_digest.c @@ -110,30 +110,38 @@ int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot) return -ENOENT; } +static int _digest_verify(struct crypt_device *cd, + int digest, + const struct volume_key *vk) +{ + const digest_handler *h; + int r; + + h = LUKS2_digest_handler(cd, digest); + if (!h) + return -EINVAL; + + r = h->verify(cd, digest, vk->key, vk->keylength); + if (r < 0) + log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r); + + return r; +} + int LUKS2_digest_verify(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vk, int keyslot) { - const digest_handler *h; int digest, r; digest = LUKS2_digest_by_keyslot(hdr, keyslot); if (digest < 0) return digest; - log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest); - h = LUKS2_digest_handler(cd, digest); - if (!h) - return -EINVAL; + r = _digest_verify(cd, digest, vk); - r = h->verify(cd, digest, vk->key, vk->keylength); - if (r < 0) { - log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r); - return r; - } - - return digest; + return r < 0 ? r : digest; } int LUKS2_digest_dump(struct crypt_device *cd, int digest) @@ -151,7 +159,6 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd, int segment, const struct volume_key *vk) { - const digest_handler *h; int digest, r; digest = LUKS2_digest_by_segment(hdr, segment); @@ -160,17 +167,24 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd, log_dbg(cd, "Verifying key digest %d.", digest); - h = LUKS2_digest_handler(cd, digest); - if (!h) - return -EINVAL; + r = _digest_verify(cd, digest, vk); - r = h->verify(cd, digest, vk->key, vk->keylength); - if (r < 0) { - log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r); - return r; + return r < 0 ? r : digest; +} + +int LUKS2_digest_any_matching(struct crypt_device *cd, + struct luks2_hdr *hdr, + const struct volume_key *vk) +{ + int digest; + + for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++) { + if (_digest_verify(cd, digest, vk) < 0) + continue; + return digest; } - return digest; + return -ENOENT; } /* FIXME: segment can have more digests */ diff --git a/lib/setup.c b/lib/setup.c index 1c5e9f24..3a724332 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -5281,9 +5281,15 @@ int crypt_keyslot_add_by_key(struct crypt_device *cd, if (digest >= 0) flags &= ~CRYPT_VOLUME_KEY_SET; + /* if key matches any existing digest, do not create new digest */ + if (digest < 0 && (flags & CRYPT_VOLUME_KEY_DIGEST_REUSE)) + digest = LUKS2_digest_any_matching(cd, &cd->u.luks2.hdr, vk); + /* no segment flag or new vk flag requires new key digest */ - if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET)) - digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk); + if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET)) { + if (digest < 0 || !(flags & CRYPT_VOLUME_KEY_DIGEST_REUSE)) + digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk); + } r = digest; if (r < 0) {