// 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),
};