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 <string.h> 11 #include <tee_api_types.h> 12 #include <tee/tee_cryp_utl.h> 13 #include <util.h> 14 15 16 /* From libtomcrypt doc: 17 * Ciphertext stealing is a method of dealing with messages 18 * in CBC mode which are not a multiple of the block 19 * length. This is accomplished by encrypting the last 20 * ciphertext block in ECB mode, and XOR'ing the output 21 * against the last partial block of plaintext. LibTomCrypt 22 * does not support this mode directly but it is fairly 23 * easy to emulate with a call to the cipher's 24 * ecb encrypt() callback function. 25 * The more sane way to deal with partial blocks is to pad 26 * them with zeroes, and then use CBC normally 27 */ 28 29 /* 30 * From Global Platform: CTS = CBC-CS3 31 */ 32 33 struct cts_ctx { 34 struct crypto_cipher_ctx ctx; 35 struct crypto_cipher_ctx *ecb; 36 struct crypto_cipher_ctx *cbc; 37 TEE_OperationMode mode; 38 }; 39 40 static const struct crypto_cipher_ops cts_ops; 41 42 static struct cts_ctx *to_cts_ctx(struct crypto_cipher_ctx *ctx) 43 { 44 assert(ctx && ctx->ops == &cts_ops); 45 46 return container_of(ctx, struct cts_ctx, ctx); 47 } 48 49 static TEE_Result cts_init(struct crypto_cipher_ctx *ctx, 50 TEE_OperationMode mode, const uint8_t *key1, 51 size_t key1_len, const uint8_t *key2, 52 size_t key2_len, const uint8_t *iv, size_t iv_len) 53 { 54 TEE_Result res = TEE_SUCCESS; 55 struct cts_ctx *c = to_cts_ctx(ctx); 56 57 c->mode = mode; 58 59 res = crypto_cipher_init(c->ecb, mode, key1, key1_len, key2, key2_len, 60 iv, iv_len); 61 if (res) 62 return res; 63 64 return crypto_cipher_init(c->cbc, mode, key1, key1_len, key2, key2_len, 65 iv, iv_len); 66 } 67 68 /* 69 * From http://en.wikipedia.org/wiki/Ciphertext_stealing 70 * CBC ciphertext stealing encryption using a standard 71 * CBC interface: 72 * 1. Pad the last partial plaintext block with 0. 73 * 2. Encrypt the whole padded plaintext using the 74 * standard CBC mode. 75 * 3. Swap the last two ciphertext blocks. 76 * 4. Truncate the ciphertext to the length of the 77 * original plaintext. 78 * 79 * CBC ciphertext stealing decryption using a standard 80 * CBC interface 81 * 1. Dn = Decrypt (K, Cn-1). Decrypt the second to last 82 * ciphertext block. 83 * 2. Cn = Cn || Tail (Dn, B-M). Pad the ciphertext to the 84 * nearest multiple of the block size using the last 85 * B-M bits of block cipher decryption of the 86 * second-to-last ciphertext block. 87 * 3. Swap the last two ciphertext blocks. 88 * 4. Decrypt the (modified) ciphertext using the standard 89 * CBC mode. 90 * 5. Truncate the plaintext to the length of the original 91 * ciphertext. 92 */ 93 static TEE_Result cbc_cts_update(void *cbc_ctx, void *ecb_ctx, 94 TEE_OperationMode mode, bool last_block, 95 const uint8_t *data, size_t len, uint8_t *dst) 96 { 97 TEE_Result res = TEE_SUCCESS; 98 uint8_t tmp2_block[64] = { 0 }; 99 uint8_t tmp_block[64] = { 0 }; 100 int len_last_block = 0; 101 int block_size = 16; 102 int nb_blocks = 0; 103 104 if (!last_block) 105 return tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 106 mode, last_block, data, len, dst); 107 108 /* Compute the last block length and check constraints */ 109 nb_blocks = (len + block_size - 1) / block_size; 110 if (nb_blocks < 2) 111 return TEE_ERROR_BAD_STATE; 112 len_last_block = len % block_size; 113 if (len_last_block == 0) 114 len_last_block = block_size; 115 116 if (mode == TEE_MODE_ENCRYPT) { 117 memcpy(tmp_block, 118 data + ((nb_blocks - 1) * block_size), 119 len_last_block); 120 memset(tmp_block + len_last_block, 121 0, 122 block_size - len_last_block); 123 124 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 125 mode, 0, data, 126 (nb_blocks - 1) * block_size, dst); 127 if (res != TEE_SUCCESS) 128 return res; 129 130 memcpy(dst + (nb_blocks - 1) * block_size, 131 dst + (nb_blocks - 2) * block_size, 132 len_last_block); 133 134 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 135 mode, 0, tmp_block, block_size, 136 dst + (nb_blocks - 2) * block_size); 137 if (res != TEE_SUCCESS) 138 return res; 139 } else { 140 /* 1. Decrypt the second to last ciphertext block */ 141 res = tee_do_cipher_update(ecb_ctx, TEE_ALG_AES_ECB_NOPAD, 142 mode, 0, 143 data + (nb_blocks - 2) * block_size, 144 block_size, tmp2_block); 145 if (res != TEE_SUCCESS) 146 return res; 147 148 /* 2. Cn = Cn || Tail (Dn, B-M) */ 149 memcpy(tmp_block, data + ((nb_blocks - 1) * block_size), 150 len_last_block); 151 memcpy(tmp_block + len_last_block, tmp2_block + len_last_block, 152 block_size - len_last_block); 153 154 /* 3. Swap the last two ciphertext blocks */ 155 /* done by passing the correct buffers in step 4. */ 156 157 /* 4. Decrypt the (modified) ciphertext */ 158 if (nb_blocks > 2) { 159 res = tee_do_cipher_update(cbc_ctx, 160 TEE_ALG_AES_CBC_NOPAD, mode, 161 0, data, 162 (nb_blocks - 2) * 163 block_size, dst); 164 if (res != TEE_SUCCESS) 165 return res; 166 } 167 168 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 169 mode, 0, tmp_block, block_size, 170 dst + 171 ((nb_blocks - 2) * block_size)); 172 if (res != TEE_SUCCESS) 173 return res; 174 175 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 176 mode, 0, data + 177 ((nb_blocks - 2) * block_size), 178 block_size, tmp_block); 179 if (res != TEE_SUCCESS) 180 return res; 181 182 /* 5. Truncate the plaintext */ 183 memcpy(dst + (nb_blocks - 1) * block_size, tmp_block, 184 len_last_block); 185 } 186 return TEE_SUCCESS; 187 } 188 189 static TEE_Result cts_update(struct crypto_cipher_ctx *ctx, bool last_block, 190 const uint8_t *data, size_t len, uint8_t *dst) 191 { 192 struct cts_ctx *c = to_cts_ctx(ctx); 193 194 return cbc_cts_update(c->cbc, c->ecb, c->mode, last_block, data, len, 195 dst); 196 } 197 198 static void cts_final(struct crypto_cipher_ctx *ctx) 199 { 200 struct cts_ctx *c = to_cts_ctx(ctx); 201 202 crypto_cipher_final(c->cbc); 203 crypto_cipher_final(c->ecb); 204 } 205 206 static void cts_free_ctx(struct crypto_cipher_ctx *ctx) 207 { 208 struct cts_ctx *c = to_cts_ctx(ctx); 209 210 crypto_cipher_free_ctx(c->cbc); 211 crypto_cipher_free_ctx(c->ecb); 212 free(c); 213 } 214 215 static void cts_copy_state(struct crypto_cipher_ctx *dst_ctx, 216 struct crypto_cipher_ctx *src_ctx) 217 { 218 struct cts_ctx *src = to_cts_ctx(src_ctx); 219 struct cts_ctx *dst = to_cts_ctx(dst_ctx); 220 221 crypto_cipher_copy_state(dst->cbc, src->cbc); 222 crypto_cipher_copy_state(dst->ecb, src->ecb); 223 } 224 225 static const struct crypto_cipher_ops cts_ops = { 226 .init = cts_init, 227 .update = cts_update, 228 .final = cts_final, 229 .free_ctx = cts_free_ctx, 230 .copy_state = cts_copy_state, 231 }; 232 233 TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx) 234 { 235 TEE_Result res = TEE_SUCCESS; 236 struct cts_ctx *c = calloc(1, sizeof(*c)); 237 238 if (!c) 239 return TEE_ERROR_OUT_OF_MEMORY; 240 241 res = crypto_aes_ecb_alloc_ctx(&c->ecb); 242 if (res) 243 goto err; 244 res = crypto_aes_cbc_alloc_ctx(&c->cbc); 245 if (res) 246 goto err; 247 248 c->ctx.ops = &cts_ops; 249 *ctx = &c->ctx; 250 251 return TEE_SUCCESS; 252 err: 253 crypto_cipher_free_ctx(c->ecb); 254 free(c); 255 256 return res; 257 } 258