X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=crypto%2Fgcm.c;h=d60c340b0b9dc7e18f0144ca0a1b5ccde75865ef;hb=fe70f5dfe1a7b5caab96531089dac3d8728c0ebd;hp=ad8b8b9aeef2bc051bc01043baabf707f37eff32;hpb=28db8e3e38e593d22e2c69942bb1ca7be2a35f05;p=powerpc.git diff --git a/crypto/gcm.c b/crypto/gcm.c index ad8b8b9aee..d60c340b0b 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -36,6 +36,7 @@ struct crypto_gcm_ghash_ctx { struct crypto_gcm_req_priv_ctx { u8 auth_tag[16]; + u8 iauth_tag[16]; u8 counter[16]; struct crypto_gcm_ghash_ctx ghash; }; @@ -89,6 +90,9 @@ static void crypto_gcm_ghash_update_sg(struct crypto_gcm_ghash_ctx *ctx, u8 *src; int n; + if (!len) + return; + scatterwalk_start(&walk, sg); while (len) { @@ -211,9 +215,10 @@ static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key, } static int crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req, - struct aead_request *req, - void (*done)(struct crypto_async_request *, - int)) + struct aead_request *req, + unsigned int cryptlen, + void (*done)(struct crypto_async_request *, + int)) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead); @@ -228,7 +233,7 @@ static int crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req, ablkcipher_request_set_callback(ablk_req, aead_request_flags(req), done, req); ablkcipher_request_set_crypt(ablk_req, req->src, req->dst, - req->cryptlen, counter); + cryptlen, counter); err = crypto_gcm_encrypt_counter(aead, auth_tag, 0, req->iv); if (err) @@ -239,18 +244,16 @@ static int crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req, crypto_gcm_ghash_init(ghash, flags, ctx->gf128); - if (req->assoclen) { - crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen); - crypto_gcm_ghash_flush(ghash); - } + crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen); + crypto_gcm_ghash_flush(ghash); out: return err; } -static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err) +static int crypto_gcm_hash(struct aead_request *req) { - struct aead_request *req = areq->data; + struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_gcm_req_priv_ctx *pctx = aead_request_ctx(req); u8 *auth_tag = pctx->auth_tag; struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; @@ -259,18 +262,28 @@ static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err) crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen, auth_tag); + scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen, + crypto_aead_authsize(aead), 1); + return 0; +} + +static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err) +{ + struct aead_request *req = areq->data; + + if (!err) + err = crypto_gcm_hash(req); + aead_request_complete(req, err); } static int crypto_gcm_encrypt(struct aead_request *req) { struct ablkcipher_request abreq; - struct crypto_gcm_req_priv_ctx *pctx = aead_request_ctx(req); - u8 *auth_tag = pctx->auth_tag; - struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; int err = 0; - err = crypto_gcm_init_crypt(&abreq, req, crypto_gcm_encrypt_done); + err = crypto_gcm_init_crypt(&abreq, req, req->cryptlen, + crypto_gcm_encrypt_done); if (err) return err; @@ -278,14 +291,9 @@ static int crypto_gcm_encrypt(struct aead_request *req) err = crypto_ablkcipher_encrypt(&abreq); if (err) return err; - - crypto_gcm_ghash_update_sg(ghash, req->dst, req->cryptlen); } - crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen, - auth_tag); - - return err; + return crypto_gcm_hash(req); } static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err) @@ -296,26 +304,30 @@ static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err) static int crypto_gcm_decrypt(struct aead_request *req) { struct ablkcipher_request abreq; + struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_gcm_req_priv_ctx *pctx = aead_request_ctx(req); u8 *auth_tag = pctx->auth_tag; + u8 *iauth_tag = pctx->iauth_tag; struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; - u8 tag[16]; + unsigned int cryptlen = req->cryptlen; + unsigned int authsize = crypto_aead_authsize(aead); int err; - if (!req->cryptlen) + if (cryptlen < authsize) return -EINVAL; + cryptlen -= authsize; - memcpy(tag, auth_tag, 16); - err = crypto_gcm_init_crypt(&abreq, req, crypto_gcm_decrypt_done); + err = crypto_gcm_init_crypt(&abreq, req, cryptlen, + crypto_gcm_decrypt_done); if (err) return err; - crypto_gcm_ghash_update_sg(ghash, req->src, req->cryptlen); - crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen, - auth_tag); + crypto_gcm_ghash_update_sg(ghash, req->src, cryptlen); + crypto_gcm_ghash_final_xor(ghash, req->assoclen, cryptlen, auth_tag); - if (memcmp(tag, auth_tag, 16)) - return -EINVAL; + scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0); + if (memcmp(iauth_tag, auth_tag, authsize)) + return -EBADMSG; return crypto_ablkcipher_decrypt(&abreq); } @@ -414,7 +426,7 @@ static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) inst->alg.cra_alignmask = __alignof__(u32) - 1; inst->alg.cra_type = &crypto_aead_type; inst->alg.cra_aead.ivsize = 12; - inst->alg.cra_aead.authsize = 16; + inst->alg.cra_aead.maxauthsize = 16; inst->alg.cra_ctxsize = sizeof(struct crypto_gcm_ctx); inst->alg.cra_init = crypto_gcm_init_tfm; inst->alg.cra_exit = crypto_gcm_exit_tfm;