aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2005-11-05 00:58:14 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-01-09 17:15:37 -0500
commit5cb1454b862ab3040b78364d58330262fea1ddba (patch)
tree7e62126fa1f1398bb6a6b7f9e136aece32b0e112
parent06ace7a9bafeb9047352707eb79e8eaa0dfdf5f2 (diff)
[CRYPTO] Allow multiple implementations of the same algorithm
This is the first step on the road towards asynchronous support in the Crypto API. It adds support for having multiple crypto_alg objects for the same algorithm registered in the system. For example, each device driver would register a crypto_alg object for each algorithm that it supports. While at the same time the user may load software implementations of those same algorithms. Users of the Crypto API may then select a specific implementation by name, or choose any implementation for a given algorithm with the highest priority. The priority field is a 32-bit signed integer. In future it will be possible to modify it from user-space. This also provides a solution to the problem of selecting amongst various AES implementations, that is, aes vs. aes-i586 vs. aes-padlock. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/api.c52
-rw-r--r--crypto/internal.h6
-rw-r--r--crypto/proc.c6
-rw-r--r--include/linux/crypto.h5
4 files changed, 60 insertions, 9 deletions
diff --git a/crypto/api.c b/crypto/api.c
index 40ae42e9b6a6..2715afdf678c 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
5 * Copyright (c) 2002 David S. Miller (davem@redhat.com) 5 * Copyright (c) 2002 David S. Miller (davem@redhat.com)
6 * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
6 * 7 *
7 * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no> 8 * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
8 * and Nettle, by Niels Möller. 9 * and Nettle, by Niels Möller.
@@ -18,9 +19,11 @@
18#include <linux/init.h> 19#include <linux/init.h>
19#include <linux/crypto.h> 20#include <linux/crypto.h>
20#include <linux/errno.h> 21#include <linux/errno.h>
22#include <linux/kernel.h>
21#include <linux/kmod.h> 23#include <linux/kmod.h>
22#include <linux/rwsem.h> 24#include <linux/rwsem.h>
23#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/string.h>
24#include "internal.h" 27#include "internal.h"
25 28
26LIST_HEAD(crypto_alg_list); 29LIST_HEAD(crypto_alg_list);
@@ -39,6 +42,7 @@ static inline void crypto_alg_put(struct crypto_alg *alg)
39static struct crypto_alg *crypto_alg_lookup(const char *name) 42static struct crypto_alg *crypto_alg_lookup(const char *name)
40{ 43{
41 struct crypto_alg *q, *alg = NULL; 44 struct crypto_alg *q, *alg = NULL;
45 int best = -1;
42 46
43 if (!name) 47 if (!name)
44 return NULL; 48 return NULL;
@@ -46,11 +50,23 @@ static struct crypto_alg *crypto_alg_lookup(const char *name)
46 down_read(&crypto_alg_sem); 50 down_read(&crypto_alg_sem);
47 51
48 list_for_each_entry(q, &crypto_alg_list, cra_list) { 52 list_for_each_entry(q, &crypto_alg_list, cra_list) {
49 if (!(strcmp(q->cra_name, name))) { 53 int exact, fuzzy;
50 if (crypto_alg_get(q)) 54
51 alg = q; 55 exact = !strcmp(q->cra_driver_name, name);
56 fuzzy = !strcmp(q->cra_name, name);
57 if (!exact && !(fuzzy && q->cra_priority > best))
58 continue;
59
60 if (unlikely(!crypto_alg_get(q)))
61 continue;
62
63 best = q->cra_priority;
64 if (alg)
65 crypto_alg_put(alg);
66 alg = q;
67
68 if (exact)
52 break; 69 break;
53 }
54 } 70 }
55 71
56 up_read(&crypto_alg_sem); 72 up_read(&crypto_alg_sem);
@@ -207,9 +223,26 @@ void crypto_free_tfm(struct crypto_tfm *tfm)
207 kfree(tfm); 223 kfree(tfm);
208} 224}
209 225
226static inline int crypto_set_driver_name(struct crypto_alg *alg)
227{
228 static const char suffix[] = "-generic";
229 char *driver_name = (char *)alg->cra_driver_name;
230 int len;
231
232 if (*driver_name)
233 return 0;
234
235 len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
236 if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
237 return -ENAMETOOLONG;
238
239 memcpy(driver_name + len, suffix, sizeof(suffix));
240 return 0;
241}
242
210int crypto_register_alg(struct crypto_alg *alg) 243int crypto_register_alg(struct crypto_alg *alg)
211{ 244{
212 int ret = 0; 245 int ret;
213 struct crypto_alg *q; 246 struct crypto_alg *q;
214 247
215 if (alg->cra_alignmask & (alg->cra_alignmask + 1)) 248 if (alg->cra_alignmask & (alg->cra_alignmask + 1))
@@ -220,11 +253,18 @@ int crypto_register_alg(struct crypto_alg *alg)
220 253
221 if (alg->cra_blocksize > PAGE_SIZE) 254 if (alg->cra_blocksize > PAGE_SIZE)
222 return -EINVAL; 255 return -EINVAL;
256
257 if (alg->cra_priority < 0)
258 return -EINVAL;
223 259
260 ret = crypto_set_driver_name(alg);
261 if (unlikely(ret))
262 return ret;
263
224 down_write(&crypto_alg_sem); 264 down_write(&crypto_alg_sem);
225 265
226 list_for_each_entry(q, &crypto_alg_list, cra_list) { 266 list_for_each_entry(q, &crypto_alg_list, cra_list) {
227 if (!(strcmp(q->cra_name, alg->cra_name))) { 267 if (!strcmp(q->cra_driver_name, alg->cra_driver_name)) {
228 ret = -EEXIST; 268 ret = -EEXIST;
229 goto out; 269 goto out;
230 } 270 }
diff --git a/crypto/internal.h b/crypto/internal.h
index 37aa652ce5ce..959e602909a6 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -2,6 +2,7 @@
2 * Cryptographic API. 2 * Cryptographic API.
3 * 3 *
4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
5 * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify it 7 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free 8 * under the terms of the GNU General Public License as published by the Free
@@ -16,10 +17,15 @@
16#include <linux/highmem.h> 17#include <linux/highmem.h>
17#include <linux/interrupt.h> 18#include <linux/interrupt.h>
18#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/list.h>
19#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include <linux/rwsem.h>
20#include <linux/slab.h> 23#include <linux/slab.h>
21#include <asm/kmap_types.h> 24#include <asm/kmap_types.h>
22 25
26extern struct list_head crypto_alg_list;
27extern struct rw_semaphore crypto_alg_sem;
28
23extern enum km_type crypto_km_types[]; 29extern enum km_type crypto_km_types[];
24 30
25static inline enum km_type crypto_kmap_type(int out) 31static inline enum km_type crypto_kmap_type(int out)
diff --git a/crypto/proc.c b/crypto/proc.c
index 630ba91c08f1..c0a5dd7ce2cc 100644
--- a/crypto/proc.c
+++ b/crypto/proc.c
@@ -4,6 +4,7 @@
4 * Procfs information. 4 * Procfs information.
5 * 5 *
6 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 6 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
7 * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify it 9 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free 10 * under the terms of the GNU General Public License as published by the Free
@@ -18,9 +19,6 @@
18#include <linux/seq_file.h> 19#include <linux/seq_file.h>
19#include "internal.h" 20#include "internal.h"
20 21
21extern struct list_head crypto_alg_list;
22extern struct rw_semaphore crypto_alg_sem;
23
24static void *c_start(struct seq_file *m, loff_t *pos) 22static void *c_start(struct seq_file *m, loff_t *pos)
25{ 23{
26 struct list_head *v; 24 struct list_head *v;
@@ -53,7 +51,9 @@ static int c_show(struct seq_file *m, void *p)
53 struct crypto_alg *alg = (struct crypto_alg *)p; 51 struct crypto_alg *alg = (struct crypto_alg *)p;
54 52
55 seq_printf(m, "name : %s\n", alg->cra_name); 53 seq_printf(m, "name : %s\n", alg->cra_name);
54 seq_printf(m, "driver : %s\n", alg->cra_driver_name);
56 seq_printf(m, "module : %s\n", module_name(alg->cra_module)); 55 seq_printf(m, "module : %s\n", module_name(alg->cra_module));
56 seq_printf(m, "priority : %d\n", alg->cra_priority);
57 57
58 switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { 58 switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
59 case CRYPTO_ALG_TYPE_CIPHER: 59 case CRYPTO_ALG_TYPE_CIPHER:
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 3c89df6e7768..d88bf8aa8b47 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> 4 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
5 * Copyright (c) 2002 David S. Miller (davem@redhat.com) 5 * Copyright (c) 2002 David S. Miller (davem@redhat.com)
6 * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
6 * 7 *
7 * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no> 8 * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
8 * and Nettle, by Niels Möller. 9 * and Nettle, by Niels Möller.
@@ -126,7 +127,11 @@ struct crypto_alg {
126 unsigned int cra_blocksize; 127 unsigned int cra_blocksize;
127 unsigned int cra_ctxsize; 128 unsigned int cra_ctxsize;
128 unsigned int cra_alignmask; 129 unsigned int cra_alignmask;
130
131 int cra_priority;
132
129 const char cra_name[CRYPTO_MAX_ALG_NAME]; 133 const char cra_name[CRYPTO_MAX_ALG_NAME];
134 const char cra_driver_name[CRYPTO_MAX_ALG_NAME];
130 135
131 union { 136 union {
132 struct cipher_alg cipher; 137 struct cipher_alg cipher;