blob: 76cb1d0a939cdf006287f4fb32094dec075b8d97 [file] [log] [blame]
/****************************************************************************
* arch/risc-v/src/esp32c3-legacy/esp32c3_crypto.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <stddef.h>
#include <sys/queue.h>
#include <crypto/cryptodev.h>
#include <crypto/xform.h>
#include <nuttx/kmalloc.h>
#include <nuttx/crypto/crypto.h>
#include "esp32c3_sha.h"
#include "esp32c3_aes.h"
/****************************************************************************
* Private Functions Prototypes
****************************************************************************/
static void sha1_init(void *ctx);
static int sha1_update(void *ctx, const uint8_t *in, size_t len);
static void sha1_final(uint8_t *out, void *ctx);
static void sha256_init(void *ctx);
static int sha256_update(void *ctx, const uint8_t *in, size_t len);
static void sha256_final(uint8_t *out, void *ctx);
static int esp32c3_freesession(uint64_t tid);
/****************************************************************************
* Private Data
****************************************************************************/
SLIST_HEAD(esp32c3_crypto_list, esp32c3_crypto_data);
static struct esp32c3_crypto_list *g_esp32c3_sessions = NULL;
static uint32_t g_esp32c3_sesnum = 0;
const struct auth_hash g_auth_hash_hmac_sha1_esp32c3 =
{
CRYPTO_SHA1_HMAC, "HMAC-SHA1",
20, 20, 12, sizeof(struct esp32c3_sha1_context_s),
HMAC_SHA1_BLOCK_LEN,
sha1_init, NULL, NULL,
sha1_update,
sha1_final
};
const struct auth_hash g_auth_hash_hmac_sha256_esp32c3 =
{
CRYPTO_SHA2_256_HMAC, "HMAC-SHA2-256",
32, 32, 16, sizeof(struct esp32c3_sha256_context_s),
HMAC_SHA2_256_BLOCK_LEN,
sha256_init, NULL, NULL,
sha256_update,
sha256_final
};
struct esp32c3_crypto_data
{
int alg; /* Algorithm */
union
{
struct
{
uint8_t *ictx;
uint8_t *octx;
uint32_t klen;
const struct auth_hash *axf;
} HWCR_AUTH;
} HWCR_UN;
#define hw_ictx HWCR_UN.HWCR_AUTH.ictx
#define hw_octx HWCR_UN.HWCR_AUTH.octx
#define hw_klen HWCR_UN.HWCR_AUTH.klen
#define hw_axf HWCR_UN.HWCR_AUTH.axf
SLIST_ENTRY(esp32c3_crypto_data) next;
};
/****************************************************************************
* Private Functions
****************************************************************************/
static void sha1_init(void *ctx)
{
esp32c3_sha1_starts(ctx);
}
static int sha1_update(void *ctx, const uint8_t *in, size_t len)
{
return esp32c3_sha1_update((struct esp32c3_sha1_context_s *)ctx,
(const unsigned char *)in,
(size_t)len);
}
static void sha1_final(uint8_t *out, void *ctx)
{
esp32c3_sha1_finish((struct esp32c3_sha1_context_s *)ctx,
(unsigned char *)out);
}
static void sha256_init(void *ctx)
{
esp32c3_sha256_starts(ctx, false);
}
static int sha256_update(void *ctx, const uint8_t *in, size_t len)
{
return esp32c3_sha256_update((struct esp32c3_sha256_context_s *)ctx,
(const unsigned char *)in,
(size_t)len);
}
static void sha256_final(uint8_t *out, void *ctx)
{
esp32c3_sha256_finish((struct esp32c3_sha256_context_s *)ctx,
(unsigned char *)out);
}
/****************************************************************************
* Name: authcompute
*
* Description:
* Calculate the hash.
*
****************************************************************************/
static int authcompute(struct cryptop *crp, struct cryptodesc *crd,
struct esp32c3_crypto_data *data,
caddr_t buf)
{
unsigned char aalg[AALG_MAX_RESULT_LEN];
const struct auth_hash *axf;
int err = 0;
if (data->hw_ictx == 0)
{
return -EINVAL;
}
axf = data->hw_axf;
err = axf->update(data->hw_ictx, (uint8_t *)buf, crd->crd_len);
if (err)
{
return err;
}
if (crd->crd_flags & CRD_F_ESN)
{
axf->update(data->hw_ictx, crd->crd_esn, 4);
}
switch (data->alg)
{
case CRYPTO_SHA1_HMAC:
case CRYPTO_SHA2_256_HMAC:
if (data->hw_octx == NULL)
{
return -EINVAL;
}
axf->final(aalg, data->hw_ictx);
axf->update(data->hw_octx, aalg, axf->hashsize);
axf->final(aalg, data->hw_octx);
break;
}
/* Inject the authentication data */
bcopy(aalg, crp->crp_mac, axf->hashsize);
return 0;
}
/****************************************************************************
* Name: esp32c3_newsession
*
* Description:
* create new session for crypto.
*
****************************************************************************/
static int esp32c3_newsession(uint32_t *sid, struct cryptoini *cri)
{
struct esp32c3_crypto_list *session;
struct esp32c3_crypto_data *prev = NULL;
struct esp32c3_crypto_data *data;
const struct auth_hash *axf;
int i;
int k;
if (sid == NULL || cri == NULL)
{
return -EINVAL;
}
for (i = 0; i < g_esp32c3_sesnum; i++)
{
if (SLIST_EMPTY(&g_esp32c3_sessions[i]))
{
break;
}
}
if (i >= g_esp32c3_sesnum)
{
if (g_esp32c3_sessions == NULL)
{
g_esp32c3_sesnum = 1;
}
else
{
g_esp32c3_sesnum *= 2;
}
session = kmm_calloc(g_esp32c3_sesnum,
sizeof(struct esp32c3_crypto_list));
if (session == NULL)
{
g_esp32c3_sesnum /= 2;
return -ENOBUFS;
}
if (g_esp32c3_sessions != NULL)
{
bcopy(g_esp32c3_sessions, session, (g_esp32c3_sesnum / 2) *
sizeof(struct esp32c3_crypto_list));
kmm_free(g_esp32c3_sessions);
}
g_esp32c3_sessions = session;
}
session = &g_esp32c3_sessions[i];
*sid = i;
while (cri)
{
data = kmm_malloc(sizeof(struct esp32c3_crypto_data));
if (data == NULL)
{
esp32c3_freesession(i);
return -ENOBUFS;
}
switch (cri->cri_alg)
{
case CRYPTO_AES_CBC:
break;
case CRYPTO_AES_CTR:
if ((cri->cri_klen / 8 - 4) != 16 &&
(cri->cri_klen / 8 -4) != 32)
{
/* esp32c3 aes-ctr key bits just support 128 & 256 */
esp32c3_freesession(i);
kmm_free(data);
return -EINVAL;
}
break;
case CRYPTO_SHA1_HMAC:
axf = &g_auth_hash_hmac_sha1_esp32c3;
goto common;
case CRYPTO_SHA2_256_HMAC:
axf = &g_auth_hash_hmac_sha256_esp32c3;
goto common;
common:
data->hw_ictx = kmm_malloc(axf->ctxsize);
if (data->hw_ictx == NULL)
{
kmm_free(data);
return -ENOBUFS;
}
data->hw_octx = kmm_malloc(axf->ctxsize);
if (data->hw_octx == NULL)
{
kmm_free(data->hw_ictx);
kmm_free(data);
return -ENOBUFS;
}
for (k = 0; k < cri->cri_klen / 8; k++)
{
cri->cri_key[k] ^= HMAC_IPAD_VAL;
}
axf->init(data->hw_ictx);
axf->update(data->hw_ictx, (uint8_t *)cri->cri_key,
cri->cri_klen / 8);
axf->update(data->hw_ictx, hmac_ipad_buffer,
axf->blocksize - (cri->cri_klen / 8));
for (k = 0; k < cri->cri_klen / 8; k++)
{
cri->cri_key[k] ^= (HMAC_IPAD_VAL ^ HMAC_OPAD_VAL);
}
axf->init(data->hw_octx);
axf->update(data->hw_octx, (uint8_t *)cri->cri_key,
cri->cri_klen / 8);
axf->update(data->hw_octx, hmac_opad_buffer,
axf->blocksize - (cri->cri_klen / 8));
for (k = 0; k < cri->cri_klen / 8; k++)
{
cri->cri_key[k] ^= HMAC_OPAD_VAL;
}
data->hw_axf = axf;
break;
default :
esp32c3_freesession(i);
kmm_free(data);
return -EINVAL;
}
if (prev == NULL)
{
SLIST_INSERT_HEAD(session, data, next);
}
else
{
SLIST_INSERT_AFTER(prev, data, next);
}
data->alg = cri->cri_alg;
cri = cri->cri_next;
prev = data;
}
return OK;
}
/****************************************************************************
* Name: esp32c3_freesession
*
* Description:
* free session.
*
****************************************************************************/
static int esp32c3_freesession(uint64_t tid)
{
struct esp32c3_crypto_list *session;
struct esp32c3_crypto_data *data;
const struct auth_hash *axf;
uint32_t sid = ((uint32_t)tid) & 0xffffffff;
if (sid > g_esp32c3_sesnum || SLIST_EMPTY(&g_esp32c3_sessions[sid]))
{
return -EINVAL;
}
session = &g_esp32c3_sessions[sid];
while (!SLIST_EMPTY(session))
{
data = SLIST_FIRST(session);
switch (data->alg)
{
case CRYPTO_SHA1_HMAC:
case CRYPTO_SHA2_256_HMAC:
axf = data->hw_axf;
if (data->hw_ictx)
{
explicit_bzero(data->hw_ictx, axf->ctxsize);
kmm_free(data->hw_ictx);
}
if (data->hw_octx)
{
explicit_bzero(data->hw_octx, axf->ctxsize);
kmm_free(data->hw_octx);
}
break;
}
SLIST_REMOVE_HEAD(session, next);
kmm_free(data);
}
return 0;
}
/****************************************************************************
* Name: esp32c3_process
*
* Description:
* process session to use hardware algorithm.
*
****************************************************************************/
static int esp32c3_process(struct cryptop *crp)
{
struct cryptodesc *crd;
struct esp32c3_crypto_list *session;
struct esp32c3_crypto_data *data;
uint8_t iv[AESCTR_BLOCKSIZE];
uint32_t lid;
int err = 0;
lid = crp->crp_sid & 0xffffffff;
/* Go through crypto descriptors, processing as we go */
session = &g_esp32c3_sessions[lid];
for (crd = crp->crp_desc; crd; crd = crd->crd_next)
{
SLIST_FOREACH(data, session, next)
{
if (data->alg == crd->crd_alg)
{
break;
}
}
if (data == NULL)
{
crp->crp_etype = EINVAL;
return -EINVAL;
}
switch (data->alg)
{
case CRYPTO_AES_CBC:
err = aes_cypher(crp->crp_dst, crp->crp_buf, crd->crd_len,
crd->crd_iv, crd->crd_key, 16, AES_MODE_CBC,
crd->crd_flags & CRD_F_ENCRYPT);
if (err < 0)
{
return err;
}
break;
case CRYPTO_AES_CTR:
memcpy(iv, crd->crd_key + crd->crd_klen / 8 - 4, 4);
memcpy(iv + 4, crd->crd_iv, 8);
iv[15] = 0x1;
err = aes_cypher(crp->crp_dst, crp->crp_buf, crd->crd_len, iv,
crd->crd_key, crd->crd_klen / 8 - 4,
AES_MODE_CTR, crd->crd_flags & CRD_F_ENCRYPT);
if (err < 0)
{
return err;
}
break;
case CRYPTO_SHA1_HMAC:
case CRYPTO_SHA2_256_HMAC:
if ((crp->crp_etype = authcompute(crp, crd, data,
crp->crp_buf)) != 0)
{
return crp->crp_etype;
}
break;
default:
return -EINVAL;
}
}
return OK;
}
/****************************************************************************
* Name: hwcr_init
*
* Description:
* register the hardware crypto driver.
*
****************************************************************************/
void hwcr_init(void)
{
int hwcr_id;
int algs[CRYPTO_ALGORITHM_MAX + 1];
hwcr_id = crypto_get_driverid(0);
DEBUGASSERT(hwcr_id >= 0);
memset(algs, 0, sizeof(algs));
algs[CRYPTO_AES_CBC] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_AES_CTR] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_SHA1_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
algs[CRYPTO_SHA2_256_HMAC] = CRYPTO_ALG_FLAG_SUPPORTED;
esp32c3_sha_init();
crypto_register(hwcr_id, algs, esp32c3_newsession,
esp32c3_freesession, esp32c3_process);
}