From: Shasi Pulijala <spulijala@xxxxxxxx> Hi Herbert, This patch adds PKA support to Linux CryptoAPI. All the basic algorithms like add, sub, div, expmod and expmod-crt can be supported by this interface. Currently the max number of src and dst operands have been defined as 6 and 2 respectively. These values should fit all the above mentioned algorithms (for example add needs 2 for input and 1 for output, expmod-crt 6 for input and 1 for output). Although, there is no specific mapping of operands, it is assumed that for add, operand A would be the first entry, operand B would be the second entry of the source. The output would be the first output. Signed-off-by: Shasi Pulijala <spulijala@xxxxxxxx> Acked-by: Loc Ho <lho@xxxxxxxx> --- crypto/Kconfig | 4 + crypto/Makefile | 1 + crypto/pka.c | 107 +++++++++++++++++++++++++++++++++ include/crypto/algapi.h | 17 +++++ include/linux/crypto.h | 153 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 279 insertions(+), 3 deletions(-) create mode 100644 crypto/pka.c diff --git a/crypto/Kconfig b/crypto/Kconfig index eb66c4e..4e112e9 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -38,6 +38,10 @@ config CRYPTO_HASH tristate select CRYPTO_ALGAPI +config CRYPTO_PKA + tristate + select CRYPTO_ALGAPI + config CRYPTO_MANAGER tristate "Cryptographic algorithm manager" select CRYPTO_ALGAPI diff --git a/crypto/Makefile b/crypto/Makefile index 6819da9..949f08e 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -19,9 +19,9 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o crypto_hash-objs := hash.o +obj-$(CONFIG_CRYPTO_PKA) += pka.o obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o obj-$(CONFIG_CRYPTO_HMAC) += hmac.o diff --git a/crypto/pka.c b/crypto/pka.c new file mode 100644 index 0000000..532e8d5 --- /dev/null +++ b/crypto/pka.c @@ -0,0 +1,107 @@ +/* + * @ pka.c + * Linux CryptoAPI Module for PKA + * + * Copyright (c) 2008 Shasi Pulijala <spulijala@xxxxxxxx> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <crypto/algapi.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/seq_file.h> + +#include "internal.h" + +static unsigned int crypto_pka_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) +{ + return alg->cra_ctxsize; +} + +static int crypto_init_pka_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +{ + struct pka_alg *alg = &tfm->__crt_alg->cra_pka; + struct pka_tfm *crt = &tfm->crt_pka; + + crt->base = __crypto_pka_cast(tfm); + crt->pka_op = alg->pka_op; + return 0; +} + +static void crypto_pka_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_pka_show(struct seq_file *m, struct crypto_alg *alg) +{ + seq_printf(m, "type : pka\n"); + seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? + "yes" : "no"); +} + +const struct crypto_type crypto_pka_type = { + .ctxsize = crypto_pka_ctxsize, + .init = crypto_init_pka_ops, +#ifdef CONFIG_PROC_FS + .show = crypto_pka_show, +#endif +}; +EXPORT_SYMBOL_GPL(crypto_pka_type); + +struct crypto_pka *crypto_alloc_pka(const char *alg_name, + u32 type, u32 mask) +{ + struct crypto_tfm *tfm; + int err; + + mask &= ~CRYPTO_ALG_TYPE_MASK; + + for (;;) { + struct crypto_alg *alg; + + type &= ~CRYPTO_ALG_TYPE_MASK; + type |= CRYPTO_ALG_TYPE_ASYNC_PKA; + alg = crypto_alg_mod_lookup(alg_name, type, mask); + if (IS_ERR(alg)) { + type &= ~CRYPTO_ALG_TYPE_MASK; + type |= CRYPTO_ALG_TYPE_ASYNC_PKA; + alg = crypto_alg_mod_lookup(alg_name, type, mask); + if (IS_ERR(alg)) { + err = PTR_ERR(alg); + goto err; + } + } + + tfm = __crypto_alloc_tfm(alg, type, mask | CRYPTO_ALG_ASYNC); + if (!IS_ERR(tfm)) + return __crypto_pka_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_pka); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cryptographic PKA type"); diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 60d06e7..2498a9c 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -98,6 +98,7 @@ extern const struct crypto_type crypto_ablkcipher_type; extern const struct crypto_type crypto_aead_type; extern const struct crypto_type crypto_blkcipher_type; extern const struct crypto_type crypto_hash_type; +extern const struct crypto_type crypto_pka_type; void crypto_mod_put(struct crypto_alg *alg); @@ -314,5 +315,21 @@ static inline int crypto_requires_sync(u32 type, u32 mask) return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC; } +static inline void *crypto_pka_ctx(struct crypto_pka *tfm) +{ + return crypto_tfm_ctx(&tfm->base); +} + +static inline struct pka_alg *crypto_pka_alg( + struct crypto_pka *tfm) +{ + return &crypto_pka_tfm(tfm)->__crt_alg->cra_pka; +} + +static inline void *pka_request_ctx(struct pka_request *req) +{ + return req->__ctx; +} + #endif /* _CRYPTO_ALGAPI_H */ diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 425824b..ae697f6 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -37,6 +37,7 @@ #define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006 #define CRYPTO_ALG_TYPE_COMPRESS 0x00000008 #define CRYPTO_ALG_TYPE_AEAD 0x00000009 +#define CRYPTO_ALG_TYPE_ASYNC_PKA 0x0000000B #define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e #define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c @@ -102,6 +103,7 @@ struct crypto_async_request; struct crypto_aead; struct crypto_blkcipher; struct crypto_hash; +struct crypto_pka; struct crypto_tfm; struct crypto_type; struct aead_givcrypt_request; @@ -132,6 +134,33 @@ struct ablkcipher_request { }; /** + * struct pka_request - PKA request + * @base: Common attributes for async pka requests + * @src: list of source operands + * @dst: result operands + * @shift_value: shift value for shift operation + * @__ctx: Start of private context data + */ +#define PKA_SRC_OPERANDS 6 +#define PKA_DST_OPERANDS 2 + +struct pka_request { + struct crypto_async_request base; + + struct scatterlist *src[6]; + struct scatterlist *dst[2]; + u32 operand_src_size[6]; + u32 operand_dst_size[2]; + + int iops; + int oops; + + u8 shift_value; + + void *__ctx[] CRYPTO_MINALIGN_ATTR; +}; + +/** * struct aead_request - AEAD request * @base: Common attributes for async crypto requests * @assoclen: Length in bytes of associated data for authentication @@ -266,6 +295,10 @@ struct compress_alg { unsigned int slen, u8 *dst, unsigned int *dlen); }; +struct pka_alg { + int (*pka_op)(struct pka_request *req); +}; + #define cra_ablkcipher cra_u.ablkcipher #define cra_aead cra_u.aead #define cra_blkcipher cra_u.blkcipher @@ -273,6 +306,7 @@ struct compress_alg { #define cra_digest cra_u.digest #define cra_hash cra_u.hash #define cra_compress cra_u.compress +#define cra_pka cra_u.pka struct crypto_alg { struct list_head cra_list; @@ -299,12 +333,13 @@ struct crypto_alg { struct digest_alg digest; struct hash_alg hash; struct compress_alg compress; + struct pka_alg pka; } cra_u; int (*cra_init)(struct crypto_tfm *tfm); void (*cra_exit)(struct crypto_tfm *tfm); void (*cra_destroy)(struct crypto_alg *alg); - + struct module *cra_module; }; @@ -392,17 +427,23 @@ struct compress_tfm { u8 *dst, unsigned int *dlen); }; +struct pka_tfm { + struct crypto_pka *base; + int (*pka_op)(struct pka_request *req); +}; + #define crt_ablkcipher crt_u.ablkcipher #define crt_aead crt_u.aead #define crt_blkcipher crt_u.blkcipher #define crt_cipher crt_u.cipher #define crt_hash crt_u.hash #define crt_compress crt_u.compress +#define crt_pka crt_u.pka struct crypto_tfm { u32 crt_flags; - + union { struct ablkcipher_tfm ablkcipher; struct aead_tfm aead; @@ -410,8 +451,9 @@ struct crypto_tfm { struct cipher_tfm cipher; struct hash_tfm hash; struct compress_tfm compress; + struct pka_tfm pka; } crt_u; - + struct crypto_alg *__crt_alg; void *__crt_ctx[] CRYPTO_MINALIGN_ATTR; @@ -441,6 +483,10 @@ struct crypto_hash { struct crypto_tfm base; }; +struct crypto_pka { + struct crypto_tfm base; +}; + enum { CRYPTOA_UNSPEC, CRYPTOA_ALG, @@ -1264,5 +1310,106 @@ static inline int crypto_comp_decompress(struct crypto_comp *tfm, src, slen, dst, dlen); } +static inline struct crypto_digest *__crypto_digest_cast( + struct crypto_tfm *tfm) +{ + return (struct crypto_digest *) tfm; +} + +static inline struct crypto_pka *__crypto_pka_cast(struct crypto_tfm *tfm) +{ + return (struct crypto_pka *) tfm; +} + +static inline struct crypto_tfm *crypto_pka_tfm( + struct crypto_pka *tfm) +{ + return &tfm->base; +} + +static inline struct pka_tfm *crypto_pka_crt(struct crypto_pka *tfm) +{ + return &crypto_pka_tfm(tfm)->crt_pka; +} + +static inline struct crypto_pka *crypto_pka_reqtfm( + struct pka_request *req) +{ + return __crypto_pka_cast(req->base.tfm); +} + +static inline int crypto_pka_op(struct pka_request *req) +{ + struct pka_tfm *crt = crypto_pka_crt(crypto_pka_reqtfm(req)); + return crt->pka_op(req); +} + +static inline void pka_request_set_tfm( + struct pka_request *req, struct crypto_pka *tfm) +{ + req->base.tfm = crypto_pka_tfm(crypto_pka_crt(tfm)->base); +} + +static inline struct pka_request *pka_request_alloc( + struct crypto_pka *tfm, gfp_t gfp) +{ + struct pka_request *req; + + req = kmalloc(sizeof(struct pka_request), gfp); + + if (likely(req)) + pka_request_set_tfm(req, tfm); + + return req; +} + +static inline void pka_request_free(struct pka_request *req) +{ + kfree(req); +} + +static inline void crypto_free_pka(struct crypto_pka *tfm) +{ + crypto_free_tfm(crypto_pka_tfm(tfm)); +} + +static inline void pka_request_set_operands( + struct pka_request *req, + struct scatterlist **sg_src, + struct scatterlist **sg_dst, + u32 *ssize, + u32 *dsize, + int iops, int oops, u8 shift) +{ + int i; + req->iops = iops; + req->oops = oops; + req->shift_value = shift; + + for (i = 0; i < iops; i++) { + req->src[i] = sg_src[i]; + req->operand_src_size[i] = ssize[i]; + } + + for (i = 0; i < oops; i++) { + req->dst[i] = sg_dst[i]; + req->operand_dst_size[i] = dsize[i]; + } + +} + +static inline void pka_request_set_callback( + struct pka_request *req, + u32 flags, crypto_completion_t complete, void *data) +{ + req->base.complete = complete; + req->base.data = data; + req->base.flags = flags; +} + + +struct crypto_pka *crypto_alloc_pka(const char *alg_name, + u32 type, u32 mask); + #endif /* _LINUX_CRYPTO_H */ -- 1.5.5 -- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html