[LEDE-DEV] [RFC 4/6 v2] Generic: Crypto - aesni - add ccm(aes) algorithm implementation

Christian Lamparter chunkeey at googlemail.com
Sat Oct 22 12:12:19 PDT 2016


On Saturday, October 22, 2016 12:39:26 PM CEST Chris Blake wrote:
> This patch was provided by Ben at http://lists.infradead.org/pipermail
> /lede-dev/2016-October/003332.html and adds ccm(aes) support to the AES-NI
> acceleration. Currently it is not submitted upstream, but has been confirmed
> working on the PC Engines APU2 using openssl.
Well, I might be able to provide a bit of context for that patch
and why it was never for upstream.

First, the original version can be found here:
"Re: Looking for non-NIC hardware-offload for wpa2 decrypt."
<http://marc.info/?l=linux-wireless&m=140767827527151>

And it wasn't about openssl at all (In fact, openssl could just use
AES-NI directly instead of bothering the kernel, since it's part of
the x86 ISA). Instead it was a PoC that improved the performance of
the software encryption/decryption in mac80211's aes_ccm.c code-path.

In order to get mac80211 to pick it up as a viable aead cipher, it 
had to support the synchronous crypto reguests from mac80211. So most
of the special code deals with setting up aes-ccm fallback (for
!irq_fpu_usable() cases - used by ICMP) and the other is just the AESNI
aes-ctr with parts from ccm.c.

I don't think this will ever fly by the crypto folks in this form due
to the CRYPTO_ALGO_ASYNC fallback parts which are  necessary to get it
to work with mac80211. And in case CRYPTO_ALGO_ASYNC is possible, the
crypto framework will already pick up AESNI aes-ctr anyway.

The real solution here would be: make mac80211 support asynchronous
software encryption/decryption. This has the added benefit that it
would work with other ciphers and also allow for hardware crypto
devices (like the ppc4xx-crypto). And not supporting this patch.
(Note: crypto API changes are a pain and "expensive").

Regards,
Christian

[...]
> ++struct ccm_async_ctx {
> ++	struct crypto_aes_ctx ctx;
> ++	struct crypto_aead *fallback;
> ++};
> ++[...]
> ++
> ++static int ccm_init(struct crypto_aead *tfm)
> ++{
> ++	struct crypto_aead *crypto_tfm;
> ++	struct ccm_async_ctx *ctx = (struct ccm_async_ctx *)
> ++		PTR_ALIGN((u8 *)crypto_aead_ctx(tfm), AESNI_ALIGN);
> ++
> ++	crypto_tfm = crypto_alloc_aead("ccm(aes)", 0,
> ++		CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
> ++	if (IS_ERR(crypto_tfm))
> ++		return PTR_ERR(crypto_tfm);
> ++
> ++	ctx->fallback = crypto_tfm;
> ++	return 0;
> ++}
> ++
> ++static void ccm_exit(struct crypto_aead *tfm)
> ++{
> ++	struct ccm_async_ctx *ctx = (struct ccm_async_ctx *)
> ++		PTR_ALIGN((u8 *)crypto_aead_ctx(tfm), AESNI_ALIGN);
> ++
> ++	if (!IS_ERR_OR_NULL(ctx->fallback))
> ++		crypto_free_aead(ctx->fallback);
> ++}
> ++
> ++static int ccm_setkey(struct crypto_aead *aead, const u8 *in_key,
> ++		      unsigned int key_len)
> ++{
> ++	struct crypto_tfm *tfm = crypto_aead_tfm(aead);
> ++	struct ccm_async_ctx *ctx = (struct ccm_async_ctx *)
> ++		PTR_ALIGN((u8 *)crypto_aead_ctx(aead), AESNI_ALIGN);
> ++	int err;
> ++
> ++	err = __ccm_setkey(aead, in_key, key_len);
> ++	if (err)
> ++		return err;
> ++
> ++	/*
> ++	 * Set the fallback transform to use the same request flags as
> ++	 * the hardware transform.
> ++	 */
> ++	ctx->fallback->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
> ++	ctx->fallback->base.crt_flags |=
> ++			tfm->crt_flags & CRYPTO_TFM_REQ_MASK;
> ++	return crypto_aead_setkey(ctx->fallback, in_key, key_len);
> ++}
> ++
> ++static int ccm_setauthsize(struct crypto_aead *aead, unsigned int authsize)
> ++{
> ++	struct ccm_async_ctx *ctx = (struct ccm_async_ctx *)
> ++		PTR_ALIGN((u8 *)crypto_aead_ctx(aead), AESNI_ALIGN);
> ++	int err;
> ++
> ++	err = __ccm_setauthsize(aead, authsize);
> ++	if (err)
> ++		return err;
> ++
> ++	return crypto_aead_setauthsize(ctx->fallback, authsize);
> ++}
> ++
> ++static int ccm_encrypt(struct aead_request *req)
> ++{
> ++	int ret;
> ++
> ++	if (!irq_fpu_usable()) {
> ++		struct crypto_aead *aead = crypto_aead_reqtfm(req);
> ++		struct ccm_async_ctx *ctx = get_ccm_ctx(aead);
> ++		struct crypto_aead *fallback = ctx->fallback;
> ++
> ++		char aead_req_data[sizeof(struct aead_request) +
> ++				   crypto_aead_reqsize(fallback)]
> ++		__aligned(__alignof__(struct aead_request));
> ++		struct aead_request *aead_req = (void *) aead_req_data;
> ++
> ++		memset(aead_req, 0, sizeof(aead_req_data));
> ++		aead_request_set_tfm(aead_req, fallback);
> ++		aead_request_set_ad(aead_req, req->assoclen);
> ++		aead_request_set_crypt(aead_req, req->src, req->dst,
> ++				       req->cryptlen, req->iv);
> ++		aead_request_set_callback(aead_req, req->base.flags,
> ++					  req->base.complete, req->base.data);
> ++		ret = crypto_aead_encrypt(aead_req);
> ++	} else {
> ++		kernel_fpu_begin();
> ++		ret = __ccm_encrypt(req);
> ++		kernel_fpu_end();
> ++	}
> ++	return ret;
> ++}
> ++
> ++static int ccm_decrypt(struct aead_request *req)
> ++{
> ++	int ret;
> ++
> ++	if (!irq_fpu_usable()) {
> ++		struct crypto_aead *aead = crypto_aead_reqtfm(req);
> ++		struct ccm_async_ctx *ctx = get_ccm_ctx(aead);
> ++		struct crypto_aead *fallback = ctx->fallback;
> ++
> ++		char aead_req_data[sizeof(struct aead_request) +
> ++				   crypto_aead_reqsize(fallback)]
> ++		__aligned(__alignof__(struct aead_request));
> ++		struct aead_request *aead_req = (void *) aead_req_data;
> ++
> ++		memset(aead_req, 0, sizeof(aead_req_data));
> ++		aead_request_set_tfm(aead_req, fallback);
> ++		aead_request_set_ad(aead_req, req->assoclen);
> ++		aead_request_set_crypt(aead_req, req->src, req->dst,
> ++				       req->cryptlen, req->iv);
> ++		aead_request_set_callback(aead_req, req->base.flags,
> ++					  req->base.complete, req->base.data);
> ++		ret = crypto_aead_decrypt(aead_req);
> ++	} else {
> ++		kernel_fpu_begin();
> ++		ret = __ccm_decrypt(req);
> ++		kernel_fpu_end();
> ++	}
> ++	return ret;
> ++}
> + #endif
> +
> + static int ablk_ecb_init(struct crypto_tfm *tfm)
> +@@ -1437,7 +1888,45 @@ static struct aead_alg aesni_aead_algs[] = { {
> + 		.cra_ctxsize		= sizeof(struct cryptd_aead *),
> + 		.cra_module		= THIS_MODULE,
> + 	},
> +-} };
> ++}, {
> ++	.ivsize		= AES_BLOCK_SIZE,
> ++	.maxauthsize	= AES_BLOCK_SIZE,
> ++	.setkey		= __ccm_setkey,
> ++	.setauthsize	= __ccm_setauthsize,
> ++	.encrypt	= __ccm_encrypt,
> ++	.decrypt	= __ccm_decrypt,
> ++	.base = {
> ++		.cra_name		= "__ccm-aes-aesni",
> ++		.cra_driver_name	= "__driver-ccm-aes-aesni",
> ++		.cra_priority		= 0,
> ++		.cra_flags		= CRYPTO_ALG_INTERNAL,
> ++		.cra_blocksize		= 1,
> ++		.cra_ctxsize		= sizeof(struct crypto_aes_ctx) +
> ++						AESNI_ALIGN - 1,
> ++		.cra_alignmask		= 0,
> ++		.cra_module		= THIS_MODULE,
> ++	},
> ++}, {
> ++	.base = {
> ++		.cra_name		= "ccm(aes)",
> ++		.cra_driver_name	= "ccm-aes-aesni",
> ++		.cra_priority		= 700,
> ++		.cra_flags		= CRYPTO_ALG_NEED_FALLBACK,
> ++		.cra_blocksize		= 1,
> ++		.cra_ctxsize		= AESNI_ALIGN - 1 +
> ++						sizeof(struct ccm_async_ctx),
> ++		.cra_alignmask		= 0,
> ++		.cra_module		= THIS_MODULE,
> ++	},
> ++	.init		= ccm_init,
> ++	.exit		= ccm_exit,
> ++	.ivsize		= AES_BLOCK_SIZE,
> ++	.maxauthsize	= AES_BLOCK_SIZE,
> ++	.setkey		= ccm_setkey,
> ++	.setauthsize	= ccm_setauthsize,
> ++	.encrypt	= ccm_encrypt,
> ++	.decrypt	= ccm_decrypt,
> ++}};
> + #else
> + static struct aead_alg aesni_aead_algs[0];
> + #endif




More information about the Lede-dev mailing list