Skip to content

Commit

Permalink
crypto: stm32: SAES cipher support
Browse files Browse the repository at this point in the history
Add SAES HW driver, and update OP-TEE cipher hooks to be able to use
SAES or CRYP for cipher algorithms.
SAES and CRYP cannot be enabled at the same time in OP-TEE.

Co-developed-by: Nicolas Toromanoff <nicolas.toromanoff@foss.st.com>
Signed-off-by: Nicolas Toromanoff <nicolas.toromanoff@foss.st.com>
Signed-off-by: Thomas Bourgoin <thomas.bourgoin@foss.st.com>
Reviewed-by: Etienne Carriere <etienne.carriere@foss.st.com>
  • Loading branch information
tbourgoi authored and jforissier committed Aug 22, 2023
1 parent 0981062 commit 4320f5c
Show file tree
Hide file tree
Showing 7 changed files with 1,441 additions and 66 deletions.
211 changes: 171 additions & 40 deletions core/drivers/crypto/stm32/cipher.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,108 @@

#include "common.h"
#include "stm32_cryp.h"
#include "stm32_saes.h"

#define DES3_KEY_SIZE 24

struct cryp_ctx {
struct stm32_cryp_context ctx;
enum stm32_cryp_algo_mode algo;
};

struct saes_ctx {
struct stm32_saes_context ctx;
enum stm32_saes_chaining_mode algo;
};

/*
* Internal peripheral context
* SAES and CRYP are registered under the same ID in the crypto framework.
* Therefore, only one of them can be registered.
*/

union ip_ctx {
struct saes_ctx saes;
struct cryp_ctx cryp;
};

/* Internal Peripheral cipher ops*/
struct ip_cipher_ops {
TEE_Result (*init)(union ip_ctx *ctx, bool is_decrypt,
const uint8_t *key, size_t key_len,
const uint8_t *iv, size_t iv_len);
TEE_Result (*update)(union ip_ctx *ctx, bool last_block, uint8_t *src,
uint8_t *dst, size_t len);
};

struct stm32_cipher_ctx {
struct crypto_cipher_ctx c_ctx;
struct stm32_cryp_context cryp;
enum stm32_cryp_algo_mode algo;
union ip_ctx ip_ctx;
const struct ip_cipher_ops *ops;
};

static TEE_Result cryp_init(union ip_ctx *ip_ctx, bool is_decrypt,
const uint8_t *key, size_t key_len,
const uint8_t *iv, size_t iv_len)
{
uint8_t temp_key[DES3_KEY_SIZE] = { };

if (!IS_ENABLED(CFG_STM32_CRYP))
return TEE_ERROR_NOT_IMPLEMENTED;

if (key_len == 16 &&
(ip_ctx->cryp.algo == STM32_CRYP_MODE_TDES_ECB ||
ip_ctx->cryp.algo == STM32_CRYP_MODE_TDES_CBC)) {
/* Manage DES2: i.e. K=K1.K2.K1 */
memcpy(temp_key, key, key_len);
memcpy(temp_key + key_len, key, key_len / 2);
key_len = DES3_KEY_SIZE;
key = temp_key;
}

return stm32_cryp_init(&ip_ctx->cryp.ctx, is_decrypt, ip_ctx->cryp.algo,
key, key_len, iv, iv_len);
}

static TEE_Result cryp_update(union ip_ctx *ip_ctx, bool last_block,
uint8_t *src, uint8_t *dst, size_t len)
{
if (!IS_ENABLED(CFG_STM32_CRYP))
return TEE_ERROR_NOT_IMPLEMENTED;

return stm32_cryp_update(&ip_ctx->cryp.ctx, last_block, src, dst, len);
}

static TEE_Result saes_init(union ip_ctx *ip_ctx, bool is_decrypt,
const uint8_t *key, size_t key_len,
const uint8_t *iv, size_t iv_len)
{
enum stm32_saes_key_selection key_sel = STM32_SAES_KEY_SOFT;

if (!IS_ENABLED(CFG_STM32_SAES))
return TEE_ERROR_NOT_IMPLEMENTED;

return stm32_saes_init(&ip_ctx->saes.ctx, is_decrypt, ip_ctx->saes.algo,
key_sel, key, key_len, iv, iv_len);
}

static TEE_Result saes_update(union ip_ctx *ip_ctx, bool last_block,
uint8_t *src, uint8_t *dst, size_t len)
{
if (!IS_ENABLED(CFG_STM32_SAES))
return TEE_ERROR_NOT_IMPLEMENTED;

return stm32_saes_update(&ip_ctx->saes.ctx, last_block, src, dst, len);
}

const struct ip_cipher_ops cryp_ops = {
.init = cryp_init,
.update = cryp_update,
};

const struct ip_cipher_ops saes_ops = {
.init = saes_init,
.update = saes_update,
};

static struct stm32_cipher_ctx *
Expand All @@ -35,37 +130,19 @@ to_stm32_cipher_ctx(struct crypto_cipher_ctx *ctx)
static TEE_Result stm32_cipher_initialize(struct drvcrypt_cipher_init *dinit)
{
struct stm32_cipher_ctx *c = to_stm32_cipher_ctx(dinit->ctx);
uint8_t temp_key[DES3_KEY_SIZE] = { 0 };
uint8_t *key = NULL;
size_t key_size = 0;

if (dinit->key1.length == 16 &&
(c->algo == STM32_CRYP_MODE_TDES_ECB ||
c->algo == STM32_CRYP_MODE_TDES_CBC)) {
/* Manage DES2: ie K=K1.K2.K1 */
memcpy(temp_key, dinit->key1.data, dinit->key1.length);
memcpy(temp_key + dinit->key1.length, dinit->key1.data,
dinit->key1.length / 2);
key_size = DES3_KEY_SIZE;
key = temp_key;
} else {
key_size = dinit->key1.length;
key = dinit->key1.data;
}

return stm32_cryp_init(&c->cryp, !dinit->encrypt, c->algo,
key, key_size, dinit->iv.data,
dinit->iv.length);
return c->ops->init(&c->ip_ctx, !dinit->encrypt, dinit->key1.data,
dinit->key1.length, dinit->iv.data,
dinit->iv.length);
}

static TEE_Result stm32_cipher_update(struct drvcrypt_cipher_update *dupdate)
{
struct stm32_cipher_ctx *c = to_stm32_cipher_ctx(dupdate->ctx);
size_t len = MIN(dupdate->src.length, dupdate->dst.length);

return stm32_cryp_update(&c->cryp, dupdate->last,
dupdate->src.data, dupdate->dst.data,
len);
return c->ops->update(&c->ip_ctx, dupdate->last, dupdate->src.data,
dupdate->dst.data, len);
}

static void stm32_cipher_final(void *ctx __unused)
Expand All @@ -87,60 +164,114 @@ static void stm32_cipher_copy_state(void *dst_ctx, void *src_ctx)
memcpy(dst, src, sizeof(*dst));
}

static TEE_Result alloc_ctx(void **ctx, enum stm32_cryp_algo_mode algo)
static TEE_Result alloc_cryp_ctx(void **ctx, enum stm32_cryp_algo_mode algo)
{
struct stm32_cipher_ctx *c = calloc(1, sizeof(*c));

if (!c)
return TEE_ERROR_OUT_OF_MEMORY;

DMSG("Using CRYP %d", algo);
c->ip_ctx.cryp.algo = algo;
c->ops = &cryp_ops;
*ctx = &c->c_ctx;

return TEE_SUCCESS;
}

static TEE_Result alloc_saes_ctx(void **ctx, enum stm32_saes_chaining_mode algo)
{
struct stm32_cipher_ctx *c = calloc(1, sizeof(*c));

if (!c)
return TEE_ERROR_OUT_OF_MEMORY;

c->algo = algo;
DMSG("Using SAES %d", algo);
c->ip_ctx.saes.algo = algo;
c->ops = &saes_ops;
*ctx = &c->c_ctx;

return TEE_SUCCESS;
}

/*
* Allocate the SW cipher data context.
* Allocate the SW cipher data context for CRYP peripheral.
*
* @ctx [out] Caller context variable
* @algo Algorithm ID of the context
*/
static TEE_Result stm32_cipher_allocate(void **ctx, uint32_t algo)
static TEE_Result stm32_cryp_cipher_allocate(void **ctx, uint32_t algo)
{
/*
* Convert TEE_ALGO id to internal id
*/
switch (algo) {
case TEE_ALG_DES_ECB_NOPAD:
return alloc_ctx(ctx, STM32_CRYP_MODE_DES_ECB);
return alloc_cryp_ctx(ctx, STM32_CRYP_MODE_DES_ECB);
case TEE_ALG_DES_CBC_NOPAD:
return alloc_ctx(ctx, STM32_CRYP_MODE_DES_CBC);
return alloc_cryp_ctx(ctx, STM32_CRYP_MODE_DES_CBC);
case TEE_ALG_DES3_ECB_NOPAD:
return alloc_ctx(ctx, STM32_CRYP_MODE_TDES_ECB);
return alloc_cryp_ctx(ctx, STM32_CRYP_MODE_TDES_ECB);
case TEE_ALG_DES3_CBC_NOPAD:
return alloc_ctx(ctx, STM32_CRYP_MODE_TDES_CBC);
return alloc_cryp_ctx(ctx, STM32_CRYP_MODE_TDES_CBC);
case TEE_ALG_AES_ECB_NOPAD:
return alloc_cryp_ctx(ctx, STM32_CRYP_MODE_AES_ECB);
case TEE_ALG_AES_CBC_NOPAD:
return alloc_cryp_ctx(ctx, STM32_CRYP_MODE_AES_CBC);
case TEE_ALG_AES_CTR:
return alloc_cryp_ctx(ctx, STM32_CRYP_MODE_AES_CTR);
default:
return TEE_ERROR_NOT_IMPLEMENTED;
}
}

/*
* Allocate the SW cipher data context for SAES peripheral.
*
* @ctx [out] Caller context variable
* @algo Algorithm ID of the context
*/
static TEE_Result stm32_saes_cipher_allocate(void **ctx, uint32_t algo)
{
/*
* Convert TEE_ALGO id to internal id
*/
switch (algo) {
case TEE_ALG_AES_ECB_NOPAD:
return alloc_ctx(ctx, STM32_CRYP_MODE_AES_ECB);
return alloc_saes_ctx(ctx, STM32_SAES_MODE_ECB);
case TEE_ALG_AES_CBC_NOPAD:
return alloc_ctx(ctx, STM32_CRYP_MODE_AES_CBC);
return alloc_saes_ctx(ctx, STM32_SAES_MODE_CBC);
case TEE_ALG_AES_CTR:
return alloc_ctx(ctx, STM32_CRYP_MODE_AES_CTR);
return alloc_saes_ctx(ctx, STM32_SAES_MODE_CTR);
default:
return TEE_ERROR_NOT_IMPLEMENTED;
}
}

static struct drvcrypt_cipher driver_cipher = {
.alloc_ctx = &stm32_cipher_allocate,
static struct drvcrypt_cipher driver_cipher_cryp = {
.alloc_ctx = &stm32_cryp_cipher_allocate,
.free_ctx = &stm32_cipher_free,
.init = &stm32_cipher_initialize,
.update = &stm32_cipher_update,
.final = &stm32_cipher_final,
.copy_state = &stm32_cipher_copy_state,
};

static struct drvcrypt_cipher driver_cipher_saes = {
.alloc_ctx = &stm32_saes_cipher_allocate,
.free_ctx = &stm32_cipher_free,
.init = &stm32_cipher_initialize,
.update = &stm32_cipher_update,
.final = &stm32_cipher_final,
.copy_state = &stm32_cipher_copy_state,
};

TEE_Result stm32_register_cipher(void)
TEE_Result stm32_register_cipher(enum stm32_cipher_ip_id cipher_ip)
{
return drvcrypt_register_cipher(&driver_cipher);
if (cipher_ip == SAES_IP)
return drvcrypt_register_cipher(&driver_cipher_saes);
else if (cipher_ip == CRYP_IP)
return drvcrypt_register_cipher(&driver_cipher_cryp);
else
return TEE_ERROR_BAD_PARAMETERS;
}
26 changes: 25 additions & 1 deletion core/drivers/crypto/stm32/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,31 @@

#include <tee_api_types.h>

enum stm32_cipher_ip_id {
CRYP_IP,
SAES_IP,
};

/*
* Crypto algorithm common macro used in stm32_saes and stm32_cryp driver
*/

#define INT8_BIT U(8)
#define AES_BLOCK_SIZE_BIT U(128)
#define AES_BLOCK_SIZE (AES_BLOCK_SIZE_BIT / INT8_BIT)
#define AES_BLOCK_NB_U32 (AES_BLOCK_SIZE / sizeof(uint32_t))
#define DES_BLOCK_SIZE_BIT U(64)
#define DES_BLOCK_SIZE (DES_BLOCK_SIZE_BIT / INT8_BIT)
#define DES_BLOCK_NB_U32 (DES_BLOCK_SIZE / sizeof(uint32_t))
#define MAX_BLOCK_SIZE_BIT AES_BLOCK_SIZE_BIT
#define MAX_BLOCK_SIZE AES_BLOCK_SIZE
#define MAX_BLOCK_NB_U32 AES_BLOCK_NB_U32
#define AES_KEYSIZE_128 U(16)
#define AES_KEYSIZE_192 U(24)
#define AES_KEYSIZE_256 U(32)
#define AES_IVSIZE U(16)

TEE_Result stm32_register_authenc(void);
TEE_Result stm32_register_cipher(void);
TEE_Result stm32_register_cipher(enum stm32_cipher_ip_id);

#endif /* __DRIVERS_CRYPTO_STM32_COMMON_H */
2 changes: 1 addition & 1 deletion core/drivers/crypto/stm32/crypto.mk
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ifeq ($(CFG_STM32_CRYPTO_DRIVER),y)
$(call force,CFG_CRYPTO_DRIVER,y)
CFG_CRYPTO_DRIVER_DEBUG ?= 0

ifeq ($(CFG_STM32_CRYP),y)
ifeq ($(call cfg-one-enabled, CFG_STM32_CRYP CFG_STM32_SAES),y)
$(call force,CFG_CRYPTO_DRV_CIPHER,y,Mandated by CFG_STM32_CRYP)
endif

Expand Down

0 comments on commit 4320f5c

Please sign in to comment.