From 332f8840f7095d294f9bb066b175a100bcde214c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 15 Nov 2007 22:36:07 +0800 Subject: [CRYPTO] ablkcipher: Add distinct ABLKCIPHER type Up until now we have ablkcipher algorithms have been identified as type BLKCIPHER with the ASYNC bit set. This is suboptimal because ablkcipher refers to two things. On the one hand it refers to the top-level ablkcipher interface with requests. On the other hand it refers to and algorithm type underneath. As it is you cannot request a synchronous block cipher algorithm with the ablkcipher interface on top. This is a problem because we want to be able to eventually phase out the blkcipher top-level interface. This patch fixes this by making ABLKCIPHER its own type, just as we have distinct types for HASH and DIGEST. The type it associated with the algorithm implementation only. Which top-level interface is used for synchronous block ciphers is then determined by the mask that's used. If it's a specific mask then the old blkcipher interface is given, otherwise we go with the new ablkcipher interface. Signed-off-by: Herbert Xu --- include/linux/crypto.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'include/linux/crypto.h') diff --git a/include/linux/crypto.h b/include/linux/crypto.h index f3110ebe894a..f56ae8721bc9 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -33,10 +33,12 @@ #define CRYPTO_ALG_TYPE_DIGEST 0x00000002 #define CRYPTO_ALG_TYPE_HASH 0x00000003 #define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 -#define CRYPTO_ALG_TYPE_COMPRESS 0x00000005 -#define CRYPTO_ALG_TYPE_AEAD 0x00000006 +#define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005 +#define CRYPTO_ALG_TYPE_COMPRESS 0x00000008 +#define CRYPTO_ALG_TYPE_AEAD 0x00000009 #define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e +#define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c #define CRYPTO_ALG_LARVAL 0x00000010 #define CRYPTO_ALG_DEAD 0x00000020 @@ -530,7 +532,7 @@ static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher( { type &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; + mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; return __crypto_ablkcipher_cast( crypto_alloc_base(alg_name, type, mask)); @@ -552,7 +554,7 @@ static inline int crypto_has_ablkcipher(const char *alg_name, u32 type, { type &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; + mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; return crypto_has_alg(alg_name, type, mask); } @@ -841,9 +843,9 @@ static inline struct crypto_blkcipher *crypto_blkcipher_cast( static inline struct crypto_blkcipher *crypto_alloc_blkcipher( const char *alg_name, u32 type, u32 mask) { - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + type &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC; + mask |= CRYPTO_ALG_TYPE_MASK; return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask)); } @@ -861,9 +863,9 @@ static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm) static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask) { - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + type &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC; + mask |= CRYPTO_ALG_TYPE_MASK; return crypto_has_alg(alg_name, type, mask); } -- cgit v1.2.3 From 7ba683a6deba70251756aa5a021cdaa5c875a7a2 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 2 Dec 2007 18:49:21 +1100 Subject: [CRYPTO] aead: Make authsize a run-time parameter As it is authsize is an algorithm paramter which cannot be changed at run-time. This is inconvenient because hardware that implements such algorithms would have to register each authsize that they support separately. Since authsize is a property common to all AEAD algorithms, we can add a function setauthsize that sets it at run-time, just like setkey. This patch does exactly that and also changes authenc so that authsize is no longer a parameter of its template. Signed-off-by: Herbert Xu --- crypto/aead.c | 24 +++++++++++++++++++++--- crypto/authenc.c | 39 ++++++++++++--------------------------- crypto/gcm.c | 2 +- include/linux/crypto.h | 5 ++++- 4 files changed, 38 insertions(+), 32 deletions(-) (limited to 'include/linux/crypto.h') diff --git a/crypto/aead.c b/crypto/aead.c index 84a3501fb478..f23c2b0ee009 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -53,6 +53,24 @@ static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) return aead->setkey(tfm, key, keylen); } +int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) +{ + int err; + + if (authsize > crypto_aead_alg(tfm)->maxauthsize) + return -EINVAL; + + if (crypto_aead_alg(tfm)->setauthsize) { + err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize); + if (err) + return err; + } + + crypto_aead_crt(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) { @@ -64,14 +82,14 @@ static int crypto_init_aead_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->authsize, alg->ivsize) > PAGE_SIZE / 8) + if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) return -EINVAL; crt->setkey = setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; crt->ivsize = alg->ivsize; - crt->authsize = alg->authsize; + crt->authsize = alg->maxauthsize; return 0; } @@ -85,7 +103,7 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "type : aead\n"); seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); seq_printf(m, "ivsize : %u\n", aead->ivsize); - seq_printf(m, "authsize : %u\n", aead->authsize); + seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); } const struct crypto_type crypto_aead_type = { diff --git a/crypto/authenc.c b/crypto/authenc.c index 66fb2aa5c325..5df5fb169cbe 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -24,7 +24,6 @@ struct authenc_instance_ctx { struct crypto_spawn auth; struct crypto_spawn enc; - unsigned int authsize; unsigned int enckeylen; }; @@ -76,8 +75,6 @@ out: static int crypto_authenc_hash(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); - struct authenc_instance_ctx *ictx = - crypto_instance_ctx(crypto_aead_alg_instance(authenc)); struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); struct crypto_hash *auth = ctx->auth; struct hash_desc desc = { @@ -111,7 +108,8 @@ auth_unlock: if (err) return err; - scatterwalk_map_and_copy(hash, dst, cryptlen, ictx->authsize, 1); + scatterwalk_map_and_copy(hash, dst, cryptlen, + crypto_aead_authsize(authenc), 1); return 0; } @@ -147,8 +145,6 @@ static int crypto_authenc_encrypt(struct aead_request *req) static int crypto_authenc_verify(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); - struct authenc_instance_ctx *ictx = - crypto_instance_ctx(crypto_aead_alg_instance(authenc)); struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); struct crypto_hash *auth = ctx->auth; struct hash_desc desc = { @@ -186,7 +182,7 @@ auth_unlock: if (err) return err; - authsize = ictx->authsize; + authsize = crypto_aead_authsize(authenc); scatterwalk_map_and_copy(ihash, src, cryptlen, authsize, 0); return memcmp(ihash, ohash, authsize) ? -EINVAL : 0; } @@ -224,18 +220,12 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm) struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm); struct crypto_hash *auth; struct crypto_ablkcipher *enc; - unsigned int digestsize; int err; auth = crypto_spawn_hash(&ictx->auth); if (IS_ERR(auth)) return PTR_ERR(auth); - err = -EINVAL; - digestsize = crypto_hash_digestsize(auth); - if (ictx->authsize > digestsize) - goto err_free_hash; - enc = crypto_spawn_ablkcipher(&ictx->enc); err = PTR_ERR(enc); if (IS_ERR(enc)) @@ -246,7 +236,7 @@ static int crypto_authenc_init_tfm(struct crypto_tfm *tfm) tfm->crt_aead.reqsize = max_t(unsigned int, (crypto_hash_alignmask(auth) & ~(crypto_tfm_ctx_alignment() - 1)) + - digestsize * 2, + crypto_hash_digestsize(auth) * 2, sizeof(struct ablkcipher_request) + crypto_ablkcipher_reqsize(enc)); @@ -273,7 +263,6 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) struct crypto_alg *auth; struct crypto_alg *enc; struct authenc_instance_ctx *ctx; - unsigned int authsize; unsigned int enckeylen; int err; @@ -286,18 +275,13 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) if (IS_ERR(auth)) return ERR_PTR(PTR_ERR(auth)); - err = crypto_attr_u32(tb[2], &authsize); - inst = ERR_PTR(err); - if (err) - goto out_put_auth; - - enc = crypto_attr_alg(tb[3], CRYPTO_ALG_TYPE_BLKCIPHER, + enc = crypto_attr_alg(tb[2], CRYPTO_ALG_TYPE_BLKCIPHER, CRYPTO_ALG_TYPE_BLKCIPHER_MASK); inst = ERR_PTR(PTR_ERR(enc)); if (IS_ERR(enc)) goto out_put_auth; - err = crypto_attr_u32(tb[4], &enckeylen); + err = crypto_attr_u32(tb[3], &enckeylen); if (err) goto out_put_enc; @@ -308,18 +292,17 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) err = -ENAMETOOLONG; if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, - "authenc(%s,%u,%s,%u)", auth->cra_name, authsize, + "authenc(%s,%s,%u)", auth->cra_name, enc->cra_name, enckeylen) >= CRYPTO_MAX_ALG_NAME) goto err_free_inst; if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "authenc(%s,%u,%s,%u)", auth->cra_driver_name, - authsize, enc->cra_driver_name, enckeylen) >= + "authenc(%s,%s,%u)", auth->cra_driver_name, + enc->cra_driver_name, enckeylen) >= CRYPTO_MAX_ALG_NAME) goto err_free_inst; ctx = crypto_instance_ctx(inst); - ctx->authsize = authsize; ctx->enckeylen = enckeylen; err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK); @@ -337,7 +320,9 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb) inst->alg.cra_type = &crypto_aead_type; inst->alg.cra_aead.ivsize = enc->cra_blkcipher.ivsize; - inst->alg.cra_aead.authsize = authsize; + inst->alg.cra_aead.maxauthsize = auth->cra_type == &crypto_hash_type ? + auth->cra_hash.digestsize : + auth->cra_digest.dia_digestsize; inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx); diff --git a/crypto/gcm.c b/crypto/gcm.c index ad8b8b9aeef2..5681c7957b88 100644 --- a/crypto/gcm.c +++ b/crypto/gcm.c @@ -414,7 +414,7 @@ static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb) inst->alg.cra_alignmask = __alignof__(u32) - 1; inst->alg.cra_type = &crypto_aead_type; inst->alg.cra_aead.ivsize = 12; - inst->alg.cra_aead.authsize = 16; + inst->alg.cra_aead.maxauthsize = 16; inst->alg.cra_ctxsize = sizeof(struct crypto_gcm_ctx); inst->alg.cra_init = crypto_gcm_init_tfm; inst->alg.cra_exit = crypto_gcm_exit_tfm; diff --git a/include/linux/crypto.h b/include/linux/crypto.h index f56ae8721bc9..48aa5959abbb 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -187,11 +187,12 @@ struct ablkcipher_alg { struct aead_alg { int (*setkey)(struct crypto_aead *tfm, const u8 *key, unsigned int keylen); + int (*setauthsize)(struct crypto_aead *tfm, unsigned int authsize); int (*encrypt)(struct aead_request *req); int (*decrypt)(struct aead_request *req); unsigned int ivsize; - unsigned int authsize; + unsigned int maxauthsize; }; struct blkcipher_alg { @@ -754,6 +755,8 @@ static inline int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, return crypto_aead_crt(tfm)->setkey(tfm, key, keylen); } +int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize); + static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req) { return __crypto_aead_cast(req->base.tfm); -- cgit v1.2.3 From 551a09a7a954f720067f207657bbbd26a3fe156a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sat, 1 Dec 2007 21:47:07 +1100 Subject: [CRYPTO] api: Sanitise mask when allocating ablkcipher/hash When allocating ablkcipher/hash objects, we use a mask that's wider than the usual type mask. This patch sanitises the mask supplied by the user so we don't end up using a narrower mask which may lead to unintended results. Signed-off-by: Herbert Xu --- include/linux/crypto.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/linux/crypto.h') diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 48aa5959abbb..ef7642ed3e42 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -532,6 +532,7 @@ static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher( const char *alg_name, u32 type, u32 mask) { type &= ~CRYPTO_ALG_TYPE_MASK; + mask &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; @@ -554,6 +555,7 @@ static inline int crypto_has_ablkcipher(const char *alg_name, u32 type, u32 mask) { type &= ~CRYPTO_ALG_TYPE_MASK; + mask &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; @@ -1086,6 +1088,7 @@ static inline struct crypto_hash *crypto_alloc_hash(const char *alg_name, u32 type, u32 mask) { type &= ~CRYPTO_ALG_TYPE_MASK; + mask &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_HASH; mask |= CRYPTO_ALG_TYPE_HASH_MASK; @@ -1105,6 +1108,7 @@ static inline void crypto_free_hash(struct crypto_hash *tfm) static inline int crypto_has_hash(const char *alg_name, u32 type, u32 mask) { type &= ~CRYPTO_ALG_TYPE_MASK; + mask &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_HASH; mask |= CRYPTO_ALG_TYPE_HASH_MASK; -- cgit v1.2.3 From 378f4f51f9fdd8df80ea875320e2bf1d7c6e6e77 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 17 Dec 2007 20:07:31 +0800 Subject: [CRYPTO] skcipher: Add crypto_grab_skcipher interface Note: From now on the collective of ablkcipher/blkcipher/givcipher will be known as skcipher, i.e., symmetric key cipher. The name blkcipher has always been much of a misnomer since it supports stream ciphers too. This patch adds the function crypto_grab_skcipher as a new way of getting an ablkcipher spawn. The problem is that previously we did this in two steps, first getting the algorithm and then calling crypto_init_spawn. This meant that each spawn user had to be aware of what type and mask to use for these two steps. This is difficult and also presents a problem when the type/mask changes as they're about to be for IV generators. The new interface does both steps together just like crypto_alloc_ablkcipher. As a side-effect this also allows us to be stronger on type enforcement for spawns. For now this is only done for ablkcipher but it's trivial to extend for other types. This patch also moves the type/mask logic for skcipher into the helpers crypto_skcipher_type and crypto_skcipher_mask. Finally this patch introduces the function crypto_require_sync to determine whether the user is specifically requesting a sync algorithm. Signed-off-by: Herbert Xu --- crypto/ablkcipher.c | 25 +++++++++++++++++-- include/crypto/algapi.h | 22 +++++++++++++--- include/crypto/internal/skcipher.h | 51 ++++++++++++++++++++++++++++++++++++++ include/linux/crypto.h | 26 +++++++++++-------- 4 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 include/crypto/internal/skcipher.h (limited to 'include/linux/crypto.h') diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 2731acb86e7d..0083140304d2 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -13,14 +13,16 @@ * */ -#include -#include +#include +#include #include #include #include #include #include +#include "internal.h" + static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { @@ -105,5 +107,24 @@ const struct crypto_type crypto_ablkcipher_type = { }; EXPORT_SYMBOL_GPL(crypto_ablkcipher_type); +int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, + u32 type, u32 mask) +{ + struct crypto_alg *alg; + int err; + + type = crypto_skcipher_type(type); + mask = crypto_skcipher_mask(mask); + + 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; +} +EXPORT_SYMBOL_GPL(crypto_grab_skcipher); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Asynchronous block chaining cipher type"); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 726a765e5ec6..fda1759ffe2d 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -111,6 +111,12 @@ void crypto_drop_spawn(struct crypto_spawn *spawn); struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, u32 mask); +static inline void crypto_set_spawn(struct crypto_spawn *spawn, + struct crypto_instance *inst) +{ + spawn->inst = inst; +} + struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb); int crypto_check_attr_type(struct rtattr **tb, u32 type); const char *crypto_attr_alg_name(struct rtattr *rta); @@ -195,10 +201,9 @@ static inline struct crypto_instance *crypto_aead_alg_instance( static inline struct crypto_ablkcipher *crypto_spawn_ablkcipher( struct crypto_spawn *spawn) { - u32 type = CRYPTO_ALG_TYPE_BLKCIPHER; - u32 mask = CRYPTO_ALG_TYPE_BLKCIPHER_MASK; - - return __crypto_ablkcipher_cast(crypto_spawn_tfm(spawn, type, mask)); + return __crypto_ablkcipher_cast( + crypto_spawn_tfm(spawn, crypto_skcipher_type(0), + crypto_skcipher_mask(0))); } static inline struct crypto_blkcipher *crypto_spawn_blkcipher( @@ -308,5 +313,14 @@ static inline struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, return crypto_attr_alg(tb[1], type, mask); } +/* + * Returns CRYPTO_ALG_ASYNC if type/mask requires the use of sync algorithms. + * Otherwise returns zero. + */ +static inline int crypto_requires_sync(u32 type, u32 mask) +{ + return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC; +} + #endif /* _CRYPTO_ALGAPI_H */ diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h new file mode 100644 index 000000000000..87879e64ff4c --- /dev/null +++ b/include/crypto/internal/skcipher.h @@ -0,0 +1,51 @@ +/* + * Symmetric key ciphers. + * + * Copyright (c) 2007 Herbert Xu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _CRYPTO_INTERNAL_SKCIPHER_H +#define _CRYPTO_INTERNAL_SKCIPHER_H + +#include + +struct crypto_skcipher_spawn { + struct crypto_spawn base; +}; + +static inline void crypto_set_skcipher_spawn( + struct crypto_skcipher_spawn *spawn, struct crypto_instance *inst) +{ + crypto_set_spawn(&spawn->base, inst); +} + +int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, + u32 type, u32 mask); + +static inline void crypto_drop_skcipher(struct crypto_skcipher_spawn *spawn) +{ + crypto_drop_spawn(&spawn->base); +} + +static inline struct crypto_alg *crypto_skcipher_spawn_alg( + struct crypto_skcipher_spawn *spawn) +{ + return spawn->base.alg; +} + +static inline struct crypto_ablkcipher *crypto_spawn_skcipher( + struct crypto_skcipher_spawn *spawn) +{ + return __crypto_ablkcipher_cast( + crypto_spawn_tfm(&spawn->base, crypto_skcipher_type(0), + crypto_skcipher_mask(0))); +} + +#endif /* _CRYPTO_INTERNAL_SKCIPHER_H */ + diff --git a/include/linux/crypto.h b/include/linux/crypto.h index ef7642ed3e42..d6962b409489 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -528,16 +528,26 @@ static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast( return (struct crypto_ablkcipher *)tfm; } -static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher( - const char *alg_name, u32 type, u32 mask) +static inline u32 crypto_skcipher_type(u32 type) { type &= ~CRYPTO_ALG_TYPE_MASK; - mask &= ~CRYPTO_ALG_TYPE_MASK; type |= CRYPTO_ALG_TYPE_BLKCIPHER; + return type; +} + +static inline u32 crypto_skcipher_mask(u32 mask) +{ + mask &= ~CRYPTO_ALG_TYPE_MASK; mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; + return mask; +} +static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher( + const char *alg_name, u32 type, u32 mask) +{ return __crypto_ablkcipher_cast( - crypto_alloc_base(alg_name, type, mask)); + crypto_alloc_base(alg_name, crypto_skcipher_type(type), + crypto_skcipher_mask(mask))); } static inline struct crypto_tfm *crypto_ablkcipher_tfm( @@ -554,12 +564,8 @@ static inline void crypto_free_ablkcipher(struct crypto_ablkcipher *tfm) static inline int crypto_has_ablkcipher(const char *alg_name, u32 type, u32 mask) { - type &= ~CRYPTO_ALG_TYPE_MASK; - mask &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; - - return crypto_has_alg(alg_name, type, mask); + return crypto_has_alg(alg_name, crypto_skcipher_type(type), + crypto_skcipher_mask(mask)); } static inline struct ablkcipher_tfm *crypto_ablkcipher_crt( -- cgit v1.2.3 From 61da88e2b800eed2b03834a73c46cc89ad48716d Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 17 Dec 2007 21:51:27 +0800 Subject: [CRYPTO] skcipher: Add givcrypt operations and givcipher type Different block cipher modes have different requirements for intialisation vectors. For example, CBC can use a simple randomly generated IV while modes such as CTR must use an IV generation mechanisms that give a stronger guarantee on the lack of collisions. Furthermore, disk encryption modes have their own IV generation algorithms. Up until now IV generation has been left to the users of the symmetric key cipher API. This is inconvenient as the number of block cipher modes increase because the user needs to be aware of which mode is supposed to be paired with which IV generation algorithm. Therefore it makes sense to integrate the IV generation into the crypto API. This patch takes the first step in that direction by creating two new ablkcipher operations, givencrypt and givdecrypt that generates an IV before performing the actual encryption or decryption. The operations are currently not exposed to the user. That will be done once the underlying functionality has actually been implemented. It also creates the underlying givcipher type. Algorithms that directly generate IVs would use it instead of ablkcipher. All other algorithms (including all existing ones) would generate a givcipher algorithm upon registration. This givcipher algorithm will be constructed from the geniv string that's stored in every algorithm. That string will locate a template which is instantiated by the blkcipher/ablkcipher algorithm in question to give a givcipher algorithm. Signed-off-by: Herbert Xu --- crypto/ablkcipher.c | 46 ++++++++++++++++++++++++++++++++++++++ include/crypto/internal/skcipher.h | 9 ++++++++ include/crypto/skcipher.h | 38 +++++++++++++++++++++++++++++++ include/linux/crypto.h | 7 ++++++ 4 files changed, 100 insertions(+) create mode 100644 include/crypto/skcipher.h (limited to 'include/linux/crypto.h') diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 0083140304d2..e403d8137ecd 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -107,6 +107,52 @@ const struct crypto_type crypto_ablkcipher_type = { }; EXPORT_SYMBOL_GPL(crypto_ablkcipher_type); +static int no_givdecrypt(struct skcipher_givcrypt_request *req) +{ + return -ENOSYS; +} + +static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type, + u32 mask) +{ + struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; + struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; + + if (alg->ivsize > PAGE_SIZE / 8) + return -EINVAL; + + crt->setkey = setkey; + crt->encrypt = alg->encrypt; + crt->decrypt = alg->decrypt; + crt->givencrypt = alg->givencrypt; + crt->givdecrypt = alg->givdecrypt ?: no_givdecrypt; + crt->ivsize = alg->ivsize; + + return 0; +} + +static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg) +{ + struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher; + + seq_printf(m, "type : givcipher\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); + seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); + seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); +} + +const struct crypto_type crypto_givcipher_type = { + .ctxsize = crypto_ablkcipher_ctxsize, + .init = crypto_init_givcipher_ops, +#ifdef CONFIG_PROC_FS + .show = crypto_givcipher_show, +#endif +}; +EXPORT_SYMBOL_GPL(crypto_givcipher_type); + int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, u32 type, u32 mask) { diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h index 87879e64ff4c..c9402dd12d03 100644 --- a/include/crypto/internal/skcipher.h +++ b/include/crypto/internal/skcipher.h @@ -14,11 +14,14 @@ #define _CRYPTO_INTERNAL_SKCIPHER_H #include +#include struct crypto_skcipher_spawn { struct crypto_spawn base; }; +extern const struct crypto_type crypto_givcipher_type; + static inline void crypto_set_skcipher_spawn( struct crypto_skcipher_spawn *spawn, struct crypto_instance *inst) { @@ -47,5 +50,11 @@ static inline struct crypto_ablkcipher *crypto_spawn_skcipher( crypto_skcipher_mask(0))); } +static inline void *skcipher_givcrypt_reqctx( + struct skcipher_givcrypt_request *req) +{ + return ablkcipher_request_ctx(&req->creq); +} + #endif /* _CRYPTO_INTERNAL_SKCIPHER_H */ diff --git a/include/crypto/skcipher.h b/include/crypto/skcipher.h new file mode 100644 index 000000000000..c283fab5eddb --- /dev/null +++ b/include/crypto/skcipher.h @@ -0,0 +1,38 @@ +/* + * Symmetric key ciphers. + * + * Copyright (c) 2007 Herbert Xu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _CRYPTO_SKCIPHER_H +#define _CRYPTO_SKCIPHER_H + +#include + +/** + * struct skcipher_givcrypt_request - Crypto request with IV generation + * @seq: Sequence number for IV generation + * @giv: Space for generated IV + * @creq: The crypto request itself + */ +struct skcipher_givcrypt_request { + u64 seq; + u8 *giv; + + struct ablkcipher_request creq; +}; + +static inline struct crypto_ablkcipher *skcipher_givcrypt_reqtfm( + struct skcipher_givcrypt_request *req) +{ + return crypto_ablkcipher_reqtfm(&req->creq); +} + +#endif /* _CRYPTO_SKCIPHER_H */ + diff --git a/include/linux/crypto.h b/include/linux/crypto.h index d6962b409489..3656a24ea7f0 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -34,6 +34,7 @@ #define CRYPTO_ALG_TYPE_HASH 0x00000003 #define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 #define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005 +#define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006 #define CRYPTO_ALG_TYPE_COMPRESS 0x00000008 #define CRYPTO_ALG_TYPE_AEAD 0x00000009 @@ -99,6 +100,7 @@ struct crypto_blkcipher; struct crypto_hash; struct crypto_tfm; struct crypto_type; +struct skcipher_givcrypt_request; typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err); @@ -178,6 +180,8 @@ struct ablkcipher_alg { unsigned int keylen); int (*encrypt)(struct ablkcipher_request *req); int (*decrypt)(struct ablkcipher_request *req); + int (*givencrypt)(struct skcipher_givcrypt_request *req); + int (*givdecrypt)(struct skcipher_givcrypt_request *req); unsigned int min_keysize; unsigned int max_keysize; @@ -320,6 +324,9 @@ struct ablkcipher_tfm { unsigned int keylen); int (*encrypt)(struct ablkcipher_request *req); int (*decrypt)(struct ablkcipher_request *req); + int (*givencrypt)(struct skcipher_givcrypt_request *req); + int (*givdecrypt)(struct skcipher_givcrypt_request *req); + unsigned int ivsize; unsigned int reqsize; }; -- cgit v1.2.3 From 23508e11ab3bb405dca66bf4d77e488bf2b07b0c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 27 Nov 2007 21:33:24 +0800 Subject: [CRYPTO] skcipher: Added geniv field This patch introduces the geniv field which indicates the default IV generator for each algorithm. It should point to a string that is not freed as long as the algorithm is registered. Signed-off-by: Herbert Xu --- crypto/ablkcipher.c | 2 ++ crypto/blkcipher.c | 2 ++ include/linux/crypto.h | 4 ++++ 3 files changed, 8 insertions(+) (limited to 'include/linux/crypto.h') diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index e403d8137ecd..8f48b4d58fca 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -96,6 +96,7 @@ static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); + seq_printf(m, "geniv : %s\n", ablkcipher->geniv ?: ""); } const struct crypto_type crypto_ablkcipher_type = { @@ -142,6 +143,7 @@ static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); + seq_printf(m, "geniv : %s\n", ablkcipher->geniv ?: ""); } const struct crypto_type crypto_givcipher_type = { diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 7939504dfd8b..7a3e1a308074 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -496,6 +496,8 @@ static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "min keysize : %u\n", alg->cra_blkcipher.min_keysize); seq_printf(m, "max keysize : %u\n", alg->cra_blkcipher.max_keysize); seq_printf(m, "ivsize : %u\n", alg->cra_blkcipher.ivsize); + seq_printf(m, "geniv : %s\n", alg->cra_blkcipher.geniv ?: + ""); } const struct crypto_type crypto_blkcipher_type = { diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 3656a24ea7f0..facafa1bd8ca 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -183,6 +183,8 @@ struct ablkcipher_alg { int (*givencrypt)(struct skcipher_givcrypt_request *req); int (*givdecrypt)(struct skcipher_givcrypt_request *req); + const char *geniv; + unsigned int min_keysize; unsigned int max_keysize; unsigned int ivsize; @@ -209,6 +211,8 @@ struct blkcipher_alg { struct scatterlist *dst, struct scatterlist *src, unsigned int nbytes); + const char *geniv; + unsigned int min_keysize; unsigned int max_keysize; unsigned int ivsize; -- cgit v1.2.3 From ecfc43292f68566c144afca966b46b371c26d56c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 5 Dec 2007 21:08:36 +1100 Subject: [CRYPTO] skcipher: Add skcipher_geniv_alloc/skcipher_geniv_free This patch creates the infrastructure to help the construction of givcipher templates that wrap around existing blkcipher/ablkcipher algorithms by adding an IV generator to them. Signed-off-by: Herbert Xu --- crypto/ablkcipher.c | 10 +- crypto/blkcipher.c | 185 ++++++++++++++++++++++++++++++++++++- include/crypto/internal/skcipher.h | 18 ++++ include/linux/crypto.h | 18 +++- 4 files changed, 225 insertions(+), 6 deletions(-) (limited to 'include/linux/crypto.h') diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 8f48b4d58fca..092d9659b861 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -80,6 +80,7 @@ static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type, crt->setkey = setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; + crt->base = __crypto_ablkcipher_cast(tfm); crt->ivsize = alg->ivsize; return 0; @@ -122,11 +123,13 @@ static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type, if (alg->ivsize > PAGE_SIZE / 8) return -EINVAL; - crt->setkey = setkey; + 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; crt->givdecrypt = alg->givdecrypt ?: no_givdecrypt; + crt->base = __crypto_ablkcipher_cast(tfm); crt->ivsize = alg->ivsize; return 0; @@ -155,6 +158,11 @@ const struct crypto_type crypto_givcipher_type = { }; EXPORT_SYMBOL_GPL(crypto_givcipher_type); +const char *crypto_default_geniv(const struct crypto_alg *alg) +{ + return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : "chainiv"; +} + int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, u32 type, u32 mask) { diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index 7a3e1a308074..ca6ef065cded 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -14,8 +14,8 @@ * */ +#include #include -#include #include #include #include @@ -450,6 +450,7 @@ static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm) crt->setkey = async_setkey; crt->encrypt = async_encrypt; crt->decrypt = async_decrypt; + crt->base = __crypto_ablkcipher_cast(tfm); crt->ivsize = alg->ivsize; return 0; @@ -509,5 +510,187 @@ const struct crypto_type crypto_blkcipher_type = { }; EXPORT_SYMBOL_GPL(crypto_blkcipher_type); +static int crypto_grab_nivcipher(struct crypto_skcipher_spawn *spawn, + const char *name, u32 type, u32 mask) +{ + struct crypto_alg *alg; + int err; + + type = crypto_skcipher_type(type); + mask = crypto_skcipher_mask(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; +} + +struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl, + struct rtattr **tb, u32 type, + u32 mask) +{ + struct { + int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen); + int (*encrypt)(struct ablkcipher_request *req); + int (*decrypt)(struct ablkcipher_request *req); + + unsigned int min_keysize; + unsigned int max_keysize; + unsigned int ivsize; + + const char *geniv; + } balg; + const char *name; + struct crypto_skcipher_spawn *spawn; + struct crypto_attr_type *algt; + struct crypto_instance *inst; + struct crypto_alg *alg; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ (CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_GENIV)) & + algt->mask) + return ERR_PTR(-EINVAL); + + name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(name); + if (IS_ERR(name)) + return ERR_PTR(err); + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return ERR_PTR(-ENOMEM); + + spawn = crypto_instance_ctx(inst); + + /* Ignore async algorithms if necessary. */ + mask |= crypto_requires_sync(algt->type, algt->mask); + + crypto_set_skcipher_spawn(spawn, inst); + err = crypto_grab_nivcipher(spawn, name, type, mask); + if (err) + goto err_free_inst; + + alg = crypto_skcipher_spawn_alg(spawn); + + if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_BLKCIPHER) { + balg.ivsize = alg->cra_blkcipher.ivsize; + balg.min_keysize = alg->cra_blkcipher.min_keysize; + balg.max_keysize = alg->cra_blkcipher.max_keysize; + + balg.setkey = async_setkey; + balg.encrypt = async_encrypt; + balg.decrypt = async_decrypt; + + balg.geniv = alg->cra_blkcipher.geniv; + } else { + balg.ivsize = alg->cra_ablkcipher.ivsize; + balg.min_keysize = alg->cra_ablkcipher.min_keysize; + balg.max_keysize = alg->cra_ablkcipher.max_keysize; + + balg.setkey = alg->cra_ablkcipher.setkey; + balg.encrypt = alg->cra_ablkcipher.encrypt; + balg.decrypt = alg->cra_ablkcipher.decrypt; + + balg.geniv = alg->cra_ablkcipher.geniv; + } + + err = -EINVAL; + if (!balg.ivsize) + goto err_drop_alg; + + /* + * This is only true if we're constructing an algorithm with its + * default IV generator. For the default generator we elide the + * template name and double-check the IV generator. + */ + if (algt->mask & CRYPTO_ALG_GENIV) { + if (!balg.geniv) + balg.geniv = crypto_default_geniv(alg); + err = -EAGAIN; + if (strcmp(tmpl->name, balg.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, + 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; + } + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | 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_givcipher_type; + + inst->alg.cra_ablkcipher.ivsize = balg.ivsize; + inst->alg.cra_ablkcipher.min_keysize = balg.min_keysize; + inst->alg.cra_ablkcipher.max_keysize = balg.max_keysize; + inst->alg.cra_ablkcipher.geniv = balg.geniv; + + inst->alg.cra_ablkcipher.setkey = balg.setkey; + inst->alg.cra_ablkcipher.encrypt = balg.encrypt; + inst->alg.cra_ablkcipher.decrypt = balg.decrypt; + +out: + return inst; + +err_drop_alg: + crypto_drop_skcipher(spawn); +err_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} +EXPORT_SYMBOL_GPL(skcipher_geniv_alloc); + +void skcipher_geniv_free(struct crypto_instance *inst) +{ + crypto_drop_skcipher(crypto_instance_ctx(inst)); + kfree(inst); +} +EXPORT_SYMBOL_GPL(skcipher_geniv_free); + +int skcipher_geniv_init(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = (void *)tfm->__crt_alg; + struct crypto_ablkcipher *cipher; + + cipher = crypto_spawn_skcipher(crypto_instance_ctx(inst)); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + tfm->crt_ablkcipher.base = cipher; + tfm->crt_ablkcipher.reqsize += crypto_ablkcipher_reqsize(cipher); + + return 0; +} +EXPORT_SYMBOL_GPL(skcipher_geniv_init); + +void skcipher_geniv_exit(struct crypto_tfm *tfm) +{ + crypto_free_ablkcipher(tfm->crt_ablkcipher.base); +} +EXPORT_SYMBOL_GPL(skcipher_geniv_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Generic block chaining cipher type"); diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h index c9402dd12d03..07e7c82324ad 100644 --- a/include/crypto/internal/skcipher.h +++ b/include/crypto/internal/skcipher.h @@ -15,6 +15,9 @@ #include #include +#include + +struct rtattr; struct crypto_skcipher_spawn { struct crypto_spawn base; @@ -50,6 +53,21 @@ static inline struct crypto_ablkcipher *crypto_spawn_skcipher( crypto_skcipher_mask(0))); } +const char *crypto_default_geniv(const struct crypto_alg *alg); + +struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl, + struct rtattr **tb, u32 type, + u32 mask); +void skcipher_geniv_free(struct crypto_instance *inst); +int skcipher_geniv_init(struct crypto_tfm *tfm); +void skcipher_geniv_exit(struct crypto_tfm *tfm); + +static inline struct crypto_ablkcipher *skcipher_geniv_cipher( + struct crypto_ablkcipher *geniv) +{ + return crypto_ablkcipher_crt(geniv)->base; +} + static inline void *skcipher_givcrypt_reqctx( struct skcipher_givcrypt_request *req) { diff --git a/include/linux/crypto.h b/include/linux/crypto.h index facafa1bd8ca..fa7afa9b9f4f 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -52,6 +52,12 @@ */ #define CRYPTO_ALG_NEED_FALLBACK 0x00000100 +/* + * This bit is set for symmetric key ciphers that have already been wrapped + * with a generic IV generator to prevent them from being wrapped again. + */ +#define CRYPTO_ALG_GENIV 0x00000200 + /* * Transform masks and values (for crt_flags). */ @@ -331,6 +337,8 @@ struct ablkcipher_tfm { int (*givencrypt)(struct skcipher_givcrypt_request *req); int (*givdecrypt)(struct skcipher_givcrypt_request *req); + struct crypto_ablkcipher *base; + unsigned int ivsize; unsigned int reqsize; }; @@ -541,14 +549,14 @@ static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast( static inline u32 crypto_skcipher_type(u32 type) { - type &= ~CRYPTO_ALG_TYPE_MASK; + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); type |= CRYPTO_ALG_TYPE_BLKCIPHER; return type; } static inline u32 crypto_skcipher_mask(u32 mask) { - mask &= ~CRYPTO_ALG_TYPE_MASK; + mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; return mask; } @@ -623,7 +631,9 @@ static inline void crypto_ablkcipher_clear_flags(struct crypto_ablkcipher *tfm, static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen) { - return crypto_ablkcipher_crt(tfm)->setkey(tfm, key, keylen); + struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(tfm); + + return crt->setkey(crt->base, key, keylen); } static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm( @@ -655,7 +665,7 @@ static inline unsigned int crypto_ablkcipher_reqsize( static inline void ablkcipher_request_set_tfm( struct ablkcipher_request *req, struct crypto_ablkcipher *tfm) { - req->base.tfm = crypto_ablkcipher_tfm(tfm); + req->base.tfm = crypto_ablkcipher_tfm(crypto_ablkcipher_crt(tfm)->base); } static inline struct ablkcipher_request *ablkcipher_request_cast( -- cgit v1.2.3 From b9c55aa475599183d0eab6833ea23e70c52dd24b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 4 Dec 2007 12:46:48 +1100 Subject: [CRYPTO] skcipher: Create default givcipher instances This patch makes crypto_alloc_ablkcipher/crypto_grab_skcipher always return algorithms that are capable of generating their own IVs through givencrypt and givdecrypt. Each algorithm may specify its default IV generator through the geniv field. For algorithms that do not set the geniv field, the blkcipher layer will pick a default. Currently it's chainiv for synchronous algorithms and eseqiv for asynchronous algorithms. Note that if these wrappers do not work on an algorithm then that algorithm must specify its own geniv or it can't be used at all. Signed-off-by: Herbert Xu --- crypto/ablkcipher.c | 158 ++++++++++++++++++++++++++++++++++++- crypto/api.c | 19 +++-- crypto/blkcipher.c | 4 + crypto/internal.h | 2 + include/crypto/internal/skcipher.h | 2 + include/linux/crypto.h | 9 +-- 6 files changed, 181 insertions(+), 13 deletions(-) (limited to 'include/linux/crypto.h') diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index 092d9659b861..d1df528c8fa3 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -68,6 +70,16 @@ static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type, return alg->cra_ctxsize; } +int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req) +{ + return crypto_ablkcipher_encrypt(&req->creq); +} + +int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req) +{ + return crypto_ablkcipher_decrypt(&req->creq); +} + static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { @@ -80,6 +92,10 @@ static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type, crt->setkey = setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; + if (!alg->ivsize) { + crt->givencrypt = skcipher_null_givencrypt; + crt->givdecrypt = skcipher_null_givdecrypt; + } crt->base = __crypto_ablkcipher_cast(tfm); crt->ivsize = alg->ivsize; @@ -163,6 +179,108 @@ const char *crypto_default_geniv(const struct crypto_alg *alg) return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : "chainiv"; } +static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask) +{ + struct rtattr *tb[3]; + struct { + struct rtattr attr; + struct crypto_attr_type data; + } ptype; + struct { + struct rtattr attr; + struct crypto_attr_alg data; + } palg; + struct crypto_template *tmpl; + struct crypto_instance *inst; + struct crypto_alg *larval; + const char *geniv; + int err; + + larval = crypto_larval_lookup(alg->cra_driver_name, + CRYPTO_ALG_TYPE_GIVCIPHER, + CRYPTO_ALG_TYPE_MASK); + err = PTR_ERR(larval); + if (IS_ERR(larval)) + goto out; + + err = -EAGAIN; + if (!crypto_is_larval(larval)) + goto drop_larval; + + ptype.attr.rta_len = sizeof(ptype); + ptype.attr.rta_type = CRYPTOA_TYPE; + ptype.data.type = type | CRYPTO_ALG_GENIV; + /* GENIV tells the template that we're making a default geniv. */ + ptype.data.mask = mask | CRYPTO_ALG_GENIV; + tb[0] = &ptype.attr; + + palg.attr.rta_len = sizeof(palg); + palg.attr.rta_type = CRYPTOA_ALG; + /* Must use the exact name to locate ourselves. */ + memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME); + tb[1] = &palg.attr; + + tb[2] = NULL; + + if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_BLKCIPHER) + geniv = alg->cra_blkcipher.geniv; + else + geniv = alg->cra_ablkcipher.geniv; + + if (!geniv) + geniv = crypto_default_geniv(alg); + + tmpl = crypto_lookup_template(geniv); + err = -ENOENT; + if (!tmpl) + goto kill_larval; + + inst = tmpl->alloc(tb); + err = PTR_ERR(inst); + if (IS_ERR(inst)) + goto put_tmpl; + + if ((err = crypto_register_instance(tmpl, inst))) { + tmpl->free(inst); + goto put_tmpl; + } + + /* Redo the lookup to use the instance we just registered. */ + err = -EAGAIN; + +put_tmpl: + crypto_tmpl_put(tmpl); +kill_larval: + crypto_larval_kill(larval); +drop_larval: + crypto_mod_put(larval); +out: + crypto_mod_put(alg); + return err; +} + +static struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type, + u32 mask) +{ + struct crypto_alg *alg; + + alg = crypto_alg_mod_lookup(name, type, mask); + if (IS_ERR(alg)) + return alg; + + if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_GIVCIPHER) + return alg; + + if (!((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == + CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize : + alg->cra_ablkcipher.ivsize)) + return alg; + + return ERR_PTR(crypto_givcipher_default(alg, type, mask)); +} + int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, u32 type, u32 mask) { @@ -172,7 +290,7 @@ int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, type = crypto_skcipher_type(type); mask = crypto_skcipher_mask(mask); - alg = crypto_alg_mod_lookup(name, type, mask); + alg = crypto_lookup_skcipher(name, type, mask); if (IS_ERR(alg)) return PTR_ERR(alg); @@ -182,5 +300,43 @@ int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, } EXPORT_SYMBOL_GPL(crypto_grab_skcipher); +struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name, + u32 type, u32 mask) +{ + struct crypto_tfm *tfm; + int err; + + type = crypto_skcipher_type(type); + mask = crypto_skcipher_mask(mask); + + for (;;) { + struct crypto_alg *alg; + + alg = crypto_lookup_skcipher(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_ablkcipher_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); +} +EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Asynchronous block chaining cipher type"); diff --git a/crypto/api.c b/crypto/api.c index 1f5c72477356..a2496d1bc6d4 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -137,7 +137,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, return alg; } -static void crypto_larval_kill(struct crypto_alg *alg) +void crypto_larval_kill(struct crypto_alg *alg) { struct crypto_larval *larval = (void *)alg; @@ -147,6 +147,7 @@ static void crypto_larval_kill(struct crypto_alg *alg) complete_all(&larval->completion); crypto_alg_put(alg); } +EXPORT_SYMBOL_GPL(crypto_larval_kill); static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) { @@ -176,11 +177,9 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, return alg; } -struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) +struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *alg; - struct crypto_alg *larval; - int ok; if (!name) return ERR_PTR(-ENOENT); @@ -193,7 +192,17 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) if (alg) return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; - larval = crypto_larval_alloc(name, type, mask); + return crypto_larval_alloc(name, type, mask); +} +EXPORT_SYMBOL_GPL(crypto_larval_lookup); + +struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) +{ + struct crypto_alg *alg; + struct crypto_alg *larval; + int ok; + + larval = crypto_larval_lookup(name, type, mask); if (IS_ERR(larval) || !crypto_is_larval(larval)) return larval; diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index ca6ef065cded..4a7e65c4df4d 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -450,6 +450,10 @@ static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm) crt->setkey = async_setkey; crt->encrypt = async_encrypt; crt->decrypt = async_decrypt; + if (!alg->ivsize) { + crt->givencrypt = skcipher_null_givencrypt; + crt->givdecrypt = skcipher_null_givdecrypt; + } crt->base = __crypto_ablkcipher_cast(tfm); crt->ivsize = alg->ivsize; diff --git a/crypto/internal.h b/crypto/internal.h index cb13952f82bf..32f4c2145603 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -93,6 +93,8 @@ void crypto_exit_digest_ops(struct crypto_tfm *tfm); void crypto_exit_cipher_ops(struct crypto_tfm *tfm); void crypto_exit_compress_ops(struct crypto_tfm *tfm); +void crypto_larval_kill(struct crypto_alg *alg); +struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask); void crypto_larval_error(const char *name, u32 type, u32 mask); void crypto_shoot_alg(struct crypto_alg *alg); diff --git a/include/crypto/internal/skcipher.h b/include/crypto/internal/skcipher.h index 80c5bfb14a60..2071999d4b5e 100644 --- a/include/crypto/internal/skcipher.h +++ b/include/crypto/internal/skcipher.h @@ -53,6 +53,8 @@ static inline struct crypto_ablkcipher *crypto_spawn_skcipher( crypto_skcipher_mask(0))); } +int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req); +int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req); const char *crypto_default_geniv(const struct crypto_alg *alg); struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl, diff --git a/include/linux/crypto.h b/include/linux/crypto.h index fa7afa9b9f4f..835dcaf3fe4e 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -561,13 +561,8 @@ static inline u32 crypto_skcipher_mask(u32 mask) return mask; } -static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher( - const char *alg_name, u32 type, u32 mask) -{ - return __crypto_ablkcipher_cast( - crypto_alloc_base(alg_name, crypto_skcipher_type(type), - crypto_skcipher_mask(mask))); -} +struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name, + u32 type, u32 mask); static inline struct crypto_tfm *crypto_ablkcipher_tfm( struct crypto_ablkcipher *tfm) -- cgit v1.2.3 From 743edf57272fd420348e148bf94f9e48ed6abb70 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 10 Dec 2007 16:18:01 +0800 Subject: [CRYPTO] aead: Add givcrypt operations This patch adds the underlying givcrypt operations for aead and associated support elements. The rationale is identical to that of the skcipher givcrypt operations, i.e., sometimes only the algorithm knows how the IV should be generated. A new request type aead_givcrypt_request is added which contains an embedded aead_request structure with two new elements to support this operation. The new elements are seq and giv. The seq field should contain a strictly increasing 64-bit integer which may be used by certain IV generators as an input value. The giv field will be used to store the generated IV. It does not need to obey the alignment requirements of the algorithm because it's not used during the operation. The existing iv field must still be available as it will be used to store intermediate IVs and the output IV if chaining is desired. Signed-off-by: Herbert Xu --- crypto/aead.c | 7 +++++++ include/crypto/aead.h | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/crypto.h | 5 +++++ 3 files changed, 50 insertions(+) create mode 100644 include/crypto/aead.h (limited to 'include/linux/crypto.h') diff --git a/crypto/aead.c b/crypto/aead.c index f23c2b0ee009..0402b606fcfd 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -77,6 +77,11 @@ static unsigned int crypto_aead_ctxsize(struct crypto_alg *alg, u32 type, return alg->cra_ctxsize; } +static int no_givdecrypt(struct aead_givcrypt_request *req) +{ + return -ENOSYS; +} + static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) { struct aead_alg *alg = &tfm->__crt_alg->cra_aead; @@ -88,6 +93,8 @@ static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) crt->setkey = setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; + crt->givencrypt = alg->givencrypt; + crt->givdecrypt = alg->givdecrypt ?: no_givdecrypt; crt->ivsize = alg->ivsize; crt->authsize = alg->maxauthsize; diff --git a/include/crypto/aead.h b/include/crypto/aead.h new file mode 100644 index 000000000000..083920312da0 --- /dev/null +++ b/include/crypto/aead.h @@ -0,0 +1,38 @@ +/* + * AEAD: Authenticated Encryption with Associated Data + * + * Copyright (c) 2007 Herbert Xu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _CRYPTO_AEAD_H +#define _CRYPTO_AEAD_H + +#include +#include + +/** + * struct aead_givcrypt_request - AEAD request with IV generation + * @seq: Sequence number for IV generation + * @giv: Space for generated IV + * @areq: The AEAD request itself + */ +struct aead_givcrypt_request { + u64 seq; + u8 *giv; + + struct aead_request areq; +}; + +static inline struct crypto_aead *aead_givcrypt_reqtfm( + struct aead_givcrypt_request *req) +{ + return crypto_aead_reqtfm(&req->areq); +} + +#endif /* _CRYPTO_AEAD_H */ diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 835dcaf3fe4e..7524928bff93 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -106,6 +106,7 @@ struct crypto_blkcipher; struct crypto_hash; struct crypto_tfm; struct crypto_type; +struct aead_givcrypt_request; struct skcipher_givcrypt_request; typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err); @@ -202,6 +203,8 @@ struct aead_alg { int (*setauthsize)(struct crypto_aead *tfm, unsigned int authsize); int (*encrypt)(struct aead_request *req); int (*decrypt)(struct aead_request *req); + int (*givencrypt)(struct aead_givcrypt_request *req); + int (*givdecrypt)(struct aead_givcrypt_request *req); unsigned int ivsize; unsigned int maxauthsize; @@ -348,6 +351,8 @@ struct aead_tfm { unsigned int keylen); int (*encrypt)(struct aead_request *req); int (*decrypt)(struct aead_request *req); + int (*givencrypt)(struct aead_givcrypt_request *req); + int (*givdecrypt)(struct aead_givcrypt_request *req); unsigned int ivsize; unsigned int authsize; unsigned int reqsize; -- cgit v1.2.3 From 5b6d2d7fdf806f2b5a9352416f9e670911fc4748 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 12 Dec 2007 19:23:36 +0800 Subject: [CRYPTO] aead: Add aead_geniv_alloc/aead_geniv_free This patch creates the infrastructure to help the construction of IV generator templates that wrap around AEAD algorithms by adding an IV generator to them. This is useful for AEAD algorithms with no built-in IV generator or to replace their built-in generator. Signed-off-by: Herbert Xu --- crypto/aead.c | 216 ++++++++++++++++++++++++++++++++++++++++- include/crypto/internal/aead.h | 77 +++++++++++++++ include/linux/crypto.h | 11 ++- 3 files changed, 297 insertions(+), 7 deletions(-) create mode 100644 include/crypto/internal/aead.h (limited to 'include/linux/crypto.h') diff --git a/crypto/aead.c b/crypto/aead.c index 15335ed9010a..9f7aca891926 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -12,14 +12,16 @@ * */ -#include -#include +#include +#include #include #include #include #include #include +#include "internal.h" + static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { @@ -55,18 +57,20 @@ static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) 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(tfm, authsize); + err = crypto_aead_alg(tfm)->setauthsize(crt->base, authsize); if (err) return err; } - crypto_aead_crt(tfm)->authsize = authsize; + crypto_aead_crt(crt->base)->authsize = authsize; + crt->authsize = authsize; return 0; } EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); @@ -90,11 +94,13 @@ static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) return -EINVAL; - crt->setkey = setkey; + 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); crt->ivsize = alg->ivsize; crt->authsize = alg->maxauthsize; @@ -111,6 +117,7 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) 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 : %s\n", aead->geniv ?: ""); } const struct crypto_type crypto_aead_type = { @@ -122,5 +129,204 @@ const struct crypto_type crypto_aead_type = { }; EXPORT_SYMBOL_GPL(crypto_aead_type); +static int aead_null_givencrypt(struct aead_givcrypt_request *req) +{ + return crypto_aead_encrypt(&req->areq); +} + +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; +} + +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; + + seq_printf(m, "type : nivaead\n"); + 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 : %s\n", aead->geniv); +} + +const struct crypto_type crypto_nivaead_type = { + .ctxsize = crypto_aead_ctxsize, + .init = crypto_init_nivaead_ops, +#ifdef CONFIG_PROC_FS + .show = crypto_nivaead_show, +#endif +}; +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; +} + +struct crypto_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; + int err; + + algt = crypto_get_attr_type(tb); + err = PTR_ERR(algt); + if (IS_ERR(algt)) + return ERR_PTR(err); + + if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV)) & + algt->mask) + return ERR_PTR(-EINVAL); + + name = crypto_attr_alg_name(tb[1]); + err = PTR_ERR(name); + if (IS_ERR(name)) + return ERR_PTR(err); + + inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); + if (!inst) + return ERR_PTR(-ENOMEM); + + spawn = crypto_instance_ctx(inst); + + /* Ignore async algorithms if necessary. */ + mask |= crypto_requires_sync(algt->type, algt->mask); + + crypto_set_aead_spawn(spawn, inst); + err = crypto_grab_nivaead(spawn, name, type, mask); + if (err) + goto err_free_inst; + + alg = crypto_aead_spawn_alg(spawn); + + err = -EINVAL; + if (!alg->cra_aead.ivsize) + goto err_drop_alg; + + /* + * This is only true if we're constructing an algorithm with its + * default IV generator. For the default generator we elide the + * template name and double-check the IV generator. + */ + if (algt->mask & CRYPTO_ALG_GENIV) { + if (strcmp(tmpl->name, alg->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, + 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; + } + + 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; + + 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.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; + +out: + return inst; + +err_drop_alg: + crypto_drop_aead(spawn); +err_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} +EXPORT_SYMBOL_GPL(aead_geniv_alloc); + +void aead_geniv_free(struct crypto_instance *inst) +{ + crypto_drop_aead(crypto_instance_ctx(inst)); + kfree(inst); +} +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 *aead; + + aead = crypto_spawn_aead(crypto_instance_ctx(inst)); + if (IS_ERR(aead)) + return PTR_ERR(aead); + + tfm->crt_aead.base = aead; + tfm->crt_aead.reqsize += crypto_aead_reqsize(aead); + + return 0; +} +EXPORT_SYMBOL_GPL(aead_geniv_init); + +void aead_geniv_exit(struct crypto_tfm *tfm) +{ + crypto_free_aead(tfm->crt_aead.base); +} +EXPORT_SYMBOL_GPL(aead_geniv_exit); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); diff --git a/include/crypto/internal/aead.h b/include/crypto/internal/aead.h new file mode 100644 index 000000000000..eb4eee7a7804 --- /dev/null +++ b/include/crypto/internal/aead.h @@ -0,0 +1,77 @@ +/* + * AEAD: Authenticated Encryption with Associated Data + * + * Copyright (c) 2007 Herbert Xu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#ifndef _CRYPTO_INTERNAL_AEAD_H +#define _CRYPTO_INTERNAL_AEAD_H + +#include +#include +#include + +struct rtattr; + +struct crypto_aead_spawn { + struct crypto_spawn base; +}; + +extern const struct crypto_type crypto_nivaead_type; + +static inline void crypto_set_aead_spawn( + struct crypto_aead_spawn *spawn, struct crypto_instance *inst) +{ + crypto_set_spawn(&spawn->base, inst); +} + +static inline void crypto_drop_aead(struct crypto_aead_spawn *spawn) +{ + crypto_drop_spawn(&spawn->base); +} + +static inline struct crypto_alg *crypto_aead_spawn_alg( + struct crypto_aead_spawn *spawn) +{ + return spawn->base.alg; +} + +static inline struct crypto_aead *crypto_spawn_aead( + struct crypto_aead_spawn *spawn) +{ + return __crypto_aead_cast( + crypto_spawn_tfm(&spawn->base, CRYPTO_ALG_TYPE_AEAD, + CRYPTO_ALG_TYPE_MASK)); +} + +struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl, + struct rtattr **tb, u32 type, + u32 mask); +void aead_geniv_free(struct crypto_instance *inst); +int aead_geniv_init(struct crypto_tfm *tfm); +void aead_geniv_exit(struct crypto_tfm *tfm); + +static inline struct crypto_aead *aead_geniv_base(struct crypto_aead *geniv) +{ + return crypto_aead_crt(geniv)->base; +} + +static inline void *aead_givcrypt_reqctx(struct aead_givcrypt_request *req) +{ + return aead_request_ctx(&req->areq); +} + +static inline void aead_givcrypt_complete(struct aead_givcrypt_request *req, + int err) +{ + aead_request_complete(&req->areq, err); +} + +#endif /* _CRYPTO_INTERNAL_AEAD_H */ + diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 7524928bff93..639385a9672d 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -206,6 +206,8 @@ struct aead_alg { int (*givencrypt)(struct aead_givcrypt_request *req); int (*givdecrypt)(struct aead_givcrypt_request *req); + const char *geniv; + unsigned int ivsize; unsigned int maxauthsize; }; @@ -353,6 +355,9 @@ struct aead_tfm { int (*decrypt)(struct aead_request *req); int (*givencrypt)(struct aead_givcrypt_request *req); int (*givdecrypt)(struct aead_givcrypt_request *req); + + struct crypto_aead *base; + unsigned int ivsize; unsigned int authsize; unsigned int reqsize; @@ -781,7 +786,9 @@ static inline void crypto_aead_clear_flags(struct crypto_aead *tfm, u32 flags) static inline int crypto_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) { - return crypto_aead_crt(tfm)->setkey(tfm, key, keylen); + struct aead_tfm *crt = crypto_aead_crt(tfm); + + return crt->setkey(crt->base, key, keylen); } int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize); @@ -809,7 +816,7 @@ static inline unsigned int crypto_aead_reqsize(struct crypto_aead *tfm) static inline void aead_request_set_tfm(struct aead_request *req, struct crypto_aead *tfm) { - req->base.tfm = crypto_aead_tfm(tfm); + req->base.tfm = crypto_aead_tfm(crypto_aead_crt(tfm)->base); } static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm, -- cgit v1.2.3 From d29ce988aeb459203c74f14747f4f77e1829ef78 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Wed, 12 Dec 2007 19:24:27 +0800 Subject: [CRYPTO] aead: Create default givcipher instances This patch makes crypto_alloc_aead always return algorithms that is capable of generating their own IVs through givencrypt and givdecrypt. All existing AEAD algorithms already do. New ones must either supply their own or specify a generic IV generator with the geniv field. Signed-off-by: Herbert Xu --- crypto/aead.c | 153 +++++++++++++++++++++++++++++++++++++++++ include/crypto/internal/aead.h | 3 + include/linux/crypto.h | 10 +-- 3 files changed, 157 insertions(+), 9 deletions(-) (limited to 'include/linux/crypto.h') diff --git a/crypto/aead.c b/crypto/aead.c index 9f7aca891926..f5b1add31976 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -328,5 +329,157 @@ void aead_geniv_exit(struct crypto_tfm *tfm) } EXPORT_SYMBOL_GPL(aead_geniv_exit); +static int crypto_nivaead_default(struct crypto_alg *alg, u32 type, u32 mask) +{ + struct rtattr *tb[3]; + struct { + struct rtattr attr; + struct crypto_attr_type data; + } ptype; + struct { + struct rtattr attr; + struct crypto_attr_alg data; + } palg; + struct crypto_template *tmpl; + struct crypto_instance *inst; + struct crypto_alg *larval; + const char *geniv; + int err; + + larval = crypto_larval_lookup(alg->cra_driver_name, + CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); + err = PTR_ERR(larval); + if (IS_ERR(larval)) + goto out; + + err = -EAGAIN; + if (!crypto_is_larval(larval)) + goto drop_larval; + + ptype.attr.rta_len = sizeof(ptype); + ptype.attr.rta_type = CRYPTOA_TYPE; + ptype.data.type = type | CRYPTO_ALG_GENIV; + /* GENIV tells the template that we're making a default geniv. */ + ptype.data.mask = mask | CRYPTO_ALG_GENIV; + tb[0] = &ptype.attr; + + palg.attr.rta_len = sizeof(palg); + palg.attr.rta_type = CRYPTOA_ALG; + /* Must use the exact name to locate ourselves. */ + memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME); + tb[1] = &palg.attr; + + tb[2] = NULL; + + geniv = alg->cra_aead.geniv; + + tmpl = crypto_lookup_template(geniv); + err = -ENOENT; + if (!tmpl) + goto kill_larval; + + inst = tmpl->alloc(tb); + err = PTR_ERR(inst); + if (IS_ERR(inst)) + goto put_tmpl; + + if ((err = crypto_register_instance(tmpl, inst))) { + tmpl->free(inst); + goto put_tmpl; + } + + /* Redo the lookup to use the instance we just registered. */ + err = -EAGAIN; + +put_tmpl: + crypto_tmpl_put(tmpl); +kill_larval: + crypto_larval_kill(larval); +drop_larval: + crypto_mod_put(larval); +out: + crypto_mod_put(alg); + return err; +} + +static struct crypto_alg *crypto_lookup_aead(const char *name, u32 type, + u32 mask) +{ + struct crypto_alg *alg; + + alg = crypto_alg_mod_lookup(name, type, mask); + if (IS_ERR(alg)) + return alg; + + if (alg->cra_type == &crypto_aead_type) + return alg; + + if (!alg->cra_aead.ivsize) + return alg; + + return ERR_PTR(crypto_nivaead_default(alg, type, mask)); +} + +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; +} +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); +} +EXPORT_SYMBOL_GPL(crypto_alloc_aead); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); diff --git a/include/crypto/internal/aead.h b/include/crypto/internal/aead.h index eb4eee7a7804..d838c945575a 100644 --- a/include/crypto/internal/aead.h +++ b/include/crypto/internal/aead.h @@ -31,6 +31,9 @@ static inline void crypto_set_aead_spawn( crypto_set_spawn(&spawn->base, inst); } +int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name, + u32 type, u32 mask); + static inline void crypto_drop_aead(struct crypto_aead_spawn *spawn) { crypto_drop_spawn(&spawn->base); diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 639385a9672d..0aba10460201 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -723,15 +723,7 @@ static inline struct crypto_aead *__crypto_aead_cast(struct crypto_tfm *tfm) return (struct crypto_aead *)tfm; } -static inline struct crypto_aead *crypto_alloc_aead(const char *alg_name, - u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_AEAD; - mask |= CRYPTO_ALG_TYPE_MASK; - - return __crypto_aead_cast(crypto_alloc_base(alg_name, type, mask)); -} +struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask); static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm) { -- cgit v1.2.3 From 6eb7228421c01ba48a6a88a7a5b3e71cfb70d4a9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 8 Jan 2008 17:16:44 +1100 Subject: [CRYPTO] api: Set default CRYPTO_MINALIGN to unsigned long long Thanks to David Miller for pointing out that the SLAB (or SLOB/SLUB) cache uses the alignment of unsigned long long if the architecture kmalloc/slab alignment macros are not defined. This patch changes the CRYPTO_MINALIGN so that it uses the same default value. Signed-off-by: Herbert Xu --- include/linux/crypto.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'include/linux/crypto.h') diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 0aba10460201..5e02d1b46370 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -90,13 +90,11 @@ #define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN #elif defined(ARCH_SLAB_MINALIGN) #define CRYPTO_MINALIGN ARCH_SLAB_MINALIGN +#else +#define CRYPTO_MINALIGN __alignof__(unsigned long long) #endif -#ifdef CRYPTO_MINALIGN #define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN))) -#else -#define CRYPTO_MINALIGN_ATTR -#endif struct scatterlist; struct crypto_ablkcipher; -- cgit v1.2.3