/*
 * SPDX-FileCopyrightText: 2023 Nordic Semiconductor ASA
 * SPDX-FileContributor: 2026 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <string.h>
#include <errno.h>

#include "esp_random.h"
#include "psa/crypto.h"

#include "mesh/common.h"
#include "mesh/crypto.h"
#include "mesh/trace.h"
#include "mesh/config.h"

/* PSA Key ID range for BLE Mesh */
#define BT_MESH_PSA_KEY_ID_MIN      0x0001A000
#define BT_MESH_PSA_KEY_ID_RANGE_SIZE \
    (2 * CONFIG_BLE_MESH_SUBNET_COUNT + 2 * CONFIG_BLE_MESH_APP_KEY_COUNT + 2)

/* Internal DH key pair storage
 *
 * PSA functions expect BIG-ENDIAN format.
 */
static struct {
    bool is_ready;
    psa_key_id_t priv_key_id;
    uint8_t public_key[PUB_KEY_SIZE + 1];  /* Big-endian, PSA format: 0x04 + X + Y */
} dh_pair;

/* Bitmap for tracking allocated key IDs */
static uint32_t pst_keys[(BT_MESH_PSA_KEY_ID_RANGE_SIZE + 31) / 32];

static psa_key_id_t keyid_alloc(void)
{
    for (int i = 0; i < BT_MESH_PSA_KEY_ID_RANGE_SIZE; i++) {
        int word = i / 32;
        int bit = i % 32;
        if (!(pst_keys[word] & (1U << bit))) {
            pst_keys[word] |= (1U << bit);
            return BT_MESH_PSA_KEY_ID_MIN + i;
        }
    }
    return PSA_KEY_ID_NULL;
}

static int keyid_free(psa_key_id_t key_id)
{
    if (key_id >= BT_MESH_PSA_KEY_ID_MIN &&
        key_id < BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE) {
        int idx = key_id - BT_MESH_PSA_KEY_ID_MIN;
        int word = idx / 32;
        int bit = idx % 32;
        pst_keys[word] &= ~(1U << bit);
        return 0;
    }
    return -EIO;
}

static void keyid_assign(psa_key_id_t key_id)
{
    if (key_id >= BT_MESH_PSA_KEY_ID_MIN &&
        key_id < BT_MESH_PSA_KEY_ID_MIN + BT_MESH_PSA_KEY_ID_RANGE_SIZE) {
        int idx = key_id - BT_MESH_PSA_KEY_ID_MIN;
        int word = idx / 32;
        int bit = idx % 32;
        pst_keys[word] |= (1U << bit);
    }
}

int bt_mesh_crypto_init(void)
{
    psa_status_t status = psa_crypto_init();
    if (status != PSA_SUCCESS) {
        BT_ERR("PSA crypto init failed: %d", status);
        return -EIO;
    }

    dh_pair.is_ready = false;
    dh_pair.priv_key_id = PSA_KEY_ID_NULL;
    memset(pst_keys, 0, sizeof(pst_keys));

    return 0;
}

int bt_mesh_encrypt(const struct bt_mesh_key *key, const uint8_t plaintext[16],
                    uint8_t enc_data[16])
{
    size_t output_len;
    psa_status_t status;

    status = psa_cipher_encrypt(key->key, PSA_ALG_ECB_NO_PADDING,
                                plaintext, 16, enc_data, 16, &output_len);

    if (status != PSA_SUCCESS || output_len != 16) {
        BT_ERR("PSA cipher encrypt failed: %d", status);
        return -EIO;
    }

    return 0;
}

int bt_mesh_ccm_encrypt(const struct bt_mesh_key *key, uint8_t nonce[13],
                        const uint8_t *plaintext, size_t len,
                        const uint8_t *aad, size_t aad_len,
                        uint8_t *enc_data, size_t mic_size)
{
    size_t output_len;
    psa_status_t status;
    psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, mic_size);

    status = psa_aead_encrypt(key->key, alg, nonce, 13, aad, aad_len,
                              plaintext, len, enc_data, len + mic_size, &output_len);

    if (status != PSA_SUCCESS || output_len != len + mic_size) {
        BT_ERR("PSA AEAD encrypt failed: %d", status);
        return -EIO;
    }

    return 0;
}

int bt_mesh_ccm_decrypt(const struct bt_mesh_key *key, uint8_t nonce[13],
                        const uint8_t *enc_data, size_t len,
                        const uint8_t *aad, size_t aad_len,
                        uint8_t *plaintext, size_t mic_size)
{
    size_t output_len;
    psa_status_t status;
    psa_algorithm_t alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, mic_size);

    status = psa_aead_decrypt(key->key, alg, nonce, 13, aad, aad_len,
                              enc_data, len + mic_size, plaintext, len, &output_len);

    if (status != PSA_SUCCESS || output_len != len) {
        BT_ERR("PSA AEAD decrypt failed: %d", status);
        return -EIO;
    }

    return 0;
}

int bt_mesh_ccm_encrypt_raw_key(const uint8_t key[16], uint8_t nonce[13],
                                const uint8_t *plaintext, size_t len,
                                const uint8_t *aad, size_t aad_len,
                                uint8_t *enc_data, size_t mic_size)
{
    struct bt_mesh_key mesh_key;
    int err;

    err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CCM, key, &mesh_key);
    if (err) {
        return err;
    }

    err = bt_mesh_ccm_encrypt(&mesh_key, nonce, plaintext, len, aad, aad_len,
                              enc_data, mic_size);

    psa_destroy_key(mesh_key.key);
    return err;
}

int bt_mesh_ccm_decrypt_raw_key(const uint8_t key[16], uint8_t nonce[13],
                                const uint8_t *enc_data, size_t len,
                                const uint8_t *aad, size_t aad_len,
                                uint8_t *plaintext, size_t mic_size)
{
    struct bt_mesh_key mesh_key;
    int err;

    err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CCM, key, &mesh_key);
    if (err) {
        return err;
    }

    err = bt_mesh_ccm_decrypt(&mesh_key, nonce, enc_data, len, aad, aad_len,
                              plaintext, mic_size);

    psa_destroy_key(mesh_key.key);
    return err;
}

int bt_mesh_aes_cmac_mesh_key(const struct bt_mesh_key *key,
                              struct bt_mesh_sg *sg, size_t sg_len,
                              uint8_t mac[16])
{
    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
    psa_status_t status;
    size_t mac_len;

    status = psa_mac_sign_setup(&operation, key->key, PSA_ALG_CMAC);
    if (status != PSA_SUCCESS) {
        BT_ERR("PSA MAC setup failed: %d", status);
        return -EIO;
    }

    for (; sg_len; sg_len--, sg++) {
        status = psa_mac_update(&operation, sg->data, sg->len);
        if (status != PSA_SUCCESS) {
            psa_mac_abort(&operation);
            BT_ERR("PSA MAC update failed: %d", status);
            return -EIO;
        }
    }

    status = psa_mac_sign_finish(&operation, mac, 16, &mac_len);
    if (status != PSA_SUCCESS || mac_len != 16) {
        BT_ERR("PSA MAC finish failed: %d", status);
        return -EIO;
    }

    return 0;
}

int bt_mesh_aes_cmac_raw_key(const uint8_t key[16], struct bt_mesh_sg *sg,
                             size_t sg_len, uint8_t mac[16])
{
    struct bt_mesh_key key_id;
    int err;

    err = bt_mesh_key_import(BT_MESH_KEY_TYPE_CMAC, key, &key_id);
    if (err) {
        return err;
    }

    err = bt_mesh_aes_cmac_mesh_key(&key_id, sg, sg_len, mac);

    psa_destroy_key(key_id.key);

    return err;
}

int bt_mesh_sha256_hmac_raw_key(const uint8_t key[32], struct bt_mesh_sg *sg,
                                size_t sg_len, uint8_t mac[32])
{
    psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_key_id_t key_id;
    psa_status_t status;
    size_t mac_len;
    int err = 0;

    /* Import HMAC key */
    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
    psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
    psa_set_key_algorithm(&attributes, PSA_ALG_HMAC(PSA_ALG_SHA_256));
    psa_set_key_type(&attributes, PSA_KEY_TYPE_HMAC);
    psa_set_key_bits(&attributes, 256);

    status = psa_import_key(&attributes, key, 32, &key_id);
    if (status != PSA_SUCCESS) {
        BT_ERR("PSA import HMAC key failed: %d", status);
        return -EIO;
    }
    psa_reset_key_attributes(&attributes);

    status = psa_mac_sign_setup(&operation, key_id, PSA_ALG_HMAC(PSA_ALG_SHA_256));
    if (status != PSA_SUCCESS) {
        BT_ERR("PSA HMAC setup failed: %d", status);
        err = -EIO;
        goto end;
    }

    for (; sg_len; sg_len--, sg++) {
        status = psa_mac_update(&operation, sg->data, sg->len);
        if (status != PSA_SUCCESS) {
            psa_mac_abort(&operation);
            BT_ERR("PSA HMAC update failed: %d", status);
            err = -EIO;
            goto end;
        }
    }

    status = psa_mac_sign_finish(&operation, mac, 32, &mac_len);
    if (status != PSA_SUCCESS || mac_len != 32) {
        BT_ERR("PSA HMAC finish failed: %d", status);
        err = -EIO;
    }

end:
    psa_destroy_key(key_id);
    return err;
}

int bt_mesh_pub_key_gen(void)
{
    psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t status;
    uint8_t private_key[PRIV_KEY_SIZE];
    size_t key_len;
    int err;

    /* Destroy any existing key */
    if (dh_pair.priv_key_id != PSA_KEY_ID_NULL) {
        psa_destroy_key(dh_pair.priv_key_id);
        dh_pair.priv_key_id = PSA_KEY_ID_NULL;
    }
    dh_pair.is_ready = false;

    /* Generate a random private key (in little-endian format for storage) */
    do {
        err = bt_mesh_rand(private_key, sizeof(private_key));
        if (err) {
            BT_ERR("Failed to generate random private key");
            return err;
        }
        /* Ensure the private key is valid (non-zero first bytes in BE) */
    } while (private_key[0] == 0 && private_key[1] == 0);

    /* Configure key attributes for ECDH with P-256 */
    psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE);
    psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
    psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDH);
    psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_bits(&key_attributes, 256);

    /* Import the private key */
    status = psa_import_key(&key_attributes, private_key, sizeof(private_key),
                            &dh_pair.priv_key_id);
    if (status != PSA_SUCCESS) {
        BT_ERR("PSA import private key failed: %d", status);
        psa_reset_key_attributes(&key_attributes);
        return -EIO;
    }

    /* Export public key (PSA computes it from the private key) */
    status = psa_export_public_key(dh_pair.priv_key_id, dh_pair.public_key,
                                   sizeof(dh_pair.public_key), &key_len);
    if (status != PSA_SUCCESS || key_len != PUB_KEY_SIZE + 1) {
        BT_ERR("PSA export public key failed: %d", status);
        psa_destroy_key(dh_pair.priv_key_id);
        dh_pair.priv_key_id = PSA_KEY_ID_NULL;
        psa_reset_key_attributes(&key_attributes);
        return -EIO;
    }

    dh_pair.is_ready = true;
    psa_reset_key_attributes(&key_attributes);

    return 0;
}

const uint8_t *bt_mesh_pub_key_get_raw(void)
{
    if (!dh_pair.is_ready) {
        if (bt_mesh_pub_key_gen() != 0) {
            return NULL;
        }
    }

    return &dh_pair.public_key[1];
}

void bt_mesh_set_private_key_raw(const uint8_t pri_key[32])
{
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t status;
    size_t key_len;

    /* Destroy any existing key */
    if (dh_pair.priv_key_id != PSA_KEY_ID_NULL) {
        psa_destroy_key(dh_pair.priv_key_id);
        dh_pair.priv_key_id = PSA_KEY_ID_NULL;
    }
    dh_pair.is_ready = false;

    /* Import the provided private key */
    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
    psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
    psa_set_key_algorithm(&attributes, PSA_ALG_ECDH);
    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_bits(&attributes, 256);

    status = psa_import_key(&attributes, pri_key, PRIV_KEY_SIZE, &dh_pair.priv_key_id);
    if (status != PSA_SUCCESS) {
        BT_ERR("PSA import private key failed: %d", status);
        psa_reset_key_attributes(&attributes);
        return;
    }

    /* Export public key (PSA computes it from the private key) */
    status = psa_export_public_key(dh_pair.priv_key_id, dh_pair.public_key,
                                   sizeof(dh_pair.public_key), &key_len);
    if (status != PSA_SUCCESS || key_len != PUB_KEY_SIZE + 1) {
        BT_ERR("PSA export public key failed: %d", status);
        psa_destroy_key(dh_pair.priv_key_id);
        dh_pair.priv_key_id = PSA_KEY_ID_NULL;
        psa_reset_key_attributes(&attributes);
        return;
    }

    BT_DBG("Pubkey:%s", bt_hex(&dh_pair.public_key[1], PUB_KEY_SIZE));
    BT_DBG("Privkey:%s", bt_hex(pri_key, PRIV_KEY_SIZE));
    dh_pair.is_ready = true;
    psa_reset_key_attributes(&attributes);
}

bool bt_mesh_check_public_key_raw(const uint8_t key[64])
{
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_key_id_t key_id;
    psa_status_t status;
    uint8_t pub_be[PUB_KEY_SIZE + 1];

    /* PSA requires 0x04 prefix for uncompressed point */
    pub_be[0] = 0x04;
    /* Convert from little-endian to big-endian */
    memcpy(&pub_be[1], key, 32);
    memcpy(&pub_be[33], key + 32, 32);

    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_VERIFY_HASH);
    psa_set_key_algorithm(&attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
    psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
    psa_set_key_bits(&attributes, 256);

    status = psa_import_key(&attributes, pub_be, sizeof(pub_be), &key_id);
    psa_reset_key_attributes(&attributes);

    if (status != PSA_SUCCESS) {
        return false;
    }

    psa_destroy_key(key_id);
    return true;
}

int bt_mesh_dhkey_gen_raw(const uint8_t *pub_key, const uint8_t *priv_key,
                          uint8_t *dhkey)
{
    psa_key_id_t priv_key_id = PSA_KEY_ID_NULL;
    uint8_t public_key_be[PUB_KEY_SIZE + 1];
    psa_status_t status;
    size_t dh_key_len;
    int err = 0;

    if (priv_key) {
        psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;

        /* Import custom private key */
        psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
        psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
        psa_set_key_algorithm(&attributes, PSA_ALG_ECDH);
        psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
        psa_set_key_bits(&attributes, 256);

        status = psa_import_key(&attributes, priv_key, PRIV_KEY_SIZE, &priv_key_id);
        psa_reset_key_attributes(&attributes);

        if (status != PSA_SUCCESS) {
            BT_ERR("PSA import private key failed: %d", status);
            return -EIO;
        }
    } else {
        priv_key_id = dh_pair.priv_key_id;
    }

    /* Prepare public key with 0x04 prefix in big-endian format */
    public_key_be[0] = 0x04;
    /* Convert from little-endian to big-endian */
    memcpy(public_key_be + 1, pub_key, 32);
    memcpy(public_key_be + 33, pub_key + 32, 32);

    /* Calculate shared secret */
    status = psa_raw_key_agreement(PSA_ALG_ECDH, priv_key_id, public_key_be,
                                   PUB_KEY_SIZE + 1, dhkey, DH_KEY_SIZE, &dh_key_len);

    if (status != PSA_SUCCESS || dh_key_len != DH_KEY_SIZE) {
        BT_ERR("PSA ECDH failed: %d", status);
        err = -EIO;
    }

    if (priv_key && priv_key_id != PSA_KEY_ID_NULL) {
        psa_destroy_key(priv_key_id);
    }

    return err;
}

int bt_mesh_key_import(enum bt_mesh_key_type type, const uint8_t in[16],
                       struct bt_mesh_key *out)
{
    psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_status_t status;
    psa_key_id_t key_id = PSA_KEY_ID_NULL;

    switch (type) {
    case BT_MESH_KEY_TYPE_ECB:
        psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
        psa_set_key_usage_flags(&key_attributes,
            PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
        psa_set_key_algorithm(&key_attributes, PSA_ALG_ECB_NO_PADDING);
        break;
    case BT_MESH_KEY_TYPE_CCM:
        psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
        psa_set_key_usage_flags(&key_attributes,
            PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
        psa_set_key_algorithm(&key_attributes,
            PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 4));
        break;
    case BT_MESH_KEY_TYPE_CMAC:
        psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
        psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
        psa_set_key_algorithm(&key_attributes, PSA_ALG_CMAC);
        break;
    case BT_MESH_KEY_TYPE_NET:
#if CONFIG_BT_SETTINGS
        key_id = keyid_alloc();
        if (key_id == PSA_KEY_ID_NULL) {
            return -ENOMEM;
        }
        psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
        psa_set_key_id(&key_attributes, key_id);
#else
        psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
#endif
        psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_EXPORT);
        break;
    case BT_MESH_KEY_TYPE_APP:
    case BT_MESH_KEY_TYPE_DEV:
#if CONFIG_BT_SETTINGS
        key_id = keyid_alloc();
        if (key_id == PSA_KEY_ID_NULL) {
            return -ENOMEM;
        }
        psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_PERSISTENT);
        psa_set_key_id(&key_attributes, key_id);
#else
        psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
#endif
        psa_set_key_usage_flags(&key_attributes,
            PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_EXPORT);
        psa_set_key_algorithm(&key_attributes,
            PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 4));
        break;
    default:
        return -EINVAL;
    }

    psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
    psa_set_key_bits(&key_attributes, 128);

    status = psa_import_key(&key_attributes, in, 16, &out->key);
    if (status == PSA_ERROR_ALREADY_EXISTS) {
        BT_WARN("Key 0x%04x already exists, destroying and reimporting", key_id);
        psa_destroy_key(key_id);
        status = psa_import_key(&key_attributes, in, 16, &out->key);
    }

    psa_reset_key_attributes(&key_attributes);

    if (status != PSA_SUCCESS) {
        BT_ERR("PSA import key failed: %d", status);
        if (key_id != PSA_KEY_ID_NULL) {
            keyid_free(key_id);
        }
        return -EIO;
    }

    return 0;
}

int bt_mesh_key_export(uint8_t out[16], const struct bt_mesh_key *in)
{
    size_t data_length;
    psa_status_t status;

    status = psa_export_key(in->key, out, 16, &data_length);
    if (status != PSA_SUCCESS || data_length != 16) {
        BT_ERR("PSA export key failed: %d", status);
        return -EIO;
    }

    return 0;
}

void bt_mesh_key_assign(struct bt_mesh_key *dst, const struct bt_mesh_key *src)
{
    memcpy(dst, src, sizeof(struct bt_mesh_key));
#if CONFIG_BT_SETTINGS
    keyid_assign(dst->key);
#endif
}

int bt_mesh_key_destroy(const struct bt_mesh_key *key)
{
    psa_status_t status;

    status = psa_destroy_key(key->key);
    if (status != PSA_SUCCESS) {
        BT_ERR("PSA destroy key failed: %d", status);
        return -EIO;
    }

#if CONFIG_BT_SETTINGS
    return keyid_free(key->key);
#else
    return 0;
#endif
}

int bt_mesh_key_compare(const uint8_t raw_key[16], const struct bt_mesh_key *key)
{
    uint8_t out[16];
    int err;

    err = bt_mesh_key_export(out, key);
    if (err) {
        return err;
    }

    return memcmp(out, raw_key, 16);
}

int bt_mesh_encrypt_le(const uint8_t key[16], const uint8_t plaintext[16],
                       uint8_t enc_data[16])
{
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_key_id_t key_id;
    psa_status_t status;
    uint8_t tmp[16];
    size_t output_len;

    BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));

    /* Swap key bytes (LE to BE) */
    sys_memcpy_swap(tmp, key, 16);

    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
    psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING);
    psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
    psa_set_key_bits(&attributes, 128);

    status = psa_import_key(&attributes, tmp, 16, &key_id);
    psa_reset_key_attributes(&attributes);

    if (status != PSA_SUCCESS) {
        BT_ERR("PSA import key failed: %d", status);
        return -EINVAL;
    }

    /* Swap plaintext bytes and encrypt */
    sys_memcpy_swap(tmp, plaintext, 16);

    status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING,
                                tmp, 16, enc_data, 16, &output_len);

    psa_destroy_key(key_id);

    if (status != PSA_SUCCESS || output_len != 16) {
        BT_ERR("PSA encrypt failed: %d", status);
        return -EINVAL;
    }

    /* Swap result bytes (BE to LE) */
    sys_mem_swap(enc_data, 16);

    BT_DBG("enc_data %s", bt_hex(enc_data, 16));
    return 0;
}

int bt_mesh_encrypt_be(const uint8_t key[16], const uint8_t plaintext[16],
                       uint8_t enc_data[16])
{
    psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
    psa_key_id_t key_id;
    psa_status_t status;
    size_t output_len;

    BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));

    psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_ENCRYPT);
    psa_set_key_algorithm(&attributes, PSA_ALG_ECB_NO_PADDING);
    psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
    psa_set_key_bits(&attributes, 128);

    status = psa_import_key(&attributes, key, 16, &key_id);
    psa_reset_key_attributes(&attributes);

    if (status != PSA_SUCCESS) {
        BT_ERR("PSA import key failed: %d", status);
        return -EINVAL;
    }

    status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING,
                                plaintext, 16, enc_data, 16, &output_len);

    psa_destroy_key(key_id);

    if (status != PSA_SUCCESS || output_len != 16) {
        BT_ERR("PSA encrypt failed: %d", status);
        return -EINVAL;
    }

    BT_DBG("enc_data %s", bt_hex(enc_data, 16));
    return 0;
}

#if 0
int bt_mesh_rand(void *buf, size_t len)
{
    psa_status_t status;

    if (buf == NULL || len == 0) {
        return -EINVAL;
    }

    status = psa_generate_random(buf, len);
    return status == PSA_SUCCESS ? 0 : -EIO;
}
#endif
