// SPDX-License-Identifier: GPL-2.0-only
/*
* GCM: Galois/Counter Mode.
*
* Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
*/
#include <crypto/gf128mul.h>
#include <crypto/internal/aead.h>
#include <crypto/internal/skcipher.h>
#include <crypto/internal/hash.h>
#include <crypto/null.h>
#include <crypto/scatterwalk.h>
#include <crypto/gcm.h>
#include <crypto/hash.h>
#include "internal.h"
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
struct gcm_instance_ctx {
struct crypto_skcipher_spawn ctr;
struct crypto_ahash_spawn ghash;
};
struct crypto_gcm_ctx {
struct crypto_skcipher *ctr;
struct crypto_ahash *ghash;
};
struct crypto_rfc4106_ctx {
struct crypto_aead *child;
u8 nonce[4];
};
struct crypto_rfc4106_req_ctx {
struct scatterlist src[3];
struct scatterlist dst[3];
struct aead_request subreq;
};
struct crypto_rfc4543_instance_ctx {
struct crypto_aead_spawn aead;
};
struct crypto_rfc4543_ctx {
struct crypto_aead *child;
struct crypto_sync_skcipher *null;
u8 nonce[4];
};
struct crypto_rfc4543_req_ctx {
struct aead_request subreq;
};
struct crypto_gcm_ghash_ctx {
unsigned int cryptlen;
struct scatterlist *src;
int (*complete)(struct aead_request *req, u32 flags);
};
struct crypto_gcm_req_priv_ctx {
u8 iv[16];
u8 auth_tag[16];
u8 iauth_tag[16];
struct scatterlist src[3];
struct scatterlist dst[3];
struct scatterlist sg;
struct crypto_gcm_ghash_ctx ghash_ctx;
union {
struct ahash_request ahreq;
struct skcipher_request skreq;
} u;
};
static struct {
u8 buf[16];
struct scatterlist sg;
} *gcm_zeroes;
static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc);
static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx(
struct aead_request *req)
{
unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
}
static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
unsigned int keylen)
{
struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
struct crypto_ahash *ghash = ctx->ghash;
struct crypto_skcipher *ctr = ctx->ctr;
struct {
be128 hash;
u8 iv[16];
struct crypto_wait wait;
struct scatterlist sg[1];
struct skcipher_request req;
} *data;
int err;
crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
CRYPTO_TFM_REQ_MASK);
err = crypto_skcipher_setkey(ctr, key, keylen);
crypto_aead_set_flags(aead, crypto_skcipher_get_flags(ctr) &
CRYPTO_TFM_RES_MASK);
if (err)
return err;
data = kzalloc(sizeof(*data) + crypto_skcipher_reqsize(ctr),
GFP_KERNEL);
if (!data)
return -ENOMEM;
crypto_init_wait(&data->wait);
sg_init_one(data->sg, &data->hash