Skip to content

Commit bc646ee

Browse files
[Silabs] AES_CCM_decrypt output buffer fixed.
1 parent 92f9f0b commit bc646ee

File tree

1 file changed

+51
-12
lines changed

1 file changed

+51
-12
lines changed

src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp

+51-12
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
106106
const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext,
107107
uint8_t * tag, size_t tag_length)
108108
{
109+
ChipLogDetail(Crypto, "~~~ AES_CCM_encrypt, pl:%u", (unsigned)plaintext_length);
109110
VerifyOrReturnError(IsBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT);
110111
VerifyOrReturnError(IsValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT);
111112
VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || plaintext_length == 0, CHIP_ERROR_INVALID_ARGUMENT);
@@ -114,8 +115,8 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
114115
const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length);
115116
psa_status_t status = PSA_SUCCESS;
116117
psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
117-
size_t out_length;
118-
size_t tag_out_length;
118+
size_t out_length = 0;
119+
size_t tag_out_length = 0;
119120

120121
status = psa_aead_encrypt_setup(&operation, key.As<psa_key_id_t>(), algorithm);
121122
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
@@ -136,20 +137,58 @@ CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, c
136137
ChipLogDetail(Crypto, "AES_CCM_encrypt: Using aad == null path");
137138
}
138139

139-
if (plaintext_length != 0)
140+
if (0 == plaintext_length)
140141
{
141-
status = psa_aead_update(&operation, plaintext, plaintext_length, ciphertext,
142-
PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, plaintext_length), &out_length);
143-
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
144-
145-
ciphertext += out_length;
146-
147-
status = psa_aead_finish(&operation, ciphertext, PSA_AEAD_FINISH_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &out_length, tag,
148-
tag_length, &tag_out_length);
142+
// Empty plaintext
143+
status = psa_aead_finish(&operation, nullptr, 0, &out_length, tag, tag_length, &tag_out_length);
149144
}
150145
else
151146
{
152-
status = psa_aead_finish(&operation, nullptr, 0, &out_length, tag, tag_length, &tag_out_length);
147+
// psa_aead_update() requires use of the macro PSA_AEAD_UPDATE_OUTPUT_SIZE to determine the output buffer size.
148+
// For AES-CCM, PSA_AEAD_UPDATE_OUTPUT_SIZE will round up the size to the next multiple of the block size (16).
149+
// 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.
151+
constexpr uint8_t kBlockSize = PSA_BLOCK_CIPHER_BLOCK_LENGTH(PSA_KEY_TYPE_AES);
152+
size_t block_aligned_length = (plaintext_length / kBlockSize) * kBlockSize;
153+
size_t partial_block_length = plaintext_length % kBlockSize;
154+
size_t ciphertext_length = 0;
155+
uint8_t temp[kBlockSize];
156+
157+
// Make sure the calculated block_aligned_length is compliant with PSA's output size requirements.
158+
VerifyOrReturnError(block_aligned_length == PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, block_aligned_length),
159+
CHIP_ERROR_INTERNAL);
160+
161+
// Add the aligned part of the plaintext
162+
status = psa_aead_update(&operation, plaintext, block_aligned_length, ciphertext, block_aligned_length, &out_length);
163+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
164+
VerifyOrReturnError(out_length == block_aligned_length, CHIP_ERROR_INTERNAL);
165+
ciphertext_length += out_length;
166+
167+
if(partial_block_length > 0)
168+
{
169+
// The update output should fit in the temp buffer
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+
173+
// 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);
175+
VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL);
176+
// Add the encrypted output, if any
177+
memcpy(&ciphertext[ciphertext_length], temp, out_length);
178+
ciphertext_length += out_length;
179+
}
180+
181+
// The finish output should fit in the temp buffer
182+
size_t max_finish = PSA_AEAD_FINISH_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm);
183+
VerifyOrReturnError(max_finish <= sizeof(temp), CHIP_ERROR_BUFFER_TOO_SMALL);
184+
185+
// The finish may return the last part of the ciphertext
186+
status = psa_aead_finish(&operation, temp, max_finish, &out_length, tag, tag_length, &tag_out_length);
187+
VerifyOrReturnError(ciphertext_length + out_length <= plaintext_length, CHIP_ERROR_INTERNAL);
188+
// Add the encrypted output, if any
189+
memcpy(&ciphertext[ciphertext_length], temp, out_length);
190+
ciphertext_length += out_length;
191+
VerifyOrReturnError(ciphertext_length == plaintext_length, CHIP_ERROR_INTERNAL);
153192
}
154193
VerifyOrReturnError(status == PSA_SUCCESS && tag_length == tag_out_length, CHIP_ERROR_INTERNAL);
155194

0 commit comments

Comments
 (0)