crypto: authenc - convert to ahash
PATCH v2 1/1 crypto: authenc - convert to ahash
This patch converts authenc to the new ahash interface.
--- crypto/authenc.c | 371 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 files changed, 302 insertions(+), 69 deletions(-)
crypto/authenc.c +302 -69
@@ -23,24 +23,36 @@#include <linux/slab.h> #include <linux/spinlock.h> +typedef u8 *(*authenc_ahash_t )(struct aead_request *req,unsigned int flags); +struct authenc_instance_ctx { -struct crypto_spawn auth; +struct crypto_ahash_spawn auth;struct crypto_skcipher_spawn enc; };struct crypto_authenc_ctx { -spinlock_t auth_lock; -struct crypto_hash *auth; +unsigned int reqoff; +struct crypto_ahash *auth;struct crypto_ablkcipher *enc; }; +struct authenc_request_ctx { +unsigned int cryptlen; +struct scatterlist *sg; +struct scatterlist asg[2 ]; +struct scatterlist cipher[2 ]; +crypto_completion_t complete; +crypto_completion_t update_complete; +char tail[]; +}; +static int crypto_authenc_setkey (struct crypto_aead *authenc,const u8 *key,unsigned int keylen) {unsigned int authkeylen;unsigned int enckeylen;struct crypto_authenc_ctx *ctx =crypto_aead_ctx (authenc); -struct crypto_hash *auth = ctx->auth; +struct crypto_ahash *auth = ctx->auth;struct crypto_ablkcipher *enc = ctx->enc;struct rtattr *rta = (void *)key;struct crypto_authenc_key_param *param;
@@ -64,11 +76,11 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key, authkeylen = keylen - enckeylen; -crypto_hash_clear_flags (auth,CRYPTO_TFM_REQ_MASK ); -crypto_hash_set_flags (auth,crypto_aead_get_flags (authenc) & +crypto_ahash_clear_flags (auth,CRYPTO_TFM_REQ_MASK ); +crypto_ahash_set_flags (auth,crypto_aead_get_flags (authenc) &CRYPTO_TFM_REQ_MASK ); - err =crypto_hash_setkey (auth, key, authkeylen); -crypto_aead_set_flags (authenc,crypto_hash_get_flags (auth) & + err =crypto_ahash_setkey (auth, key, authkeylen); +crypto_aead_set_flags (authenc,crypto_ahash_get_flags (auth) &CRYPTO_TFM_RES_MASK );if (err)
@@ -103,40 +115,209 @@ static void authenc_chain(struct scatterlist *head, struct scatterlist *sg,sg_mark_end (head); } -static u8 *crypto_authenc_hash (struct aead_request *req,unsigned int flags, -struct scatterlist *cipher, -unsigned int cryptlen) + +static void authenc_geniv_ahash_update_done (struct crypto_async_request *areq, +int err) +{ +struct aead_request *req = areq->data; +struct crypto_aead *authenc =crypto_aead_reqtfm (req); +struct crypto_authenc_ctx *ctx =crypto_aead_ctx (authenc); +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req); +struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + +if (err) + goto out; + +ahash_request_set_crypt (ahreq, areq_ctx->sg, ahreq->result, + areq_ctx->cryptlen); +ahash_request_set_callback (ahreq,aead_request_flags (req) & +CRYPTO_TFM_REQ_MAY_SLEEP , + areq_ctx->complete, req); + + err =crypto_ahash_finup (ahreq); +if (err == -EINPROGRESS ) +return ; +else if (err) + goto out; + +scatterwalk_map_and_copy (ahreq->result, areq_ctx->sg, + areq_ctx->cryptlen, +crypto_aead_authsize (authenc),1 ); + +out: +aead_request_complete (req, err); +} + +static void authenc_geniv_ahash_done (struct crypto_async_request *areq,int err) +{ +struct aead_request *req = areq->data; +struct crypto_aead *authenc =crypto_aead_reqtfm (req); +struct crypto_authenc_ctx *ctx =crypto_aead_ctx (authenc); +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req); +struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + +if (err) + goto out; + +scatterwalk_map_and_copy (ahreq->result, areq_ctx->sg, + areq_ctx->cryptlen, +crypto_aead_authsize (authenc),1 ); + +out: +aead_request_complete (req, err); +} + + +static void authenc_verify_ahash_update_done (struct crypto_async_request *areq, +int err) +{ +u8 *ihash; +unsigned int authsize; +struct ablkcipher_request *abreq; +struct aead_request *req = areq->data; +struct crypto_aead *authenc =crypto_aead_reqtfm (req); +struct crypto_authenc_ctx *ctx =crypto_aead_ctx (authenc); +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req); +struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + +if (err) + goto out; + +ahash_request_set_crypt (ahreq, areq_ctx->sg, ahreq->result, + areq_ctx->cryptlen); +ahash_request_set_callback (ahreq,aead_request_flags (req) & +CRYPTO_TFM_REQ_MAY_SLEEP , + areq_ctx->complete, req); + + err =crypto_ahash_finup (ahreq); +if (err == -EINPROGRESS ) +return ; +else if (err) + goto out; + + authsize =crypto_aead_authsize (authenc); + ihash = ahreq->result + authsize; +scatterwalk_map_and_copy (ihash, areq_ctx->sg, areq_ctx->cryptlen, + authsize,0 ); + + err =memcmp (ihash, ahreq->result, authsize) ? -EBADMSG :0 ; +if (err) + goto out; + + abreq =aead_request_ctx (req); +ablkcipher_request_set_tfm (abreq, ctx->enc); +ablkcipher_request_set_callback (abreq,aead_request_flags (req), + req->base.complete, req->base.data); +ablkcipher_request_set_crypt (abreq, req->src, req->dst, + req->cryptlen, req->iv); + + err =crypto_ablkcipher_decrypt (abreq); + +if (err == -EINPROGRESS ) +return ; + +out: +aead_request_complete (req, err); +} + +static void authenc_verify_ahash_done (struct crypto_async_request *areq, +int err) +{ +u8 *ihash; +unsigned int authsize; +struct ablkcipher_request *abreq; +struct aead_request *req = areq->data; +struct crypto_aead *authenc =crypto_aead_reqtfm (req); +struct crypto_authenc_ctx *ctx =crypto_aead_ctx (authenc); +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req); +struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); + +if (err) + goto out; + + authsize =crypto_aead_authsize (authenc); + ihash = ahreq->result + authsize; +scatterwalk_map_and_copy (ihash, areq_ctx->sg, areq_ctx->cryptlen, + authsize,0 ); + + err =memcmp (ihash, ahreq->result, authsize) ? -EBADMSG :0 ; +if (err) + goto out; + + abreq =aead_request_ctx (req); +ablkcipher_request_set_tfm (abreq, ctx->enc); +ablkcipher_request_set_callback (abreq,aead_request_flags (req), + req->base.complete, req->base.data); +ablkcipher_request_set_crypt (abreq, req->src, req->dst, + req->cryptlen, req->iv); + + err =crypto_ablkcipher_decrypt (abreq); +if (err == -EINPROGRESS ) +return ; + +out: +aead_request_complete (req, err); +} + +static u8 *crypto_authenc_ahash_fb (struct aead_request *req,unsigned int flags) {struct crypto_aead *authenc =crypto_aead_reqtfm (req);struct crypto_authenc_ctx *ctx =crypto_aead_ctx (authenc); -struct crypto_hash *auth = ctx->auth; -struct hash_desc desc = { - .tfm = auth, - .flags =aead_request_flags (req) & flags, - }; -u8 *hash =aead_request_ctx (req); +struct crypto_ahash *auth = ctx->auth; +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req); +struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); +u8 *hash = areq_ctx->tail;int err; - hash = (u8 *)ALIGN ((unsigned long )hash +crypto_hash_alignmask (auth), -crypto_hash_alignmask (auth) +1 ); + hash = (u8 *)ALIGN ((unsigned long )hash +crypto_ahash_alignmask (auth), +crypto_ahash_alignmask (auth) +1 ); -spin_lock_bh (&ctx->auth_lock); - err =crypto_hash_init (&desc); +ahash_request_set_tfm (ahreq, auth); + + err =crypto_ahash_init (ahreq);if (err) - goto auth_unlock; +return ERR_PTR (err); - err =crypto_hash_update (&desc, req->assoc, req->assoclen); +ahash_request_set_crypt (ahreq, req->assoc, hash, req->assoclen); +ahash_request_set_callback (ahreq,aead_request_flags (req) & flags, + areq_ctx->update_complete, req); + + err =crypto_ahash_update (ahreq);if (err) - goto auth_unlock; +return ERR_PTR (err); - err =crypto_hash_update (&desc, cipher, cryptlen); +ahash_request_set_crypt (ahreq, areq_ctx->sg, hash, + areq_ctx->cryptlen); +ahash_request_set_callback (ahreq,aead_request_flags (req) & flags, + areq_ctx->complete, req); + + err =crypto_ahash_finup (ahreq);if (err) - goto auth_unlock; +return ERR_PTR (err); - err =crypto_hash_final (&desc, hash); -auth_unlock: -spin_unlock_bh (&ctx->auth_lock); +return hash; +} + +static u8 *crypto_authenc_ahash (struct aead_request *req,unsigned int flags) +{ +struct crypto_aead *authenc =crypto_aead_reqtfm (req); +struct crypto_authenc_ctx *ctx =crypto_aead_ctx (authenc); +struct crypto_ahash *auth = ctx->auth; +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req); +struct ahash_request *ahreq = (void *)(areq_ctx->tail + ctx->reqoff); +u8 *hash = areq_ctx->tail; +int err; + + hash = (u8 *)ALIGN ((unsigned long )hash +crypto_ahash_alignmask (auth), +crypto_ahash_alignmask (auth) +1 ); + +ahash_request_set_tfm (ahreq, auth); +ahash_request_set_crypt (ahreq, areq_ctx->sg, hash, + areq_ctx->cryptlen); +ahash_request_set_callback (ahreq,aead_request_flags (req) & flags, + areq_ctx->complete, req); + err =crypto_ahash_digest (ahreq);if (err)return ERR_PTR (err);
@@ -147,11 +328,15 @@ static int crypto_authenc_genicv(struct aead_request *req, u8 *iv, unsigned int flags) {struct crypto_aead *authenc =crypto_aead_reqtfm (req); +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req);struct scatterlist *dst = req->dst; -struct scatterlist cipher[2 ]; -struct page *dstp; +struct scatterlist *assoc = req->assoc; +struct scatterlist *cipher = areq_ctx->cipher; +struct scatterlist *asg = areq_ctx->asg;unsigned int ivsize =crypto_aead_ivsize (authenc); -unsigned int cryptlen; +unsigned int cryptlen = req->cryptlen; +authenc_ahash_t authenc_ahash_fn = crypto_authenc_ahash_fb; +struct page *dstp;u8 *vdst;u8 *hash;
@@ -163,10 +348,25 @@ static int crypto_authenc_genicv(struct aead_request *req, u8 *iv,sg_set_buf (cipher, iv, ivsize);authenc_chain (cipher, dst, vdst == iv + ivsize); dst = cipher; + cryptlen += ivsize; + } + +if (sg_is_last (assoc)) { + authenc_ahash_fn = crypto_authenc_ahash; +sg_init_table (asg,2 ); +sg_set_page (asg,sg_page (assoc), assoc->length, assoc->offset); +authenc_chain (asg, dst,0 ); + dst = asg; + cryptlen += req->assoclen; } - cryptlen = req->cryptlen + ivsize; - hash =crypto_authenc_hash (req, flags, dst, cryptlen); + areq_ctx->cryptlen = cryptlen; + areq_ctx->sg = dst; + + areq_ctx->complete = authenc_geniv_ahash_done; + areq_ctx->update_complete = authenc_geniv_ahash_update_done; + + hash =authenc_ahash_fn (req, flags);if (IS_ERR (hash))return PTR_ERR (hash);
@@ -188,6 +388,9 @@ static void crypto_authenc_encrypt_done(struct crypto_async_request *req,crypto_ablkcipher_reqsize (ctx->enc); err =crypto_authenc_genicv (areq, iv,0 ); + +if (err == -EINPROGRESS ) +return ; }aead_request_complete (areq, err);
@@ -227,6 +430,9 @@ static void crypto_authenc_givencrypt_done(struct crypto_async_request *req,struct skcipher_givcrypt_request *greq =aead_request_ctx (areq); err =crypto_authenc_genicv (areq, greq->giv,0 ); + +if (err == -EINPROGRESS ) +return ; }aead_request_complete (areq, err);
@@ -256,22 +462,25 @@ static int crypto_authenc_givencrypt(struct aead_givcrypt_request *req) }static int crypto_authenc_verify (struct aead_request *req, -struct scatterlist *cipher, -unsigned int cryptlen) +authenc_ahash_t authenc_ahash_fn) {struct crypto_aead *authenc =crypto_aead_reqtfm (req); +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req);u8 *ohash;u8 *ihash;unsigned int authsize; - ohash =crypto_authenc_hash (req,CRYPTO_TFM_REQ_MAY_SLEEP , cipher, - cryptlen); + areq_ctx->complete = authenc_verify_ahash_done; + areq_ctx->complete = authenc_verify_ahash_update_done; + + ohash =authenc_ahash_fn (req,CRYPTO_TFM_REQ_MAY_SLEEP );if (IS_ERR (ohash))return PTR_ERR (ohash); authsize =crypto_aead_authsize (authenc); ihash = ohash + authsize; -scatterwalk_map_and_copy (ihash, cipher, cryptlen, authsize,0 ); +scatterwalk_map_and_copy (ihash, areq_ctx->sg, areq_ctx->cryptlen, + authsize,0 );return memcmp (ihash, ohash, authsize) ? -EBADMSG :0 ; }
@@ -279,10 +488,14 @@ static int crypto_authenc_iverify(struct aead_request *req, u8 *iv, unsigned int cryptlen) {struct crypto_aead *authenc =crypto_aead_reqtfm (req); +struct authenc_request_ctx *areq_ctx =aead_request_ctx (req);struct scatterlist *src = req->src; -struct scatterlist cipher[2 ]; -struct page *srcp; +struct scatterlist *assoc = req->assoc; +struct scatterlist *cipher = areq_ctx->cipher; +struct scatterlist *asg = areq_ctx->asg;unsigned int ivsize =crypto_aead_ivsize (authenc); +authenc_ahash_t authenc_ahash_fn = crypto_authenc_ahash_fb; +struct page *srcp;u8 *vsrc; srcp =sg_page (src);
@@ -293,9 +506,22 @@ static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,sg_set_buf (cipher, iv, ivsize);authenc_chain (cipher, src, vsrc == iv + ivsize); src = cipher; + cryptlen += ivsize; + } + +if (sg_is_last (assoc)) { + authenc_ahash_fn = crypto_authenc_ahash; +sg_init_table (asg,2 ); +sg_set_page (asg,sg_page (assoc), assoc->length, assoc->offset); +authenc_chain (asg, src,0 ); + src = asg; + cryptlen += req->assoclen; } -return crypto_authenc_verify (req, src, cryptlen + ivsize); + areq_ctx->cryptlen = cryptlen; + areq_ctx->sg = src; + +return crypto_authenc_verify (req, authenc_ahash_fn); }static int crypto_authenc_decrypt (struct aead_request *req)
@@ -326,38 +552,41 @@ static int crypto_authenc_decrypt(struct aead_request *req)static int crypto_authenc_init_tfm (struct crypto_tfm *tfm) { -struct crypto_instance *inst = (void *)tfm->__crt_alg; +struct crypto_instance *inst =crypto_tfm_alg_instance (tfm);struct authenc_instance_ctx *ictx =crypto_instance_ctx (inst);struct crypto_authenc_ctx *ctx =crypto_tfm_ctx (tfm); -struct crypto_hash *auth; +struct crypto_ahash *auth;struct crypto_ablkcipher *enc;int err; - auth =crypto_spawn_hash (&ictx->auth); + auth =crypto_spawn_ahash (&ictx->auth);if (IS_ERR (auth))return PTR_ERR (auth); + ctx->reqoff =ALIGN (2 *crypto_ahash_digestsize (auth) + +crypto_ahash_alignmask (auth), +crypto_ahash_alignmask (auth) +1 ); + enc =crypto_spawn_skcipher (&ictx->enc); err =PTR_ERR (enc);if (IS_ERR (enc)) - goto err_free_hash; + goto err_free_ahash; ctx->auth = auth; ctx->enc = enc; + tfm->crt_aead.reqsize = max_t(unsigned int, - (crypto_hash_alignmask (auth) & - ~(crypto_tfm_ctx_alignment () -1 )) + -crypto_hash_digestsize (auth) *2 , -sizeof (struct skcipher_givcrypt_request ) + -crypto_ablkcipher_reqsize (enc) + -crypto_ablkcipher_ivsize (enc)); - -spin_lock_init (&ctx->auth_lock); +crypto_ahash_reqsize (auth) + ctx->reqoff + +sizeof (struct authenc_request_ctx ) + +sizeof (struct ahash_request ), +sizeof (struct skcipher_givcrypt_request ) + +crypto_ablkcipher_reqsize (enc) + +crypto_ablkcipher_ivsize (enc));return 0 ; -err_free_hash: -crypto_free_hash (auth); +err_free_ahash: +crypto_free_ahash (auth);return err; }
@@ -365,7 +594,7 @@ static void crypto_authenc_exit_tfm(struct crypto_tfm *tfm) {struct crypto_authenc_ctx *ctx =crypto_tfm_ctx (tfm); -crypto_free_hash (ctx->auth); +crypto_free_ahash (ctx->auth);crypto_free_ablkcipher (ctx->enc); }
@@ -373,7 +602,8 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) {struct crypto_attr_type *algt;struct crypto_instance *inst; -struct crypto_alg *auth; +struct hash_alg_common *auth; +struct crypto_alg *auth_base;struct crypto_alg *enc;struct authenc_instance_ctx *ctx;const char *enc_name;
@@ -387,11 +617,13 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)if ((algt->type ^CRYPTO_ALG_TYPE_AEAD ) & algt->mask)return ERR_PTR (-EINVAL ); - auth =crypto_attr_alg (tb[1 ],CRYPTO_ALG_TYPE_HASH , -CRYPTO_ALG_TYPE_HASH_MASK ); + auth =ahash_attr_alg (tb[1 ],CRYPTO_ALG_TYPE_HASH , +CRYPTO_ALG_TYPE_AHASH_MASK );if (IS_ERR (auth))return ERR_PTR (PTR_ERR (auth)); + auth_base = &auth->base; + enc_name =crypto_attr_alg_name (tb[2 ]); err =PTR_ERR (enc_name);if (IS_ERR (enc_name))
@@ -404,7 +636,7 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) ctx =crypto_instance_ctx (inst); - err =crypto_init_spawn (&ctx->auth, auth, inst,CRYPTO_ALG_TYPE_MASK ); + err =crypto_init_ahash_spawn (&ctx->auth, auth, inst);if (err) goto err_free_inst;
@@ -419,24 +651,25 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) err = -ENAMETOOLONG ;if (snprintf (inst->alg.cra_name,CRYPTO_MAX_ALG_NAME , -"authenc(%s,%s)" , auth->cra_name, enc->cra_name) >= +"authenc(%s,%s)" , auth_base->cra_name, enc->cra_name) >=CRYPTO_MAX_ALG_NAME ) goto err_drop_enc;if (snprintf (inst->alg.cra_driver_name,CRYPTO_MAX_ALG_NAME , -"authenc(%s,%s)" , auth->cra_driver_name, +"authenc(%s,%s)" , auth_base->cra_driver_name, enc->cra_driver_name) >=CRYPTO_MAX_ALG_NAME ) goto err_drop_enc; inst->alg.cra_flags =CRYPTO_ALG_TYPE_AEAD ; inst->alg.cra_flags |= enc->cra_flags &CRYPTO_ALG_ASYNC ; - inst->alg.cra_priority = enc->cra_priority *10 + auth->cra_priority; + inst->alg.cra_priority = enc->cra_priority * +10 + auth_base->cra_priority; inst->alg.cra_blocksize = enc->cra_blocksize; - inst->alg.cra_alignmask = auth->cra_alignmask | enc->cra_alignmask; + inst->alg.cra_alignmask = auth_base->cra_alignmask | enc->cra_alignmask; inst->alg.cra_type = &crypto_aead_type; inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize; - inst->alg.cra_aead.maxauthsize =__crypto_shash_alg (auth)->digestsize; + inst->alg.cra_aead.maxauthsize = auth->digestsize; inst->alg.cra_ctxsize =sizeof (struct crypto_authenc_ctx );
@@ -449,13 +682,13 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) inst->alg.cra_aead.givencrypt = crypto_authenc_givencrypt; out: -crypto_mod_put (auth); +crypto_mod_put (auth_base);return inst; err_drop_enc:crypto_drop_skcipher (&ctx->enc); err_drop_auth: -crypto_drop_spawn (&ctx->auth); +crypto_drop_ahash (&ctx->auth); err_free_inst:kfree (inst); out_put_auth:
@@ -468,7 +701,7 @@ static void crypto_authenc_free(struct crypto_instance *inst)struct authenc_instance_ctx *ctx =crypto_instance_ctx (inst);crypto_drop_skcipher (&ctx->enc); -crypto_drop_spawn (&ctx->auth); +crypto_drop_ahash (&ctx->auth);kfree (inst); }
Signature · 1 line
1.5.4.2
I just noticed that your shash version of hmac keeps the paded keys on the transform. I assumed the hashing to be reentrant, so I removed the locks arround the hash functions here.
Is there a plan to move the paded keys to the request soon, or should we keep the locks for now and remove them later?
Herbert Xu
maintainerQuoted 3 lines · Steffen Klassert
I just noticed that your shash version of hmac keeps the paded keys on the transform. I assumed the hashing to be reentrant, so I removed the locks arround the hash functions here.
The padded keys are in the transform because they never change unless you call setkey. The assumption has always been that you should use one tfm per key.
Quoted 2 lines
Is there a plan to move the paded keys to the request soon, or should we keep the locks for now and remove them later?
You don't need to lock it since the same assumption applies to AEAD.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtQuoted 8 lines · Herbert Xu
Quoted 3 lines · Steffen Klassert
I just noticed that your shash version of hmac keeps the paded keys on the transform. I assumed the hashing to be reentrant, so I removed the locks arround the hash functions here.
The padded keys are in the transform because they never change unless you call setkey. The assumption has always been that you should use one tfm per key.
Ah, yes of course.
Quoted 7 lines
Quoted 3 lines
Is there a plan to move the paded keys to the request soon, or should we keep the locks for now and remove them later?
You don't need to lock it since the same assumption applies to AEAD.
I came on it because I applied the pcrypt patches on top of this one and I had to put the locks arround the hash functions to get it to work. The problem is probaply somewhere else, I'll look at it again.
Quoted 9 lines · Herbert Xu
Quoted 3 lines · Steffen Klassert
I just noticed that your shash version of hmac keeps the paded keys on the transform. I assumed the hashing to be reentrant, so I removed the locks arround the hash functions here.
The padded keys are in the transform because they never change unless you call setkey. The assumption has always been that you should use one tfm per key.
I found the problem. It's the digest state that is saved on the transform right behind the opad in hmac_finup() and hmac_final(). The digest state is of course not constant and must be saved on the request. That's why I needed the locks in authenc to get pcrypt to work. I have a patch which moves the digest state to the request, based on the cryptodev-2.6 tree.
However, as soon as your recent import/export patches are in the cryptodev-2.6 tree we could probaply change hmac to do prehashing of the keys what would fix the problem too.
Herbert Xu
maintainerQuoted 10 lines · Steffen Klassert
I found the problem. It's the digest state that is saved on the transform right behind the opad in
hmac_finup()andhmac_final(). The digest state is of course not constant and must be saved on the request. That's why I needed the locks in authenc to get pcrypt to work. I have a patch which moves the digest state to the request, based on the cryptodev-2.6 tree.
However, as soon as your recent import/export patches are in the cryptodev-2.6 tree we could probaply change hmac to do prehashing of the keys what would fix the problem too.
Ah, that makes sense. I've done the prehash patch, let me know if this works.
commit 0b767b4df360bd442434d9d40b8a495e64202254
Author: Herbert Xu <[email protected]> Date: Fri Jul 24 15:18:41 2009 +0800
crypto: hmac - Prehash ipad/opad
This patch uses crypto_shash_export/crypto_shash_import to prehash ipad/opad to speed up hmac. This is partly based on a similar patch by Steffen Klassert.
crypto/hmac.c +62 -46
@@ -27,7 +27,7 @@#include <linux/string.h> struct hmac_ctx { -struct shash_desc *desc; +struct crypto_shash *hash; };static inline void *align_ptr (void *p,unsigned int align)
@@ -38,8 +38,7 @@ static inline void *align_ptr(void *p, unsigned int align)static inline struct hmac_ctx *hmac_ctx (struct crypto_shash *tfm) {return align_ptr (crypto_shash_ctx_aligned (tfm) + -crypto_shash_blocksize (tfm) *2 + -crypto_shash_digestsize (tfm), +crypto_shash_statesize (tfm) *2 ,crypto_tfm_ctx_alignment ()); }
@@ -48,28 +47,33 @@ static int hmac_setkey(struct crypto_shash *parent, {int bs =crypto_shash_blocksize (parent);int ds =crypto_shash_digestsize (parent); +int ss =crypto_shash_statesize (parent);char *ipad =crypto_shash_ctx_aligned (parent); -char *opad = ipad + bs; -char *digest = opad + bs; -struct hmac_ctx *ctx =align_ptr (digest + ds, +char *opad = ipad + ss; +struct hmac_ctx *ctx =align_ptr (opad + ss,crypto_tfm_ctx_alignment ()); +struct crypto_shash *hash = ctx->hash; +struct { +struct shash_desc shash; +char ctx[crypto_shash_descsize (hash)]; + } desc;unsigned int i; + desc.shash.tfm = hash; + desc.shash.flags =crypto_shash_get_flags (parent) & +CRYPTO_TFM_REQ_MAY_SLEEP ; +if (keylen > bs) {int err; - ctx->desc->flags =crypto_shash_get_flags (parent) & -CRYPTO_TFM_REQ_MAY_SLEEP ; - - err =crypto_shash_digest (ctx->desc, inkey, keylen, digest); + err =crypto_shash_digest (&desc.shash, inkey, keylen, ipad);if (err)return err; - inkey = digest; keylen = ds; - } + }else +memcpy (ipad, inkey, keylen); -memcpy (ipad, inkey, keylen);memset (ipad + keylen,0 , bs - keylen);memcpy (opad, ipad, bs);
@@ -78,24 +82,37 @@ static int hmac_setkey(struct crypto_shash *parent, opad[i] ^=0x5c ; } -return 0 ; +return crypto_shash_init (&desc.shash) ?: +crypto_shash_update (&desc.shash, ipad, bs) ?: +crypto_shash_export (&desc.shash, ipad) ?: +crypto_shash_init (&desc.shash) ?: +crypto_shash_update (&desc.shash, opad, bs) ?: +crypto_shash_export (&desc.shash, opad); } -static int hmac_init (struct shash_desc *pdesc) +static int hmac_export (struct shash_desc *pdesc,void *out) +{ +struct shash_desc *desc =shash_desc_ctx (pdesc); + + desc->flags = pdesc->flags &CRYPTO_TFM_REQ_MAY_SLEEP ; + +return crypto_shash_export (desc, out); +} + +static int hmac_import (struct shash_desc *pdesc,const void *in) { -struct crypto_shash *parent = pdesc->tfm; -int bs =crypto_shash_blocksize (parent); -int ds =crypto_shash_digestsize (parent); -char *ipad =crypto_shash_ctx_aligned (parent); -struct hmac_ctx *ctx =align_ptr (ipad + bs *2 + ds, -crypto_tfm_ctx_alignment ());struct shash_desc *desc =shash_desc_ctx (pdesc); +struct hmac_ctx *ctx =hmac_ctx (pdesc->tfm); - desc->tfm = ctx->desc->tfm; + desc->tfm = ctx->hash; desc->flags = pdesc->flags &CRYPTO_TFM_REQ_MAY_SLEEP ; -return crypto_shash_init (desc) ?: -crypto_shash_update (desc, ipad, bs); +return crypto_shash_import (desc, in); +} + +static int hmac_init (struct shash_desc *pdesc) +{ +return hmac_import (pdesc,crypto_shash_ctx_aligned (pdesc->tfm)); } static int hmac_update(struct shash_desc *pdesc,
@@ -111,16 +128,16 @@ static int hmac_update(struct shash_desc *pdesc,static int hmac_final (struct shash_desc *pdesc,u8 *out) {struct crypto_shash *parent = pdesc->tfm; -int bs =crypto_shash_blocksize (parent);int ds =crypto_shash_digestsize (parent); -char *opad =crypto_shash_ctx_aligned (parent) + bs; -char *digest = opad + bs; +int ss =crypto_shash_statesize (parent); +char *opad =crypto_shash_ctx_aligned (parent) + ss;struct shash_desc *desc =shash_desc_ctx (pdesc); desc->flags = pdesc->flags &CRYPTO_TFM_REQ_MAY_SLEEP ; -return crypto_shash_final (desc, digest) ?: -crypto_shash_digest (desc, opad, bs + ds, out); +return crypto_shash_final (desc, out) ?: +crypto_shash_import (desc, opad) ?: +crypto_shash_finup (desc, out, ds, out); } static int hmac_finup(struct shash_desc *pdesc, const u8 *data,
@@ -128,16 +145,16 @@ static int hmac_finup(struct shash_desc *pdesc, const u8 *data, {struct crypto_shash *parent = pdesc->tfm; -int bs =crypto_shash_blocksize (parent);int ds =crypto_shash_digestsize (parent); -char *opad =crypto_shash_ctx_aligned (parent) + bs; -char *digest = opad + bs; +int ss =crypto_shash_statesize (parent); +char *opad =crypto_shash_ctx_aligned (parent) + ss;struct shash_desc *desc =shash_desc_ctx (pdesc); desc->flags = pdesc->flags &CRYPTO_TFM_REQ_MAY_SLEEP ; -return crypto_shash_finup (desc, data, nbytes, digest) ?: -crypto_shash_digest (desc, opad, bs + ds, out); +return crypto_shash_finup (desc, data, nbytes, out) ?: +crypto_shash_import (desc, opad) ?: +crypto_shash_finup (desc, out, ds, out); }static int hmac_init_tfm (struct crypto_tfm *tfm)
@@ -155,21 +172,14 @@ static int hmac_init_tfm(struct crypto_tfm *tfm) parent->descsize =sizeof (struct shash_desc ) +crypto_shash_descsize (hash); - ctx->desc =kmalloc (parent->descsize,GFP_KERNEL ); -if (!ctx->desc) { -crypto_free_shash (hash); -return -ENOMEM ; - } - - ctx->desc->tfm = hash; + ctx->hash = hash;return 0 ; }static void hmac_exit_tfm (struct crypto_tfm *tfm) {struct hmac_ctx *ctx =hmac_ctx (__crypto_shash_cast (tfm)); -crypto_free_shash (ctx->desc->tfm); -kzfree (ctx->desc); +crypto_free_shash (ctx->hash); }static int hmac_create (struct crypto_template *tmpl,struct rtattr **tb)
@@ -179,6 +189,7 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb)struct shash_alg *salg;int err;int ds; +int ss; err =crypto_check_attr_type (tb,CRYPTO_ALG_TYPE_SHASH );if (err)
@@ -190,8 +201,10 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) err = -EINVAL ; ds = salg->digestsize; + ss = salg->statesize; alg = &salg->base; -if (ds > alg->cra_blocksize) +if (ds > alg->cra_blocksize || + ss < alg->cra_blocksize) goto out_put_alg; inst =shash_alloc_instance ("hmac" , alg);
@@ -208,11 +221,12 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.base.cra_blocksize = alg->cra_blocksize; inst->alg.base.cra_alignmask = alg->cra_alignmask; + ss =ALIGN (ss, alg->cra_alignmask +1 ); inst->alg.digestsize = ds; + inst->alg.statesize = ss; inst->alg.base.cra_ctxsize =sizeof (struct hmac_ctx ) + -ALIGN (alg->cra_blocksize *2 + ds, -crypto_tfm_ctx_alignment ()); +ALIGN (ss *2 ,crypto_tfm_ctx_alignment ()); inst->alg.base.cra_init = hmac_init_tfm; inst->alg.base.cra_exit = hmac_exit_tfm;
@@ -221,6 +235,8 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) inst->alg.update = hmac_update; inst->alg.final = hmac_final; inst->alg.finup = hmac_finup; + inst->alg.export = hmac_export; + inst->alg.import = hmac_import; inst->alg.setkey = hmac_setkey; err =shash_register_instance (tmpl, inst);
Thanks,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtQuoted 4 lines · Herbert Xu
Ah, that makes sense. I've done the prehash patch, let me know if this works.
Yes, it works.
Thanks!
Herbert Xu
maintainercrypto/authenc.c static void authenc_chain(struct scatterlist *head, struct scatterlist *sg, · line 139
Quoted 4 lines · Steffen Klassert
crypto/authenc.c +3
-0+ err =crypto_ahash_finup (ahreq); +if (err == -EINPROGRESS ) +return ;
This is redundant. All completion functions must expect to be called with EINPROGRESS followed by the actual completion later.
The same probably applies to other EINPROGRESS checks in this patch.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txtQuoted 8 lines · Herbert Xu
crypto/authenc.c static void authenc_chain(struct scatterlist *head, struct scatterlist *sg, · line 139
Quoted 4 lines · Steffen Klassert
crypto/authenc.c +3
-0+ err =crypto_ahash_finup (ahreq); +if (err == -EINPROGRESS ) +return ;This is redundant. All completion functions must expect to be called with EINPROGRESS followed by the actual completion later.
I copied this from crypto_authenc_encrypt_done(), so this is probaply redundant too. If so, I'd send a patch to remove the already existing checks too and put the updated ahash convertion patch on top of it.
Herbert Xu
maintainerQuoted 10 lines · Steffen Klassert
Quoted 8 lines · Herbert Xu
crypto/authenc.c static void authenc_chain(struct scatterlist *head, struct scatterlist *sg, · line 139
Quoted 4 lines · Steffen Klassert
crypto/authenc.c +3
-0+ err =crypto_ahash_finup (ahreq); +if (err == -EINPROGRESS ) +return ;This is redundant. All completion functions must expect to be called with EINPROGRESS followed by the actual completion later.
Quoted 3 lines
I copied this from
crypto_authenc_encrypt_done(), so this is probaply redundant too. If so, I'd send a patch to remove the already existing checks too and put the updated ahash convertion patch on top of it.
Hmm this check doesn't exist in my tree.
Cheers,
Signature · 4 lines
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt