+u8 auth_tag[16];
This field needs to be aligned to whatever alignment needed by
the underlying cipher algorithm (currently the biggest is padlock
which needs 16-byte alignment).
Didn't realize that, thanks. I fixed the aligning according to
how it's done in GCM.
Regards,
Tobias
-8-8-
This patch adds the RFC4543 (GMAC) wrapper for GCM similar to the
existing RFC4106 wrapper. The main differences between GCM and GMAC are
the contents of the AAD and that the plaintext is empty for the latter.
Signed-off-by: Tobias Brunner tob...@strongswan.org
---
crypto/gcm.c| 287 +++
include/linux/pfkeyv2.h |1 +
net/xfrm/xfrm_algo.c| 16 +++
3 files changed, 304 insertions(+), 0 deletions(-)
diff --git a/crypto/gcm.c b/crypto/gcm.c
index 5fc3292..7d3fba8 100644
--- a/crypto/gcm.c
+++ b/crypto/gcm.c
@@ -37,6 +37,19 @@ struct crypto_rfc4106_ctx {
u8 nonce[4];
};
+struct crypto_rfc4543_ctx {
+ struct crypto_aead *child;
+ u8 nonce[4];
+};
+
+struct crypto_rfc4543_req_ctx {
+ u8 auth_tag[16];
+ struct scatterlist cipher[1];
+ struct scatterlist payload[2];
+ struct scatterlist assoc[2];
+ struct aead_request subreq;
+};
+
struct crypto_gcm_ghash_ctx {
unsigned int cryptlen;
struct scatterlist *src;
@@ -1008,6 +1021,272 @@ static struct crypto_template crypto_rfc4106_tmpl = {
.module = THIS_MODULE,
};
+static inline struct crypto_rfc4543_req_ctx *crypto_rfc4543_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_rfc4543_setkey(struct crypto_aead *parent, const u8 *key,
+unsigned int keylen)
+{
+ struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent);
+ struct crypto_aead *child = ctx-child;
+ int err;
+
+ if (keylen 4)
+ return -EINVAL;
+
+ keylen -= 4;
+ memcpy(ctx-nonce, key + keylen, 4);
+
+ crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_aead_set_flags(child, crypto_aead_get_flags(parent)
+CRYPTO_TFM_REQ_MASK);
+ err = crypto_aead_setkey(child, key, keylen);
+ crypto_aead_set_flags(parent, crypto_aead_get_flags(child)
+ CRYPTO_TFM_RES_MASK);
+
+ return err;
+}
+
+static int crypto_rfc4543_setauthsize(struct crypto_aead *parent,
+ unsigned int authsize)
+{
+ struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent);
+
+ if (authsize != 16)
+ return -EINVAL;
+
+ return crypto_aead_setauthsize(ctx-child, authsize);
+}
+
+/* this is the same as crypto_authenc_chain */
+static void crypto_rfc4543_chain(struct scatterlist *head,
+struct scatterlist *sg, int chain)
+{
+ if (chain) {
+ head-length += sg-length;
+ sg = scatterwalk_sg_next(sg);
+ }
+
+ if (sg)
+ scatterwalk_sg_chain(head, 2, sg);
+ else
+ sg_mark_end(head);
+}
+
+static struct aead_request *crypto_rfc4543_crypt(struct aead_request *req,
+int enc)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
+ struct crypto_rfc4543_req_ctx *rctx = crypto_rfc4543_reqctx(req);
+ struct aead_request *subreq = rctx-subreq;
+ struct scatterlist *dst = req-dst;
+ struct scatterlist *cipher = rctx-cipher;
+ struct scatterlist *payload = rctx-payload;
+ struct scatterlist *assoc = rctx-assoc;
+ unsigned int authsize = crypto_aead_authsize(aead);
+ unsigned int assoclen = req-assoclen;
+ struct page *dstp;
+ u8 *vdst;
+ u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx-child),
+ crypto_aead_alignmask(ctx-child) + 1);
+
+ memcpy(iv, ctx-nonce, 4);
+ memcpy(iv + 4, req-iv, 8);
+
+ /* construct cipher/plaintext */
+ if (enc)
+ memset(rctx-auth_tag, 0, authsize);
+ else
+ scatterwalk_map_and_copy(rctx-auth_tag, dst,
+req-cryptlen - authsize,
+authsize, 0);
+
+ sg_init_one(cipher, rctx-auth_tag, authsize);
+
+ /* construct the aad */
+ dstp = sg_page(dst);
+ vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + dst-offset;
+
+ sg_init_table(payload, 2);
+ sg_set_buf(payload, req-iv, 8);
+ crypto_rfc4543_chain(payload, dst, vdst == req-iv + 8);
+ assoclen += 8 + req-cryptlen - (enc ? 0 : authsize);
+
+ sg_init_table(assoc, 2);
+