Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
1 contributor

Users who have contributed to this file

188 lines (184 sloc) 5.81 KB
From ac745f1fd1d955ee6dd5c467e03ba1cc6c6006a5 Mon Sep 17 00:00:00 2001
From: Ignat Korchagin <ignat@cloudflare.com>
Date: Wed, 4 Dec 2019 16:53:46 +0000
Subject: [PATCH] Add xtsproxy Crypto API module
This module implements a Crypto API AES-XTS synchronous driver, which uses
AES NI implementation as a backend and falls back to generic AES implementation,
when FPU is not usable.
---
crypto/Kconfig | 10 +++++
crypto/Makefile | 1 +
crypto/xtsproxy.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 142 insertions(+)
create mode 100644 crypto/xtsproxy.c
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 9e524044d312..a401338a033e 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -434,6 +434,16 @@ config CRYPTO_XTS
key size 256, 384 or 512 bits. This implementation currently
can't handle a sectorsize which is not a multiple of 16 bytes.
+config CRYPTO_XTS_AES_SYNC
+ tristate "XTS AES synchronous implementation"
+ depends on X86 && 64BIT
+ select CRYPTO_AES
+ select CRYPTO_AES_NI_INTEL
+ help
+ A synchronous AES-XTS implementaion, which uses AES NI as a
+ backend implementation and falls back to generic implementation,
+ when FPU is not usable.
+
config CRYPTO_KEYWRAP
tristate "Key wrapping support"
select CRYPTO_BLKCIPHER
diff --git a/crypto/Makefile b/crypto/Makefile
index fcb1ee679782..197ae4caf90c 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
obj-$(CONFIG_CRYPTO_CTS) += cts.o
obj-$(CONFIG_CRYPTO_LRW) += lrw.o
obj-$(CONFIG_CRYPTO_XTS) += xts.o
+obj-$(CONFIG_CRYPTO_XTS_AES_SYNC) += xtsproxy.o
obj-$(CONFIG_CRYPTO_CTR) += ctr.o
obj-$(CONFIG_CRYPTO_KEYWRAP) += keywrap.o
obj-$(CONFIG_CRYPTO_ADIANTUM) += adiantum.o
diff --git a/crypto/xtsproxy.c b/crypto/xtsproxy.c
new file mode 100644
index 000000000000..51ecfb7b4891
--- /dev/null
+++ b/crypto/xtsproxy.c
@@ -0,0 +1,131 @@
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/aes.h>
+#include <asm/fpu/api.h>
+
+struct xtsproxy_ctx {
+ struct crypto_skcipher *xts_aesni;
+ struct crypto_skcipher *xts_generic;
+};
+
+static int xtsproxy_skcipher_init(struct crypto_skcipher *tfm)
+{
+ struct xtsproxy_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ /* AESNI based XTS implementation, requires FPU to be available */
+ ctx->xts_aesni = crypto_alloc_skcipher("__xts-aes-aesni", CRYPTO_ALG_INTERNAL, 0);
+ if (IS_ERR(ctx->xts_aesni))
+ return PTR_ERR(ctx->xts_aesni);
+
+ /* generic XTS implementation based on generic FPU-less AES */
+ /* there is also aes-aesni implementation, which falls back to aes-generic */
+ /* but we're doing FPU checks in our code, so no need to repeat those */
+ /* as we will always fallback to aes-generic in this case */
+ ctx->xts_generic = crypto_alloc_skcipher("xts(ecb(aes-generic))", 0, 0);
+ if (IS_ERR(ctx->xts_generic))
+ return PTR_ERR(ctx->xts_generic);
+
+ /* make sure we allocate enough request memory for both implementations */
+ crypto_skcipher_set_reqsize(tfm, max(crypto_skcipher_reqsize(ctx->xts_aesni), crypto_skcipher_reqsize(ctx->xts_generic)));
+
+ return 0;
+}
+
+static void xtsproxy_skcipher_exit(struct crypto_skcipher *tfm)
+{
+ struct xtsproxy_ctx *ctx = crypto_skcipher_ctx(tfm);
+
+ if (!IS_ERR_OR_NULL(ctx->xts_generic)) {
+ crypto_free_skcipher(ctx->xts_generic);
+ ctx->xts_generic = NULL;
+ }
+
+ if (!IS_ERR_OR_NULL(ctx->xts_aesni)) {
+ crypto_free_skcipher(ctx->xts_aesni);
+ ctx->xts_aesni = NULL;
+ }
+}
+
+static int xtsproxy_setkey(struct crypto_skcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct xtsproxy_ctx *ctx = crypto_skcipher_ctx(tfm);
+ int err;
+
+ err = crypto_skcipher_setkey(ctx->xts_aesni, key, keylen);
+ if (err)
+ return err;
+
+ return crypto_skcipher_setkey(ctx->xts_generic, key, keylen);
+}
+
+static int xtsproxy_encrypt(struct skcipher_request *req)
+{
+ struct xtsproxy_ctx *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (irq_fpu_usable())
+ skcipher_request_set_tfm(req, ctx->xts_aesni);
+ else
+ skcipher_request_set_tfm(req, ctx->xts_generic);
+
+ /* underlying implementations should not try to sleep */
+ req->base.flags &= ~(CRYPTO_TFM_REQ_MAY_SLEEP | CRYPTO_TFM_REQ_MAY_BACKLOG);
+
+ return crypto_skcipher_encrypt(req);
+}
+
+static int xtsproxy_decrypt(struct skcipher_request *req)
+{
+ struct xtsproxy_ctx *ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req));
+
+ if (irq_fpu_usable())
+ skcipher_request_set_tfm(req, ctx->xts_aesni);
+ else
+ skcipher_request_set_tfm(req, ctx->xts_generic);
+
+ /* underlying implementations should not try to sleep */
+ req->base.flags &= ~(CRYPTO_TFM_REQ_MAY_SLEEP | CRYPTO_TFM_REQ_MAY_BACKLOG);
+
+ return crypto_skcipher_decrypt(req);
+}
+
+static struct skcipher_alg xtsproxy_skcipher = {
+ .base = {
+ .cra_name = "xts(aes)",
+ .cra_driver_name = "xts-aes-xtsproxy",
+ /* make sure we don't use it unless requested explicitly */
+ .cra_priority = 0,
+ /* .cra_flags = CRYPTO_ALG_INTERNAL, */
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct xtsproxy_ctx),
+ .cra_module = THIS_MODULE,
+ },
+ .min_keysize = 2 * AES_MIN_KEY_SIZE,
+ .max_keysize = 2 * AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .init = xtsproxy_skcipher_init,
+ .exit = xtsproxy_skcipher_exit,
+ .setkey = xtsproxy_setkey,
+ .encrypt = xtsproxy_encrypt,
+ .decrypt = xtsproxy_decrypt,
+};
+
+static int __init xtsproxy_init(void)
+{
+ return crypto_register_skcipher(&xtsproxy_skcipher);
+}
+
+static void __exit xtsproxy_fini(void)
+{
+ crypto_unregister_skcipher(&xtsproxy_skcipher);
+}
+
+module_init(xtsproxy_init);
+module_exit(xtsproxy_fini);
+
+MODULE_DESCRIPTION("XTS-AES using AESNI implementation with generic AES fallback");
+MODULE_AUTHOR("Ignat Korchagin <ignat@cloudflare.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CRYPTO("xts(aes)");
--
2.11.0
You can’t perform that action at this time.