static int crypto_gcm_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); struct ablkcipher_request *abreq = &pctx->u.abreq; struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; unsigned int authsize = crypto_aead_authsize(aead); unsigned int cryptlen = req->cryptlen; int err; if (cryptlen < authsize) return -EINVAL; cryptlen -= authsize; gctx->src = req->src; gctx->cryptlen = cryptlen; gctx->complete = gcm_dec_hash_done; err = gcm_hash(req, pctx); if (err) return err; ablkcipher_request_set_callback(abreq, aead_request_flags(req), gcm_decrypt_done, req); crypto_gcm_init_crypt(abreq, req, cryptlen); err = crypto_ablkcipher_decrypt(abreq); if (err) return err; return crypto_gcm_verify(req, pctx); }
static int pcrypt_aead_givencrypt(struct aead_givcrypt_request *req) { int err; struct aead_request *areq = &req->areq; struct pcrypt_request *preq = aead_request_ctx(areq); struct aead_givcrypt_request *creq = pcrypt_request_ctx(preq); struct padata_priv *padata = pcrypt_request_padata(preq); struct crypto_aead *aead = aead_givcrypt_reqtfm(req); struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(aead); u32 flags = aead_request_flags(areq); memset(padata, 0, sizeof(struct padata_priv)); padata->parallel = pcrypt_aead_givenc; padata->serial = pcrypt_aead_giv_serial; aead_givcrypt_set_tfm(creq, ctx->child); aead_givcrypt_set_callback(creq, flags & ~CRYPTO_TFM_REQ_MAY_SLEEP, pcrypt_aead_done, areq); aead_givcrypt_set_crypt(creq, areq->src, areq->dst, areq->cryptlen, areq->iv); aead_givcrypt_set_assoc(creq, areq->assoc, areq->assoclen); aead_givcrypt_set_giv(creq, req->giv, req->seq); err = pcrypt_do_parallel(padata, &ctx->cb_cpu, &pencrypt); if (!err) return -EINPROGRESS; return err; }
static int crypto_gcm_encrypt(struct aead_request *req) { struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); struct ablkcipher_request *abreq = &pctx->u.abreq; struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; int err; crypto_gcm_init_crypt(abreq, req, req->cryptlen); ablkcipher_request_set_callback(abreq, aead_request_flags(req), gcm_encrypt_done, req); gctx->src = req->dst; gctx->cryptlen = req->cryptlen; gctx->complete = gcm_enc_hash_done; err = crypto_ablkcipher_encrypt(abreq); if (err) return err; err = gcm_hash(req, pctx); if (err) return err; crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16); gcm_enc_copy_hash(req, pctx); return 0; }
static int crypto_gcm_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); struct ablkcipher_request *abreq = &pctx->abreq; struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash; unsigned int cryptlen = req->cryptlen; unsigned int authsize = crypto_aead_authsize(aead); int err; if (cryptlen < authsize) return -EINVAL; cryptlen -= authsize; crypto_gcm_init_crypt(abreq, req, cryptlen); ablkcipher_request_set_callback(abreq, aead_request_flags(req), crypto_gcm_decrypt_done, req); crypto_gcm_ghash_update_sg(ghash, req->src, cryptlen); err = crypto_ablkcipher_decrypt(abreq); if (err) return err; return crypto_gcm_verify(req); }
static int crypto_ccm_init_crypt(struct aead_request *req, u8 *tag) { struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); struct scatterlist *sg; u8 *iv = req->iv; int err; err = crypto_ccm_check_iv(iv); if (err) return err; pctx->flags = aead_request_flags(req); /* Note: rfc 3610 and NIST 800-38C require counter of * zero to encrypt auth tag. */ memset(iv + 15 - iv[0], 0, iv[0] + 1); sg_init_table(pctx->src, 3); sg_set_buf(pctx->src, tag, 16); sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen); if (sg != pctx->src + 1) sg_chain(pctx->src, 2, sg); if (req->src != req->dst) { sg_init_table(pctx->dst, 3); sg_set_buf(pctx->dst, tag, 16); sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen); if (sg != pctx->dst + 1) sg_chain(pctx->dst, 2, sg); } return 0; }
static int crypto_ccm_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead); struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); struct ablkcipher_request *abreq = &pctx->abreq; struct scatterlist *dst; unsigned int authsize = crypto_aead_authsize(aead); unsigned int cryptlen = req->cryptlen; u8 *authtag = pctx->auth_tag; u8 *odata = pctx->odata; u8 *iv = req->iv; int err; if (cryptlen < authsize) return -EINVAL; cryptlen -= authsize; err = crypto_ccm_check_iv(iv); if (err) return err; pctx->flags = aead_request_flags(req); scatterwalk_map_and_copy(authtag, req->src, cryptlen, authsize, 0); memset(iv + 15 - iv[0], 0, iv[0] + 1); sg_init_table(pctx->src, 2); sg_set_buf(pctx->src, authtag, 16); scatterwalk_sg_chain(pctx->src, 2, req->src); dst = pctx->src; if (req->src != req->dst) { sg_init_table(pctx->dst, 2); sg_set_buf(pctx->dst, authtag, 16); scatterwalk_sg_chain(pctx->dst, 2, req->dst); dst = pctx->dst; } ablkcipher_request_set_tfm(abreq, ctx->ctr); ablkcipher_request_set_callback(abreq, pctx->flags, crypto_ccm_decrypt_done, req); ablkcipher_request_set_crypt(abreq, pctx->src, dst, cryptlen + 16, iv); err = crypto_ablkcipher_decrypt(abreq); if (err) return err; err = crypto_ccm_auth(req, req->dst, cryptlen); if (err) return err; /* verify */ if (crypto_memneq(authtag, odata, authsize)) return -EBADMSG; return err; }
static int gcm_hash_final(struct aead_request *req, struct crypto_gcm_req_priv_ctx *pctx) { struct ahash_request *ahreq = &pctx->u.ahreq; ahash_request_set_callback(ahreq, aead_request_flags(req), gcm_hash_final_done, req); ahash_request_set_crypt(ahreq, NULL, pctx->iauth_tag, 0); return crypto_ahash_final(ahreq); }
static int crypto_ccm_encrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); struct crypto_ccm_ctx *ctx = crypto_aead_ctx(aead); struct crypto_ccm_req_priv_ctx *pctx = crypto_ccm_reqctx(req); struct ablkcipher_request *abreq = &pctx->abreq; struct scatterlist *dst; unsigned int cryptlen = req->cryptlen; u8 *odata = pctx->odata; u8 *iv = req->iv; int err; err = crypto_ccm_check_iv(iv); if (err) return err; pctx->flags = aead_request_flags(req); err = crypto_ccm_auth(req, req->src, cryptlen); if (err) return err; /* Note: rfc 3610 and NIST 800-38C require counter of * zero to encrypt auth tag. */ memset(iv + 15 - iv[0], 0, iv[0] + 1); sg_init_table(pctx->src, 2); sg_set_buf(pctx->src, odata, 16); scatterwalk_sg_chain(pctx->src, 2, req->src); dst = pctx->src; if (req->src != req->dst) { sg_init_table(pctx->dst, 2); sg_set_buf(pctx->dst, odata, 16); scatterwalk_sg_chain(pctx->dst, 2, req->dst); dst = pctx->dst; } ablkcipher_request_set_tfm(abreq, ctx->ctr); ablkcipher_request_set_callback(abreq, pctx->flags, crypto_ccm_encrypt_done, req); ablkcipher_request_set_crypt(abreq, pctx->src, dst, cryptlen + 16, iv); err = crypto_ablkcipher_encrypt(abreq); if (err) return err; /* copy authtag to end of dst */ scatterwalk_map_and_copy(odata, req->dst, cryptlen, crypto_aead_authsize(aead), 1); return err; }
static int gcm_hash_remain(struct aead_request *req, struct crypto_gcm_req_priv_ctx *pctx, unsigned int remain, crypto_completion_t compl) { struct ahash_request *ahreq = &pctx->u.ahreq; ahash_request_set_callback(ahreq, aead_request_flags(req), compl, req); sg_init_one(pctx->src, gcm_zeroes, remain); ahash_request_set_crypt(ahreq, pctx->src, NULL, remain); return crypto_ahash_update(ahreq); }
static int gcm_hash_update(struct aead_request *req, struct crypto_gcm_req_priv_ctx *pctx, crypto_completion_t compl, struct scatterlist *src, unsigned int len) { struct ahash_request *ahreq = &pctx->u.ahreq; ahash_request_set_callback(ahreq, aead_request_flags(req), compl, req); ahash_request_set_crypt(ahreq, src, NULL, len); return crypto_ahash_update(ahreq); }
static int gcm_hash(struct aead_request *req, struct crypto_gcm_req_priv_ctx *pctx) { struct ahash_request *ahreq = &pctx->u.ahreq; struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(req->base.tfm); unsigned int remain; crypto_completion_t compl; int err; ahash_request_set_tfm(ahreq, ctx->ghash); ahash_request_set_callback(ahreq, aead_request_flags(req), gcm_hash_init_done, req); err = crypto_ahash_init(ahreq); if (err) return err; remain = gcm_remain(req->assoclen); compl = remain ? gcm_hash_assoc_done : gcm_hash_assoc_remain_done; err = gcm_hash_update(req, pctx, compl, req->assoc, req->assoclen); if (err) return err; if (remain) { err = gcm_hash_remain(req, pctx, remain, gcm_hash_assoc_remain_done); if (err) return err; } remain = gcm_remain(gctx->cryptlen); compl = remain ? gcm_hash_crypt_done : gcm_hash_crypt_remain_done; err = gcm_hash_update(req, pctx, compl, gctx->src, gctx->cryptlen); if (err) return err; if (remain) { err = gcm_hash_remain(req, pctx, remain, gcm_hash_crypt_remain_done); if (err) return err; } err = gcm_hash_len(req, pctx); if (err) return err; err = gcm_hash_final(req, pctx); if (err) return err; return 0; }
static int crypto_gcm_encrypt(struct aead_request *req) { struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); struct ablkcipher_request *abreq = &pctx->abreq; int err; crypto_gcm_init_crypt(abreq, req, req->cryptlen); ablkcipher_request_set_callback(abreq, aead_request_flags(req), crypto_gcm_encrypt_done, req); err = crypto_ablkcipher_encrypt(abreq); if (err) return err; return crypto_gcm_hash(req); }
static int gcm_hash_len(struct aead_request *req, struct crypto_gcm_req_priv_ctx *pctx) { struct ahash_request *ahreq = &pctx->u.ahreq; struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; u128 lengths; lengths.a = cpu_to_be64(req->assoclen * 8); lengths.b = cpu_to_be64(gctx->cryptlen * 8); memcpy(pctx->iauth_tag, &lengths, 16); sg_init_one(pctx->src, pctx->iauth_tag, 16); ahash_request_set_callback(ahreq, aead_request_flags(req), gcm_hash_len_done, req); ahash_request_set_crypt(ahreq, pctx->src, NULL, sizeof(lengths)); return crypto_ahash_update(ahreq); }
static void gcm_dec_hash_done(struct crypto_async_request *areq, int err) { struct aead_request *req = areq->data; struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req); struct ablkcipher_request *abreq = &pctx->u.abreq; struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx; if (!err) { ablkcipher_request_set_callback(abreq, aead_request_flags(req), gcm_decrypt_done, req); crypto_gcm_init_crypt(abreq, req, gctx->cryptlen); err = crypto_ablkcipher_decrypt(abreq); if (err == -EINPROGRESS || err == -EBUSY) return; } gcm_decrypt_done(areq, err); }