@@ -106,17 +106,16 @@ 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;
118
- size_t out_length = 0 ;
119
- size_t tag_out_length = 0 ;
116
+ psa_status_t status = PSA_SUCCESS;
117
+ size_t out_length = 0 ;
118
+ size_t tag_out_length = 0 ;
120
119
121
120
status = psa_aead_encrypt_setup (&operation, key.As <psa_key_id_t >(), algorithm);
122
121
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
@@ -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)
@@ -147,13 +146,14 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
147
146
// psa_aead_update() requires use of the macro PSA_AEAD_UPDATE_OUTPUT_SIZE to determine the output buffer size.
148
147
// For AES-CCM, PSA_AEAD_UPDATE_OUTPUT_SIZE will round up the size to the next multiple of the block size (16).
149
148
// If the ciphertext length is not a multiple of the block size, we will encrypt in two steps, first with the
150
- // block_aligned_length, and then with a rounded up partial_block_length, where a temporary buffer will be used for the output.
149
+ // block_aligned_length, and then with a rounded up partial_block_length, where a temporary buffer will be used for the
150
+ // output.
151
151
constexpr uint8_t kBlockSize = PSA_BLOCK_CIPHER_BLOCK_LENGTH (PSA_KEY_TYPE_AES);
152
152
size_t block_aligned_length = (plaintext_length / kBlockSize ) * kBlockSize ;
153
153
size_t partial_block_length = plaintext_length % kBlockSize ;
154
- size_t ciphertext_length = 0 ;
155
- uint8_t temp[kBlockSize ];
156
-
154
+ size_t ciphertext_length = 0 ;
155
+ uint8_t temp[kBlockSize ] = { 0 } ;
156
+
157
157
// Make sure the calculated block_aligned_length is compliant with PSA's output size requirements.
158
158
VerifyOrReturnError (block_aligned_length == PSA_AEAD_UPDATE_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm, block_aligned_length),
159
159
CHIP_ERROR_INTERNAL);
@@ -164,26 +164,28 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
164
164
VerifyOrReturnError (out_length == block_aligned_length, CHIP_ERROR_INTERNAL);
165
165
ciphertext_length += out_length;
166
166
167
- if (partial_block_length > 0 )
167
+ if (partial_block_length > 0 )
168
168
{
169
169
// The update output should fit in the temp buffer
170
170
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
171
173
172
// Add the non-aligned end of the plaintext
174
- status = psa_aead_update (&operation, &plaintext[block_aligned_length], partial_block_length, temp, max_output, &out_length);
173
+ status =
174
+ psa_aead_update (&operation, &plaintext[block_aligned_length], partial_block_length, temp, max_output, &out_length);
175
175
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
176
+ VerifyOrReturnError (ciphertext_length + out_length <= plaintext_length, CHIP_ERROR_INTERNAL);
176
177
// Add the encrypted output, if any
177
178
memcpy (&ciphertext[ciphertext_length], temp, out_length);
178
179
ciphertext_length += out_length;
179
180
}
180
-
181
+
181
182
// The finish output should fit in the temp buffer
182
183
size_t max_finish = PSA_AEAD_FINISH_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm);
183
184
VerifyOrReturnError (max_finish <= sizeof (temp), CHIP_ERROR_BUFFER_TOO_SMALL);
184
185
185
186
// The finish may return the last part of the ciphertext
186
187
status = psa_aead_finish (&operation, temp, max_finish, &out_length, tag, tag_length, &tag_out_length);
188
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
187
189
VerifyOrReturnError (ciphertext_length + out_length <= plaintext_length, CHIP_ERROR_INTERNAL);
188
190
// Add the encrypted output, if any
189
191
memcpy (&ciphertext[ciphertext_length], temp, out_length);
@@ -205,9 +207,9 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length,
205
207
VerifyOrReturnError (aad != nullptr || aad_length == 0 , CHIP_ERROR_INVALID_ARGUMENT);
206
208
207
209
const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG (PSA_ALG_CCM, tag_length);
208
- psa_status_t status = PSA_SUCCESS;
209
210
psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
210
- size_t outLength;
211
+ psa_status_t status = PSA_SUCCESS;
212
+ size_t out_length;
211
213
212
214
status = psa_aead_decrypt_setup (&operation, key.As <psa_key_id_t >(), algorithm);
213
215
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
@@ -218,32 +220,71 @@ CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length,
218
220
status = psa_aead_set_nonce (&operation, nonce, nonce_length);
219
221
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
220
222
221
- if (aad_length != 0 )
223
+ if (0 == aad_length )
222
224
{
223
- status = psa_aead_update_ad (&operation, aad, aad_length);
224
- VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
225
+ ChipLogDetail (Crypto, " AES_CCM_decrypt: Using aad == null path" );
225
226
}
226
227
else
227
228
{
228
- ChipLogDetail (Crypto, " AES_CCM_decrypt: Using aad == null path" );
229
+ status = psa_aead_update_ad (&operation, aad, aad_length);
230
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
229
231
}
230
232
231
- if (ciphertext_length != 0 )
233
+ if (0 == ciphertext_length )
232
234
{
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);
235
+ status = psa_aead_verify (&operation, nullptr , 0 , &out_length, tag, tag_length);
241
236
}
242
237
else
243
238
{
244
- status = psa_aead_verify (&operation, nullptr , 0 , &outLength, tag, tag_length);
245
- }
239
+ // psa_aead_update() requires use of the macro PSA_AEAD_UPDATE_OUTPUT_SIZE to determine the output buffer size.
240
+ // For AES-CCM, PSA_AEAD_UPDATE_OUTPUT_SIZE will round up the size to the next multiple of the block size (16).
241
+ // If the plaintext length is not a multiple of the block size, we will encrypt in two steps, first with the
242
+ // block_aligned_length, and then with a rounded up partial_block_length, where a temporary buffer will be used for the
243
+ // output.
244
+ constexpr uint8_t kBlockSize = PSA_BLOCK_CIPHER_BLOCK_LENGTH (PSA_KEY_TYPE_AES);
245
+ size_t block_aligned_length = (ciphertext_length / kBlockSize ) * kBlockSize ;
246
+ size_t partial_block_length = ciphertext_length % kBlockSize ;
247
+ size_t plaintext_length = 0 ;
248
+ uint8_t temp[kBlockSize ] = { 0 };
249
+
250
+ // Make sure the calculated block_aligned_length is compliant with PSA's output size requirements.
251
+ VerifyOrReturnError (block_aligned_length == PSA_AEAD_UPDATE_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm, block_aligned_length),
252
+ CHIP_ERROR_INTERNAL);
253
+
254
+ // Add the aligned part of the ciphertext
255
+ status = psa_aead_update (&operation, ciphertext, block_aligned_length, plaintext, block_aligned_length, &out_length);
256
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
257
+ VerifyOrReturnError (out_length == block_aligned_length, CHIP_ERROR_INTERNAL);
258
+ plaintext_length += out_length;
246
259
260
+ if (partial_block_length > 0 )
261
+ {
262
+ // The update output should fit in the temp buffer
263
+ size_t max_output = PSA_AEAD_UPDATE_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm, partial_block_length);
264
+
265
+ // Add the non-aligned end of the ciphertext
266
+ status =
267
+ psa_aead_update (&operation, &ciphertext[block_aligned_length], partial_block_length, temp, max_output, &out_length);
268
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
269
+ VerifyOrReturnError (plaintext_length + out_length <= ciphertext_length, CHIP_ERROR_INTERNAL);
270
+ // Add the decrypted output, if any
271
+ memcpy (&plaintext[plaintext_length], temp, out_length);
272
+ plaintext_length += out_length;
273
+ }
274
+
275
+ // The finish output should fit in the temp buffer
276
+ size_t max_verify = PSA_AEAD_VERIFY_OUTPUT_SIZE (PSA_KEY_TYPE_AES, algorithm);
277
+ VerifyOrReturnError (max_verify <= sizeof (temp), CHIP_ERROR_BUFFER_TOO_SMALL);
278
+
279
+ // Complete verification
280
+ status = psa_aead_verify (&operation, temp, max_verify, &out_length, tag, tag_length);
281
+ VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
282
+ VerifyOrReturnError (plaintext_length + out_length <= ciphertext_length, CHIP_ERROR_INTERNAL);
283
+ // Add the decrypted output, if any
284
+ memcpy (&plaintext[plaintext_length], temp, out_length);
285
+ plaintext_length += out_length;
286
+ VerifyOrReturnError (ciphertext_length == plaintext_length, CHIP_ERROR_INTERNAL);
287
+ }
247
288
VerifyOrReturnError (status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
248
289
249
290
return CHIP_NO_ERROR;
0 commit comments