/*
 * Copyright (c) 2019 Winner Microelectronics Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-05-17     tyx          1st version
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <stdlib.h>
#include <string.h>
#include "drv_crypto.h"
#include "wm_crypto_hard.h"

// #define WM_HWCRYPTO_NOT_LOCK
// #define WM_HWCRYPTO_NOT_ALIGN_CHECK

extern u32 tls_crypto_crc_update_adv(u32 crc_val, CRYPTO_CRC_TYPE type, u8 mode, const unsigned char *in, u32 len);
extern int tls_crypto_des_encrypt_decrypt_adv(unsigned char *key, unsigned char *IV, const unsigned char *in, unsigned char *out, u32 len, CRYPTO_MODE cbc, CRYPTO_WAY dec);
extern int tls_crypto_3des_encrypt_decrypt_adv(unsigned char *key, unsigned char *IV, const unsigned char *in, unsigned char *out, u32 len, CRYPTO_MODE cbc, CRYPTO_WAY dec);
extern int tls_crypto_aes_encrypt_decrypt_adv(unsigned char *key, unsigned char *IV, const unsigned char *in, unsigned char *out, u32 len, CRYPTO_MODE cbc, CRYPTO_WAY dec);
extern int tls_crypto_rc4_adv(unsigned char *key, u32 keylen, const unsigned char *in, unsigned char *out, u32 len);

struct wm_hwcrypto_device
{
    struct rt_hwcrypto_device dev;
    struct rt_mutex mutex;
};

struct hash_ctx_des
{
    psDigestContext_t contex;
};

static rt_uint32_t _rng_rand(struct hwcrypto_rng *ctx)
{
    rt_uint32_t rand_num;
    struct wm_hwcrypto_device *_hwcrypto = (struct wm_hwcrypto_device *)ctx->parent.device;

#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_take(&_hwcrypto->mutex, RT_WAITING_FOREVER);
#endif
    tls_crypto_random_init((u32)rt_tick_get(), CRYPTO_RNG_SWITCH_32);
    tls_crypto_random_bytes((unsigned char *)&rand_num, sizeof(rand_num));
    tls_crypto_random_stop();
#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_release(&_hwcrypto->mutex);
#endif

    return rand_num;
}

static rt_uint32_t _crc_update(struct hwcrypto_crc *ctx, const rt_uint8_t *in, rt_size_t length)
{
    rt_uint32_t crc_result;
    CRYPTO_CRC_TYPE type;
    u8 mode = 0;
    struct wm_hwcrypto_device *_hwcrypto = (struct wm_hwcrypto_device *)ctx->parent.device;
    unsigned char align_flag = 0;

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (((rt_uint32_t)in % 4) != 0)
    {
        void *temp;
        temp = rt_malloc(length);
        if (temp)
        {
            memcpy(temp, in, length);
            in = temp;
            align_flag = 1;
        }
        else
        {
            return 0;
        }
    }
#endif

    switch (ctx->crc_cfg.poly)
    {
    case 0x04C11DB7:
        type = CRYPTO_CRC_TYPE_32;
        break;
    case 0x00001021:
        type = CRYPTO_CRC_TYPE_16_CCITT;
        break;
    case 0x00008005:
        type = CRYPTO_CRC_TYPE_16_MODBUS;
        break;
    case 0x00000007:
    case 0x00000207:
        type = CRYPTO_CRC_TYPE_8;
        break;
    default:
        return 0;
    }

    mode |= ctx->crc_cfg.flags & CRC_FLAG_REFOUT ? OUTPUT_REFLECT : 0;
    mode |= ctx->crc_cfg.flags & CRC_FLAG_REFIN ? INPUT_REFLECT : 0;

#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_take(&_hwcrypto->mutex, RT_WAITING_FOREVER);
#endif
    crc_result = tls_crypto_crc_update_adv(ctx->crc_cfg.last_val, type, mode, in, length);
#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_release(&_hwcrypto->mutex);
#endif

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (align_flag)
    {
        rt_free((rt_uint8_t *)in);
    }
#endif

    ctx->crc_cfg.last_val = crc_result;
    return crc_result ^ 0x00 ^ ctx->crc_cfg.xorout;
}

static rt_err_t _hash_update(struct hwcrypto_hash *ctx, const rt_uint8_t *in, rt_size_t length)
{
    rt_err_t err = RT_EOK;
    struct wm_hwcrypto_device *_hwcrypto = (struct wm_hwcrypto_device *)ctx->parent.device;
    unsigned char align_flag = 0;

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (((rt_uint32_t)in % 4) != 0)
    {
        void *temp;
        temp = rt_malloc(length);
        if (temp)
        {
            memcpy(temp, in, length);
            in = temp;
            align_flag = 1;
        }
        else
        {
            return -RT_ENOMEM;
        }
    }
#endif

#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_take(&_hwcrypto->mutex, RT_WAITING_FOREVER);
#endif
    switch (ctx->parent.type & HWCRYPTO_MAIN_TYPE_MASK)
    {
    case HWCRYPTO_TYPE_MD5:
        tls_crypto_md5_update(&((struct hash_ctx_des *)(ctx->parent.contex))->contex, in, length);
        break;
    case HWCRYPTO_TYPE_SHA1:
        tls_crypto_sha1_update(&((struct hash_ctx_des *)(ctx->parent.contex))->contex, in, length);
        break;
    default:
        err = -RT_ERROR;
        break;
    }
#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_release(&_hwcrypto->mutex);
#endif

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (align_flag)
    {
        rt_free((rt_uint8_t *)in);
    }
#endif

    return err;
}

static rt_err_t _hash_finish(struct hwcrypto_hash *ctx, rt_uint8_t *out, rt_size_t length)
{
    rt_err_t err = RT_EOK;
    struct wm_hwcrypto_device *_hwcrypto = (struct wm_hwcrypto_device *)ctx->parent.device;

#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_take(&_hwcrypto->mutex, RT_WAITING_FOREVER);
#endif
    switch (ctx->parent.type & HWCRYPTO_MAIN_TYPE_MASK)
    {
    case HWCRYPTO_TYPE_MD5:
        tls_crypto_md5_final(&((struct hash_ctx_des *)(ctx->parent.contex))->contex, out);
        break;
    case HWCRYPTO_TYPE_SHA1:
        tls_crypto_sha1_final(&((struct hash_ctx_des *)(ctx->parent.contex))->contex, out);
        break;
    default:
        err = -RT_ERROR;
        break;
    }
#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_release(&_hwcrypto->mutex);
#endif

    return err;
}

static rt_err_t _des_crypt(struct hwcrypto_symmetric *symmetric_ctx, struct hwcrypto_symmetric_info *symmetric_info)
{
    CRYPTO_WAY mode;
    CRYPTO_MODE cbc;
    struct wm_hwcrypto_device *_hwcrypto = (struct wm_hwcrypto_device *)symmetric_ctx->parent.device;
    unsigned char *in, *out, align_flag = 0;

    if ((symmetric_ctx->key_bitlen >> 3) != 8
            || (symmetric_info->length % 8) != 0)
    {
        return -RT_EINVAL;
    }

    in = (unsigned char *)symmetric_info->in;
    out = (unsigned char *)symmetric_info->out;

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (((rt_uint32_t)in % 4) != 0 || ((rt_uint32_t)out % 4) != 0)
    {
        in = rt_malloc(symmetric_info->length);
        if (in)
        {
            memcpy(in, symmetric_info->in, symmetric_info->length);
            out = in;
            align_flag = 1;
        }
        else
        {
            return -RT_ENOMEM;
        }
    }
#endif

    mode = symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT ? CRYPTO_WAY_ENCRYPT : CRYPTO_WAY_DECRYPT;

    switch (symmetric_ctx->parent.type & (HWCRYPTO_MAIN_TYPE_MASK | HWCRYPTO_SUB_TYPE_MASK))
    {
    case HWCRYPTO_TYPE_DES_ECB:
        cbc = CRYPTO_MODE_ECB;
        break;
    case HWCRYPTO_TYPE_DES_CBC:
        cbc = CRYPTO_MODE_CBC;
        break;
    default :
        return -RT_ERROR;
    }

#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_take(&_hwcrypto->mutex, RT_WAITING_FOREVER);
#endif
    tls_crypto_des_encrypt_decrypt_adv(symmetric_ctx->key, symmetric_ctx->iv,
                                       symmetric_info->in, symmetric_info->out,
                                       symmetric_info->length, cbc, mode);
#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_release(&_hwcrypto->mutex);
#endif

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (align_flag)
    {
        memcpy(symmetric_info->out, out, symmetric_info->length);
        rt_free(in);
    }
#endif

    return RT_EOK;
}

static rt_err_t _des3_crypt(struct hwcrypto_symmetric *symmetric_ctx, struct hwcrypto_symmetric_info *symmetric_info)
{
    CRYPTO_WAY mode;
    CRYPTO_MODE cbc;
    struct wm_hwcrypto_device *_hwcrypto = (struct wm_hwcrypto_device *)symmetric_ctx->parent.device;
    unsigned char *in, *out, align_flag = 0;

    if ((symmetric_ctx->key_bitlen >> 3) != 24
            || (symmetric_info->length % 8) != 0)
    {
        return -RT_EINVAL;
    }

    in = (unsigned char *)symmetric_info->in;
    out = (unsigned char *)symmetric_info->out;

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (((rt_uint32_t)in % 4) != 0 || ((rt_uint32_t)out % 4) != 0)
    {
        in = rt_malloc(symmetric_info->length);
        if (in)
        {
            memcpy(in, symmetric_info->in, symmetric_info->length);
            out = in;
            align_flag = 1;
        }
        else
        {
            return -RT_ENOMEM;
        }
    }
#endif

    mode = symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT ? CRYPTO_WAY_ENCRYPT : CRYPTO_WAY_DECRYPT;

    switch (symmetric_ctx->parent.type & (HWCRYPTO_MAIN_TYPE_MASK | HWCRYPTO_SUB_TYPE_MASK))
    {
    case HWCRYPTO_TYPE_3DES_ECB:
        cbc = CRYPTO_MODE_ECB;
        break;
    case HWCRYPTO_TYPE_3DES_CBC:
        cbc = CRYPTO_MODE_CBC;
        break;
    default :
        return -RT_ERROR;
    }

#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_take(&_hwcrypto->mutex, RT_WAITING_FOREVER);
#endif
    tls_crypto_3des_encrypt_decrypt_adv(symmetric_ctx->key, symmetric_ctx->iv,
                                        symmetric_info->in, symmetric_info->out,
                                        symmetric_info->length, cbc, mode);
#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_release(&_hwcrypto->mutex);
#endif

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (align_flag)
    {
        memcpy(symmetric_info->out, out, symmetric_info->length);
        rt_free(in);
    }
#endif

    return RT_EOK;
}

static rt_err_t _rc4_crypt(struct hwcrypto_symmetric *symmetric_ctx, struct hwcrypto_symmetric_info *symmetric_info)
{
    struct wm_hwcrypto_device *_hwcrypto = (struct wm_hwcrypto_device *)symmetric_ctx->parent.device;
    unsigned char *in, *out, align_flag = 0;

    if ((symmetric_ctx->key_bitlen >> 3) != 16)
    {
        return -RT_EINVAL;
    }

    in = (unsigned char *)symmetric_info->in;
    out = (unsigned char *)symmetric_info->out;

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (((rt_uint32_t)in % 4) != 0 || ((rt_uint32_t)out % 4) != 0)
    {
        in = rt_malloc(symmetric_info->length);
        if (in)
        {
            memcpy(in, symmetric_info->in, symmetric_info->length);
            out = in;
            align_flag = 1;
        }
        else
        {
            return -RT_ENOMEM;
        }
    }
#endif

#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_take(&_hwcrypto->mutex, RT_WAITING_FOREVER);
#endif
    tls_crypto_rc4_adv(symmetric_ctx->key, symmetric_ctx->key_bitlen >> 3,
                       (unsigned char *)symmetric_info->in,
                       symmetric_info->out,
                       symmetric_info->length);
#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_release(&_hwcrypto->mutex);
#endif

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (align_flag)
    {
        memcpy(symmetric_info->out, out, symmetric_info->length);
        rt_free(in);
    }
#endif

    return RT_EOK;
}

static rt_err_t _aes_crypt(struct hwcrypto_symmetric *symmetric_ctx, struct hwcrypto_symmetric_info *symmetric_info)
{
    CRYPTO_WAY mode;
    CRYPTO_MODE cbc;
    struct wm_hwcrypto_device *_hwcrypto = (struct wm_hwcrypto_device *)symmetric_ctx->parent.device;
    unsigned char *in, *out, align_flag = 0;

    if ((symmetric_ctx->key_bitlen >> 3) != 16
            || (symmetric_info->length % 16) != 0)
    {
        return -RT_EINVAL;
    }

    in = (unsigned char *)symmetric_info->in;
    out = (unsigned char *)symmetric_info->out;

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (((rt_uint32_t)in % 4) != 0 || ((rt_uint32_t)out % 4) != 0)
    {
        in = rt_malloc(symmetric_info->length);
        if (in)
        {
            memcpy(in, symmetric_info->in, symmetric_info->length);
            out = in;
            align_flag = 1;
        }
        else
        {
            return -RT_ENOMEM;
        }
    }
#endif

    mode = symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT ? CRYPTO_WAY_ENCRYPT : CRYPTO_WAY_DECRYPT;

    switch (symmetric_ctx->parent.type & (HWCRYPTO_MAIN_TYPE_MASK | HWCRYPTO_SUB_TYPE_MASK))
    {
    case HWCRYPTO_TYPE_AES_ECB:
        cbc = CRYPTO_MODE_ECB;
        break;
    case HWCRYPTO_TYPE_AES_CBC:
        cbc = CRYPTO_MODE_CBC;
        break;
    case HWCRYPTO_TYPE_AES_CTR:
        cbc = CRYPTO_MODE_CTR;
        break;
    default :
        return -RT_ERROR;
    }

#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_take(&_hwcrypto->mutex, RT_WAITING_FOREVER);
#endif
    tls_crypto_aes_encrypt_decrypt_adv(symmetric_ctx->key, symmetric_ctx->iv,
                                       in, out, symmetric_info->length, cbc, mode);
#if !defined(WM_HWCRYPTO_NOT_LOCK)
    rt_mutex_release(&_hwcrypto->mutex);
#endif

#if !defined(WM_HWCRYPTO_NOT_ALIGN_CHECK)
    if (align_flag)
    {
        memcpy(symmetric_info->out, out, symmetric_info->length);
        rt_free(in);
    }
#endif

    return RT_EOK;
}

/**< a = b ^ c (mod d) */
static rt_err_t _bignum_exptmod(struct hwcrypto_bignum *bignum_ctx,
                    struct hw_bignum_mpi *x,
                    const struct hw_bignum_mpi *a,
                    const struct hw_bignum_mpi *b,
                    const struct hw_bignum_mpi *c)
{
    pstm_int pa, pb, pm, pres;
    u32 * buff_a = NULL;
    u32 * buff_b = NULL;
    u32 * buff_m = NULL;
    int err = -1;
    void *buff;
    int buff_len;

    pstm_init(NULL, &pres);

    buff_a = tls_mem_alloc(a->total);
    if(buff_a == NULL)
        goto out;
    buff_b = tls_mem_alloc(b->total);
    if(buff_b == NULL)
        goto out;
    buff_m = tls_mem_alloc(c->total);
    if(buff_m == NULL)
        goto out;

    memset(buff_a, 0, a->total);
    memset(buff_b, 0, b->total);
    memset(buff_m, 0, c->total);

    memcpy(buff_a, a->p, a->total);
    memcpy(buff_b, b->p, b->total);
    memcpy(buff_m, c->p, c->total);

    pstm_reverse((unsigned char *)buff_a, a->total);
    pstm_reverse((unsigned char *)buff_b, b->total);
    pstm_reverse((unsigned char *)buff_m, c->total);

//    *((volatile unsigned int *)0x40000710) = *((volatile unsigned int *)0x40000710) | (0x1 << 28);

    if ((err = pstm_init_for_read_unsigned_bin(NULL, &pa, a->total)) != PS_SUCCESS){
        goto out;
    }
    if ((err = pstm_read_unsigned_bin(&pa, (unsigned char *)buff_a, a->total)) != PS_SUCCESS) {
        goto out;
    }
    if ((err = pstm_init_for_read_unsigned_bin(NULL, &pb, b->total)) != PS_SUCCESS){
        goto out;
    }
    if ((err = pstm_read_unsigned_bin(&pb, (unsigned char *)buff_b, b->total)) != PS_SUCCESS) {
        goto out;
    }
    if ((err = pstm_init_for_read_unsigned_bin(NULL, &pm, c->total)) != PS_SUCCESS){
        goto out;
    }
    if ((err = pstm_read_unsigned_bin(&pm, (unsigned char *)buff_m, c->total)) != PS_SUCCESS) {
        goto out;
    }

    tls_crypto_exptmod(&pa, &pb, &pm, &pres);
    buff_len = pstm_unsigned_bin_size(&pres);
    buff = rt_malloc(buff_len);
    pstm_to_unsigned_bin_nr(NULL, &pres, buff);
    x->sign = pres.sign;
    x->p = buff;
    x->total = buff_len;

out:
    if(buff_a)
        tls_mem_free(buff_a);
    if(buff_b)
        tls_mem_free(buff_b);
    if(buff_m)
        tls_mem_free(buff_m);

    pstm_clear(&pa);
    pstm_clear(&pb);
    pstm_clear(&pm);
    pstm_clear(&pres);

    if (a->sign < 0)
    {
        rt_kprintf("a->sign < 0\n");
    }

    return err == PS_SUCCESS ? RT_EOK : -RT_ERROR;
}

static const struct hwcrypto_symmetric_ops aes_ops =
{
    .crypt = _aes_crypt,
};

static const struct hwcrypto_symmetric_ops rc4_ops =
{
    .crypt = _rc4_crypt,
};

static const struct hwcrypto_symmetric_ops des_ops =
{
    .crypt = _des_crypt,
};

static const struct hwcrypto_symmetric_ops des3_ops =
{
    .crypt = _des3_crypt,
};

static const struct hwcrypto_hash_ops hash_ops =
{
    .update = _hash_update,
    .finish = _hash_finish,
};

static const struct hwcrypto_rng_ops rng_ops =
{
    .update = _rng_rand,
};

static const struct hwcrypto_crc_ops crc_ops =
{
    .update = _crc_update,
};

static const struct hwcrypto_bignum_ops bignum_ops =
{
    .add = RT_NULL,
    .sub = RT_NULL,
    .mul = RT_NULL,
    .mulmod = RT_NULL,
    .exptmod = _bignum_exptmod,
};

static rt_err_t _crypto_create(struct rt_hwcrypto_ctx *ctx)
{
    rt_err_t res = RT_EOK;
    void *contex;

    switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK)
    {
    case HWCRYPTO_TYPE_AES :
        ctx->contex = RT_NULL;
        ((struct hwcrypto_symmetric *)ctx)->ops = &aes_ops;
        break;
    case HWCRYPTO_TYPE_RC4 :
        ctx->contex = RT_NULL;
        ((struct hwcrypto_symmetric *)ctx)->ops = &rc4_ops;
        break;
    case HWCRYPTO_TYPE_MD5:
    case HWCRYPTO_TYPE_SHA1:
        contex = rt_malloc(sizeof(struct hash_ctx_des));
        if (contex == RT_NULL)
        {
            return -RT_ENOMEM;
        }
        memset(contex, 0, sizeof(struct hash_ctx_des));
        ctx->contex = contex;
        ((struct hwcrypto_hash *)ctx)->ops = &hash_ops;
        if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_MD5)
        {
            tls_crypto_md5_init(&((struct hash_ctx_des *)contex)->contex);
        }
        else
        {
            tls_crypto_sha1_init(&((struct hash_ctx_des *)contex)->contex);
        }
        break;
    case HWCRYPTO_TYPE_DES:
        ctx->contex = RT_NULL;
        ((struct hwcrypto_symmetric *)ctx)->ops = &des_ops;
        break;
    case HWCRYPTO_TYPE_3DES:
        ctx->contex = RT_NULL;
        ((struct hwcrypto_symmetric *)ctx)->ops = &des3_ops;
        break;
    case HWCRYPTO_TYPE_RNG:
        ctx->contex = RT_NULL;
        ((struct hwcrypto_rng *)ctx)->ops = &rng_ops;
        ctx->contex = RT_NULL;
        break;
    case HWCRYPTO_TYPE_CRC:
        ctx->contex = RT_NULL;
        ((struct hwcrypto_crc *)ctx)->ops = &crc_ops;
        break;
    case HWCRYPTO_TYPE_BIGNUM:
        ((struct hwcrypto_bignum *)ctx)->ops = &bignum_ops;
        break;
    default:
        res = -RT_ERROR;
        break;
    }

    return res;
}

static void _crypto_destroy(struct rt_hwcrypto_ctx *ctx)
{
    rt_free(ctx->contex);
}

static rt_err_t _crypto_clone(struct rt_hwcrypto_ctx *des, const struct rt_hwcrypto_ctx *src)
{
    rt_err_t res = RT_EOK;

    switch (src->type & HWCRYPTO_MAIN_TYPE_MASK)
    {
    case HWCRYPTO_TYPE_AES:
    case HWCRYPTO_TYPE_RC4:
    case HWCRYPTO_TYPE_RNG:
    case HWCRYPTO_TYPE_CRC:
    case HWCRYPTO_TYPE_BIGNUM:
        break;
    case HWCRYPTO_TYPE_MD5:
    case HWCRYPTO_TYPE_SHA1:
        if (des->contex && src->contex)
        {
            rt_memcpy(des->contex, src->contex, sizeof(struct hash_ctx_des));
        }
        break;
    default:
        res = -RT_ERROR;
        break;
    }

    return res;
}

static void _crypto_reset(struct rt_hwcrypto_ctx *ctx)
{
    switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK)
    {
    case HWCRYPTO_TYPE_AES:
    case HWCRYPTO_TYPE_RC4:
    case HWCRYPTO_TYPE_RNG:
    case HWCRYPTO_TYPE_CRC:
        break;
    case HWCRYPTO_TYPE_MD5:
        tls_crypto_md5_init(&((struct hash_ctx_des *)(ctx->contex))->contex);
        break;
    case HWCRYPTO_TYPE_SHA1:
        tls_crypto_sha1_init(&((struct hash_ctx_des *)(ctx->contex))->contex);
        break;
    default:
        break;
    }
}

static const struct rt_hwcrypto_ops _ops =
{
    .create = _crypto_create,
    .destroy = _crypto_destroy,
    .copy = _crypto_clone,
    .reset = _crypto_reset,
};

extern u8 *wpa_supplicant_get_mac(void);

int wm_hw_crypto_device_init(void)
{
    static struct wm_hwcrypto_device _crypto_dev;

    _crypto_dev.dev.ops = &_ops;
    _crypto_dev.dev.id = 0;
    rt_memcpy(&_crypto_dev.dev.id, wpa_supplicant_get_mac(),
        sizeof(_crypto_dev.dev.id) > 6 ?
        6 : sizeof(_crypto_dev.dev.id));
    _crypto_dev.dev.user_data = &_crypto_dev;

    if (rt_hwcrypto_register(&_crypto_dev.dev,
                             RT_HWCRYPTO_DEFAULT_NAME) != RT_EOK)
    {
        return -1;
    }
    rt_mutex_init(&_crypto_dev.mutex, RT_HWCRYPTO_DEFAULT_NAME, RT_IPC_FLAG_PRIO);
    return 0;
}
INIT_DEVICE_EXPORT(wm_hw_crypto_device_init);