Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 534

kernel-2.6.18-238.el5.src.rpm

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Sun, 6 Jan 2008 16:09:26 +1100
Subject: [crypto] digest: added user api for new hash type
Message-id: E1JBNlG-0001BB-00@gondolin.me.apana.org.au
O-Subject: [PATCH 12/32] [CRYPTO] digest: Added user API for new hash type
Bugzilla: 253051

[CRYPTO] digest: Added user API for new hash type

The existing digest user interface is inadequate for support asynchronous
operations.  For one it doesn't return a value to indicate success or
failure, nor does it take a per-operation descriptor which is essential
for the issuing of requests while other requests are still outstanding.

This patch is the first in a series of steps to remodel the interface
for asynchronous operations.

For the ease of transition the new interface will be known as "hash"
while the old one will remain as "digest".

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Acked-by: "David S. Miller" <davem@redhat.com>

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 7bfc4be..dcf163d 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -42,6 +42,11 @@ config CRYPTO_SEQIV
 	  xoring it with a salt.  This algorithm is mainly useful for CTR
 	  and similar modes.
 
+config CRYPTO_HASH
+	tristate
+	depends on CRYPTO
+	select CRYPTO_ALGAPI
+
 config CRYPTO_MANAGER
 	tristate "Cryptographic algorithm manager"
 	depends on CRYPTO
diff --git a/crypto/Makefile b/crypto/Makefile
index ba067a2..552ee39 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -19,6 +19,9 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER) += chainiv.o
 obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o
 obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
 
+crypto_hash-objs := hash.o
+obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
+
 obj-$(CONFIG_CRYPTO_API) += crypto_api.o
 obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
diff --git a/crypto/hash.c b/crypto/hash.c
new file mode 100644
index 0000000..57fac45
--- /dev/null
+++ b/crypto/hash.c
@@ -0,0 +1,99 @@
+/*
+ * Cryptographic Hash operations.
+ * 
+ * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+
+#include "ninternal.h"
+
+static unsigned int crypto_hash_ctxsize(struct ncrypto_alg *alg, u32 type,
+					u32 mask)
+{
+	return alg->cra_ctxsize;
+}
+
+static int hash_setkey_unaligned(struct crypto_hash *crt, const u8 *key,
+		                 unsigned int keylen)
+{
+	struct ncrypto_tfm *tfm = crypto_hash_tfm(crt);
+	struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+	unsigned long alignmask = crypto_hash_alignmask(crt);
+	int ret;
+	u8 *buffer, *alignbuffer;
+	unsigned long absize;
+
+	absize = keylen + alignmask;
+	buffer = kmalloc(absize, GFP_ATOMIC);
+	if (!buffer)
+		return -ENOMEM;
+
+	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+	memcpy(alignbuffer, key, keylen);
+	ret = alg->setkey(crt, alignbuffer, keylen);
+	memset(alignbuffer, 0, keylen);
+	kfree(buffer);
+	return ret;
+}
+
+static int hash_setkey(struct crypto_hash *crt, const u8 *key,
+		       unsigned int keylen)
+{
+	struct ncrypto_tfm *tfm = crypto_hash_tfm(crt);
+	struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+	unsigned long alignmask = crypto_hash_alignmask(crt);
+
+	if ((unsigned long)key & alignmask)
+		return hash_setkey_unaligned(crt, key, keylen);
+
+	return alg->setkey(crt, key, keylen);
+}
+
+static int crypto_init_hash_ops(struct ncrypto_tfm *tfm, u32 type, u32 mask)
+{
+	struct hash_tfm *crt = &tfm->crt_hash;
+	struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+
+	if (alg->digestsize > ncrypto_tfm_alg_blocksize(tfm))
+		return -EINVAL;
+
+	crt->init = alg->init;
+	crt->update = alg->update;
+	crt->final = alg->final;
+	crt->digest = alg->digest;
+	crt->setkey = hash_setkey;
+	crt->digestsize = alg->digestsize;
+
+	return 0;
+}
+
+static void crypto_hash_show(struct seq_file *m, struct ncrypto_alg *alg)
+	__attribute__ ((unused));
+static void crypto_hash_show(struct seq_file *m, struct ncrypto_alg *alg)
+{
+	seq_printf(m, "type         : hash\n");
+	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+	seq_printf(m, "digestsize   : %u\n", alg->cra_hash.digestsize);
+}
+
+const struct crypto_type crypto_hash_type = {
+	.ctxsize = crypto_hash_ctxsize,
+	.init = crypto_init_hash_ops,
+#ifdef CONFIG_PROC_FS
+	.show = crypto_hash_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_hash_type);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic cryptographic hash type");
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index d5181b1..9cf929b 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -97,6 +97,7 @@ struct blkcipher_walk {
 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;
 
 void crypto_mod_put(struct ncrypto_alg *alg);
 
@@ -229,6 +230,24 @@ static inline struct cipher_alg *crypto_cipher_alg(struct crypto_cipher *tfm)
 	return &crypto_cipher_tfm(tfm)->__crt_alg->cra_cipher;
 }
 
+static inline struct crypto_tfm *crypto_spawn_digest(const char *name)
+{
+	return ocrypto_spawn_tfm(name, CRYPTO_ALG_TYPE_DIGEST);
+}
+
+static inline struct crypto_hash *crypto_spawn_hash(struct crypto_spawn *spawn)
+{
+	u32 type = NCRYPTO_ALG_TYPE_HASH;
+	u32 mask = NCRYPTO_ALG_TYPE_HASH_MASK;
+
+	return __crypto_hash_cast(crypto_spawn_tfm(spawn, type, mask));
+}
+
+static inline void *crypto_hash_ctx_aligned(struct crypto_hash *tfm)
+{
+	return crypto_tfm_ctx_aligned(&tfm->base);
+}
+
 static inline void blkcipher_walk_init(struct blkcipher_walk *walk,
 				       struct scatterlist *dst,
 				       struct scatterlist *src,
diff --git a/include/linux/ncrypto.h b/include/linux/ncrypto.h
index cd07bf7..63169ff 100644
--- a/include/linux/ncrypto.h
+++ b/include/linux/ncrypto.h
@@ -27,12 +27,14 @@
 #define NCRYPTO_ALG_TYPE_MASK		0x0000000f
 #define NCRYPTO_ALG_TYPE_CIPHER		0x00000001
 #define NCRYPTO_ALG_TYPE_DIGEST		0x00000002
+#define NCRYPTO_ALG_TYPE_HASH		0x00000003
 #define NCRYPTO_ALG_TYPE_BLKCIPHER	0x00000004
 #define NCRYPTO_ALG_TYPE_ABLKCIPHER	0x00000005
 #define NCRYPTO_ALG_TYPE_GIVCIPHER	0x00000006
 #define NCRYPTO_ALG_TYPE_COMPRESS	0x00000008
 #define NCRYPTO_ALG_TYPE_AEAD		0x00000009
 
+#define NCRYPTO_ALG_TYPE_HASH_MASK	0x0000000e
 #define NCRYPTO_ALG_TYPE_BLKCIPHER_MASK	0x0000000c
 
 #define NCRYPTO_ALG_LARVAL		0x00000010
@@ -85,6 +87,7 @@ struct crypto_ablkcipher;
 struct crypto_async_request;
 struct crypto_aead;
 struct crypto_blkcipher;
+struct crypto_hash;
 struct ncrypto_tfm;
 struct crypto_type;
 struct module;
@@ -147,6 +150,11 @@ struct blkcipher_desc {
 	u32 flags;
 };
 
+struct hash_desc {
+	struct crypto_hash *tfm;
+	u32 flags;
+};
+
 struct ablkcipher_alg {
 	int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key,
 	              unsigned int keylen);
@@ -194,9 +202,23 @@ struct blkcipher_alg {
 	unsigned int ivsize;
 };
 
+struct hash_alg {
+	int (*init)(struct hash_desc *desc);
+	int (*update)(struct hash_desc *desc, struct scatterlist *sg,
+		      unsigned int nbytes);
+	int (*final)(struct hash_desc *desc, u8 *out);
+	int (*digest)(struct hash_desc *desc, struct scatterlist *sg,
+		      unsigned int nbytes, u8 *out);
+	int (*setkey)(struct crypto_hash *tfm, const u8 *key,
+		      unsigned int keylen);
+
+	unsigned int digestsize;
+};
+
 #define cra_ablkcipher	cra_u.ablkcipher
 #define cra_aead	cra_u.aead
 #define cra_blkcipher	cra_u.blkcipher
+#define cra_hash	cra_u.hash
 
 struct ncrypto_alg {
 	struct list_head cra_list;
@@ -219,6 +241,7 @@ struct ncrypto_alg {
 		struct ablkcipher_alg ablkcipher;
 		struct aead_alg aead;
 		struct blkcipher_alg blkcipher;
+		struct hash_alg hash;
 	} cra_u;
 
 	int (*cra_init)(struct ncrypto_tfm *tfm);
@@ -285,9 +308,22 @@ struct blkcipher_tfm {
 		       struct scatterlist *src, unsigned int nbytes);
 };
 
+struct hash_tfm {
+	int (*init)(struct hash_desc *desc);
+	int (*update)(struct hash_desc *desc,
+		      struct scatterlist *sg, unsigned int nsg);
+	int (*final)(struct hash_desc *desc, u8 *out);
+	int (*digest)(struct hash_desc *desc, struct scatterlist *sg,
+		      unsigned int nsg, u8 *out);
+	int (*setkey)(struct crypto_hash *tfm, const u8 *key,
+		      unsigned int keylen);
+	unsigned int digestsize;
+};
+
 #define crt_ablkcipher	crt_u.ablkcipher
 #define crt_aead	crt_u.aead
 #define crt_blkcipher	crt_u.blkcipher
+#define crt_hash	crt_u.hash
 
 struct ncrypto_tfm {
 
@@ -297,6 +333,7 @@ struct ncrypto_tfm {
 		struct ablkcipher_tfm ablkcipher;
 		struct aead_tfm aead;
 		struct blkcipher_tfm blkcipher;
+		struct hash_tfm hash;
 	} crt_u;
 	
 	struct ncrypto_alg *__crt_alg;
@@ -318,6 +355,10 @@ struct crypto_blkcipher {
 
 #define crypto_cipher crypto_tfm
 
+struct crypto_hash {
+	struct ncrypto_tfm base;
+};
+
 enum {
 	CRYPTOA_UNSPEC,
 	CRYPTOA_ALG,
@@ -948,4 +989,112 @@ void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
 void crypto_cipher_decrypt_one(struct crypto_cipher *tfm,
 			       u8 *dst, const u8 *src);
 
+static inline struct crypto_hash *__crypto_hash_cast(struct ncrypto_tfm *tfm)
+{
+	return (struct crypto_hash *)tfm;
+}
+
+static inline struct crypto_hash *crypto_hash_cast(struct ncrypto_tfm *tfm)
+{
+	BUG_ON((ncrypto_tfm_alg_type(tfm) ^ NCRYPTO_ALG_TYPE_HASH) &
+	       NCRYPTO_ALG_TYPE_HASH_MASK);
+	return __crypto_hash_cast(tfm);
+}
+
+static inline struct crypto_hash *crypto_alloc_hash(const char *alg_name,
+						    u32 type, u32 mask)
+{
+	type &= ~NCRYPTO_ALG_TYPE_MASK;
+	mask &= ~NCRYPTO_ALG_TYPE_MASK;
+	type |= NCRYPTO_ALG_TYPE_HASH;
+	mask |= NCRYPTO_ALG_TYPE_HASH_MASK;
+
+	return __crypto_hash_cast(crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct ncrypto_tfm *crypto_hash_tfm(struct crypto_hash *tfm)
+{
+	return &tfm->base;
+}
+
+static inline void crypto_free_hash(struct crypto_hash *tfm)
+{
+	ncrypto_free_tfm(crypto_hash_tfm(tfm));
+}
+
+static inline int crypto_has_hash(const char *alg_name, u32 type, u32 mask)
+{
+	type &= ~NCRYPTO_ALG_TYPE_MASK;
+	mask &= ~NCRYPTO_ALG_TYPE_MASK;
+	type |= NCRYPTO_ALG_TYPE_HASH;
+	mask |= NCRYPTO_ALG_TYPE_HASH_MASK;
+
+	return crypto_has_alg(alg_name, type, mask);
+}
+
+static inline struct hash_tfm *crypto_hash_crt(struct crypto_hash *tfm)
+{
+	return &crypto_hash_tfm(tfm)->crt_hash;
+}
+
+static inline unsigned int crypto_hash_blocksize(struct crypto_hash *tfm)
+{
+	return ncrypto_tfm_alg_blocksize(crypto_hash_tfm(tfm));
+}
+
+static inline unsigned int crypto_hash_alignmask(struct crypto_hash *tfm)
+{
+	return ncrypto_tfm_alg_alignmask(crypto_hash_tfm(tfm));
+}
+
+static inline unsigned int crypto_hash_digestsize(struct crypto_hash *tfm)
+{
+	return crypto_hash_crt(tfm)->digestsize;
+}
+
+static inline u32 crypto_hash_get_flags(struct crypto_hash *tfm)
+{
+	return ncrypto_tfm_get_flags(crypto_hash_tfm(tfm));
+}
+
+static inline void crypto_hash_set_flags(struct crypto_hash *tfm, u32 flags)
+{
+	ncrypto_tfm_set_flags(crypto_hash_tfm(tfm), flags);
+}
+
+static inline void crypto_hash_clear_flags(struct crypto_hash *tfm, u32 flags)
+{
+	ncrypto_tfm_clear_flags(crypto_hash_tfm(tfm), flags);
+}
+
+static inline int crypto_hash_init(struct hash_desc *desc)
+{
+	return crypto_hash_crt(desc->tfm)->init(desc);
+}
+
+static inline int crypto_hash_update(struct hash_desc *desc,
+				     struct scatterlist *sg,
+				     unsigned int nbytes)
+{
+	return crypto_hash_crt(desc->tfm)->update(desc, sg, nbytes);
+}
+
+static inline int crypto_hash_final(struct hash_desc *desc, u8 *out)
+{
+	return crypto_hash_crt(desc->tfm)->final(desc, out);
+}
+
+static inline int crypto_hash_digest(struct hash_desc *desc,
+				     struct scatterlist *sg,
+				     unsigned int nbytes, u8 *out)
+{
+	return crypto_hash_crt(desc->tfm)->digest(desc, sg, nbytes, out);
+}
+
+static inline int crypto_hash_setkey(struct crypto_hash *hash,
+				     const u8 *key, unsigned int keylen)
+{
+	return crypto_hash_crt(hash)->setkey(hash, key, keylen);
+}
+
 #endif	/* _LINUX_NCRYPTO_H */