Message ID | 1379702811-8025-2-git-send-email-ard.biesheuvel@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 20.09.2013 21:46, Ard Biesheuvel wrote: > Create a generic version of ablk_helper so it can be reused > by other architectures. > > Acked-by: Jussi Kivilinna <jussi.kivilinna@iki.fi> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Why resent this patch here when this was in the earlier patchset? http://marc.info/?l=linux-crypto-vger&m=137966378813818&w=2 -Jussi > --- > crypto/Kconfig | 4 ++ > crypto/Makefile | 1 + > crypto/ablk_helper.c | 150 +++++++++++++++++++++++++++++++++++++++++++ > include/asm-generic/simd.h | 14 ++++ > include/crypto/ablk_helper.h | 31 +++++++++ > 5 files changed, 200 insertions(+) > create mode 100644 crypto/ablk_helper.c > create mode 100644 include/asm-generic/simd.h > create mode 100644 include/crypto/ablk_helper.h > > diff --git a/crypto/Kconfig b/crypto/Kconfig > index 69ce573..8179ae6 100644 > --- a/crypto/Kconfig > +++ b/crypto/Kconfig > @@ -179,6 +179,10 @@ config CRYPTO_ABLK_HELPER_X86 > depends on X86 > select CRYPTO_CRYPTD > > +config CRYPTO_ABLK_HELPER > + tristate > + select CRYPTO_CRYPTD > + > config CRYPTO_GLUE_HELPER_X86 > tristate > depends on X86 > diff --git a/crypto/Makefile b/crypto/Makefile > index 80019ba..5e1bdb1 100644 > --- a/crypto/Makefile > +++ b/crypto/Makefile > @@ -104,3 +104,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o > obj-$(CONFIG_XOR_BLOCKS) += xor.o > obj-$(CONFIG_ASYNC_CORE) += async_tx/ > obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ > +obj-$(CONFIG_CRYPTO_ABLK_HELPER) += ablk_helper.o > diff --git a/crypto/ablk_helper.c b/crypto/ablk_helper.c > new file mode 100644 > index 0000000..62568b1 > --- /dev/null > +++ b/crypto/ablk_helper.c > @@ -0,0 +1,150 @@ > +/* > + * Shared async block cipher helpers > + * > + * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> > + * > + * Based on aesni-intel_glue.c by: > + * Copyright (C) 2008, Intel Corp. > + * Author: Huang Ying <ying.huang@intel.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 > + * USA > + * > + */ > + > +#include <linux/kernel.h> > +#include <linux/crypto.h> > +#include <linux/init.h> > +#include <linux/module.h> > +#include <linux/hardirq.h> > +#include <crypto/algapi.h> > +#include <crypto/cryptd.h> > +#include <crypto/ablk_helper.h> > +#include <asm/simd.h> > + > +int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, > + unsigned int key_len) > +{ > + struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); > + struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base; > + int err; > + > + crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); > + crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm) > + & CRYPTO_TFM_REQ_MASK); > + err = crypto_ablkcipher_setkey(child, key, key_len); > + crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child) > + & CRYPTO_TFM_RES_MASK); > + return err; > +} > +EXPORT_SYMBOL_GPL(ablk_set_key); > + > +int __ablk_encrypt(struct ablkcipher_request *req) > +{ > + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); > + struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); > + struct blkcipher_desc desc; > + > + desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); > + desc.info = req->info; > + desc.flags = 0; > + > + return crypto_blkcipher_crt(desc.tfm)->encrypt( > + &desc, req->dst, req->src, req->nbytes); > +} > +EXPORT_SYMBOL_GPL(__ablk_encrypt); > + > +int ablk_encrypt(struct ablkcipher_request *req) > +{ > + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); > + struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); > + > + if (!may_use_simd()) { > + struct ablkcipher_request *cryptd_req = > + ablkcipher_request_ctx(req); > + > + memcpy(cryptd_req, req, sizeof(*req)); > + ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); > + > + return crypto_ablkcipher_encrypt(cryptd_req); > + } else { > + return __ablk_encrypt(req); > + } > +} > +EXPORT_SYMBOL_GPL(ablk_encrypt); > + > +int ablk_decrypt(struct ablkcipher_request *req) > +{ > + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); > + struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); > + > + if (!may_use_simd()) { > + struct ablkcipher_request *cryptd_req = > + ablkcipher_request_ctx(req); > + > + memcpy(cryptd_req, req, sizeof(*req)); > + ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); > + > + return crypto_ablkcipher_decrypt(cryptd_req); > + } else { > + struct blkcipher_desc desc; > + > + desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); > + desc.info = req->info; > + desc.flags = 0; > + > + return crypto_blkcipher_crt(desc.tfm)->decrypt( > + &desc, req->dst, req->src, req->nbytes); > + } > +} > +EXPORT_SYMBOL_GPL(ablk_decrypt); > + > +void ablk_exit(struct crypto_tfm *tfm) > +{ > + struct async_helper_ctx *ctx = crypto_tfm_ctx(tfm); > + > + cryptd_free_ablkcipher(ctx->cryptd_tfm); > +} > +EXPORT_SYMBOL_GPL(ablk_exit); > + > +int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name) > +{ > + struct async_helper_ctx *ctx = crypto_tfm_ctx(tfm); > + struct cryptd_ablkcipher *cryptd_tfm; > + > + cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0); > + if (IS_ERR(cryptd_tfm)) > + return PTR_ERR(cryptd_tfm); > + > + ctx->cryptd_tfm = cryptd_tfm; > + tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + > + crypto_ablkcipher_reqsize(&cryptd_tfm->base); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(ablk_init_common); > + > +int ablk_init(struct crypto_tfm *tfm) > +{ > + char drv_name[CRYPTO_MAX_ALG_NAME]; > + > + snprintf(drv_name, sizeof(drv_name), "__driver-%s", > + crypto_tfm_alg_driver_name(tfm)); > + > + return ablk_init_common(tfm, drv_name); > +} > +EXPORT_SYMBOL_GPL(ablk_init); > + > +MODULE_LICENSE("GPL"); > diff --git a/include/asm-generic/simd.h b/include/asm-generic/simd.h > new file mode 100644 > index 0000000..f57eb7b > --- /dev/null > +++ b/include/asm-generic/simd.h > @@ -0,0 +1,14 @@ > + > +#include <linux/hardirq.h> > + > +/* > + * may_use_simd - whether it is allowable at this time to issue SIMD > + * instructions or access the SIMD register file > + * > + * As architectures typically don't preserve the SIMD register file when > + * taking an interrupt, !in_interrupt() should be a reasonable default. > + */ > +static __must_check inline bool may_use_simd(void) > +{ > + return !in_interrupt(); > +} > diff --git a/include/crypto/ablk_helper.h b/include/crypto/ablk_helper.h > new file mode 100644 > index 0000000..4f93df5 > --- /dev/null > +++ b/include/crypto/ablk_helper.h > @@ -0,0 +1,31 @@ > +/* > + * Shared async block cipher helpers > + */ > + > +#ifndef _CRYPTO_ABLK_HELPER_H > +#define _CRYPTO_ABLK_HELPER_H > + > +#include <linux/crypto.h> > +#include <linux/kernel.h> > +#include <crypto/cryptd.h> > + > +struct async_helper_ctx { > + struct cryptd_ablkcipher *cryptd_tfm; > +}; > + > +int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, > + unsigned int key_len); > + > +int __ablk_encrypt(struct ablkcipher_request *req); > + > +int ablk_encrypt(struct ablkcipher_request *req); > + > +int ablk_decrypt(struct ablkcipher_request *req); > + > +void ablk_exit(struct crypto_tfm *tfm); > + > +int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name); > + > +int ablk_init(struct crypto_tfm *tfm); > + > +#endif /* _CRYPTO_ABLK_HELPER_H */ >
diff --git a/crypto/Kconfig b/crypto/Kconfig index 69ce573..8179ae6 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -179,6 +179,10 @@ config CRYPTO_ABLK_HELPER_X86 depends on X86 select CRYPTO_CRYPTD +config CRYPTO_ABLK_HELPER + tristate + select CRYPTO_CRYPTD + config CRYPTO_GLUE_HELPER_X86 tristate depends on X86 diff --git a/crypto/Makefile b/crypto/Makefile index 80019ba..5e1bdb1 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -104,3 +104,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o obj-$(CONFIG_XOR_BLOCKS) += xor.o obj-$(CONFIG_ASYNC_CORE) += async_tx/ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ +obj-$(CONFIG_CRYPTO_ABLK_HELPER) += ablk_helper.o diff --git a/crypto/ablk_helper.c b/crypto/ablk_helper.c new file mode 100644 index 0000000..62568b1 --- /dev/null +++ b/crypto/ablk_helper.c @@ -0,0 +1,150 @@ +/* + * Shared async block cipher helpers + * + * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> + * + * Based on aesni-intel_glue.c by: + * Copyright (C) 2008, Intel Corp. + * Author: Huang Ying <ying.huang@intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +#include <linux/kernel.h> +#include <linux/crypto.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/hardirq.h> +#include <crypto/algapi.h> +#include <crypto/cryptd.h> +#include <crypto/ablk_helper.h> +#include <asm/simd.h> + +int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int key_len) +{ + struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); + struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base; + int err; + + crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm) + & CRYPTO_TFM_REQ_MASK); + err = crypto_ablkcipher_setkey(child, key, key_len); + crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child) + & CRYPTO_TFM_RES_MASK); + return err; +} +EXPORT_SYMBOL_GPL(ablk_set_key); + +int __ablk_encrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); + struct blkcipher_desc desc; + + desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); + desc.info = req->info; + desc.flags = 0; + + return crypto_blkcipher_crt(desc.tfm)->encrypt( + &desc, req->dst, req->src, req->nbytes); +} +EXPORT_SYMBOL_GPL(__ablk_encrypt); + +int ablk_encrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); + + if (!may_use_simd()) { + struct ablkcipher_request *cryptd_req = + ablkcipher_request_ctx(req); + + memcpy(cryptd_req, req, sizeof(*req)); + ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); + + return crypto_ablkcipher_encrypt(cryptd_req); + } else { + return __ablk_encrypt(req); + } +} +EXPORT_SYMBOL_GPL(ablk_encrypt); + +int ablk_decrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct async_helper_ctx *ctx = crypto_ablkcipher_ctx(tfm); + + if (!may_use_simd()) { + struct ablkcipher_request *cryptd_req = + ablkcipher_request_ctx(req); + + memcpy(cryptd_req, req, sizeof(*req)); + ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); + + return crypto_ablkcipher_decrypt(cryptd_req); + } else { + struct blkcipher_desc desc; + + desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); + desc.info = req->info; + desc.flags = 0; + + return crypto_blkcipher_crt(desc.tfm)->decrypt( + &desc, req->dst, req->src, req->nbytes); + } +} +EXPORT_SYMBOL_GPL(ablk_decrypt); + +void ablk_exit(struct crypto_tfm *tfm) +{ + struct async_helper_ctx *ctx = crypto_tfm_ctx(tfm); + + cryptd_free_ablkcipher(ctx->cryptd_tfm); +} +EXPORT_SYMBOL_GPL(ablk_exit); + +int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name) +{ + struct async_helper_ctx *ctx = crypto_tfm_ctx(tfm); + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + + ctx->cryptd_tfm = cryptd_tfm; + tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + + crypto_ablkcipher_reqsize(&cryptd_tfm->base); + + return 0; +} +EXPORT_SYMBOL_GPL(ablk_init_common); + +int ablk_init(struct crypto_tfm *tfm) +{ + char drv_name[CRYPTO_MAX_ALG_NAME]; + + snprintf(drv_name, sizeof(drv_name), "__driver-%s", + crypto_tfm_alg_driver_name(tfm)); + + return ablk_init_common(tfm, drv_name); +} +EXPORT_SYMBOL_GPL(ablk_init); + +MODULE_LICENSE("GPL"); diff --git a/include/asm-generic/simd.h b/include/asm-generic/simd.h new file mode 100644 index 0000000..f57eb7b --- /dev/null +++ b/include/asm-generic/simd.h @@ -0,0 +1,14 @@ + +#include <linux/hardirq.h> + +/* + * may_use_simd - whether it is allowable at this time to issue SIMD + * instructions or access the SIMD register file + * + * As architectures typically don't preserve the SIMD register file when + * taking an interrupt, !in_interrupt() should be a reasonable default. + */ +static __must_check inline bool may_use_simd(void) +{ + return !in_interrupt(); +} diff --git a/include/crypto/ablk_helper.h b/include/crypto/ablk_helper.h new file mode 100644 index 0000000..4f93df5 --- /dev/null +++ b/include/crypto/ablk_helper.h @@ -0,0 +1,31 @@ +/* + * Shared async block cipher helpers + */ + +#ifndef _CRYPTO_ABLK_HELPER_H +#define _CRYPTO_ABLK_HELPER_H + +#include <linux/crypto.h> +#include <linux/kernel.h> +#include <crypto/cryptd.h> + +struct async_helper_ctx { + struct cryptd_ablkcipher *cryptd_tfm; +}; + +int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int key_len); + +int __ablk_encrypt(struct ablkcipher_request *req); + +int ablk_encrypt(struct ablkcipher_request *req); + +int ablk_decrypt(struct ablkcipher_request *req); + +void ablk_exit(struct crypto_tfm *tfm); + +int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name); + +int ablk_init(struct crypto_tfm *tfm); + +#endif /* _CRYPTO_ABLK_HELPER_H */