From f01465930dd5bc79cc2581a857f431222a5efe4d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 23 Apr 2015 16:37:46 +0800 Subject: crypto: aead - Fix corner case in crypto_lookup_aead When the user explicitly states that they don't care whether the algorithm has been tested (type = CRYPTO_ALG_TESTED and mask = 0), there is a corner case where we may erroneously return ENOENT. This patch fixes it by correcting the logic in the test. Signed-off-by: Herbert Xu --- crypto/aead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index 22227107..d6ad0c66 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -489,7 +489,7 @@ struct crypto_alg *crypto_lookup_aead(const char *name, u32 type, u32 mask) return alg; if (alg->cra_type == &crypto_aead_type) { - if ((alg->cra_flags ^ type ^ ~mask) & CRYPTO_ALG_TESTED) { + if (~alg->cra_flags & (type ^ ~mask) & CRYPTO_ALG_TESTED) { crypto_mod_put(alg); alg = ERR_PTR(-ENOENT); } -- cgit v1.2.3 From a332b55bbe239459983c968ae3dda77bef9fdd07 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 11 May 2015 17:48:12 +0800 Subject: crypto: aead - Convert top level interface to new style This patch converts the top-level aead interface to the new style. All user-level AEAD interface code have been moved into crypto/aead.h. The allocation/free functions have switched over to the new way of allocating tfms. This patch also removes the double indrection on setkey so the indirection now exists only at the alg level. Apart from these there are no user-visible changes. Signed-off-by: Herbert Xu --- crypto/aead.c | 161 +++++++++++++++++----------------------------------------- 1 file changed, 48 insertions(+), 113 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index d6ad0c66..717b2f6e 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -26,6 +26,9 @@ #include "internal.h" +static int aead_null_givencrypt(struct aead_givcrypt_request *req); +static int aead_null_givdecrypt(struct aead_givcrypt_request *req); + static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { @@ -48,63 +51,63 @@ static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, return ret; } -static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) +int crypto_aead_setkey(struct crypto_aead *tfm, + const u8 *key, unsigned int keylen) { struct aead_alg *aead = crypto_aead_alg(tfm); unsigned long alignmask = crypto_aead_alignmask(tfm); + tfm = tfm->child; + if ((unsigned long)key & alignmask) return setkey_unaligned(tfm, key, keylen); return aead->setkey(tfm, key, keylen); } +EXPORT_SYMBOL_GPL(crypto_aead_setkey); int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) { - struct aead_tfm *crt = crypto_aead_crt(tfm); int err; if (authsize > crypto_aead_alg(tfm)->maxauthsize) return -EINVAL; if (crypto_aead_alg(tfm)->setauthsize) { - err = crypto_aead_alg(tfm)->setauthsize(crt->base, authsize); + err = crypto_aead_alg(tfm)->setauthsize(tfm->child, authsize); if (err) return err; } - crypto_aead_crt(crt->base)->authsize = authsize; - crt->authsize = authsize; + tfm->child->authsize = authsize; + tfm->authsize = authsize; return 0; } EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); -static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type, - u32 mask) -{ - return alg->cra_ctxsize; -} - static int no_givcrypt(struct aead_givcrypt_request *req) { return -ENOSYS; } -static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +static int crypto_aead_init_tfm(struct crypto_tfm *tfm) { struct aead_alg *alg = &tfm->__crt_alg->cra_aead; - struct aead_tfm *crt = &tfm->crt_aead; + struct crypto_aead *crt = __crypto_aead_cast(tfm); if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) return -EINVAL; - crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ? - alg->setkey : setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; - crt->givencrypt = alg->givencrypt ?: no_givcrypt; - crt->givdecrypt = alg->givdecrypt ?: no_givcrypt; - crt->base = __crypto_aead_cast(tfm); + if (alg->ivsize) { + crt->givencrypt = alg->givencrypt ?: no_givcrypt; + crt->givdecrypt = alg->givdecrypt ?: no_givcrypt; + } else { + crt->givencrypt = aead_null_givencrypt; + crt->givdecrypt = aead_null_givdecrypt; + } + crt->child = __crypto_aead_cast(tfm); crt->ivsize = alg->ivsize; crt->authsize = alg->maxauthsize; @@ -155,12 +158,17 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) } const struct crypto_type crypto_aead_type = { - .ctxsize = crypto_aead_ctxsize, - .init = crypto_init_aead_ops, + .extsize = crypto_alg_extsize, + .init_tfm = crypto_aead_init_tfm, #ifdef CONFIG_PROC_FS .show = crypto_aead_show, #endif .report = crypto_aead_report, + .lookup = crypto_lookup_aead, + .maskclear = ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV), + .maskset = CRYPTO_ALG_TYPE_MASK, + .type = CRYPTO_ALG_TYPE_AEAD, + .tfmsize = offsetof(struct crypto_aead, base), }; EXPORT_SYMBOL_GPL(crypto_aead_type); @@ -174,28 +182,6 @@ static int aead_null_givdecrypt(struct aead_givcrypt_request *req) return crypto_aead_decrypt(&req->areq); } -static int crypto_init_nivaead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) -{ - struct aead_alg *alg = &tfm->__crt_alg->cra_aead; - struct aead_tfm *crt = &tfm->crt_aead; - - if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) - return -EINVAL; - - crt->setkey = setkey; - crt->encrypt = alg->encrypt; - crt->decrypt = alg->decrypt; - if (!alg->ivsize) { - crt->givencrypt = aead_null_givencrypt; - crt->givdecrypt = aead_null_givdecrypt; - } - crt->base = __crypto_aead_cast(tfm); - crt->ivsize = alg->ivsize; - crt->authsize = alg->maxauthsize; - - return 0; -} - #ifdef CONFIG_NET static int crypto_nivaead_report(struct sk_buff *skb, struct crypto_alg *alg) { @@ -241,32 +227,24 @@ static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg) } const struct crypto_type crypto_nivaead_type = { - .ctxsize = crypto_aead_ctxsize, - .init = crypto_init_nivaead_ops, + .extsize = crypto_alg_extsize, + .init_tfm = crypto_aead_init_tfm, #ifdef CONFIG_PROC_FS .show = crypto_nivaead_show, #endif .report = crypto_nivaead_report, + .maskclear = ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV), + .maskset = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV, + .type = CRYPTO_ALG_TYPE_AEAD, + .tfmsize = offsetof(struct crypto_aead, base), }; EXPORT_SYMBOL_GPL(crypto_nivaead_type); static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn, const char *name, u32 type, u32 mask) { - struct crypto_alg *alg; - int err; - - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); - type |= CRYPTO_ALG_TYPE_AEAD; - mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV; - - alg = crypto_alg_mod_lookup(name, type, mask); - if (IS_ERR(alg)) - return PTR_ERR(alg); - - err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask); - crypto_mod_put(alg); - return err; + spawn->base.frontend = &crypto_nivaead_type; + return crypto_grab_spawn(&spawn->base, name, type, mask); } struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl, @@ -374,14 +352,17 @@ EXPORT_SYMBOL_GPL(aead_geniv_free); int aead_geniv_init(struct crypto_tfm *tfm) { struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_aead *child; struct crypto_aead *aead; - aead = crypto_spawn_aead(crypto_instance_ctx(inst)); - if (IS_ERR(aead)) - return PTR_ERR(aead); + aead = __crypto_aead_cast(tfm); - tfm->crt_aead.base = aead; - tfm->crt_aead.reqsize += crypto_aead_reqsize(aead); + child = crypto_spawn_aead(crypto_instance_ctx(inst)); + if (IS_ERR(child)) + return PTR_ERR(child); + + aead->child = child; + aead->reqsize += crypto_aead_reqsize(child); return 0; } @@ -389,7 +370,7 @@ EXPORT_SYMBOL_GPL(aead_geniv_init); void aead_geniv_exit(struct crypto_tfm *tfm) { - crypto_free_aead(tfm->crt_aead.base); + crypto_free_aead(__crypto_aead_cast(tfm)->child); } EXPORT_SYMBOL_GPL(aead_geniv_exit); @@ -505,60 +486,14 @@ EXPORT_SYMBOL_GPL(crypto_lookup_aead); int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name, u32 type, u32 mask) { - struct crypto_alg *alg; - int err; - - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); - type |= CRYPTO_ALG_TYPE_AEAD; - mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); - mask |= CRYPTO_ALG_TYPE_MASK; - - alg = crypto_lookup_aead(name, type, mask); - if (IS_ERR(alg)) - return PTR_ERR(alg); - - err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask); - crypto_mod_put(alg); - return err; + spawn->base.frontend = &crypto_aead_type; + return crypto_grab_spawn(&spawn->base, name, type, mask); } EXPORT_SYMBOL_GPL(crypto_grab_aead); struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask) { - struct crypto_tfm *tfm; - int err; - - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); - type |= CRYPTO_ALG_TYPE_AEAD; - mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); - mask |= CRYPTO_ALG_TYPE_MASK; - - for (;;) { - struct crypto_alg *alg; - - alg = crypto_lookup_aead(alg_name, type, mask); - if (IS_ERR(alg)) { - err = PTR_ERR(alg); - goto err; - } - - tfm = __crypto_alloc_tfm(alg, type, mask); - if (!IS_ERR(tfm)) - return __crypto_aead_cast(tfm); - - crypto_mod_put(alg); - err = PTR_ERR(tfm); - -err: - if (err != -EAGAIN) - break; - if (signal_pending(current)) { - err = -EINTR; - break; - } - } - - return ERR_PTR(err); + return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask); } EXPORT_SYMBOL_GPL(crypto_alloc_aead); -- cgit v1.2.3 From 1ab4af2a218235e82bf417c823b15b871fe98220 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 21 May 2015 15:11:01 +0800 Subject: 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 --- crypto/aead.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index 717b2f6e..c2bf3b31 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -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; -- cgit v1.2.3 From a02089ad892581f317dd507cde619d8a5c09cac5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 21 May 2015 15:11:02 +0800 Subject: crypto: aead - Rename aead_alg to old_aead_alg This patch is the first step in the introduction of a new AEAD alg type. Unlike normal conversions this patch only renames the existing aead_alg structure because there are external references to it. Those references will be removed after this patch. Signed-off-by: Herbert Xu --- crypto/aead.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index c2bf3b31..ebc91ea8 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -33,7 +33,7 @@ static int aead_null_givdecrypt(struct aead_givcrypt_request *req); static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { - struct aead_alg *aead = crypto_aead_alg(tfm); + struct old_aead_alg *aead = crypto_old_aead_alg(tfm); unsigned long alignmask = crypto_aead_alignmask(tfm); int ret; u8 *buffer, *alignbuffer; @@ -55,7 +55,7 @@ static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { - struct aead_alg *aead = crypto_aead_alg(tfm); + struct old_aead_alg *aead = crypto_old_aead_alg(tfm); unsigned long alignmask = crypto_aead_alignmask(tfm); tfm = tfm->child; @@ -71,11 +71,12 @@ int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) { int err; - if (authsize > crypto_aead_alg(tfm)->maxauthsize) + if (authsize > crypto_old_aead_alg(tfm)->maxauthsize) return -EINVAL; - if (crypto_aead_alg(tfm)->setauthsize) { - err = crypto_aead_alg(tfm)->setauthsize(tfm->child, authsize); + if (crypto_old_aead_alg(tfm)->setauthsize) { + err = crypto_old_aead_alg(tfm)->setauthsize( + tfm->child, authsize); if (err) return err; } @@ -126,7 +127,7 @@ static int old_crypt(struct aead_request *req, static int old_encrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct aead_alg *alg = crypto_aead_alg(aead); + struct old_aead_alg *alg = crypto_old_aead_alg(aead); return old_crypt(req, alg->encrypt); } @@ -134,7 +135,7 @@ static int old_encrypt(struct aead_request *req) static int old_decrypt(struct aead_request *req) { struct crypto_aead *aead = crypto_aead_reqtfm(req); - struct aead_alg *alg = crypto_aead_alg(aead); + struct old_aead_alg *alg = crypto_old_aead_alg(aead); return old_crypt(req, alg->decrypt); } @@ -146,7 +147,7 @@ static int no_givcrypt(struct aead_givcrypt_request *req) static int crypto_aead_init_tfm(struct crypto_tfm *tfm) { - struct aead_alg *alg = &tfm->__crt_alg->cra_aead; + struct old_aead_alg *alg = &tfm->__crt_alg->cra_aead; struct crypto_aead *crt = __crypto_aead_cast(tfm); if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) @@ -172,7 +173,7 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm) static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_aead raead; - struct aead_alg *aead = &alg->cra_aead; + struct old_aead_alg *aead = &alg->cra_aead; strncpy(raead.type, "aead", sizeof(raead.type)); strncpy(raead.geniv, aead->geniv ?: "", sizeof(raead.geniv)); @@ -200,7 +201,7 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) __attribute__ ((unused)); static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) { - struct aead_alg *aead = &alg->cra_aead; + struct old_aead_alg *aead = &alg->cra_aead; seq_printf(m, "type : aead\n"); seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? @@ -240,7 +241,7 @@ static int aead_null_givdecrypt(struct aead_givcrypt_request *req) static int crypto_nivaead_report(struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_aead raead; - struct aead_alg *aead = &alg->cra_aead; + struct old_aead_alg *aead = &alg->cra_aead; strncpy(raead.type, "nivaead", sizeof(raead.type)); strncpy(raead.geniv, aead->geniv, sizeof(raead.geniv)); @@ -269,7 +270,7 @@ static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg) __attribute__ ((unused)); static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg) { - struct aead_alg *aead = &alg->cra_aead; + struct old_aead_alg *aead = &alg->cra_aead; seq_printf(m, "type : nivaead\n"); seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? -- cgit v1.2.3 From a1301fe3d55fb0d37004bc8b41b810dee1027097 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 21 May 2015 15:11:08 +0800 Subject: crypto: aead - Add support for new AEAD implementations This patch adds the basic structure of the new AEAD type. Unlike the current version, there is no longer any concept of geniv. IV generation will still be carried out by wrappers but they will be normal AEAD algorithms that simply take the IPsec sequence number as the IV. Signed-off-by: Herbert Xu --- crypto/aead.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 137 insertions(+), 15 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index ebc91ea8..d231e283 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -33,7 +33,6 @@ static int aead_null_givdecrypt(struct aead_givcrypt_request *req); static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { - struct old_aead_alg *aead = crypto_old_aead_alg(tfm); unsigned long alignmask = crypto_aead_alignmask(tfm); int ret; u8 *buffer, *alignbuffer; @@ -46,7 +45,7 @@ static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); memcpy(alignbuffer, key, keylen); - ret = aead->setkey(tfm, alignbuffer, keylen); + ret = tfm->setkey(tfm, alignbuffer, keylen); memset(alignbuffer, 0, keylen); kfree(buffer); return ret; @@ -55,7 +54,6 @@ static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { - struct old_aead_alg *aead = crypto_old_aead_alg(tfm); unsigned long alignmask = crypto_aead_alignmask(tfm); tfm = tfm->child; @@ -63,7 +61,7 @@ int crypto_aead_setkey(struct crypto_aead *tfm, if ((unsigned long)key & alignmask) return setkey_unaligned(tfm, key, keylen); - return aead->setkey(tfm, key, keylen); + return tfm->setkey(tfm, key, keylen); } EXPORT_SYMBOL_GPL(crypto_aead_setkey); @@ -71,12 +69,11 @@ int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) { int err; - if (authsize > crypto_old_aead_alg(tfm)->maxauthsize) + if (authsize > tfm->maxauthsize) return -EINVAL; - if (crypto_old_aead_alg(tfm)->setauthsize) { - err = crypto_old_aead_alg(tfm)->setauthsize( - tfm->child, authsize); + if (tfm->setauthsize) { + err = tfm->setauthsize(tfm->child, authsize); if (err) return err; } @@ -145,7 +142,7 @@ static int no_givcrypt(struct aead_givcrypt_request *req) return -ENOSYS; } -static int crypto_aead_init_tfm(struct crypto_tfm *tfm) +static int crypto_old_aead_init_tfm(struct crypto_tfm *tfm) { struct old_aead_alg *alg = &tfm->__crt_alg->cra_aead; struct crypto_aead *crt = __crypto_aead_cast(tfm); @@ -153,6 +150,8 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm) if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) return -EINVAL; + crt->setkey = alg->setkey; + crt->setauthsize = alg->setauthsize; crt->encrypt = old_encrypt; crt->decrypt = old_decrypt; if (alg->ivsize) { @@ -164,13 +163,34 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm) } crt->child = __crypto_aead_cast(tfm); crt->ivsize = alg->ivsize; + crt->maxauthsize = alg->maxauthsize; crt->authsize = alg->maxauthsize; return 0; } +static int crypto_aead_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_aead *aead = __crypto_aead_cast(tfm); + struct aead_alg *alg = crypto_aead_alg(aead); + + if (crypto_old_aead_alg(aead)->encrypt) + return crypto_old_aead_init_tfm(tfm); + + aead->setkey = alg->setkey; + aead->setauthsize = alg->setauthsize; + aead->encrypt = alg->encrypt; + aead->decrypt = alg->decrypt; + aead->child = __crypto_aead_cast(tfm); + aead->ivsize = alg->ivsize; + aead->maxauthsize = alg->maxauthsize; + aead->authsize = alg->maxauthsize; + + return 0; +} + #ifdef CONFIG_NET -static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) +static int crypto_old_aead_report(struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_aead raead; struct old_aead_alg *aead = &alg->cra_aead; @@ -191,15 +211,15 @@ nla_put_failure: return -EMSGSIZE; } #else -static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) +static int crypto_old_aead_report(struct sk_buff *skb, struct crypto_alg *alg) { return -ENOSYS; } #endif -static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) +static void crypto_old_aead_show(struct seq_file *m, struct crypto_alg *alg) __attribute__ ((unused)); -static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) +static void crypto_old_aead_show(struct seq_file *m, struct crypto_alg *alg) { struct old_aead_alg *aead = &alg->cra_aead; @@ -216,9 +236,9 @@ const struct crypto_type crypto_aead_type = { .extsize = crypto_alg_extsize, .init_tfm = crypto_aead_init_tfm, #ifdef CONFIG_PROC_FS - .show = crypto_aead_show, + .show = crypto_old_aead_show, #endif - .report = crypto_aead_report, + .report = crypto_old_aead_report, .lookup = crypto_lookup_aead, .maskclear = ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV), .maskset = CRYPTO_ALG_TYPE_MASK, @@ -227,6 +247,62 @@ const struct crypto_type crypto_aead_type = { }; EXPORT_SYMBOL_GPL(crypto_aead_type); +#ifdef CONFIG_NET +static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) +{ + struct crypto_report_aead raead; + struct aead_alg *aead = container_of(alg, struct aead_alg, base); + + strncpy(raead.type, "aead", sizeof(raead.type)); + strncpy(raead.geniv, "", sizeof(raead.geniv)); + + raead.blocksize = alg->cra_blocksize; + raead.maxauthsize = aead->maxauthsize; + raead.ivsize = aead->ivsize; + + if (nla_put(skb, CRYPTOCFGA_REPORT_AEAD, + sizeof(struct crypto_report_aead), &raead)) + goto nla_put_failure; + return 0; + +nla_put_failure: + return -EMSGSIZE; +} +#else +static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) +{ + return -ENOSYS; +} +#endif + +static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) +{ + struct aead_alg *aead = container_of(alg, struct aead_alg, base); + + seq_printf(m, "type : aead\n"); + seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? + "yes" : "no"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "ivsize : %u\n", aead->ivsize); + seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); + seq_printf(m, "geniv : \n"); +} + +static const struct crypto_type crypto_new_aead_type = { + .extsize = crypto_alg_extsize, + .init_tfm = crypto_aead_init_tfm, +#ifdef CONFIG_PROC_FS + .show = crypto_aead_show, +#endif + .report = crypto_aead_report, + .maskclear = ~CRYPTO_ALG_TYPE_MASK, + .maskset = CRYPTO_ALG_TYPE_MASK, + .type = CRYPTO_ALG_TYPE_AEAD, + .tfmsize = offsetof(struct crypto_aead, base), +}; + static int aead_null_givencrypt(struct aead_givcrypt_request *req) { return crypto_aead_encrypt(&req->areq); @@ -552,5 +628,51 @@ struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(crypto_alloc_aead); +static int aead_prepare_alg(struct aead_alg *alg) +{ + struct crypto_alg *base = &alg->base; + + if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) + return -EINVAL; + + base->cra_type = &crypto_new_aead_type; + base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; + base->cra_flags |= CRYPTO_ALG_TYPE_AEAD; + + return 0; +} + +int crypto_register_aead(struct aead_alg *alg) +{ + struct crypto_alg *base = &alg->base; + int err; + + err = aead_prepare_alg(alg); + if (err) + return err; + + return crypto_register_alg(base); +} +EXPORT_SYMBOL_GPL(crypto_register_aead); + +int crypto_unregister_aead(struct aead_alg *alg) +{ + return crypto_unregister_alg(&alg->base); +} +EXPORT_SYMBOL_GPL(crypto_unregister_aead); + +int aead_register_instance(struct crypto_template *tmpl, + struct aead_instance *inst) +{ + int err; + + err = aead_prepare_alg(&inst->alg); + if (err) + return err; + + return crypto_register_instance(tmpl, aead_crypto_instance(inst)); +} +EXPORT_SYMBOL_GPL(aead_register_instance); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); -- cgit v1.2.3 From 66d678ee742a91d8a6eace277eba39afaa354b56 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 21 May 2015 15:11:13 +0800 Subject: crypto: seqiv - Add support for new AEAD interface This patch converts the seqiv IV generator to work with the new AEAD interface where IV generators are just normal AEAD algorithms. Full backwards compatibility is paramount at this point since no users have yet switched over to the new interface. Nor can they switch to the new interface until IV generation is fully supported by it. So this means we are adding two versions of seqiv alongside the existing one. The first one is the one that will be used when the underlying AEAD algorithm has switched over to the new AEAD interface. The second one handles the current case where the underlying AEAD algorithm still uses the old interface. Both versions export themselves through the new AEAD interface. Signed-off-by: Herbert Xu --- crypto/Kconfig | 1 + crypto/aead.c | 100 +++++++++------ crypto/seqiv.c | 386 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 440 insertions(+), 47 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/Kconfig b/crypto/Kconfig index eba55b42..657bb82a 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -221,6 +221,7 @@ config CRYPTO_SEQIV tristate "Sequence Number IV Generator" select CRYPTO_AEAD select CRYPTO_BLKCIPHER + select CRYPTO_NULL select CRYPTO_RNG help This IV generator generates an IV based on a sequence number by diff --git a/crypto/aead.c b/crypto/aead.c index d231e283..5fa992ac 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -378,15 +378,16 @@ static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn, return crypto_grab_spawn(&spawn->base, name, type, mask); } -struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl, - struct rtattr **tb, u32 type, - u32 mask) +struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, + struct rtattr **tb, u32 type, u32 mask) { const char *name; struct crypto_aead_spawn *spawn; struct crypto_attr_type *algt; - struct crypto_instance *inst; - struct crypto_alg *alg; + struct aead_instance *inst; + struct aead_alg *alg; + unsigned int ivsize; + unsigned int maxauthsize; int err; algt = crypto_get_attr_type(tb); @@ -405,20 +406,28 @@ struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl, if (!inst) return ERR_PTR(-ENOMEM); - spawn = crypto_instance_ctx(inst); + spawn = aead_instance_ctx(inst); /* Ignore async algorithms if necessary. */ mask |= crypto_requires_sync(algt->type, algt->mask); - crypto_set_aead_spawn(spawn, inst); + crypto_set_aead_spawn(spawn, aead_crypto_instance(inst)); err = crypto_grab_nivaead(spawn, name, type, mask); if (err) goto err_free_inst; - alg = crypto_aead_spawn_alg(spawn); + alg = crypto_spawn_aead_alg(spawn); + + if (alg->base.cra_aead.encrypt) { + ivsize = alg->base.cra_aead.ivsize; + maxauthsize = alg->base.cra_aead.maxauthsize; + } else { + ivsize = alg->ivsize; + maxauthsize = alg->maxauthsize; + } err = -EINVAL; - if (!alg->cra_aead.ivsize) + if (!ivsize) goto err_drop_alg; /* @@ -427,39 +436,56 @@ struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl, * template name and double-check the IV generator. */ if (algt->mask & CRYPTO_ALG_GENIV) { - if (strcmp(tmpl->name, alg->cra_aead.geniv)) + if (!alg->base.cra_aead.encrypt) + goto err_drop_alg; + if (strcmp(tmpl->name, alg->base.cra_aead.geniv)) goto err_drop_alg; - memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); - memcpy(inst->alg.cra_driver_name, alg->cra_driver_name, + memcpy(inst->alg.base.cra_name, alg->base.cra_name, CRYPTO_MAX_ALG_NAME); - } else { - err = -ENAMETOOLONG; - if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, - "%s(%s)", tmpl->name, alg->cra_name) >= - CRYPTO_MAX_ALG_NAME) - goto err_drop_alg; - if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "%s(%s)", tmpl->name, alg->cra_driver_name) >= - CRYPTO_MAX_ALG_NAME) - goto err_drop_alg; + memcpy(inst->alg.base.cra_driver_name, + alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME); + + inst->alg.base.cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_GENIV; + inst->alg.base.cra_flags |= alg->base.cra_flags & + CRYPTO_ALG_ASYNC; + inst->alg.base.cra_priority = alg->base.cra_priority; + inst->alg.base.cra_blocksize = alg->base.cra_blocksize; + inst->alg.base.cra_alignmask = alg->base.cra_alignmask; + inst->alg.base.cra_type = &crypto_aead_type; + + inst->alg.base.cra_aead.ivsize = ivsize; + inst->alg.base.cra_aead.maxauthsize = maxauthsize; + + inst->alg.base.cra_aead.setkey = alg->base.cra_aead.setkey; + inst->alg.base.cra_aead.setauthsize = + alg->base.cra_aead.setauthsize; + inst->alg.base.cra_aead.encrypt = alg->base.cra_aead.encrypt; + inst->alg.base.cra_aead.decrypt = alg->base.cra_aead.decrypt; + + goto out; } - inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV; - inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC; - inst->alg.cra_priority = alg->cra_priority; - inst->alg.cra_blocksize = alg->cra_blocksize; - inst->alg.cra_alignmask = alg->cra_alignmask; - inst->alg.cra_type = &crypto_aead_type; + err = -ENAMETOOLONG; + if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, + "%s(%s)", tmpl->name, alg->base.cra_name) >= + CRYPTO_MAX_ALG_NAME) + goto err_drop_alg; + if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "%s(%s)", tmpl->name, alg->base.cra_driver_name) >= + CRYPTO_MAX_ALG_NAME) + goto err_drop_alg; - inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize; - inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize; - inst->alg.cra_aead.geniv = alg->cra_aead.geniv; + inst->alg.base.cra_flags = CRYPTO_ALG_TYPE_AEAD; + inst->alg.base.cra_flags |= alg->base.cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.base.cra_priority = alg->base.cra_priority; + inst->alg.base.cra_blocksize = alg->base.cra_blocksize; + inst->alg.base.cra_alignmask = alg->base.cra_alignmask; + inst->alg.base.cra_type = &crypto_new_aead_type; - inst->alg.cra_aead.setkey = alg->cra_aead.setkey; - inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize; - inst->alg.cra_aead.encrypt = alg->cra_aead.encrypt; - inst->alg.cra_aead.decrypt = alg->cra_aead.decrypt; + inst->alg.ivsize = ivsize; + inst->alg.maxauthsize = maxauthsize; out: return inst; @@ -473,9 +499,9 @@ err_free_inst: } EXPORT_SYMBOL_GPL(aead_geniv_alloc); -void aead_geniv_free(struct crypto_instance *inst) +void aead_geniv_free(struct aead_instance *inst) { - crypto_drop_aead(crypto_instance_ctx(inst)); + crypto_drop_aead(aead_instance_ctx(inst)); kfree(inst); } EXPORT_SYMBOL_GPL(aead_geniv_free); diff --git a/crypto/seqiv.c b/crypto/seqiv.c index 5bbf2e9e..27dbab8a 100644 --- a/crypto/seqiv.c +++ b/crypto/seqiv.c @@ -15,7 +15,9 @@ #include #include +#include #include +#include #include #include #include @@ -29,6 +31,29 @@ struct seqiv_ctx { u8 salt[] __attribute__ ((aligned(__alignof__(u32)))); }; +struct seqiv_aead_ctx { + struct crypto_aead *child; + spinlock_t lock; + struct crypto_blkcipher *null; + u8 salt[] __attribute__ ((aligned(__alignof__(u32)))); +}; + +static int seqiv_aead_setkey(struct crypto_aead *tfm, + const u8 *key, unsigned int keylen) +{ + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(tfm); + + return crypto_aead_setkey(ctx->child, key, keylen); +} + +static int seqiv_aead_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(tfm); + + return crypto_aead_setauthsize(ctx->child, authsize); +} + static void seqiv_complete2(struct skcipher_givcrypt_request *req, int err) { struct ablkcipher_request *subreq = skcipher_givcrypt_reqctx(req); @@ -81,6 +106,33 @@ static void seqiv_aead_complete(struct crypto_async_request *base, int err) aead_givcrypt_complete(req, err); } +static void seqiv_aead_encrypt_complete2(struct aead_request *req, int err) +{ + struct aead_request *subreq = aead_request_ctx(req); + struct crypto_aead *geniv; + + if (err == -EINPROGRESS) + return; + + if (err) + goto out; + + geniv = crypto_aead_reqtfm(req); + memcpy(req->iv, subreq->iv, crypto_aead_ivsize(geniv)); + +out: + kzfree(subreq->iv); +} + +static void seqiv_aead_encrypt_complete(struct crypto_async_request *base, + int err) +{ + struct aead_request *req = base->data; + + seqiv_aead_encrypt_complete2(req, err); + aead_request_complete(req, err); +} + static void seqiv_geniv(struct seqiv_ctx *ctx, u8 *info, u64 seq, unsigned int ivsize) { @@ -186,6 +238,171 @@ static int seqiv_aead_givencrypt(struct aead_givcrypt_request *req) return err; } +static int seqiv_aead_encrypt_compat(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv); + struct aead_request *subreq = aead_request_ctx(req); + crypto_completion_t compl; + void *data; + u8 *info; + unsigned int ivsize; + int err; + + aead_request_set_tfm(subreq, ctx->child); + + compl = req->base.complete; + data = req->base.data; + info = req->iv; + + ivsize = crypto_aead_ivsize(geniv); + + if (unlikely(!IS_ALIGNED((unsigned long)info, + crypto_aead_alignmask(geniv) + 1))) { + info = kmalloc(ivsize, req->base.flags & + CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: + GFP_ATOMIC); + if (!info) + return -ENOMEM; + + memcpy(info, req->iv, ivsize); + compl = seqiv_aead_encrypt_complete; + data = req; + } + + aead_request_set_callback(subreq, req->base.flags, compl, data); + aead_request_set_crypt(subreq, req->src, req->dst, + req->cryptlen - ivsize, info); + aead_request_set_ad(subreq, req->assoclen, ivsize); + + crypto_xor(info, ctx->salt, ivsize); + scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); + + err = crypto_aead_encrypt(subreq); + if (unlikely(info != req->iv)) + seqiv_aead_encrypt_complete2(req, err); + return err; +} + +static int seqiv_aead_encrypt(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv); + struct aead_request *subreq = aead_request_ctx(req); + crypto_completion_t compl; + void *data; + u8 *info; + unsigned int ivsize; + int err; + + aead_request_set_tfm(subreq, ctx->child); + + compl = req->base.complete; + data = req->base.data; + info = req->iv; + + ivsize = crypto_aead_ivsize(geniv); + + if (req->src != req->dst) { + struct scatterlist src[2]; + struct scatterlist dst[2]; + struct blkcipher_desc desc = { + .tfm = ctx->null, + }; + + err = crypto_blkcipher_encrypt( + &desc, + scatterwalk_ffwd(dst, req->dst, + req->assoclen + ivsize), + scatterwalk_ffwd(src, req->src, + req->assoclen + ivsize), + req->cryptlen - ivsize); + if (err) + return err; + } + + if (unlikely(!IS_ALIGNED((unsigned long)info, + crypto_aead_alignmask(geniv) + 1))) { + info = kmalloc(ivsize, req->base.flags & + CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: + GFP_ATOMIC); + if (!info) + return -ENOMEM; + + memcpy(info, req->iv, ivsize); + compl = seqiv_aead_encrypt_complete; + data = req; + } + + aead_request_set_callback(subreq, req->base.flags, compl, data); + aead_request_set_crypt(subreq, req->dst, req->dst, + req->cryptlen - ivsize, info); + aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + + crypto_xor(info, ctx->salt, ivsize); + scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); + + err = crypto_aead_encrypt(subreq); + if (unlikely(info != req->iv)) + seqiv_aead_encrypt_complete2(req, err); + return err; +} + +static int seqiv_aead_decrypt_compat(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv); + struct aead_request *subreq = aead_request_ctx(req); + crypto_completion_t compl; + void *data; + unsigned int ivsize; + + aead_request_set_tfm(subreq, ctx->child); + + compl = req->base.complete; + data = req->base.data; + + ivsize = crypto_aead_ivsize(geniv); + + aead_request_set_callback(subreq, req->base.flags, compl, data); + aead_request_set_crypt(subreq, req->src, req->dst, + req->cryptlen - ivsize, req->iv); + aead_request_set_ad(subreq, req->assoclen, ivsize); + + scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); + + return crypto_aead_decrypt(subreq); +} + +static int seqiv_aead_decrypt(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv); + struct aead_request *subreq = aead_request_ctx(req); + crypto_completion_t compl; + void *data; + unsigned int ivsize; + + aead_request_set_tfm(subreq, ctx->child); + + compl = req->base.complete; + data = req->base.data; + + ivsize = crypto_aead_ivsize(geniv); + + aead_request_set_callback(subreq, req->base.flags, compl, data); + aead_request_set_crypt(subreq, req->src, req->dst, + req->cryptlen - ivsize, req->iv); + aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + + scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); + if (req->src != req->dst) + scatterwalk_map_and_copy(req->iv, req->dst, + req->assoclen, ivsize, 1); + + return crypto_aead_decrypt(subreq); +} + static int seqiv_givencrypt_first(struct skcipher_givcrypt_request *req) { struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req); @@ -232,6 +449,52 @@ unlock: return seqiv_aead_givencrypt(req); } +static int seqiv_aead_encrypt_compat_first(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv); + int err = 0; + + spin_lock_bh(&ctx->lock); + if (geniv->encrypt != seqiv_aead_encrypt_compat_first) + goto unlock; + + geniv->encrypt = seqiv_aead_encrypt_compat; + err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, + crypto_aead_ivsize(geniv)); + +unlock: + spin_unlock_bh(&ctx->lock); + + if (err) + return err; + + return seqiv_aead_encrypt_compat(req); +} + +static int seqiv_aead_encrypt_first(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv); + int err = 0; + + spin_lock_bh(&ctx->lock); + if (geniv->encrypt != seqiv_aead_encrypt_first) + goto unlock; + + geniv->encrypt = seqiv_aead_encrypt; + err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, + crypto_aead_ivsize(geniv)); + +unlock: + spin_unlock_bh(&ctx->lock); + + if (err) + return err; + + return seqiv_aead_encrypt(req); +} + static int seqiv_init(struct crypto_tfm *tfm) { struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm); @@ -244,7 +507,7 @@ static int seqiv_init(struct crypto_tfm *tfm) return skcipher_geniv_init(tfm); } -static int seqiv_aead_init(struct crypto_tfm *tfm) +static int seqiv_old_aead_init(struct crypto_tfm *tfm) { struct crypto_aead *geniv = __crypto_aead_cast(tfm); struct seqiv_ctx *ctx = crypto_aead_ctx(geniv); @@ -257,6 +520,69 @@ static int seqiv_aead_init(struct crypto_tfm *tfm) return aead_geniv_init(tfm); } +static int seqiv_aead_compat_init(struct crypto_tfm *tfm) +{ + struct crypto_aead *geniv = __crypto_aead_cast(tfm); + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv); + int err; + + spin_lock_init(&ctx->lock); + + crypto_aead_set_reqsize(geniv, sizeof(struct aead_request)); + + err = aead_geniv_init(tfm); + + ctx->child = geniv->child; + geniv->child = geniv; + + return err; +} + +static int seqiv_aead_init(struct crypto_tfm *tfm) +{ + struct crypto_aead *geniv = __crypto_aead_cast(tfm); + struct seqiv_aead_ctx *ctx = crypto_aead_ctx(geniv); + int err; + + spin_lock_init(&ctx->lock); + + crypto_aead_set_reqsize(geniv, sizeof(struct aead_request)); + + ctx->null = crypto_get_default_null_skcipher(); + err = PTR_ERR(ctx->null); + if (IS_ERR(ctx->null)) + goto out; + + err = aead_geniv_init(tfm); + if (err) + goto drop_null; + + ctx->child = geniv->child; + geniv->child = geniv; + +out: + return err; + +drop_null: + crypto_put_default_null_skcipher(); + goto out; +} + +static void seqiv_aead_compat_exit(struct crypto_tfm *tfm) +{ + struct seqiv_aead_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_aead(ctx->child); +} + +static void seqiv_aead_exit(struct crypto_tfm *tfm) +{ + struct seqiv_aead_ctx *ctx = crypto_tfm_ctx(tfm); + + crypto_free_aead(ctx->child); + crypto_put_default_null_skcipher(); +} + static struct crypto_template seqiv_tmpl; static struct crypto_instance *seqiv_ablkcipher_alloc(struct rtattr **tb) @@ -280,35 +606,76 @@ static struct crypto_instance *seqiv_ablkcipher_alloc(struct rtattr **tb) inst->alg.cra_exit = skcipher_geniv_exit; inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize; + inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx); out: return inst; } +static struct crypto_instance *seqiv_old_aead_alloc(struct aead_instance *aead) +{ + struct crypto_instance *inst = aead_crypto_instance(aead); + + if (inst->alg.cra_aead.ivsize < sizeof(u64)) { + aead_geniv_free(aead); + return ERR_PTR(-EINVAL); + } + + inst->alg.cra_aead.givencrypt = seqiv_aead_givencrypt_first; + + inst->alg.cra_init = seqiv_old_aead_init; + inst->alg.cra_exit = aead_geniv_exit; + + inst->alg.cra_ctxsize = inst->alg.cra_aead.ivsize; + inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx); + + return inst; +} + static struct crypto_instance *seqiv_aead_alloc(struct rtattr **tb) { - struct crypto_instance *inst; + struct aead_instance *inst; + struct crypto_aead_spawn *spawn; + struct aead_alg *alg; inst = aead_geniv_alloc(&seqiv_tmpl, tb, 0, 0); if (IS_ERR(inst)) goto out; - if (inst->alg.cra_aead.ivsize < sizeof(u64)) { + if (inst->alg.base.cra_aead.encrypt) + return seqiv_old_aead_alloc(inst); + + if (inst->alg.ivsize < sizeof(u64)) { aead_geniv_free(inst); inst = ERR_PTR(-EINVAL); goto out; } - inst->alg.cra_aead.givencrypt = seqiv_aead_givencrypt_first; + spawn = aead_instance_ctx(inst); + alg = crypto_spawn_aead_alg(spawn); - inst->alg.cra_init = seqiv_aead_init; - inst->alg.cra_exit = aead_geniv_exit; + inst->alg.setkey = seqiv_aead_setkey; + inst->alg.setauthsize = seqiv_aead_setauthsize; + inst->alg.encrypt = seqiv_aead_encrypt_first; + inst->alg.decrypt = seqiv_aead_decrypt; - inst->alg.cra_ctxsize = inst->alg.cra_aead.ivsize; + inst->alg.base.cra_init = seqiv_aead_init; + inst->alg.base.cra_exit = seqiv_aead_exit; + + inst->alg.base.cra_ctxsize = sizeof(struct seqiv_aead_ctx); + inst->alg.base.cra_ctxsize += inst->alg.base.cra_aead.ivsize; + + if (alg->base.cra_aead.encrypt) { + inst->alg.encrypt = seqiv_aead_encrypt_compat_first; + inst->alg.decrypt = seqiv_aead_decrypt_compat; + + inst->alg.base.cra_init = seqiv_aead_compat_init; + inst->alg.base.cra_exit = seqiv_aead_compat_exit; + } out: - return inst; + return aead_crypto_instance(inst); } static struct crypto_instance *seqiv_alloc(struct rtattr **tb) @@ -334,7 +701,6 @@ static struct crypto_instance *seqiv_alloc(struct rtattr **tb) goto put_rng; inst->alg.cra_alignmask |= __alignof__(u32) - 1; - inst->alg.cra_ctxsize += sizeof(struct seqiv_ctx); out: return inst; @@ -349,7 +715,7 @@ static void seqiv_free(struct crypto_instance *inst) if ((inst->alg.cra_flags ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK) skcipher_geniv_free(inst); else - aead_geniv_free(inst); + aead_geniv_free(aead_instance(inst)); crypto_put_default_rng(); } -- cgit v1.2.3 From 8684eae8dddde8a05435386f6491d530e2a203e4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 22 May 2015 16:30:48 +0800 Subject: crypto: aead - Add crypto_aead_alg_ivsize/maxauthsize AEAD algorithm implementors need to figure out a given algorithm's IV size and maximum authentication size. During the transition this is difficult to do as an algorithm could be new style or old style. This patch creates two helpers to make this easier. Signed-off-by: Herbert Xu --- crypto/aead.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index 5fa992ac..c1f73a96 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -69,7 +69,7 @@ int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) { int err; - if (authsize > tfm->maxauthsize) + if (authsize > crypto_aead_maxauthsize(tfm)) return -EINVAL; if (tfm->setauthsize) { @@ -162,8 +162,6 @@ static int crypto_old_aead_init_tfm(struct crypto_tfm *tfm) crt->givdecrypt = aead_null_givdecrypt; } crt->child = __crypto_aead_cast(tfm); - crt->ivsize = alg->ivsize; - crt->maxauthsize = alg->maxauthsize; crt->authsize = alg->maxauthsize; return 0; @@ -182,8 +180,6 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm) aead->encrypt = alg->encrypt; aead->decrypt = alg->decrypt; aead->child = __crypto_aead_cast(tfm); - aead->ivsize = alg->ivsize; - aead->maxauthsize = alg->maxauthsize; aead->authsize = alg->maxauthsize; return 0; @@ -418,13 +414,8 @@ struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, alg = crypto_spawn_aead_alg(spawn); - if (alg->base.cra_aead.encrypt) { - ivsize = alg->base.cra_aead.ivsize; - maxauthsize = alg->base.cra_aead.maxauthsize; - } else { - ivsize = alg->ivsize; - maxauthsize = alg->maxauthsize; - } + ivsize = crypto_aead_alg_ivsize(alg); + maxauthsize = crypto_aead_alg_maxauthsize(alg); err = -EINVAL; if (!ivsize) -- cgit v1.2.3 From c4fd4d37c0a3b28d0f5a3d6442f4546406e40619 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 23 May 2015 15:41:49 +0800 Subject: crypto: aead - Use tmpl->create Newer templates use tmpl->create and have a NULL tmpl->alloc. So we must use tmpl->create if it is set. Signed-off-by: Herbert Xu --- crypto/aead.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index c1f73a96..a6385bd0 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -572,6 +572,13 @@ static int crypto_nivaead_default(struct crypto_alg *alg, u32 type, u32 mask) if (!tmpl) goto kill_larval; + if (tmpl->create) { + err = tmpl->create(tmpl, tb); + if (err) + goto put_tmpl; + goto ok; + } + inst = tmpl->alloc(tb); err = PTR_ERR(inst); if (IS_ERR(inst)) @@ -583,6 +590,7 @@ static int crypto_nivaead_default(struct crypto_alg *alg, u32 type, u32 mask) goto put_tmpl; } +ok: /* Redo the lookup to use the instance we just registered. */ err = -EAGAIN; -- cgit v1.2.3 From d89db82b2e49bd5c3e5350f042198b9911e9c93f Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 23 May 2015 15:41:53 +0800 Subject: crypto: aead - Do not set cra_type for new style instances The function aead_geniv_alloc currently sets cra_type even for new style instances. This is unnecessary and may hide bugs such as when our caller uses crypto_register_instance instead of the correct aead_register_instance. Signed-off-by: Herbert Xu --- crypto/aead.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index a6385bd0..070e4b9e 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -468,12 +468,10 @@ struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, CRYPTO_MAX_ALG_NAME) goto err_drop_alg; - inst->alg.base.cra_flags = CRYPTO_ALG_TYPE_AEAD; - inst->alg.base.cra_flags |= alg->base.cra_flags & CRYPTO_ALG_ASYNC; + inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC; inst->alg.base.cra_priority = alg->base.cra_priority; inst->alg.base.cra_blocksize = alg->base.cra_blocksize; inst->alg.base.cra_alignmask = alg->base.cra_alignmask; - inst->alg.base.cra_type = &crypto_new_aead_type; inst->alg.ivsize = ivsize; inst->alg.maxauthsize = maxauthsize; -- cgit v1.2.3 From 7cd298d06cad210c681a4c3f5d77ca6d173ebc4d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 23 May 2015 15:41:57 +0800 Subject: crypto: aead - Remove unused cryptoff parameter This patch removes the cryptoff parameter now that all users set it to zero. Signed-off-by: Herbert Xu --- crypto/aead.c | 6 ++---- crypto/echainiv.c | 4 ++-- crypto/seqiv.c | 8 ++++---- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index 070e4b9e..7c3d725b 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -106,10 +106,8 @@ static int old_crypt(struct aead_request *req, 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); + src = scatterwalk_ffwd(nreq->srcbuf, req->src, req->assoclen); + dst = scatterwalk_ffwd(nreq->dstbuf, req->dst, req->assoclen); aead_request_set_tfm(&nreq->subreq, aead); aead_request_set_callback(&nreq->subreq, aead_request_flags(req), diff --git a/crypto/echainiv.c b/crypto/echainiv.c index 149d8fb8..bd85dcc4 100644 --- a/crypto/echainiv.c +++ b/crypto/echainiv.c @@ -259,7 +259,7 @@ static int echainiv_encrypt(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->dst, req->dst, req->cryptlen - ivsize, info); - aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + aead_request_set_ad(subreq, req->assoclen + ivsize); crypto_xor(info, ctx->salt, ivsize); scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); @@ -322,7 +322,7 @@ static int echainiv_decrypt(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + aead_request_set_ad(subreq, req->assoclen + ivsize); scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); if (req->src != req->dst) diff --git a/crypto/seqiv.c b/crypto/seqiv.c index 16738c5f..127970a6 100644 --- a/crypto/seqiv.c +++ b/crypto/seqiv.c @@ -337,7 +337,7 @@ static int seqiv_aead_encrypt_compat(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, dst, dst, req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen, 0); + aead_request_set_ad(subreq, req->assoclen); memcpy(buf, req->iv, ivsize); crypto_xor(buf, ctx->salt, ivsize); @@ -406,7 +406,7 @@ static int seqiv_aead_encrypt(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->dst, req->dst, req->cryptlen - ivsize, info); - aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + aead_request_set_ad(subreq, req->assoclen + ivsize); crypto_xor(info, ctx->salt, ivsize); scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); @@ -473,7 +473,7 @@ static int seqiv_aead_decrypt_compat(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, dst, dst, req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen, 0); + aead_request_set_ad(subreq, req->assoclen); err = crypto_aead_decrypt(subreq); if (req->assoclen > 8) @@ -501,7 +501,7 @@ static int seqiv_aead_decrypt(struct aead_request *req) aead_request_set_callback(subreq, req->base.flags, compl, data); aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen + ivsize, 0); + aead_request_set_ad(subreq, req->assoclen + ivsize); scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); if (req->src != req->dst) -- cgit v1.2.3 From 19009e8c06657783c0c398070be715f176737d49 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 27 May 2015 14:37:29 +0800 Subject: crypto: aead - Preserve in-place processing in old_crypt This patch tries to preserve in-place processing in old_crypt as various algorithms are optimised for in-place processing where src == dst. Signed-off-by: Herbert Xu --- crypto/aead.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index 7c3d725b..35c55e04 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -107,7 +107,8 @@ static int old_crypt(struct aead_request *req, return crypt(req); src = scatterwalk_ffwd(nreq->srcbuf, req->src, req->assoclen); - dst = scatterwalk_ffwd(nreq->dstbuf, req->dst, req->assoclen); + dst = req->src == req->dst ? + src : scatterwalk_ffwd(nreq->dstbuf, req->dst, req->assoclen); aead_request_set_tfm(&nreq->subreq, aead); aead_request_set_callback(&nreq->subreq, aead_request_flags(req), -- cgit v1.2.3 From b77e06fec867aa0451b6a80ad0dd5f298c5da04a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 27 May 2015 14:37:30 +0800 Subject: crypto: aead - Add common IV generation code This patch adds some common IV generation code currently duplicated by seqiv and echainiv. For example, the setkey and setauthsize functions are completely identical. Signed-off-by: Herbert Xu --- crypto/aead.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 202 insertions(+), 3 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index 35c55e04..8cdea899 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -12,7 +12,7 @@ * */ -#include +#include #include #include #include @@ -27,6 +27,14 @@ #include "internal.h" +struct compat_request_ctx { + struct scatterlist src[2]; + struct scatterlist dst[2]; + struct scatterlist ivbuf[2]; + struct scatterlist *ivsg; + struct aead_givcrypt_request subreq; +}; + static int aead_null_givencrypt(struct aead_givcrypt_request *req); static int aead_null_givdecrypt(struct aead_givcrypt_request *req); @@ -373,6 +381,185 @@ static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn, return crypto_grab_spawn(&spawn->base, name, type, mask); } +static int aead_geniv_setkey(struct crypto_aead *tfm, + const u8 *key, unsigned int keylen) +{ + struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); + + return crypto_aead_setkey(ctx->child, key, keylen); +} + +static int aead_geniv_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); + + return crypto_aead_setauthsize(ctx->child, authsize); +} + +static void compat_encrypt_complete2(struct aead_request *req, int err) +{ + struct compat_request_ctx *rctx = aead_request_ctx(req); + struct aead_givcrypt_request *subreq = &rctx->subreq; + struct crypto_aead *geniv; + + if (err == -EINPROGRESS) + return; + + if (err) + goto out; + + geniv = crypto_aead_reqtfm(req); + scatterwalk_map_and_copy(subreq->giv, rctx->ivsg, 0, + crypto_aead_ivsize(geniv), 1); + +out: + kzfree(subreq->giv); +} + +static void compat_encrypt_complete(struct crypto_async_request *base, int err) +{ + struct aead_request *req = base->data; + + compat_encrypt_complete2(req, err); + aead_request_complete(req, err); +} + +static int compat_encrypt(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); + struct compat_request_ctx *rctx = aead_request_ctx(req); + struct aead_givcrypt_request *subreq = &rctx->subreq; + unsigned int ivsize = crypto_aead_ivsize(geniv); + struct scatterlist *src, *dst; + crypto_completion_t compl; + void *data; + u8 *info; + __be64 seq; + int err; + + if (req->cryptlen < ivsize) + return -EINVAL; + + compl = req->base.complete; + data = req->base.data; + + rctx->ivsg = scatterwalk_ffwd(rctx->ivbuf, req->dst, req->assoclen); + info = PageHighMem(sg_page(rctx->ivsg)) ? NULL : sg_virt(rctx->ivsg); + + if (!info) { + info = kmalloc(ivsize, req->base.flags & + CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL: + GFP_ATOMIC); + if (!info) + return -ENOMEM; + + compl = compat_encrypt_complete; + data = req; + } + + memcpy(&seq, req->iv + ivsize - sizeof(seq), sizeof(seq)); + + src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen + ivsize); + dst = req->src == req->dst ? + src : scatterwalk_ffwd(rctx->dst, rctx->ivsg, ivsize); + + aead_givcrypt_set_tfm(subreq, ctx->child); + aead_givcrypt_set_callback(subreq, req->base.flags, + req->base.complete, req->base.data); + aead_givcrypt_set_crypt(subreq, src, dst, + req->cryptlen - ivsize, req->iv); + aead_givcrypt_set_assoc(subreq, req->src, req->assoclen); + aead_givcrypt_set_giv(subreq, info, be64_to_cpu(seq)); + + err = crypto_aead_givencrypt(subreq); + if (unlikely(PageHighMem(sg_page(rctx->ivsg)))) + compat_encrypt_complete2(req, err); + return err; +} + +static int compat_decrypt(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); + struct compat_request_ctx *rctx = aead_request_ctx(req); + struct aead_request *subreq = &rctx->subreq.areq; + unsigned int ivsize = crypto_aead_ivsize(geniv); + struct scatterlist *src, *dst; + crypto_completion_t compl; + void *data; + + if (req->cryptlen < ivsize) + return -EINVAL; + + aead_request_set_tfm(subreq, ctx->child); + + compl = req->base.complete; + data = req->base.data; + + src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen + ivsize); + dst = req->src == req->dst ? + src : scatterwalk_ffwd(rctx->dst, req->dst, + req->assoclen + ivsize); + + aead_request_set_callback(subreq, req->base.flags, compl, data); + aead_request_set_crypt(subreq, src, dst, + req->cryptlen - ivsize, req->iv); + aead_request_set_assoc(subreq, req->src, req->assoclen); + + scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); + + return crypto_aead_decrypt(subreq); +} + +static int compat_encrypt_first(struct aead_request *req) +{ + struct crypto_aead *geniv = crypto_aead_reqtfm(req); + struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); + int err = 0; + + spin_lock_bh(&ctx->lock); + if (geniv->encrypt != compat_encrypt_first) + goto unlock; + + geniv->encrypt = compat_encrypt; + +unlock: + spin_unlock_bh(&ctx->lock); + + if (err) + return err; + + return compat_encrypt(req); +} + +static int aead_geniv_init_compat(struct crypto_tfm *tfm) +{ + struct crypto_aead *geniv = __crypto_aead_cast(tfm); + struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); + int err; + + spin_lock_init(&ctx->lock); + + crypto_aead_set_reqsize(geniv, sizeof(struct compat_request_ctx)); + + err = aead_geniv_init(tfm); + + ctx->child = geniv->child; + geniv->child = geniv; + + return err; +} + +static void aead_geniv_exit_compat(struct crypto_tfm *tfm) +{ + struct crypto_aead *geniv = __crypto_aead_cast(tfm); + struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); + + crypto_free_aead(ctx->child); +} + struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, struct rtattr **tb, u32 type, u32 mask) { @@ -407,7 +594,9 @@ struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, mask |= crypto_requires_sync(algt->type, algt->mask); crypto_set_aead_spawn(spawn, aead_crypto_instance(inst)); - err = crypto_grab_nivaead(spawn, name, type, mask); + err = (algt->mask & CRYPTO_ALG_GENIV) ? + crypto_grab_nivaead(spawn, name, type, mask) : + crypto_grab_aead(spawn, name, type, mask); if (err) goto err_free_inst; @@ -417,7 +606,7 @@ struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, maxauthsize = crypto_aead_alg_maxauthsize(alg); err = -EINVAL; - if (!ivsize) + if (ivsize < sizeof(u64)) goto err_drop_alg; /* @@ -471,10 +660,20 @@ struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, inst->alg.base.cra_priority = alg->base.cra_priority; inst->alg.base.cra_blocksize = alg->base.cra_blocksize; inst->alg.base.cra_alignmask = alg->base.cra_alignmask; + inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx); + + inst->alg.setkey = aead_geniv_setkey; + inst->alg.setauthsize = aead_geniv_setauthsize; inst->alg.ivsize = ivsize; inst->alg.maxauthsize = maxauthsize; + inst->alg.encrypt = compat_encrypt_first; + inst->alg.decrypt = compat_decrypt; + + inst->alg.base.cra_init = aead_geniv_init_compat; + inst->alg.base.cra_exit = aead_geniv_exit_compat; + out: return inst; -- cgit v1.2.3 From 4b1a6955656f027637027e1d5ad7ea1fd5b7feb5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 28 May 2015 22:07:53 +0800 Subject: crypto: aead - Add type-safe init/exit functions As it stands the only non-type safe functions left in the new AEAD interface are the cra_init/cra_exit functions. It means exposing the ugly __crypto_aead_cast to every AEAD implementor. This patch adds type-safe init/exit functions to AEAD. Existing algorithms are unaffected while new implementations can simply fill in these two instead of cra_init/cra_exit. Signed-off-by: Herbert Xu --- crypto/aead.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index 8cdea899..4bab3cff 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -174,6 +174,14 @@ static int crypto_old_aead_init_tfm(struct crypto_tfm *tfm) return 0; } +static void crypto_aead_exit_tfm(struct crypto_tfm *tfm) +{ + struct crypto_aead *aead = __crypto_aead_cast(tfm); + struct aead_alg *alg = crypto_aead_alg(aead); + + alg->exit(aead); +} + static int crypto_aead_init_tfm(struct crypto_tfm *tfm) { struct crypto_aead *aead = __crypto_aead_cast(tfm); @@ -189,6 +197,12 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm) aead->child = __crypto_aead_cast(tfm); aead->authsize = alg->maxauthsize; + if (alg->exit) + aead->base.exit = crypto_aead_exit_tfm; + + if (alg->init) + return alg->init(aead); + return 0; } -- cgit v1.2.3 From ee61bc25ac681fa39cb2179062fde30a95c506e8 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 28 May 2015 22:07:57 +0800 Subject: crypto: aead - Ignore return value from crypto_unregister_alg No new code should be using the return value of crypto_unregister_alg as it will become void soon. Signed-off-by: Herbert Xu --- crypto/aead.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index 4bab3cff..ac447929 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -890,9 +890,9 @@ int crypto_register_aead(struct aead_alg *alg) } EXPORT_SYMBOL_GPL(crypto_register_aead); -int crypto_unregister_aead(struct aead_alg *alg) +void crypto_unregister_aead(struct aead_alg *alg) { - return crypto_unregister_alg(&alg->base); + crypto_unregister_alg(&alg->base); } EXPORT_SYMBOL_GPL(crypto_unregister_aead); -- cgit v1.2.3 From f3f3012daeea8bb9195b68645ba0ae9ce8e6e8ff Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 28 May 2015 22:07:59 +0800 Subject: crypto: aead - Add multiple algorithm registration interface This patch adds the helpers that allow the registration and removal of multiple algorithms. Signed-off-by: Herbert Xu --- crypto/aead.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'crypto/aead.c') diff --git a/crypto/aead.c b/crypto/aead.c index ac447929..07bf9977 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -896,6 +896,35 @@ void crypto_unregister_aead(struct aead_alg *alg) } EXPORT_SYMBOL_GPL(crypto_unregister_aead); +int crypto_register_aeads(struct aead_alg *algs, int count) +{ + int i, ret; + + for (i = 0; i < count; i++) { + ret = crypto_register_aead(&algs[i]); + if (ret) + goto err; + } + + return 0; + +err: + for (--i; i >= 0; --i) + crypto_unregister_aead(&algs[i]); + + return ret; +} +EXPORT_SYMBOL_GPL(crypto_register_aeads); + +void crypto_unregister_aeads(struct aead_alg *algs, int count) +{ + int i; + + for (i = count - 1; i >= 0; --i) + crypto_unregister_aead(&algs[i]); +} +EXPORT_SYMBOL_GPL(crypto_unregister_aeads); + int aead_register_instance(struct crypto_template *tmpl, struct aead_instance *inst) { -- cgit v1.2.3