From 200e64960bf4ab36edf4e0be05c4291c878426b0 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Thu, 1 Dec 2011 10:49:00 +0100 Subject: [PATCH] Preliminary code for AES-GCM. --- cryptlib.c | 151 ++++++++++----- crypto/cryptodev.h | 2 + cryptodev_int.h | 24 ++- examples/Makefile | 4 +- examples/cipher-gcm.c | 524 ++++++++++++++++++++++++++++++++++++++++++++++++++ ioctl.c | 12 +- 6 files changed, 665 insertions(+), 52 deletions(-) create mode 100644 examples/cipher-gcm.c diff --git a/cryptlib.c b/cryptlib.c index ba6d7c0..73c75cb 100644 --- a/cryptlib.c +++ b/cryptlib.c @@ -1,7 +1,7 @@ /* * Driver for /dev/crypto device (aka CryptoDev) * - * Copyright (c) 2010 Nikos Mavrogiannopoulos + * Copyright (c) 2010,2011 Nikos Mavrogiannopoulos * Portions Copyright (c) 2010 Michael Weiser * Portions Copyright (c) 2010 Phil Sutter * @@ -33,6 +33,7 @@ #include #include #include +#include #include "cryptodev_int.h" @@ -53,38 +54,58 @@ static void cryptodev_complete(struct crypto_async_request *req, int err) } int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, - uint8_t *keyp, size_t keylen, int stream) + uint8_t *keyp, size_t keylen, int stream, int aead) { - struct ablkcipher_alg *alg; int ret; memset(out, 0, sizeof(*out)); - 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__, alg_name); - return -EINVAL; - } + if (aead == 0) { + struct ablkcipher_alg *alg; - alg = crypto_ablkcipher_alg(out->async.s); + 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__, alg_name); + return -EINVAL; + } - if (alg != NULL) { - /* Was correct key length supplied? */ - if (alg->max_keysize > 0 && - unlikely((keylen < alg->min_keysize) || + alg = crypto_ablkcipher_alg(out->async.s); + if (alg != NULL) { + /* Was correct key length supplied? */ + if (alg->max_keysize > 0 && + unlikely((keylen < alg->min_keysize) || (keylen > alg->max_keysize))) { - dprintk(1, KERN_DEBUG, - "Wrong keylen '%zu' for algorithm '%s'. \ - Use %u to %u.\n", - keylen, alg_name, alg->min_keysize, - alg->max_keysize); - ret = -EINVAL; - goto error; + dprintk(1, KERN_DEBUG, + "Wrong keylen '%zu' for algorithm '%s'. \ + Use %u to %u.\n", + keylen, alg_name, alg->min_keysize, + alg->max_keysize); + ret = -EINVAL; + goto error; + } + } + + out->blocksize = crypto_ablkcipher_blocksize(out->async.s); + out->ivsize = crypto_ablkcipher_ivsize(out->async.s); + out->alignmask = crypto_ablkcipher_alignmask(out->async.s); + + ret = crypto_ablkcipher_setkey(out->async.s, keyp, keylen); + } else { + out->async.as = crypto_alloc_aead(alg_name, 0, 0); + if (unlikely(IS_ERR(out->async.s))) { + dprintk(1, KERN_DEBUG, "%s: Failed to load cipher %s\n", + __func__, alg_name); + return -EINVAL; } + + out->blocksize = crypto_aead_blocksize(out->async.as); + out->ivsize = crypto_aead_ivsize(out->async.as); + out->alignmask = crypto_aead_alignmask(out->async.as); + + ret = crypto_aead_setkey(out->async.as, keyp, keylen); } - ret = crypto_ablkcipher_setkey(out->async.s, keyp, keylen); if (unlikely(ret)) { dprintk(1, KERN_DEBUG, "Setting key failed for %s-%zu.\n", alg_name, keylen*8); @@ -93,9 +114,7 @@ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, } out->stream = stream; - out->blocksize = crypto_ablkcipher_blocksize(out->async.s); - out->ivsize = crypto_ablkcipher_ivsize(out->async.s); - out->alignmask = crypto_ablkcipher_alignmask(out->async.s); + out->aead = aead; out->async.result = kmalloc(sizeof(*out->async.result), GFP_KERNEL); if (unlikely(!out->async.result)) { @@ -106,25 +125,45 @@ int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, memset(out->async.result, 0, sizeof(*out->async.result)); init_completion(&out->async.result->completion); - out->async.request = ablkcipher_request_alloc(out->async.s, GFP_KERNEL); - if (unlikely(!out->async.request)) { - dprintk(1, KERN_ERR, "error allocating async crypto request\n"); - ret = -ENOMEM; - goto error; - } + if (aead == 0) { + out->async.request = ablkcipher_request_alloc(out->async.s, GFP_KERNEL); + if (unlikely(!out->async.request)) { + dprintk(1, KERN_ERR, "error allocating async crypto request\n"); + ret = -ENOMEM; + goto error; + } - ablkcipher_request_set_callback(out->async.request, + ablkcipher_request_set_callback(out->async.request, CRYPTO_TFM_REQ_MAY_BACKLOG, cryptodev_complete, out->async.result); + } else { + out->async.arequest = aead_request_alloc(out->async.as, GFP_KERNEL); + if (unlikely(!out->async.arequest)) { + dprintk(1, KERN_ERR, "error allocating async crypto request\n"); + ret = -ENOMEM; + goto error; + } + + aead_request_set_callback(out->async.arequest, + CRYPTO_TFM_REQ_MAY_BACKLOG, + cryptodev_complete, out->async.result); + } out->init = 1; return 0; error: - if (out->async.request) - ablkcipher_request_free(out->async.request); + if (aead == 0) { + if (out->async.request) + ablkcipher_request_free(out->async.request); + if (out->async.s) + crypto_free_ablkcipher(out->async.s); + } else { + if (out->async.arequest) + aead_request_free(out->async.arequest); + if (out->async.s) + crypto_free_aead(out->async.as); + } kfree(out->async.result); - if (out->async.s) - crypto_free_ablkcipher(out->async.s); return ret; } @@ -132,12 +171,19 @@ error: void cryptodev_cipher_deinit(struct cipher_data *cdata) { if (cdata->init) { - if (cdata->async.request) - ablkcipher_request_free(cdata->async.request); - kfree(cdata->async.result); - if (cdata->async.s) - crypto_free_ablkcipher(cdata->async.s); + if (cdata->aead == 0) { + if (cdata->async.request) + ablkcipher_request_free(cdata->async.request); + if (cdata->async.s) + crypto_free_ablkcipher(cdata->async.s); + } else { + if (cdata->async.arequest) + aead_request_free(cdata->async.arequest); + if (cdata->async.s) + crypto_free_aead(cdata->async.as); + } + kfree(cdata->async.result); cdata->init = 0; } } @@ -177,10 +223,18 @@ ssize_t cryptodev_cipher_encrypt(struct cipher_data *cdata, int ret; INIT_COMPLETION(cdata->async.result->completion); - ablkcipher_request_set_crypt(cdata->async.request, + + if (cdata->aead == 0) { + ablkcipher_request_set_crypt(cdata->async.request, + (struct scatterlist *)sg1, sg2, + len, cdata->async.iv); + ret = crypto_ablkcipher_encrypt(cdata->async.request); + } else { + aead_request_set_crypt(cdata->async.arequest, (struct scatterlist *)sg1, sg2, len, cdata->async.iv); - ret = crypto_ablkcipher_encrypt(cdata->async.request); + ret = crypto_aead_encrypt(cdata->async.arequest); + } return waitfor(cdata->async.result, ret); } @@ -192,10 +246,17 @@ ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata, int ret; INIT_COMPLETION(cdata->async.result->completion); - ablkcipher_request_set_crypt(cdata->async.request, + if (cdata->aead == 0) { + ablkcipher_request_set_crypt(cdata->async.request, + (struct scatterlist *)sg1, sg2, + len, cdata->async.iv); + ret = crypto_ablkcipher_decrypt(cdata->async.request); + } else { + aead_request_set_crypt(cdata->async.arequest, (struct scatterlist *)sg1, sg2, len, cdata->async.iv); - ret = crypto_ablkcipher_decrypt(cdata->async.request); + ret = crypto_aead_decrypt(cdata->async.arequest); + } return waitfor(cdata->async.result, ret); } diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h index f56a043..408c2a5 100644 --- a/crypto/cryptodev.h +++ b/crypto/cryptodev.h @@ -41,6 +41,7 @@ enum cryptodev_crypto_op_t { CRYPTO_AES_CTR = 21, CRYPTO_AES_XTS = 22, CRYPTO_AES_ECB = 23, + CRYPTO_AES_GCM = 50, CRYPTO_CAMELLIA_CBC = 101, CRYPTO_RIPEMD160, @@ -140,6 +141,7 @@ struct crypt_auth_op { /* initialization vector for encryption operations */ __u8 __user *iv; + __u32 iv_len; }; /* In TLS mode the following are required: diff --git a/cryptodev_int.h b/cryptodev_int.h index d7412a6..634f195 100644 --- a/cryptodev_int.h +++ b/cryptodev_int.h @@ -12,6 +12,7 @@ #include #include #include +#include #define PFX "cryptodev: " #define dprintk(level, severity, format, a...) \ @@ -40,13 +41,18 @@ void release_user_pages(struct page **pg, int pagecount); struct cipher_data { int init; /* 0 uninitialized */ int blocksize; + int aead; int stream; int ivsize; int alignmask; struct { struct crypto_ablkcipher *s; - struct cryptodev_result *result; struct ablkcipher_request *request; + + struct crypto_aead *as; + struct aead_request *arequest; + + struct cryptodev_result *result; uint8_t iv[EALG_MAX_BLOCK_LEN]; } async; }; @@ -57,7 +63,7 @@ struct fcrypt { }; int cryptodev_cipher_init(struct cipher_data *out, const char *alg_name, - uint8_t *key, size_t keylen, int stream); + uint8_t *key, size_t keylen, int stream, int aead); void cryptodev_cipher_deinit(struct cipher_data *cdata); ssize_t cryptodev_cipher_decrypt(struct cipher_data *cdata, const struct scatterlist *sg1, @@ -66,6 +72,20 @@ ssize_t cryptodev_cipher_encrypt(struct cipher_data *cdata, const struct scatterlist *sg1, struct scatterlist *sg2, size_t len); +/* AEAD */ +inline static void cryptodev_cipher_auth(struct cipher_data *cdata, + const struct scatterlist *sg1, size_t len) +{ + aead_request_set_assoc(cdata->async.arequest, + (struct scatterlist *)sg1, len); +} + +inline static void cryptodev_cipher_set_tag_size(struct cipher_data *cdata, int size) +{ + if (cdata->aead != 0) + crypto_aead_setauthsize(cdata->async.as, size); +} + inline static void cryptodev_cipher_set_iv(struct cipher_data *cdata, void *iv, size_t iv_size) { diff --git a/examples/Makefile b/examples/Makefile index eeb9d62..4e86390 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,7 +1,9 @@ KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build KBUILD_CFLAGS += -I.. -hostprogs := cipher cipher-aead hmac speed async_cipher async_hmac async_speed sha_speed hashcrypt_speed fullspeed +hostprogs := cipher cipher-aead hmac speed async_cipher async_hmac \ + async_speed sha_speed hashcrypt_speed fullspeed cipher-gcm + example-cipher-objs := cipher.o example-cipher-aead-objs := cipher-aead.o example-hmac-objs := hmac.o diff --git a/examples/cipher-gcm.c b/examples/cipher-gcm.c new file mode 100644 index 0000000..0643416 --- /dev/null +++ b/examples/cipher-gcm.c @@ -0,0 +1,524 @@ +/* + * Demo on how to use /dev/crypto device for ciphering. + * + * Placed under public domain. + * + */ +#include +#include +#include +#include +#include + +#include +#include + +#define DATA_SIZE (8*1024) +#define AUTH_SIZE 31 +#define BLOCK_SIZE 16 +#define KEY_SIZE 16 + + +static void print_buf(char *desc, const unsigned char *buf, int size) +{ + int i; + fputs(desc, stdout); + for (i = 0; i < size; i++) { + printf("%.2x", (uint8_t) buf[i]); + } + fputs("\n", stdout); +} + +struct aes_gcm_vectors_st { + const uint8_t *key; + const uint8_t *auth; + int auth_size; + const uint8_t *plaintext; + int plaintext_size; + const uint8_t *iv; + const uint8_t *ciphertext; + const uint8_t *tag; +}; + +struct aes_gcm_vectors_st aes_gcm_vectors[] = { + { + .key = + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .auth = NULL, + .auth_size = 0, + .plaintext = NULL, + .plaintext_size = 0, + .ciphertext = NULL, + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .tag = + "\x58\xe2\xfc\xce\xfa\x7e\x30\x61\x36\x7f\x1d\x57\xa4\xe7\x45\x5a"}, + { + .key = + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .auth = NULL, + .auth_size = 0, + .plaintext = + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .plaintext_size = 16, + .ciphertext = + "\x03\x88\xda\xce\x60\xb6\xa3\x92\xf3\x28\xc2\xb9\x71\xb2\xfe\x78", + .iv = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .tag = + "\xab\x6e\x47\xd4\x2c\xec\x13\xbd\xf5\x3a\x67\xb2\x12\x57\xbd\xdf"}, + { + .key = + "\xfe\xff\xe9\x92\x86\x65\x73\x1c\x6d\x6a\x8f\x94\x67\x30\x83\x08", + .auth = + "\xfe\xed\xfa\xce\xde\xad\xbe\xef\xfe\xed\xfa\xce\xde\xad\xbe\xef\xab\xad\xda\xd2", + .auth_size = 20, + .plaintext = + "\xd9\x31\x32\x25\xf8\x84\x06\xe5\xa5\x59\x09\xc5\xaf\xf5\x26\x9a\x86\xa7\xa9\x53\x15\x34\xf7\xda\x2e\x4c\x30\x3d\x8a\x31\x8a\x72\x1c\x3c\x0c\x95\x95\x68\x09\x53\x2f\xcf\x0e\x24\x49\xa6\xb5\x25\xb1\x6a\xed\xf5\xaa\x0d\xe6\x57\xba\x63\x7b\x39", + .plaintext_size = 60, + .ciphertext = + "\x42\x83\x1e\xc2\x21\x77\x74\x24\x4b\x72\x21\xb7\x84\xd0\xd4\x9c\xe3\xaa\x21\x2f\x2c\x02\xa4\xe0\x35\xc1\x7e\x23\x29\xac\xa1\x2e\x21\xd5\x14\xb2\x54\x66\x93\x1c\x7d\x8f\x6a\x5a\xac\x84\xaa\x05\x1b\xa3\x0b\x39\x6a\x0a\xac\x97\x3d\x58\xe0\x91", + .iv = "\xca\xfe\xba\xbe\xfa\xce\xdb\xad\xde\xca\xf8\x88", + .tag = + "\x5b\xc9\x4f\xbc\x32\x21\xa5\xdb\x94\xfa\xe9\x5a\xe7\x12\x1a\x47"} +}; + + +/* Test against AES-GCM test vectors. + */ +static int test_crypto(int cfd) +{ + char iv[BLOCK_SIZE]; + unsigned char tag[16]; + int pad, i; + int8_t tmp[128]; + + struct session_op sess; + struct crypt_auth_op cao; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + /* Get crypto session for AES128 */ + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } + printf + ("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n", + siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); +#endif + + + fprintf(stdout, "Tests on AES-GCM: "); + fflush(stdout); + for (i = 0; + i < sizeof(aes_gcm_vectors) / sizeof(aes_gcm_vectors[0]); + i++) { + memset(&sess, 0, sizeof(sess)); + memset(tmp, 0, sizeof(tmp)); + + sess.cipher = CRYPTO_AES_GCM; + sess.keylen = 16; + sess.key = (void *) aes_gcm_vectors[i].key; + + memset(&cao, 0, sizeof(cao)); + + cao.ses = sess.ses; + cao.dst = tmp; + cao.iv = (void *) aes_gcm_vectors[i].iv; + cao.iv_len = 12; + cao.op = COP_ENCRYPT; + cao.flags = 0; + + if (aes_gcm_vectors[i].auth_size > 0) { + cao.auth_src = (void *) aes_gcm_vectors[i].auth; + cao.auth_len = aes_gcm_vectors[i].auth_size; + } + + if (aes_gcm_vectors[i].plaintext_size > 0) { + cao.src = (void *) aes_gcm_vectors[i].plaintext; + cao.len = aes_gcm_vectors[i].plaintext_size; + } + + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return 1; + } + + if (aes_gcm_vectors[i].plaintext_size > 0) + if (memcmp + (tmp, aes_gcm_vectors[i].ciphertext, + aes_gcm_vectors[i].plaintext_size) != 0) { + fprintf(stderr, + "AES-GCM test vector %d failed!\n", + i); + + print_buf("Cipher: ", tmp, aes_gcm_vectors[i].plaintext_size); + print_buf("Expected: ", aes_gcm_vectors[i].ciphertext, aes_gcm_vectors[i].plaintext_size); + return 1; + } + + if (memcmp + (&tmp[cao.len - cao.tag_len], aes_gcm_vectors[i].tag, + 16) != 0) { + fprintf(stderr, + "AES-GCM test vector %d failed (tag)!\n", + i); + + print_buf("Tag: ", tmp, cao.tag_len); + print_buf("Expected tag: ", + aes_gcm_vectors[i].tag, 16); + return 1; + } + + } + fprintf(stdout, "ok\n"); + fprintf(stdout, "\n"); + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +/* Checks if encryption and subsequent decryption + * produces the same data. + */ +static int test_encrypt_decrypt(int cfd) +{ + char plaintext_raw[DATA_SIZE + 63], *plaintext; + char ciphertext_raw[DATA_SIZE + 63], *ciphertext; + char iv[BLOCK_SIZE]; + char key[KEY_SIZE]; + char auth[AUTH_SIZE]; + unsigned char sha1mac[20]; + int pad, i, enc_len; + + struct session_op sess; + struct crypt_auth_op cao; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + memset(&sess, 0, sizeof(sess)); + memset(&cao, 0, sizeof(cao)); + + memset(key, 0x33, sizeof(key)); + memset(iv, 0x03, sizeof(iv)); + memset(auth, 0xf1, sizeof(auth)); + + /* Get crypto session for AES128 */ + sess.cipher = CRYPTO_AES_GCM; + sess.keylen = KEY_SIZE; + sess.key = key; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } +// printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n", +// siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + + plaintext = + (char *) (((unsigned long) plaintext_raw + siop.alignmask) & + ~siop.alignmask); + ciphertext = + (char *) (((unsigned long) ciphertext_raw + siop.alignmask) & + ~siop.alignmask); +#else + plaintext = plaintext_raw; + ciphertext = ciphertext_raw; +#endif + memset(plaintext, 0x15, DATA_SIZE); + + /* Encrypt data.in to data.encrypted */ + cao.ses = sess.ses; + cao.auth_src = auth; + cao.auth_len = sizeof(auth); + cao.len = DATA_SIZE; + cao.src = plaintext; + cao.dst = ciphertext; + cao.iv = iv; + cao.op = COP_ENCRYPT; + cao.flags = 0; + + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return 1; + } + + enc_len = cao.len; + //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len); + + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + /* Get crypto session for AES128 */ + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_AES_GCM; + sess.keylen = KEY_SIZE; + sess.key = key; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + + /* Decrypt data.encrypted to data.decrypted */ + cao.ses = sess.ses; + cao.auth_src = auth; + cao.auth_len = sizeof(auth); + cao.len = enc_len; + cao.src = ciphertext; + cao.dst = ciphertext; + cao.iv = iv; + cao.op = COP_DECRYPT; + cao.flags = 0; + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return 1; + } + + if (cao.len != DATA_SIZE) { + fprintf(stderr, "decrypted data size incorrect!\n"); + return 1; + } + + /* Verify the result */ + if (memcmp(plaintext, ciphertext, DATA_SIZE) != 0) { + int i; + fprintf(stderr, + "FAIL: Decrypted data are different from the input data.\n"); + printf("plaintext:"); + for (i = 0; i < DATA_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", plaintext[i]); + } + printf("ciphertext:"); + for (i = 0; i < DATA_SIZE; i++) { + if ((i % 30) == 0) + printf("\n"); + printf("%02x ", ciphertext[i]); + } + printf("\n"); + return 1; + } + + printf("Test passed\n"); + + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + return 0; +} + +static int test_encrypt_decrypt_error(int cfd, int err) +{ + char plaintext_raw[DATA_SIZE + 63], *plaintext; + char ciphertext_raw[DATA_SIZE + 63], *ciphertext; + char iv[BLOCK_SIZE]; + char key[KEY_SIZE]; + char auth[AUTH_SIZE]; + int pad, i, enc_len; + + struct session_op sess; + struct crypt_op co; + struct crypt_auth_op cao; +#ifdef CIOCGSESSINFO + struct session_info_op siop; +#endif + + memset(&sess, 0, sizeof(sess)); + memset(&cao, 0, sizeof(cao)); + memset(&co, 0, sizeof(co)); + + memset(key, 0x33, sizeof(key)); + memset(iv, 0x03, sizeof(iv)); + memset(auth, 0xf1, sizeof(auth)); + + /* Get crypto session for AES128 */ + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key; + + sess.mac = CRYPTO_SHA1_HMAC; + sess.mackeylen = 16; + sess.mackey = + (uint8_t *) + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } +#ifdef CIOCGSESSINFO + siop.ses = sess.ses; + if (ioctl(cfd, CIOCGSESSINFO, &siop)) { + perror("ioctl(CIOCGSESSINFO)"); + return 1; + } +// printf("requested cipher CRYPTO_AES_CBC/HMAC-SHA1, got %s with driver %s\n", +// siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name); + + plaintext = + (char *) (((unsigned long) plaintext_raw + siop.alignmask) & + ~siop.alignmask); + ciphertext = + (char *) (((unsigned long) ciphertext_raw + siop.alignmask) & + ~siop.alignmask); +#else + plaintext = plaintext_raw; + ciphertext = ciphertext_raw; +#endif + memset(plaintext, 0x15, DATA_SIZE); + + /* Encrypt data.in to data.encrypted */ + cao.ses = sess.ses; + cao.auth_src = auth; + cao.auth_len = sizeof(auth); + cao.len = DATA_SIZE; + cao.src = plaintext; + cao.dst = ciphertext; + cao.iv = iv; + cao.op = COP_ENCRYPT; + cao.flags = COP_FLAG_AEAD_TLS_TYPE; + + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + perror("ioctl(CIOCAUTHCRYPT)"); + return 1; + } + + enc_len = cao.len; + //printf("Original plaintext size: %d, ciphertext: %d\n", DATA_SIZE, enc_len); + + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + /* Get crypto session for AES128 */ + memset(&sess, 0, sizeof(sess)); + sess.cipher = CRYPTO_AES_CBC; + sess.keylen = KEY_SIZE; + sess.key = key; + sess.mac = CRYPTO_SHA1_HMAC; + sess.mackeylen = 16; + sess.mackey = + (uint8_t *) + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + + if (err == 0) + auth[2]++; + else + ciphertext[4]++; + + /* Decrypt data.encrypted to data.decrypted */ + cao.ses = sess.ses; + cao.auth_src = auth; + cao.auth_len = sizeof(auth); + cao.len = enc_len; + cao.src = ciphertext; + cao.dst = ciphertext; + cao.iv = iv; + cao.op = COP_DECRYPT; + cao.flags = COP_FLAG_AEAD_TLS_TYPE; + if (ioctl(cfd, CIOCAUTHCRYPT, &cao)) { + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + printf("Test passed\n"); + return 0; + } + + /* Finish crypto session */ + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + + fprintf(stderr, "Modification to ciphertext was not detected\n"); + return 1; +} + +int main() +{ + int fd = -1, cfd = -1; + + /* Open the crypto device */ + fd = open("/dev/crypto", O_RDWR, 0); + if (fd < 0) { + perror("open(/dev/crypto)"); + return 1; + } + + /* Clone file descriptor */ + if (ioctl(fd, CRIOGET, &cfd)) { + perror("ioctl(CRIOGET)"); + return 1; + } + + /* Set close-on-exec (not really neede here) */ + if (fcntl(cfd, F_SETFD, 1) == -1) { + perror("fcntl(F_SETFD)"); + return 1; + } + + /* Run the test itself */ + + if (test_crypto(cfd)) + return 1; + + if (test_encrypt_decrypt(cfd)) + return 1; + + if (test_encrypt_decrypt_error(cfd, 0)) + return 1; + + if (test_encrypt_decrypt_error(cfd, 1)) + return 1; + + /* Close cloned descriptor */ + if (close(cfd)) { + perror("close(cfd)"); + return 1; + } + + /* Close the original descriptor */ + if (close(fd)) { + perror("close(fd)"); + return 1; + } + + return 0; +} diff --git a/ioctl.c b/ioctl.c index 6177007..aa8ad51 100644 --- a/ioctl.c +++ b/ioctl.c @@ -103,7 +103,7 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) int ret = 0; const char *alg_name = NULL; const char *hash_name = NULL; - int hmac_mode = 1, stream = 0; + int hmac_mode = 1, stream = 0, aead = 0; /* Does the request make sense? */ if (unlikely(!sop->cipher && !sop->mac)) { @@ -136,6 +136,11 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) alg_name = "ctr(aes)"; stream = 1; break; + case CRYPTO_AES_GCM: + alg_name = "gcm(aes)"; + stream = 1; + aead = 1; + break; case CRYPTO_NULL: alg_name = "ecb(cipher_null)"; stream = 1; @@ -193,7 +198,6 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) hash_name = "sha512"; hmac_mode = 0; break; - default: dprintk(1, KERN_DEBUG, "%s: bad mac: %d\n", __func__, sop->mac); @@ -223,7 +227,7 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) } ret = cryptodev_cipher_init(&ses_new->cdata, alg_name, keyp, - sop->keylen, stream); + sop->keylen, stream, aead); if (ret < 0) { dprintk(1, KERN_DEBUG, "%s: Failed to load cipher for %s\n", @@ -233,7 +237,7 @@ crypto_create_session(struct fcrypt *fcr, struct session_op *sop) } } - if (hash_name) { + if (hash_name && aead == 0) { uint8_t keyp[CRYPTO_HMAC_MAX_KEY_LEN]; if (unlikely(sop->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) { -- 2.11.4.GIT