From 494d8ec04ce11854bd4048ad6aaa09470da6fe29 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Sat, 9 Nov 2019 21:59:53 +0100 Subject: [PATCH] Add kernel backend for Bitlk key decryption. --- lib/crypto_backend/crypto_backend_internal.h | 4 + lib/crypto_backend/crypto_cipher_kernel.c | 78 +++++++++++++++++--- lib/crypto_backend/crypto_kernel.c | 3 +- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/lib/crypto_backend/crypto_backend_internal.h b/lib/crypto_backend/crypto_backend_internal.h index efee36ae..65f98bc0 100644 --- a/lib/crypto_backend/crypto_backend_internal.h +++ b/lib/crypto_backend/crypto_backend_internal.h @@ -55,5 +55,9 @@ int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx, const char *in, char *out, size_t length, const char *iv, size_t iv_length); void crypt_cipher_destroy_kernel(struct crypt_cipher_kernel *ctx); +int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length, + const char *in, char *out, size_t length, + const char *iv, size_t iv_length, + const char *tag, size_t tag_length); #endif /* _CRYPTO_BACKEND_INTERNAL_H */ diff --git a/lib/crypto_backend/crypto_cipher_kernel.c b/lib/crypto_backend/crypto_cipher_kernel.c index 483d36fc..cad121d8 100644 --- a/lib/crypto_backend/crypto_cipher_kernel.c +++ b/lib/crypto_backend/crypto_cipher_kernel.c @@ -49,7 +49,7 @@ */ static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx, const void *key, size_t key_length, - struct sockaddr_alg *sa) + size_t tag_length, struct sockaddr_alg *sa) { if (!ctx) return -EINVAL; @@ -71,6 +71,11 @@ static int _crypt_cipher_init(struct crypt_cipher_kernel *ctx, return -EINVAL; } + if (tag_length && setsockopt(ctx->tfmfd, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, tag_length) < 0) { + crypt_cipher_destroy_kernel(ctx); + return -EINVAL; + } + ctx->opfd = accept(ctx->tfmfd, NULL, 0); if (ctx->opfd < 0) { crypt_cipher_destroy_kernel(ctx); @@ -93,12 +98,13 @@ int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name, snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(%s)", mode, name); - return _crypt_cipher_init(ctx, key, key_length, &sa); + return _crypt_cipher_init(ctx, key, key_length, 0, &sa); } /* The in/out should be aligned to page boundary */ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx, - const char *in, char *out, size_t length, + const char *in, size_t in_length, + char *out, size_t out_length, const char *iv, size_t iv_length, uint32_t direction) { @@ -109,7 +115,7 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx, uint32_t *type; struct iovec iov = { .iov_base = (void*)(uintptr_t)in, - .iov_len = length, + .iov_len = in_length, }; int iv_msg_size = iv ? CMSG_SPACE(sizeof(*alg_iv) + iv_length) : 0; char buffer[CMSG_SPACE(sizeof(*type)) + iv_msg_size]; @@ -120,7 +126,7 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx, .msg_iovlen = 1, }; - if (!in || !out || !length) + if (!in || !out || !in_length) return -EINVAL; if ((!iv && iv_length) || (iv && !iv_length)) @@ -151,13 +157,13 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx, } len = sendmsg(ctx->opfd, &msg, 0); - if (len != (ssize_t)length) { + if (len != (ssize_t)(in_length)) { r = -EIO; goto bad; } - len = read(ctx->opfd, out, length); - if (len != (ssize_t)length) + len = read(ctx->opfd, out, out_length); + if (len != (ssize_t)out_length) r = -EIO; bad: crypt_backend_memzero(buffer, sizeof(buffer)); @@ -168,7 +174,7 @@ int crypt_cipher_encrypt_kernel(struct crypt_cipher_kernel *ctx, const char *in, char *out, size_t length, const char *iv, size_t iv_length) { - return _crypt_cipher_crypt(ctx, in, out, length, + return _crypt_cipher_crypt(ctx, in, length, out, length, iv, iv_length, ALG_OP_ENCRYPT); } @@ -176,7 +182,7 @@ int crypt_cipher_decrypt_kernel(struct crypt_cipher_kernel *ctx, const char *in, char *out, size_t length, const char *iv, size_t iv_length) { - return _crypt_cipher_crypt(ctx, in, out, length, + return _crypt_cipher_crypt(ctx, in, length, out, length, iv, iv_length, ALG_OP_DECRYPT); } @@ -243,13 +249,56 @@ int crypt_cipher_check_kernel(const char *name, const char *mode, memset(key, 0xab, key_length); *key = 0xef; - r = _crypt_cipher_init(&c, key, key_length, &sa); + r = _crypt_cipher_init(&c, key, key_length, 0, &sa); crypt_cipher_destroy_kernel(&c); free(key); return r; } +int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length, + const char *in, char *out, size_t length, + const char *iv, size_t iv_length, + const char *tag, size_t tag_length) +{ + struct crypt_cipher_kernel c; + struct sockaddr_alg sa = { + .salg_family = AF_ALG, + .salg_type = "aead", + .salg_name = "ccm(aes)", + }; + int r; + char buffer[128], ccm_iv[16]; + + if (length + tag_length > sizeof(buffer)) + return -EINVAL; + + if (iv_length > sizeof(ccm_iv) - 1) + return -EINVAL; + + r = _crypt_cipher_init(&c, key, key_length, tag_length, &sa); + if (r < 0) + return r; + + memcpy(buffer, in, length); + memcpy(buffer + length, tag, tag_length); + + /* CCM IV - RFC3610 */ + memset(ccm_iv, 0, sizeof(ccm_iv)); + ccm_iv[0] = 15 - iv_length - 1; + memcpy(ccm_iv + 1, iv, iv_length); + memset(ccm_iv + 1 + iv_length, 0, ccm_iv[0] + 1); + iv_length = sizeof(ccm_iv); + + r = _crypt_cipher_crypt(&c, buffer, length + tag_length, out, length, + ccm_iv, iv_length, ALG_OP_DECRYPT); + + crypt_cipher_destroy_kernel(&c); + crypt_backend_memzero(buffer, sizeof(buffer)); + + return r; +} + #else /* ENABLE_AF_ALG */ int crypt_cipher_init_kernel(struct crypt_cipher_kernel *ctx, const char *name, const char *mode, const void *key, size_t key_length) @@ -280,4 +329,11 @@ int crypt_cipher_check_kernel(const char *name, const char *mode, /* Cannot check, expect success. */ return 0; } +int crypt_bitlk_decrypt_key_kernel(const void *key, size_t key_length, + const char *in, char *out, size_t length, + const char *iv, size_t iv_length, + const char *tag, size_t tag_length) +{ + return -ENOTSUP; +} #endif diff --git a/lib/crypto_backend/crypto_kernel.c b/lib/crypto_backend/crypto_kernel.c index 34297a2a..9eedff66 100644 --- a/lib/crypto_backend/crypto_kernel.c +++ b/lib/crypto_backend/crypto_kernel.c @@ -398,5 +398,6 @@ int crypt_bitlk_decrypt_key(const void *key, size_t key_length, const char *iv, size_t iv_length, const char *tag, size_t tag_length) { - return -ENOTSUP; + return crypt_bitlk_decrypt_key_kernel(key, key_length, in, out, length, + iv, iv_length, tag, tag_length); }