summaryrefslogtreecommitdiff
path: root/drivers/crypto/aes/aes-sw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto/aes/aes-sw.c')
-rw-r--r--drivers/crypto/aes/aes-sw.c167
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),
+};