aboutsummaryrefslogtreecommitdiff
path: root/core/lib/libtomcrypt/cts.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/lib/libtomcrypt/cts.c')
-rw-r--r--core/lib/libtomcrypt/cts.c138
1 files changed, 138 insertions, 0 deletions
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;
+}