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 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'crypto/ablkcipher.c') 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"); -- 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 'crypto/ablkcipher.c') 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 'crypto/ablkcipher.c') 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 'crypto/ablkcipher.c') 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 'crypto/ablkcipher.c') 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 189ed66e95fb23666a62963b718dcbe62adbadde Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 14 Dec 2007 22:29:37 +0800 Subject: [CRYPTO] api: Show async type This patch adds an async field to /proc/crypto for ablkcipher and aead algorithms. Signed-off-by: Herbert Xu --- crypto/ablkcipher.c | 4 ++++ crypto/aead.c | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'crypto/ablkcipher.c') diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c index d1df528c8fa3..3bcb099b4a85 100644 --- a/crypto/ablkcipher.c +++ b/crypto/ablkcipher.c @@ -109,6 +109,8 @@ static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher; seq_printf(m, "type : ablkcipher\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, "min keysize : %u\n", ablkcipher->min_keysize); seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); @@ -158,6 +160,8 @@ 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, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? + "yes" : "no"); 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); diff --git a/crypto/aead.c b/crypto/aead.c index f5b1add31976..3a6f3f52c7c7 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -115,6 +115,8 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) struct aead_alg *aead = &alg->cra_aead; 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); @@ -169,6 +171,8 @@ 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, "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); -- cgit v1.2.3