diff options
author | Tom Rini <trini@konsulko.com> | 2020-01-17 13:23:32 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2020-01-17 13:23:32 -0500 |
commit | 2d2f91a480f6849a8548414003d36fa030d434f1 (patch) | |
tree | 08667edb96f6a8efde767b10fabceafb746e3af7 /lib | |
parent | d7bb6aceb2e99a832efbb96f9bf480bf95602192 (diff) | |
parent | 4df3578119b043d76b86b50077b06898fc2a4f62 (diff) |
Merge branch '2020-01-17-improve-aes-support'
- Add support and tests for AES192 and AES256
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile | 1 | ||||
-rw-r--r-- | lib/aes.c | 111 | ||||
-rw-r--r-- | lib/aes/Makefile | 5 | ||||
-rw-r--r-- | lib/aes/aes-decrypt.c | 41 | ||||
-rw-r--r-- | lib/aes/aes-encrypt.c | 136 |
5 files changed, 254 insertions, 40 deletions
diff --git a/lib/Makefile b/lib/Makefile index 6b7b9ce85c..51eba80b89 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_ASN1_DECODER) += asn1_decoder.o obj-y += crypto/ obj-$(CONFIG_AES) += aes.o +obj-$(CONFIG_AES) += aes/ obj-$(CONFIG_$(SPL_TPL_)BINMAN_FDT) += binman.o ifndef API_BUILD @@ -508,50 +508,79 @@ static u8 rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; +static u32 aes_get_rounds(u32 key_len) +{ + u32 rounds = AES128_ROUNDS; + + if (key_len == AES192_KEY_LENGTH) + rounds = AES192_ROUNDS; + else if (key_len == AES256_KEY_LENGTH) + rounds = AES256_ROUNDS; + + return rounds; +} + +static u32 aes_get_keycols(u32 key_len) +{ + u32 keycols = AES128_KEYCOLS; + + if (key_len == AES192_KEY_LENGTH) + keycols = AES192_KEYCOLS; + else if (key_len == AES256_KEY_LENGTH) + keycols = AES256_KEYCOLS; + + return keycols; +} + /* produce AES_STATECOLS bytes for each round */ -void aes_expand_key(u8 *key, u8 *expkey) +void aes_expand_key(u8 *key, u32 key_len, u8 *expkey) { u8 tmp0, tmp1, tmp2, tmp3, tmp4; - u32 idx; + u32 idx, aes_rounds, aes_keycols; - memcpy(expkey, key, AES_KEYCOLS * 4); + aes_rounds = aes_get_rounds(key_len); + aes_keycols = aes_get_keycols(key_len); - for (idx = AES_KEYCOLS; idx < AES_STATECOLS * (AES_ROUNDS + 1); idx++) { + memcpy(expkey, key, key_len); + + for (idx = aes_keycols; idx < AES_STATECOLS * (aes_rounds + 1); idx++) { tmp0 = expkey[4*idx - 4]; tmp1 = expkey[4*idx - 3]; tmp2 = expkey[4*idx - 2]; tmp3 = expkey[4*idx - 1]; - if (!(idx % AES_KEYCOLS)) { + if (!(idx % aes_keycols)) { tmp4 = tmp3; tmp3 = sbox[tmp0]; - tmp0 = sbox[tmp1] ^ rcon[idx / AES_KEYCOLS]; + tmp0 = sbox[tmp1] ^ rcon[idx / aes_keycols]; tmp1 = sbox[tmp2]; tmp2 = sbox[tmp4]; - } else if ((AES_KEYCOLS > 6) && (idx % AES_KEYCOLS == 4)) { + } else if ((aes_keycols > 6) && (idx % aes_keycols == 4)) { tmp0 = sbox[tmp0]; tmp1 = sbox[tmp1]; tmp2 = sbox[tmp2]; tmp3 = sbox[tmp3]; } - expkey[4*idx+0] = expkey[4*idx - 4*AES_KEYCOLS + 0] ^ tmp0; - expkey[4*idx+1] = expkey[4*idx - 4*AES_KEYCOLS + 1] ^ tmp1; - expkey[4*idx+2] = expkey[4*idx - 4*AES_KEYCOLS + 2] ^ tmp2; - expkey[4*idx+3] = expkey[4*idx - 4*AES_KEYCOLS + 3] ^ tmp3; + expkey[4*idx+0] = expkey[4*idx - 4*aes_keycols + 0] ^ tmp0; + expkey[4*idx+1] = expkey[4*idx - 4*aes_keycols + 1] ^ tmp1; + expkey[4*idx+2] = expkey[4*idx - 4*aes_keycols + 2] ^ tmp2; + expkey[4*idx+3] = expkey[4*idx - 4*aes_keycols + 3] ^ tmp3; } } /* encrypt one 128 bit block */ -void aes_encrypt(u8 *in, u8 *expkey, u8 *out) +void aes_encrypt(u32 key_len, u8 *in, u8 *expkey, u8 *out) { u8 state[AES_STATECOLS * 4]; - u32 round; + u32 round, aes_rounds; + + aes_rounds = aes_get_rounds(key_len); memcpy(state, in, AES_STATECOLS * 4); add_round_key((u32 *)state, (u32 *)expkey); - for (round = 1; round < AES_ROUNDS + 1; round++) { - if (round < AES_ROUNDS) + for (round = 1; round < aes_rounds + 1; round++) { + if (round < aes_rounds) mix_sub_columns(state); else shift_rows(state); @@ -563,18 +592,20 @@ void aes_encrypt(u8 *in, u8 *expkey, u8 *out) memcpy(out, state, sizeof(state)); } -void aes_decrypt(u8 *in, u8 *expkey, u8 *out) +void aes_decrypt(u32 key_len, u8 *in, u8 *expkey, u8 *out) { u8 state[AES_STATECOLS * 4]; - int round; + int round, aes_rounds; + + aes_rounds = aes_get_rounds(key_len); memcpy(state, in, sizeof(state)); add_round_key((u32 *)state, - (u32 *)expkey + AES_ROUNDS * AES_STATECOLS); + (u32 *)expkey + aes_rounds * AES_STATECOLS); inv_shift_rows(state); - for (round = AES_ROUNDS; round--; ) { + for (round = aes_rounds; round--; ) { add_round_key((u32 *)state, (u32 *)expkey + round * AES_STATECOLS); if (round) @@ -596,62 +627,62 @@ void aes_apply_cbc_chain_data(u8 *cbc_chain_data, u8 *src, u8 *dst) { int i; - for (i = 0; i < AES_KEY_LENGTH; i++) + for (i = 0; i < AES_BLOCK_LENGTH; i++) *dst++ = *src++ ^ *cbc_chain_data++; } -void aes_cbc_encrypt_blocks(u8 *key_exp, u8 *iv, u8 *src, u8 *dst, +void aes_cbc_encrypt_blocks(u32 key_len, u8 *key_exp, u8 *iv, u8 *src, u8 *dst, u32 num_aes_blocks) { - u8 tmp_data[AES_KEY_LENGTH]; + u8 tmp_data[AES_BLOCK_LENGTH]; u8 *cbc_chain_data = iv; u32 i; for (i = 0; i < num_aes_blocks; i++) { debug("encrypt_object: block %d of %d\n", i, num_aes_blocks); - debug_print_vector("AES Src", AES_KEY_LENGTH, src); + debug_print_vector("AES Src", AES_BLOCK_LENGTH, src); /* Apply the chain data */ aes_apply_cbc_chain_data(cbc_chain_data, src, tmp_data); - debug_print_vector("AES Xor", AES_KEY_LENGTH, tmp_data); + debug_print_vector("AES Xor", AES_BLOCK_LENGTH, tmp_data); /* Encrypt the AES block */ - aes_encrypt(tmp_data, key_exp, dst); - debug_print_vector("AES Dst", AES_KEY_LENGTH, dst); + aes_encrypt(key_len, tmp_data, key_exp, dst); + debug_print_vector("AES Dst", AES_BLOCK_LENGTH, dst); /* Update pointers for next loop. */ cbc_chain_data = dst; - src += AES_KEY_LENGTH; - dst += AES_KEY_LENGTH; + src += AES_BLOCK_LENGTH; + dst += AES_BLOCK_LENGTH; } } -void aes_cbc_decrypt_blocks(u8 *key_exp, u8 *iv, u8 *src, u8 *dst, +void aes_cbc_decrypt_blocks(u32 key_len, u8 *key_exp, u8 *iv, u8 *src, u8 *dst, u32 num_aes_blocks) { - u8 tmp_data[AES_KEY_LENGTH], tmp_block[AES_KEY_LENGTH]; + u8 tmp_data[AES_BLOCK_LENGTH], tmp_block[AES_BLOCK_LENGTH]; /* Convenient array of 0's for IV */ - u8 cbc_chain_data[AES_KEY_LENGTH]; + u8 cbc_chain_data[AES_BLOCK_LENGTH]; u32 i; - memcpy(cbc_chain_data, iv, AES_KEY_LENGTH); + memcpy(cbc_chain_data, iv, AES_BLOCK_LENGTH); for (i = 0; i < num_aes_blocks; i++) { debug("encrypt_object: block %d of %d\n", i, num_aes_blocks); - debug_print_vector("AES Src", AES_KEY_LENGTH, src); + debug_print_vector("AES Src", AES_BLOCK_LENGTH, src); - memcpy(tmp_block, src, AES_KEY_LENGTH); + memcpy(tmp_block, src, AES_BLOCK_LENGTH); /* Decrypt the AES block */ - aes_decrypt(src, key_exp, tmp_data); - debug_print_vector("AES Xor", AES_KEY_LENGTH, tmp_data); + aes_decrypt(key_len, src, key_exp, tmp_data); + debug_print_vector("AES Xor", AES_BLOCK_LENGTH, tmp_data); /* Apply the chain data */ aes_apply_cbc_chain_data(cbc_chain_data, tmp_data, dst); - debug_print_vector("AES Dst", AES_KEY_LENGTH, dst); + debug_print_vector("AES Dst", AES_BLOCK_LENGTH, dst); /* Update pointers for next loop. */ - memcpy(cbc_chain_data, tmp_block, AES_KEY_LENGTH); - src += AES_KEY_LENGTH; - dst += AES_KEY_LENGTH; + memcpy(cbc_chain_data, tmp_block, AES_BLOCK_LENGTH); + src += AES_BLOCK_LENGTH; + dst += AES_BLOCK_LENGTH; } } diff --git a/lib/aes/Makefile b/lib/aes/Makefile new file mode 100644 index 0000000000..daed52a713 --- /dev/null +++ b/lib/aes/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (c) 2019, Softathome + +obj-$(CONFIG_$(SPL_)FIT_CIPHER) += aes-decrypt.o diff --git a/lib/aes/aes-decrypt.c b/lib/aes/aes-decrypt.c new file mode 100644 index 0000000000..345029fa78 --- /dev/null +++ b/lib/aes/aes-decrypt.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019, softathome + */ + +#ifndef USE_HOSTCC +#include <common.h> +#include <malloc.h> +#endif +#include <image.h> +#include <uboot_aes.h> + +int image_aes_decrypt(struct image_cipher_info *info, + const void *cipher, size_t cipher_len, + void **data, size_t *size) +{ +#ifndef USE_HOSTCC + unsigned char key_exp[AES256_EXPAND_KEY_LENGTH]; + unsigned int aes_blocks, key_len = info->cipher->key_len; + + *data = malloc(cipher_len); + if (!*data) { + printf("Can't allocate memory to decrypt\n"); + return -ENOMEM; + } + *size = info->size_unciphered; + + memcpy(&key_exp[0], info->key, key_len); + + /* First we expand the key. */ + aes_expand_key((u8 *)info->key, key_len, key_exp); + + /* Calculate the number of AES blocks to encrypt. */ + aes_blocks = DIV_ROUND_UP(cipher_len, AES_BLOCK_LENGTH); + + aes_cbc_decrypt_blocks(key_len, key_exp, (u8 *)info->iv, + (u8 *)cipher, *data, aes_blocks); +#endif + + return 0; +} diff --git a/lib/aes/aes-encrypt.c b/lib/aes/aes-encrypt.c new file mode 100644 index 0000000000..de00a836f6 --- /dev/null +++ b/lib/aes/aes-encrypt.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019,Softathome + */ +#include "mkimage.h" +#include <stdio.h> +#include <string.h> +#include <image.h> +#include <time.h> +#include <openssl/bn.h> +#include <openssl/rsa.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#include <openssl/evp.h> +#include <openssl/engine.h> +#include <uboot_aes.h> + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#define HAVE_ERR_REMOVE_THREAD_STATE +#endif + +int image_aes_encrypt(struct image_cipher_info *info, + unsigned char *data, int size, + unsigned char **cipher, int *cipher_len) +{ + EVP_CIPHER_CTX *ctx; + unsigned char *buf = NULL; + int buf_len, len, ret = 0; + + /* create and initialise the context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) { + printf("Can't create context\n"); + return -1; + } + + /* allocate a buffer for the result */ + buf = malloc(size + AES_BLOCK_LENGTH); + if (!buf) { + printf("Can't allocate memory to encrypt\n"); + ret = -1; + goto out; + } + + if (EVP_EncryptInit_ex(ctx, info->cipher->calculate_type(), + NULL, info->key, info->iv) != 1) { + printf("Can't init encryption\n"); + ret = -1; + goto out; + } + + if (EVP_EncryptUpdate(ctx, buf, &len, data, size) != 1) { + printf("Can't encrypt data\n"); + ret = -1; + goto out; + } + + buf_len = len; + + if (EVP_EncryptFinal_ex(ctx, buf + len, &len) != 1) { + printf("Can't finalise the encryption\n"); + ret = -1; + goto out; + } + + buf_len += len; + + *cipher = buf; + *cipher_len = buf_len; + + out: + EVP_CIPHER_CTX_free(ctx); + return ret; +} + +int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest) +{ + int parent, node; + char name[128]; + int ret = 0; + + /* Either create or overwrite the named cipher node */ + parent = fdt_subnode_offset(keydest, 0, FIT_CIPHER_NODENAME); + if (parent == -FDT_ERR_NOTFOUND) { + parent = fdt_add_subnode(keydest, 0, FIT_CIPHER_NODENAME); + if (parent < 0) { + ret = parent; + if (ret != -FDT_ERR_NOSPACE) { + fprintf(stderr, + "Couldn't create cipher node: %s\n", + fdt_strerror(parent)); + } + } + } + if (ret) + goto done; + + /* Either create or overwrite the named key node */ + snprintf(name, sizeof(name), "key-%s-%s-%s", + info->name, info->keyname, info->ivname); + node = fdt_subnode_offset(keydest, parent, name); + if (node == -FDT_ERR_NOTFOUND) { + node = fdt_add_subnode(keydest, parent, name); + if (node < 0) { + ret = node; + if (ret != -FDT_ERR_NOSPACE) { + fprintf(stderr, + "Could not create key subnode: %s\n", + fdt_strerror(node)); + } + } + } else if (node < 0) { + fprintf(stderr, "Cannot select keys parent: %s\n", + fdt_strerror(node)); + ret = node; + } + + if (!ret) + ret = fdt_setprop(keydest, node, "iv", + info->iv, info->cipher->iv_len); + + if (!ret) + ret = fdt_setprop(keydest, node, "key", + info->key, info->cipher->key_len); + + if (!ret) + ret = fdt_setprop_u32(keydest, node, "key-len", + info->cipher->key_len); + +done: + if (ret) + ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; + + return ret; +} |