@@ -106,15 +106,14 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
106
106
const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext,
107
107
uint8_t * tag, size_t tag_length)
108
108
{
109
- ChipLogDetail (Crypto, " ~~~ AES_CCM_encrypt, pl:%u" , (unsigned )plaintext_length);
110
109
VerifyOrReturnError (IsBufferNonEmpty (nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT);
111
110
VerifyOrReturnError (IsValidTag (tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT);
112
111
VerifyOrReturnError ((ciphertext != nullptr && plaintext != nullptr ) || plaintext_length == 0 , CHIP_ERROR_INVALID_ARGUMENT);
113
112
VerifyOrReturnError (aad != nullptr || aad_length == 0 , CHIP_ERROR_INVALID_ARGUMENT);
114
113
115
114
const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG (PSA_ALG_CCM, tag_length);
116
- psa_status_t status = PSA_SUCCESS;
117
115
psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
116
+ psa_status_t status = PSA_SUCCESS;
118
117
size_t out_length = 0 ;
119
118
size_t tag_out_length = 0 ;
120
119
@@ -127,14 +126,14 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
127
126
status = psa_aead_set_nonce (&operation, nonce, nonce_length);
128
127
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
129
128
130
- if (aad_length != 0 )
129
+ if (0 == aad_length )
131
130
{
132
- status = psa_aead_update_ad (&operation, aad, aad_length);
133
- VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
131
+ ChipLogDetail (Crypto, " AES_CCM_encrypt: Using aad == null path" );
134
132
}
135
133
else
136
134
{
137
- ChipLogDetail (Crypto, " AES_CCM_encrypt: Using aad == null path" );
135
+ status = psa_aead_update_ad (&operation, aad, aad_length);
136
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
138
137
}
139
138
140
139
if (0 == plaintext_length)
@@ -153,7 +152,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
153
152
size_t partial_block_length = plaintext_length % kBlockSize ;
154
153
size_t ciphertext_length = 0 ;
155
154
uint8_t temp[kBlockSize ];
156
-
155
+
157
156
// Make sure the calculated block_aligned_length is compliant with PSA's output size requirements.
158
157
VerifyOrReturnError (block_aligned_length == PSA_AEAD_UPDATE_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm, block_aligned_length),
159
158
CHIP_ERROR_INTERNAL);
@@ -168,7 +167,6 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
168
167
{
169
168
// The update output should fit in the temp buffer
170
169
size_t max_output = PSA_AEAD_UPDATE_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm, partial_block_length);
171
- VerifyOrReturnError (max_output <= sizeof (temp), CHIP_ERROR_BUFFER_TOO_SMALL);
172
170
173
171
// Add the non-aligned end of the plaintext
174
172
status = psa_aead_update (&operation, &plaintext[block_aligned_length], partial_block_length, temp, max_output, &out_length);
@@ -177,7 +175,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
177
175
memcpy (&ciphertext[ciphertext_length], temp, out_length);
178
176
ciphertext_length += out_length;
179
177
}
180
-
178
+
181
179
// The finish output should fit in the temp buffer
182
180
size_t max_finish = PSA_AEAD_FINISH_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm);
183
181
VerifyOrReturnError (max_finish <= sizeof (temp), CHIP_ERROR_BUFFER_TOO_SMALL);
@@ -205,9 +203,9 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length,
205
203
VerifyOrReturnError (aad != nullptr || aad_length == 0 , CHIP_ERROR_INVALID_ARGUMENT);
206
204
207
205
const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG (PSA_ALG_CCM, tag_length);
208
- psa_status_t status = PSA_SUCCESS;
209
206
psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
210
- size_t outLength;
207
+ psa_status_t status = PSA_SUCCESS;
208
+ size_t out_length;
211
209
212
210
status = psa_aead_decrypt_setup (&operation, key.As <psa_key_id_t >(), algorithm);
213
211
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
@@ -218,32 +216,66 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length,
218
216
status = psa_aead_set_nonce (&operation, nonce, nonce_length);
219
217
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
220
218
221
- if (aad_length != 0 )
219
+ if (0 == aad_length )
222
220
{
223
- status = psa_aead_update_ad (&operation, aad, aad_length);
224
- VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
221
+ ChipLogDetail (Crypto, " AES_CCM_decrypt: Using aad == null path" );
225
222
}
226
223
else
227
224
{
228
- ChipLogDetail (Crypto, " AES_CCM_decrypt: Using aad == null path" );
225
+ status = psa_aead_update_ad (&operation, aad, aad_length);
226
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
229
227
}
230
228
231
- if (ciphertext_length != 0 )
229
+ if (0 == ciphertext_length )
232
230
{
233
- status = psa_aead_update (&operation, ciphertext, ciphertext_length, plaintext,
234
- PSA_AEAD_UPDATE_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm, ciphertext_length), &outLength);
235
- VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
236
-
237
- plaintext += outLength;
238
-
239
- status = psa_aead_verify (&operation, plaintext, PSA_AEAD_VERIFY_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm), &outLength, tag,
240
- tag_length);
231
+ status = psa_aead_verify (&operation, nullptr , 0 , &out_length, tag, tag_length);
241
232
}
242
233
else
243
234
{
244
- status = psa_aead_verify (&operation, nullptr , 0 , &outLength, tag, tag_length);
245
- }
235
+ // psa_aead_update() requires use of the macro PSA_AEAD_UPDATE_OUTPUT_SIZE to determine the output buffer size.
236
+ // For AES-CCM, PSA_AEAD_UPDATE_OUTPUT_SIZE will round up the size to the next multiple of the block size (16).
237
+ // If the plaintext length is not a multiple of the block size, we will encrypt in two steps, first with the
238
+ // block_aligned_length, and then with a rounded up partial_block_length, where a temporary buffer will be used for the output.
239
+ constexpr uint8_t kBlockSize = PSA_BLOCK_CIPHER_BLOCK_LENGTH (PSA_KEY_TYPE_AES);
240
+ size_t block_aligned_length = (ciphertext_length / kBlockSize ) * kBlockSize ;
241
+ size_t partial_block_length = ciphertext_length % kBlockSize ;
242
+ size_t plaintext_length = 0 ;
243
+ uint8_t temp[kBlockSize ];
244
+
245
+ // Make sure the calculated block_aligned_length is compliant with PSA's output size requirements.
246
+ VerifyOrReturnError (block_aligned_length == PSA_AEAD_UPDATE_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm, block_aligned_length),
247
+ CHIP_ERROR_INTERNAL);
248
+
249
+ // Add the aligned part of the ciphertext
250
+ status = psa_aead_update (&operation, ciphertext, block_aligned_length, plaintext, block_aligned_length, &out_length);
251
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
252
+ VerifyOrReturnError (out_length == block_aligned_length, CHIP_ERROR_INTERNAL);
253
+ plaintext_length += out_length;
246
254
255
+ if (partial_block_length > 0 )
256
+ {
257
+ // The update output should fit in the temp buffer
258
+ size_t max_output = PSA_AEAD_UPDATE_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm, partial_block_length);
259
+
260
+ // Add the non-aligned end of the ciphertext
261
+ status = psa_aead_update (&operation, &ciphertext[block_aligned_length], partial_block_length, temp, max_output, &out_length);
262
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
263
+ // Add the decrypted output, if any
264
+ memcpy (&plaintext[plaintext_length], temp, out_length);
265
+ plaintext_length += out_length;
266
+ }
267
+
268
+ // The finish output should fit in the temp buffer
269
+ size_t max_verify = PSA_AEAD_VERIFY_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm);
270
+ VerifyOrReturnError (max_verify <= sizeof (temp), CHIP_ERROR_BUFFER_TOO_SMALL);
271
+
272
+ // Complete verification
273
+ status = psa_aead_verify (&operation, temp, max_verify, &out_length, tag, tag_length);
274
+ // Add the decrypted output, if any
275
+ memcpy (&plaintext[plaintext_length], temp, out_length);
276
+ plaintext_length += out_length;
277
+ VerifyOrReturnError (ciphertext_length == plaintext_length, CHIP_ERROR_INTERNAL);
278
+ }
247
279
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
248
280
249
281
return CHIP_NO_ERROR;
0 commit comments