From patchwork Wed Oct 28 12:34:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gilad Ben-Yossef X-Patchwork-Id: 319328 Delivered-To: patch@linaro.org Received: by 2002:a92:7b12:0:0:0:0:0 with SMTP id w18csp52995ilc; Wed, 28 Oct 2020 18:38:36 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzHVEkXKk9wA9RWDzohaveO+6GSQ/8FJTQ/EnJSlnGCxtLNgtwX7P6jH2dcVV+/GvV+v0fC X-Received: by 2002:a17:906:6702:: with SMTP id a2mr1776524ejp.309.1603935516085; Wed, 28 Oct 2020 18:38:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1603935516; cv=none; d=google.com; s=arc-20160816; b=bMd0ajGveOJ4mz/tbofDusuEQAEoRO16cbMInS/Q0FtLdcOBwORWLZV83UJNNGL59m OueK/4ChcYHRZmqET8/4WFXH4GWZ5cgoi8joUkuFdkoi1fkMs/34oojtsP1JU/24LRaR DUXER5yq4uk2V8LmpCCRVaCQLKB2XKZkfyXLORm9lcyxuFyLlwft7dON3XnJampmw+wy Aj25nq6i83W/4cANqkFe/8WClL0DYL0gn8i8geJpfLJhw5wULi9ynXdw/ULK1sPZdZNc EYd3PSZOGKoxo5IS3F5U3Sj9rWBmugbvFoUPM6cjM+kuHG4bQw6W9OJFpiQuA23OWVcN UjLQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=mrqVQhwcHvMCL5tQckdc4N5AsnMIffnPBM0g8RVqOxU=; b=Jwsbfx1LioRybn1yAiuDYfB/XyvsK/9PPTc/C46M5JjsoBW3Jb1KXPSSK99el8huUh +4zvZPFbjEXCe6xUHN/CwK0/RBJ7/8bq08T/vO+3sMOKv1f/99YUTTGextGyYivtr1Cn wpmOy00FM4DL+cJ3vQ1tKHp1cBGZwVk+Qk36ZQ32JOfJwBf2AJ9UD0aMzjhccAGMzjbO tZ51Fr8MunZQ8GMPXAnZVhQCUoxYqTRLYe8qnLOB1Xf6n0EqzSMcVKxJylVSDOuzXnH6 J01h14rY9fRqIUuLNucj12pNSZ4c/Qgv6q72dpJoiGDIyBusbzVCyQ6H8KrQksGriU3e U07A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id q7si757091ejj.150.2020.10.28.18.38.35; Wed, 28 Oct 2020 18:38:36 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-crypto-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-crypto-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729882AbgJ1WDB (ORCPT + 2 others); Wed, 28 Oct 2020 18:03:01 -0400 Received: from foss.arm.com ([217.140.110.172]:38782 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729503AbgJ1WCQ (ORCPT ); Wed, 28 Oct 2020 18:02:16 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id C79671764; Wed, 28 Oct 2020 05:34:27 -0700 (PDT) Received: from e110176-lin.kfn.arm.com (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9FC1E3F719; Wed, 28 Oct 2020 05:34:25 -0700 (PDT) From: Gilad Ben-Yossef To: Herbert Xu , "David S. Miller" , Alasdair Kergon , Mike Snitzer , dm-devel@redhat.com Cc: Ofir Drang , Eric Biggers , linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/4] crypto: add eboiv as a crypto API template Date: Wed, 28 Oct 2020 14:34:16 +0200 Message-Id: <20201028123420.30623-2-gilad@benyossef.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20201028123420.30623-1-gilad@benyossef.com> References: <20201028123420.30623-1-gilad@benyossef.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org Encrypted byte-offset initialization vector (EBOIV) is an IV generation method that is used in some cases by dm-crypt for supporting the BitLocker volume encryption used by Windows 8 and onwards as a backwards compatible version in lieu of XTS support. Support for eboiv was added to dm-crypt in 5.6. This patch re-implements eboiv as a generic crypto API template, thus allowing use of a alternative architecture specific optimzied implementations (as well as saving a memory allocation along the way). Signed-off-by: Gilad Ben-Yossef Cc: Eric Biggers --- crypto/Kconfig | 23 ++++ crypto/Makefile | 1 + crypto/eboiv.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 295 insertions(+) create mode 100644 crypto/eboiv.c -- 2.28.0 diff --git a/crypto/Kconfig b/crypto/Kconfig index 094ef56ab7b4..57676a2de01e 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -538,6 +538,29 @@ config CRYPTO_ESSIV combined with ESSIV the only feasible mode for h/w accelerated block encryption) +config CRYPTO_EBOIV + tristate "EBOIV support for block encryption" + default DM_CRYPT + select CRYPTO_CBC + help + Encrypted byte-offset initialization vector (EBOIV) is an IV + generation method that is used in some cases by dm-crypt for + supporting the BitLocker volume encryption used by Windows 8 + and onwards as a backwards compatible version in lieu of XTS + support. + + It uses the block encryption key as the symmetric key for a + block encryption pass applied to the sector offset of the block. + Additional details can be found at + https://www.jedec.org/sites/default/files/docs/JESD223C.pdf + + Note that the use of EBOIV is not recommended for new deployments, + and so this only needs to be enabled when interoperability with + existing encrypted volumes of filesystems is required, or when + building for a particular system that requires it (e.g., when + interop with BitLocker encrypted volumes of Windows systems + prior to Windows 10 is required) + comment "Hash modes" config CRYPTO_CMAC diff --git a/crypto/Makefile b/crypto/Makefile index b279483fba50..9f00b2f1ad9c 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -174,6 +174,7 @@ obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o obj-$(CONFIG_CRYPTO_OFB) += ofb.o obj-$(CONFIG_CRYPTO_ECC) += ecc.o obj-$(CONFIG_CRYPTO_ESSIV) += essiv.o +obj-$(CONFIG_CRYPTO_EBOIV) += eboiv.o obj-$(CONFIG_CRYPTO_CURVE25519) += curve25519-generic.o ecdh_generic-y += ecdh.o diff --git a/crypto/eboiv.c b/crypto/eboiv.c new file mode 100644 index 000000000000..28b9e349b458 --- /dev/null +++ b/crypto/eboiv.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * EBOIV skcipher template for block encryption + * + * This template encapsulates the Encrypted byte-offset IV generation algorithm + * used in Bitlocker in CBC mode by dm-crypt, which converts the initial vector + * for the skcipher used for block encryption, by encrypting it using the same + * skcipher key as encryption key. Usually, the input IV is a 64-bit sector + * offset (the byte offset of the start of the sector) in LE representation + * zero-padded to the size of the IV, but this * is not assumed by this driver. + * + * The typical use of this template is to instantiate the skcipher + * 'eboiv(cbc(aes))', which is the only instantiation used by + * dm-crypt for supporting BitLocker AES-CBC mode as specified in + * https://www.jedec.org/sites/default/files/docs/JESD223C.pdf + * + * Copyright (C) 2020 ARM Limited or its affiliates. + * Written by Gilad Ben-Yossef + * + * Heavily based on: + * + * ESSIV skcipher and aead template for block encryption + * Copyright (c) 2019 Linaro, Ltd. + * + * and + * + * dm-crypt eboiv code + * by Milan Broz and Ard Biesheuvel + * + */ + +#include +#include +#include + +#include "internal.h" + +struct eboiv_instance_ctx { + struct crypto_skcipher_spawn skcipher_spawn; +}; + +struct eboiv_tfm_ctx { + struct crypto_skcipher *skcipher; +}; + +struct eboiv_req_ctx { + struct skcipher_request *req; + bool enc; + struct scatterlist src; + struct scatterlist dst; + u8 iv[MAX_CIPHER_BLOCKSIZE] __aligned(__alignof__(__le64)); + struct skcipher_request subreq; +}; + +static int eboiv_skcipher_setkey(struct crypto_skcipher *tfm, + const u8 *key, unsigned int keylen) +{ + struct eboiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm); + + crypto_skcipher_clear_flags(tctx->skcipher, CRYPTO_TFM_REQ_MASK); + crypto_skcipher_set_flags(tctx->skcipher, + crypto_skcipher_get_flags(tfm) & + CRYPTO_TFM_REQ_MASK); + return crypto_skcipher_setkey(tctx->skcipher, key, keylen); +} + +static void eboiv_skcipher_done(struct crypto_async_request *areq, int err) +{ + struct skcipher_request *req = areq->data; + + if (err == -EINPROGRESS) + return; + + skcipher_request_complete(req, err); +} + +static int eboiv_skcipher_do_crypt(struct skcipher_request *req, bool enc) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + const struct eboiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm); + struct eboiv_req_ctx *req_ctx = skcipher_request_ctx(req); + struct skcipher_request *subreq = &req_ctx->subreq; + + skcipher_request_set_tfm(subreq, tctx->skcipher); + skcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, req_ctx->iv); + skcipher_request_set_callback(subreq, skcipher_request_flags(req), eboiv_skcipher_done, + req); + + return enc ? crypto_skcipher_encrypt(subreq) : + crypto_skcipher_decrypt(subreq); +} + +static void eboiv_skcipher_iv_done(struct crypto_async_request *areq, int err) +{ + struct eboiv_req_ctx *req_ctx = areq->data; + struct skcipher_request *req = req_ctx->req; + + if (!err) { + + err = eboiv_skcipher_do_crypt(req, req_ctx->enc); + + if ((err == -EINPROGRESS) || (err == -EBUSY)) + return; + } + + skcipher_request_complete(req, err); +} + +static int eboiv_skcipher_crypt(struct skcipher_request *req, bool enc) +{ + struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); + const struct eboiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm); + struct eboiv_req_ctx *req_ctx = skcipher_request_ctx(req); + struct skcipher_request *subreq = &req_ctx->subreq; + size_t iv_size = crypto_skcipher_ivsize(tfm); + int ret; + + /* The supplied IV is assumed to be in sector offset format (though + * we don't enforce it) - encrypt it. + */ + sg_init_one(&req_ctx->src, page_address(ZERO_PAGE(0)), iv_size); + sg_init_one(&req_ctx->dst, req_ctx->iv, iv_size); + skcipher_request_set_tfm(subreq, tctx->skcipher); + skcipher_request_set_crypt(subreq, &req_ctx->src, &req_ctx->dst, iv_size, req->iv); + + req_ctx->req = req; + req_ctx->enc = enc; + + skcipher_request_set_callback(subreq, skcipher_request_flags(req), eboiv_skcipher_iv_done, + req_ctx); + + ret = crypto_skcipher_encrypt(subreq); + + if (ret) + return ret; + + return eboiv_skcipher_do_crypt(req, enc); + +} + +static int eboiv_skcipher_encrypt(struct skcipher_request *req) +{ + return eboiv_skcipher_crypt(req, true); +} + +static int eboiv_skcipher_decrypt(struct skcipher_request *req) +{ + return eboiv_skcipher_crypt(req, false); +} + +static int eboiv_skcipher_init_tfm(struct crypto_skcipher *tfm) +{ + struct skcipher_instance *inst = skcipher_alg_instance(tfm); + struct eboiv_instance_ctx *ictx = skcipher_instance_ctx(inst); + struct eboiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm); + struct crypto_skcipher *skcipher; + + skcipher = crypto_spawn_skcipher(&ictx->skcipher_spawn); + if (IS_ERR(skcipher)) + return PTR_ERR(skcipher); + + crypto_skcipher_set_reqsize(tfm, sizeof(struct eboiv_req_ctx) + + crypto_skcipher_reqsize(skcipher)); + + tctx->skcipher = skcipher; + return 0; +} + +static void eboiv_skcipher_exit_tfm(struct crypto_skcipher *tfm) +{ + struct eboiv_tfm_ctx *tctx = crypto_skcipher_ctx(tfm); + + crypto_free_skcipher(tctx->skcipher); +} + +static void eboiv_skcipher_free_instance(struct skcipher_instance *inst) +{ + struct eboiv_instance_ctx *ictx = skcipher_instance_ctx(inst); + + crypto_drop_skcipher(&ictx->skcipher_spawn); + kfree(inst); +} + +static int eboiv_create(struct crypto_template *tmpl, struct rtattr **tb) +{ + struct skcipher_instance *inst; + struct eboiv_instance_ctx *ictx; + struct skcipher_alg *alg; + u32 mask; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER, &mask); + if (err) + return err; + + inst = kzalloc(sizeof(*inst) + sizeof(*ictx), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + ictx = skcipher_instance_ctx(inst); + + err = crypto_grab_skcipher(&ictx->skcipher_spawn, skcipher_crypto_instance(inst), + crypto_attr_alg_name(tb[1]), 0, mask); + if (err) + goto err_free_inst; + alg = crypto_spawn_skcipher_alg(&ictx->skcipher_spawn); + + err = -EINVAL; + if (strncmp(alg->base.cra_name, "cbc(", 4) || + crypto_skcipher_alg_ivsize(alg) != alg->base.cra_blocksize) + goto err_free_inst; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, "eboiv(%s)", + alg->base.cra_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "eboiv(%s)", alg->base.cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto err_free_inst; + + inst->alg.base.cra_blocksize = alg->base.cra_blocksize; + inst->alg.base.cra_ctxsize = sizeof(struct eboiv_tfm_ctx); + inst->alg.base.cra_alignmask = alg->base.cra_alignmask; + inst->alg.base.cra_priority = alg->base.cra_priority; + + inst->alg.setkey = eboiv_skcipher_setkey; + inst->alg.encrypt = eboiv_skcipher_encrypt; + inst->alg.decrypt = eboiv_skcipher_decrypt; + inst->alg.init = eboiv_skcipher_init_tfm; + inst->alg.exit = eboiv_skcipher_exit_tfm; + + inst->alg.min_keysize = crypto_skcipher_alg_min_keysize(alg); + inst->alg.max_keysize = crypto_skcipher_alg_max_keysize(alg); + inst->alg.ivsize = crypto_skcipher_alg_ivsize(alg); + + inst->free = eboiv_skcipher_free_instance; + + err = skcipher_register_instance(tmpl, inst); + + if (err) { +err_free_inst: + eboiv_skcipher_free_instance(inst); + } + + return err; +} + +/* eboiv(cipher_name) */ +static struct crypto_template eboiv_tmpl = { + .name = "eboiv", + .create = eboiv_create, + .module = THIS_MODULE, +}; + +static int __init eboiv_module_init(void) +{ + return crypto_register_template(&eboiv_tmpl); +} + +static void __exit eboiv_module_exit(void) +{ + crypto_unregister_template(&eboiv_tmpl); +} + +subsys_initcall(eboiv_module_init); +module_exit(eboiv_module_exit); + +MODULE_DESCRIPTION("EBOIV (BitLocker) skcipher wrapper for block encryption"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS_CRYPTO("eboiv");