summaryrefslogtreecommitdiffstats
path: root/crypto/aead.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2015-05-21 15:11:01 +0800
committerHerbert Xu <herbert@gondor.apana.org.au>2015-05-22 11:25:51 +0800
commit996d98d85ccc27d9c592ad7dc1371c60cd6585cc (patch)
treea7f9c96dc0ec10e5761495fc2116d4d3364705bd /crypto/aead.c
parentfc42bcba97bae738f905b83741134a63af7e6c02 (diff)
downloadlinux-996d98d85ccc27d9c592ad7dc1371c60cd6585cc.tar.bz2
crypto: aead - Add new interface with single SG list
The primary user of AEAD, IPsec includes the IV in the AD in most cases, except where it is implicitly authenticated by the underlying algorithm. The way it is currently implemented is a hack because we pass the data in piecemeal and the underlying algorithms try to stitch them back up into one piece. This is why this patch is adding a new interface that allows a single SG list to be passed in that contains everything so the algorithm implementors do not have to stitch. The new interface accepts a single source SG list and a single destination SG list. Both must be laid out as follows: AD, skipped data, plain/cipher text, ICV The ICV is not present from the source during encryption and from the destination during decryption. For the top-level IPsec AEAD algorithm the plain/cipher text will contain the generated (or received) IV. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/aead.c')
-rw-r--r--crypto/aead.c58
1 files changed, 56 insertions, 2 deletions
diff --git a/crypto/aead.c b/crypto/aead.c
index 717b2f6ec9bb..c2bf3b313354 100644
--- a/crypto/aead.c
+++ b/crypto/aead.c
@@ -13,6 +13,7 @@
*/
#include <crypto/internal/aead.h>
+#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -85,6 +86,59 @@ int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
}
EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
+struct aead_old_request {
+ struct scatterlist srcbuf[2];
+ struct scatterlist dstbuf[2];
+ struct aead_request subreq;
+};
+
+unsigned int crypto_aead_reqsize(struct crypto_aead *tfm)
+{
+ return tfm->reqsize + sizeof(struct aead_old_request);
+}
+EXPORT_SYMBOL_GPL(crypto_aead_reqsize);
+
+static int old_crypt(struct aead_request *req,
+ int (*crypt)(struct aead_request *req))
+{
+ struct aead_old_request *nreq = aead_request_ctx(req);
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct scatterlist *src, *dst;
+
+ if (req->old)
+ return crypt(req);
+
+ src = scatterwalk_ffwd(nreq->srcbuf, req->src,
+ req->assoclen + req->cryptoff);
+ dst = scatterwalk_ffwd(nreq->dstbuf, req->dst,
+ req->assoclen + req->cryptoff);
+
+ aead_request_set_tfm(&nreq->subreq, aead);
+ aead_request_set_callback(&nreq->subreq, aead_request_flags(req),
+ req->base.complete, req->base.data);
+ aead_request_set_crypt(&nreq->subreq, src, dst, req->cryptlen,
+ req->iv);
+ aead_request_set_assoc(&nreq->subreq, req->src, req->assoclen);
+
+ return crypt(&nreq->subreq);
+}
+
+static int old_encrypt(struct aead_request *req)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct aead_alg *alg = crypto_aead_alg(aead);
+
+ return old_crypt(req, alg->encrypt);
+}
+
+static int old_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ struct aead_alg *alg = crypto_aead_alg(aead);
+
+ return old_crypt(req, alg->decrypt);
+}
+
static int no_givcrypt(struct aead_givcrypt_request *req)
{
return -ENOSYS;
@@ -98,8 +152,8 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm)
if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
return -EINVAL;
- crt->encrypt = alg->encrypt;
- crt->decrypt = alg->decrypt;
+ crt->encrypt = old_encrypt;
+ crt->decrypt = old_decrypt;
if (alg->ivsize) {
crt->givencrypt = alg->givencrypt ?: no_givcrypt;
crt->givdecrypt = alg->givdecrypt ?: no_givcrypt;