117c68af4SJens Wiklander // SPDX-License-Identifier: BSD-2-Clause 217c68af4SJens Wiklander /* 317c68af4SJens Wiklander * Copyright (c) 2014-2019, Linaro Limited 417c68af4SJens Wiklander */ 517c68af4SJens Wiklander 617c68af4SJens Wiklander #include <assert.h> 717c68af4SJens Wiklander #include <crypto/crypto.h> 817c68af4SJens Wiklander #include <crypto/crypto_impl.h> 917c68af4SJens Wiklander #include <stdlib.h> 10cbda7091SJens Wiklander #include <string.h> 1117c68af4SJens Wiklander #include <tee_api_types.h> 1217c68af4SJens Wiklander #include <tee/tee_cryp_utl.h> 1317c68af4SJens Wiklander #include <util.h> 1417c68af4SJens Wiklander 1517c68af4SJens Wiklander 1617c68af4SJens Wiklander /* From libtomcrypt doc: 1717c68af4SJens Wiklander * Ciphertext stealing is a method of dealing with messages 1817c68af4SJens Wiklander * in CBC mode which are not a multiple of the block 1917c68af4SJens Wiklander * length. This is accomplished by encrypting the last 2017c68af4SJens Wiklander * ciphertext block in ECB mode, and XOR'ing the output 2117c68af4SJens Wiklander * against the last partial block of plaintext. LibTomCrypt 2217c68af4SJens Wiklander * does not support this mode directly but it is fairly 2317c68af4SJens Wiklander * easy to emulate with a call to the cipher's 2417c68af4SJens Wiklander * ecb encrypt() callback function. 2517c68af4SJens Wiklander * The more sane way to deal with partial blocks is to pad 2617c68af4SJens Wiklander * them with zeroes, and then use CBC normally 2717c68af4SJens Wiklander */ 2817c68af4SJens Wiklander 2917c68af4SJens Wiklander /* 3017c68af4SJens Wiklander * From Global Platform: CTS = CBC-CS3 3117c68af4SJens Wiklander */ 3217c68af4SJens Wiklander 3317c68af4SJens Wiklander struct cts_ctx { 3417c68af4SJens Wiklander struct crypto_cipher_ctx ctx; 3517c68af4SJens Wiklander struct crypto_cipher_ctx *ecb; 3617c68af4SJens Wiklander struct crypto_cipher_ctx *cbc; 3717c68af4SJens Wiklander TEE_OperationMode mode; 3817c68af4SJens Wiklander }; 3917c68af4SJens Wiklander 4017c68af4SJens Wiklander static const struct crypto_cipher_ops cts_ops; 4117c68af4SJens Wiklander 4217c68af4SJens Wiklander static struct cts_ctx *to_cts_ctx(struct crypto_cipher_ctx *ctx) 4317c68af4SJens Wiklander { 4417c68af4SJens Wiklander assert(ctx && ctx->ops == &cts_ops); 4517c68af4SJens Wiklander 4617c68af4SJens Wiklander return container_of(ctx, struct cts_ctx, ctx); 4717c68af4SJens Wiklander } 4817c68af4SJens Wiklander 4917c68af4SJens Wiklander static TEE_Result cts_init(struct crypto_cipher_ctx *ctx, 5017c68af4SJens Wiklander TEE_OperationMode mode, const uint8_t *key1, 5117c68af4SJens Wiklander size_t key1_len, const uint8_t *key2, 5217c68af4SJens Wiklander size_t key2_len, const uint8_t *iv, size_t iv_len) 5317c68af4SJens Wiklander { 5417c68af4SJens Wiklander TEE_Result res = TEE_SUCCESS; 5517c68af4SJens Wiklander struct cts_ctx *c = to_cts_ctx(ctx); 5617c68af4SJens Wiklander 5717c68af4SJens Wiklander c->mode = mode; 5817c68af4SJens Wiklander 59cbda7091SJens Wiklander res = crypto_cipher_init(c->ecb, mode, key1, key1_len, key2, key2_len, 60cbda7091SJens Wiklander iv, iv_len); 6117c68af4SJens Wiklander if (res) 6217c68af4SJens Wiklander return res; 6317c68af4SJens Wiklander 64cbda7091SJens Wiklander return crypto_cipher_init(c->cbc, mode, key1, key1_len, key2, key2_len, 65cbda7091SJens Wiklander iv, iv_len); 66cbda7091SJens Wiklander } 67cbda7091SJens Wiklander 68cbda7091SJens Wiklander /* 69cbda7091SJens Wiklander * From http://en.wikipedia.org/wiki/Ciphertext_stealing 70cbda7091SJens Wiklander * CBC ciphertext stealing encryption using a standard 71cbda7091SJens Wiklander * CBC interface: 72cbda7091SJens Wiklander * 1. Pad the last partial plaintext block with 0. 73cbda7091SJens Wiklander * 2. Encrypt the whole padded plaintext using the 74cbda7091SJens Wiklander * standard CBC mode. 75cbda7091SJens Wiklander * 3. Swap the last two ciphertext blocks. 76cbda7091SJens Wiklander * 4. Truncate the ciphertext to the length of the 77cbda7091SJens Wiklander * original plaintext. 78cbda7091SJens Wiklander * 79cbda7091SJens Wiklander * CBC ciphertext stealing decryption using a standard 80cbda7091SJens Wiklander * CBC interface 81cbda7091SJens Wiklander * 1. Dn = Decrypt (K, Cn-1). Decrypt the second to last 82cbda7091SJens Wiklander * ciphertext block. 83cbda7091SJens Wiklander * 2. Cn = Cn || Tail (Dn, B-M). Pad the ciphertext to the 84cbda7091SJens Wiklander * nearest multiple of the block size using the last 85cbda7091SJens Wiklander * B-M bits of block cipher decryption of the 86cbda7091SJens Wiklander * second-to-last ciphertext block. 87cbda7091SJens Wiklander * 3. Swap the last two ciphertext blocks. 88cbda7091SJens Wiklander * 4. Decrypt the (modified) ciphertext using the standard 89cbda7091SJens Wiklander * CBC mode. 90cbda7091SJens Wiklander * 5. Truncate the plaintext to the length of the original 91cbda7091SJens Wiklander * ciphertext. 92cbda7091SJens Wiklander */ 93cbda7091SJens Wiklander static TEE_Result cbc_cts_update(void *cbc_ctx, void *ecb_ctx, 94cbda7091SJens Wiklander TEE_OperationMode mode, bool last_block, 95cbda7091SJens Wiklander const uint8_t *data, size_t len, uint8_t *dst) 96cbda7091SJens Wiklander { 97*abd18a27SJens Wiklander TEE_Result res = TEE_SUCCESS; 98*abd18a27SJens Wiklander uint8_t tmp2_block[64] = { 0 }; 99*abd18a27SJens Wiklander uint8_t tmp_block[64] = { 0 }; 100*abd18a27SJens Wiklander int len_last_block = 0; 101*abd18a27SJens Wiklander int block_size = 16; 102*abd18a27SJens Wiklander int nb_blocks = 0; 103cbda7091SJens Wiklander 104cbda7091SJens Wiklander if (!last_block) 105cbda7091SJens Wiklander return tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 106cbda7091SJens Wiklander mode, last_block, data, len, dst); 107cbda7091SJens Wiklander 108cbda7091SJens Wiklander /* Compute the last block length and check constraints */ 109*abd18a27SJens Wiklander nb_blocks = (len + block_size - 1) / block_size; 110cbda7091SJens Wiklander if (nb_blocks < 2) 111cbda7091SJens Wiklander return TEE_ERROR_BAD_STATE; 112cbda7091SJens Wiklander len_last_block = len % block_size; 113cbda7091SJens Wiklander if (len_last_block == 0) 114cbda7091SJens Wiklander len_last_block = block_size; 115cbda7091SJens Wiklander 116cbda7091SJens Wiklander if (mode == TEE_MODE_ENCRYPT) { 117cbda7091SJens Wiklander memcpy(tmp_block, 118cbda7091SJens Wiklander data + ((nb_blocks - 1) * block_size), 119cbda7091SJens Wiklander len_last_block); 120cbda7091SJens Wiklander memset(tmp_block + len_last_block, 121cbda7091SJens Wiklander 0, 122cbda7091SJens Wiklander block_size - len_last_block); 123cbda7091SJens Wiklander 124cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 125cbda7091SJens Wiklander mode, 0, data, 126cbda7091SJens Wiklander (nb_blocks - 1) * block_size, dst); 127cbda7091SJens Wiklander if (res != TEE_SUCCESS) 128cbda7091SJens Wiklander return res; 129cbda7091SJens Wiklander 130cbda7091SJens Wiklander memcpy(dst + (nb_blocks - 1) * block_size, 131cbda7091SJens Wiklander dst + (nb_blocks - 2) * block_size, 132cbda7091SJens Wiklander len_last_block); 133cbda7091SJens Wiklander 134cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 135cbda7091SJens Wiklander mode, 0, tmp_block, block_size, 136cbda7091SJens Wiklander dst + (nb_blocks - 2) * block_size); 137cbda7091SJens Wiklander if (res != TEE_SUCCESS) 138cbda7091SJens Wiklander return res; 139cbda7091SJens Wiklander } else { 140cbda7091SJens Wiklander /* 1. Decrypt the second to last ciphertext block */ 141cbda7091SJens Wiklander res = tee_do_cipher_update(ecb_ctx, TEE_ALG_AES_ECB_NOPAD, 142cbda7091SJens Wiklander mode, 0, 143cbda7091SJens Wiklander data + (nb_blocks - 2) * block_size, 144cbda7091SJens Wiklander block_size, tmp2_block); 145cbda7091SJens Wiklander if (res != TEE_SUCCESS) 146cbda7091SJens Wiklander return res; 147cbda7091SJens Wiklander 148cbda7091SJens Wiklander /* 2. Cn = Cn || Tail (Dn, B-M) */ 149cbda7091SJens Wiklander memcpy(tmp_block, data + ((nb_blocks - 1) * block_size), 150cbda7091SJens Wiklander len_last_block); 151cbda7091SJens Wiklander memcpy(tmp_block + len_last_block, tmp2_block + len_last_block, 152cbda7091SJens Wiklander block_size - len_last_block); 153cbda7091SJens Wiklander 154cbda7091SJens Wiklander /* 3. Swap the last two ciphertext blocks */ 155cbda7091SJens Wiklander /* done by passing the correct buffers in step 4. */ 156cbda7091SJens Wiklander 157cbda7091SJens Wiklander /* 4. Decrypt the (modified) ciphertext */ 158cbda7091SJens Wiklander if (nb_blocks > 2) { 159cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, 160cbda7091SJens Wiklander TEE_ALG_AES_CBC_NOPAD, mode, 161cbda7091SJens Wiklander 0, data, 162cbda7091SJens Wiklander (nb_blocks - 2) * 163cbda7091SJens Wiklander block_size, dst); 164cbda7091SJens Wiklander if (res != TEE_SUCCESS) 165cbda7091SJens Wiklander return res; 166cbda7091SJens Wiklander } 167cbda7091SJens Wiklander 168cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 169cbda7091SJens Wiklander mode, 0, tmp_block, block_size, 170cbda7091SJens Wiklander dst + 171cbda7091SJens Wiklander ((nb_blocks - 2) * block_size)); 172cbda7091SJens Wiklander if (res != TEE_SUCCESS) 173cbda7091SJens Wiklander return res; 174cbda7091SJens Wiklander 175cbda7091SJens Wiklander res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 176cbda7091SJens Wiklander mode, 0, data + 177cbda7091SJens Wiklander ((nb_blocks - 2) * block_size), 178cbda7091SJens Wiklander block_size, tmp_block); 179cbda7091SJens Wiklander if (res != TEE_SUCCESS) 180cbda7091SJens Wiklander return res; 181cbda7091SJens Wiklander 182cbda7091SJens Wiklander /* 5. Truncate the plaintext */ 183cbda7091SJens Wiklander memcpy(dst + (nb_blocks - 1) * block_size, tmp_block, 184cbda7091SJens Wiklander len_last_block); 185cbda7091SJens Wiklander } 186cbda7091SJens Wiklander return TEE_SUCCESS; 18717c68af4SJens Wiklander } 18817c68af4SJens Wiklander 18917c68af4SJens Wiklander static TEE_Result cts_update(struct crypto_cipher_ctx *ctx, bool last_block, 19017c68af4SJens Wiklander const uint8_t *data, size_t len, uint8_t *dst) 19117c68af4SJens Wiklander { 19217c68af4SJens Wiklander struct cts_ctx *c = to_cts_ctx(ctx); 19317c68af4SJens Wiklander 194cbda7091SJens Wiklander return cbc_cts_update(c->cbc, c->ecb, c->mode, last_block, data, len, 195cbda7091SJens Wiklander dst); 19617c68af4SJens Wiklander } 19717c68af4SJens Wiklander 19817c68af4SJens Wiklander static void cts_final(struct crypto_cipher_ctx *ctx) 19917c68af4SJens Wiklander { 20017c68af4SJens Wiklander struct cts_ctx *c = to_cts_ctx(ctx); 20117c68af4SJens Wiklander 202cbda7091SJens Wiklander crypto_cipher_final(c->cbc); 203cbda7091SJens Wiklander crypto_cipher_final(c->ecb); 20417c68af4SJens Wiklander } 20517c68af4SJens Wiklander 20617c68af4SJens Wiklander static void cts_free_ctx(struct crypto_cipher_ctx *ctx) 20717c68af4SJens Wiklander { 20817c68af4SJens Wiklander struct cts_ctx *c = to_cts_ctx(ctx); 20917c68af4SJens Wiklander 210cbda7091SJens Wiklander crypto_cipher_free_ctx(c->cbc); 211cbda7091SJens Wiklander crypto_cipher_free_ctx(c->ecb); 21217c68af4SJens Wiklander free(c); 21317c68af4SJens Wiklander } 21417c68af4SJens Wiklander 21517c68af4SJens Wiklander static void cts_copy_state(struct crypto_cipher_ctx *dst_ctx, 21617c68af4SJens Wiklander struct crypto_cipher_ctx *src_ctx) 21717c68af4SJens Wiklander { 21817c68af4SJens Wiklander struct cts_ctx *src = to_cts_ctx(src_ctx); 21917c68af4SJens Wiklander struct cts_ctx *dst = to_cts_ctx(dst_ctx); 22017c68af4SJens Wiklander 221cbda7091SJens Wiklander crypto_cipher_copy_state(dst->cbc, src->cbc); 222cbda7091SJens Wiklander crypto_cipher_copy_state(dst->ecb, src->ecb); 22317c68af4SJens Wiklander } 22417c68af4SJens Wiklander 22517c68af4SJens Wiklander static const struct crypto_cipher_ops cts_ops = { 22617c68af4SJens Wiklander .init = cts_init, 22717c68af4SJens Wiklander .update = cts_update, 22817c68af4SJens Wiklander .final = cts_final, 22917c68af4SJens Wiklander .free_ctx = cts_free_ctx, 23017c68af4SJens Wiklander .copy_state = cts_copy_state, 23117c68af4SJens Wiklander }; 23217c68af4SJens Wiklander 23317c68af4SJens Wiklander TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx) 23417c68af4SJens Wiklander { 23517c68af4SJens Wiklander TEE_Result res = TEE_SUCCESS; 23617c68af4SJens Wiklander struct cts_ctx *c = calloc(1, sizeof(*c)); 23717c68af4SJens Wiklander 23817c68af4SJens Wiklander if (!c) 23917c68af4SJens Wiklander return TEE_ERROR_OUT_OF_MEMORY; 24017c68af4SJens Wiklander 24117c68af4SJens Wiklander res = crypto_aes_ecb_alloc_ctx(&c->ecb); 24217c68af4SJens Wiklander if (res) 24317c68af4SJens Wiklander goto err; 24417c68af4SJens Wiklander res = crypto_aes_cbc_alloc_ctx(&c->cbc); 24517c68af4SJens Wiklander if (res) 24617c68af4SJens Wiklander goto err; 24717c68af4SJens Wiklander 24817c68af4SJens Wiklander c->ctx.ops = &cts_ops; 24917c68af4SJens Wiklander *ctx = &c->ctx; 25017c68af4SJens Wiklander 25117c68af4SJens Wiklander return TEE_SUCCESS; 25217c68af4SJens Wiklander err: 253cbda7091SJens Wiklander crypto_cipher_free_ctx(c->ecb); 25417c68af4SJens Wiklander free(c); 25517c68af4SJens Wiklander 25617c68af4SJens Wiklander return res; 25717c68af4SJens Wiklander } 258