2009-07-21 08:59:44

by Steffen Klassert

[permalink] [raw]
Subject: [PATCH v2] crypto: authenc - convert to ahash

This patch converts authenc to the new ahash interface.

Signed-off-by: Steffen Klassert <[email protected]>
---
crypto/authenc.c | 371 ++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 302 insertions(+), 69 deletions(-)

diff --git a/crypto/authenc.c b/crypto/authenc.c
index 2e16ce0..b9da719 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -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);
}

--
1.5.4.2



2009-07-21 12:22:35

by Steffen Klassert

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

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?


2009-07-21 13:07:27

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

On Tue, Jul 21, 2009 at 02:25:09PM +0200, Steffen Klassert wrote:
> 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.

> 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,
--
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

2009-07-21 13:20:36

by Steffen Klassert

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

On Tue, Jul 21, 2009 at 09:07:25PM +0800, Herbert Xu wrote:
> On Tue, Jul 21, 2009 at 02:25:09PM +0200, Steffen Klassert wrote:
> > 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.

>
> > 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.


2009-07-22 07:03:02

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

On Tue, Jul 21, 2009 at 11:02:17AM +0200, Steffen Klassert wrote:
>
> + 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,
--
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

2009-07-22 07:29:35

by Steffen Klassert

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

On Wed, Jul 22, 2009 at 03:02:59PM +0800, Herbert Xu wrote:
> On Tue, Jul 21, 2009 at 11:02:17AM +0200, Steffen Klassert wrote:
> >
> > + 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.

2009-07-22 07:52:03

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

On Wed, Jul 22, 2009 at 09:32:11AM +0200, Steffen Klassert wrote:
> On Wed, Jul 22, 2009 at 03:02:59PM +0800, Herbert Xu wrote:
> > On Tue, Jul 21, 2009 at 11:02:17AM +0200, Steffen Klassert wrote:
> > >
> > > + 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.

Hmm this check doesn't exist in my tree.

Cheers,
--
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

2009-07-23 10:20:40

by Steffen Klassert

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

On Tue, Jul 21, 2009 at 09:07:25PM +0800, Herbert Xu wrote:
> On Tue, Jul 21, 2009 at 02:25:09PM +0200, Steffen Klassert wrote:
> > 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.

2009-07-24 07:23:14

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

On Thu, Jul 23, 2009 at 12:23:14PM +0200, Steffen Klassert wrote:
>
> 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.

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.

Signed-off-by: Herbert Xu <[email protected]>

diff --git a/crypto/hmac.c b/crypto/hmac.c
index 02aa53e..15c2eb5 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -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,
--
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

2009-07-24 08:29:34

by Steffen Klassert

[permalink] [raw]
Subject: Re: [PATCH v2] crypto: authenc - convert to ahash

On Fri, Jul 24, 2009 at 03:23:11PM +0800, Herbert Xu wrote:
>
> Ah, that makes sense. I've done the prehash patch, let me know
> if this works.
>

Yes, it works.

Thanks!