diff options
Diffstat (limited to 'drivers/crypto/aes/aes-sw.c')
-rw-r--r-- | drivers/crypto/aes/aes-sw.c | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/drivers/crypto/aes/aes-sw.c b/drivers/crypto/aes/aes-sw.c new file mode 100644 index 00000000000..a65200fb79b --- /dev/null +++ b/drivers/crypto/aes/aes-sw.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <config.h> +#include <dm.h> +#include <log.h> +#include <malloc.h> +#include <uboot_aes.h> + +#define SW_KEY_SLOTS 2 + +struct sw_aes_priv { + u8 key_slots[SW_KEY_SLOTS][AES256_KEY_LENGTH]; + u8 key_schedule[AES256_EXPAND_KEY_LENGTH]; + u8 selected_slot; + u32 selected_key_size; + bool key_expanded; +}; + +static int prepare_aes(struct sw_aes_priv *priv) +{ + if (!priv->selected_key_size) { + log_debug("%s: AES key size not set, setup a slot first\n", __func__); + return 1; + } + + if (priv->key_expanded) + return 0; + + priv->key_expanded = 1; + + aes_expand_key(priv->key_slots[priv->selected_slot], priv->selected_key_size, + priv->key_schedule); + + return 0; +} + +static int sw_aes_ops_available_key_slots(struct udevice *dev) +{ + return SW_KEY_SLOTS; +} + +static int sw_aes_ops_select_key_slot(struct udevice *dev, u32 key_size, u8 slot) +{ + struct sw_aes_priv *priv = dev_get_priv(dev); + + if (slot >= SW_KEY_SLOTS) + return 1; + + priv->selected_slot = slot; + priv->selected_key_size = key_size; + priv->key_expanded = 0; + + return 0; +} + +static int sw_aes_ops_set_key_for_key_slot(struct udevice *dev, u32 key_size, + u8 *key, u8 slot) +{ + struct sw_aes_priv *priv = dev_get_priv(dev); + + if (slot >= SW_KEY_SLOTS) + return 1; + + memcpy(priv->key_slots[slot], key, key_size / 8); + + if (priv->selected_slot == slot) + priv->selected_key_size = key_size; + + priv->key_expanded = 0; + + return 0; +} + +static int sw_aes_ops_aes_ecb_encrypt(struct udevice *dev, u8 *src, u8 *dst, + u32 num_aes_blocks) +{ + struct sw_aes_priv *priv = dev_get_priv(dev); + int ret; + + ret = prepare_aes(priv); + if (ret) + return ret; + + while (num_aes_blocks > 0) { + aes_encrypt(priv->selected_key_size, src, priv->key_schedule, dst); + num_aes_blocks -= 1; + src += AES_BLOCK_LENGTH; + dst += AES_BLOCK_LENGTH; + } + + return 0; +} + +static int sw_aes_ops_aes_ecb_decrypt(struct udevice *dev, u8 *src, u8 *dst, + u32 num_aes_blocks) +{ + struct sw_aes_priv *priv = dev_get_priv(dev); + int ret; + + ret = prepare_aes(priv); + if (ret) + return ret; + + while (num_aes_blocks > 0) { + aes_decrypt(priv->selected_key_size, src, priv->key_schedule, dst); + num_aes_blocks -= 1; + src += AES_BLOCK_LENGTH; + dst += AES_BLOCK_LENGTH; + } + + return 0; +} + +static int sw_aes_ops_aes_cbc_encrypt(struct udevice *dev, u8 *iv, u8 *src, + u8 *dst, u32 num_aes_blocks) +{ + struct sw_aes_priv *priv = dev_get_priv(dev); + int ret; + + ret = prepare_aes(priv); + if (ret) + return ret; + + aes_cbc_encrypt_blocks(priv->selected_key_size, priv->key_schedule, iv, + src, dst, num_aes_blocks); + + return 0; +} + +static int sw_aes_ops_aes_cbc_decrypt(struct udevice *dev, u8 *iv, u8 *src, + u8 *dst, u32 num_aes_blocks) +{ + struct sw_aes_priv *priv = dev_get_priv(dev); + int ret; + + ret = prepare_aes(priv); + if (ret) + return ret; + + aes_cbc_decrypt_blocks(priv->selected_key_size, priv->key_schedule, + iv, src, dst, num_aes_blocks); + + return 0; +} + +static const struct aes_ops aes_ops_sw = { + .available_key_slots = sw_aes_ops_available_key_slots, + .select_key_slot = sw_aes_ops_select_key_slot, + .set_key_for_key_slot = sw_aes_ops_set_key_for_key_slot, + .aes_ecb_encrypt = sw_aes_ops_aes_ecb_encrypt, + .aes_ecb_decrypt = sw_aes_ops_aes_ecb_decrypt, + .aes_cbc_encrypt = sw_aes_ops_aes_cbc_encrypt, + .aes_cbc_decrypt = sw_aes_ops_aes_cbc_decrypt, +}; + +static const struct udevice_id sw_aes_ids[] = { + { .compatible = "software-aes-engine" }, + { } +}; + +U_BOOT_DRIVER(aes_sw) = { + .name = "aes_sw", + .id = UCLASS_AES, + .of_match = sw_aes_ids, + .ops = &aes_ops_sw, + .priv_auto = sizeof(struct sw_aes_priv), +}; |