aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorJens Wiklander <jens.wiklander@linaro.org>2019-03-08 15:22:14 +0100
committerJérôme Forissier <jerome.forissier@linaro.org>2019-03-11 17:58:04 +0100
commit96098f011f7cc334d2c9eb694e1cc45ded4f64cf (patch)
tree7890a93496ba7157a5ff79e0708b98a02752bddf /core
parent5da36a2473928a821089a37f8d0ca585e7a7cfcc (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.c87
-rw-r--r--core/include/crypto/crypto_impl.h69
-rw-r--r--core/lib/libtomcrypt/cbc.c140
-rw-r--r--core/lib/libtomcrypt/ctr.c113
-rw-r--r--core/lib/libtomcrypt/cts.c138
-rw-r--r--core/lib/libtomcrypt/des2_key.h22
-rw-r--r--core/lib/libtomcrypt/ecb.c138
-rw-r--r--core/lib/libtomcrypt/src/tee_ltc_provider.c393
-rw-r--r--core/lib/libtomcrypt/sub.mk5
-rw-r--r--core/lib/libtomcrypt/xts.c130
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 == &ltc_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 = &ltc_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 == &ltc_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 = &ltc_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 == &ltc_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 = &ltc_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 == &ltc_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 = &ltc_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, &ltc_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 == &ltc_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 = &ltc_xts_ops;
+ c->cipher_idx = cipher_idx;
+ *ctx_ret = &c->ctx;
+
+ return TEE_SUCCESS;
+}