summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2010-07-27 13:47:06 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2010-07-27 13:47:06 +0200
commitc0c14cb837e6ea4a1c4ec0f8888f500c78ccdbf6 (patch)
tree82f4a723fe8c0f1e4c02e044012d4fcb1a945dee
parent81633c5ffee3806a7195258122fe8e7e337c8c54 (diff)
downloadcryptodev-linux-c0c14cb837e6ea4a1c4ec0f8888f500c78ccdbf6.tar.gz
cryptodev-linux-c0c14cb837e6ea4a1c4ec0f8888f500c78ccdbf6.tar.xz
cryptodev-linux-c0c14cb837e6ea4a1c4ec0f8888f500c78ccdbf6.zip
Added Diffie Hellman key generation.
-rw-r--r--Makefile2
-rw-r--r--examples/pk.c79
-rw-r--r--ncr-dh.c145
-rw-r--r--ncr-dh.h21
-rw-r--r--ncr-int.h3
-rw-r--r--ncr-key.c11
-rw-r--r--ncr-pk.c96
-rw-r--r--ncr-pk.h2
-rw-r--r--ncr-sessions.c2
-rw-r--r--ncr.h17
10 files changed, 354 insertions, 24 deletions
diff --git a/Makefile b/Makefile
index 41c82c4..0e33540 100644
--- a/Makefile
+++ b/Makefile
@@ -67,7 +67,7 @@ TOMCRYPT_OBJECTS = libtomcrypt/misc/zeromem.o libtomcrypt/misc/crypt/crypt_argch
libtomcrypt/pk/asn1/der/x509/der_decode_subject_public_key_info.o
cryptodev-objs = cryptodev_main.o cryptodev_cipher.o ncr.o \
- ncr-key.o ncr-limits.o ncr-pk.o ncr-sessions.o \
+ ncr-key.o ncr-limits.o ncr-pk.o ncr-sessions.o ncr-dh.o \
ncr-key-wrap.o ncr-key-storage.o $(TOMMATH_OBJECTS) \
$(TOMCRYPT_OBJECTS)
diff --git a/examples/pk.c b/examples/pk.c
index 1aa4c5a..1385a0e 100644
--- a/examples/pk.c
+++ b/examples/pk.c
@@ -297,6 +297,82 @@ int pubkey_info(void* data, int data_size, int verbose)
return 0;
}
+/* Diffie Hellman */
+const char dh_params_txt[] = "-----BEGIN DH PARAMETERS-----\n"\
+"MIGHAoGBAKMox0/IjuGqSaGMJESYMhdmXiTe1pY8gkSzWZ/ktWaUdaYAzgAZp7r3\n"\
+"OCh68YslS9Oi7/UQjmBbgGuOucMKgq3tYeYzY8G2epIuIzM4TAogaEqwkdSrXlth\n"\
+"MMsP2FhLhHg8m6V6iItitnMOz9r8t3BEf04GRlfzgZraM0gUUwTjAgEF\n"\
+"-----END DH PARAMETERS-----\n";
+
+static int test_ncr_dh(int cfd)
+{
+struct ncr_key_generate_st kgen;
+ncr_key_t private1, public1;
+int ret;
+gnutls_datum g, p, params;
+gnutls_dh_params_t dhp;
+
+ fprintf(stdout, "Tests on DH key exchange:");
+ fflush(stdout);
+
+ params.data = (void*)dh_params_txt;
+ params.size = sizeof(dh_params_txt)-1;
+
+ ret = gnutls_dh_params_init(&dhp);
+ if (ret < 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ fprintf(stderr, "gnutls: %s\n", gnutls_strerror(ret));
+ return 1;
+ }
+
+ ret = gnutls_dh_params_import_pkcs3(dhp, &params, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ fprintf(stderr, "gnutls: %s\n", gnutls_strerror(ret));
+ return 1;
+ }
+
+ ret = gnutls_dh_params_export_raw(dhp, &p, &g, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ fprintf(stderr, "gnutls: %s\n", gnutls_strerror(ret));
+ return 1;
+ }
+
+ /* generate a DH key */
+ if (ioctl(cfd, NCRIO_KEY_INIT, &private1)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_INIT)");
+ return 1;
+ }
+
+ if (ioctl(cfd, NCRIO_KEY_INIT, &public1)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_INIT)");
+ return 1;
+ }
+
+ memset(&kgen, 0, sizeof(kgen));
+ kgen.desc = private1;
+ kgen.desc2 = public1;
+ kgen.params.algorithm = NCR_ALG_DH;
+ kgen.params.keyflags = NCR_KEY_FLAG_EXPORTABLE;
+ kgen.params.params.dh.p = p.data;
+ kgen.params.params.dh.p_size = p.size;
+ kgen.params.params.dh.g = g.data;
+ kgen.params.params.dh.g_size = g.size;
+
+ if (ioctl(cfd, NCRIO_KEY_GENERATE_PAIR, &kgen)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_GENERATE)");
+ return 1;
+ }
+
+ fprintf(stdout, " Success\n");
+
+ return 0;
+}
+
#define RSA_ENCRYPT_SIZE 32
static int rsa_key_encrypt(int cfd, ncr_key_t privkey, ncr_key_t pubkey, int oaep)
@@ -726,6 +802,9 @@ main()
return 1;
}
+ if (test_ncr_dh(fd))
+ return 1;
+
if (test_ncr_rsa(fd))
return 1;
diff --git a/ncr-dh.c b/ncr-dh.c
new file mode 100644
index 0000000..4741c2b
--- /dev/null
+++ b/ncr-dh.c
@@ -0,0 +1,145 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Katholieke Universiteit Leuven
+ *
+ * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/mm.h>
+#include <linux/random.h>
+#include "cryptodev.h"
+#include <asm/uaccess.h>
+#include <asm/ioctl.h>
+#include <linux/scatterlist.h>
+#include <ncr.h>
+#include <ncr-int.h>
+#include <tomcrypt.h>
+#include <ncr-dh.h>
+
+void dh_free(dh_key * key)
+{
+ mp_clear_multi(&key->p, &key->g, &key->x, NULL);
+}
+
+int dh_import_params(dh_key * key, uint8_t* p, size_t p_size, uint8_t* g, size_t g_size)
+{
+int ret;
+int err;
+
+ if ((err = mp_init_multi(&key->p, &key->g, &key->x, &key->y, NULL)) != CRYPT_OK) {
+ err();
+ return -ENOMEM;
+ }
+
+ if ((err = mp_read_unsigned_bin(&key->p, (unsigned char *)p, p_size)) != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ if ((err = mp_read_unsigned_bin(&key->g, (unsigned char *)g, g_size)) != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ return 0;
+fail:
+ mp_clear_multi(&key->p, &key->g, &key->x, &key->y, NULL);
+
+ return ret;
+}
+
+int dh_generate_key(dh_key * key)
+{
+void* buf;
+int size;
+int err, ret;
+
+ size = mp_unsigned_bin_size(&key->p);
+ if (size == 0) {
+ err();
+ return -EINVAL;
+ }
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == NULL) {
+ err();
+ return -ENOMEM;
+ }
+
+ get_random_bytes( buf, size);
+
+ if ((err = mp_read_unsigned_bin(&key->x, buf, size)) != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ err = mp_mod( &key->g, &key->p, &key->x);
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ key->type = PK_PRIVATE;
+
+ ret = 0;
+fail:
+ kfree(buf);
+
+ return ret;
+
+}
+
+int dh_generate_public(dh_key * public, dh_key* private)
+{
+int err, ret;
+
+ err = mp_copy(&private->g, &public->g);
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ err = mp_copy(&private->p, &public->p);
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ err = mp_exptmod(&private->g, &private->x, &private->p, &public->y);
+ if (err != CRYPT_OK) {
+ err();
+ ret = _ncr_tomerr(err);
+ goto fail;
+ }
+
+ public->type = PK_PUBLIC;
+
+ ret = 0;
+fail:
+
+ return ret;
+
+}
diff --git a/ncr-dh.h b/ncr-dh.h
new file mode 100644
index 0000000..ba7a92b
--- /dev/null
+++ b/ncr-dh.h
@@ -0,0 +1,21 @@
+#ifndef NCR_DH_H
+# define NCR_DH_H
+
+#include <tomcrypt.h>
+
+typedef struct {
+ int type; /* PK_PRIVATE or PK_PUBLIC */
+ mp_int p;
+ mp_int g;
+ mp_int x; /* private */
+ mp_int y; /* public: y=g^x */
+} dh_key;
+
+int dh_generate_key(dh_key * key);
+int dh_import_params(dh_key * key, uint8_t* p, size_t p_size, uint8_t* g, size_t g_size);
+void dh_free(dh_key * key);
+int dh_generate_public(dh_key * public, dh_key* private);
+
+int dh_export(uint8_t *out, size_t *outlen, int type, dh_key *key);
+int dh_import(const uint8_t *in, size_t inlen, dh_key *key);
+#endif
diff --git a/ncr-int.h b/ncr-int.h
index 03fab19..2598967 100644
--- a/ncr-int.h
+++ b/ncr-int.h
@@ -5,6 +5,7 @@
#include <asm/atomic.h>
#include "cryptodev_int.h"
#include <ncr-pk.h>
+#include <ncr-dh.h>
#define KEY_DATA_MAX_SIZE 3*1024
@@ -18,6 +19,7 @@ struct algo_properties_st {
unsigned can_sign:1;
unsigned can_digest:1;
unsigned can_encrypt:1;
+ unsigned can_kx:1; /* key exchange */
unsigned is_symmetric:1;
unsigned is_pk:1;
int digest_size;
@@ -73,6 +75,7 @@ struct key_item_st {
union {
rsa_key rsa;
dsa_key dsa;
+ dh_key dh;
} pk;
} key;
diff --git a/ncr-key.c b/ncr-key.c
index 21c7cf2..31eba04 100644
--- a/ncr-key.c
+++ b/ncr-key.c
@@ -510,14 +510,23 @@ int ret;
err();
return ret;
}
+
+ if (item->type == NCR_KEY_TYPE_INVALID) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
info.flags = item->flags;
info.type = item->type;
info.algorithm = item->algorithm->algo;
+
+ ret = 0;
+fail:
_ncr_key_item_put( item);
- return 0;
+ return ret;
}
int ncr_key_generate_pair(struct list_sem_st* lst, void __user* arg)
diff --git a/ncr-pk.c b/ncr-pk.c
index e4a4e67..41d51e8 100644
--- a/ncr-pk.c
+++ b/ncr-pk.c
@@ -34,7 +34,7 @@
static struct workqueue_struct * pk_wq = NULL;
-static int tomerr(int err)
+int _ncr_tomerr(int err)
{
switch (err) {
case CRYPT_BUFFER_OVERFLOW:
@@ -57,6 +57,9 @@ void ncr_pk_clear(struct key_item_st* key)
case NCR_ALG_DSA:
dsa_free(&key->key.pk.dsa);
break;
+ case NCR_ALG_DH:
+ dh_free(&key->key.pk.dh);
+ break;
default:
return;
}
@@ -81,14 +84,14 @@ static int ncr_pk_make_public_and_id( struct key_item_st * private, struct key_i
cret = rsa_export(tmp, &max_size, PK_PUBLIC, &private->key.pk.rsa);
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
goto fail;
}
cret = rsa_import(tmp, max_size, &public->key.pk.rsa);
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
goto fail;
}
break;
@@ -96,14 +99,21 @@ static int ncr_pk_make_public_and_id( struct key_item_st * private, struct key_i
cret = dsa_export(tmp, &max_size, PK_PUBLIC, &private->key.pk.dsa);
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
goto fail;
}
cret = dsa_import(tmp, max_size, &public->key.pk.dsa);
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
+ goto fail;
+ }
+ break;
+ case NCR_ALG_DH:
+ ret = dh_generate_public(&public->key.pk.dh, &private->key.pk.dh);
+ if (ret < 0) {
+ err();
goto fail;
}
break;
@@ -117,7 +127,7 @@ static int ncr_pk_make_public_and_id( struct key_item_st * private, struct key_i
cret = hash_memory(_ncr_algo_to_properties(NCR_ALG_SHA1), tmp, max_size, private->key_id, &key_id_size);
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
goto fail;
}
private->key_id_size = public->key_id_size = key_id_size;
@@ -146,7 +156,7 @@ int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * pa
if (cret != CRYPT_OK) {
*packed_size = max_size;
err();
- return tomerr(cret);
+ return _ncr_tomerr(cret);
}
break;
case NCR_ALG_DSA:
@@ -154,7 +164,7 @@ int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * pa
if (cret != CRYPT_OK) {
*packed_size = max_size;
err();
- return tomerr(cret);
+ return _ncr_tomerr(cret);
}
break;
default:
@@ -180,14 +190,14 @@ int ncr_pk_unpack( struct key_item_st * key, const void * packed, size_t packed_
cret = rsa_import(packed, packed_size, (void*)&key->key.pk.rsa);
if (cret != CRYPT_OK) {
err();
- return tomerr(cret);
+ return _ncr_tomerr(cret);
}
break;
case NCR_ALG_DSA:
cret = dsa_import(packed, packed_size, (void*)&key->key.pk.dsa);
if (cret != CRYPT_OK) {
err();
- return tomerr(cret);
+ return _ncr_tomerr(cret);
}
break;
default:
@@ -211,7 +221,8 @@ struct keygen_st {
static void keygen_handler(struct work_struct *instance)
{
unsigned long e;
- int cret;
+ int cret, ret;
+ uint8_t * tmp = NULL;
struct keygen_st *st =
container_of(instance, struct keygen_st, pk_gen);
@@ -224,7 +235,7 @@ static void keygen_handler(struct work_struct *instance)
cret = rsa_make_key(st->params->params.rsa.bits/8, e, &st->private->key.pk.rsa);
if (cret != CRYPT_OK) {
err();
- st->ret = tomerr(cret);
+ st->ret = _ncr_tomerr(cret);
} else
st->ret = 0;
break;
@@ -238,15 +249,62 @@ static void keygen_handler(struct work_struct *instance)
st->params->params.dsa.p_bits/8, &st->private->key.pk.dsa);
if (cret != CRYPT_OK) {
err();
- st->ret = tomerr(cret);
+ st->ret = _ncr_tomerr(cret);
} else
st->ret = 0;
break;
+ case NCR_ALG_DH: {
+ uint8_t * p, *g;
+ size_t p_size, g_size;
+
+ p_size = st->params->params.dh.p_size;
+ g_size = st->params->params.dh.g_size;
+
+ tmp = kmalloc(g_size+p_size, GFP_KERNEL);
+ if (tmp == NULL) {
+ err();
+ st->ret = -ENOMEM;
+ goto fail;
+ }
+
+ p = tmp;
+ g = &tmp[p_size];
+
+ if (unlikely(copy_from_user(p, st->params->params.dh.p, p_size))) {
+ err();
+ st->ret = -EFAULT;
+ goto fail;
+ }
+
+ if (unlikely(copy_from_user(g, st->params->params.dh.g, g_size))) {
+ err();
+ st->ret = -EFAULT;
+ goto fail;
+ }
+
+ ret = dh_import_params(&st->private->key.pk.dh, p, p_size, g, g_size);
+ if (ret < 0) {
+ err();
+ st->ret = ret;
+ goto fail;
+ }
+
+ ret = dh_generate_key(&st->private->key.pk.dh);
+ if (ret < 0) {
+ st->ret = ret;
+ err();
+ goto fail;
+ }
+ st->ret = 0;
+ break;
+ }
default:
err();
st->ret = -EINVAL;
}
+fail:
+ kfree(tmp);
complete(&st->completed);
}
@@ -416,7 +474,7 @@ void * input, *output;
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
goto fail;
}
*osg_size = osize;
@@ -478,7 +536,7 @@ void * input, *output;
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
goto fail;
}
@@ -543,7 +601,7 @@ void * input, *output;
ctx->type, ctx->sign_hash, ctx->salt_len, &ctx->key->key.pk.rsa);
if (cret != CRYPT_OK) {
err();
- return tomerr(cret);
+ return _ncr_tomerr(cret);
}
*osg_size = osize;
break;
@@ -553,7 +611,7 @@ void * input, *output;
if (cret != CRYPT_OK) {
err();
- return tomerr(cret);
+ return _ncr_tomerr(cret);
}
*osg_size = osize;
break;
@@ -604,7 +662,7 @@ uint8_t* sig;
ctx->salt_len, &stat, &ctx->key->key.pk.rsa);
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
goto fail;
}
@@ -619,7 +677,7 @@ uint8_t* sig;
hash, hash_size, &stat, &ctx->key->key.pk.dsa);
if (cret != CRYPT_OK) {
err();
- ret = tomerr(cret);
+ ret = _ncr_tomerr(cret);
goto fail;
}
diff --git a/ncr-pk.h b/ncr-pk.h
index fdc5e1c..734f6fd 100644
--- a/ncr-pk.h
+++ b/ncr-pk.h
@@ -51,4 +51,6 @@ int ncr_pk_cipher_verify(const struct ncr_pk_ctx* ctx,
const struct scatterlist* sign_sg, unsigned int sign_sg_cnt, size_t sign_sg_size,
const void* hash, size_t hash_size, ncr_error_t* err);
+int _ncr_tomerr(int err);
+
#endif
diff --git a/ncr-sessions.c b/ncr-sessions.c
index bd68075..c5b31ac 100644
--- a/ncr-sessions.c
+++ b/ncr-sessions.c
@@ -201,6 +201,8 @@ static const struct algo_properties_st algo_properties[] = {
.can_encrypt=1, .can_sign=1, .key_type = NCR_KEY_TYPE_PUBLIC },
{ .algo = NCR_ALG_DSA, .kstr = NULL, .is_pk = 1,
.can_sign=1, .key_type = NCR_KEY_TYPE_PUBLIC },
+ { .algo = NCR_ALG_DH, .kstr = NULL, .is_pk = 1,
+ .can_kx=1, .key_type = NCR_KEY_TYPE_PUBLIC },
{ .algo = NCR_ALG_NONE }
};
diff --git a/ncr.h b/ncr.h
index ee6d502..5d0f6b4 100644
--- a/ncr.h
+++ b/ncr.h
@@ -39,6 +39,7 @@ typedef enum {
NCR_ALG_RSA=140,
NCR_ALG_DSA,
+ NCR_ALG_DH, /* DH as in PKCS #3 */
} ncr_algorithm_t;
@@ -76,6 +77,7 @@ struct ncr_key_generate_params_st {
ncr_algorithm_t algorithm; /* just a cipher algorithm when
* generating secret keys
*/
+
unsigned int keyflags;
union {
struct {
@@ -83,14 +85,23 @@ struct ncr_key_generate_params_st {
} secret;
struct {
unsigned int bits;
- unsigned long e;
+ unsigned long e; /* use zero for default */
} rsa;
struct {
- unsigned int q_bits;
+ /* For DSS standard allowed values
+ * are: p:1024 q: 160
+ * p:2048 q: 224
+ * p:2048 q: 256
+ * p:3072 q: 256
+ */
unsigned int p_bits;
+ unsigned int q_bits;
} dsa;
struct {
- unsigned int bits;
+ uint8_t __user *p; /* prime */
+ size_t p_size;
+ uint8_t __user *g; /* generator */
+ size_t g_size;
} dh;
} params;
};