1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014-2019, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <crypto/crypto.h> 8 #include <crypto/crypto_impl.h> 9 #include <stdlib.h> 10 #include <tee_api_types.h> 11 #include <tee/tee_cryp_utl.h> 12 #include <util.h> 13 14 15 /* From libtomcrypt doc: 16 * Ciphertext stealing is a method of dealing with messages 17 * in CBC mode which are not a multiple of the block 18 * length. This is accomplished by encrypting the last 19 * ciphertext block in ECB mode, and XOR'ing the output 20 * against the last partial block of plaintext. LibTomCrypt 21 * does not support this mode directly but it is fairly 22 * easy to emulate with a call to the cipher's 23 * ecb encrypt() callback function. 24 * The more sane way to deal with partial blocks is to pad 25 * them with zeroes, and then use CBC normally 26 */ 27 28 /* 29 * From Global Platform: CTS = CBC-CS3 30 */ 31 32 struct cts_ctx { 33 struct crypto_cipher_ctx ctx; 34 struct crypto_cipher_ctx *ecb; 35 struct crypto_cipher_ctx *cbc; 36 TEE_OperationMode mode; 37 }; 38 39 static const struct crypto_cipher_ops cts_ops; 40 41 static struct cts_ctx *to_cts_ctx(struct crypto_cipher_ctx *ctx) 42 { 43 assert(ctx && ctx->ops == &cts_ops); 44 45 return container_of(ctx, struct cts_ctx, ctx); 46 } 47 48 static TEE_Result cts_init(struct crypto_cipher_ctx *ctx, 49 TEE_OperationMode mode, const uint8_t *key1, 50 size_t key1_len, const uint8_t *key2, 51 size_t key2_len, const uint8_t *iv, size_t iv_len) 52 { 53 TEE_Result res = TEE_SUCCESS; 54 struct cts_ctx *c = to_cts_ctx(ctx); 55 56 c->mode = mode; 57 58 res = crypto_cipher_init(c->ecb, TEE_ALG_AES_ECB_NOPAD, mode, key1, 59 key1_len, key2, key2_len, iv, iv_len); 60 if (res) 61 return res; 62 63 return crypto_cipher_init(c->cbc, TEE_ALG_AES_CBC_NOPAD, mode, key1, 64 key1_len, key2, key2_len, iv, iv_len); 65 } 66 67 static TEE_Result cts_update(struct crypto_cipher_ctx *ctx, bool last_block, 68 const uint8_t *data, size_t len, uint8_t *dst) 69 { 70 struct cts_ctx *c = to_cts_ctx(ctx); 71 72 return tee_aes_cbc_cts_update(c->cbc, c->ecb, c->mode, last_block, 73 data, len, dst); 74 } 75 76 static void cts_final(struct crypto_cipher_ctx *ctx) 77 { 78 struct cts_ctx *c = to_cts_ctx(ctx); 79 80 crypto_cipher_final(c->cbc, TEE_ALG_AES_CBC_NOPAD); 81 crypto_cipher_final(c->ecb, TEE_ALG_AES_ECB_NOPAD); 82 } 83 84 static void cts_free_ctx(struct crypto_cipher_ctx *ctx) 85 { 86 struct cts_ctx *c = to_cts_ctx(ctx); 87 88 crypto_cipher_free_ctx(c->cbc, TEE_ALG_AES_CBC_NOPAD); 89 crypto_cipher_free_ctx(c->ecb, TEE_ALG_AES_ECB_NOPAD); 90 free(c); 91 } 92 93 static void cts_copy_state(struct crypto_cipher_ctx *dst_ctx, 94 struct crypto_cipher_ctx *src_ctx) 95 { 96 struct cts_ctx *src = to_cts_ctx(src_ctx); 97 struct cts_ctx *dst = to_cts_ctx(dst_ctx); 98 99 crypto_cipher_copy_state(dst->cbc, src->cbc, TEE_ALG_AES_CBC_NOPAD); 100 crypto_cipher_copy_state(dst->ecb, src->ecb, TEE_ALG_AES_ECB_NOPAD); 101 } 102 103 static const struct crypto_cipher_ops cts_ops = { 104 .init = cts_init, 105 .update = cts_update, 106 .final = cts_final, 107 .free_ctx = cts_free_ctx, 108 .copy_state = cts_copy_state, 109 }; 110 111 TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx) 112 { 113 TEE_Result res = TEE_SUCCESS; 114 struct cts_ctx *c = calloc(1, sizeof(*c)); 115 116 if (!c) 117 return TEE_ERROR_OUT_OF_MEMORY; 118 119 res = crypto_aes_ecb_alloc_ctx(&c->ecb); 120 if (res) 121 goto err; 122 res = crypto_aes_cbc_alloc_ctx(&c->cbc); 123 if (res) 124 goto err; 125 126 c->ctx.ops = &cts_ops; 127 *ctx = &c->ctx; 128 129 return TEE_SUCCESS; 130 err: 131 crypto_cipher_free_ctx(c->ecb, TEE_ALG_AES_ECB_NOPAD); 132 free(c); 133 134 return res; 135 } 136