diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | cryptodev_cipher.c | 8 | ||||
-rw-r--r-- | cryptodev_int.h | 16 | ||||
-rw-r--r-- | cryptodev_main.c | 11 | ||||
-rw-r--r-- | examples/Makefile | 8 | ||||
-rw-r--r-- | examples/ncr-direct.c | 443 | ||||
-rw-r--r-- | examples/ncr.c | 15 | ||||
-rw-r--r-- | examples/pk.c | 30 | ||||
-rw-r--r-- | examples/speed.c | 5 | ||||
-rw-r--r-- | ncr-data.c | 2 | ||||
-rw-r--r-- | ncr-pk.c | 210 | ||||
-rw-r--r-- | ncr-pk.h | 22 | ||||
-rw-r--r-- | ncr-sessions.c | 667 | ||||
-rw-r--r-- | ncr.c | 1 | ||||
-rw-r--r-- | ncr.h | 26 | ||||
-rw-r--r-- | ncr_int.h | 9 |
16 files changed, 1246 insertions, 228 deletions
@@ -10,6 +10,7 @@ modules.order examples/cipher examples/hmac examples/ncr +examples/ncr-direct examples/pk examples/speed releases diff --git a/cryptodev_cipher.c b/cryptodev_cipher.c index fa5aab2..0dd0db7 100644 --- a/cryptodev_cipher.c +++ b/cryptodev_cipher.c @@ -188,24 +188,24 @@ struct scatterlist sg, sg2; } -ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, struct scatterlist *sg1, struct scatterlist *sg2, size_t len) +ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len) { int ret; INIT_COMPLETION(cdata->async.result->completion); - ablkcipher_request_set_crypt(cdata->async.request, sg1, sg2, + ablkcipher_request_set_crypt(cdata->async.request, (struct scatterlist*)sg1, sg2, len, cdata->async.iv); ret = crypto_ablkcipher_encrypt(cdata->async.request); return waitfor(cdata->async.result,ret); } -ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, struct scatterlist *sg1, struct scatterlist *sg2, size_t len) +ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len) { int ret; INIT_COMPLETION(cdata->async.result->completion); - ablkcipher_request_set_crypt(cdata->async.request, sg1, sg2, + ablkcipher_request_set_crypt(cdata->async.request, (struct scatterlist*)sg1, sg2, len, cdata->async.iv); ret = crypto_ablkcipher_decrypt(cdata->async.request); diff --git a/cryptodev_int.h b/cryptodev_int.h index a0d3073..3c6eca4 100644 --- a/cryptodev_int.h +++ b/cryptodev_int.h @@ -24,6 +24,18 @@ extern int cryptodev_verbosity; +/* For zero copy */ +int __get_userbuf(uint8_t *addr, uint32_t len, int write, + int pgcount, struct page **pg, struct scatterlist *sg); +void release_user_pages(struct page **pg, int pagecount); + +/* last page - first page + 1 */ +#define PAGECOUNT(buf, buflen) \ + ((((unsigned long)(buf + buflen - 1) & PAGE_MASK) >> PAGE_SHIFT) - \ + (((unsigned long) buf & PAGE_MASK) >> PAGE_SHIFT) + 1) + +#define DEFAULT_PREALLOC_PAGES 32 + struct cipher_data { int init; /* 0 uninitialized */ @@ -39,8 +51,8 @@ struct cipher_data 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); +ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len); +ssize_t cryptodev_cipher_encrypt( struct cipher_data* cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len); void 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, diff --git a/cryptodev_main.c b/cryptodev_main.c index 0316a74..89b9a02 100644 --- a/cryptodev_main.c +++ b/cryptodev_main.c @@ -65,8 +65,6 @@ module_param(enable_stats, int, 0644); MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage"); #endif -#define DEFAULT_PREALLOC_PAGES 16 - /* ====== CryptoAPI ====== */ struct fcrypt { struct list_head list; @@ -495,7 +493,7 @@ __crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop) #ifndef DISABLE_ZCOPY -static void release_user_pages(struct page **pg, int pagecount) +void release_user_pages(struct page **pg, int pagecount) { while (pagecount--) { if (!PageReserved(pg[pagecount])) @@ -504,16 +502,11 @@ static void release_user_pages(struct page **pg, int pagecount) } } -/* last page - first page + 1 */ -#define PAGECOUNT(buf, buflen) \ - ((((unsigned long)(buf + buflen - 1) & PAGE_MASK) >> PAGE_SHIFT) - \ - (((unsigned long) buf & PAGE_MASK) >> PAGE_SHIFT) + 1) - /* offset of buf in it's first page */ #define PAGEOFFSET(buf) ((unsigned long)buf & ~PAGE_MASK) /* fetch the pages addr resides in into pg and initialise sg with them */ -static int __get_userbuf(uint8_t *addr, uint32_t len, int write, +int __get_userbuf(uint8_t *addr, uint32_t len, int write, int pgcount, struct page **pg, struct scatterlist *sg) { int ret, pglen, i = 0; diff --git a/examples/Makefile b/examples/Makefile index c65297f..f482649 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS = -Wall -g -O2 -progs := cipher hmac ncr pk speed +progs := cipher hmac ncr pk speed ncr-direct all: $(progs) @@ -17,15 +17,19 @@ hmac: hmac.c ncr: ncr.c $(CC) $(CFLAGS) $< -o $@ +ncr-direct: ncr-direct.c + $(CC) $(CFLAGS) $< -o $@ + pk: pk.c $(CC) $(CFLAGS) $< -o $@ -L/usr/local/lib -lgnutls check: $(progs) ./ncr + ./ncr-direct ./pk ./cipher ./hmac ./speed clean: - rm -f *.o *~ hmac cipher ncr pk speed + rm -f *.o *~ hmac cipher ncr pk speed ncr-direct diff --git a/examples/ncr-direct.c b/examples/ncr-direct.c new file mode 100644 index 0000000..0908e2c --- /dev/null +++ b/examples/ncr-direct.c @@ -0,0 +1,443 @@ +/* + * Demo on how to use /dev/crypto device for HMAC. + * + * Placed under public domain. + * + */ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "../ncr.h" +#include <stdlib.h> + +#define DATA_SIZE 4096 +#define KEY_DATA_SIZE 16 + + +struct aes_vectors_st { + const uint8_t* key; + const uint8_t* plaintext; + const uint8_t* ciphertext; +} aes_vectors[] = { + { + .key = (uint8_t*)"\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .plaintext = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .ciphertext = (uint8_t*)"\x4b\xc3\xf8\x83\x45\x0c\x11\x3c\x64\xca\x42\xe1\x11\x2a\x9e\x87", + }, + { + .key = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .plaintext = (uint8_t*)"\xf3\x44\x81\xec\x3c\xc6\x27\xba\xcd\x5d\xc3\xfb\x08\xf2\x73\xe6", + .ciphertext = (uint8_t*)"\x03\x36\x76\x3e\x96\x6d\x92\x59\x5a\x56\x7c\xc9\xce\x53\x7f\x5e", + }, + { + .key = (uint8_t*)"\x10\xa5\x88\x69\xd7\x4b\xe5\xa3\x74\xcf\x86\x7c\xfb\x47\x38\x59", + .plaintext = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .ciphertext = (uint8_t*)"\x6d\x25\x1e\x69\x44\xb0\x51\xe0\x4e\xaa\x6f\xb4\xdb\xf7\x84\x65", + }, + { + .key = (uint8_t*)"\xca\xea\x65\xcd\xbb\x75\xe9\x16\x9e\xcd\x22\xeb\xe6\xe5\x46\x75", + .plaintext = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .ciphertext = (uint8_t*)"\x6e\x29\x20\x11\x90\x15\x2d\xf4\xee\x05\x81\x39\xde\xf6\x10\xbb", + }, + { + .key = (uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe", + .plaintext = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .ciphertext = (uint8_t*)"\x9b\xa4\xa9\x14\x3f\x4e\x5d\x40\x48\x52\x1c\x4f\x88\x77\xd8\x8e", + }, +}; + +/* AES cipher */ +static int +test_ncr_aes(int cfd) +{ + struct ncr_data_init_st dinit; + ncr_key_t key; + struct ncr_key_data_st keydata; + struct ncr_data_st kdata; + ncr_data_t dd, dd2; + uint8_t data[KEY_DATA_SIZE]; + int i, j; + struct ncr_session_once_op_st nop; + + dinit.max_object_size = KEY_DATA_SIZE; + dinit.flags = NCR_DATA_FLAG_EXPORTABLE; + dinit.initial_data = NULL; + dinit.initial_data_size = 0; + + if (ioctl(cfd, NCRIO_DATA_INIT, &dinit)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_DATA_INIT)"); + return 1; + } + + dd = dinit.desc; + + if (ioctl(cfd, NCRIO_DATA_INIT, &dinit)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_DATA_INIT)"); + return 1; + } + + dd2 = dinit.desc; + + /* convert it to key */ + if (ioctl(cfd, NCRIO_KEY_INIT, &key)) { + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + keydata.key_id[0] = 'a'; + keydata.key_id[2] = 'b'; + keydata.key_id_size = 2; + keydata.type = NCR_KEY_TYPE_SECRET; + keydata.algorithm = NCR_ALG_AES_CBC; + keydata.flags = NCR_KEY_FLAG_EXPORTABLE; + + + fprintf(stdout, "Tests on AES Encryption\n"); + for (i=0;i<sizeof(aes_vectors)/sizeof(aes_vectors[0]);i++) { + + /* import key */ + kdata.data = (void*)aes_vectors[i].key; + kdata.data_size = 16; + kdata.desc = dd; + + if (ioctl(cfd, NCRIO_DATA_SET, &kdata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_DATA_SET)"); + return 1; + } + + keydata.key = key; + keydata.data = dd; + if (ioctl(cfd, NCRIO_KEY_IMPORT, &keydata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_IMPORT)"); + return 1; + } + + /* encrypt */ + memset(&nop, 0, sizeof(nop)); + nop.init.algorithm = NCR_ALG_AES_ECB; + nop.init.key = key; + nop.init.op = NCR_OP_ENCRYPT; + nop.op.data.udata.input = (void*)aes_vectors[i].plaintext; + nop.op.data.udata.input_size = 16; + nop.op.data.udata.output = data; + nop.op.data.udata.output_size = sizeof(data); + nop.op.type = NCR_DIRECT_DATA; + + if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_SESSION_ONCE)"); + return 1; + } + + /* verify */ + + if (nop.op.data.udata.output_size != 16 || memcmp(data, aes_vectors[i].ciphertext, 16) != 0) { + fprintf(stderr, "AES test vector %d failed!\n", i); + + fprintf(stderr, "Cipher[%d]: ", (int)nop.op.data.udata.output_size); + for(j=0;j<nop.op.data.udata.output_size;j++) + fprintf(stderr, "%.2x:", (int)data[j]); + fprintf(stderr, "\n"); + + fprintf(stderr, "Expected[%d]: ", 16); + for(j=0;j<16;j++) + fprintf(stderr, "%.2x:", (int)aes_vectors[i].ciphertext[j]); + fprintf(stderr, "\n"); + return 1; + } + } + + fprintf(stdout, "Tests on AES Decryption\n"); + for (i=0;i<sizeof(aes_vectors)/sizeof(aes_vectors[0]);i++) { + + /* import key */ + kdata.data = (void*)aes_vectors[i].key; + kdata.data_size = 16; + kdata.desc = dd; + + if (ioctl(cfd, NCRIO_DATA_SET, &kdata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_DATA_SET)"); + return 1; + } + + keydata.key = key; + keydata.data = dd; + if (ioctl(cfd, NCRIO_KEY_IMPORT, &keydata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_IMPORT)"); + return 1; + } + + + /* decrypt */ + memset(&nop, 0, sizeof(nop)); + nop.init.algorithm = NCR_ALG_AES_ECB; + nop.init.key = key; + nop.init.op = NCR_OP_DECRYPT; + nop.op.data.udata.input = (void*)aes_vectors[i].ciphertext; + nop.op.data.udata.input_size = 16; + nop.op.data.udata.output = data; + nop.op.data.udata.output_size = sizeof(data); + nop.op.type = NCR_DIRECT_DATA; + + if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_SESSION_ONCE)"); + return 1; + } + + if (nop.op.data.udata.output_size != 16 || memcmp(data, aes_vectors[i].plaintext, 16) != 0) { + fprintf(stderr, "AES test vector %d failed!\n", i); + + fprintf(stderr, "Plain[%d]: ", (int)nop.op.data.udata.output_size); + for(j=0;j<nop.op.data.udata.output_size;j++) + fprintf(stderr, "%.2x:", (int)data[j]); + fprintf(stderr, "\n"); + + fprintf(stderr, "Expected[%d]: ", 16); + for(j=0;j<16;j++) + fprintf(stderr, "%.2x:", (int)aes_vectors[i].plaintext[j]); + fprintf(stderr, "\n"); + return 1; + } + } + + + fprintf(stdout, "\n"); + + return 0; + +} + +struct hash_vectors_st { + const char* name; + ncr_algorithm_t algorithm; + const uint8_t* key; /* if hmac */ + int key_size; + const uint8_t* plaintext; + int plaintext_size; + const uint8_t* output; + int output_size; + ncr_crypto_op_t op; +} hash_vectors[] = { + { + .name = "SHA1", + .algorithm = NCR_ALG_SHA1, + .key = NULL, + .plaintext = (uint8_t*)"what do ya want for nothing?", + .plaintext_size = sizeof("what do ya want for nothing?")-1, + .output = (uint8_t*)"\x8f\x82\x03\x94\xf9\x53\x35\x18\x20\x45\xda\x24\xf3\x4d\xe5\x2b\xf8\xbc\x34\x32", + .output_size = 20, + .op = NCR_OP_SIGN, + }, + { + .name = "HMAC-MD5", + .algorithm = NCR_ALG_HMAC_MD5, + .key = (uint8_t*)"Jefe", + .key_size = 4, + .plaintext = (uint8_t*)"what do ya want for nothing?", + .plaintext_size = sizeof("what do ya want for nothing?")-1, + .output = (uint8_t*)"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38", + .output_size = 16, + .op = NCR_OP_SIGN, + }, + /* from rfc4231 */ + { + .name = "HMAC-SHA224", + .algorithm = NCR_ALG_HMAC_SHA2_224, + .key = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + .key_size = 20, + .plaintext = (uint8_t*)"Hi There", + .plaintext_size = sizeof("Hi There")-1, + .output = (uint8_t*)"\x89\x6f\xb1\x12\x8a\xbb\xdf\x19\x68\x32\x10\x7c\xd4\x9d\xf3\x3f\x47\xb4\xb1\x16\x99\x12\xba\x4f\x53\x68\x4b\x22", + .output_size = 28, + .op = NCR_OP_SIGN, + }, + { + .name = "HMAC-SHA256", + .algorithm = NCR_ALG_HMAC_SHA2_256, + .key = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + .key_size = 20, + .plaintext = (uint8_t*)"Hi There", + .plaintext_size = sizeof("Hi There")-1, + .output = (uint8_t*)"\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7", + .output_size = 32, + .op = NCR_OP_SIGN, + }, + { + .name = "HMAC-SHA384", + .algorithm = NCR_ALG_HMAC_SHA2_384, + .key = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + .key_size = 20, + .plaintext = (uint8_t*)"Hi There", + .plaintext_size = sizeof("Hi There")-1, + .output = (uint8_t*)"\xaf\xd0\x39\x44\xd8\x48\x95\x62\x6b\x08\x25\xf4\xab\x46\x90\x7f\x15\xf9\xda\xdb\xe4\x10\x1e\xc6\x82\xaa\x03\x4c\x7c\xeb\xc5\x9c\xfa\xea\x9e\xa9\x07\x6e\xde\x7f\x4a\xf1\x52\xe8\xb2\xfa\x9c\xb6", + .output_size = 48, + .op = NCR_OP_SIGN, + }, + { + .name = "HMAC-SHA512", + .algorithm = NCR_ALG_HMAC_SHA2_512, + .key = (uint8_t*)"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + .key_size = 20, + .plaintext = (uint8_t*)"Hi There", + .plaintext_size = sizeof("Hi There")-1, + .output = (uint8_t*)"\x87\xaa\x7c\xde\xa5\xef\x61\x9d\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0\x23\x79\xf4\xe2\xce\x4e\xc2\x78\x7a\xd0\xb3\x05\x45\xe1\x7c\xde\xda\xa8\x33\xb7\xd6\xb8\xa7\x02\x03\x8b\x27\x4e\xae\xa3\xf4\xe4\xbe\x9d\x91\x4e\xeb\x61\xf1\x70\x2e\x69\x6c\x20\x3a\x12\x68\x54", + .output_size = 64, + .op = NCR_OP_SIGN, + }, +}; + +#define HASH_DATA_SIZE 64 + +/* SHA1 and other hashes */ +static int +test_ncr_hash(int cfd) +{ + struct ncr_data_init_st dinit; + ncr_key_t key; + struct ncr_key_data_st keydata; + struct ncr_data_st kdata; + ncr_data_t dd, dd2; + uint8_t data[HASH_DATA_SIZE]; + int i, j; + struct ncr_session_once_op_st nop; + + dinit.max_object_size = HASH_DATA_SIZE; + dinit.flags = NCR_DATA_FLAG_EXPORTABLE; + dinit.initial_data = NULL; + dinit.initial_data_size = 0; + + if (ioctl(cfd, NCRIO_DATA_INIT, &dinit)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_DATA_INIT)"); + return 1; + } + + dd = dinit.desc; + + if (ioctl(cfd, NCRIO_DATA_INIT, &dinit)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_DATA_INIT)"); + return 1; + } + + dd2 = dinit.desc; + + /* convert it to key */ + if (ioctl(cfd, NCRIO_KEY_INIT, &key)) { + perror("ioctl(NCRIO_KEY_INIT)"); + return 1; + } + + keydata.key_id[0] = 'a'; + keydata.key_id[2] = 'b'; + keydata.key_id_size = 2; + keydata.type = NCR_KEY_TYPE_SECRET; + keydata.algorithm = NCR_ALG_AES_CBC; + keydata.flags = NCR_KEY_FLAG_EXPORTABLE; + + + fprintf(stdout, "Tests on Hashes\n"); + for (i=0;i<sizeof(hash_vectors)/sizeof(hash_vectors[0]);i++) { + + fprintf(stdout, "\t%s:\n", hash_vectors[i].name); + /* import key */ + if (hash_vectors[i].key != NULL) { + kdata.data = (void*)hash_vectors[i].key; + kdata.data_size = hash_vectors[i].key_size; + kdata.desc = dd; + + if (ioctl(cfd, NCRIO_DATA_SET, &kdata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_DATA_SET)"); + return 1; + } + + keydata.key = key; + keydata.data = dd; + if (ioctl(cfd, NCRIO_KEY_IMPORT, &keydata)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_KEY_IMPORT)"); + return 1; + } + } + + /* encrypt */ + memset(&nop, 0, sizeof(nop)); + nop.init.algorithm = hash_vectors[i].algorithm; + if (hash_vectors[i].key != NULL) + nop.init.key = key; + nop.init.op = hash_vectors[i].op; + nop.op.data.udata.input = (void*)hash_vectors[i].plaintext; + nop.op.data.udata.input_size = hash_vectors[i].plaintext_size; + nop.op.data.udata.output = data; + nop.op.data.udata.output_size = sizeof(data); + nop.op.type = NCR_DIRECT_DATA; + + if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { + fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); + perror("ioctl(NCRIO_SESSION_ONCE)"); + return 1; + } + + if (nop.op.data.udata.output_size != hash_vectors[i].output_size || + memcmp(data, hash_vectors[i].output, hash_vectors[i].output_size) != 0) { + fprintf(stderr, "HASH test vector %d failed!\n", i); + + fprintf(stderr, "Output[%d]: ", (int)nop.op.data.udata.output_size); + for(j=0;j<nop.op.data.udata.output_size;j++) + fprintf(stderr, "%.2x:", (int)data[j]); + fprintf(stderr, "\n"); + + fprintf(stderr, "Expected[%d]: ", hash_vectors[i].output_size); + for(j=0;j<hash_vectors[i].output_size;j++) + fprintf(stderr, "%.2x:", (int)hash_vectors[i].output[j]); + fprintf(stderr, "\n"); + return 1; + } + } + + fprintf(stdout, "\n"); + + return 0; + +} + + +int +main() +{ + int fd = -1; + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + if (test_ncr_aes(fd)) + return 1; + + if (test_ncr_hash(fd)) + return 1; + + /* Close the original descriptor */ + if (close(fd)) { + perror("close(fd)"); + return 1; + } + + return 0; +} diff --git a/examples/ncr.c b/examples/ncr.c index d9870e0..bd5779c 100644 --- a/examples/ncr.c +++ b/examples/ncr.c @@ -809,8 +809,9 @@ test_ncr_aes(int cfd) nop.init.algorithm = NCR_ALG_AES_ECB; nop.init.key = key; nop.init.op = NCR_OP_ENCRYPT; - nop.op.input = dd; - nop.op.output = dd2; + nop.op.data.ndata.input = dd; + nop.op.data.ndata.output = dd2; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); @@ -884,8 +885,9 @@ test_ncr_aes(int cfd) nop.init.algorithm = NCR_ALG_AES_ECB; nop.init.key = key; nop.init.op = NCR_OP_DECRYPT; - nop.op.input = dd; - nop.op.output = dd2; + nop.op.data.ndata.input = dd; + nop.op.data.ndata.output = dd2; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); @@ -1098,8 +1100,9 @@ test_ncr_hash(int cfd) if (hash_vectors[i].key != NULL) nop.init.key = key; nop.init.op = hash_vectors[i].op; - nop.op.input = dd; - nop.op.output = dd2; + nop.op.data.ndata.input = dd; + nop.op.data.ndata.output = dd2; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); diff --git a/examples/pk.c b/examples/pk.c index ce9dff8..287e9f3 100644 --- a/examples/pk.c +++ b/examples/pk.c @@ -371,8 +371,9 @@ static int rsa_key_encrypt(int cfd, ncr_key_t privkey, ncr_key_t pubkey, int oae nop.init.params.params.rsa.type = RSA_PKCS1_V1_5; } nop.init.op = NCR_OP_ENCRYPT; - nop.op.input = datad; - nop.op.output = encd; + nop.op.data.ndata.input = datad; + nop.op.data.ndata.output = encd; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); @@ -391,8 +392,9 @@ static int rsa_key_encrypt(int cfd, ncr_key_t privkey, ncr_key_t pubkey, int oae } else { nop.init.params.params.rsa.type = RSA_PKCS1_V1_5; } - nop.op.input = encd; - nop.op.output = encd; + nop.op.data.ndata.input = encd; + nop.op.data.ndata.output = encd; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); @@ -466,8 +468,9 @@ static int rsa_key_sign_verify(int cfd, ncr_key_t privkey, ncr_key_t pubkey, int nop.init.params.params.rsa.sign_hash = NCR_ALG_SHA1; nop.init.op = NCR_OP_SIGN; - nop.op.input = datad; - nop.op.output = signd; + nop.op.data.ndata.input = datad; + nop.op.data.ndata.output = signd; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); @@ -483,8 +486,9 @@ static int rsa_key_sign_verify(int cfd, ncr_key_t privkey, ncr_key_t pubkey, int nop.init.params.params.rsa.sign_hash = NCR_ALG_SHA1; nop.init.op = NCR_OP_VERIFY; - nop.op.input = datad; - nop.op.output = signd; + nop.op.data.ndata.input = datad; + nop.op.data.ndata.output = signd; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); @@ -545,8 +549,9 @@ static int dsa_key_sign_verify(int cfd, ncr_key_t privkey, ncr_key_t pubkey) nop.init.params.params.dsa.sign_hash = NCR_ALG_SHA1; nop.init.op = NCR_OP_SIGN; - nop.op.input = datad; - nop.op.output = signd; + nop.op.data.ndata.input = datad; + nop.op.data.ndata.output = signd; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); @@ -561,8 +566,9 @@ static int dsa_key_sign_verify(int cfd, ncr_key_t privkey, ncr_key_t pubkey) nop.init.params.params.dsa.sign_hash = NCR_ALG_SHA1; nop.init.op = NCR_OP_VERIFY; - nop.op.input = datad; - nop.op.output = signd; + nop.op.data.ndata.input = datad; + nop.op.data.ndata.output = signd; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); diff --git a/examples/speed.c b/examples/speed.c index d3cf04a..1416411 100644 --- a/examples/speed.c +++ b/examples/speed.c @@ -189,8 +189,9 @@ int encrypt_data_ncr(int cfd, int algo, int chunksize) nop.init.algorithm = algo; nop.init.key = key; nop.init.op = NCR_OP_ENCRYPT; - nop.op.input = dd; - nop.op.output = dd; + nop.op.data.ndata.input = dd; + nop.op.data.ndata.output = dd; + nop.op.type = NCR_DATA; if (ioctl(cfd, NCRIO_SESSION_ONCE, &nop)) { fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); @@ -146,6 +146,8 @@ int ncr_data_init(struct list_sem_st* lst, void __user* arg) goto err_data; } data->max_data_size = init.max_object_size; + + sg_init_one(&data->sg, data->data, data->max_data_size); if (init.initial_data != NULL) { if (unlikely(copy_from_user(data->data, init.initial_data, @@ -377,129 +377,230 @@ int ncr_pk_cipher_init(const struct algo_properties_st *algo, } int ncr_pk_cipher_encrypt(const struct ncr_pk_ctx* ctx, - const void* input, size_t input_size, - void* output, size_t *output_size) + const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size, + struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size) { -int cret; -unsigned long osize = *output_size; +int cret, ret; +unsigned long osize = *osg_size; +uint8_t* tmp; +void * input, *output; + + tmp = kmalloc(isg_size + *osg_size, GFP_KERNEL); + if (tmp == NULL) { + err(); + return -ENOMEM; + } + + ret = sg_copy_to_buffer((struct scatterlist*)isg, isg_cnt, tmp, isg_size); + if (ret != isg_size) { + err(); + ret = -EINVAL; + goto fail; + } + + input = tmp; + output = &tmp[isg_size]; + switch(ctx->algorithm->algo) { case NCR_ALG_RSA: - cret = rsa_encrypt_key_ex( input, input_size, output, &osize, + cret = rsa_encrypt_key_ex( input, isg_size, output, &osize, NULL, 0, ctx->oaep_hash, ctx->type, &ctx->key->key.pk.rsa); if (cret != CRYPT_OK) { - printk("cret: %d type: %d\n", cret, ctx->type); err(); - return tomerr(cret); + ret = tomerr(cret); + goto fail; } - *output_size = osize; + *osg_size = osize; + break; case NCR_ALG_DSA: - return -EINVAL; - break; + ret = -EINVAL; + goto fail; default: err(); - return -EINVAL; + ret = -EINVAL; + goto fail; } - - return 0; + + ret = sg_copy_from_buffer(osg, osg_cnt, output, *osg_size); + if (ret != *osg_size) { + err(); + ret = -EINVAL; + goto fail; + } + + ret = 0; + +fail: + kfree(tmp); + return ret; } -int ncr_pk_cipher_decrypt(const struct ncr_pk_ctx* ctx, const void* input, size_t input_size, - void* output, size_t *output_size) +int ncr_pk_cipher_decrypt(const struct ncr_pk_ctx* ctx, + const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size, + struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size) { -int cret; -unsigned long osize = *output_size; +int cret, ret; int stat; +unsigned long osize = *osg_size; +uint8_t* tmp; +void * input, *output; + + tmp = kmalloc(isg_size + *osg_size, GFP_KERNEL); + if (tmp == NULL) { + err(); + return -ENOMEM; + } + + input = tmp; + output = &tmp[isg_size]; + + ret = sg_copy_to_buffer((struct scatterlist*)isg, isg_cnt, input, isg_size); + if (ret != isg_size) { + err(); + ret = -EINVAL; + goto fail; + } switch(ctx->algorithm->algo) { case NCR_ALG_RSA: - cret = rsa_decrypt_key_ex( input, input_size, output, &osize, + cret = rsa_decrypt_key_ex( input, isg_size, output, &osize, NULL, 0, ctx->oaep_hash, ctx->type, &stat, &ctx->key->key.pk.rsa); if (cret != CRYPT_OK) { err(); - return tomerr(cret); + ret = tomerr(cret); + goto fail; } if (stat==0) { err(); - return -EINVAL; + ret = -EINVAL; + goto fail; } - *output_size = osize; + *osg_size = osize; break; case NCR_ALG_DSA: - return -EINVAL; - break; + ret = -EINVAL; + goto fail; default: err(); - return -EINVAL; + ret = -EINVAL; + goto fail; } + + ret = sg_copy_from_buffer(osg, osg_cnt, output, *osg_size); + if (ret != *osg_size) { + err(); + ret = -EINVAL; + goto fail; + } + + ret = 0; +fail: + kfree(tmp); - return 0; + return ret; } int ncr_pk_cipher_sign(const struct ncr_pk_ctx* ctx, - const void* input, size_t input_size, - void* output, size_t *output_size) + const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size, + struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size) { -int cret; -unsigned long osize = *output_size; +int cret, ret; +unsigned long osize = *osg_size; +uint8_t* tmp; +void * input, *output; + + tmp = kmalloc(isg_size + *osg_size, GFP_KERNEL); + if (tmp == NULL) { + err(); + return -ENOMEM; + } + + input = tmp; + output = &tmp[isg_size]; + + ret = sg_copy_to_buffer((struct scatterlist*)isg, isg_cnt, input, isg_size); + if (ret != isg_size) { + err(); + ret = -EINVAL; + goto fail; + } switch(ctx->algorithm->algo) { case NCR_ALG_RSA: - if (ctx->sign_hash == NULL) { - err(); - return -EINVAL; - } - cret = rsa_sign_hash_ex( input, input_size, output, &osize, + cret = rsa_sign_hash_ex( input, isg_size, output, &osize, ctx->type, ctx->sign_hash, ctx->salt_len, &ctx->key->key.pk.rsa); if (cret != CRYPT_OK) { err(); return tomerr(cret); } - *output_size = osize; + *osg_size = osize; break; case NCR_ALG_DSA: - cret = dsa_sign_hash( input, input_size, output, &osize, + cret = dsa_sign_hash( input, isg_size, output, &osize, &ctx->key->key.pk.dsa); if (cret != CRYPT_OK) { err(); return tomerr(cret); } - *output_size = osize; + *osg_size = osize; break; default: err(); - return -EINVAL; + ret = -EINVAL; + goto fail; + } + + ret = sg_copy_from_buffer(osg, osg_cnt, output, *osg_size); + if (ret != *osg_size) { + err(); + ret = -EINVAL; + goto fail; } + ret = 0; +fail: + kfree(tmp); - return 0; + return ret; } int ncr_pk_cipher_verify(const struct ncr_pk_ctx* ctx, - const void* signature, size_t signature_size, + 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 cret; +int cret, ret; int stat; +uint8_t* sig; + + sig = kmalloc(sign_sg_size, GFP_KERNEL); + if (sig == NULL) { + err(); + return -ENOMEM; + } + + ret = sg_copy_to_buffer((struct scatterlist*)sign_sg, sign_sg_cnt, sig, sign_sg_size); + if (ret != sign_sg_size) { + err(); + ret = -EINVAL; + goto fail; + } switch(ctx->algorithm->algo) { case NCR_ALG_RSA: - if (ctx->sign_hash == NULL) { - err(); - return -EINVAL; - } - cret = rsa_verify_hash_ex( signature, signature_size, + cret = rsa_verify_hash_ex( sig, sign_sg_size, hash, hash_size, ctx->type, ctx->sign_hash, ctx->salt_len, &stat, &ctx->key->key.pk.rsa); if (cret != CRYPT_OK) { err(); - return tomerr(cret); + ret = tomerr(cret); + goto fail; } if (stat == 1) @@ -509,11 +610,12 @@ int stat; break; case NCR_ALG_DSA: - cret = dsa_verify_hash( signature, signature_size, + cret = dsa_verify_hash( sig, sign_sg_size, hash, hash_size, &stat, &ctx->key->key.pk.dsa); if (cret != CRYPT_OK) { err(); - return tomerr(cret); + ret = tomerr(cret); + goto fail; } if (stat == 1) @@ -524,8 +626,12 @@ int stat; break; default: err(); - return -EINVAL; + ret = -EINVAL; + goto fail; } - - return 0; + + ret = 0; +fail: + kfree(sig); + return ret; } @@ -34,15 +34,21 @@ int ncr_pk_cipher_init(const struct algo_properties_st *algo, struct ncr_pk_ctx* ctx, struct ncr_key_params_st* params, struct key_item_st *key, const struct algo_properties_st *sign_hash); void ncr_pk_cipher_deinit(struct ncr_pk_ctx* ctx); -int ncr_pk_cipher_encrypt(const struct ncr_pk_ctx* ctx, const void* input, - size_t input_size, void* output, size_t *output_size); -int ncr_pk_cipher_decrypt(const struct ncr_pk_ctx* ctx, const void* input, - size_t input_size, void* output, size_t *output_size); -int ncr_pk_cipher_sign(const struct ncr_pk_ctx* ctx, const void* input, - size_t input_size, void* output, size_t *output_size); +int ncr_pk_cipher_encrypt(const struct ncr_pk_ctx* ctx, + const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size, + struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size); + +int ncr_pk_cipher_decrypt(const struct ncr_pk_ctx* ctx, + const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size, + struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size); + +int ncr_pk_cipher_sign(const struct ncr_pk_ctx* ctx, + const struct scatterlist* isg, unsigned int isg_cnt, size_t isg_size, + struct scatterlist *osg, unsigned int osg_cnt, size_t* osg_size); + int ncr_pk_cipher_verify(const struct ncr_pk_ctx* ctx, - const void* signature, size_t signature_size, - const void* hash, size_t hash_size, ncr_error_t*); + 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); #endif diff --git a/ncr-sessions.c b/ncr-sessions.c index b8eabdd..fb9fe4f 100644 --- a/ncr-sessions.c +++ b/ncr-sessions.c @@ -23,6 +23,8 @@ #include "cryptodev.h" #include "ncr.h" #include "ncr_int.h" +#include <linux/mm_types.h> +#include <linux/scatterlist.h> static void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc); @@ -84,6 +86,8 @@ void _ncr_sessions_item_put( struct session_item_st* item) cryptodev_hash_deinit(&item->hash); if (item->key) _ncr_key_item_put(item->key); + kfree(item->sg); + kfree(item->pages); kfree(item); } } @@ -92,13 +96,25 @@ struct session_item_st* ncr_session_new(struct list_sem_st* lst) { struct session_item_st* sess; - sess = kmalloc(sizeof(*sess), GFP_KERNEL); + sess = kzalloc(sizeof(*sess), GFP_KERNEL); if (sess == NULL) { err(); return NULL; } - memset(sess, 0, sizeof(*sess)); + sess->array_size = DEFAULT_PREALLOC_PAGES; + sess->pages = kzalloc(sess->array_size * + sizeof(struct page *), GFP_KERNEL); + sess->sg = kzalloc(sess->array_size * + sizeof(struct scatterlist), GFP_KERNEL); + if (sess->sg == NULL || sess->pages == NULL) { + err(); + kfree(sess->sg); + kfree(sess->pages); + kfree(sess); + return NULL; + } + init_MUTEX(&sess->mem_mutex); atomic_set(&sess->refcnt, 1); @@ -216,6 +232,7 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses ret = -EINVAL; goto fail; } + switch(session->op) { case NCR_OP_ENCRYPT: case NCR_OP_DECRYPT: @@ -395,6 +412,63 @@ int ncr_session_init(struct ncr_lists* lists, void __user* arg) return ret; } +int _ncr_session_encrypt(struct session_item_st* sess, const struct scatterlist* input, unsigned input_cnt, + size_t input_size, void *output, unsigned output_cnt, size_t *output_size) +{ +int ret; + + if (sess->algorithm->is_symmetric) { + /* read key */ + ret = cryptodev_cipher_encrypt(&sess->cipher, input, + output, input_size); + if (ret < 0) { + err(); + return ret; + } + /* FIXME: handle ciphers that do not require that */ + + } else { /* public key */ + ret = ncr_pk_cipher_encrypt(&sess->pk, input, input_cnt, input_size, + output, output_cnt, output_size); + + if (ret < 0) { + err(); + return ret; + } + } + + return 0; +} + +int _ncr_session_decrypt(struct session_item_st* sess, const struct scatterlist* input, + unsigned input_cnt, size_t input_size, + struct scatterlist *output, unsigned output_cnt, size_t *output_size) +{ +int ret; + + if (sess->algorithm->is_symmetric) { + /* read key */ + ret = cryptodev_cipher_decrypt(&sess->cipher, input, + output, input_size); + if (ret < 0) { + err(); + return ret; + } + /* FIXME: handle ciphers that do not require equality */ + + } else { /* public key */ + ret = ncr_pk_cipher_decrypt(&sess->pk, input, input_cnt, input_size, + output, output_cnt, output_size); + + if (ret < 0) { + err(); + return ret; + } + } + + return 0; +} + /* Main update function */ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op) @@ -403,6 +477,7 @@ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st struct session_item_st* sess; struct data_item_st* data = NULL; struct data_item_st* odata = NULL; + size_t new_size; sess = ncr_sessions_item_get( &lists->sessions, op->ses); if (sess == NULL) { @@ -410,17 +485,17 @@ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st return -EINVAL; } + /* obtain data item */ + data = ncr_data_item_get( &lists->data, op->data.ndata.input); + if (data == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + switch(sess->op) { case NCR_OP_ENCRYPT: - /* obtain data item */ - data = ncr_data_item_get( &lists->data, op->input); - if (data == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - odata = ncr_data_item_get( &lists->data, op->output); + odata = ncr_data_item_get( &lists->data, op->data.ndata.output); if (odata == NULL) { err(); ret = -EINVAL; @@ -433,39 +508,16 @@ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st goto fail; } - if (sess->algorithm->is_symmetric) { - /* read key */ - ret = _cryptodev_cipher_encrypt(&sess->cipher, data->data, - data->data_size, odata->data, data->data_size); - if (ret < 0) { - err(); - goto fail; - } - /* FIXME: handle ciphers that do not require that */ - odata->data_size = data->data_size; - } else { /* public key */ - size_t new_size = odata->max_data_size; - ret = ncr_pk_cipher_encrypt(&sess->pk, data->data, data->data_size, - odata->data, &new_size); - - odata->data_size = new_size; - - if (ret < 0) { - err(); - goto fail; - } - } - break; - case NCR_OP_DECRYPT: - /* obtain data item */ - data = ncr_data_item_get( &lists->data, op->input); - if (data == NULL) { + odata->data_size = odata->max_data_size; + ret = _ncr_session_encrypt(sess, &data->sg, 1, data->data_size, + &odata->sg, 1, &odata->data_size); + if (ret < 0) { err(); - ret = -EINVAL; goto fail; } - - odata = ncr_data_item_get( &lists->data, op->output); + break; + case NCR_OP_DECRYPT: + odata = ncr_data_item_get( &lists->data, op->data.ndata.output); if (odata == NULL) { err(); ret = -EINVAL; @@ -477,63 +529,26 @@ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st ret = -EINVAL; goto fail; } - - /* read key */ - if (sess->algorithm->is_symmetric) { - ret = _cryptodev_cipher_decrypt(&sess->cipher, data->data, data->data_size, odata->data, data->data_size); - if (ret < 0) { - err(); - goto fail; - } - /* FIXME: handle ciphers that do not require that */ - odata->data_size = data->data_size; - } else { /* public key */ - size_t new_size = odata->max_data_size; - ret = ncr_pk_cipher_decrypt(&sess->pk, data->data, data->data_size, - odata->data, &new_size); - - odata->data_size = new_size; - - if (ret < 0) { - err(); - goto fail; - } - } - - break; - - case NCR_OP_SIGN: - /* obtain data item */ - data = ncr_data_item_get( &lists->data, op->input); - if (data == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - ret = _cryptodev_hash_update(&sess->hash, data->data, data->data_size); + new_size = odata->max_data_size; + ret = _ncr_session_decrypt(sess, &data->sg, 1, data->data_size, + &odata->sg, 1, &new_size); if (ret < 0) { err(); goto fail; } + odata->data_size = new_size; + break; + case NCR_OP_SIGN: case NCR_OP_VERIFY: - /* obtain data item */ - data = ncr_data_item_get( &lists->data, op->input); - if (data == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - ret = _cryptodev_hash_update(&sess->hash, data->data, data->data_size); + ret = cryptodev_hash_update(&sess->hash, &data->sg, data->data_size); if (ret < 0) { err(); goto fail; } break; - default: err(); ret = -EINVAL; @@ -550,16 +565,117 @@ fail: return ret; } -int ncr_session_update(struct ncr_lists* lists, void __user* arg) +/* Only the output buffer is given as scatterlist */ +static int get_userbuf1(struct session_item_st* ses, + struct ncr_session_op_st* op, struct scatterlist **dst_sg, unsigned *dst_cnt) { - struct ncr_session_op_st op; + int pagecount = 0; - if (unlikely(copy_from_user( &op, arg, sizeof(op)))) { - err(); - return -EFAULT; + if (op->data.udata.output == NULL) { + return -EINVAL; } - - return _ncr_session_update(lists, &op); + + pagecount = PAGECOUNT(op->data.udata.output, op->data.udata.output_size); + + + ses->available_pages = pagecount; + + if (pagecount > ses->array_size) { + while (ses->array_size < pagecount) + ses->array_size *= 2; + + dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n", + __func__, ses->array_size); + ses->pages = krealloc(ses->pages, ses->array_size * + sizeof(struct page *), GFP_KERNEL); + ses->sg = krealloc(ses->sg, ses->array_size * + sizeof(struct scatterlist), GFP_KERNEL); + + if (ses->sg == NULL || ses->pages == NULL) { + return -ENOMEM; + } + } + + if (__get_userbuf(op->data.udata.output, op->data.udata.output_size, 1, + pagecount, ses->pages, ses->sg)) { + dprintk(1, KERN_ERR, "failed to get user pages for data input\n"); + return -EINVAL; + } + (*dst_sg) = ses->sg; + *dst_cnt = pagecount; + + return 0; +} + +/* make op->data.udata.input and op->data.udata.output available in scatterlists */ +static int get_userbuf2(struct session_item_st* ses, + struct ncr_session_op_st* op, struct scatterlist **src_sg, + unsigned *src_cnt, struct scatterlist **dst_sg, unsigned *dst_cnt) +{ + int src_pagecount, dst_pagecount = 0, pagecount, write_src = 1; + + if (op->data.udata.input == NULL) { + return -EINVAL; + } + + src_pagecount = PAGECOUNT(op->data.udata.input, op->data.udata.input_size); + + if (op->data.udata.input != op->data.udata.output) { /* non-in-situ transformation */ + if (op->data.udata.output != NULL) { + dst_pagecount = PAGECOUNT(op->data.udata.output, op->data.udata.output_size); + write_src = 0; + } else { + dst_pagecount = 0; + } + } + + ses->available_pages = pagecount = src_pagecount + dst_pagecount; + + if (pagecount > ses->array_size) { + while (ses->array_size < pagecount) + ses->array_size *= 2; + + dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n", + __func__, ses->array_size); + ses->pages = krealloc(ses->pages, ses->array_size * + sizeof(struct page *), GFP_KERNEL); + ses->sg = krealloc(ses->sg, ses->array_size * + sizeof(struct scatterlist), GFP_KERNEL); + + if (ses->sg == NULL || ses->pages == NULL) { + return -ENOMEM; + } + } + + if (__get_userbuf(op->data.udata.input, op->data.udata.input_size, write_src, + src_pagecount, ses->pages, ses->sg)) { + dprintk(1, KERN_ERR, "failed to get user pages for data input\n"); + return -EINVAL; + } + (*src_sg) = ses->sg; + *src_cnt = src_pagecount; + + if (dst_pagecount) { + *dst_cnt = dst_pagecount; + (*dst_sg) = ses->sg + src_pagecount; + + if (__get_userbuf(op->data.udata.output, op->data.udata.output_size, 1, dst_pagecount, + ses->pages + src_pagecount, *dst_sg)) { + dprintk(1, KERN_ERR, "failed to get user pages for data output\n"); + release_user_pages(ses->pages, src_pagecount); + return -EINVAL; + } + } else { + if (op->data.udata.output != NULL) { + *dst_cnt = src_pagecount; + (*dst_sg) = (*src_sg); + } else { + *dst_cnt = 0; + *dst_sg = NULL; + } + } + + return 0; } static void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc) @@ -581,6 +697,15 @@ static void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc) return; } +static int try_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op) +{ + if (op->data.ndata.input != NCR_DATA_INVALID) { + return _ncr_session_update(lists, op); + } + + return 0; +} + static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* op) { int ret; @@ -595,33 +720,260 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* return -EINVAL; } + ret = try_session_update(lists, op); + if (ret < 0) { + err(); + goto fail; + } + switch(sess->op) { case NCR_OP_ENCRYPT: case NCR_OP_DECRYPT: - /* obtain data item */ - if (op->input != NCR_DATA_INVALID && - op->output != NCR_DATA_INVALID) { - ret = _ncr_session_update(lists, op); - if (ret < 0) + break; + + case NCR_OP_VERIFY: + digest_size = sess->hash.digestsize; + if (digest_size == 0 || sizeof(digest) < digest_size) { + err(); + ret = -EINVAL; + goto fail; + } + ret = cryptodev_hash_final(&sess->hash, digest); + if (ret < 0) { + err(); + goto fail; + } + + odata = ncr_data_item_get( &lists->data, op->data.ndata.output); + if (odata == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + if (sess->algorithm->is_hmac) { + if (digest_size != odata->data_size || + memcmp(odata->data, digest, digest_size) != 0) { + + op->err = NCR_VERIFICATION_FAILED; + } else { + op->err = NCR_SUCCESS; + } + } else { + /* PK signature */ + ret = ncr_pk_cipher_verify(&sess->pk, &odata->sg, 1, odata->data_size, + digest, digest_size, &op->err); + if (ret < 0) { + err(); goto fail; + } } break; - case NCR_OP_VERIFY: - /* obtain data item */ - if (op->input != NCR_DATA_INVALID) { - ret = _ncr_session_update(lists, op); - if (ret < 0) + case NCR_OP_SIGN: + odata = ncr_data_item_get( &lists->data, op->data.ndata.output); + if (odata == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + digest_size = sess->hash.digestsize; + if (digest_size == 0 || odata->max_data_size < digest_size) { + err(); + ret = -EINVAL; + goto fail; + } + ret = cryptodev_hash_final(&sess->hash, odata->data); + odata->data_size = digest_size; + + cryptodev_hash_deinit(&sess->hash); + + if (sess->algorithm->is_pk) { + /* PK signature */ + size_t new_size = odata->max_data_size; + ret = ncr_pk_cipher_sign(&sess->pk, &odata->sg, 1, odata->data_size, + &odata->sg, 1, &new_size); + if (ret < 0) { + err(); goto fail; + } + odata->data_size = new_size; + } + break; + default: + err(); + ret = -EINVAL; + goto fail; + } + + ret = 0; + +fail: + if (odata) _ncr_data_item_put(odata); + cryptodev_hash_deinit(&sess->hash); + if (sess->algorithm->is_symmetric) { + cryptodev_cipher_deinit(&sess->cipher); + } else { + ncr_pk_cipher_deinit(&sess->pk); + } + + _ncr_sessions_item_put(sess); + _ncr_session_remove(&lists->sessions, op->ses); + + return ret; +} + +/* Called when userspace buffers are used */ +static int _ncr_session_direct_update(struct ncr_lists* lists, struct ncr_session_op_st* op) +{ + int ret; + struct session_item_st* sess; + struct scatterlist *isg; + struct scatterlist *osg; + unsigned osg_cnt=0, isg_cnt=0; + size_t isg_size, osg_size; + + sess = ncr_sessions_item_get( &lists->sessions, op->ses); + if (sess == NULL) { + err(); + return -EINVAL; + } + + if (down_interruptible(&sess->mem_mutex)) { + err(); + _ncr_sessions_item_put(sess); + return -ERESTARTSYS; + } + + ret = get_userbuf2(sess, op, &isg, &isg_cnt, &osg, &osg_cnt); + if (ret < 0) { + err(); + goto fail; + } + isg_size = op->data.udata.input_size; + osg_size = op->data.udata.output_size; + + switch(sess->op) { + case NCR_OP_ENCRYPT: + if (osg == NULL) { + err(); + ret = -EINVAL; + goto fail; } - odata = ncr_data_item_get( &lists->data, op->output); - if (odata == NULL) { + ret = _ncr_session_encrypt(sess, isg, isg_cnt, isg_size, + osg, osg_cnt, &osg_size); + if (ret < 0) { + err(); + goto fail; + } + op->data.udata.output_size = osg_size; + + break; + case NCR_OP_DECRYPT: + if (osg == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + if (osg_size < isg_size) { err(); ret = -EINVAL; goto fail; } + ret = _ncr_session_decrypt(sess, isg, isg_cnt, isg_size, + osg, osg_cnt, &osg_size); + if (ret < 0) { + err(); + goto fail; + } + op->data.udata.output_size = osg_size; + + break; + + case NCR_OP_SIGN: + case NCR_OP_VERIFY: + ret = cryptodev_hash_update(&sess->hash, isg, isg_size); + if (ret < 0) { + err(); + goto fail; + } + break; + default: + err(); + ret = -EINVAL; + goto fail; + } + + ret = 0; + +fail: + if (sess->available_pages) { + release_user_pages(sess->pages, sess->available_pages); + sess->available_pages = 0; + } + up(&sess->mem_mutex); + _ncr_sessions_item_put(sess); + + return ret; +} + +static int try_session_direct_update(struct ncr_lists* lists, struct ncr_session_op_st* op) +{ + if (op->data.udata.input != NULL) { + return _ncr_session_direct_update(lists, op); + } + + return 0; +} + +static int _ncr_session_direct_final(struct ncr_lists* lists, struct ncr_session_op_st* op) +{ + int ret; + struct session_item_st* sess; + struct data_item_st* odata = NULL; + int digest_size; + uint8_t digest[NCR_HASH_MAX_OUTPUT_SIZE]; + uint8_t vdigest[NCR_HASH_MAX_OUTPUT_SIZE]; + struct scatterlist *osg; + unsigned osg_cnt=0; + size_t osg_size = 0; + size_t orig_osg_size; + + sess = ncr_sessions_item_get( &lists->sessions, op->ses); + if (sess == NULL) { + err(); + return -EINVAL; + } + + ret = try_session_direct_update(lists, op); + if (ret < 0) { + err(); + _ncr_sessions_item_put(sess); + return ret; + } + + if (down_interruptible(&sess->mem_mutex)) { + err(); + _ncr_sessions_item_put(sess); + return -ERESTARTSYS; + } + + switch(sess->op) { + case NCR_OP_ENCRYPT: + case NCR_OP_DECRYPT: + break; + case NCR_OP_VERIFY: + ret = get_userbuf1(sess, op, &osg, &osg_cnt); + if (ret < 0) { + err(); + goto fail; + } + orig_osg_size = osg_size = op->data.udata.output_size; + digest_size = sess->hash.digestsize; if (digest_size == 0 || sizeof(digest) < digest_size) { err(); @@ -633,11 +985,17 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* err(); goto fail; } - if (sess->algorithm->is_hmac) { + ret = sg_copy_to_buffer(osg, osg_cnt, vdigest, digest_size); + if (ret != digest_size) { + err(); + ret = -EINVAL; + goto fail; + } + if (digest_size != odata->data_size || - memcmp(odata->data, digest, digest_size) != 0) { + memcmp(vdigest, digest, digest_size) != 0) { op->err = NCR_VERIFICATION_FAILED; } else { @@ -645,7 +1003,7 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* } } else { /* PK signature */ - ret = ncr_pk_cipher_verify(&sess->pk, odata->data, odata->data_size, + ret = ncr_pk_cipher_verify(&sess->pk, osg, osg_cnt, osg_size, digest, digest_size, &op->err); if (ret < 0) { err(); @@ -655,40 +1013,46 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* break; case NCR_OP_SIGN: - /* obtain data item */ - if (op->input != NCR_DATA_INVALID) { - ret = _ncr_session_update(lists, op); - if (ret < 0) - goto fail; + ret = get_userbuf1(sess, op, &osg, &osg_cnt); + if (ret < 0) { + err(); + goto fail; } - odata = ncr_data_item_get( &lists->data, op->output); - if (odata == NULL) { + orig_osg_size = osg_size = op->data.udata.output_size; + + digest_size = sess->hash.digestsize; + if (digest_size == 0 || osg_size < digest_size) { err(); ret = -EINVAL; goto fail; } - digest_size = sess->hash.digestsize; - if (digest_size == 0 || odata->max_data_size < digest_size) { + ret = cryptodev_hash_final(&sess->hash, digest); + if (ret < 0) { + err(); + goto fail; + } + + ret = sg_copy_from_buffer(osg, osg_cnt, digest, digest_size); + if (ret != digest_size) { err(); ret = -EINVAL; goto fail; } - ret = cryptodev_hash_final(&sess->hash, odata->data); - odata->data_size = digest_size; + osg_size = digest_size; cryptodev_hash_deinit(&sess->hash); if (sess->algorithm->is_pk) { /* PK signature */ - size_t new_size = odata->max_data_size; - ret = ncr_pk_cipher_sign(&sess->pk, odata->data, odata->data_size, - odata->data, &new_size); + + ret = ncr_pk_cipher_sign(&sess->pk, osg, osg_cnt, osg_size, + osg, osg_cnt, &orig_osg_size); if (ret < 0) { err(); goto fail; } - odata->data_size = new_size; + osg_size = orig_osg_size; } break; default: @@ -697,10 +1061,18 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* goto fail; } + if (osg_size > 0) + op->data.udata.output_size = osg_size; + ret = 0; fail: - if (odata) _ncr_data_item_put(odata); + if (sess->available_pages) { + release_user_pages(sess->pages, sess->available_pages); + sess->available_pages = 0; + } + up(&sess->mem_mutex); + cryptodev_hash_deinit(&sess->hash); if (sess->algorithm->is_symmetric) { cryptodev_cipher_deinit(&sess->cipher); @@ -714,6 +1086,37 @@ fail: return ret; } + +int ncr_session_update(struct ncr_lists* lists, void __user* arg) +{ + struct ncr_session_op_st op; + int ret; + + if (unlikely(copy_from_user( &op, arg, sizeof(op)))) { + err(); + return -EFAULT; + } + + if (op.type == NCR_DIRECT_DATA) + ret = _ncr_session_direct_update(lists, &op); + else if (op.type == NCR_DATA) + ret = _ncr_session_update(lists, &op); + else + ret = -EINVAL; + + if (unlikely(ret)) { + err(); + return ret; + } + + if (unlikely(copy_to_user(arg, &op, sizeof(op)))) { + err(); + return -EFAULT; + } + + return 0; +} + int ncr_session_final(struct ncr_lists* lists, void __user* arg) { struct ncr_session_op_st op; @@ -724,7 +1127,14 @@ int ncr_session_final(struct ncr_lists* lists, void __user* arg) return -EFAULT; } - ret = _ncr_session_final(lists, &op); + if (op.type == NCR_DATA) { + ret = _ncr_session_final(lists, &op); + } else if (op.type == NCR_DIRECT_DATA) { + ret = _ncr_session_direct_final(lists, &op); + } else { + ret = -EINVAL; + } + if (unlikely(ret)) { err(); return ret; @@ -754,7 +1164,13 @@ int ncr_session_once(struct ncr_lists* lists, void __user* arg) } kop.op.ses = kop.init.ses; - ret = _ncr_session_final(lists, &kop.op); + if (kop.op.type == NCR_DIRECT_DATA) + ret = _ncr_session_direct_final(lists, &kop.op); + else if (kop.op.type == NCR_DATA) + ret = _ncr_session_final(lists, &kop.op); + else + ret = -EINVAL; + if (ret < 0) { err(); return ret; @@ -764,4 +1180,3 @@ int ncr_session_once(struct ncr_lists* lists, void __user* arg) return -EFAULT; return 0; } - @@ -161,6 +161,7 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp, return ncr_session_final(lst, arg); case NCRIO_SESSION_ONCE: return ncr_session_once(lst, arg); + case NCRIO_MASTER_KEY_SET: return ncr_master_key_set(arg); case NCRIO_KEY_GENERATE_PAIR: @@ -276,14 +276,30 @@ typedef enum { NCR_VERIFICATION_FAILED = -2, } ncr_error_t; +typedef enum { + NCR_DATA, + NCR_DIRECT_DATA, +} ncr_data_type_t; + struct ncr_session_op_st { /* input */ ncr_session_t ses; - ncr_data_t input; - ncr_data_t output; /* when verifying signature this is - * the place of the signature. - */ + union { + struct { + ncr_data_t input; + ncr_data_t output; /* when verifying signature this is + * the place of the signature. + */ + } ndata; + struct { + void* input; + size_t input_size; + void* output; + size_t output_size; + } udata; + } data; + ncr_data_type_t type; /* output of verification */ ncr_error_t err; @@ -296,7 +312,7 @@ struct ncr_session_once_op_st { #define NCRIO_SESSION_INIT _IOR ('c', 300, struct ncr_session_st) #define NCRIO_SESSION_UPDATE _IOWR ('c', 301, struct ncr_session_op_st) -#define NCRIO_SESSION_FINAL _IOR ('c', 302, struct ncr_session_op_st) +#define NCRIO_SESSION_FINAL _IOWR ('c', 302, struct ncr_session_op_st) /* everything in one call */ #define NCRIO_SESSION_ONCE _IOWR ('c', 303, struct ncr_session_once_op_st) @@ -41,6 +41,14 @@ struct session_item_st { struct ncr_pk_ctx pk; struct hash_data hash; + struct scatterlist *sg; + struct page **pages; + unsigned array_size; + unsigned available_pages; + struct semaphore mem_mutex; /* down when the + * values above are changed. + */ + struct key_item_st* key; atomic_t refcnt; @@ -53,6 +61,7 @@ struct data_item_st { * I see no reason to allow concurrent writes (reads are * not an issue). */ + struct scatterlist sg; /* points to data */ uint8_t* data; size_t data_size; |