summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--cryptodev_cipher.c30
-rw-r--r--cryptodev_int.h5
-rw-r--r--cryptodev_main.c24
-rw-r--r--ncr-cipher.c236
-rw-r--r--ncr-cipher.h20
-rw-r--r--ncr-key-wrap.c309
-rw-r--r--ncr-key.c5
-rw-r--r--ncr-sessions.c125
-rw-r--r--ncr.c8
-rw-r--r--ncr.h7
-rw-r--r--ncr_int.h42
12 files changed, 778 insertions, 36 deletions
diff --git a/Makefile b/Makefile
index b25b634..b427b3f 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,8 @@ KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
VERSION = 0.1
cryptodev-objs = cryptodev_main.o cryptodev_cipher.o ncr.o \
- ncr-data.o ncr-key.o ncr-limits.o
+ ncr-data.o ncr-key.o ncr-limits.o ncr-sessions.o ncr-cipher.o \
+ ncr-key-wrap.o
obj-m += cryptodev.o
diff --git a/cryptodev_cipher.c b/cryptodev_cipher.c
index 2f52f46..7c1db6a 100644
--- a/cryptodev_cipher.c
+++ b/cryptodev_cipher.c
@@ -48,9 +48,9 @@ static void cryptodev_complete(struct crypto_async_request *req, int err)
complete(&res->completion);
}
-int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, uint8_t __user * key, size_t keylen)
+int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, uint8_t * keyp, size_t keylen)
{
- uint8_t keyp[CRYPTO_CIPHER_MAX_KEY_LEN];
+
struct ablkcipher_alg* alg;
int ret;
@@ -58,17 +58,6 @@ int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, uint8_t
out->init = 1;
- if (unlikely(keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) {
- dprintk(1,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
- alg_name, keylen*8);
- return -EINVAL;
- }
- /* Copy the key from user and set to TFM. */
- if (unlikely(copy_from_user(keyp, key, keylen))) {
- dprintk(1, KERN_DEBUG, "copy_from_user() failed for key\n");
- return -EINVAL;
- }
-
out->async.s = crypto_alloc_ablkcipher(alg_name, 0, 0);
if (unlikely(IS_ERR(out->async.s))) {
dprintk(1,KERN_DEBUG,"%s: Failed to load cipher %s\n", __func__,
@@ -196,23 +185,12 @@ ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, struct scatterlist
/* Hash functions */
-int cryptodev_hash_init( struct hash_data* hdata, const char* alg_name, int hmac_mode, void __user* mackey, size_t mackeylen)
+int cryptodev_hash_init( struct hash_data* hdata, const char* alg_name, int hmac_mode, void * mackey, size_t mackeylen)
{
int ret;
-uint8_t hkeyp[CRYPTO_HMAC_MAX_KEY_LEN];
hdata->init = 1;
- if (unlikely(mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) {
- dprintk(1,KERN_DEBUG,"Setting hmac key failed for %s-%zu.\n",
- alg_name, mackeylen*8);
- return -EINVAL;
- }
- if (unlikely(copy_from_user(hkeyp, mackey, mackeylen))) {
- dprintk(1, KERN_DEBUG, "copy_from_user() failed for mackey\n");
- return -EINVAL;
- }
-
hdata->async.s = crypto_alloc_ahash(alg_name, 0, 0);
if (unlikely(IS_ERR(hdata->async.s))) {
dprintk(1,KERN_DEBUG,"%s: Failed to load transform for %s\n", __func__,
@@ -223,7 +201,7 @@ uint8_t hkeyp[CRYPTO_HMAC_MAX_KEY_LEN];
/* Copy the key from user and set to TFM. */
if (hmac_mode != 0) {
- ret = crypto_ahash_setkey(hdata->async.s, hkeyp, mackeylen);
+ ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen);
if (unlikely(ret)) {
dprintk(1,KERN_DEBUG,"Setting hmac key failed for %s-%zu.\n",
alg_name, mackeylen*8);
diff --git a/cryptodev_int.h b/cryptodev_int.h
index 6f2cc5e..5d4ebfe 100644
--- a/cryptodev_int.h
+++ b/cryptodev_int.h
@@ -10,6 +10,7 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/scatterlist.h>
#define PFX "cryptodev: "
#define dprintk(level,severity,format,a...) \
@@ -35,7 +36,7 @@ struct cipher_data
} async;
};
-int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, __user uint8_t * key, size_t keylen);
+int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, uint8_t * key, size_t keylen);
void cryptodev_cipher_deinit(struct cipher_data* cdata);
ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, struct scatterlist *sg1, struct scatterlist *sg2, size_t len);
ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, struct scatterlist *sg1, struct scatterlist *sg2, size_t len);
@@ -57,7 +58,7 @@ int cryptodev_hash_final( struct hash_data* hdata, void* output);
ssize_t cryptodev_hash_update( struct hash_data* hdata, struct scatterlist *sg, size_t len);
int cryptodev_hash_reset( struct hash_data* hdata);
void cryptodev_hash_deinit(struct hash_data* hdata);
-int cryptodev_hash_init( struct hash_data* hdata, const char* alg_name, int hmac_mode, __user void* mackey, size_t mackeylen);
+int cryptodev_hash_init( struct hash_data* hdata, const char* alg_name, int hmac_mode, void* mackey, size_t mackeylen);
/* compatibility stuff */
#ifdef CONFIG_COMPAT
diff --git a/cryptodev_main.c b/cryptodev_main.c
index 58ae45b..0b2493d 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -198,7 +198,17 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
/* Set-up crypto transform. */
if (alg_name) {
- ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, sop->key, sop->keylen);
+ uint8_t keyp[CRYPTO_CIPHER_MAX_KEY_LEN];
+
+ if (unlikely(sop->keylen > CRYPTO_CIPHER_MAX_KEY_LEN)) {
+ dprintk(1,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
+ alg_name, sop->keylen*8);
+ ret = -EINVAL;
+ goto error;
+ }
+ copy_from_user(keyp, sop->key, sop->keylen);
+
+ ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keyp, sop->keylen);
if (ret < 0) {
dprintk(1,KERN_DEBUG,"%s: Failed to load cipher for %s\n", __func__,
alg_name);
@@ -208,7 +218,17 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
}
if (hash_name) {
- ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode, sop->mackey, sop->mackeylen);
+ uint8_t keyp[CRYPTO_HMAC_MAX_KEY_LEN];
+
+ if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) {
+ dprintk(1,KERN_DEBUG,"Setting key failed for %s-%zu.\n",
+ alg_name, sop->mackeylen*8);
+ ret = -EINVAL;
+ goto error;
+ }
+ copy_from_user(keyp, sop->mackey, sop->mackeylen);
+
+ ret = cryptodev_hash_init(&ses_new->hdata, hash_name, hmac_mode, keyp, sop->mackeylen);
if (ret != 0) {
dprintk(1,KERN_DEBUG,"%s: Failed to load hash for %s\n", __func__,
hash_name);
diff --git a/ncr-cipher.c b/ncr-cipher.c
new file mode 100644
index 0000000..d0fc320
--- /dev/null
+++ b/ncr-cipher.c
@@ -0,0 +1,236 @@
+/*
+ * Driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * cryptodev 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cryptodev 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/random.h>
+#include <asm/uaccess.h>
+#include <asm/ioctl.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include "cryptodev.h"
+#include "cryptodev_int.h"
+#include "ncr_int.h"
+
+static inline const char* algo2str(ncr_algorithm_t algo)
+{
+ switch(algo) {
+ case NCR_ALG_AES_ECB:
+ return "ecb(aes)";
+ case NCR_ALG_3DES_CBC:
+ return "cbc(des3_ede)";
+ case NCR_ALG_AES_CBC:
+ return "cbc(aes)";
+ case NCR_ALG_CAMELLIA_CBC:
+ return "cbc(camelia)";
+ case NCR_ALG_SHA1:
+ return "sha1";
+ case NCR_ALG_MD5:
+ return "md5";
+ case NCR_ALG_SHA2_224:
+ return "sha224";
+ case NCR_ALG_SHA2_256:
+ return "sha256";
+ case NCR_ALG_SHA2_384:
+ return "sha384";
+ case NCR_ALG_SHA2_512:
+ return "sha512";
+ case NCR_ALG_HMAC_SHA1:
+ return "hmac(sha1)";
+ case NCR_ALG_HMAC_MD5:
+ return "hmac(md5)";
+ case NCR_ALG_HMAC_SHA2_224:
+ return "hmac(sha224)";
+ case NCR_ALG_HMAC_SHA2_256:
+ return "hmac(sha256)";
+ case NCR_ALG_HMAC_SHA2_384:
+ return "hmac(sha384)";
+ case NCR_ALG_HMAC_SHA2_512:
+ return "hmac(sha512)";
+ default:
+ return NULL;
+ }
+}
+
+ncr_session_t ncr_cipher_init(struct list_sem_st* sess_lst, ncr_algorithm_t algorithm, struct key_item_st *key, void* iv, size_t iv_size);
+void ncr_cipher_deinit(struct list_sem_st* sess_lst, ncr_session_t session);
+int ncr_cipher_encrypt(struct list_sem_st* sess_lst, ncr_session_t session, const struct data_item_st * plaintext, struct data_item_st* ciphertext);
+int ncr_cipher_decrypt(struct list_sem_st* sess_lst, ncr_session_t session, const struct data_item_st * ciphertext, struct data_item_st* plaintext);
+
+ncr_session_t ncr_cipher_init(struct list_sem_st* sess_lst, ncr_algorithm_t algorithm, struct key_item_st *key, void* iv, size_t iv_size)
+{
+struct session_item_st* sess;
+int ret;
+const char* str;
+
+ if (key->type != NCR_KEY_TYPE_SECRET) {
+ err();
+ return NCR_SESSION_INVALID;
+ }
+
+ sess = ncr_session_new(sess_lst);
+ if (sess == NULL) {
+ err();
+ return NCR_SESSION_INVALID;
+ }
+
+ str = algo2str(algorithm);
+ if (str == NULL) {
+ err();
+ return NCR_SESSION_INVALID;
+ }
+
+ ret = cryptodev_cipher_init(&sess->ctx, str, key->key.secret.data, key->key.secret.size);
+ if (ret < 0) {
+ err();
+ _ncr_sessions_item_put(sess);
+ return NCR_SESSION_INVALID;
+ }
+
+ return sess->desc;
+}
+
+int ncr_cipher_encrypt(struct list_sem_st* sess_lst, ncr_session_t session, const struct data_item_st * plaintext, struct data_item_st* ciphertext)
+{
+ssize_t output;
+struct scatterlist sg, sgo;
+struct session_item_st* sess;
+
+ sess = ncr_sessions_item_get( sess_lst, session);
+ if (sess == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ sg_init_one(&sg, plaintext->data, plaintext->data_size);
+
+ sg_init_one(&sgo, ciphertext->data, ciphertext->data_size);
+
+ output = cryptodev_cipher_encrypt( &sess->ctx, &sg, &sgo, plaintext->data_size);
+ _ncr_sessions_item_put(sess);
+
+ if (output < 0) {
+ err();
+ return output;
+ }
+
+ return 0;
+}
+
+/* inplace encryption */
+int _ncr_cipher_encrypt(struct list_sem_st* sess_lst, ncr_session_t session, void* plaintext, size_t plaintext_size)
+{
+ssize_t output;
+struct scatterlist sg;
+struct session_item_st* sess;
+
+ sess = ncr_sessions_item_get( sess_lst, session);
+ if (sess == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ sg_init_one(&sg, plaintext, plaintext_size);
+
+ output = cryptodev_cipher_encrypt( &sess->ctx, &sg, &sg, plaintext_size);
+ _ncr_sessions_item_put(sess);
+
+ if (output < 0) {
+ err();
+ return output;
+ }
+
+ return 0;
+}
+
+/* inplace encryption */
+int _ncr_cipher_decrypt(struct list_sem_st* sess_lst, ncr_session_t session, void* ciphertext, size_t ciphertext_size)
+{
+ssize_t output;
+struct scatterlist sg;
+struct session_item_st* sess;
+
+ sess = ncr_sessions_item_get( sess_lst, session);
+ if (sess == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ sg_init_one(&sg, ciphertext, ciphertext_size);
+
+ output = cryptodev_cipher_encrypt( &sess->ctx, &sg, &sg, ciphertext_size);
+ _ncr_sessions_item_put(sess);
+
+ if (output < 0) {
+ err();
+ return output;
+ }
+
+ return 0;
+}
+
+int ncr_cipher_decrypt(struct list_sem_st* sess_lst, ncr_session_t session, const struct data_item_st * ciphertext, struct data_item_st* plaintext)
+{
+ssize_t output;
+struct scatterlist sg, sgo;
+struct session_item_st* sess;
+
+ sess = ncr_sessions_item_get( sess_lst, session);
+ if (sess == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ sg_init_one(&sgo, plaintext->data, plaintext->data_size);
+
+ sg_init_one(&sg, ciphertext->data, ciphertext->data_size);
+
+ output = cryptodev_cipher_decrypt( &sess->ctx, &sg, &sgo, ciphertext->data_size);
+ _ncr_sessions_item_put(sess);
+
+ if (output < 0) {
+ err();
+ return output;
+ }
+
+ return 0;
+}
+
+void ncr_cipher_deinit(struct list_sem_st* lst, ncr_session_t session)
+{
+ struct session_item_st * item, *tmp;
+
+ down(&lst->sem);
+
+ list_for_each_entry_safe(item, tmp, &lst->list, list) {
+ if(item->desc == session) {
+ list_del(&item->list);
+ cryptodev_cipher_deinit(&item->ctx);
+ _ncr_sessions_item_put( item); /* decrement ref count */
+ break;
+ }
+ }
+
+ up(&lst->sem);
+
+ return;
+}
diff --git a/ncr-cipher.h b/ncr-cipher.h
new file mode 100644
index 0000000..a582fc6
--- /dev/null
+++ b/ncr-cipher.h
@@ -0,0 +1,20 @@
+/* cipher stuff */
+
+#ifndef NCR_CIPHER_H
+# define NCR_CIPHER_H
+
+ncr_session_t ncr_cipher_init(struct list_sem_st* sess_lst,
+ ncr_algorithm_t algorithm, struct key_item_st *key, void* iv, size_t iv_size);
+int ncr_cipher_encrypt(struct list_sem_st* sess_lst, ncr_session_t session,
+ const struct data_item_st * plaintext, struct data_item_st* ciphertext);
+int ncr_cipher_decrypt(struct list_sem_st* sess_lst, ncr_session_t session,
+ const struct data_item_st * ciphertext, struct data_item_st* plaintext);
+void ncr_cipher_deinit(struct list_sem_st* lst, ncr_session_t session);
+
+int _ncr_cipher_encrypt(struct list_sem_st* sess_lst,
+ ncr_session_t session, void* plaintext, size_t plaintext_size);
+
+int _ncr_cipher_decrypt(struct list_sem_st* sess_lst,
+ ncr_session_t session, void* plaintext, size_t plaintext_size);
+
+#endif /* NCR_CIPHER_H */
diff --git a/ncr-key-wrap.c b/ncr-key-wrap.c
new file mode 100644
index 0000000..e9cd884
--- /dev/null
+++ b/ncr-key-wrap.c
@@ -0,0 +1,309 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * cryptodev 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cryptodev 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/mm.h>
+#include <linux/highmem.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 "ncr-cipher.h"
+
+typedef uint8_t val64_t[8];
+
+static const val64_t initA = "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6";
+
+void val64_zero( val64_t * val)
+{
+ memset(val, 0, sizeof(*val));
+}
+
+void val64_xor( val64_t * val, uint32_t x)
+{
+ (*val)[7] ^= x & 0xff;
+ (*val)[6] ^= (x >> 8) & 0xff;
+ (*val)[5] ^= (x >> 16) & 0xff;
+ (*val)[4] ^= (x >> 24) & 0xff;
+}
+
+/* Wraps using the RFC3394 way.
+ */
+static int wrap_aes(struct list_sem_st* sess_lst,
+ struct key_item_st* tobewrapped, struct key_item_st *kek,
+ struct data_item_st* output)
+{
+size_t key_size, n;
+uint8_t *raw_key;
+val64_t A;
+int i, j, ret;
+uint8_t aes_block[16];
+ncr_session_t kd;
+
+ kd = ncr_cipher_init(sess_lst, NCR_ALG_AES_ECB, kek, NULL, 0);
+ if (kd == NCR_SESSION_INVALID) {
+ err();
+ return -ENOMEM;
+ }
+
+ if (tobewrapped->type != NCR_KEY_TYPE_SECRET) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ raw_key = tobewrapped->key.secret.data;
+ key_size = tobewrapped->key.secret.size;
+
+ if (key_size % 8 != 0) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ n = key_size/8;
+
+ if (output->max_data_size < (n+1)*8) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+
+ {
+ val64_t R[n+1];
+
+ /* R = P */
+ for (i=0;i<n;i++) {
+ memcpy(R[i], &raw_key[i*8], 8);
+ }
+
+ memcpy(A, initA, sizeof(initA));
+
+ for (i=0;i<6*n;i++) {
+ memcpy(aes_block, A, 8);
+ memcpy(&aes_block[8], R[0], 8);
+
+ _ncr_cipher_encrypt(sess_lst, kd, aes_block, sizeof(aes_block));
+
+ memcpy(A, aes_block, 8); /* A = MSB64(AES(A^{t-1}|R_{1}^{t-1})) */
+ val64_xor(&A, i+1); /* A ^= t */
+
+ for (j=0;j<n-1;j++)
+ memcpy(R[i], R[i+1], sizeof(R[i]));
+ memcpy(R[n-1], &aes_block[8], 8); /* R[n-1] = LSB64(AES(A^{t-1}|R_{1}^{t-1})) */
+ }
+
+ memcpy(output->data, A, sizeof(A));
+ for (j=1;j<n;j++)
+ memcpy(&output->data[j*8], R[j], 8);
+ output->data_size = (n+1)*8;
+ }
+
+
+ ret = 0;
+
+cleanup:
+ ncr_cipher_deinit(sess_lst, kd);
+
+ return ret;
+}
+
+static int unwrap_aes(struct list_sem_st* sess_lst,
+ struct key_item_st* output, struct key_item_st *kek,
+ struct data_item_st* wrapped)
+{
+size_t key_size, n;
+uint8_t *raw_key;
+val64_t A;
+int i, j, ret;
+uint8_t aes_block[16];
+ncr_session_t kd;
+
+ kd = ncr_cipher_init(sess_lst, NCR_ALG_AES_ECB, kek, NULL, 0);
+ if (kd == NCR_SESSION_INVALID) {
+ err();
+ return -ENOMEM;
+ }
+
+ output->type = NCR_KEY_TYPE_SECRET;
+
+ raw_key = wrapped->data;
+ key_size = wrapped->data_size;
+
+ if (key_size % 8 != 0) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ n = key_size/8 - 1;
+
+ if (sizeof(output->key.secret.data) < (n-1)*8) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ {
+ val64_t R[n];
+
+ memcpy(A, raw_key, 8); /* A = C[0] */
+ for (i=0;i<n;i++)
+ memcpy(R[i], &raw_key[(i+1)*8], 8);
+
+ for (i=(6*n)-1;i>=0;i--) {
+ val64_xor(&A, i+1);
+
+ memcpy(aes_block, A, 8);
+ memcpy(&aes_block[8], R[n-1], 8);
+
+ _ncr_cipher_decrypt(sess_lst, kd, aes_block, sizeof(aes_block));
+
+ memcpy(A, aes_block, 8);
+ memcpy(R[0], &aes_block[8], 8);
+
+ for (j=1;j<n;j++)
+ memcpy(R[j], R[j-1], sizeof(R[j]));
+ }
+
+ if (memcmp(A, initA, sizeof(initA))!= 0) {
+ err();
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ for (i=0;i<n;i++) {
+ memcpy(&output->key.secret.data[i*8], R[i], sizeof(R[i]));
+ }
+ output->key.secret.size = n*8;
+
+ }
+
+
+ ret = 0;
+
+cleanup:
+ ncr_cipher_deinit(sess_lst, kd);
+
+ return ret;
+}
+
+int ncr_key_wrap(struct list_sem_st* key_lst, struct list_sem_st* data_lst, struct list_sem_st* sess_lst, void __user* arg)
+{
+struct ncr_key_wrap_st wrap;
+struct key_item_st* wkey = NULL;
+struct key_item_st* key = NULL;
+struct data_item_st * data = NULL;
+int ret;
+
+ copy_from_user( &wrap, arg, sizeof(wrap));
+
+ wkey = ncr_key_item_get( key_lst, wrap.keytowrap);
+ if (wkey == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ if (!(wkey->flags & NCR_KEY_FLAG_WRAPPABLE)) {
+ err();
+ return -EPERM;
+ }
+
+ key = ncr_key_item_get( key_lst, wrap.key.key);
+ if (key == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ data = ncr_data_item_get(data_lst, wrap.data);
+ if (data == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ data->flags = key_flags_to_data(wkey->flags) | NCR_DATA_FLAG_EXPORTABLE;
+
+ switch(wrap.algorithm) {
+ case NCR_WALG_AES_RFC3394:
+ ret = wrap_aes(sess_lst, wkey, key, data);
+ default:
+ ret = -EINVAL;
+ }
+
+fail:
+ if (wkey != NULL) _ncr_key_item_put(wkey);
+ if (key != NULL) _ncr_key_item_put(key);
+ if (data != NULL) _ncr_data_item_put(data);
+
+ return ret;
+}
+
+int ncr_key_unwrap(struct list_sem_st* key_lst, struct list_sem_st* data_lst, struct list_sem_st* sess_lst, void __user* arg)
+{
+struct ncr_key_wrap_st wrap;
+struct key_item_st* wkey = NULL;
+struct key_item_st* key = NULL;
+struct data_item_st * data = NULL;
+int ret;
+
+ copy_from_user( &wrap, arg, sizeof(wrap));
+
+ wkey = ncr_key_item_get( key_lst, wrap.keytowrap);
+ if (wkey == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ key = ncr_key_item_get( key_lst, wrap.key.key);
+ if (key == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ data = ncr_data_item_get(data_lst, wrap.data);
+ if (data == NULL) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ wkey->flags = data_flags_to_key(wkey->flags) | NCR_KEY_FLAG_WRAPPABLE;
+
+ switch(wrap.algorithm) {
+ case NCR_WALG_AES_RFC3394:
+ ret = unwrap_aes(sess_lst, wkey, key, data);
+ default:
+ ret = -EINVAL;
+ }
+
+fail:
+ if (wkey != NULL) _ncr_key_item_put(wkey);
+ if (key != NULL) _ncr_key_item_put(key);
+ if (data != NULL) _ncr_data_item_put(data);
+
+ return ret;
+}
diff --git a/ncr-key.c b/ncr-key.c
index 4a93a4a..8af2706 100644
--- a/ncr-key.c
+++ b/ncr-key.c
@@ -183,10 +183,7 @@ int ret;
}
/* found */
- ditem->flags = 0;
- if ((item->flags & NCR_KEY_FLAG_EXPORTABLE)) {
- ditem->flags |= NCR_DATA_FLAG_EXPORTABLE;
- }
+ ditem->flags = key_flags_to_data(item->flags);
if (item->key.secret.size > 0) {
memcpy(ditem->data, item->key.secret.data, item->key.secret.size);
diff --git a/ncr-sessions.c b/ncr-sessions.c
new file mode 100644
index 0000000..a692588
--- /dev/null
+++ b/ncr-sessions.c
@@ -0,0 +1,125 @@
+/*
+ * New driver for /dev/crypto device (aka CryptoDev)
+
+ * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org>
+ *
+ * This file is part of linux cryptodev.
+ *
+ * cryptodev 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * cryptodev 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/crypto.h>
+#include "cryptodev.h"
+#include "ncr.h"
+#include "ncr_int.h"
+
+void ncr_sessions_list_deinit(struct list_sem_st* lst)
+{
+ if(lst) {
+ struct session_item_st * item, *tmp;
+
+ down(&lst->sem);
+
+ list_for_each_entry_safe(item, tmp, &lst->list, list) {
+ list_del(&item->list);
+ _ncr_sessions_item_put( item); /* decrement ref count */
+ }
+ up(&lst->sem);
+
+ }
+}
+
+/* must be called with data semaphore down
+ */
+static ncr_session_t _ncr_sessions_get_new_desc( struct list_sem_st* lst)
+{
+struct session_item_st* item;
+int mx = 0;
+
+ list_for_each_entry(item, &lst->list, list) {
+ mx = max(mx, item->desc);
+ }
+ mx++;
+
+ return mx;
+}
+
+/* returns the data item corresponding to desc */
+struct session_item_st* ncr_sessions_item_get( struct list_sem_st* lst, ncr_session_t desc)
+{
+struct session_item_st* item;
+
+ down(&lst->sem);
+ list_for_each_entry(item, &lst->list, list) {
+ if (item->desc == desc) {
+ atomic_inc(&item->refcnt);
+ up(&lst->sem);
+ return item;
+ }
+ }
+ up(&lst->sem);
+
+ err();
+ return NULL;
+}
+
+void _ncr_sessions_item_put( struct session_item_st* item)
+{
+ if (atomic_dec_and_test(&item->refcnt)) {
+ kfree(item);
+ }
+}
+
+struct session_item_st* ncr_session_new(struct list_sem_st* lst)
+{
+ struct session_item_st* sess;
+
+ sess = kmalloc(sizeof(*sess), GFP_KERNEL);
+ if (sess == NULL) {
+ err();
+ return NULL;
+ }
+
+ memset(sess, 0, sizeof(*sess));
+
+ atomic_set(&sess->refcnt, 1);
+
+ down(&lst->sem);
+
+ sess->desc = _ncr_sessions_get_new_desc(lst);
+ list_add(&sess->list, &lst->list);
+
+ up(&lst->sem);
+
+ return sess;
+}
+
+void ncr_session_deinit(struct list_sem_st* lst, ncr_session_t desc)
+{
+ struct session_item_st * item, *tmp;
+
+ down(&lst->sem);
+
+ list_for_each_entry_safe(item, tmp, &lst->list, list) {
+ if(item->desc == desc) {
+ list_del(&item->list);
+ _ncr_sessions_item_put( item); /* decrement ref count */
+ break;
+ }
+ }
+
+ up(&lst->sem);
+
+ return;
+}
diff --git a/ncr.c b/ncr.c
index e255dbd..1736abb 100644
--- a/ncr.c
+++ b/ncr.c
@@ -48,6 +48,9 @@ void* ncr_init_lists(void)
init_MUTEX(&lst->key.sem);
INIT_LIST_HEAD(&lst->key.list);
+ init_MUTEX(&lst->sessions.sem);
+ INIT_LIST_HEAD(&lst->sessions.list);
+
return lst;
}
@@ -56,6 +59,7 @@ void ncr_deinit_lists(struct ncr_lists *lst)
if(lst) {
ncr_data_list_deinit(&lst->data);
ncr_key_list_deinit(&lst->key);
+ ncr_sessions_list_deinit(&lst->sessions);
kfree(lst);
}
}
@@ -90,6 +94,10 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp,
return ncr_key_import(&lst->data, &lst->key, (void*)arg);
case NCRIO_KEY_GET_INFO:
return ncr_key_info(&lst->key, (void*)arg);
+ case NCRIO_KEY_WRAP:
+ return ncr_key_wrap(&lst->key, &lst->data, &lst->sessions, (void*)arg);
+ case NCRIO_KEY_UNWRAP:
+ return ncr_key_unwrap(&lst->key, &lst->data, &lst->sessions, (void*)arg);
#if 0
case NCRIO_KEY_GENERATE_PAIR:
return ncr_key_generate_pair(&lst->key, (void*)arg);
diff --git a/ncr.h b/ncr.h
index 5f67f4b..fdce0c3 100644
--- a/ncr.h
+++ b/ncr.h
@@ -11,6 +11,8 @@ typedef enum {
NCR_ALG_CAMELLIA_CBC,
NCR_ALG_ARCFOUR,
+ NCR_ALG_AES_ECB,
+
NCR_ALG_SHA1=40,
NCR_ALG_MD5,
NCR_ALG_SHA2_224,
@@ -29,6 +31,9 @@ typedef enum {
NCR_ALG_DSA,
} ncr_algorithm_t;
+typedef enum {
+ NCR_WALG_AES_RFC3394,
+} ncr_wrap_algorithm_t;
typedef enum {
NCR_KEY_TYPE_INVALID,
@@ -261,7 +266,7 @@ struct ncr_private_key_params_st
/* FIXME key wrap ioctls
*/
struct ncr_key_wrap_st {
- ncr_algorithm_t algorithm;
+ ncr_wrap_algorithm_t algorithm;
ncr_key_t keytowrap;
struct ncr_key_params_st key;
ncr_data_t data; /* encrypted keytowrap */
diff --git a/ncr_int.h b/ncr_int.h
index 66f2c9a..e96e498 100644
--- a/ncr_int.h
+++ b/ncr_int.h
@@ -3,15 +3,26 @@
#include "ncr.h"
#include <asm/atomic.h>
+#include "cryptodev_int.h"
#define err() printk(KERN_DEBUG"ncr: %s: %s: %d\n", __FILE__, __func__, __LINE__)
+struct session_item_st {
+ struct list_head list;
+
+ struct cipher_data ctx;
+
+ atomic_t refcnt;
+ ncr_session_t desc;
+};
+
struct data_item_st {
struct list_head list;
/* This object is not protected from concurrent access.
* I see no reason to allow concurrent writes (reads are
* not an issue).
*/
+
uint8_t* data;
size_t data_size;
size_t max_data_size;
@@ -60,6 +71,7 @@ struct ncr_lists {
struct list_sem_st key;
/* sessions */
+ struct list_sem_st sessions;
};
void* ncr_init_lists(void);
@@ -105,5 +117,35 @@ void ncr_limits_deinit(void);
ncr_key_type_t ncr_algorithm_to_key_type(ncr_algorithm_t algo);
+int ncr_key_wrap(struct list_sem_st* keys, struct list_sem_st* data, struct list_sem_st* sess_lst, void __user* arg);
+int ncr_key_unwrap(struct list_sem_st*, struct list_sem_st* data, struct list_sem_st* sess_lst, void __user* arg);
+
+/* sessions */
+struct session_item_st* ncr_session_new(struct list_sem_st* lst);
+void _ncr_sessions_item_put( struct session_item_st* item);
+struct session_item_st* ncr_sessions_item_get( struct list_sem_st* lst, ncr_session_t desc);
+void ncr_sessions_list_deinit(struct list_sem_st* lst);
+void ncr_session_deinit(struct list_sem_st* lst, ncr_session_t desc);
+
+/* misc helper macros */
+inline static unsigned int key_flags_to_data(unsigned int key_flags)
+{
+ unsigned int flags = 0;
+
+ if (key_flags & NCR_KEY_FLAG_EXPORTABLE)
+ flags |= NCR_DATA_FLAG_EXPORTABLE;
+
+ return flags;
+}
+
+inline static unsigned int data_flags_to_key(unsigned int data_flags)
+{
+ unsigned int flags = 0;
+
+ if (data_flags & NCR_DATA_FLAG_EXPORTABLE)
+ flags |= NCR_KEY_FLAG_EXPORTABLE;
+
+ return flags;
+}
#endif