[crypto] add ECDSA API (#8273)

- remove ecdsa tinycrypt implementation
- add crypto API, move default implementation in crypto_platform.c
- define crypto ecdsa structures and format
This commit is contained in:
andrei-menzopol
2022-11-03 09:40:51 -07:00
committed by GitHub
parent f5367f6238
commit a532ce6e57
11 changed files with 361 additions and 439 deletions
-1
View File
@@ -255,7 +255,6 @@ LOCAL_SRC_FILES := \
src/core/crypto/aes_ecb.cpp \
src/core/crypto/crypto_platform.cpp \
src/core/crypto/ecdsa.cpp \
src/core/crypto/ecdsa_tinycrypt.cpp \
src/core/crypto/hkdf_sha256.cpp \
src/core/crypto/hmac_sha256.cpp \
src/core/crypto/mbedtls.cpp \
+1 -13
View File
@@ -55,25 +55,13 @@ extern "C" {
*
*/
#define OT_CRYPTO_SHA256_HASH_SIZE 32 ///< Length of SHA256 hash (in bytes).
/**
* @struct otCryptoSha256Hash
*
* This structure represents a SHA-256 hash.
*
*/
OT_TOOL_PACKED_BEGIN
struct otCryptoSha256Hash
{
uint8_t m8[OT_CRYPTO_SHA256_HASH_SIZE]; ///< Hash bytes.
} OT_TOOL_PACKED_END;
/**
* This structure represents a SHA-256 hash.
*
*/
typedef struct otCryptoSha256Hash otCryptoSha256Hash;
typedef otPlatCryptoSha256Hash otCryptoSha256Hash;
/**
* This function performs HMAC computation.
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (258)
#define OPENTHREAD_API_VERSION (259)
/**
* @addtogroup api-instance
+159 -4
View File
@@ -130,6 +130,95 @@ typedef struct otCryptoContext
uint16_t mContextSize; ///< The length of the context in bytes.
} otCryptoContext;
/**
* Length of SHA256 hash (in bytes).
*
*/
#define OT_CRYPTO_SHA256_HASH_SIZE 32
/**
* @struct otPlatCryptoSha256Hash
*
* This structure represents a SHA-256 hash.
*
*/
OT_TOOL_PACKED_BEGIN
struct otPlatCryptoSha256Hash
{
uint8_t m8[OT_CRYPTO_SHA256_HASH_SIZE]; ///< Hash bytes.
} OT_TOOL_PACKED_END;
/**
* This structure represents a SHA-256 hash.
*
*/
typedef struct otPlatCryptoSha256Hash otPlatCryptoSha256Hash;
/**
* Max buffer size (in bytes) for representing the EDCSA key-pair in DER format.
*
*/
#define OT_CRYPTO_ECDSA_MAX_DER_SIZE 125
/**
* @struct otPlatCryptoEcdsaKeyPair
*
* This structure represents an ECDSA key pair (public and private keys).
*
* The key pair is stored using Distinguished Encoding Rules (DER) format (per RFC 5915).
*
*/
typedef struct otPlatCryptoEcdsaKeyPair
{
uint8_t mDerBytes[OT_CRYPTO_ECDSA_MAX_DER_SIZE];
uint8_t mDerLength;
} otPlatCryptoEcdsaKeyPair;
/**
* Buffer size (in bytes) for representing the EDCSA public key.
*
*/
#define OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE 64
/**
* @struct otPlatCryptoEcdsaPublicKey
*
* This struct represents a ECDSA public key.
*
* The public key is stored as a byte sequence representation of an uncompressed curve point (RFC 6605 - sec 4).
*
*/
OT_TOOL_PACKED_BEGIN
struct otPlatCryptoEcdsaPublicKey
{
uint8_t m8[OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE];
} OT_TOOL_PACKED_END;
typedef struct otPlatCryptoEcdsaPublicKey otPlatCryptoEcdsaPublicKey;
/**
* Buffer size (in bytes) for representing the EDCSA signature.
*
*/
#define OT_CRYPTO_ECDSA_SIGNATURE_SIZE 64
/**
* @struct otPlatCryptoEcdsaSignature
*
* This struct represents an ECDSA signature.
*
* The signature is encoded as the concatenated binary representation of two MPIs `r` and `s` which are calculated
* during signing (RFC 6605 - section 4).
*
*/
OT_TOOL_PACKED_BEGIN
struct otPlatCryptoEcdsaSignature
{
uint8_t m8[OT_CRYPTO_ECDSA_SIGNATURE_SIZE];
} OT_TOOL_PACKED_END;
typedef struct otPlatCryptoEcdsaSignature otPlatCryptoEcdsaSignature;
/**
* Initialize the Crypto module.
*
@@ -480,15 +569,81 @@ void otPlatCryptoRandomDeinit(void);
/**
* Fills a given buffer with cryptographically secure random bytes.
*
* @param[out] aBuffer A pointer to a buffer to fill with the random bytes.
* @param[in] aSize Size of buffer (number of bytes to fill).
* @param[out] aBuffer A pointer to a buffer to fill with the random bytes.
* @param[in] aSize Size of buffer (number of bytes to fill).
*
* @retval OT_ERROR_NONE Successfully filled buffer with random values.
* @retval OT_ERROR_FAILED Operation failed.
* @retval OT_ERROR_NONE Successfully filled buffer with random values.
* @retval OT_ERROR_FAILED Operation failed.
*
*/
otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize);
/**
* Generate and populate the output buffer with a new ECDSA key-pair.
*
* @param[out] aKeyPair A pointer to an ECDSA key-pair structure to store the generated key-pair.
*
* @retval OT_ERROR_NONE A new key-pair was generated successfully.
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer for key generation.
* @retval OT_ERROR_NOT_CAPABLE Feature not supported.
* @retval OT_ERROR_FAILED Failed to generate key-pair.
*
*/
otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair);
/**
* Get the associated public key from the input context.
*
* @param[in] aKeyPair A pointer to an ECDSA key-pair structure where the key-pair is stored.
* @param[out] aPublicKey A pointer to an ECDSA public key structure to store the public key.
*
* @retval OT_ERROR_NONE Public key was retrieved successfully, and @p aBuffer is updated.
* @retval OT_ERROR_PARSE The key-pair DER format could not be parsed (invalid format).
* @retval OT_ERROR_INVALID_ARGS The @p aContext is NULL.
*
*/
otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair, otPlatCryptoEcdsaPublicKey *aPublicKey);
/**
* Calculate the ECDSA signature for a hashed message using the private key from the input context.
*
* This method uses the deterministic digital signature generation procedure from RFC 6979.
*
* @param[in] aKeyPair A pointer to an ECDSA key-pair structure where the key-pair is stored.
* @param[in] aHash A pointer to a SHA-256 hash structure where the hash value for signature calculation
* is stored.
* @param[out] aSignature A pointer to an ECDSA signature structure to output the calculated signature.
*
* @retval OT_ERROR_NONE The signature was calculated successfully, @p aSignature was updated.
* @retval OT_ERROR_PARSE The key-pair DER format could not be parsed (invalid format).
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer for signature calculation.
* @retval OT_ERROR_INVALID_ARGS The @p aContext is NULL.
*
*/
otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair,
const otPlatCryptoSha256Hash * aHash,
otPlatCryptoEcdsaSignature * aSignature);
/**
* Use the key from the input context to verify the ECDSA signature of a hashed message.
*
* @param[in] aPublicKey A pointer to an ECDSA public key structure where the public key for signature
* verification is stored.
* @param[in] aHash A pointer to a SHA-256 hash structure where the hash value for signature verification
* is stored.
* @param[in] aSignature A pointer to an ECDSA signature structure where the signature value to be verified is
* stored.
*
* @retval OT_ERROR_NONE The signature was verified successfully.
* @retval OT_ERROR_SECURITY The signature is invalid.
* @retval OT_ERROR_INVALID_ARGS The key or hash is invalid.
* @retval OT_ERROR_NO_BUFS Failed to allocate buffer for signature verification.
*
*/
otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey,
const otPlatCryptoSha256Hash * aHash,
const otPlatCryptoEcdsaSignature *aSignature);
/**
* @}
*
-1
View File
@@ -463,7 +463,6 @@ openthread_core_files = [
"crypto/crypto_platform.cpp",
"crypto/ecdsa.cpp",
"crypto/ecdsa.hpp",
"crypto/ecdsa_tinycrypt.cpp",
"crypto/hkdf_sha256.cpp",
"crypto/hkdf_sha256.hpp",
"crypto/hmac_sha256.cpp",
-1
View File
@@ -121,7 +121,6 @@ set(COMMON_SOURCES
crypto/aes_ecb.cpp
crypto/crypto_platform.cpp
crypto/ecdsa.cpp
crypto/ecdsa_tinycrypt.cpp
crypto/hkdf_sha256.cpp
crypto/hmac_sha256.cpp
crypto/mbedtls.cpp
-1
View File
@@ -211,7 +211,6 @@ SOURCES_COMMON = \
crypto/aes_ecb.cpp \
crypto/crypto_platform.cpp \
crypto/ecdsa.cpp \
crypto/ecdsa_tinycrypt.cpp \
crypto/hkdf_sha256.cpp \
crypto/hmac_sha256.cpp \
crypto/mbedtls.cpp \
+173
View File
@@ -34,9 +34,12 @@
#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/ecdsa.h>
#include <mbedtls/entropy.h>
#include <mbedtls/md.h>
#include <mbedtls/pk.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <openthread/instance.h>
#include <openthread/platform/crypto.h>
@@ -48,6 +51,7 @@
#include "common/instance.hpp"
#include "common/new.hpp"
#include "config/crypto.h"
#include "crypto/ecdsa.hpp"
#include "crypto/hmac_sha256.hpp"
#include "crypto/storage.hpp"
@@ -484,6 +488,175 @@ OT_TOOL_WEAK otError otPlatCryptoRandomGet(uint8_t *aBuffer, uint16_t aSize)
mbedtls_ctr_drbg_random(&sCtrDrbgContext, static_cast<unsigned char *>(aBuffer), static_cast<size_t>(aSize)));
}
#if OPENTHREAD_CONFIG_ECDSA_ENABLE
OT_TOOL_WEAK otError otPlatCryptoEcdsaGenerateKey(otPlatCryptoEcdsaKeyPair *aKeyPair)
{
mbedtls_pk_context pk;
int ret;
mbedtls_pk_init(&pk);
ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
VerifyOrExit(ret == 0);
ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(pk), MbedTls::CryptoSecurePrng, nullptr);
VerifyOrExit(ret == 0);
ret = mbedtls_pk_write_key_der(&pk, aKeyPair->mDerBytes, OT_CRYPTO_ECDSA_MAX_DER_SIZE);
VerifyOrExit(ret > 0);
aKeyPair->mDerLength = static_cast<uint8_t>(ret);
memmove(aKeyPair->mDerBytes, aKeyPair->mDerBytes + OT_CRYPTO_ECDSA_MAX_DER_SIZE - aKeyPair->mDerLength,
aKeyPair->mDerLength);
exit:
mbedtls_pk_free(&pk);
return (ret >= 0) ? kErrorNone : MbedTls::MapError(ret);
}
OT_TOOL_WEAK otError otPlatCryptoEcdsaGetPublicKey(const otPlatCryptoEcdsaKeyPair *aKeyPair,
otPlatCryptoEcdsaPublicKey * aPublicKey)
{
Error error = kErrorNone;
mbedtls_pk_context pk;
mbedtls_ecp_keypair *keyPair;
int ret;
mbedtls_pk_init(&pk);
VerifyOrExit(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed);
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
VerifyOrExit(mbedtls_pk_parse_key(&pk, aKeyPair->mDerBytes, aKeyPair->mDerLength, nullptr, 0,
MbedTls::CryptoSecurePrng, nullptr) == 0,
error = kErrorParse);
#else
VerifyOrExit(mbedtls_pk_parse_key(&pk, aKeyPair->mDerBytes, aKeyPair->mDerLength, nullptr, 0) == 0,
error = kErrorParse);
#endif
keyPair = mbedtls_pk_ec(pk);
ret = mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), aPublicKey->m8,
Ecdsa::P256::kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y),
aPublicKey->m8 + Ecdsa::P256::kMpiSize, Ecdsa::P256::kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
exit:
mbedtls_pk_free(&pk);
return error;
}
OT_TOOL_WEAK otError otPlatCryptoEcdsaSign(const otPlatCryptoEcdsaKeyPair *aKeyPair,
const otPlatCryptoSha256Hash * aHash,
otPlatCryptoEcdsaSignature * aSignature)
{
Error error = kErrorNone;
mbedtls_pk_context pk;
mbedtls_ecp_keypair * keypair;
mbedtls_ecdsa_context ecdsa;
mbedtls_mpi r;
mbedtls_mpi s;
int ret;
mbedtls_pk_init(&pk);
mbedtls_ecdsa_init(&ecdsa);
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
VerifyOrExit(mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed);
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
VerifyOrExit(mbedtls_pk_parse_key(&pk, aKeyPair->mDerBytes, aKeyPair->mDerLength, nullptr, 0,
MbedTls::CryptoSecurePrng, nullptr) == 0,
error = kErrorParse);
#else
VerifyOrExit(mbedtls_pk_parse_key(&pk, aKeyPair->mDerBytes, aKeyPair->mDerLength, nullptr, 0) == 0,
error = kErrorParse);
#endif
keypair = mbedtls_pk_ec(pk);
ret = mbedtls_ecdsa_from_keypair(&ecdsa, keypair);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
#if (MBEDTLS_VERSION_NUMBER >= 0x02130000)
ret = mbedtls_ecdsa_sign_det_ext(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash->m8,
Sha256::Hash::kSize, MBEDTLS_MD_SHA256, MbedTls::CryptoSecurePrng, nullptr);
#else
ret = mbedtls_ecdsa_sign_det(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash->m8,
Sha256::Hash::kSize, MBEDTLS_MD_SHA256);
#endif
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
OT_ASSERT(mbedtls_mpi_size(&r) <= Ecdsa::P256::kMpiSize);
ret = mbedtls_mpi_write_binary(&r, aSignature->m8, Ecdsa::P256::kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_write_binary(&s, aSignature->m8 + Ecdsa::P256::kMpiSize, Ecdsa::P256::kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
exit:
mbedtls_pk_free(&pk);
mbedtls_mpi_free(&s);
mbedtls_mpi_free(&r);
mbedtls_ecdsa_free(&ecdsa);
return error;
}
OT_TOOL_WEAK otError otPlatCryptoEcdsaVerify(const otPlatCryptoEcdsaPublicKey *aPublicKey,
const otPlatCryptoSha256Hash * aHash,
const otPlatCryptoEcdsaSignature *aSignature)
{
Error error = kErrorNone;
mbedtls_ecdsa_context ecdsa;
mbedtls_mpi r;
mbedtls_mpi s;
int ret;
mbedtls_ecdsa_init(&ecdsa);
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
ret = mbedtls_ecp_group_load(&ecdsa.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_read_binary(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), aPublicKey->m8, Ecdsa::P256::kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_read_binary(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), aPublicKey->m8 + Ecdsa::P256::kMpiSize,
Ecdsa::P256::kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_lset(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_read_binary(&r, aSignature->m8, Ecdsa::P256::kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_read_binary(&s, aSignature->m8 + Ecdsa::P256::kMpiSize, Ecdsa::P256::kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_ecdsa_verify(&ecdsa.MBEDTLS_PRIVATE(grp), aHash->m8, Sha256::Hash::kSize, &ecdsa.MBEDTLS_PRIVATE(Q),
&r, &s);
VerifyOrExit(ret == 0, error = kErrorSecurity);
exit:
mbedtls_mpi_free(&s);
mbedtls_mpi_free(&r);
mbedtls_ecdsa_free(&ecdsa);
return error;
}
#endif // #if OPENTHREAD_CONFIG_ECDSA_ENABLE
#endif // #if !OPENTHREAD_RADIO
#endif // #if OPENTHREAD_CONFIG_CRYPTO_LIB == OPENTHREAD_CONFIG_CRYPTO_LIB_MBEDTLS
-163
View File
@@ -35,8 +35,6 @@
#if OPENTHREAD_CONFIG_ECDSA_ENABLE
#ifndef MBEDTLS_USE_TINYCRYPT
#include <string.h>
#include <mbedtls/ctr_drbg.h>
@@ -53,166 +51,6 @@ namespace ot {
namespace Crypto {
namespace Ecdsa {
Error P256::KeyPair::Generate(void)
{
mbedtls_pk_context pk;
int ret;
mbedtls_pk_init(&pk);
ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
VerifyOrExit(ret == 0);
ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(pk), MbedTls::CryptoSecurePrng, nullptr);
VerifyOrExit(ret == 0);
ret = mbedtls_pk_write_key_der(&pk, mDerBytes, sizeof(mDerBytes));
VerifyOrExit(ret > 0);
mDerLength = static_cast<uint8_t>(ret);
memmove(mDerBytes, mDerBytes + sizeof(mDerBytes) - mDerLength, mDerLength);
exit:
mbedtls_pk_free(&pk);
return (ret >= 0) ? kErrorNone : MbedTls::MapError(ret);
}
Error P256::KeyPair::Parse(void *aContext) const
{
Error error = kErrorNone;
mbedtls_pk_context *pk = reinterpret_cast<mbedtls_pk_context *>(aContext);
mbedtls_pk_init(pk);
VerifyOrExit(mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed);
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0, MbedTls::CryptoSecurePrng, nullptr) == 0,
error = kErrorParse);
#else
VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0) == 0, error = kErrorParse);
#endif
exit:
return error;
}
Error P256::KeyPair::GetPublicKey(PublicKey &aPublicKey) const
{
Error error;
mbedtls_pk_context pk;
mbedtls_ecp_keypair *keyPair;
int ret;
SuccessOrExit(error = Parse(&pk));
keyPair = mbedtls_pk_ec(pk);
ret = mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), aPublicKey.mData, kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_write_binary(&keyPair->MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), aPublicKey.mData + kMpiSize,
kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
exit:
mbedtls_pk_free(&pk);
return error;
}
Error P256::KeyPair::Sign(const Sha256::Hash &aHash, Signature &aSignature) const
{
Error error;
mbedtls_pk_context pk;
mbedtls_ecp_keypair * keypair;
mbedtls_ecdsa_context ecdsa;
mbedtls_mpi r;
mbedtls_mpi s;
int ret;
mbedtls_ecdsa_init(&ecdsa);
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
SuccessOrExit(error = Parse(&pk));
keypair = mbedtls_pk_ec(pk);
ret = mbedtls_ecdsa_from_keypair(&ecdsa, keypair);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE
#if (MBEDTLS_VERSION_NUMBER >= 0x02130000)
ret = mbedtls_ecdsa_sign_det_ext(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(),
Sha256::Hash::kSize, MBEDTLS_MD_SHA256, MbedTls::CryptoSecurePrng, nullptr);
#else
ret = mbedtls_ecdsa_sign_det(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(),
Sha256::Hash::kSize, MBEDTLS_MD_SHA256);
#endif
#else
ret = mbedtls_ecdsa_sign(&ecdsa.MBEDTLS_PRIVATE(grp), &r, &s, &ecdsa.MBEDTLS_PRIVATE(d), aHash.GetBytes(),
Sha256::Hash::kSize, MbedTls::CryptoSecurePrng, nullptr);
#endif
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
OT_ASSERT(mbedtls_mpi_size(&r) <= kMpiSize);
ret = mbedtls_mpi_write_binary(&r, aSignature.mShared.mMpis.mR, kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_write_binary(&s, aSignature.mShared.mMpis.mS, kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
exit:
mbedtls_pk_free(&pk);
mbedtls_mpi_free(&s);
mbedtls_mpi_free(&r);
mbedtls_ecdsa_free(&ecdsa);
return error;
}
Error P256::PublicKey::Verify(const Sha256::Hash &aHash, const Signature &aSignature) const
{
Error error = kErrorNone;
mbedtls_ecdsa_context ecdsa;
mbedtls_mpi r;
mbedtls_mpi s;
int ret;
mbedtls_ecdsa_init(&ecdsa);
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
ret = mbedtls_ecp_group_load(&ecdsa.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_read_binary(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(X), GetBytes(), kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_read_binary(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Y), GetBytes() + kMpiSize, kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_lset(&ecdsa.MBEDTLS_PRIVATE(Q).MBEDTLS_PRIVATE(Z), 1);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_read_binary(&r, aSignature.mShared.mMpis.mR, kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_mpi_read_binary(&s, aSignature.mShared.mMpis.mS, kMpiSize);
VerifyOrExit(ret == 0, error = MbedTls::MapError(ret));
ret = mbedtls_ecdsa_verify(&ecdsa.MBEDTLS_PRIVATE(grp), aHash.GetBytes(), Sha256::Hash::kSize,
&ecdsa.MBEDTLS_PRIVATE(Q), &r, &s);
VerifyOrExit(ret == 0, error = kErrorSecurity);
exit:
mbedtls_mpi_free(&s);
mbedtls_mpi_free(&r);
mbedtls_ecdsa_free(&ecdsa);
return error;
}
Error Sign(uint8_t * aOutput,
uint16_t & aOutputLength,
const uint8_t *aInputHash,
@@ -286,5 +124,4 @@ exit:
} // namespace Crypto
} // namespace ot
#endif // MBEDTLS_USE_TINYCRYPT
#endif // OPENTHREAD_CONFIG_ECDSA_ENABLE
+27 -39
View File
@@ -41,6 +41,9 @@
#include <stdint.h>
#include <stdlib.h>
#include <openthread/crypto.h>
#include <openthread/platform/crypto.h>
#include "common/error.hpp"
#include "crypto/sha256.hpp"
@@ -83,13 +86,13 @@ public:
*
*/
OT_TOOL_PACKED_BEGIN
class Signature
class Signature : public otPlatCryptoEcdsaSignature
{
friend class KeyPair;
friend class PublicKey;
public:
static constexpr uint8_t kSize = 2 * kMpiSize; ///< Signature size in bytes (two times the curve MPI size).
static constexpr uint8_t kSize = OT_CRYPTO_ECDSA_SIGNATURE_SIZE; ///< Signature size in bytes.
/**
* This method returns the signature as a byte array.
@@ -97,21 +100,7 @@ public:
* @returns A pointer to the byte array containing the signature.
*
*/
const uint8_t *GetBytes(void) const { return mShared.mKey; }
private:
OT_TOOL_PACKED_BEGIN
struct Mpis
{
uint8_t mR[kMpiSize];
uint8_t mS[kMpiSize];
} OT_TOOL_PACKED_END;
union OT_TOOL_PACKED_FIELD
{
Mpis mMpis;
uint8_t mKey[kSize];
} mShared;
const uint8_t *GetBytes(void) const { return m8; }
} OT_TOOL_PACKED_END;
/**
@@ -120,23 +109,20 @@ public:
* The key pair is stored using Distinguished Encoding Rules (DER) format (per RFC 5915).
*
*/
class KeyPair
class KeyPair : public otPlatCryptoEcdsaKeyPair
{
public:
/**
* Max buffer size (in bytes) for representing the key-pair in DER format.
*
*/
static constexpr uint8_t kMaxDerSize = 125;
static constexpr uint8_t kMaxDerSize = OT_CRYPTO_ECDSA_MAX_DER_SIZE;
/**
* This constructor initializes a `KeyPair` as empty (no key).
*
*/
KeyPair(void)
: mDerLength(0)
{
}
KeyPair(void) { mDerLength = 0; }
/**
* This method generates and populates the `KeyPair` with a new public/private keys.
@@ -147,7 +133,7 @@ public:
* @retval kErrorFailed Failed to generate key.
*
*/
Error Generate(void);
Error Generate(void) { return otPlatCryptoEcdsaGenerateKey(this); }
/**
* This method gets the associated public key from the `KeyPair`.
@@ -158,7 +144,7 @@ public:
* @retval kErrorParse The key-pair DER format could not be parsed (invalid format).
*
*/
Error GetPublicKey(PublicKey &aPublicKey) const;
Error GetPublicKey(PublicKey &aPublicKey) const { return otPlatCryptoEcdsaGetPublicKey(this, &aPublicKey); }
/**
* This method gets the pointer to start of the buffer containing the key-pair info in DER format.
@@ -212,13 +198,10 @@ public:
* @retval kErrorNoBufs Failed to allocate buffer for signature calculation.
*
*/
Error Sign(const Sha256::Hash &aHash, Signature &aSignature) const;
private:
Error Parse(void *aContext) const;
uint8_t mDerBytes[kMaxDerSize];
uint8_t mDerLength;
Error Sign(const Sha256::Hash &aHash, Signature &aSignature) const
{
return otPlatCryptoEcdsaSign(this, &aHash, &aSignature);
}
};
/**
@@ -228,12 +211,12 @@ public:
*
*/
OT_TOOL_PACKED_BEGIN
class PublicKey : public Equatable<PublicKey>
class PublicKey : public otPlatCryptoEcdsaPublicKey, public Equatable<PublicKey>
{
friend class KeyPair;
public:
static constexpr uint8_t kSize = kMpiSize * 2; ///< Size of the public key in bytes.
static constexpr uint8_t kSize = OT_CRYPTO_ECDSA_PUBLIC_KEY_SIZE; ///< Size of the public key in bytes.
/**
* This method gets the pointer to the buffer containing the public key (as an uncompressed curve point).
@@ -241,7 +224,7 @@ public:
* @return The pointer to the buffer containing the public key (with `kSize` bytes).
*
*/
const uint8_t *GetBytes(void) const { return mData; }
const uint8_t *GetBytes(void) const { return m8; }
/**
* This method uses the `PublicKey` to verify the ECDSA signature of a hashed message.
@@ -255,10 +238,10 @@ public:
* @retval kErrorNoBufs Failed to allocate buffer for signature verification
*
*/
Error Verify(const Sha256::Hash &aHash, const Signature &aSignature) const;
private:
uint8_t mData[kSize];
Error Verify(const Sha256::Hash &aHash, const Signature &aSignature) const
{
return otPlatCryptoEcdsaVerify(this, &aHash, &aSignature);
}
} OT_TOOL_PACKED_END;
};
@@ -292,6 +275,11 @@ Error Sign(uint8_t * aOutput,
} // namespace Ecdsa
} // namespace Crypto
DefineCoreType(otPlatCryptoEcdsaSignature, Crypto::Ecdsa::P256::Signature);
DefineCoreType(otPlatCryptoEcdsaKeyPair, Crypto::Ecdsa::P256::KeyPair);
DefineCoreType(otPlatCryptoEcdsaPublicKey, Crypto::Ecdsa::P256::PublicKey);
} // namespace ot
#endif // OPENTHREAD_CONFIG_ECDSA_ENABLE
-215
View File
@@ -1,215 +0,0 @@
/*
* Copyright (c) 2022, 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 ECDSA signing using TinyCrypt library.
*/
#include "ecdsa.hpp"
#if OPENTHREAD_CONFIG_ECDSA_ENABLE
#ifdef MBEDTLS_USE_TINYCRYPT
#if OPENTHREAD_CONFIG_DETERMINISTIC_ECDSA_ENABLE
#warning "tinycrypt does not support generating deterministic ECDSA signatures"
#endif
#include <string.h>
#include <mbedtls/pk.h>
#include <mbedtls/version.h>
#include <tinycrypt/ecc.h>
#include <tinycrypt/ecc_dh.h>
#include <tinycrypt/ecc_dsa.h>
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/random.hpp"
#include "crypto/mbedtls.hpp"
namespace ot {
namespace Crypto {
namespace Ecdsa {
Error P256::KeyPair::Generate(void)
{
mbedtls_pk_context pk;
mbedtls_uecc_keypair *keypair;
int ret;
mbedtls_pk_init(&pk);
ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY));
VerifyOrExit(ret == 0);
keypair = mbedtls_pk_uecc(pk);
ret = uECC_make_key(keypair->public_key, keypair->private_key);
VerifyOrExit(ret == UECC_SUCCESS);
ret = mbedtls_pk_write_key_der(&pk, mDerBytes, sizeof(mDerBytes));
VerifyOrExit(ret > 0);
mDerLength = static_cast<uint8_t>(ret);
memmove(mDerBytes, mDerBytes + sizeof(mDerBytes) - mDerLength, mDerLength);
exit:
mbedtls_pk_free(&pk);
return (ret >= 0) ? kErrorNone : MbedTls::MapError(ret);
}
Error P256::KeyPair::Parse(void *aContext) const
{
Error error = kErrorNone;
mbedtls_pk_context *pk = reinterpret_cast<mbedtls_pk_context *>(aContext);
mbedtls_pk_init(pk);
VerifyOrExit(mbedtls_pk_setup(pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) == 0, error = kErrorFailed);
#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0, MbedTls::CryptoSecurePrng, nullptr) == 0,
error = kErrorParse);
#else
VerifyOrExit(mbedtls_pk_parse_key(pk, mDerBytes, mDerLength, nullptr, 0) == 0, error = kErrorParse);
#endif
exit:
return error;
}
Error P256::KeyPair::GetPublicKey(PublicKey &aPublicKey) const
{
Error error;
mbedtls_pk_context pk;
mbedtls_uecc_keypair *keyPair;
int ret;
SuccessOrExit(error = Parse(&pk));
keyPair = mbedtls_pk_uecc(pk);
memcpy(aPublicKey.mData, keyPair->public_key, kMpiSize);
memcpy(aPublicKey.mData + kMpiSize, keyPair->public_key + kMpiSize, kMpiSize);
exit:
mbedtls_pk_free(&pk);
return error;
}
Error P256::KeyPair::Sign(const Sha256::Hash &aHash, Signature &aSignature) const
{
Error error;
mbedtls_pk_context pk;
mbedtls_uecc_keypair *keypair;
int ret;
uint8_t sig[2 * kMpiSize];
SuccessOrExit(error = Parse(&pk));
keypair = mbedtls_pk_uecc(pk);
ret = uECC_sign(keypair->private_key, aHash.GetBytes(), Sha256::Hash::kSize, sig);
VerifyOrExit(ret == UECC_SUCCESS, error = MbedTls::MapError(ret));
memcpy(aSignature.mShared.mMpis.mR, sig, kMpiSize);
memcpy(aSignature.mShared.mMpis.mS, sig + kMpiSize, kMpiSize);
exit:
mbedtls_pk_free(&pk);
return error;
}
Error P256::PublicKey::Verify(const Sha256::Hash &aHash, const Signature &aSignature) const
{
Error error = kErrorNone;
int ret;
uint8_t public_key[2 * kMpiSize];
uint8_t sig[2 * kMpiSize];
memcpy(public_key, GetBytes(), 2 * kMpiSize);
memcpy(sig, aSignature.mShared.mMpis.mR, kMpiSize);
memcpy(sig + kMpiSize, aSignature.mShared.mMpis.mS, kMpiSize);
ret = uECC_verify(public_key, aHash.GetBytes(), Sha256::Hash::kSize, sig);
VerifyOrExit(ret == UECC_SUCCESS, error = kErrorSecurity);
exit:
return error;
}
Error Sign(uint8_t * aOutput,
uint16_t & aOutputLength,
const uint8_t *aInputHash,
uint16_t aInputHashLength,
const uint8_t *aPrivateKey,
uint16_t aPrivateKeyLength)
{
Error error = kErrorNone;
mbedtls_pk_context pkCtx;
mbedtls_uecc_keypair *keypair;
uint8_t sig[2 * NUM_ECC_BYTES];
mbedtls_pk_init(&pkCtx);
// Parse a private key in PEM format.
VerifyOrExit(mbedtls_pk_parse_key(&pkCtx, aPrivateKey, aPrivateKeyLength, nullptr, 0) == 0,
error = kErrorInvalidArgs);
VerifyOrExit(mbedtls_pk_get_type(&pkCtx) == MBEDTLS_PK_ECKEY, error = kErrorInvalidArgs);
keypair = mbedtls_pk_uecc(pkCtx);
OT_ASSERT(keypair != nullptr);
// Sign using ECDSA.
VerifyOrExit(uECC_sign(keypair->private_key, aInputHash, aInputHashLength, sig) == UECC_SUCCESS,
error = kErrorFailed);
VerifyOrExit(2 * NUM_ECC_BYTES <= aOutputLength, error = kErrorNoBufs);
// Concatenate the two octet sequences in the order R and then S.
memcpy(aOutput, sig, 2 * NUM_ECC_BYTES);
aOutputLength = 2 * NUM_ECC_BYTES;
exit:
mbedtls_pk_free(&pkCtx);
return error;
}
} // namespace Ecdsa
} // namespace Crypto
} // namespace ot
#endif // MBEDTLS_USE_TINYCRYPT
#endif // OPENTHREAD_CONFIG_ECDSA_ENABLE