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; 98 int nb_blocks, len_last_block, block_size = 16; 99 uint8_t tmp_block[64], tmp2_block[64]; 100 101 if (!last_block) 102 return tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 103 mode, last_block, data, len, dst); 104 105 /* Compute the last block length and check constraints */ 106 nb_blocks = ((len + block_size - 1) / block_size); 107 if (nb_blocks < 2) 108 return TEE_ERROR_BAD_STATE; 109 len_last_block = len % block_size; 110 if (len_last_block == 0) 111 len_last_block = block_size; 112 113 if (mode == TEE_MODE_ENCRYPT) { 114 memcpy(tmp_block, 115 data + ((nb_blocks - 1) * block_size), 116 len_last_block); 117 memset(tmp_block + len_last_block, 118 0, 119 block_size - len_last_block); 120 121 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 122 mode, 0, data, 123 (nb_blocks - 1) * block_size, dst); 124 if (res != TEE_SUCCESS) 125 return res; 126 127 memcpy(dst + (nb_blocks - 1) * block_size, 128 dst + (nb_blocks - 2) * block_size, 129 len_last_block); 130 131 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 132 mode, 0, tmp_block, block_size, 133 dst + (nb_blocks - 2) * block_size); 134 if (res != TEE_SUCCESS) 135 return res; 136 } else { 137 /* 1. Decrypt the second to last ciphertext block */ 138 res = tee_do_cipher_update(ecb_ctx, TEE_ALG_AES_ECB_NOPAD, 139 mode, 0, 140 data + (nb_blocks - 2) * block_size, 141 block_size, tmp2_block); 142 if (res != TEE_SUCCESS) 143 return res; 144 145 /* 2. Cn = Cn || Tail (Dn, B-M) */ 146 memcpy(tmp_block, data + ((nb_blocks - 1) * block_size), 147 len_last_block); 148 memcpy(tmp_block + len_last_block, tmp2_block + len_last_block, 149 block_size - len_last_block); 150 151 /* 3. Swap the last two ciphertext blocks */ 152 /* done by passing the correct buffers in step 4. */ 153 154 /* 4. Decrypt the (modified) ciphertext */ 155 if (nb_blocks > 2) { 156 res = tee_do_cipher_update(cbc_ctx, 157 TEE_ALG_AES_CBC_NOPAD, mode, 158 0, data, 159 (nb_blocks - 2) * 160 block_size, dst); 161 if (res != TEE_SUCCESS) 162 return res; 163 } 164 165 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 166 mode, 0, tmp_block, block_size, 167 dst + 168 ((nb_blocks - 2) * block_size)); 169 if (res != TEE_SUCCESS) 170 return res; 171 172 res = tee_do_cipher_update(cbc_ctx, TEE_ALG_AES_CBC_NOPAD, 173 mode, 0, data + 174 ((nb_blocks - 2) * block_size), 175 block_size, tmp_block); 176 if (res != TEE_SUCCESS) 177 return res; 178 179 /* 5. Truncate the plaintext */ 180 memcpy(dst + (nb_blocks - 1) * block_size, tmp_block, 181 len_last_block); 182 } 183 return TEE_SUCCESS; 184 } 185 186 static TEE_Result cts_update(struct crypto_cipher_ctx *ctx, bool last_block, 187 const uint8_t *data, size_t len, uint8_t *dst) 188 { 189 struct cts_ctx *c = to_cts_ctx(ctx); 190 191 return cbc_cts_update(c->cbc, c->ecb, c->mode, last_block, data, len, 192 dst); 193 } 194 195 static void cts_final(struct crypto_cipher_ctx *ctx) 196 { 197 struct cts_ctx *c = to_cts_ctx(ctx); 198 199 crypto_cipher_final(c->cbc); 200 crypto_cipher_final(c->ecb); 201 } 202 203 static void cts_free_ctx(struct crypto_cipher_ctx *ctx) 204 { 205 struct cts_ctx *c = to_cts_ctx(ctx); 206 207 crypto_cipher_free_ctx(c->cbc); 208 crypto_cipher_free_ctx(c->ecb); 209 free(c); 210 } 211 212 static void cts_copy_state(struct crypto_cipher_ctx *dst_ctx, 213 struct crypto_cipher_ctx *src_ctx) 214 { 215 struct cts_ctx *src = to_cts_ctx(src_ctx); 216 struct cts_ctx *dst = to_cts_ctx(dst_ctx); 217 218 crypto_cipher_copy_state(dst->cbc, src->cbc); 219 crypto_cipher_copy_state(dst->ecb, src->ecb); 220 } 221 222 static const struct crypto_cipher_ops cts_ops = { 223 .init = cts_init, 224 .update = cts_update, 225 .final = cts_final, 226 .free_ctx = cts_free_ctx, 227 .copy_state = cts_copy_state, 228 }; 229 230 TEE_Result crypto_aes_cts_alloc_ctx(struct crypto_cipher_ctx **ctx) 231 { 232 TEE_Result res = TEE_SUCCESS; 233 struct cts_ctx *c = calloc(1, sizeof(*c)); 234 235 if (!c) 236 return TEE_ERROR_OUT_OF_MEMORY; 237 238 res = crypto_aes_ecb_alloc_ctx(&c->ecb); 239 if (res) 240 goto err; 241 res = crypto_aes_cbc_alloc_ctx(&c->cbc); 242 if (res) 243 goto err; 244 245 c->ctx.ops = &cts_ops; 246 *ctx = &c->ctx; 247 248 return TEE_SUCCESS; 249 err: 250 crypto_cipher_free_ctx(c->ecb); 251 free(c); 252 253 return res; 254 } 255