diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | ncr-key-storage.c | 104 | ||||
-rw-r--r-- | ncr-key-wrap.c | 293 | ||||
-rw-r--r-- | ncr_int.h | 5 |
4 files changed, 332 insertions, 72 deletions
@@ -3,7 +3,7 @@ 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-key-wrap.o + ncr-key-wrap.o ncr-key-storage.o obj-m += cryptodev.o diff --git a/ncr-key-storage.c b/ncr-key-storage.c new file mode 100644 index 0000000..5cdb9c6 --- /dev/null +++ b/ncr-key-storage.c @@ -0,0 +1,104 @@ +/* + * New driver for /dev/crypto device (aka CryptoDev) + + * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> + * + * This file is part of linux cryptodev. + * + * cryptodev is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * cryptodev is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/mm.h> +#include "cryptodev.h" +#include <asm/uaccess.h> +#include <asm/ioctl.h> +#include <linux/scatterlist.h> +#include "ncr.h" +#include "ncr_int.h" +#include "cryptodev_int.h" + +#define KEY_DATA_MAX_SIZE 2048 + +struct packed_key { + uint8_t type; + uint32_t flags; + uint16_t algorithm; /* valid for public/private keys */ + uint8_t key_id[MAX_KEY_ID_SIZE]; + uint8_t key_id_size; + + uint8_t raw[KEY_DATA_MAX_SIZE]; + uint32_t raw_size; +} __attribute__((__packed__)); + +int key_to_storage_data( uint8_t** sdata, size_t * sdata_size, const struct key_item_st *key) +{ + struct packed_key * pkey; + int ret; + + pkey = kmalloc(sizeof(*pkey), GFP_KERNEL); + if (pkey == NULL) { + err(); + return -ENOMEM; + } + + pkey->type = key->type; + pkey->flags = key->flags; + pkey->algorithm = key->algorithm; + pkey->key_id_size = key->key_id_size; + memcpy(pkey->key_id, key->key_id, key->key_id_size); + + if (key->type == NCR_KEY_TYPE_SECRET) { + pkey->raw_size = key->key.secret.size; + memcpy(pkey->raw, key->key.secret.data, pkey->raw_size); + } else { + err(); + ret = -EINVAL; + goto fail; + } + + *sdata = (void*)pkey; + *sdata_size = sizeof(*pkey); + + return 0; +fail: + kfree(pkey); + + return ret; +} + +int key_from_storage_data(struct key_item_st* key, const void* data, size_t data_size) +{ + const struct packed_key * pkey = data; + + if (data_size != sizeof(*pkey)) { + err(); + return -EINVAL; + } + + key->type = pkey->type; + key->flags = pkey->flags; + key->algorithm = pkey->algorithm; + key->key_id_size = pkey->key_id_size; + memcpy(key->key_id, pkey->key_id, pkey->key_id_size); + + if (key->type == NCR_KEY_TYPE_SECRET) { + key->key.secret.size = pkey->raw_size; + memcpy(key->key.secret.data, pkey->raw, pkey->raw_size); + } else { + err(); + return -EINVAL; + } + + return 0; +} diff --git a/ncr-key-wrap.c b/ncr-key-wrap.c index db0374e..6f0b013 100644 --- a/ncr-key-wrap.c +++ b/ncr-key-wrap.c @@ -34,13 +34,219 @@ typedef uint8_t val64_t[8]; static const val64_t initA = "\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6"; -static int key_from_storage_data(struct key_item_st* key, const void* data, size_t data_size); -static int key_to_storage_data( uint8_t** data, size_t * data_size, const struct key_item_st *key); -static int _wrap_aes_rfc5649(void* kdata, size_t kdata_size, struct key_item_st* key, - struct data_item_st* data, const void* iv, size_t iv_size); -static int _unwrap_aes_rfc5649(void* kdata, size_t *kdata_size, struct key_item_st* key, - struct data_item_st *data, const void* iv, size_t iv_size); +static void val64_xor( val64_t * val, uint32_t x) +{ + (*val)[7] ^= x & 0xff; + (*val)[6] ^= (x >> 8) & 0xff; + (*val)[5] ^= (x >> 16) & 0xff; + (*val)[4] ^= (x >> 24) & 0xff; +} + +static int rfc3394_wrap(val64_t R[], unsigned int n, struct cipher_data* ctx, + struct data_item_st* output, const uint8_t iv[8]) +{ +val64_t A; +uint8_t aes_block[16]; +int i,j; + + if (output->max_data_size < (n+1)*8) { + err(); + return -EINVAL; + } + + memcpy(A, iv, 8); + + for (i=0;i<6*n;i++) { + memcpy(aes_block, A, 8); + memcpy(&aes_block[8], R[0], 8); + + _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 */ + + for (j=0;j<n-1;j++) + memcpy(R[j], R[j+1], sizeof(R[j])); + memcpy(R[n-1], &aes_block[8], 8); /* R[n-1] = LSB64(AES(A^{t-1}|R_{1}^{t-1})) */ + } + + memcpy(output->data, A, sizeof(A)); + for (j=0;j<n;j++) + memcpy(&output->data[(j+1)*8], R[j], 8); + output->data_size = (n+1)*8; + + return 0; +} + +static int rfc3394_unwrap(uint8_t *wrapped_key, val64_t R[], unsigned int n, val64_t* A, struct cipher_data *ctx) +{ + int i, j; + uint8_t aes_block[16]; + + memcpy(*A, wrapped_key, 8); /* A = C[0] */ + for (i=0;i<n;i++) + memcpy(R[i], &wrapped_key[(i+1)*8], 8); + + for (i=(6*n)-1;i>=0;i--) { + val64_xor(A, i+1); + + memcpy(aes_block, *A, 8); + memcpy(&aes_block[8], R[n-1], 8); + + _cryptodev_cipher_decrypt(ctx, aes_block, sizeof(aes_block), + aes_block, sizeof(aes_block)); + + memcpy(*A, aes_block, 8); + + for (j=n-1;j>=1;j--) + memcpy(R[j], R[j-1], sizeof(R[j])); + + memcpy(R[0], &aes_block[8], 8); + } + + return 0; +} + +#define RFC5649_IV "\xA6\x59\x59\xA6" +static int _wrap_aes_rfc5649(void* kdata, size_t kdata_size, struct key_item_st* kek, + struct data_item_st* output, const void* _iv, size_t iv_size) +{ +size_t n; +int i, j, ret; +struct cipher_data ctx; +uint8_t iv[8]; + + if (iv_size != 4) { + memcpy(iv, RFC5649_IV, 4); + } else { + memcpy(iv, _iv, 4); + } + iv_size = 8; + iv[4] = (kdata_size >> 24) & 0xff; + iv[5] = (kdata_size >> 16) & 0xff; + iv[6] = (kdata_size >> 8) & 0xff; + iv[7] = (kdata_size) & 0xff; + + ret = cryptodev_cipher_init(&ctx, "ecb(aes)", kek->key.secret.data, kek->key.secret.size); + if (ret < 0) { + err(); + return ret; + } + + n = (kdata_size+7)/8; + if (n==1) { /* unimplemented */ + err(); + ret = -EINVAL; + goto cleanup; + } + + { + val64_t R[n]; + + /* R = P */ + for (i=0;i<kdata_size;i++) { + j=i/8; + R[j][i] = ((uint8_t*)kdata)[i]; + } + for (;i<n*8;i++) { + j=i/8; + R[j][i] = 0; + } + + ret = rfc3394_wrap( R, n, &ctx, output, iv); + if (ret < 0) { + err(); + goto cleanup; + } + } + + ret = 0; + +cleanup: + cryptodev_cipher_deinit(&ctx); + + return ret; +} + +static int _unwrap_aes_rfc5649(void* kdata, size_t *kdata_size, struct key_item_st* kek, + struct data_item_st *wrapped, const void* _iv, size_t iv_size) +{ +size_t wrapped_key_size, n; +uint8_t *wrapped_key; +int i, ret; +struct cipher_data ctx; +uint8_t iv[4]; +size_t size; + + if (iv_size != 4) { + memcpy(iv, RFC5649_IV, 4); + } else { + memcpy(iv, _iv, 4); + } + iv_size = 4; + + ret = cryptodev_cipher_init(&ctx, "ecb(aes)", kek->key.secret.data, kek->key.secret.size); + if (ret < 0) { + err(); + return ret; + } + + wrapped_key = wrapped->data; + wrapped_key_size = wrapped->data_size; + + if (wrapped_key_size % 8 != 0) { + err(); + ret = -EINVAL; + goto cleanup; + } + + n = wrapped_key_size/8 - 1; + + if (*kdata_size < (n-1)*8) { + err(); + ret = -EINVAL; + goto cleanup; + } + + { + val64_t R[n], A; + + ret = rfc3394_unwrap(wrapped_key, R, n, &A, &ctx); + if (ret < 0) { + err(); + return ret; + } + + if (memcmp(A, iv, 4)!= 0) { + err(); + ret = -EINVAL; + goto cleanup; + } + + size = (A[4] << 24) | (A[5] << 16) | (A[6] << 8) | A[7]; + if (size > n*8 || size < (n-1)*8 || *kdata_size < size) { + err(); + ret = -EINVAL; + goto cleanup; + } + + memset(kdata, 0, size); + *kdata_size = size; + for (i=0;i<size;i++) { + ((uint8_t*)kdata)[i] = R[i/8][i%8]; + } + } + + + ret = 0; + +cleanup: + cryptodev_cipher_deinit(&ctx); + + return ret; +} static int wrap_aes_rfc5649(struct key_item_st* tobewrapped, struct key_item_st *kek, @@ -65,19 +271,6 @@ static int unwrap_aes_rfc5649(struct key_item_st* output, struct key_item_st *ke } -static void val64_zero( val64_t * val) -{ - memset(val, 0, sizeof(*val)); -} - -static void val64_xor( val64_t * val, uint32_t x) -{ - (*val)[7] ^= x & 0xff; - (*val)[6] ^= (x >> 8) & 0xff; - (*val)[5] ^= (x >> 16) & 0xff; - (*val)[4] ^= (x >> 24) & 0xff; -} - /* Wraps using the RFC3394 way. */ static int wrap_aes(struct key_item_st* tobewrapped, struct key_item_st *kek, @@ -85,9 +278,7 @@ static int wrap_aes(struct key_item_st* tobewrapped, struct key_item_st *kek, { size_t key_size, n; uint8_t *raw_key; -val64_t A; -int i, j, ret; -uint8_t aes_block[16]; +int i, ret; struct cipher_data ctx; if (tobewrapped->type != NCR_KEY_TYPE_SECRET) { @@ -117,12 +308,6 @@ struct cipher_data ctx; n = key_size/8; - if (output->max_data_size < (n+1)*8) { - err(); - ret = -EINVAL; - goto cleanup; - } - { val64_t R[n]; @@ -132,30 +317,13 @@ struct cipher_data ctx; memcpy(R[i], &raw_key[i*8], 8); } - memcpy(A, iv, 8); - - for (i=0;i<6*n;i++) { - memcpy(aes_block, A, 8); - memcpy(&aes_block[8], R[0], 8); - - _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 */ - - for (j=0;j<n-1;j++) - memcpy(R[j], R[j+1], sizeof(R[j])); - memcpy(R[n-1], &aes_block[8], 8); /* R[n-1] = LSB64(AES(A^{t-1}|R_{1}^{t-1})) */ + ret = rfc3394_wrap( R, n, &ctx, output, iv); + if (ret < 0) { + err(); + goto cleanup; } - - memcpy(output->data, A, sizeof(A)); - for (j=0;j<n;j++) - memcpy(&output->data[(j+1)*8], R[j], 8); - output->data_size = (n+1)*8; } - ret = 0; cleanup: @@ -183,8 +351,7 @@ static int unwrap_aes(struct key_item_st* output, struct key_item_st *kek, size_t wrapped_key_size, n; uint8_t *wrapped_key; val64_t A; -int i, j, ret; -uint8_t aes_block[16]; +int i, ret; struct cipher_data ctx; if (iv_size < sizeof(initA)) { @@ -220,28 +387,12 @@ struct cipher_data ctx; { val64_t R[n]; - memcpy(A, wrapped_key, 8); /* A = C[0] */ - for (i=0;i<n;i++) - memcpy(R[i], &wrapped_key[(i+1)*8], 8); - - for (i=(6*n)-1;i>=0;i--) { - val64_xor(&A, i+1); - - memcpy(aes_block, A, 8); - memcpy(&aes_block[8], R[n-1], 8); - - _cryptodev_cipher_decrypt(&ctx, aes_block, sizeof(aes_block), - aes_block, sizeof(aes_block)); - - memcpy(A, aes_block, 8); - - for (j=n-1;j>=1;j--) - memcpy(R[j], R[j-1], sizeof(R[j])); - - memcpy(R[0], &aes_block[8], 8); + ret = rfc3394_unwrap(wrapped_key, R, n, &A, &ctx); + if (ret < 0) { + err(); + return ret; } - if (memcmp(A, iv, 8)!= 0) { err(); ret = -EINVAL; @@ -139,6 +139,11 @@ extern struct key_item_st master_key; void ncr_master_key_reset(void); +/* storage */ +int key_from_storage_data(struct key_item_st* key, const void* data, size_t data_size); +int key_to_storage_data( uint8_t** data, size_t * data_size, const struct key_item_st *key); + + /* misc helper macros */ inline static unsigned int key_flags_to_data(unsigned int key_flags) { |