diff --git a/src/crypto/BUILD.gn b/src/crypto/BUILD.gn index d0fe7190175ed6..1b782141796bdc 100644 --- a/src/crypto/BUILD.gn +++ b/src/crypto/BUILD.gn @@ -139,13 +139,20 @@ static_library("crypto") { if (chip_crypto == "psa") { sources += [ + "PSAKeyDerivation.cpp", + "PSAKeyDerivation.h", "PSASessionKeystore.cpp", "PSASessionKeystore.h", ] } else { sources += [ - "RawKeySessionKeystore.cpp", - "RawKeySessionKeystore.h", + "PSAKeyDerivation.cpp", + "PSAKeyDerivation.h", + "PSASessionKeystore.cpp", + "PSASessionKeystore.h", + + # "RawKeySessionKeystore.cpp", + # "RawKeySessionKeystore.h", ] } diff --git a/src/crypto/CHIPCryptoPALPSA.cpp b/src/crypto/CHIPCryptoPALPSA.cpp index 5f21030eb69a72..73c05307657704 100644 --- a/src/crypto/CHIPCryptoPALPSA.cpp +++ b/src/crypto/CHIPCryptoPALPSA.cpp @@ -21,6 +21,7 @@ */ #include "CHIPCryptoPALPSA.h" +#include "PSAKeyDerivation.h" #include #include @@ -305,53 +306,6 @@ void Hash_SHA256_stream::Clear() psa_hash_abort(toHashOperation(&mContext)); } -CHIP_ERROR PsaKdf::Init(psa_algorithm_t algorithm, const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info) -{ - psa_status_t status = PSA_SUCCESS; - psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; - - psa_set_key_type(&attrs, PSA_KEY_TYPE_DERIVE); - psa_set_key_algorithm(&attrs, PSA_ALG_HKDF(PSA_ALG_SHA_256)); - psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_DERIVE); - - status = psa_import_key(&attrs, secret.data(), secret.size(), &mSecretKeyId); - psa_reset_key_attributes(&attrs); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - status = psa_key_derivation_setup(&mOperation, algorithm); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - if (salt.size() > 0) - { - status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size()); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - } - - status = psa_key_derivation_input_key(&mOperation, PSA_KEY_DERIVATION_INPUT_SECRET, mSecretKeyId); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size()); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR PsaKdf::DeriveBytes(const MutableByteSpan & output) -{ - psa_status_t status = psa_key_derivation_output_bytes(&mOperation, output.data(), output.size()); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR PsaKdf::DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId) -{ - psa_status_t status = psa_key_derivation_output_key(&attributes, &mOperation, &keyId); - VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - - return CHIP_NO_ERROR; -} - CHIP_ERROR HKDF_sha::HKDF_SHA256(const uint8_t * secret, const size_t secret_length, const uint8_t * salt, const size_t salt_length, const uint8_t * info, const size_t info_length, uint8_t * out_buffer, size_t out_length) { diff --git a/src/crypto/CHIPCryptoPALPSA.h b/src/crypto/CHIPCryptoPALPSA.h index 1a64c1f8794dfa..6033293921a238 100644 --- a/src/crypto/CHIPCryptoPALPSA.h +++ b/src/crypto/CHIPCryptoPALPSA.h @@ -94,54 +94,5 @@ inline const PsaP256KeypairContext & ToConstPsaContext(const P256KeypairContext return *SafePointerCast(&context); } -/** - * @brief Wrapper for PSA key derivation API. - */ -class PsaKdf -{ -public: - ~PsaKdf() - { - psa_key_derivation_abort(&mOperation); - psa_destroy_key(mSecretKeyId); - } - - /** - * @brief Initializes the key derivation operation. - */ - CHIP_ERROR Init(psa_algorithm_t algorithm, const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info); - - /** - * @brief Derives raw key material from the operation. - * - * This method together with @p DeriveKeys can be called multiple times to - * derive several keys. - * - * @param[out] output Span that provides location and length for the derived key material. - * - * @retval CHIP_NO_ERROR On success. - * @retval CHIP_ERROR_INTERNAL On PSA crypto API error. - */ - CHIP_ERROR DeriveBytes(const MutableByteSpan & output); - - /** - * @brief Derives a key from the operation. - * - * This method together with @p DeriveBytes can be called multiple times to - * derive several keys. - * - * @param[in] attributes Attributes of the derived key. - * @param[out] keyId PSA key ID of the derived key. - * - * @retval CHIP_NO_ERROR On success. - * @retval CHIP_ERROR_INTERNAL On PSA crypto API error. - */ - CHIP_ERROR DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId); - -private: - psa_key_id_t mSecretKeyId = 0; - psa_key_derivation_operation_t mOperation = PSA_KEY_DERIVATION_OPERATION_INIT; -}; - } // namespace Crypto } // namespace chip diff --git a/src/crypto/DefaultSessionKeystore.h b/src/crypto/DefaultSessionKeystore.h index 8fa6121af5c20d..914320a3f155de 100644 --- a/src/crypto/DefaultSessionKeystore.h +++ b/src/crypto/DefaultSessionKeystore.h @@ -21,11 +21,11 @@ #include #endif -#if CHIP_CRYPTO_PSA +// #if CHIP_CRYPTO_PSA #include -#else -#include -#endif +// #else +// #include +// #endif namespace chip { namespace Crypto { @@ -34,11 +34,11 @@ namespace Crypto { // when the PSA crypto backend is used, AES encryption/decryption function assume that the input // key handle carries a key reference instead of raw key material, so PSASessionKeystore must be // used instead of RawKeySessionKeystore to initialize the key handle. -#if CHIP_CRYPTO_PSA +// #if CHIP_CRYPTO_PSA using DefaultSessionKeystore = PSASessionKeystore; -#else -using DefaultSessionKeystore = RawKeySessionKeystore; -#endif +// #else +// using DefaultSessionKeystore = RawKeySessionKeystore; +// #endif } // namespace Crypto } // namespace chip diff --git a/src/crypto/PSAKeyDerivation.cpp b/src/crypto/PSAKeyDerivation.cpp new file mode 100644 index 00000000000000..82765ec6f31204 --- /dev/null +++ b/src/crypto/PSAKeyDerivation.cpp @@ -0,0 +1,54 @@ +#include "PSAKeyDerivation.h" + +namespace chip { +namespace Crypto { + +CHIP_ERROR PsaKdf::Init(psa_algorithm_t algorithm, const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info) +{ + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attrs = PSA_KEY_ATTRIBUTES_INIT; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_DERIVE); + psa_set_key_algorithm(&attrs, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_DERIVE); + + status = psa_import_key(&attrs, secret.data(), secret.size(), &mSecretKeyId); + psa_reset_key_attributes(&attrs); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + status = psa_key_derivation_setup(&mOperation, algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + if (salt.size() > 0) + { + status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + } + + status = psa_key_derivation_input_key(&mOperation, PSA_KEY_DERIVATION_INPUT_SECRET, mSecretKeyId); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + status = psa_key_derivation_input_bytes(&mOperation, PSA_KEY_DERIVATION_INPUT_INFO, info.data(), info.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PsaKdf::DeriveBytes(const MutableByteSpan & output) +{ + psa_status_t status = psa_key_derivation_output_bytes(&mOperation, output.data(), output.size()); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR PsaKdf::DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId) +{ + psa_status_t status = psa_key_derivation_output_key(&attributes, &mOperation, &keyId); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; +} + +} // namespace Crypto +} // namespace chip diff --git a/src/crypto/PSAKeyDerivation.h b/src/crypto/PSAKeyDerivation.h new file mode 100644 index 00000000000000..d1f0cde38d717b --- /dev/null +++ b/src/crypto/PSAKeyDerivation.h @@ -0,0 +1,67 @@ + +#pragma once + +#include +#include +// #include +// #include +// #include +// #include +#include +#include + + +namespace chip { +namespace Crypto { + +/** + * @brief Wrapper for PSA key derivation API. + */ +class PsaKdf +{ +public: + ~PsaKdf() + { + psa_key_derivation_abort(&mOperation); + psa_destroy_key(mSecretKeyId); + } + + /** + * @brief Initializes the key derivation operation. + */ + CHIP_ERROR Init(psa_algorithm_t algorithm, const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info); + + /** + * @brief Derives raw key material from the operation. + * + * This method together with @p DeriveKeys can be called multiple times to + * derive several keys. + * + * @param[out] output Span that provides location and length for the derived key material. + * + * @retval CHIP_NO_ERROR On success. + * @retval CHIP_ERROR_INTERNAL On PSA crypto API error. + */ + CHIP_ERROR DeriveBytes(const MutableByteSpan & output); + + /** + * @brief Derives a key from the operation. + * + * This method together with @p DeriveBytes can be called multiple times to + * derive several keys. + * + * @param[in] attributes Attributes of the derived key. + * @param[out] keyId PSA key ID of the derived key. + * + * @retval CHIP_NO_ERROR On success. + * @retval CHIP_ERROR_INTERNAL On PSA crypto API error. + */ + CHIP_ERROR DeriveKey(const psa_key_attributes_t & attributes, psa_key_id_t & keyId); + +private: + psa_key_id_t mSecretKeyId = 0; + psa_key_derivation_operation_t mOperation = PSA_KEY_DERIVATION_OPERATION_INIT; +}; + +} // namespace Crypto +} // namespace chip diff --git a/src/crypto/PSASessionKeystore.cpp b/src/crypto/PSASessionKeystore.cpp index 0b8a237a9d405b..85f8d60d903cd8 100644 --- a/src/crypto/PSASessionKeystore.cpp +++ b/src/crypto/PSASessionKeystore.cpp @@ -16,6 +16,7 @@ */ #include "PSASessionKeystore.h" +#include "PSAKeyDerivation.h" #include @@ -35,7 +36,7 @@ class AesKeyAttributes psa_set_key_type(&mAttrs, PSA_KEY_TYPE_AES); psa_set_key_algorithm(&mAttrs, kAlgorithm); - psa_set_key_usage_flags(&mAttrs, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_usage_flags(&mAttrs, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_EXPORT); psa_set_key_bits(&mAttrs, CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES * 8); } @@ -51,6 +52,8 @@ class AesKeyAttributes CHIP_ERROR PSASessionKeystore::CreateKey(const Aes128KeyByteArray & keyMaterial, Aes128KeyHandle & key) { + Progress::Debug("◇ PSASessionKeystore::CreateKey, key:%04x", (unsigned)key.As()); + // Destroy the old key if already allocated psa_destroy_key(key.As()); @@ -65,6 +68,8 @@ CHIP_ERROR PSASessionKeystore::DeriveKey(const P256ECDHDerivedSecret & secret, c Aes128KeyHandle & key) { PsaKdf kdf; + + Progress::Debug("◇ PSASessionKeystore::DeriveKey, key:%04x", (unsigned)key.As()); ReturnErrorOnFailure(kdf.Init(PSA_ALG_HKDF(PSA_ALG_SHA_256), secret.Span(), salt, info)); AesKeyAttributes attrs; @@ -77,15 +82,26 @@ CHIP_ERROR PSASessionKeystore::DeriveSessionKeys(const ByteSpan & secret, const AttestationChallenge & attestationChallenge) { PsaKdf kdf; - ReturnErrorOnFailure(kdf.Init(PSA_ALG_HKDF(PSA_ALG_SHA_256), secret, salt, info)); - CHIP_ERROR error; AesKeyAttributes attrs; + uint8_t i2r[sizeof(Aes128KeyByteArray)]; + uint8_t r2i[sizeof(Aes128KeyByteArray)]; + size_t key_len = 0; + psa_status_t stat1 = 0; + psa_status_t stat2 = 0; + + ReturnErrorOnFailure(kdf.Init(PSA_ALG_HKDF(PSA_ALG_SHA_256), secret, salt, info)); SuccessOrExit(error = kdf.DeriveKey(attrs.Get(), i2rKey.AsMutable())); SuccessOrExit(error = kdf.DeriveKey(attrs.Get(), r2iKey.AsMutable())); SuccessOrExit(error = kdf.DeriveBytes(MutableByteSpan(attestationChallenge.Bytes(), AttestationChallenge::Capacity()))); + stat1 = psa_export_key(i2rKey.As(), i2r, sizeof(i2r), &key_len); + stat2 = psa_export_key(r2iKey.As(), r2i, sizeof(r2i), &key_len); + + Progress::Debug("◇ PSASessionKeystore::DeriveSessionKeys, I2R:%04x [%02x %02x] !%d, R2I:%04x [%02x %02x] !%d", + (unsigned)i2rKey.As(), i2r[0], i2r[1], stat1, (unsigned)r2iKey.As(), r2i[0], r2i[1], stat2); + exit: if (error != CHIP_NO_ERROR) { @@ -100,6 +116,7 @@ void PSASessionKeystore::DestroyKey(Aes128KeyHandle & key) { auto & keyId = key.AsMutable(); + Progress::Debug("◇ PSASessionKeystore::DestroyKey, key:%04x", (unsigned)key.As()); psa_destroy_key(keyId); keyId = 0; } diff --git a/src/crypto/RawKeySessionKeystore.cpp b/src/crypto/RawKeySessionKeystore.cpp index 9115f248b68f81..30d84741a01614 100644 --- a/src/crypto/RawKeySessionKeystore.cpp +++ b/src/crypto/RawKeySessionKeystore.cpp @@ -28,19 +28,24 @@ using HKDF_sha_crypto = HKDF_sha; CHIP_ERROR RawKeySessionKeystore::CreateKey(const Aes128KeyByteArray & keyMaterial, Aes128KeyHandle & key) { - volatile unsigned e = 0; - Progress::Debug("◉ RawKeySessionKeystore::CreateKey, err:%u", e); - memcpy(key.AsMutable(), keyMaterial, sizeof(Aes128KeyByteArray)); - return CHIP_NO_ERROR; + Progress::Debug("◇ RawKeySessionKeystore::CreateKey"); + // volatile unsigned e = 0; + // Progress::Debug("◇ RawKeySessionKeystore::CreateKey, err:%u", e); + // memcpy(key.AsMutable(), keyMaterial, sizeof(Aes128KeyByteArray)); + // return CHIP_NO_ERROR; + return CHIP_ERROR_ACCESS_DENIED; } CHIP_ERROR RawKeySessionKeystore::DeriveKey(const P256ECDHDerivedSecret & secret, const ByteSpan & salt, const ByteSpan & info, Aes128KeyHandle & key) { HKDF_sha_crypto hkdf; - - return hkdf.HKDF_SHA256(secret.ConstBytes(), secret.Length(), salt.data(), salt.size(), info.data(), info.size(), + CHIP_ERROR err = hkdf.HKDF_SHA256(secret.ConstBytes(), secret.Length(), salt.data(), salt.size(), info.data(), info.size(), key.AsMutable(), sizeof(Aes128KeyByteArray)); + + auto k = key.As(); + Progress::Debug("◇ RawKeySessionKeystore::DeriveKey, key[%02x %02x]", k[0], k[1]); + return err; } CHIP_ERROR RawKeySessionKeystore::DeriveSessionKeys(const ByteSpan & secret, const ByteSpan & salt, const ByteSpan & info, @@ -55,14 +60,23 @@ CHIP_ERROR RawKeySessionKeystore::DeriveSessionKeys(const ByteSpan & secret, con Encoding::LittleEndian::Reader reader(keyMaterial, sizeof(keyMaterial)); - return reader.ReadBytes(i2rKey.AsMutable(), sizeof(Aes128KeyByteArray)) + CHIP_ERROR err = reader.ReadBytes(i2rKey.AsMutable(), sizeof(Aes128KeyByteArray)) .ReadBytes(r2iKey.AsMutable(), sizeof(Aes128KeyByteArray)) .ReadBytes(attestationChallenge.Bytes(), AttestationChallenge::Capacity()) .StatusCode(); + + + auto i2r = i2rKey.As(); + auto r2i = r2iKey.As(); + Progress::Debug("◇ RawKeySessionKeystore::DeriveSessionKeys(%u), I2R[%02x %02x], R2I[%02x %02x]", + sizeof(Aes128KeyByteArray), i2r[0], i2r[1], r2i[0], r2i[1]); + + return err; } void RawKeySessionKeystore::DestroyKey(Aes128KeyHandle & key) { + Progress::Debug("◇ RawKeySessionKeystore::DestroyKey"); ClearSecretData(key.AsMutable()); } diff --git a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp index 9948017c4d3f94..bc50be9e260e19 100644 --- a/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp +++ b/src/platform/silabs/efr32/CHIPCryptoPALPsaEfr32.cpp @@ -118,13 +118,14 @@ static void _log_PSA_error(psa_status_t status) } } -static bool _isValidTagLength(size_t tag_length) +bool isBufferNonEmpty(const uint8_t * data, size_t data_length) { - if (tag_length == 8 || tag_length == 12 || tag_length == 16) - { - return true; - } - return false; + return data != nullptr && data_length > 0; +} + +bool isValidTag(const uint8_t * tag, size_t tag_length) +{ + return tag != nullptr && (tag_length == 8 || tag_length == 12 || tag_length == 16); } /** @@ -157,119 +158,128 @@ static int timeCompare(mbedtls_x509_time * t1, mbedtls_x509_time * t2) return 0; } + CHIP_ERROR AES_CCM_encrypt(const uint8_t * plaintext, size_t plaintext_length, const uint8_t * aad, size_t aad_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * ciphertext, uint8_t * tag, size_t tag_length) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - uint8_t * buffer = nullptr; - bool allocated_buffer = false; + VerifyOrReturnError(isBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(isValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || plaintext_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(aad != nullptr || aad_length == 0, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(CanCastTo(nonce_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); + Progress::Debug("◆ AES_CCM_encrypt, key:%04x", (unsigned)key.As()); - // If the ciphertext and tag outputs aren't a contiguous buffer, the PSA API requires buffer copying - if (Uint8::to_uchar(ciphertext) + plaintext_length != Uint8::to_uchar(tag)) - { - buffer = (uint8_t *) MemoryCalloc(1, plaintext_length + tag_length); - allocated_buffer = true; - VerifyOrExit(buffer != nullptr, error = CHIP_ERROR_NO_MEMORY); - } + const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length); + psa_status_t status = PSA_SUCCESS; + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; + size_t out_length; + size_t tag_out_length; - psa_crypto_init(); - - psa_set_key_type(&attr, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attr, sizeof(Aes128KeyByteArray) * 8); - psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_ENCRYPT); + status = psa_aead_encrypt_setup(&operation, key.As(), algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_driver_wrapper_aead_encrypt( - &attr, key.As(), sizeof(Aes128KeyByteArray), PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), - Uint8::to_const_uchar(nonce), nonce_length, Uint8::to_const_uchar(aad), aad_length, Uint8::to_const_uchar(plaintext), - plaintext_length, allocated_buffer ? buffer : ciphertext, plaintext_length + tag_length, &output_length); + status = psa_aead_set_lengths(&operation, aad_length, plaintext_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == plaintext_length + tag_length, error = CHIP_ERROR_INTERNAL); + status = psa_aead_set_nonce(&operation, nonce, nonce_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - if (allocated_buffer) + if (aad_length != 0) + { + status = psa_aead_update_ad(&operation, aad, aad_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + } + else { - memcpy(Uint8::to_uchar(ciphertext), buffer, plaintext_length); - memcpy(Uint8::to_uchar(tag), buffer + plaintext_length, tag_length); - memset(buffer, 0, plaintext_length + tag_length); + ChipLogDetail(Crypto, "AES_CCM_encrypt: Using aad == null path"); } -exit: - if (allocated_buffer) + if (plaintext_length != 0) { - MemoryFree(buffer); + status = psa_aead_update(&operation, plaintext, plaintext_length, ciphertext, + PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, plaintext_length), &out_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + ciphertext += out_length; + + status = psa_aead_finish(&operation, ciphertext, PSA_AEAD_FINISH_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &out_length, tag, + tag_length, &tag_out_length); } - psa_reset_key_attributes(&attr); - return error; + else + { + status = psa_aead_finish(&operation, nullptr, 0, &out_length, tag, tag_length, &tag_out_length); + } + VerifyOrReturnError(status == PSA_SUCCESS && tag_length == tag_out_length, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; } -CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_len, const uint8_t * aad, size_t aad_len, +CHIP_ERROR AES_CCM_decrypt(const uint8_t * ciphertext, size_t ciphertext_length, const uint8_t * aad, size_t aad_length, const uint8_t * tag, size_t tag_length, const Aes128KeyHandle & key, const uint8_t * nonce, size_t nonce_length, uint8_t * plaintext) { - CHIP_ERROR error = CHIP_NO_ERROR; - psa_status_t status = PSA_ERROR_BAD_STATE; - psa_key_attributes_t attr = PSA_KEY_ATTRIBUTES_INIT; - size_t output_length = 0; - uint8_t * buffer = nullptr; - bool allocated_buffer = false; - VerifyOrExit(_isValidTagLength(tag_length), error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(tag != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce != nullptr, error = CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrExit(nonce_length > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + uint8_t kbuf[sizeof(Aes128KeyByteArray)]; + size_t key_len = 0; + psa_status_t stat = 0; - // If the ciphertext and tag outputs aren't a contiguous buffer, the PSA API requires buffer copying - if (Uint8::to_const_uchar(ciphertext) + ciphertext_len != Uint8::to_const_uchar(tag)) - { - buffer = (uint8_t *) MemoryCalloc(1, ciphertext_len + tag_length); - allocated_buffer = true; - VerifyOrExit(buffer != nullptr, error = CHIP_ERROR_NO_MEMORY); - } + stat = psa_export_key(key.As(), kbuf, sizeof(kbuf), &key_len); - psa_crypto_init(); + Progress::Debug("◇ AES_CCM_decrypt, key(%u):%04x [%02x %02x] !%d", + key_len, (unsigned)key.As(), kbuf[0], kbuf[1], stat); - psa_set_key_type(&attr, PSA_KEY_TYPE_AES); - psa_set_key_bits(&attr, sizeof(Aes128KeyByteArray) * 8); - psa_set_key_algorithm(&attr, PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(PSA_ALG_CCM, 8)); - psa_set_key_usage_flags(&attr, PSA_KEY_USAGE_DECRYPT); + VerifyOrReturnError(isBufferNonEmpty(nonce, nonce_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(isValidTag(tag, tag_length), CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError((ciphertext != nullptr && plaintext != nullptr) || ciphertext_length == 0, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(aad != nullptr || aad_length == 0, CHIP_ERROR_INVALID_ARGUMENT); - if (allocated_buffer) - { - memcpy(buffer, ciphertext, ciphertext_len); - memcpy(buffer + ciphertext_len, tag, tag_length); - } + const psa_algorithm_t algorithm = PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length); + psa_status_t status = PSA_SUCCESS; + psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT; + size_t outLength = 0; + + status = psa_aead_decrypt_setup(&operation, key.As(), algorithm); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - status = psa_driver_wrapper_aead_decrypt( - &attr, key.As(), sizeof(Aes128KeyByteArray), PSA_ALG_AEAD_WITH_SHORTENED_TAG(PSA_ALG_CCM, tag_length), - Uint8::to_const_uchar(nonce), nonce_length, Uint8::to_const_uchar(aad), aad_len, allocated_buffer ? buffer : ciphertext, - ciphertext_len + tag_length, plaintext, ciphertext_len, &output_length); + status = psa_aead_set_lengths(&operation, aad_length, ciphertext_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + status = psa_aead_set_nonce(&operation, nonce, nonce_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); - if (allocated_buffer) + if (aad_length != 0) { - memset(buffer, 0, ciphertext_len + tag_length); + status = psa_aead_update_ad(&operation, aad, aad_length); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + } + else + { + ChipLogDetail(Crypto, "AES_CCM_decrypt: Using aad == null path"); } - VerifyOrExit(status == PSA_SUCCESS, error = CHIP_ERROR_INTERNAL); - VerifyOrExit(output_length == ciphertext_len, error = CHIP_ERROR_INTERNAL); -exit: - if (allocated_buffer) + if (ciphertext_length != 0) { - MemoryFree(buffer); + status = psa_aead_update(&operation, ciphertext, ciphertext_length, plaintext, + PSA_AEAD_UPDATE_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm, ciphertext_length), &outLength); + Progress::Debug("AES_CCM_decrypt, psa_aead_update: !%d, olen:%u", status, (unsigned)outLength); + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + plaintext += outLength; + + status = psa_aead_verify(&operation, plaintext, PSA_AEAD_VERIFY_OUTPUT_SIZE(PSA_KEY_TYPE_AES, algorithm), &outLength, tag, + tag_length); + Progress::Debug("AES_CCM_decrypt, psa_aead_verify1: !%d", status); + } + else + { + status = psa_aead_verify(&operation, nullptr, 0, &outLength, tag, tag_length); + Progress::Debug("AES_CCM_decrypt, psa_aead_verify2: !%d", status); } - psa_reset_key_attributes(&attr); - return error; + VerifyOrReturnError(status == PSA_SUCCESS, CHIP_ERROR_INTERNAL); + + return CHIP_NO_ERROR; } CHIP_ERROR Hash_SHA256(const uint8_t * data, const size_t data_length, uint8_t * out_buffer)