From 9cfd6e13a239a61288f34b1219e1b41dc70f8457 Mon Sep 17 00:00:00 2001 From: Damian Krolik Date: Wed, 27 Nov 2024 15:07:49 +0100 Subject: [PATCH] [nrf noup] Implement Spake2pVerifier for PSA crypto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Spake2+ implementation for PSA crypto API is enabled: - do notĀ build the generic Spake2p nor its subclasses - do not build Spake2pVerifier::Generate method that generates the verifier key out of the passcode, salt and iteration count. Instead, provide the implementation Spake2pVerifier::Generate that uses PSA crypto API. Note that using Spake2pVerifier::Generate requires setting CONFIG_PSA_WANT_ALG_PBKDF2_HMAC and CONFIG_PSA_WANT_KEY_TYPE_SPAKE2P_KEY_PAIR_DERIVE Kconfig options. Signed-off-by: Damian Krolik (cherry picked from commit aa2e0569bb5db9c94cc36764b3a50f08299add58) Signed-off-by: Adrian Gielniewski --- src/crypto/CHIPCryptoPAL.cpp | 48 +++++++++++++++------------- src/crypto/PSASpake2p.cpp | 62 ++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/crypto/CHIPCryptoPAL.cpp b/src/crypto/CHIPCryptoPAL.cpp index fa84d786b8..6ff388b10d 100644 --- a/src/crypto/CHIPCryptoPAL.cpp +++ b/src/crypto/CHIPCryptoPAL.cpp @@ -238,6 +238,8 @@ CHIP_ERROR Find16BitUpperCaseHexAfterPrefix(const ByteSpan & buffer, const char using HKDF_sha_crypto = HKDF_sha; +#if !CHIP_CRYPTO_PSA_SPAKE2P + CHIP_ERROR Spake2p::InternalHash(const uint8_t * in, size_t in_len) { const uint64_t u64_len = in_len; @@ -546,28 +548,6 @@ CHIP_ERROR Spake2p_P256_SHA256_HKDF_HMAC::ComputeW0(uint8_t * w0out, size_t * w0 return CHIP_NO_ERROR; } -CHIP_ERROR Spake2pVerifier::Serialize(MutableByteSpan & outSerialized) const -{ - VerifyOrReturnError(outSerialized.size() >= kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT); - - memcpy(&outSerialized.data()[0], mW0, sizeof(mW0)); - memcpy(&outSerialized.data()[sizeof(mW0)], mL, sizeof(mL)); - - outSerialized.reduce_size(kSpake2p_VerifierSerialized_Length); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR Spake2pVerifier::Deserialize(const ByteSpan & inSerialized) -{ - VerifyOrReturnError(inSerialized.size() >= kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT); - - memcpy(mW0, &inSerialized.data()[0], sizeof(mW0)); - memcpy(mL, &inSerialized.data()[sizeof(mW0)], sizeof(mL)); - - return CHIP_NO_ERROR; -} - CHIP_ERROR Spake2pVerifier::Generate(uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t setupPin) { uint8_t serializedWS[kSpake2p_WS_Length * 2] = { 0 }; @@ -596,6 +576,30 @@ CHIP_ERROR Spake2pVerifier::Generate(uint32_t pbkdf2IterCount, const ByteSpan & return err; } +#endif // !CHIP_CRYPTO_PSA_SPAKE2P + +CHIP_ERROR Spake2pVerifier::Serialize(MutableByteSpan & outSerialized) const +{ + VerifyOrReturnError(outSerialized.size() >= kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT); + + memcpy(&outSerialized.data()[0], mW0, sizeof(mW0)); + memcpy(&outSerialized.data()[sizeof(mW0)], mL, sizeof(mL)); + + outSerialized.reduce_size(kSpake2p_VerifierSerialized_Length); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR Spake2pVerifier::Deserialize(const ByteSpan & inSerialized) +{ + VerifyOrReturnError(inSerialized.size() >= kSpake2p_VerifierSerialized_Length, CHIP_ERROR_INVALID_ARGUMENT); + + memcpy(mW0, &inSerialized.data()[0], sizeof(mW0)); + memcpy(mL, &inSerialized.data()[sizeof(mW0)], sizeof(mL)); + + return CHIP_NO_ERROR; +} + CHIP_ERROR Spake2pVerifier::ComputeWS(uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t setupPin, uint8_t * ws, uint32_t ws_len) { diff --git a/src/crypto/PSASpake2p.cpp b/src/crypto/PSASpake2p.cpp index ae98b083c8..50172fe1c7 100644 --- a/src/crypto/PSASpake2p.cpp +++ b/src/crypto/PSASpake2p.cpp @@ -197,5 +197,67 @@ CHIP_ERROR PSASpake2p_P256_SHA256_HKDF_HMAC::GetKeys(SessionKeystore & keystore, return CHIP_NO_ERROR; } +CHIP_ERROR Spake2pVerifier::Generate(uint32_t pbkdf2IterCount, const ByteSpan & salt, uint32_t setupPin) +{ + psa_status_t status = PSA_SUCCESS; + psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT; + psa_key_id_t passwordKey = PSA_KEY_ID_NULL; + psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT; + psa_key_id_t spakeKey = PSA_KEY_ID_NULL; + uint8_t verifier[kP256_FE_Length + kP256_Point_Length]; + size_t verifierLen; + + // Prepare password key + uint8_t password[sizeof(uint32_t)]; + Encoding::LittleEndian::Put32(password, setupPin); + + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE); + psa_set_key_algorithm(&attributes, PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)); + psa_set_key_type(&attributes, PSA_KEY_TYPE_PASSWORD); + + status = psa_import_key(&attributes, password, sizeof(password), &passwordKey); + psa_reset_key_attributes(&attributes); + VerifyOrExit(status == PSA_SUCCESS, ); + + // Run PBKDF + status = psa_key_derivation_setup(&operation, PSA_ALG_PBKDF2_HMAC(PSA_ALG_SHA_256)); + VerifyOrExit(status == PSA_SUCCESS, ); + + status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, pbkdf2IterCount); + VerifyOrExit(status == PSA_SUCCESS, ); + + status = psa_key_derivation_input_bytes(&operation, PSA_KEY_DERIVATION_INPUT_SALT, salt.data(), salt.size()); + VerifyOrExit(status == PSA_SUCCESS, ); + + status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, passwordKey); + VerifyOrExit(status == PSA_SUCCESS, ); + + attributes = psa_key_attributes_init(); + psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT); + psa_set_key_algorithm(&attributes, PSA_ALG_SPAKE2P_MATTER); + psa_set_key_type(&attributes, PSA_KEY_TYPE_SPAKE2P_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1)); + psa_set_key_bits(&attributes, kP256_FE_Length * 8); + + status = psa_key_derivation_output_key(&attributes, &operation, &spakeKey); + psa_reset_key_attributes(&attributes); + VerifyOrExit(status == PSA_SUCCESS, ); + + // Export verifier as raw bytes + status = psa_export_public_key(spakeKey, verifier, sizeof(verifier), &verifierLen); + +exit: + psa_key_derivation_abort(&operation); + psa_destroy_key(passwordKey); + psa_destroy_key(spakeKey); + + if (status != PSA_SUCCESS) + { + ChipLogError(Crypto, "PSA error: %d", static_cast(status)); + return CHIP_ERROR_INTERNAL; + } + + return Deserialize(ByteSpan(verifier, verifierLen)); +} + } // namespace Crypto } // namespace chip