1 /*
2  * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <psa/crypto.h>
8 #include "psa_crypto_client.h"
9 #include "crypto_caller_selector.h"
10 
psa_aead_encrypt_setup(psa_aead_operation_t * operation,psa_key_id_t key,psa_algorithm_t alg)11 psa_status_t psa_aead_encrypt_setup(psa_aead_operation_t *operation,
12 	psa_key_id_t key,
13 	psa_algorithm_t alg)
14 {
15 	if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
16 		return psa_crypto_client_instance.init_status;
17 
18 	return crypto_caller_aead_encrypt_setup(&psa_crypto_client_instance.base,
19 		&operation->handle, key, alg);
20 }
21 
psa_aead_decrypt_setup(psa_aead_operation_t * operation,psa_key_id_t key,psa_algorithm_t alg)22 psa_status_t psa_aead_decrypt_setup(psa_aead_operation_t *operation,
23 	psa_key_id_t key,
24 	psa_algorithm_t alg)
25 {
26 	if (psa_crypto_client_instance.init_status != PSA_SUCCESS)
27 		return psa_crypto_client_instance.init_status;
28 
29 	return crypto_caller_aead_decrypt_setup(&psa_crypto_client_instance.base,
30 		&operation->handle, key, alg);
31 }
32 
psa_aead_generate_nonce(psa_aead_operation_t * operation,uint8_t * nonce,size_t nonce_size,size_t * nonce_length)33 psa_status_t psa_aead_generate_nonce(psa_aead_operation_t *operation,
34 	uint8_t *nonce,
35 	size_t nonce_size,
36 	size_t *nonce_length)
37 {
38 	return crypto_caller_aead_generate_nonce(&psa_crypto_client_instance.base,
39 		operation->handle,
40 		nonce, nonce_size, nonce_length);
41 }
42 
psa_aead_set_nonce(psa_aead_operation_t * operation,const uint8_t * nonce,size_t nonce_length)43 psa_status_t psa_aead_set_nonce(psa_aead_operation_t *operation,
44 	const uint8_t *nonce,
45 	size_t nonce_length)
46 {
47 	return crypto_caller_aead_set_nonce(&psa_crypto_client_instance.base,
48 		operation->handle,
49 		nonce, nonce_length);
50 }
51 
psa_aead_set_lengths(psa_aead_operation_t * operation,size_t ad_length,size_t plaintext_length)52 psa_status_t psa_aead_set_lengths(psa_aead_operation_t *operation,
53 	size_t ad_length,
54 	size_t plaintext_length)
55 {
56 	return crypto_caller_aead_set_lengths(&psa_crypto_client_instance.base,
57 		operation->handle,
58 		ad_length, plaintext_length);
59 }
60 
psa_aead_update_ad(psa_aead_operation_t * operation,const uint8_t * input,size_t input_length)61 psa_status_t psa_aead_update_ad(psa_aead_operation_t *operation,
62 	const uint8_t *input,
63 	size_t input_length)
64 {
65 	return crypto_caller_aead_update_ad(&psa_crypto_client_instance.base,
66 		operation->handle,
67 		input, input_length);
68 }
69 
psa_aead_update(psa_aead_operation_t * operation,const uint8_t * input,size_t input_length,uint8_t * output,size_t output_size,size_t * output_length)70 psa_status_t psa_aead_update(psa_aead_operation_t *operation,
71 	const uint8_t *input,
72 	size_t input_length,
73 	uint8_t *output,
74 	size_t output_size,
75 	size_t *output_length)
76 {
77 	psa_status_t status = crypto_caller_aead_update(&psa_crypto_client_instance.base,
78 		operation->handle,
79 		input, input_length,
80 		output, output_size, output_length);
81 
82 	/*
83 	 * If too small a buffer has been provided for the output, the operation
84 	 * state will have been updated but the result can't be put anywhere. This
85 	 * is an unrecoveral condition so abort the operation.
86 	 */
87 	if (status == PSA_ERROR_BUFFER_TOO_SMALL) {
88 
89 		psa_aead_abort(operation);
90 	}
91 
92 	return status;
93 }
94 
psa_aead_finish(psa_aead_operation_t * operation,uint8_t * aeadtext,size_t aeadtext_size,size_t * aeadtext_length,uint8_t * tag,size_t tag_size,size_t * tag_length)95 psa_status_t psa_aead_finish(psa_aead_operation_t *operation,
96 	uint8_t *aeadtext,
97 	size_t aeadtext_size,
98 	size_t *aeadtext_length,
99 	uint8_t *tag,
100 	size_t tag_size,
101 	size_t *tag_length)
102 {
103 	return crypto_caller_aead_finish(&psa_crypto_client_instance.base,
104 		operation->handle,
105 		aeadtext, aeadtext_size, aeadtext_length,
106 		tag, tag_size, tag_length);
107 }
108 
psa_aead_verify(psa_aead_operation_t * operation,uint8_t * plaintext,size_t plaintext_size,size_t * plaintext_length,const uint8_t * tag,size_t tag_length)109 psa_status_t psa_aead_verify(psa_aead_operation_t *operation,
110 	uint8_t *plaintext,
111 	size_t plaintext_size,
112 	size_t *plaintext_length,
113 	const uint8_t *tag,
114 	size_t tag_length)
115 {
116 	return crypto_caller_aead_verify(&psa_crypto_client_instance.base,
117 		operation->handle,
118 		plaintext, plaintext_size, plaintext_length,
119 		tag, tag_length);
120 }
121 
psa_aead_abort(psa_aead_operation_t * operation)122 psa_status_t psa_aead_abort(psa_aead_operation_t *operation)
123 {
124 	return crypto_caller_aead_abort(&psa_crypto_client_instance.base,
125 		operation->handle);
126 }
127 
multi_aead_update_ad(psa_aead_operation_t * operation,const uint8_t * input,size_t input_length)128 static psa_status_t multi_aead_update_ad(psa_aead_operation_t *operation,
129 	const uint8_t *input,
130 	size_t input_length)
131 {
132 	psa_status_t psa_status = PSA_SUCCESS;
133 	size_t max_update_size =
134 		crypto_caller_aead_max_update_ad_size(&psa_crypto_client_instance.base);
135 	size_t bytes_input = 0;
136 
137 	if (!max_update_size) {
138 
139 		/* Don't know the max update size so assume that the entire
140 		 * input and output can be handled in a single update.  If
141 		 * this isn't true, the first aead update operation will fail
142 		 * safely.
143 		 */
144 		max_update_size = input_length;
145 	}
146 
147 	while (bytes_input < input_length) {
148 
149 		size_t bytes_remaining = input_length - bytes_input;
150 		size_t update_len = (bytes_remaining < max_update_size) ?
151 			bytes_remaining :
152 			max_update_size;
153 
154 		psa_status = psa_aead_update_ad(operation,
155 			&input[bytes_input], update_len);
156 
157 		if (psa_status != PSA_SUCCESS) break;
158 
159 		bytes_input += update_len;
160 	}
161 
162 	return psa_status;
163 }
164 
multi_aead_update(psa_aead_operation_t * operation,const uint8_t * input,size_t input_length,uint8_t * output,size_t output_size,size_t * output_length)165 static psa_status_t multi_aead_update(psa_aead_operation_t *operation,
166 	const uint8_t *input,
167 	size_t input_length,
168 	uint8_t *output,
169 	size_t output_size,
170 	size_t *output_length)
171 {
172 	psa_status_t psa_status = PSA_SUCCESS;
173 	size_t max_update_size =
174 		crypto_caller_aead_max_update_size(&psa_crypto_client_instance.base);
175 	size_t bytes_input = 0;
176 	size_t bytes_output = 0;
177 
178 	*output_length = 0;
179 
180 	if (!max_update_size) {
181 
182 		/* Don't know the max update size so assume that the entire
183 		 * input and output can be handled in a single update.  If
184 		 * this isn't true, the first aead update operation will fail
185 		 * safely.
186 		 */
187 		max_update_size = input_length;
188 	}
189 
190 	while ((bytes_input < input_length) && (bytes_output < output_size)) {
191 
192 		size_t update_output_len = 0;
193 		size_t bytes_remaining = input_length - bytes_input;
194 		size_t update_len = (bytes_remaining < max_update_size) ?
195 			bytes_remaining :
196 			max_update_size;
197 
198 		psa_status = psa_aead_update(operation,
199 			&input[bytes_input], update_len,
200 			&output[bytes_output], output_size - bytes_output, &update_output_len);
201 
202 		if (psa_status != PSA_SUCCESS) break;
203 
204 		bytes_input += update_len;
205 		bytes_output += update_output_len;
206 	}
207 
208 	if (psa_status == PSA_SUCCESS) {
209 
210 		*output_length = bytes_output;
211 	}
212 
213 	return psa_status;
214 }
215 
psa_aead_encrypt(psa_key_id_t key,psa_algorithm_t alg,const uint8_t * nonce,size_t nonce_length,const uint8_t * additional_data,size_t additional_data_length,const uint8_t * plaintext,size_t plaintext_length,uint8_t * aeadtext,size_t aeadtext_size,size_t * aeadtext_length)216 psa_status_t psa_aead_encrypt(psa_key_id_t key,
217 	psa_algorithm_t alg,
218 	const uint8_t *nonce,
219 	size_t nonce_length,
220 	const uint8_t *additional_data,
221 	size_t additional_data_length,
222 	const uint8_t *plaintext,
223 	size_t plaintext_length,
224 	uint8_t *aeadtext,
225 	size_t aeadtext_size,
226 	size_t *aeadtext_length)
227 {
228 	psa_aead_operation_t operation = psa_aead_operation_init();
229 	size_t bytes_output = 0;
230 	*aeadtext_length = 0;
231 
232 	psa_status_t psa_status = psa_aead_encrypt_setup(&operation, key, alg);
233 	if (psa_status != PSA_SUCCESS) return psa_status;
234 
235 	if ((psa_status = psa_aead_set_lengths(&operation, additional_data_length, plaintext_length),
236 			psa_status == PSA_SUCCESS) &&
237 		(psa_status = psa_aead_set_nonce(&operation, nonce, nonce_length),
238 			psa_status == PSA_SUCCESS) &&
239 		(psa_status = multi_aead_update_ad(&operation, additional_data, additional_data_length),
240 			psa_status == PSA_SUCCESS) &&
241 		(psa_status = multi_aead_update(&operation, plaintext, plaintext_length,
242 			aeadtext, aeadtext_size, &bytes_output),
243 			psa_status == PSA_SUCCESS))
244 	{
245 		size_t remaining_aead_len = 0;
246 		size_t tag_len = 0;
247 
248 		psa_status = psa_aead_finish(&operation,
249 			NULL, 0, &remaining_aead_len,
250 			&aeadtext[bytes_output], aeadtext_size - bytes_output, &tag_len);
251 
252 		if (psa_status == PSA_SUCCESS) {
253 
254 			*aeadtext_length = bytes_output + remaining_aead_len + tag_len;
255 		}
256 		else {
257 
258 			psa_aead_abort(&operation);
259 		}
260 	}
261 	else {
262 
263 		psa_aead_abort(&operation);
264 	}
265 
266 	return psa_status;
267 }
268 
psa_aead_decrypt(psa_key_id_t key,psa_algorithm_t alg,const uint8_t * nonce,size_t nonce_length,const uint8_t * additional_data,size_t additional_data_length,const uint8_t * aeadtext,size_t aeadtext_length,uint8_t * plaintext,size_t plaintext_size,size_t * plaintext_length)269 psa_status_t psa_aead_decrypt(psa_key_id_t key,
270 	psa_algorithm_t alg,
271 	const uint8_t *nonce,
272 	size_t nonce_length,
273 	const uint8_t *additional_data,
274 	size_t additional_data_length,
275 	const uint8_t *aeadtext,
276 	size_t aeadtext_length,
277 	uint8_t *plaintext,
278 	size_t plaintext_size,
279 	size_t *plaintext_length)
280 {
281 	psa_aead_operation_t operation = psa_aead_operation_init();
282 	size_t bytes_output = 0;
283 	*plaintext_length = 0;
284 
285 	psa_status_t psa_status = psa_aead_decrypt_setup(&operation, key, alg);
286 	if (psa_status != PSA_SUCCESS) return psa_status;
287 
288 	size_t tag_len = PSA_ALG_AEAD_GET_TAG_LENGTH(alg);
289 	size_t ciphertext_len = (aeadtext_length > tag_len) ? aeadtext_length - tag_len : 0;
290 
291 	if ((psa_status = psa_aead_set_lengths(&operation, additional_data_length, ciphertext_len),
292 			psa_status == PSA_SUCCESS) &&
293 		(psa_status = psa_aead_set_nonce(&operation, nonce, nonce_length),
294 			psa_status == PSA_SUCCESS) &&
295 		(psa_status = multi_aead_update_ad(&operation, additional_data, additional_data_length),
296 			psa_status == PSA_SUCCESS) &&
297 		(psa_status = multi_aead_update(&operation, aeadtext, ciphertext_len,
298 			plaintext, plaintext_size, &bytes_output),
299 			psa_status == PSA_SUCCESS))
300 	{
301 		size_t remaining_plaintext_len = 0;
302 
303 		psa_status = psa_aead_verify(&operation,
304 			NULL, 0, &remaining_plaintext_len,
305 			&aeadtext[bytes_output], aeadtext_length - bytes_output);
306 
307 		if (psa_status == PSA_SUCCESS) {
308 
309 			*plaintext_length = bytes_output + remaining_plaintext_len;
310 		}
311 		else {
312 
313 			psa_aead_abort(&operation);
314 		}
315 	}
316 	else {
317 
318 		psa_aead_abort(&operation);
319 	}
320 
321 	return psa_status;
322 }
323