diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | cryptodev_cipher.c | 32 | ||||
-rw-r--r-- | cryptodev_int.h | 6 | ||||
-rw-r--r-- | ncr-cipher.c | 236 | ||||
-rw-r--r-- | ncr-cipher.h | 20 | ||||
-rw-r--r-- | ncr-key-wrap.c | 47 | ||||
-rw-r--r-- | ncr-sessions.c | 376 | ||||
-rw-r--r-- | ncr.c | 12 | ||||
-rw-r--r-- | ncr.h | 13 | ||||
-rw-r--r-- | ncr_int.h | 13 |
10 files changed, 465 insertions, 292 deletions
@@ -2,7 +2,7 @@ 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-sessions.o ncr-cipher.o \ + ncr-data.o ncr-key.o ncr-limits.o ncr-sessions.o \ ncr-key-wrap.o obj-m += cryptodev.o diff --git a/cryptodev_cipher.c b/cryptodev_cipher.c index 7c1db6a39dd..58fcba20869 100644 --- a/cryptodev_cipher.c +++ b/cryptodev_cipher.c @@ -159,6 +159,30 @@ static inline int waitfor (struct cryptodev_result* cr, ssize_t ret) return 0; } + +int _cryptodev_cipher_encrypt(struct cipher_data* cdata, const void* plaintext, + size_t plaintext_size, void* ciphertext, size_t ciphertext_size) +{ +struct scatterlist sg, sg2; + + sg_init_one(&sg, plaintext, plaintext_size); + sg_init_one(&sg2, ciphertext, ciphertext_size); + + return cryptodev_cipher_encrypt( cdata, &sg, &sg2, plaintext_size); +} + +int _cryptodev_cipher_decrypt(struct cipher_data* cdata, const void* ciphertext, + size_t ciphertext_size, void* plaintext, size_t plaintext_size) +{ +struct scatterlist sg, sg2; + + sg_init_one(&sg, ciphertext, ciphertext_size); + sg_init_one(&sg2, plaintext, plaintext_size); + + return cryptodev_cipher_encrypt( cdata, &sg, &sg2, ciphertext_size); +} + + ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, struct scatterlist *sg1, struct scatterlist *sg2, size_t len) { int ret; @@ -272,6 +296,14 @@ ssize_t cryptodev_hash_update( struct hash_data* hdata, struct scatterlist *sg, return waitfor(hdata->async.result,ret); } +ssize_t _cryptodev_hash_update( struct hash_data* hdata, const void* data, size_t len) +{ +struct scatterlist sg; + + sg_init_one(&sg, data, len); + + return cryptodev_hash_update( hdata, &sg, len); +} int cryptodev_hash_final( struct hash_data* hdata, void* output) { diff --git a/cryptodev_int.h b/cryptodev_int.h index 5d4ebfefc2b..7d2e83f7104 100644 --- a/cryptodev_int.h +++ b/cryptodev_int.h @@ -40,7 +40,12 @@ int cryptodev_cipher_init(struct cipher_data* out, const char* alg_name, uint8_t 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); + int cryptodev_cipher_set_iv(struct cipher_data* cdata, void* iv, size_t iv_size); +int _cryptodev_cipher_decrypt(struct cipher_data* cdata, const void* ciphertext, + size_t ciphertext_size, void* plaintext, size_t plaintext_size); +int _cryptodev_cipher_encrypt(struct cipher_data* cdata, const void* plaintext, + size_t plaintext_size, void* ciphertext, size_t ciphertext_size); /* hash stuff */ struct hash_data @@ -56,6 +61,7 @@ struct hash_data 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); +ssize_t _cryptodev_hash_update( struct hash_data* hdata, const void* data, 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, void* mackey, size_t mackeylen); diff --git a/ncr-cipher.c b/ncr-cipher.c deleted file mode 100644 index d0fc3202f6f..00000000000 --- a/ncr-cipher.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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 deleted file mode 100644 index a582fc61609..00000000000 --- a/ncr-cipher.h +++ /dev/null @@ -1,20 +0,0 @@ -/* 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 index e9cd884b495..00bc3dc2498 100644 --- a/ncr-key-wrap.c +++ b/ncr-key-wrap.c @@ -28,7 +28,7 @@ #include <linux/scatterlist.h> #include "ncr.h" #include "ncr_int.h" -#include "ncr-cipher.h" +#include "cryptodev_int.h" typedef uint8_t val64_t[8]; @@ -49,8 +49,7 @@ void val64_xor( val64_t * val, uint32_t x) /* 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, +static int wrap_aes(struct key_item_st* tobewrapped, struct key_item_st *kek, struct data_item_st* output) { size_t key_size, n; @@ -58,18 +57,17 @@ uint8_t *raw_key; val64_t A; int i, j, ret; uint8_t aes_block[16]; -ncr_session_t kd; +struct cipher_data ctx; - kd = ncr_cipher_init(sess_lst, NCR_ALG_AES_ECB, kek, NULL, 0); - if (kd == NCR_SESSION_INVALID) { + if (tobewrapped->type != NCR_KEY_TYPE_SECRET) { err(); - return -ENOMEM; + return -EINVAL; } - if (tobewrapped->type != NCR_KEY_TYPE_SECRET) { + ret = cryptodev_cipher_init(&ctx, "ecb(aes)", kek->key.secret.data, kek->key.secret.size); + if (ret < 0) { err(); - ret = -EINVAL; - goto cleanup; + return ret; } raw_key = tobewrapped->key.secret.data; @@ -104,7 +102,8 @@ ncr_session_t kd; memcpy(aes_block, A, 8); memcpy(&aes_block[8], R[0], 8); - _ncr_cipher_encrypt(sess_lst, kd, aes_block, sizeof(aes_block)); + _cryptodev_cipher_encrypt(&ctx, aes_block, sizeof(aes_block), + 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 */ @@ -124,13 +123,12 @@ ncr_session_t kd; ret = 0; cleanup: - ncr_cipher_deinit(sess_lst, kd); + cryptodev_cipher_deinit(&ctx); return ret; } -static int unwrap_aes(struct list_sem_st* sess_lst, - struct key_item_st* output, struct key_item_st *kek, +static int unwrap_aes(struct key_item_st* output, struct key_item_st *kek, struct data_item_st* wrapped) { size_t key_size, n; @@ -138,12 +136,12 @@ uint8_t *raw_key; val64_t A; int i, j, ret; uint8_t aes_block[16]; -ncr_session_t kd; +struct cipher_data ctx; - kd = ncr_cipher_init(sess_lst, NCR_ALG_AES_ECB, kek, NULL, 0); - if (kd == NCR_SESSION_INVALID) { + ret = cryptodev_cipher_init(&ctx, "ecb(aes)", kek->key.secret.data, kek->key.secret.size); + if (ret < 0) { err(); - return -ENOMEM; + return ret; } output->type = NCR_KEY_TYPE_SECRET; @@ -178,7 +176,8 @@ ncr_session_t kd; memcpy(aes_block, A, 8); memcpy(&aes_block[8], R[n-1], 8); - _ncr_cipher_decrypt(sess_lst, kd, aes_block, sizeof(aes_block)); + _cryptodev_cipher_decrypt(&ctx, aes_block, sizeof(aes_block), + aes_block, sizeof(aes_block)); memcpy(A, aes_block, 8); memcpy(R[0], &aes_block[8], 8); @@ -204,12 +203,12 @@ ncr_session_t kd; ret = 0; cleanup: - ncr_cipher_deinit(sess_lst, kd); + cryptodev_cipher_deinit(&ctx); 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) +int ncr_key_wrap(struct list_sem_st* key_lst, struct list_sem_st* data_lst, void __user* arg) { struct ncr_key_wrap_st wrap; struct key_item_st* wkey = NULL; @@ -248,7 +247,7 @@ int ret; switch(wrap.algorithm) { case NCR_WALG_AES_RFC3394: - ret = wrap_aes(sess_lst, wkey, key, data); + ret = wrap_aes(wkey, key, data); default: ret = -EINVAL; } @@ -261,7 +260,7 @@ fail: 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) +int ncr_key_unwrap(struct list_sem_st* key_lst, struct list_sem_st* data_lst, void __user* arg) { struct ncr_key_wrap_st wrap; struct key_item_st* wkey = NULL; @@ -295,7 +294,7 @@ int ret; switch(wrap.algorithm) { case NCR_WALG_AES_RFC3394: - ret = unwrap_aes(sess_lst, wkey, key, data); + ret = unwrap_aes(wkey, key, data); default: ret = -EINVAL; } diff --git a/ncr-sessions.c b/ncr-sessions.c index a69258845ef..1edeb0172a2 100644 --- a/ncr-sessions.c +++ b/ncr-sessions.c @@ -45,7 +45,7 @@ void ncr_sessions_list_deinit(struct list_sem_st* lst) static ncr_session_t _ncr_sessions_get_new_desc( struct list_sem_st* lst) { struct session_item_st* item; -int mx = 0; +int mx = 1; list_for_each_entry(item, &lst->list, list) { mx = max(mx, item->desc); @@ -105,7 +105,291 @@ struct session_item_st* ncr_session_new(struct list_sem_st* lst) return sess; } -void ncr_session_deinit(struct list_sem_st* lst, ncr_session_t desc) +static const struct algo_properties_st { + ncr_algorithm_t algo; + const char* kstr; + int needs_iv; + int digest_size; +} algo_properties[] = { + { .algo = NCR_ALG_3DES_CBC, .kstr = "cbc(des3_ede)", .needs_iv = 1 }, + { .algo = NCR_ALG_AES_CBC, .kstr = "cbc(aes)", .needs_iv = 1 }, + { .algo = NCR_ALG_CAMELLIA_CBC, .kstr = "ecb(camelia)", .needs_iv = 1 }, + { .algo = NCR_ALG_ARCFOUR, .kstr = NULL, .needs_iv = 0 }, + { .algo = NCR_ALG_AES_ECB, .kstr = "ecb(aes)", .needs_iv = 0 }, + { .algo = NCR_ALG_SHA1, .kstr = "sha1", .needs_iv = 0, .digest_size = 20 }, + { .algo = NCR_ALG_MD5, .kstr = "md5", .needs_iv = 0, .digest_size = 16 }, + { .algo = NCR_ALG_SHA2_224, .kstr = "sha224", .needs_iv = 0, .digest_size = 24 }, + { .algo = NCR_ALG_SHA2_256, .kstr = "sha256", .needs_iv = 0, .digest_size = 32 }, + { .algo = NCR_ALG_SHA2_384, .kstr = "sha384", .needs_iv = 0, .digest_size = 48 }, + { .algo = NCR_ALG_SHA2_512, .kstr = "sha512", .needs_iv = 0, .digest_size = 64 }, + { .algo = NCR_ALG_HMAC_SHA1, .kstr = "hmac(sha1)", .needs_iv = 0, .digest_size = 20 }, + { .algo = NCR_ALG_HMAC_MD5, .kstr = "hmac(md5)", .needs_iv = 0, .digest_size = 16 }, + { .algo = NCR_ALG_HMAC_SHA2_224, .kstr = "hmac(sha224)", .needs_iv = 0, .digest_size = 24 }, + { .algo = NCR_ALG_HMAC_SHA2_256, .kstr = "hmac(sha256)", .needs_iv = 0, .digest_size = 32 }, + { .algo = NCR_ALG_HMAC_SHA2_384, .kstr = "hmac(sha384)", .needs_iv = 0, .digest_size = 48 }, + { .algo = NCR_ALG_HMAC_SHA2_512, .kstr = "hmac(sha512)", .needs_iv = 0, .digest_size = 64 }, + { .algo = NCR_ALG_RSA, .kstr = NULL, .needs_iv = 0 }, + { .algo = NCR_ALG_DSA, .kstr = NULL, .needs_iv = 0 }, + { .algo = NCR_ALG_NONE } +}; + +static inline const char* algo2str(ncr_algorithm_t algo) +{ +ncr_algorithm_t a; +int i = 0; + + while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { + if (a == algo) + return algo_properties[i].kstr; + i++; + } + + return NULL; +} + +static int algo_needs_iv(ncr_algorithm_t algo) +{ +ncr_algorithm_t a; +int i = 0; + + while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { + if (a == algo) + return algo_properties[i].needs_iv; + i++; + } + + return 0; +} + +static int algo_digest_size(ncr_algorithm_t algo) +{ +ncr_algorithm_t a; +int i = 0; + + while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { + if (a == algo) + return algo_properties[i].digest_size; + i++; + } + + return 0; +} + +int ncr_session_init(struct ncr_lists* lists, void __user* arg) +{ + struct ncr_session_st session; + struct session_item_st* ns; + struct key_item_st *key = NULL; + int ret; + const char* str; + + copy_from_user( &session, arg, sizeof(session)); + + str = algo2str(session.algorithm); + if (str == NULL) { + err(); + return NCR_SESSION_INVALID; + } + + ns = ncr_session_new(&lists->sessions); + if (ns == NULL) { + err(); + return -EINVAL; + } + + ns->op = session.op; + ns->algo = session.algorithm; + switch(session.op) { + case NCR_OP_ENCRYPT: + case NCR_OP_DECRYPT: + /* read key */ + key = ncr_key_item_get( &lists->key, session.params.key); + if (key == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + if (key->type != NCR_KEY_TYPE_SECRET) { + err(); + ret = -EINVAL; + goto fail; + } + + ret = cryptodev_cipher_init(&ns->ctx, str, key->key.secret.data, key->key.secret.size); + if (ret < 0) { + err(); + goto fail; + } + + if (algo_needs_iv(session.algorithm)) { + if (session.params.params.cipher.iv_size > sizeof(session.params.params.cipher.iv)) { + err(); + ret = -EINVAL; + goto fail; + } + cryptodev_cipher_set_iv(&ns->ctx, session.params.params.cipher.iv, session.params.params.cipher.iv_size); + } + break; + + case NCR_OP_MAC: + /* read key */ + key = ncr_key_item_get( &lists->key, session.params.key); + if (key == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + if (key->type != NCR_KEY_TYPE_SECRET) { + err(); + ret = -EINVAL; + goto fail; + } + + ret = cryptodev_hash_init(&ns->hctx, str, 1, key->key.secret.data, key->key.secret.size); + if (ret < 0) { + err(); + goto fail; + } + break; + + case NCR_OP_DIGEST: + ret = cryptodev_hash_init(&ns->hctx, str, 0, NULL, 0); + if (ret < 0) { + err(); + goto fail; + } + + break; + + default: + err(); + ret = -EINVAL; + goto fail; + } + + ret = 0; + +fail: + if (key) _ncr_key_item_put(key); + if (ret < 0) + _ncr_sessions_item_put(ns); + + return ret; +} + +int ncr_session_update(struct ncr_lists* lists, void __user* arg) +{ + struct ncr_session_op_st op; + struct key_item_st *key = NULL; + int ret; + struct session_item_st* sess; + struct data_item_st* data = NULL; + struct data_item_st* odata = NULL; + + copy_from_user( &op, arg, sizeof(op)); + + sess = ncr_sessions_item_get( &lists->sessions, op.ses); + if (sess == NULL) { + err(); + return -EINVAL; + } + + switch(sess->op) { + case NCR_OP_ENCRYPT: + /* obtain data item */ + data = ncr_data_item_get( &lists->data, op.data.cipher.plaintext); + if (data == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + odata = ncr_data_item_get( &lists->data, op.data.cipher.ciphertext); + if (odata == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + if (odata->max_data_size < data->data_size) { + err(); + ret = -EINVAL; + goto fail; + } + + /* read key */ + ret = _cryptodev_cipher_encrypt(&sess->ctx, data->data, data->data_size, odata->data, data->data_size); + if (ret < 0) { + err(); + goto fail; + } + break; + case NCR_OP_DECRYPT: + /* obtain data item */ + data = ncr_data_item_get( &lists->data, op.data.cipher.ciphertext); + if (data == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + odata = ncr_data_item_get( &lists->data, op.data.cipher.plaintext); + if (odata == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + if (odata->max_data_size < data->data_size) { + err(); + ret = -EINVAL; + goto fail; + } + + /* read key */ + ret = _cryptodev_cipher_decrypt(&sess->ctx, data->data, data->data_size, odata->data, data->data_size); + if (ret < 0) { + err(); + goto fail; + } + break; + + case NCR_OP_MAC: + case NCR_OP_DIGEST: + /* obtain data item */ + data = ncr_data_item_get( &lists->data, op.data.digest.text); + if (data == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + ret = _cryptodev_hash_update(&sess->hctx, data->data, data->data_size); + if (ret < 0) { + err(); + goto fail; + } + break; + default: + err(); + ret = -EINVAL; + goto fail; + } + + ret = 0; + +fail: + if (key) _ncr_key_item_put(key); + if (odata) _ncr_data_item_put(odata); + if (data) _ncr_data_item_put(data); + _ncr_sessions_item_put(sess); + + return ret; +} + +static void _ncr_session_deinit(struct list_sem_st* lst, ncr_session_t desc) { struct session_item_st * item, *tmp; @@ -123,3 +407,91 @@ void ncr_session_deinit(struct list_sem_st* lst, ncr_session_t desc) return; } + +int ncr_session_final(struct ncr_lists* lists, void __user* arg) +{ + struct ncr_session_op_st op; + struct key_item_st *key = NULL; + int ret; + struct session_item_st* sess; + struct data_item_st* data = NULL; + struct data_item_st* odata = NULL; + int digest_size; + + copy_from_user( &op, arg, sizeof(op)); + + sess = ncr_sessions_item_get( &lists->sessions, op.ses); + if (sess == NULL) { + err(); + return -EINVAL; + } + + switch(sess->op) { + case NCR_OP_ENCRYPT: + case NCR_OP_DECRYPT: + /* obtain data item */ + if (op.data.cipher.plaintext != NCR_DATA_INVALID && + op.data.cipher.ciphertext != NCR_DATA_INVALID) { + ncr_session_update(lists, arg); + } + cryptodev_cipher_deinit(&sess->ctx); + break; + case NCR_OP_MAC: + case NCR_OP_DIGEST: + /* obtain data item */ + if (op.data.digest.text != NCR_DATA_INVALID) { + ncr_session_update(lists, arg); + } + odata = ncr_data_item_get( &lists->data, op.data.digest.output); + if (odata == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + digest_size = algo_digest_size(sess->algo); + if (digest_size == 0 || odata->data_size < digest_size) { + err(); + ret = -EINVAL; + goto fail; + } + ret = cryptodev_hash_final(&sess->hctx, odata->data); + break; + default: + err(); + ret = -EINVAL; + goto fail; + } + + ret = 0; + +fail: + if (key) _ncr_key_item_put(key); + if (odata) _ncr_data_item_put(odata); + if (data) _ncr_data_item_put(data); + _ncr_sessions_item_put(sess); + _ncr_session_deinit(&lists->sessions, op.ses); + + return ret; +} + +int ncr_session_once(struct ncr_lists* lists, void __user* arg) +{ + struct __user ncr_session_once_op_st* op = arg; + int ret; + + ret = ncr_session_init(lists, &op->init); + if (ret < 0) { + err(); + return ret; + } + + ret = ncr_session_final(lists, &op->op); + if (ret < 0) { + err(); + return ret; + } + + return 0; +} + @@ -95,9 +95,17 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp, 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); + return ncr_key_wrap(&lst->key, &lst->data, (void*)arg); case NCRIO_KEY_UNWRAP: - return ncr_key_unwrap(&lst->key, &lst->data, &lst->sessions, (void*)arg); + return ncr_key_unwrap(&lst->key, &lst->data, (void*)arg); + case NCRIO_SESSION_INIT: + return ncr_session_init(lst, (void*)arg); + case NCRIO_SESSION_UPDATE: + return ncr_session_update(lst, (void*)arg); + case NCRIO_SESSION_FINAL: + return ncr_session_final(lst, (void*)arg); + case NCRIO_SESSION_ONCE: + return ncr_session_once(lst, (void*)arg); #if 0 case NCRIO_KEY_GENERATE_PAIR: return ncr_key_generate_pair(&lst->key, (void*)arg); @@ -5,7 +5,10 @@ #include <inttypes.h> #endif +#define NCR_CIPHER_MAX_BLOCK_LEN 32 +#define NCR_HASH_MAX_OUTPUT_SIZE 64 typedef enum { + NCR_ALG_NONE, NCR_ALG_3DES_CBC=2, NCR_ALG_AES_CBC, NCR_ALG_CAMELLIA_CBC, @@ -31,6 +34,8 @@ typedef enum { NCR_ALG_DSA, } ncr_algorithm_t; + + typedef enum { NCR_WALG_AES_RFC3394, } ncr_wrap_algorithm_t; @@ -48,7 +53,7 @@ typedef enum { #define NCR_DATA_FLAG_SIGN_ONLY 2 /* this object can only be used with hash/sign operations */ typedef int ncr_data_t; -#define NCR_DATA_INVALID (ncr_data_t)(-1) +#define NCR_DATA_INVALID (ncr_data_t)(0) struct ncr_data_init_st { ncr_data_t desc; @@ -75,7 +80,7 @@ struct ncr_data_st { typedef int ncr_key_t; -#define NCR_KEY_INVALID (ncr_key_t)(-1) +#define NCR_KEY_INVALID (ncr_key_t)(0) #define NCR_KEY_FLAG_EXPORTABLE 1 #define NCR_KEY_FLAG_WRAPPABLE (1<<1) @@ -125,7 +130,7 @@ struct ncr_key_params_st { union { struct { - void* iv; + uint8_t iv[NCR_CIPHER_MAX_BLOCK_LEN]; size_t iv_size; } cipher; struct { @@ -288,7 +293,7 @@ typedef enum { } ncr_crypto_op_t; typedef int ncr_session_t; -#define NCR_SESSION_INVALID (ncr_session_t)-1 +#define NCR_SESSION_INVALID (ncr_session_t)0 /* input of CIOCGSESSION */ struct ncr_session_st { diff --git a/ncr_int.h b/ncr_int.h index e96e4980e2f..ec4aac17d26 100644 --- a/ncr_int.h +++ b/ncr_int.h @@ -10,7 +10,10 @@ struct session_item_st { struct list_head list; + ncr_algorithm_t algo; + ncr_crypto_op_t op; struct cipher_data ctx; + struct hash_data hctx; atomic_t refcnt; ncr_session_t desc; @@ -117,15 +120,19 @@ 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); +int ncr_key_wrap(struct list_sem_st* keys, struct list_sem_st* data, void __user* arg); +int ncr_key_unwrap(struct list_sem_st*, struct list_sem_st* data, 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); + +int ncr_session_init(struct ncr_lists* lists, void __user* arg); +int ncr_session_update(struct ncr_lists* lists, void __user* arg); +int ncr_session_final(struct ncr_lists* lists, void __user* arg); +int ncr_session_once(struct ncr_lists* lists, void __user* arg); /* misc helper macros */ inline static unsigned int key_flags_to_data(unsigned int key_flags) |