diff options
author | Jens Wiklander <jens.wiklander@linaro.org> | 2019-03-08 15:22:14 +0100 |
---|---|---|
committer | Jérôme Forissier <jerome.forissier@linaro.org> | 2019-03-11 17:58:04 +0100 |
commit | 96098f011f7cc334d2c9eb694e1cc45ded4f64cf (patch) | |
tree | 7890a93496ba7157a5ff79e0708b98a02752bddf /core | |
parent | 5da36a2473928a821089a37f8d0ca585e7a7cfcc (diff) |
core: crypto: introduce struct crypto_cipher_ops
Uses struct crypto_cipher_ops pointer in crypto context for ciphers as a
glue layer instead of a switch(algo) in each crypto_cipher_*() function.
Reviewed-by: Jerome Forissier <jerome.forissier@linaro.org>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Diffstat (limited to 'core')
-rw-r--r-- | core/crypto/crypto.c | 87 | ||||
-rw-r--r-- | core/include/crypto/crypto_impl.h | 69 | ||||
-rw-r--r-- | core/lib/libtomcrypt/cbc.c | 140 | ||||
-rw-r--r-- | core/lib/libtomcrypt/ctr.c | 113 | ||||
-rw-r--r-- | core/lib/libtomcrypt/cts.c | 138 | ||||
-rw-r--r-- | core/lib/libtomcrypt/des2_key.h | 22 | ||||
-rw-r--r-- | core/lib/libtomcrypt/ecb.c | 138 | ||||
-rw-r--r-- | core/lib/libtomcrypt/src/tee_ltc_provider.c | 393 | ||||
-rw-r--r-- | core/lib/libtomcrypt/sub.mk | 5 | ||||
-rw-r--r-- | core/lib/libtomcrypt/xts.c | 130 |
10 files changed, 824 insertions, 411 deletions
diff --git a/core/crypto/crypto.c b/core/crypto/crypto.c index 4e3fc620..32123a2d 100644 --- a/core/crypto/crypto.c +++ b/core/crypto/crypto.c @@ -86,49 +86,94 @@ TEE_Result crypto_hash_final(void *ctx, uint32_t algo __unused, return hash_ops(ctx)->final(ctx, digest, len); } -#if !defined(_CFG_CRYPTO_WITH_CIPHER) -TEE_Result crypto_cipher_alloc_ctx(void **ctx __unused, uint32_t algo __unused) +TEE_Result crypto_cipher_alloc_ctx(void **ctx, uint32_t algo) { - return TEE_ERROR_NOT_IMPLEMENTED; + TEE_Result res = TEE_SUCCESS; + struct crypto_cipher_ctx *c = NULL; + + switch (algo) { + case TEE_ALG_AES_ECB_NOPAD: + res = crypto_aes_ecb_alloc_ctx(&c); + break; + case TEE_ALG_AES_CBC_NOPAD: + res = crypto_aes_cbc_alloc_ctx(&c); + break; + case TEE_ALG_AES_CTR: + res = crypto_aes_ctr_alloc_ctx(&c); + break; + case TEE_ALG_AES_CTS: + res = crypto_aes_cts_alloc_ctx(&c); + break; + case TEE_ALG_AES_XTS: + res = crypto_aes_xts_alloc_ctx(&c); + break; + case TEE_ALG_DES_ECB_NOPAD: + res = crypto_des_ecb_alloc_ctx(&c); + break; + case TEE_ALG_DES3_ECB_NOPAD: + res = crypto_des3_ecb_alloc_ctx(&c); + break; + case TEE_ALG_DES_CBC_NOPAD: + res = crypto_des_cbc_alloc_ctx(&c); + break; + case TEE_ALG_DES3_CBC_NOPAD: + res = crypto_des3_cbc_alloc_ctx(&c); + break; + default: + return TEE_ERROR_NOT_IMPLEMENTED; + } + + if (!res) + *ctx = c; + + return res; +} + +static const struct crypto_cipher_ops *cipher_ops(void *ctx) +{ + struct crypto_cipher_ctx *c = ctx; + + assert(c && c->ops); + + return c->ops; } void crypto_cipher_free_ctx(void *ctx, uint32_t algo __unused) { if (ctx) - assert(0); + cipher_ops(ctx)->free_ctx(ctx); } -void crypto_cipher_copy_state(void *dst_ctx __unused, void *src_ctx __unused, +void crypto_cipher_copy_state(void *dst_ctx, void *src_ctx, uint32_t algo __unused) { - assert(0); + cipher_ops(dst_ctx)->copy_state(dst_ctx, src_ctx); } TEE_Result crypto_cipher_init(void *ctx __unused, uint32_t algo __unused, - TEE_OperationMode mode __unused, - const uint8_t *key1 __unused, - size_t key1_len __unused, - const uint8_t *key2 __unused, - size_t key2_len __unused, - const uint8_t *iv __unused, - size_t iv_len __unused) + TEE_OperationMode mode, const uint8_t *key1, + size_t key1_len, const uint8_t *key2, + size_t key2_len, const uint8_t *iv, size_t iv_len) { - return TEE_ERROR_NOT_IMPLEMENTED; + if (mode != TEE_MODE_DECRYPT && mode != TEE_MODE_ENCRYPT) + return TEE_ERROR_BAD_PARAMETERS; + + return cipher_ops(ctx)->init(ctx, mode, key1, key1_len, key2, key2_len, + iv, iv_len); } -TEE_Result crypto_cipher_update(void *ctx __unused, uint32_t algo __unused, +TEE_Result crypto_cipher_update(void *ctx, uint32_t algo __unused, TEE_OperationMode mode __unused, - bool last_block __unused, - const uint8_t *data __unused, - size_t len __unused, uint8_t *dst __unused) + bool last_block, const uint8_t *data, + size_t len, uint8_t *dst) { - return TEE_ERROR_NOT_IMPLEMENTED; + return cipher_ops(ctx)->update(ctx, last_block, data, len, dst); } -void crypto_cipher_final(void *ctx __unused, uint32_t algo __unused) +void crypto_cipher_final(void *ctx, uint32_t algo __unused) { + cipher_ops(ctx)->final(ctx); } -#endif /*_CFG_CRYPTO_WITH_CIPHER*/ TEE_Result crypto_cipher_get_block_size(uint32_t algo, size_t *size) { diff --git a/core/include/crypto/crypto_impl.h b/core/include/crypto/crypto_impl.h index 6a5cf337..dc07a72e 100644 --- a/core/include/crypto/crypto_impl.h +++ b/core/include/crypto/crypto_impl.h @@ -125,4 +125,73 @@ TEE_Result crypto_aes_cmac_alloc_ctx(struct crypto_mac_ctx **ctx); #else CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(aes_cmac, mac) #endif + +/* + * The crypto context used by the crypto_cipher_*() functions is defined by + * struct crypto_cipher_ctx. + */ +struct crypto_cipher_ctx { + const struct crypto_cipher_ops *ops; +}; + +struct crypto_cipher_ops { + TEE_Result (*init)(struct crypto_cipher_ctx *ctx, + TEE_OperationMode mode, + const uint8_t *key1, size_t key1_len, + const uint8_t *key2, size_t key2_len, + const uint8_t *iv, size_t iv_len); + TEE_Result (*update)(struct crypto_cipher_ctx *ctx, bool last_block, + const uint8_t *data, size_t len, uint8_t *dst); + void (*final)(struct crypto_cipher_ctx *ctx); + + void (*free_ctx)(struct crypto_cipher_ctx *ctx); + void (*copy_state)(struct crypto_cipher_ctx *dst_ctx, + struct crypto_cipher_ctx *src_ctx); +}; + +#if defined(CFG_CRYPTO_AES) && defined(CFG_CRYPTO_ECB) +TEE_Result crypto_aes_ecb_alloc_ctx(struct crypto_cipher_ctx **ctx); +#else +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(aes_ecb, cipher) +#endif + +#if defined(CFG_CRYPTO_AES) && defined(CFG_CRYPTO_CBC) +TEE_Result crypto_aes_cbc_alloc_ctx(struct crypto_cipher_ctx **ctx); +#else +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(aes_cbc, cipher) +#endif + +#if defined(CFG_CRYPTO_AES) && defined(CFG_CRYPTO_CTR) +TEE_Result crypto_aes_ctr_alloc_ctx(struct crypto_cipher_ctx **ctx); +#else +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(aes_ctr, cipher) +#endif + +#if defined(CFG_CRYPTO_AES) && defined(CFG_CRYPTO_CTS) +TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx); +#else +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(aes_cts, cipher) +#endif + +#if defined(CFG_CRYPTO_AES) && defined(CFG_CRYPTO_XTS) +TEE_Result crypto_aes_xts_alloc_ctx(struct crypto_cipher_ctx **ctx); +#else +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(aes_xts, cipher) +#endif + +#if defined(CFG_CRYPTO_DES) && defined(CFG_CRYPTO_ECB) +TEE_Result crypto_des_ecb_alloc_ctx(struct crypto_cipher_ctx **ctx); +TEE_Result crypto_des3_ecb_alloc_ctx(struct crypto_cipher_ctx **ctx); +#else +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(des_ecb, cipher) +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(des3_ecb, cipher) +#endif + +#if defined(CFG_CRYPTO_DES) && defined(CFG_CRYPTO_CBC) +TEE_Result crypto_des_cbc_alloc_ctx(struct crypto_cipher_ctx **ctx); +TEE_Result crypto_des3_cbc_alloc_ctx(struct crypto_cipher_ctx **ctx); +#else +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(des_cbc, cipher) +CRYPTO_ALLOC_CTX_NOT_IMPLEMENTED(des3_cbc, cipher) +#endif #endif /*__CRYPTO_CRYPTO_IMPL_H*/ diff --git a/core/lib/libtomcrypt/cbc.c b/core/lib/libtomcrypt/cbc.c new file mode 100644 index 00000000..ca62d11d --- /dev/null +++ b/core/lib/libtomcrypt/cbc.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2014-2019, Linaro Limited + */ + +#include <assert.h> +#include <crypto/crypto.h> +#include <crypto/crypto_impl.h> +#include <stdlib.h> +#include <tee_api_types.h> +#include <tomcrypt.h> +#include <util.h> + +#include "des2_key.h" + +struct ltc_cbc_ctx { + struct crypto_cipher_ctx ctx; + int cipher_idx; + bool des3; + int (*update)(const unsigned char *src, unsigned char *dst, + unsigned long len, symmetric_CBC *cbc); + symmetric_CBC state; +}; + +static const struct crypto_cipher_ops ltc_cbc_ops; + +static struct ltc_cbc_ctx *to_cbc_ctx(struct crypto_cipher_ctx *ctx) +{ + assert(ctx && ctx->ops == <c_cbc_ops); + + return container_of(ctx, struct ltc_cbc_ctx, ctx); +} + +static TEE_Result ltc_cbc_init(struct crypto_cipher_ctx *ctx, + TEE_OperationMode mode, const uint8_t *key1, + size_t key1_len, const uint8_t *key2 __unused, + size_t key2_len __unused, + const uint8_t *iv, size_t iv_len) +{ + struct ltc_cbc_ctx *c = to_cbc_ctx(ctx); + uint8_t tmp[24] = { 0 }; + const uint8_t *k = key1; + size_t kl = key1_len; + + if ((int)iv_len != cipher_descriptor[c->cipher_idx]->block_length) + return TEE_ERROR_BAD_PARAMETERS; + + if (mode == TEE_MODE_ENCRYPT) + c->update = cbc_encrypt; + else + c->update = cbc_decrypt; + + if (c->des3) + get_des2_key(&k, &kl, tmp); + + if (cbc_start(c->cipher_idx, iv, k, kl, 0, &c->state) == CRYPT_OK) + return TEE_SUCCESS; + else + return TEE_ERROR_BAD_STATE; +} + +static TEE_Result ltc_cbc_update(struct crypto_cipher_ctx *ctx, + bool last_block __unused, + const uint8_t *data, size_t len, uint8_t *dst) +{ + struct ltc_cbc_ctx *c = to_cbc_ctx(ctx); + + if (c->update && c->update(data, dst, len, &c->state) == CRYPT_OK) + return TEE_SUCCESS; + else + return TEE_ERROR_BAD_STATE; +} + +static void ltc_cbc_final(struct crypto_cipher_ctx *ctx) +{ + cbc_done(&to_cbc_ctx(ctx)->state); +} + +static void ltc_cbc_free_ctx(struct crypto_cipher_ctx *ctx) +{ + free(to_cbc_ctx(ctx)); +} + +static void ltc_cbc_copy_state(struct crypto_cipher_ctx *dst_ctx, + struct crypto_cipher_ctx *src_ctx) +{ + struct ltc_cbc_ctx *src = to_cbc_ctx(src_ctx); + struct ltc_cbc_ctx *dst = to_cbc_ctx(dst_ctx); + + assert(src->cipher_idx == dst->cipher_idx); + dst->update = src->update; + dst->state = src->state; +} + +static const struct crypto_cipher_ops ltc_cbc_ops = { + .init = ltc_cbc_init, + .update = ltc_cbc_update, + .final = ltc_cbc_final, + .free_ctx = ltc_cbc_free_ctx, + .copy_state = ltc_cbc_copy_state, +}; + +static TEE_Result ltc_cbc_alloc_ctx(struct crypto_cipher_ctx **ctx_ret, + int cipher_idx, bool des3) +{ + struct ltc_cbc_ctx *c = NULL; + + if (cipher_idx < 0) + return TEE_ERROR_NOT_SUPPORTED; + + c = calloc(1, sizeof(*c)); + if (!c) + return TEE_ERROR_OUT_OF_MEMORY; + + c->ctx.ops = <c_cbc_ops; + c->cipher_idx = cipher_idx; + c->des3 = des3; + *ctx_ret = &c->ctx; + + return TEE_SUCCESS; +} + +#if defined CFG_CRYPTO_AES +TEE_Result crypto_aes_cbc_alloc_ctx(struct crypto_cipher_ctx **ctx) +{ + return ltc_cbc_alloc_ctx(ctx, find_cipher("aes"), false); +} +#endif + +#if defined CFG_CRYPTO_DES +TEE_Result crypto_des_cbc_alloc_ctx(struct crypto_cipher_ctx **ctx) +{ + return ltc_cbc_alloc_ctx(ctx, find_cipher("des"), false); +} + +TEE_Result crypto_des3_cbc_alloc_ctx(struct crypto_cipher_ctx **ctx) +{ + return ltc_cbc_alloc_ctx(ctx, find_cipher("3des"), true); +} +#endif diff --git a/core/lib/libtomcrypt/ctr.c b/core/lib/libtomcrypt/ctr.c new file mode 100644 index 00000000..98fdc17d --- /dev/null +++ b/core/lib/libtomcrypt/ctr.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2014-2019, Linaro Limited + */ + +#include <assert.h> +#include <crypto/crypto.h> +#include <crypto/crypto_impl.h> +#include <stdlib.h> +#include <tee_api_types.h> +#include <tomcrypt.h> +#include <util.h> + +struct ltc_ctr_ctx { + struct crypto_cipher_ctx ctx; + int cipher_idx; + int (*update)(const unsigned char *src, unsigned char *dst, + unsigned long len, symmetric_CTR *ctr); + symmetric_CTR state; +}; + +static const struct crypto_cipher_ops ltc_ctr_ops; + +static struct ltc_ctr_ctx *to_ctr_ctx(struct crypto_cipher_ctx *ctx) +{ + assert(ctx && ctx->ops == <c_ctr_ops); + + return container_of(ctx, struct ltc_ctr_ctx, ctx); +} + +static TEE_Result ltc_ctr_init(struct crypto_cipher_ctx *ctx, + TEE_OperationMode mode, const uint8_t *key1, + size_t key1_len, const uint8_t *key2 __unused, + size_t key2_len __unused, + const uint8_t *iv __unused, + size_t iv_len __unused) +{ + struct ltc_ctr_ctx *c = to_ctr_ctx(ctx); + + if ((int)iv_len != cipher_descriptor[c->cipher_idx]->block_length) + return TEE_ERROR_BAD_PARAMETERS; + + if (mode == TEE_MODE_ENCRYPT) + c->update = ctr_encrypt; + else + c->update = ctr_decrypt; + + if (ctr_start(c->cipher_idx, iv, key1, key1_len, 0, + CTR_COUNTER_BIG_ENDIAN, &c->state) == CRYPT_OK) + return TEE_SUCCESS; + else + return TEE_ERROR_BAD_STATE; +} + +static TEE_Result ltc_ctr_update(struct crypto_cipher_ctx *ctx, + bool last_block __unused, + const uint8_t *data, size_t len, uint8_t *dst) +{ + struct ltc_ctr_ctx *c = to_ctr_ctx(ctx); + + if (c->update && c->update(data, dst, len, &c->state) == CRYPT_OK) + return TEE_SUCCESS; + else + return TEE_ERROR_BAD_STATE; +} + +static void ltc_ctr_final(struct crypto_cipher_ctx *ctx) +{ + ctr_done(&to_ctr_ctx(ctx)->state); +} + +static void ltc_ctr_free_ctx(struct crypto_cipher_ctx *ctx) +{ + free(to_ctr_ctx(ctx)); +} + +static void ltc_ctr_copy_state(struct crypto_cipher_ctx *dst_ctx, + struct crypto_cipher_ctx *src_ctx) +{ + struct ltc_ctr_ctx *src = to_ctr_ctx(src_ctx); + struct ltc_ctr_ctx *dst = to_ctr_ctx(dst_ctx); + + assert(src->cipher_idx == dst->cipher_idx); + dst->update = src->update; + dst->state = src->state; +} + +static const struct crypto_cipher_ops ltc_ctr_ops = { + .init = ltc_ctr_init, + .update = ltc_ctr_update, + .final = ltc_ctr_final, + .free_ctx = ltc_ctr_free_ctx, + .copy_state = ltc_ctr_copy_state, +}; + +TEE_Result crypto_aes_ctr_alloc_ctx(struct crypto_cipher_ctx **ctx_ret) +{ + struct ltc_ctr_ctx *c = NULL; + int cipher_idx = find_cipher("aes"); + + if (cipher_idx < 0) + return TEE_ERROR_NOT_SUPPORTED; + + c = calloc(1, sizeof(*c)); + if (!c) + return TEE_ERROR_OUT_OF_MEMORY; + + c->ctx.ops = <c_ctr_ops; + c->cipher_idx = cipher_idx; + *ctx_ret = &c->ctx; + + return TEE_SUCCESS; +} diff --git a/core/lib/libtomcrypt/cts.c b/core/lib/libtomcrypt/cts.c new file mode 100644 index 00000000..e8bb64b4 --- /dev/null +++ b/core/lib/libtomcrypt/cts.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2014-2019, Linaro Limited + */ + +#include <assert.h> +#include <crypto/crypto.h> +#include <crypto/crypto_impl.h> +#include <stdlib.h> +#include <tee_api_types.h> +#include <tee/tee_cryp_utl.h> +#include <tomcrypt.h> +#include <util.h> + + +/* From libtomcrypt doc: + * Ciphertext stealing is a method of dealing with messages + * in CBC mode which are not a multiple of the block + * length. This is accomplished by encrypting the last + * ciphertext block in ECB mode, and XOR'ing the output + * against the last partial block of plaintext. LibTomCrypt + * does not support this mode directly but it is fairly + * easy to emulate with a call to the cipher's + * ecb encrypt() callback function. + * The more sane way to deal with partial blocks is to pad + * them with zeroes, and then use CBC normally + */ + +/* + * From Global Platform: CTS = CBC-CS3 + */ + +struct ltc_cts_ctx { + struct crypto_cipher_ctx ctx; + struct crypto_cipher_ctx *ecb; + struct crypto_cipher_ctx *cbc; + TEE_OperationMode mode; +}; + +static const struct crypto_cipher_ops ltc_cts_ops; + +static struct ltc_cts_ctx *to_cts_ctx(struct crypto_cipher_ctx *ctx) +{ + assert(ctx && ctx->ops == <c_cts_ops); + + return container_of(ctx, struct ltc_cts_ctx, ctx); +} + +static TEE_Result ltc_cts_init(struct crypto_cipher_ctx *ctx, + TEE_OperationMode mode, const uint8_t *key1, + size_t key1_len, const uint8_t *key2, + size_t key2_len, const uint8_t *iv, + size_t iv_len) +{ + TEE_Result res = TEE_SUCCESS; + struct ltc_cts_ctx *c = to_cts_ctx(ctx); + + c->mode = mode; + + res = crypto_cipher_init(c->ecb, TEE_ALG_AES_ECB_NOPAD, mode, key1, + key1_len, key2, key2_len, iv, iv_len); + if (res) + return res; + + return crypto_cipher_init(c->cbc, TEE_ALG_AES_CBC_NOPAD, mode, key1, + key1_len, key2, key2_len, iv, iv_len); +} + +static TEE_Result ltc_cts_update(struct crypto_cipher_ctx *ctx, + bool last_block, const uint8_t *data, + size_t len, uint8_t *dst) +{ + struct ltc_cts_ctx *c = to_cts_ctx(ctx); + + return tee_aes_cbc_cts_update(c->cbc, c->ecb, c->mode, last_block, + data, len, dst); +} + +static void ltc_cts_final(struct crypto_cipher_ctx *ctx) +{ + struct ltc_cts_ctx *c = to_cts_ctx(ctx); + + crypto_cipher_final(c->cbc, TEE_ALG_AES_CBC_NOPAD); + crypto_cipher_final(c->ecb, TEE_ALG_AES_ECB_NOPAD); +} + +static void ltc_cts_free_ctx(struct crypto_cipher_ctx *ctx) +{ + struct ltc_cts_ctx *c = to_cts_ctx(ctx); + + crypto_cipher_free_ctx(c->cbc, TEE_ALG_AES_CBC_NOPAD); + crypto_cipher_free_ctx(c->ecb, TEE_ALG_AES_ECB_NOPAD); + free(c); +} + +static void ltc_cts_copy_state(struct crypto_cipher_ctx *dst_ctx, + struct crypto_cipher_ctx *src_ctx) +{ + struct ltc_cts_ctx *src = to_cts_ctx(src_ctx); + struct ltc_cts_ctx *dst = to_cts_ctx(dst_ctx); + + crypto_cipher_copy_state(dst->cbc, src->cbc, TEE_ALG_AES_CBC_NOPAD); + crypto_cipher_copy_state(dst->ecb, src->ecb, TEE_ALG_AES_ECB_NOPAD); +} + +static const struct crypto_cipher_ops ltc_cts_ops = { + .init = ltc_cts_init, + .update = ltc_cts_update, + .final = ltc_cts_final, + .free_ctx = ltc_cts_free_ctx, + .copy_state = ltc_cts_copy_state, +}; + +TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx) +{ + TEE_Result res = TEE_SUCCESS; + struct ltc_cts_ctx *c = calloc(1, sizeof(*c)); + + if (!c) + return TEE_ERROR_OUT_OF_MEMORY; + + res = crypto_aes_ecb_alloc_ctx(&c->ecb); + if (res) + goto err; + res = crypto_aes_cbc_alloc_ctx(&c->cbc); + if (res) + goto err; + + c->ctx.ops = <c_cts_ops; + *ctx = &c->ctx; + + return TEE_SUCCESS; +err: + crypto_cipher_free_ctx(c->ecb, TEE_ALG_AES_ECB_NOPAD); + free(c); + + return res; +} diff --git a/core/lib/libtomcrypt/des2_key.h b/core/lib/libtomcrypt/des2_key.h new file mode 100644 index 00000000..1835a27d --- /dev/null +++ b/core/lib/libtomcrypt/des2_key.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2014-2019, Linaro Limited + */ + +static inline void get_des2_key(const uint8_t **key, size_t *key_len, + uint8_t *tmp) +{ + if (*key_len == 16) { + /* + * This corresponds to a 2DES key. The 2DES encryption + * algorithm is similar to 3DES. Both perform and + * encryption step, then a decryption step, followed + * by another encryption step (EDE). However 2DES uses + * the same key for both of the encryption (E) steps. + */ + memcpy(tmp, *key, 16); + memcpy(tmp + 16, *key, 8); + *key = tmp; + *key_len = 24; + } +} diff --git a/core/lib/libtomcrypt/ecb.c b/core/lib/libtomcrypt/ecb.c new file mode 100644 index 00000000..ab68efd7 --- /dev/null +++ b/core/lib/libtomcrypt/ecb.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2014-2019, Linaro Limited + */ + +#include <assert.h> +#include <crypto/crypto.h> +#include <crypto/crypto_impl.h> +#include <stdlib.h> +#include <tee_api_types.h> +#include <tomcrypt.h> +#include <util.h> + +#include "des2_key.h" + +struct ltc_ecb_ctx { + struct crypto_cipher_ctx ctx; + int cipher_idx; + bool des3; + int (*update)(const unsigned char *src, unsigned char *dst, + unsigned long len, symmetric_ECB *ecb); + symmetric_ECB state; +}; + +static const struct crypto_cipher_ops ltc_ecb_ops; + +static struct ltc_ecb_ctx *to_ecb_ctx(struct crypto_cipher_ctx *ctx) +{ + assert(ctx && ctx->ops == <c_ecb_ops); + + return container_of(ctx, struct ltc_ecb_ctx, ctx); +} + +static TEE_Result ltc_ecb_init(struct crypto_cipher_ctx *ctx, + TEE_OperationMode mode, const uint8_t *key1, + size_t key1_len, const uint8_t *key2 __unused, + size_t key2_len __unused, + const uint8_t *iv __unused, + size_t iv_len __unused) +{ + struct ltc_ecb_ctx *c = to_ecb_ctx(ctx); + uint8_t tmp[24] = { 0 }; + const uint8_t *k = key1; + size_t kl = key1_len; + + if (mode == TEE_MODE_ENCRYPT) + c->update = ecb_encrypt; + else + c->update = ecb_decrypt; + + if (c->des3) + get_des2_key(&k, &kl, tmp); + + if (ecb_start(c->cipher_idx, k, kl, 0, &c->state) == CRYPT_OK) + return TEE_SUCCESS; + else + return TEE_ERROR_BAD_STATE; +} + +static TEE_Result ltc_ecb_update(struct crypto_cipher_ctx *ctx, + bool last_block __unused, + const uint8_t *data, size_t len, uint8_t *dst) +{ + struct ltc_ecb_ctx *c = to_ecb_ctx(ctx); + + if (c->update && c->update(data, dst, len, &c->state) == CRYPT_OK) + return TEE_SUCCESS; + else + return TEE_ERROR_BAD_STATE; +} + +static void ltc_ecb_final(struct crypto_cipher_ctx *ctx) +{ + ecb_done(&to_ecb_ctx(ctx)->state); +} + +static void ltc_ecb_free_ctx(struct crypto_cipher_ctx *ctx) +{ + free(to_ecb_ctx(ctx)); +} + +static void ltc_ecb_copy_state(struct crypto_cipher_ctx *dst_ctx, + struct crypto_cipher_ctx *src_ctx) +{ + struct ltc_ecb_ctx *src = to_ecb_ctx(src_ctx); + struct ltc_ecb_ctx *dst = to_ecb_ctx(dst_ctx); + + assert(src->cipher_idx == dst->cipher_idx); + dst->update = src->update; + dst->state = src->state; +} + +static const struct crypto_cipher_ops ltc_ecb_ops = { + .init = ltc_ecb_init, + .update = ltc_ecb_update, + .final = ltc_ecb_final, + .free_ctx = ltc_ecb_free_ctx, + .copy_state = ltc_ecb_copy_state, +}; + +static TEE_Result ltc_ecb_alloc_ctx(struct crypto_cipher_ctx **ctx_ret, + int cipher_idx, bool des3) +{ + struct ltc_ecb_ctx *c = NULL; + + if (cipher_idx < 0) + return TEE_ERROR_NOT_SUPPORTED; + + c = calloc(1, sizeof(*c)); + if (!c) + return TEE_ERROR_OUT_OF_MEMORY; + + c->ctx.ops = <c_ecb_ops; + c->cipher_idx = cipher_idx; + c->des3 = des3; + *ctx_ret = &c->ctx; + + return TEE_SUCCESS; +} + +#if defined(CFG_CRYPTO_AES) +TEE_Result crypto_aes_ecb_alloc_ctx(struct crypto_cipher_ctx **ctx) +{ + return ltc_ecb_alloc_ctx(ctx, find_cipher("aes"), false); +} +#endif + +#if defined(CFG_CRYPTO_DES) +TEE_Result crypto_des_ecb_alloc_ctx(struct crypto_cipher_ctx **ctx) +{ + return ltc_ecb_alloc_ctx(ctx, find_cipher("des"), false); +} + +TEE_Result crypto_des3_ecb_alloc_ctx(struct crypto_cipher_ctx **ctx) +{ + return ltc_ecb_alloc_ctx(ctx, find_cipher("3des"), true); +} +#endif diff --git a/core/lib/libtomcrypt/src/tee_ltc_provider.c b/core/lib/libtomcrypt/src/tee_ltc_provider.c index 580386b2..40df474f 100644 --- a/core/lib/libtomcrypt/src/tee_ltc_provider.c +++ b/core/lib/libtomcrypt/src/tee_ltc_provider.c @@ -198,8 +198,7 @@ static TEE_Result tee_algo_to_ltc_hashindex(uint32_t algo, int *ltc_hashindex) } #endif /* defined(CFG_CRYPTO_RSA) */ -#if defined(_CFG_CRYPTO_WITH_CIPHER) || defined(_CFG_CRYPTO_WITH_MAC) || \ - defined(_CFG_CRYPTO_WITH_AUTHENC) +#if defined(CFG_CRYPTO_CCM) || defined(CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB) /* * Compute the LibTomCrypt "cipherindex" given a TEE Algorithm "algo" * Return @@ -250,8 +249,8 @@ static TEE_Result tee_algo_to_ltc_cipherindex(uint32_t algo, else return TEE_SUCCESS; } -#endif /* defined(_CFG_CRYPTO_WITH_CIPHER) || - defined(_CFG_CRYPTO_WITH_HASH) || defined(_CFG_CRYPTO_WITH_AUTHENC) */ +#endif /* defined(CFG_CRYPTO_CCM) || + defined(CFG_CRYPTO_AES_GCM_FROM_CRYPTOLIB) */ /****************************************************************************** * Asymmetric algorithms @@ -1440,392 +1439,6 @@ out: #endif /* _CFG_CRYPTO_WITH_ACIPHER */ -/****************************************************************************** - * Symmetric ciphers - ******************************************************************************/ - -#if defined(_CFG_CRYPTO_WITH_CIPHER) -/* From libtomcrypt doc: - * Ciphertext stealing is a method of dealing with messages - * in CBC mode which are not a multiple of the block - * length. This is accomplished by encrypting the last - * ciphertext block in ECB mode, and XOR'ing the output - * against the last partial block of plaintext. LibTomCrypt - * does not support this mode directly but it is fairly - * easy to emulate with a call to the cipher's - * ecb encrypt() callback function. - * The more sane way to deal with partial blocks is to pad - * them with zeroes, and then use CBC normally - */ - -/* - * From Global Platform: CTS = CBC-CS3 - */ - -#if defined(CFG_CRYPTO_CTS) -struct tee_symmetric_cts { - symmetric_ECB ecb; - symmetric_CBC cbc; -}; -#endif - -#if defined(CFG_CRYPTO_XTS) -#define XTS_TWEAK_SIZE 16 -struct tee_symmetric_xts { - symmetric_xts ctx; - uint8_t tweak[XTS_TWEAK_SIZE]; -}; -#endif - -static TEE_Result cipher_get_ctx_size(uint32_t algo, size_t *size) -{ - switch (algo) { -#if defined(CFG_CRYPTO_AES) -#if defined(CFG_CRYPTO_ECB) - case TEE_ALG_AES_ECB_NOPAD: - *size = sizeof(symmetric_ECB); - break; -#endif -#if defined(CFG_CRYPTO_CBC) - case TEE_ALG_AES_CBC_NOPAD: - *size = sizeof(symmetric_CBC); - break; -#endif -#if defined(CFG_CRYPTO_CTR) - case TEE_ALG_AES_CTR: - *size = sizeof(symmetric_CTR); - break; -#endif -#if defined(CFG_CRYPTO_CTS) - case TEE_ALG_AES_CTS: - *size = sizeof(struct tee_symmetric_cts); - break; -#endif -#if defined(CFG_CRYPTO_XTS) - case TEE_ALG_AES_XTS: - *size = sizeof(struct tee_symmetric_xts); - break; -#endif -#endif -#if defined(CFG_CRYPTO_DES) -#if defined(CFG_CRYPTO_ECB) - case TEE_ALG_DES_ECB_NOPAD: - *size = sizeof(symmetric_ECB); - break; - case TEE_ALG_DES3_ECB_NOPAD: - *size = sizeof(symmetric_ECB); - break; -#endif -#if defined(CFG_CRYPTO_CBC) - case TEE_ALG_DES_CBC_NOPAD: - *size = sizeof(symmetric_CBC); - break; - case TEE_ALG_DES3_CBC_NOPAD: - *size = sizeof(symmetric_CBC); - break; -#endif -#endif - default: - return TEE_ERROR_NOT_SUPPORTED; - } - - return TEE_SUCCESS; -} - -TEE_Result crypto_cipher_alloc_ctx(void **ctx_ret, uint32_t algo) -{ - TEE_Result res; - size_t ctx_size; - void *ctx; - - res = cipher_get_ctx_size(algo, &ctx_size); - if (res) - return res; - - ctx = calloc(1, ctx_size); - if (!ctx) - return TEE_ERROR_OUT_OF_MEMORY; - - *ctx_ret = ctx; - return TEE_SUCCESS; -} - -void crypto_cipher_free_ctx(void *ctx, uint32_t algo __maybe_unused) -{ - size_t ctx_size __maybe_unused; - - /* - * Check that it's a supported algo, or crypto_cipher_alloc_ctx() - * could never have succeded above. - */ - if (ctx) - assert(!cipher_get_ctx_size(algo, &ctx_size)); - free(ctx); -} - -void crypto_cipher_copy_state(void *dst_ctx, void *src_ctx, uint32_t algo) -{ - TEE_Result res __maybe_unused; - size_t ctx_size = 0; - - res = cipher_get_ctx_size(algo, &ctx_size); - assert(!res); - memcpy(dst_ctx, src_ctx, ctx_size); -} - -static void get_des2_key(const uint8_t *key, size_t key_len, - uint8_t *key_intermediate, - uint8_t **real_key, size_t *real_key_len) -{ - if (key_len == 16) { - /* - * This corresponds to a 2DES key. The 2DES encryption - * algorithm is similar to 3DES. Both perform and - * encryption step, then a decryption step, followed - * by another encryption step (EDE). However 2DES uses - * the same key for both of the encryption (E) steps. - */ - memcpy(key_intermediate, key, 16); - memcpy(key_intermediate+16, key, 8); - *real_key = key_intermediate; - *real_key_len = 24; - } else { - *real_key = (uint8_t *)key; - *real_key_len = key_len; - } -} - -TEE_Result crypto_cipher_init(void *ctx, uint32_t algo, - TEE_OperationMode mode __maybe_unused, - const uint8_t *key1, size_t key1_len, - const uint8_t *key2 __maybe_unused, - size_t key2_len __maybe_unused, - const uint8_t *iv __maybe_unused, - size_t iv_len __maybe_unused) -{ - TEE_Result res; - int ltc_res, ltc_cipherindex; - uint8_t *real_key, key_array[24]; - size_t real_key_len; -#if defined(CFG_CRYPTO_CTS) - struct tee_symmetric_cts *cts; -#endif -#if defined(CFG_CRYPTO_XTS) - struct tee_symmetric_xts *xts; -#endif - - res = tee_algo_to_ltc_cipherindex(algo, <c_cipherindex); - if (res != TEE_SUCCESS) - return TEE_ERROR_NOT_SUPPORTED; - - switch (algo) { -#if defined(CFG_CRYPTO_ECB) - case TEE_ALG_AES_ECB_NOPAD: - case TEE_ALG_DES_ECB_NOPAD: - ltc_res = ecb_start( - ltc_cipherindex, key1, key1_len, - 0, (symmetric_ECB *)ctx); - break; - - case TEE_ALG_DES3_ECB_NOPAD: - /* either des3 or des2, depending on the size of the key */ - get_des2_key(key1, key1_len, key_array, - &real_key, &real_key_len); - ltc_res = ecb_start( - ltc_cipherindex, real_key, real_key_len, - 0, (symmetric_ECB *)ctx); - break; -#endif -#if defined(CFG_CRYPTO_CBC) - case TEE_ALG_AES_CBC_NOPAD: - case TEE_ALG_DES_CBC_NOPAD: - if (iv_len != - (size_t)cipher_descriptor[ltc_cipherindex]->block_length) - return TEE_ERROR_BAD_PARAMETERS; - ltc_res = cbc_start( - ltc_cipherindex, iv, key1, key1_len, - 0, (symmetric_CBC *)ctx); - break; - - case TEE_ALG_DES3_CBC_NOPAD: - /* either des3 or des2, depending on the size of the key */ - get_des2_key(key1, key1_len, key_array, - &real_key, &real_key_len); - if (iv_len != - (size_t)cipher_descriptor[ltc_cipherindex]->block_length) - return TEE_ERROR_BAD_PARAMETERS; - ltc_res = cbc_start( - ltc_cipherindex, iv, real_key, real_key_len, - 0, (symmetric_CBC *)ctx); - break; -#endif -#if defined(CFG_CRYPTO_CTR) - case TEE_ALG_AES_CTR: - if (iv_len != - (size_t)cipher_descriptor[ltc_cipherindex]->block_length) - return TEE_ERROR_BAD_PARAMETERS; - ltc_res = ctr_start( - ltc_cipherindex, iv, key1, key1_len, - 0, CTR_COUNTER_BIG_ENDIAN, (symmetric_CTR *)ctx); - break; -#endif -#if defined(CFG_CRYPTO_CTS) - case TEE_ALG_AES_CTS: - cts = ctx; - res = crypto_cipher_init((void *)(&(cts->ecb)), - TEE_ALG_AES_ECB_NOPAD, mode, key1, - key1_len, key2, key2_len, iv, iv_len); - if (res != TEE_SUCCESS) - return res; - res = crypto_cipher_init((void *)(&(cts->cbc)), - TEE_ALG_AES_CBC_NOPAD, mode, key1, - key1_len, key2, key2_len, iv, iv_len); - if (res != TEE_SUCCESS) - return res; - ltc_res = CRYPT_OK; - break; -#endif -#if defined(CFG_CRYPTO_XTS) - case TEE_ALG_AES_XTS: - xts = ctx; - if (key1_len != key2_len) - return TEE_ERROR_BAD_PARAMETERS; - if (iv) { - if (iv_len != XTS_TWEAK_SIZE) - return TEE_ERROR_BAD_PARAMETERS; - memcpy(xts->tweak, iv, iv_len); - } else { - memset(xts->tweak, 0, XTS_TWEAK_SIZE); - } - ltc_res = xts_start( - ltc_cipherindex, key1, key2, key1_len, - 0, &xts->ctx); - break; -#endif - default: - return TEE_ERROR_NOT_SUPPORTED; - } - - if (ltc_res == CRYPT_OK) - return TEE_SUCCESS; - else - return TEE_ERROR_BAD_STATE; -} - -TEE_Result crypto_cipher_update(void *ctx, uint32_t algo, - TEE_OperationMode mode, - bool last_block __maybe_unused, - const uint8_t *data, size_t len, uint8_t *dst) -{ - int ltc_res = CRYPT_OK; -#if defined(CFG_CRYPTO_CTS) - struct tee_symmetric_cts *cts; -#endif -#if defined(CFG_CRYPTO_XTS) - struct tee_symmetric_xts *xts; -#endif - - switch (algo) { -#if defined(CFG_CRYPTO_ECB) - case TEE_ALG_AES_ECB_NOPAD: - case TEE_ALG_DES_ECB_NOPAD: - case TEE_ALG_DES3_ECB_NOPAD: - if (mode == TEE_MODE_ENCRYPT) - ltc_res = ecb_encrypt(data, dst, len, ctx); - else - ltc_res = ecb_decrypt(data, dst, len, ctx); - break; -#endif -#if defined(CFG_CRYPTO_CBC) - case TEE_ALG_AES_CBC_NOPAD: - case TEE_ALG_DES_CBC_NOPAD: - case TEE_ALG_DES3_CBC_NOPAD: - if (mode == TEE_MODE_ENCRYPT) - ltc_res = cbc_encrypt(data, dst, len, ctx); - else - ltc_res = cbc_decrypt(data, dst, len, ctx); - break; -#endif -#if defined(CFG_CRYPTO_CTR) - case TEE_ALG_AES_CTR: - if (mode == TEE_MODE_ENCRYPT) - ltc_res = ctr_encrypt(data, dst, len, ctx); - else - ltc_res = ctr_decrypt(data, dst, len, ctx); - break; -#endif -#if defined(CFG_CRYPTO_XTS) - case TEE_ALG_AES_XTS: - xts = ctx; - if (mode == TEE_MODE_ENCRYPT) - ltc_res = xts_encrypt(data, len, dst, xts->tweak, - &xts->ctx); - else - ltc_res = xts_decrypt(data, len, dst, xts->tweak, - &xts->ctx); - break; -#endif -#if defined(CFG_CRYPTO_CTS) - case TEE_ALG_AES_CTS: - cts = ctx; - return tee_aes_cbc_cts_update(&cts->cbc, &cts->ecb, mode, - last_block, data, len, dst); -#endif - default: - return TEE_ERROR_NOT_SUPPORTED; - } - - if (ltc_res == CRYPT_OK) - return TEE_SUCCESS; - else - return TEE_ERROR_BAD_STATE; -} - -void crypto_cipher_final(void *ctx, uint32_t algo) -{ - switch (algo) { -#if defined(CFG_CRYPTO_ECB) - case TEE_ALG_AES_ECB_NOPAD: - case TEE_ALG_DES_ECB_NOPAD: - case TEE_ALG_DES3_ECB_NOPAD: - ecb_done(ctx); - break; -#endif -#if defined(CFG_CRYPTO_CBC) - case TEE_ALG_AES_CBC_NOPAD: - case TEE_ALG_DES_CBC_NOPAD: - case TEE_ALG_DES3_CBC_NOPAD: - case TEE_ALG_AES_CBC_MAC_NOPAD: - case TEE_ALG_AES_CBC_MAC_PKCS5: - case TEE_ALG_DES_CBC_MAC_NOPAD: - case TEE_ALG_DES_CBC_MAC_PKCS5: - case TEE_ALG_DES3_CBC_MAC_NOPAD: - case TEE_ALG_DES3_CBC_MAC_PKCS5: - cbc_done(ctx); - break; -#endif -#if defined(CFG_CRYPTO_CTR) - case TEE_ALG_AES_CTR: - ctr_done(ctx); - break; -#endif -#if defined(CFG_CRYPTO_XTS) - case TEE_ALG_AES_XTS: - xts_done(&(((struct tee_symmetric_xts *)ctx)->ctx)); - break; -#endif -#if defined(CFG_CRYPTO_CTS) - case TEE_ALG_AES_CTS: - cbc_done(&(((struct tee_symmetric_cts *)ctx)->cbc)); - ecb_done(&(((struct tee_symmetric_cts *)ctx)->ecb)); - break; -#endif - default: - assert(!"Unhandled algo"); - break; - } -} -#endif /* _CFG_CRYPTO_WITH_CIPHER */ /****************************************************************************** * Authenticated encryption diff --git a/core/lib/libtomcrypt/sub.mk b/core/lib/libtomcrypt/sub.mk index 7bc2a73e..04637457 100644 --- a/core/lib/libtomcrypt/sub.mk +++ b/core/lib/libtomcrypt/sub.mk @@ -9,3 +9,8 @@ subdirs-y += src srcs-$(_CFG_CRYPTO_WITH_HASH) += hash.c srcs-$(CFG_CRYPTO_HMAC) += hmac.c srcs-$(CFG_CRYPTO_CMAC) += cmac.c +srcs-$(CFG_CRYPTO_ECB) += ecb.c +srcs-$(CFG_CRYPTO_CBC) += cbc.c +srcs-$(CFG_CRYPTO_CTS) += cts.c +srcs-$(CFG_CRYPTO_CTR) += ctr.c +srcs-$(CFG_CRYPTO_XTS) += xts.c diff --git a/core/lib/libtomcrypt/xts.c b/core/lib/libtomcrypt/xts.c new file mode 100644 index 00000000..e09b2da9 --- /dev/null +++ b/core/lib/libtomcrypt/xts.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (c) 2014-2019, Linaro Limited + */ + +#include <assert.h> +#include <crypto/crypto.h> +#include <crypto/crypto_impl.h> +#include <stdlib.h> +#include <string.h> +#include <tee_api_types.h> +#include <tomcrypt.h> +#include <utee_defines.h> +#include <util.h> + +struct ltc_xts_ctx { + struct crypto_cipher_ctx ctx; + int cipher_idx; + int (*update)(const unsigned char *src, unsigned long len, + unsigned char *dst, unsigned char *tweak, + symmetric_xts *xts); + symmetric_xts state; + uint8_t tweak[TEE_AES_BLOCK_SIZE]; +}; + +static const struct crypto_cipher_ops ltc_xts_ops; + +static struct ltc_xts_ctx *to_xts_ctx(struct crypto_cipher_ctx *ctx) +{ + assert(ctx && ctx->ops == <c_xts_ops); + + return container_of(ctx, struct ltc_xts_ctx, ctx); +} + +static TEE_Result ltc_xts_init(struct crypto_cipher_ctx *ctx, + TEE_OperationMode mode, const uint8_t *key1, + size_t key1_len, const uint8_t *key2 __unused, + size_t key2_len __unused, + const uint8_t *iv __unused, + size_t iv_len __unused) +{ + struct ltc_xts_ctx *c = to_xts_ctx(ctx); + + if (key1_len != key2_len) + return TEE_ERROR_BAD_PARAMETERS; + if (iv) { + if (iv_len != sizeof(c->tweak)) + return TEE_ERROR_BAD_PARAMETERS; + memcpy(c->tweak, iv, sizeof(c->tweak)); + } else { + memset(c->tweak, 0, sizeof(c->tweak)); + } + + if ((int)iv_len != cipher_descriptor[c->cipher_idx]->block_length) + return TEE_ERROR_BAD_PARAMETERS; + + if (mode == TEE_MODE_ENCRYPT) + c->update = xts_encrypt; + else + c->update = xts_decrypt; + + + if (xts_start(c->cipher_idx, key1, key2, key1_len, 0, + &c->state) == CRYPT_OK) + return TEE_SUCCESS; + else + return TEE_ERROR_BAD_STATE; +} + +static TEE_Result ltc_xts_update(struct crypto_cipher_ctx *ctx, + bool last_block __unused, + const uint8_t *data, size_t len, uint8_t *dst) +{ + struct ltc_xts_ctx *c = to_xts_ctx(ctx); + + if (c->update && c->update(data, len, dst, c->tweak, + &c->state) == CRYPT_OK) + return TEE_SUCCESS; + else + return TEE_ERROR_BAD_STATE; +} + +static void ltc_xts_final(struct crypto_cipher_ctx *ctx) +{ + xts_done(&to_xts_ctx(ctx)->state); +} + +static void ltc_xts_free_ctx(struct crypto_cipher_ctx *ctx) +{ + free(to_xts_ctx(ctx)); +} + +static void ltc_xts_copy_state(struct crypto_cipher_ctx *dst_ctx, + struct crypto_cipher_ctx *src_ctx) +{ + struct ltc_xts_ctx *src = to_xts_ctx(src_ctx); + struct ltc_xts_ctx *dst = to_xts_ctx(dst_ctx); + + assert(src->cipher_idx == dst->cipher_idx); + dst->update = src->update; + memcpy(dst->tweak, src->tweak, sizeof(src->tweak)); + dst->state = src->state; +} + +static const struct crypto_cipher_ops ltc_xts_ops = { + .init = ltc_xts_init, + .update = ltc_xts_update, + .final = ltc_xts_final, + .free_ctx = ltc_xts_free_ctx, + .copy_state = ltc_xts_copy_state, +}; + +TEE_Result crypto_aes_xts_alloc_ctx(struct crypto_cipher_ctx **ctx_ret) +{ + struct ltc_xts_ctx *c = NULL; + int cipher_idx = find_cipher("aes"); + + if (cipher_idx < 0) + return TEE_ERROR_NOT_SUPPORTED; + + c = calloc(1, sizeof(*c)); + if (!c) + return TEE_ERROR_OUT_OF_MEMORY; + + c->ctx.ops = <c_xts_ops; + c->cipher_idx = cipher_idx; + *ctx_ret = &c->ctx; + + return TEE_SUCCESS; +} |