Files
BoilerControlUnit_Firmware/Libs/protocol/openthread/platform-abstraction/efr32/crypto.c
GClarkson 9d06f983af Imported more library files
Not compiling currently
2025-04-12 23:37:19 +01:00

797 lines
27 KiB
C

/*
* Copyright (c) 2023, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the OpenThread platform abstraction for PSA.
*
*/
#include <openthread-core-config.h>
#include <openthread/error.h>
#include <openthread/platform/crypto.h>
#if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA
#include "security_manager.h"
#include "common/debug.hpp"
#include "utils/code_utils.h"
#include "em_device.h"
#include <mbedtls/ecdsa.h>
#include <mbedtls/md.h>
#include <mbedtls/pk.h>
#include "mbedtls/psa_util.h"
#if defined(_SILICON_LABS_32B_SERIES_2)
#include "em_system.h"
#else
#include "sl_hal_system.h"
#endif
#include "sl_psa_crypto.h"
#if defined(_SILICON_LABS_32B_SERIES_2)
#define GET_SECURITY_CAPABILITY SYSTEM_GetSecurityCapability
#define VAULT_ENABLED securityCapabilityVault
#else
#define GET_SECURITY_CAPABILITY sl_hal_system_get_security_capability
#define VAULT_ENABLED SL_SYSTEM_SECURITY_CAPABILITY_VAULT
#endif
#define PERSISTENCE_KEY_ID_USED_MAX (7)
#define MAX_HMAC_KEY_SIZE (32)
// Helper function to convert otCryptoKeyType to psa_key_type_t
static psa_key_type_t getPsaKeyType(otCryptoKeyType aKeyType)
{
psa_key_type_t aPsaKeyType = 0;
switch (aKeyType)
{
case OT_CRYPTO_KEY_TYPE_RAW:
aPsaKeyType = PSA_KEY_TYPE_RAW_DATA;
break;
case OT_CRYPTO_KEY_TYPE_AES:
aPsaKeyType = PSA_KEY_TYPE_AES;
break;
case OT_CRYPTO_KEY_TYPE_HMAC:
aPsaKeyType = PSA_KEY_TYPE_HMAC;
break;
case OT_CRYPTO_KEY_TYPE_ECDSA:
aPsaKeyType = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
break;
}
return aPsaKeyType;
}
// Helper function to convert aKeyAlgorithm to psa_algorithm_t
static psa_algorithm_t getPsaAlgorithm(otCryptoKeyAlgorithm aKeyAlgorithm)
{
psa_algorithm_t aPsaKeyAlgorithm = 0;
switch (aKeyAlgorithm)
{
case OT_CRYPTO_KEY_ALG_VENDOR:
aPsaKeyAlgorithm = PSA_ALG_VENDOR_FLAG;
break;
case OT_CRYPTO_KEY_ALG_AES_ECB:
aPsaKeyAlgorithm = PSA_ALG_ECB_NO_PADDING;
break;
case OT_CRYPTO_KEY_ALG_HMAC_SHA_256:
aPsaKeyAlgorithm = PSA_ALG_HMAC(PSA_ALG_SHA_256);
break;
case OT_CRYPTO_KEY_ALG_ECDSA:
aPsaKeyAlgorithm = PSA_ALG_ECDSA(PSA_ALG_ANY_HASH);
break;
}
return aPsaKeyAlgorithm;
}
// Helper function to convert aKeyUsage to psa_key_usage_t
static psa_key_usage_t getPsaKeyUsage(int aKeyUsage)
{
psa_key_usage_t aPsaKeyUsage = 0;
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_EXPORT)
{
aPsaKeyUsage |= PSA_KEY_USAGE_EXPORT;
}
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_ENCRYPT)
{
aPsaKeyUsage |= PSA_KEY_USAGE_ENCRYPT;
}
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_DECRYPT)
{
aPsaKeyUsage |= PSA_KEY_USAGE_DECRYPT;
}
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_SIGN_HASH)
{
aPsaKeyUsage |= PSA_KEY_USAGE_SIGN_HASH;
}
if (aKeyUsage & OT_CRYPTO_KEY_USAGE_VERIFY_HASH)
{
aPsaKeyUsage |= PSA_KEY_USAGE_VERIFY_HASH;
}
return aPsaKeyUsage;
}
// Helper function to convert otCryptoKeyStorage to psa_key_persistence_t
static psa_key_persistence_t getPsaKeyPersistence(otCryptoKeyStorage aKeyPersistence)
{
psa_key_persistence_t aPsaKeyPersistence = 0;
switch (aKeyPersistence)
{
case OT_CRYPTO_KEY_STORAGE_VOLATILE:
aPsaKeyPersistence = PSA_KEY_PERSISTENCE_VOLATILE;
break;
case OT_CRYPTO_KEY_STORAGE_PERSISTENT:
aPsaKeyPersistence = PSA_KEY_PERSISTENCE_DEFAULT;
break;
}
return aPsaKeyPersistence;
}
#if defined(SEMAILBOX_PRESENT) && !defined(SL_TRUSTZONE_NONSECURE)
static bool shouldWrap(psa_key_attributes_t *key_attr)
{
psa_key_location_t keyLocation = PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(key_attr));
psa_key_type_t keyType = psa_get_key_type(key_attr);
return ((keyLocation != SL_PSA_KEY_LOCATION_WRAPPED) && (keyType != PSA_KEY_TYPE_HMAC));
}
static void checkAndWrapKeys(void)
{
for (int index = 1; index <= PERSISTENCE_KEY_ID_USED_MAX; index++)
{
otCryptoKeyRef key_ref = OPENTHREAD_CONFIG_PSA_ITS_NVM_OFFSET + index;
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
// If there is a key present in the location..
if (sl_sec_man_get_key_attributes(key_ref, &key_attr) == PSA_SUCCESS)
{
if (shouldWrap(&key_attr))
{
// Wrap the key..
otCryptoKeyRef dst_key_ref = key_ref;
psa_key_lifetime_t key_lifetime =
PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(PSA_KEY_PERSISTENCE_DEFAULT,
SL_PSA_KEY_LOCATION_WRAPPED);
psa_set_key_lifetime(&key_attr, key_lifetime);
sl_sec_man_copy_key(key_ref, &key_attr, &dst_key_ref);
}
}
}
}
#endif // SEMAILBOX_PRESENT && !SL_TRUSTZONE_NONSECURE
void otPlatCryptoInit(void)
{
#if defined(SEMAILBOX_PRESENT) && !defined(SL_TRUSTZONE_NONSECURE)
if (GET_SECURITY_CAPABILITY() == VAULT_ENABLED)
{
checkAndWrapKeys();
}
#endif
}
static otError extractPrivateKeyFromDer(uint8_t *aPrivateKey, const uint8_t *aDer, uint8_t aDerLen)
{
otError error = OT_ERROR_NONE;
mbedtls_pk_context pk;
mbedtls_ecp_keypair *keyPair;
mbedtls_pk_init(&pk);
otEXPECT_ACTION(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = OT_ERROR_FAILED);
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
otEXPECT_ACTION(mbedtls_pk_parse_key(&pk, aDer, aDerLen, NULL, 0, mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE)
== 0,
error = OT_ERROR_PARSE);
#else
otEXPECT_ACTION(mbedtls_pk_parse_key(&pk, aDer, aDerLen, NULL, 0) == 0, error = OT_ERROR_PARSE);
#endif
keyPair = mbedtls_pk_ec(pk);
mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(d), aPrivateKey, SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE);
exit:
return error;
}
otError otPlatCryptoImportKey(otCryptoKeyRef *aKeyId,
otCryptoKeyType aKeyType,
otCryptoKeyAlgorithm aKeyAlgorithm,
int aKeyUsage,
otCryptoKeyStorage aKeyPersistence,
const uint8_t *aKey,
size_t aKeyLen)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
uint8_t aPrivateKey[SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE];
const uint8_t *keyToImport = aKey;
size_t keySize = aKeyLen;
if (aKeyType == OT_CRYPTO_KEY_TYPE_ECDSA)
{
error = extractPrivateKeyFromDer(aPrivateKey, aKey, aKeyLen);
keyToImport = aPrivateKey;
keySize = SL_OPENTHREAD_ECDSA_PRIVATE_KEY_SIZE;
}
status = sl_sec_man_import_key(aKeyId,
getPsaKeyType(aKeyType),
getPsaAlgorithm(aKeyAlgorithm),
getPsaKeyUsage(aKeyUsage),
getPsaKeyPersistence(aKeyPersistence),
keyToImport,
keySize);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoExportKey(otCryptoKeyRef aKeyId, uint8_t *aBuffer, size_t aBufferLen, size_t *aKeyLen)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
status = sl_sec_man_export_key(aKeyId, aBuffer, aBufferLen, aKeyLen);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoDestroyKey(otCryptoKeyRef aKeyId)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
status = sl_sec_man_destroy_key(aKeyId);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
bool otPlatCryptoHasKey(otCryptoKeyRef aKeyRef)
{
psa_key_attributes_t aAttr = PSA_KEY_ATTRIBUTES_INIT;
return (sl_sec_man_get_key_attributes(aKeyRef, &aAttr) == PSA_SUCCESS);
}
// AES Implementation
otError otPlatCryptoAesInit(otCryptoContext *aContext)
{
otError error = OT_ERROR_NONE;
(void)aContext;
return error;
}
otError otPlatCryptoAesSetKey(otCryptoContext *aContext, const otCryptoKey *aKey)
{
otError error = OT_ERROR_NONE;
otCryptoKeyRef *mKeyRef = NULL;
otEXPECT_ACTION((aContext != NULL) && (aContext->mContext != NULL), error = OT_ERROR_INVALID_ARGS);
mKeyRef = (otCryptoKeyRef *)aContext->mContext;
*mKeyRef = aKey->mKeyRef;
exit:
return error;
}
otError otPlatCryptoAesEncrypt(otCryptoContext *aContext, const uint8_t *aInput, uint8_t *aOutput)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
otCryptoKeyRef *mKeyRef = NULL;
otEXPECT_ACTION(((aContext != NULL) && (aContext->mContext != NULL) && (aOutput != NULL) && (aInput != NULL)),
error = OT_ERROR_INVALID_ARGS);
mKeyRef = (otCryptoKeyRef *)aContext->mContext;
status = sl_sec_man_aes_encrypt(*mKeyRef, PSA_ALG_ECB_NO_PADDING, aInput, aOutput);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoAesFree(otCryptoContext *aContext)
{
otError error = OT_ERROR_NONE;
(void)aContext;
return error;
}
// HMAC implementations
otError otPlatCryptoHmacSha256Init(otCryptoContext *aContext)
{
otError error = OT_ERROR_NONE;
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
*mMacOperation = psa_mac_operation_init();
return error;
}
otError otPlatCryptoHmacSha256Deinit(otCryptoContext *aContext)
{
otError error = OT_ERROR_NONE;
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
psa_status_t status;
status = sl_sec_man_hmac_deinit(mMacOperation);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
static psa_status_t reImportUnwrapped(const otCryptoKey *aKey, otCryptoKeyRef *aHmacKeyRef)
{
psa_status_t status = PSA_SUCCESS;
#if defined(SEMAILBOX_PRESENT)
uint8_t hmacKeyBytes[MAX_HMAC_KEY_SIZE];
size_t key_size;
psa_key_attributes_t key_attr = PSA_KEY_ATTRIBUTES_INIT;
status = sl_sec_man_get_key_attributes(aKey->mKeyRef, &key_attr);
otEXPECT(status == PSA_SUCCESS);
status = sl_sec_man_export_key(aKey->mKeyRef, hmacKeyBytes, sizeof(hmacKeyBytes), &key_size);
otEXPECT(status == PSA_SUCCESS);
status = sl_sec_man_import_key(aHmacKeyRef,
psa_get_key_type(&key_attr),
psa_get_key_algorithm(&key_attr),
psa_get_key_usage_flags(&key_attr),
PSA_KEY_PERSISTENCE_VOLATILE,
hmacKeyBytes,
key_size);
memset(hmacKeyBytes, 0, sizeof(hmacKeyBytes));
otEXPECT(status == PSA_SUCCESS);
exit:
#else
*aHmacKeyRef = aKey->mKeyRef;
#endif
return status;
}
otError otPlatCryptoHmacSha256Start(otCryptoContext *aContext, const otCryptoKey *aKey)
{
otError error = OT_ERROR_NONE;
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
psa_status_t status;
otCryptoKeyRef hmacKeyRef;
status = reImportUnwrapped(aKey, &hmacKeyRef);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
status = sl_sec_man_hmac_start(mMacOperation, hmacKeyRef);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
#if defined(SEMAILBOX_PRESENT)
sl_sec_man_destroy_key(hmacKeyRef);
#else
hmacKeyRef = 0;
#endif
exit:
return error;
}
otError otPlatCryptoHmacSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength)
{
otError error = OT_ERROR_NONE;
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
psa_status_t status;
status = sl_sec_man_hmac_update(mMacOperation, (const uint8_t *)aBuf, (size_t)aBufLength);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoHmacSha256Finish(otCryptoContext *aContext, uint8_t *aBuf, size_t aBufLength)
{
otError error = OT_ERROR_NONE;
psa_mac_operation_t *mMacOperation = (psa_mac_operation_t *)aContext->mContext;
psa_status_t status;
status = sl_sec_man_hmac_finish(mMacOperation, aBuf, aBufLength);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
// HKDF platform implementations
// As the HKDF does not actually use mbedTLS APIs but uses HMAC module, this feature is not implemented.
otError otPlatCryptoHkdfExpand(otCryptoContext *aContext,
const uint8_t *aInfo,
uint16_t aInfoLength,
uint8_t *aOutputKey,
uint16_t aOutputKeyLength)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
otEXPECT_ACTION(((aContext != NULL) && (aContext->mContext != NULL) && (aInfo != NULL) && (aOutputKey != NULL)),
error = OT_ERROR_INVALID_ARGS);
status = sl_sec_man_key_derivation_expand(aContext->mContext, aInfo, aInfoLength, aOutputKey, aOutputKeyLength);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoHkdfExtract(otCryptoContext *aContext,
const uint8_t *aSalt,
uint16_t aSaltLength,
const otCryptoKey *aKey)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
otEXPECT_ACTION(
((aContext != NULL) && (aContext->mContext != NULL) && (aKey != NULL) && (aSalt != NULL) && (aSaltLength != 0)),
error = OT_ERROR_INVALID_ARGS);
status = sl_sec_man_key_derivation_extract(aContext->mContext, PSA_ALG_SHA_256, aKey->mKeyRef, aSalt, aSaltLength);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
// SHA256 platform implementations
otError otPlatCryptoSha256Init(otCryptoContext *aContext)
{
otError error = OT_ERROR_NONE;
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
otEXPECT_ACTION((ctx != NULL), error = OT_ERROR_INVALID_ARGS);
*ctx = sl_sec_man_hash_init();
exit:
return error;
}
otError otPlatCryptoSha256Deinit(otCryptoContext *aContext)
{
otError error = OT_ERROR_NONE;
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
otEXPECT_ACTION((ctx != NULL), error = OT_ERROR_INVALID_ARGS);
otEXPECT_ACTION((sl_sec_man_hash_deinit(ctx) == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoSha256Start(otCryptoContext *aContext)
{
otError error = OT_ERROR_NONE;
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
otEXPECT_ACTION((ctx != NULL), error = OT_ERROR_INVALID_ARGS);
otEXPECT_ACTION((sl_sec_man_hash_start(ctx, PSA_ALG_SHA_256) == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoSha256Update(otCryptoContext *aContext, const void *aBuf, uint16_t aBufLength)
{
otError error = OT_ERROR_NONE;
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
otEXPECT_ACTION(((ctx != NULL) && (aBuf != NULL)), error = OT_ERROR_INVALID_ARGS);
otEXPECT_ACTION((sl_sec_man_hash_update(ctx, (uint8_t *)aBuf, aBufLength) == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoSha256Finish(otCryptoContext *aContext, uint8_t *aHash, uint16_t aHashSize)
{
otError error = OT_ERROR_NONE;
size_t aHashLength = 0;
otEXPECT_ACTION((aContext != NULL), error = OT_ERROR_INVALID_ARGS);
psa_hash_operation_t *ctx = (psa_hash_operation_t *)aContext->mContext;
otEXPECT_ACTION(((ctx != NULL) && (aHash != NULL)), error = OT_ERROR_INVALID_ARGS);
otEXPECT_ACTION((sl_sec_man_hash_finish(ctx, aHash, aHashSize, &aHashLength) == PSA_SUCCESS),
error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoEcdsaGenerateAndImportKey(otCryptoKeyRef aKeyRef)
{
otError error = OT_ERROR_NONE;
size_t aKeyLength = 256;
psa_status_t status;
status = sl_sec_man_generate_key(&aKeyRef,
PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1),
PSA_ALG_ECDSA(PSA_ALG_ANY_HASH),
(PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH),
PSA_KEY_LIFETIME_PERSISTENT,
aKeyLength);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoEcdsaExportPublicKey(otCryptoKeyRef aKeyRef, otPlatCryptoEcdsaPublicKey *aPublicKey)
{
otError error = OT_ERROR_NONE;
size_t aKeyLength;
psa_status_t status;
uint8_t aByteArray[OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE + 1];
otEXPECT_ACTION((aPublicKey != NULL), error = OT_ERROR_INVALID_ARGS);
// Use byte array to get the public key because PSA adds a encoding header at the beginning of the array.
// It is easier to export it to a byte array and copy only the public key to output array.
status = sl_sec_man_export_public_key(aKeyRef, aByteArray, sizeof(aByteArray), &aKeyLength);
memcpy(aPublicKey->m8, &aByteArray[1], OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoEcdsaSignUsingKeyRef(otCryptoKeyRef aKeyRef,
const otPlatCryptoSha256Hash *aHash,
otPlatCryptoEcdsaSignature *aSignature)
{
otError error = OT_ERROR_NONE;
size_t aSignatureLength;
psa_status_t status;
bool aIsHash = true;
otEXPECT_ACTION(((aHash != NULL) && (aSignature != NULL)), error = OT_ERROR_INVALID_ARGS);
status = sl_sec_man_sign(aKeyRef,
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
aHash->m8,
sizeof(aHash->m8),
aSignature->m8,
sizeof(aSignature->m8),
&aSignatureLength,
aIsHash);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoEcdsaVerifyUsingKeyRef(otCryptoKeyRef aKeyRef,
const otPlatCryptoSha256Hash *aHash,
const otPlatCryptoEcdsaSignature *aSignature)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
bool aIsHash = true;
otEXPECT_ACTION(((aHash != NULL) && (aSignature != NULL)), error = OT_ERROR_INVALID_ARGS);
// Verify the signature.
status = sl_sec_man_verify(aKeyRef,
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
aHash->m8,
sizeof(aHash->m8),
aSignature->m8,
sizeof(aSignature->m8),
aIsHash);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
otError otPlatCryptoPbkdf2GenerateKey(const uint8_t *aPassword,
uint16_t aPasswordLen,
const uint8_t *aSalt,
uint16_t aSaltLen,
uint32_t aIterationCounter,
uint16_t aKeyLen,
uint8_t *aKey)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
size_t outSize;
psa_key_id_t passwordKeyId = 0;
psa_key_id_t saltKeyId = 0;
psa_key_id_t keyId = 0;
// Algorithm is PBKDF2-AES-CMAC-PRF-128
psa_algorithm_t algo = PSA_ALG_PBKDF2_AES_CMAC_PRF_128;
// Initialize key derivation
psa_key_derivation_operation_t operation = psa_key_derivation_operation_init();
status = psa_key_derivation_setup(&operation, algo);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Set capacity
status = psa_key_derivation_set_capacity(&operation, aKeyLen);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Set iteration count as cost
status = psa_key_derivation_input_integer(&operation, PSA_KEY_DERIVATION_INPUT_COST, aIterationCounter);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Create salt as a key
psa_key_attributes_t saltKeyAttr = psa_key_attributes_init();
psa_set_key_usage_flags(&saltKeyAttr, PSA_KEY_USAGE_DERIVE);
psa_set_key_type(&saltKeyAttr, PSA_KEY_TYPE_RAW_DATA);
psa_set_key_algorithm(&saltKeyAttr, algo);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
status = psa_import_key(&saltKeyAttr, aSalt, aSaltLen, &saltKeyId);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Provide salt
status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_SALT, saltKeyId);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Create key for password (key)
psa_key_attributes_t passwordKeyAttr = psa_key_attributes_init();
psa_set_key_usage_flags(&passwordKeyAttr, PSA_KEY_USAGE_DERIVE);
psa_set_key_type(&passwordKeyAttr, PSA_KEY_TYPE_PASSWORD);
psa_set_key_algorithm(&passwordKeyAttr, algo);
status = psa_import_key(&passwordKeyAttr, aPassword, aPasswordLen, &passwordKeyId);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Provide password (key)
status = psa_key_derivation_input_key(&operation, PSA_KEY_DERIVATION_INPUT_PASSWORD, passwordKeyId);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Configure output as a key
psa_key_attributes_t keyAttrResult = psa_key_attributes_init();
psa_set_key_bits(&keyAttrResult, (8 * aKeyLen));
psa_set_key_usage_flags(&keyAttrResult, PSA_KEY_USAGE_EXPORT);
psa_set_key_type(&keyAttrResult, PSA_KEY_TYPE_RAW_DATA);
psa_set_key_algorithm(&keyAttrResult, PSA_ALG_CTR);
status = psa_key_derivation_output_key(&keyAttrResult, &operation, &keyId);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Export output key
status = psa_export_key(keyId, aKey, aKeyLen, &outSize);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
// Release keys used
psa_destroy_key(keyId);
psa_destroy_key(saltKeyId);
psa_destroy_key(passwordKeyId);
exit:
return error;
}
otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey,
const otPlatCryptoSha256Hash *aHash,
const otPlatCryptoEcdsaSignature *aSignature)
{
otError error = OT_ERROR_NONE;
psa_status_t status;
bool aIsHash = true;
uint8_t aByteArray[OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE + 1];
otCryptoKeyRef aKeyId;
otEXPECT_ACTION(((aPublicKey != NULL) && (aHash != NULL) && (aSignature != NULL)), error = OT_ERROR_INVALID_ARGS);
// Public key needs a extra byt of encoding header, which has a value of 0x04, to be included for PSA to validate
// and process the publc key. Copy the key into a new temp array and append the encoding header to it.
aByteArray[0] = 0x04;
memcpy(&aByteArray[1], aPublicKey, OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE);
// Import the public key into a temp slot.
status = sl_sec_man_import_key(&aKeyId,
PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1),
PSA_ALG_ECDSA(PSA_ALG_ANY_HASH),
PSA_KEY_USAGE_VERIFY_HASH,
PSA_KEY_PERSISTENCE_VOLATILE,
aByteArray,
OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE + 1); // To account for the padded byte.
// If key import fails, assert, as we cannot proceed
OT_ASSERT(status == PSA_SUCCESS);
// Verify the signature.
status = sl_sec_man_verify(aKeyId,
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
aHash->m8,
sizeof(aHash->m8),
aSignature->m8,
sizeof(aSignature->m8),
aIsHash);
// Destroy the temp key.
sl_sec_man_destroy_key(aKeyId);
otEXPECT_ACTION((status == PSA_SUCCESS), error = OT_ERROR_FAILED);
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_PSA