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