1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2018-2021 NXP
4 *
5 * Implementation of Cipher XTS functions
6 */
7 #include <caam_common.h>
8 #include <caam_utils_mem.h>
9 #include <caam_utils_status.h>
10 #include <mm/core_memprot.h>
11 #include <string.h>
12
13 #include "local.h"
14
15 /*
16 * Galois Multiplication
17 *
18 * @buf [in/out] buffer to multiply
19 */
do_galois_mult(struct caambuf * buf)20 static void do_galois_mult(struct caambuf *buf)
21 {
22 size_t idx = 0;
23 uint8_t tmp = 0;
24 uint8_t tmptmp = 0;
25
26 for (idx = 0; idx < buf->length; idx++) {
27 tmptmp = buf->data[idx] >> 7;
28 buf->data[idx] = (buf->data[idx] << 1) | tmp;
29 tmp = tmptmp;
30 }
31
32 if (tmptmp)
33 buf->data[0] ^= 0x87;
34 }
35
36 /*
37 * Tweak a cipher block (XTS mode)
38 *
39 * @ctx Cipher context
40 * @enc_tweak [in/out] Encrypted tweak (Galois multiplication)
41 * @srcbuf Source data to encrypt/decrypt
42 * @dstbuf [out] Destination data encrypted/decrypted
43 * @tmp Temporary data buffer
44 */
do_tweak_block(struct cipherdata * ctx,struct caambuf * enc_tweak,struct caambuf * srcbuf,struct caambuf * dstbuf,struct caamdmaobj * tmp)45 static TEE_Result do_tweak_block(struct cipherdata *ctx,
46 struct caambuf *enc_tweak,
47 struct caambuf *srcbuf, struct caambuf *dstbuf,
48 struct caamdmaobj *tmp)
49 {
50 enum caam_status retstatus = CAAM_FAILURE;
51 unsigned int idx = 0;
52
53 /*
54 * TODO: Optimization by using CAAM to do it with MATH op in the
55 * operation description
56 */
57 for (idx = 0; idx < ctx->alg->size_block; idx++)
58 tmp->orig.data[idx] = srcbuf->data[idx] ^ enc_tweak->data[idx];
59
60 retstatus = caam_cipher_block(ctx, false, NEED_KEY1, ctx->encrypt, tmp,
61 tmp);
62
63 if (retstatus != CAAM_NO_ERROR)
64 return caam_status_to_tee_result(retstatus);
65
66 caam_dmaobj_copy_to_orig(tmp);
67
68 for (idx = 0; idx < ctx->alg->size_block; idx++)
69 dstbuf->data[idx] = tmp->orig.data[idx] ^ enc_tweak->data[idx];
70
71 /* Galois field multiplication of the tweak */
72 do_galois_mult(enc_tweak);
73
74 return TEE_SUCCESS;
75 }
76
caam_cipher_update_xts(struct drvcrypt_cipher_update * dupdate)77 TEE_Result caam_cipher_update_xts(struct drvcrypt_cipher_update *dupdate)
78 {
79 TEE_Result ret = TEE_ERROR_GENERIC;
80 enum caam_status retstatus = CAAM_FAILURE;
81 struct cipherdata *ctx = dupdate->ctx;
82 struct caambuf tmpsrc = { };
83 struct caamdmaobj tmpdst = { };
84 struct caamdmaobj tweak = { };
85 struct caamdmaobj enc_tweak = { };
86 struct caambuf srcbuf = { };
87 struct caambuf dstbuf = { };
88 size_t idx = 0;
89 size_t fullsize = 0;
90 size_t lastblk = 0;
91 paddr_t psrc = 0;
92 paddr_t pdst = 0;
93
94 CIPHER_TRACE("Algo AES XTS length=%zu - %s", dupdate->src.length,
95 ctx->encrypt ? "Encrypt" : " Decrypt");
96
97 psrc = virt_to_phys(dupdate->src.data);
98 pdst = virt_to_phys(dupdate->dst.data);
99
100 /* Check the payload/cipher physical addresses */
101 if (!psrc || !pdst) {
102 CIPHER_TRACE("Bad Addr (src %#" PRIxPA ") (dst %#" PRIxPA ")",
103 psrc, pdst);
104 return TEE_ERROR_GENERIC;
105 }
106
107 ret = caam_dmaobj_input_sgtbuf(&tweak, ctx->tweak.data,
108 ctx->tweak.length);
109 if (ret)
110 goto out;
111
112 /*
113 * First operation is to encrypt the tweak with the key #2
114 * Allocate the encrypted tweak buffer
115 */
116 ret = caam_dmaobj_output_sgtbuf(&enc_tweak, NULL, 0, ctx->tweak.length);
117 if (ret)
118 goto out;
119
120 ret = caam_dmaobj_output_sgtbuf(&tmpdst, NULL, 0, ctx->alg->size_block);
121 if (ret)
122 goto out;
123
124 retstatus = caam_cipher_block(ctx, false, NEED_KEY2, true, &tweak,
125 &enc_tweak);
126 if (retstatus != CAAM_NO_ERROR) {
127 CIPHER_TRACE("Tweak encryption error");
128 ret = caam_status_to_tee_result(retstatus);
129 goto out;
130 }
131
132 caam_dmaobj_copy_to_orig(&enc_tweak);
133
134 /*
135 * Encrypt or Decrypt input data.
136 * Check if the last block is partial or not
137 * - if last block is partial, rebuild a complete
138 * block using the penultimate complete block
139 * encryption/decryption.
140 * - else do all blocks.
141 */
142
143 /* Calculate the number of complete block */
144 fullsize = dupdate->src.length;
145 lastblk = fullsize % ctx->alg->size_block;
146 fullsize -= lastblk;
147
148 /* One full block is needed */
149 if (!fullsize) {
150 ret = TEE_ERROR_BAD_PARAMETERS;
151 goto out;
152 }
153
154 if (lastblk)
155 fullsize -= ctx->alg->size_block;
156
157 srcbuf.data = dupdate->src.data;
158 srcbuf.length = ctx->alg->size_block;
159 srcbuf.paddr = psrc;
160
161 dstbuf.data = dupdate->dst.data;
162 dstbuf.length = ctx->alg->size_block;
163 dstbuf.paddr = pdst;
164
165 for (; fullsize > 0; fullsize -= ctx->alg->size_block) {
166 CIPHER_TRACE("Tweak block fullsize %zu", fullsize);
167 ret = do_tweak_block(ctx, &enc_tweak.orig, &srcbuf, &dstbuf,
168 &tmpdst);
169
170 CIPHER_TRACE("Tweak block ret 0x%" PRIx32, ret);
171 if (ret)
172 goto out;
173
174 CIPHER_DUMPBUF("Source", srcbuf.data, srcbuf.length);
175 CIPHER_DUMPBUF("Dest", dstbuf.data, dstbuf.length);
176
177 /* Increment the source and destination block */
178 srcbuf.data += ctx->alg->size_block;
179 srcbuf.paddr += ctx->alg->size_block;
180
181 dstbuf.data += ctx->alg->size_block;
182 dstbuf.paddr += ctx->alg->size_block;
183 }
184
185 if (lastblk) {
186 CIPHER_TRACE("Last block size is %zu", lastblk);
187
188 /*
189 * Allocate the temporary buffer containing the
190 * penultimate block computed
191 */
192 retstatus = caam_alloc_align_buf(&tmpsrc, ctx->alg->size_block);
193 if (retstatus != CAAM_NO_ERROR) {
194 ret = caam_status_to_tee_result(retstatus);
195 goto out;
196 }
197
198 if (!ctx->encrypt) {
199 /*
200 * In case of decryption, need to multiply
201 * the tweak first
202 */
203 memcpy(tmpsrc.data, enc_tweak.orig.data,
204 enc_tweak.orig.length);
205 do_galois_mult(&tmpsrc);
206
207 ret = do_tweak_block(ctx, &tmpsrc, &srcbuf,
208 &tmpdst.orig, &tmpdst);
209 } else {
210 ret = do_tweak_block(ctx, &enc_tweak.orig, &srcbuf,
211 &tmpdst.orig, &tmpdst);
212 }
213
214 CIPHER_TRACE("Tweak penultimate block ret 0x%" PRIx32, ret);
215
216 if (ret)
217 goto out;
218
219 /* Build the last block and create the last destination block */
220 for (idx = 0; idx < lastblk; idx++) {
221 tmpsrc.data[idx] =
222 srcbuf.data[ctx->alg->size_block + idx];
223 dstbuf.data[ctx->alg->size_block + idx] =
224 tmpdst.orig.data[idx];
225 }
226
227 for (; idx < ctx->alg->size_block; idx++)
228 tmpsrc.data[idx] = tmpdst.orig.data[idx];
229
230 ret = do_tweak_block(ctx, &enc_tweak.orig, &tmpsrc, &dstbuf,
231 &tmpdst);
232
233 CIPHER_TRACE("Tweak last block ret 0x%" PRIx32, ret);
234 if (ret)
235 goto out;
236
237 CIPHER_DUMPBUF("Source", tmpsrc.data, tmpsrc.length);
238 CIPHER_DUMPBUF("Dest", dstbuf.data, dstbuf.length);
239 }
240
241 /* Finalize by decrypting the tweak back */
242 retstatus = caam_cipher_block(ctx, false, NEED_KEY2, false, &enc_tweak,
243 &tweak);
244 if (retstatus != CAAM_NO_ERROR) {
245 CIPHER_TRACE("Tweak decryption error");
246 ret = caam_status_to_tee_result(retstatus);
247 goto out;
248 }
249
250 caam_dmaobj_copy_to_orig(&tweak);
251
252 ret = TEE_SUCCESS;
253 out:
254 caam_free_buf(&tmpsrc);
255 caam_dmaobj_free(&tmpdst);
256 caam_dmaobj_free(&tweak);
257 caam_dmaobj_free(&enc_tweak);
258
259 return ret;
260 }
261