250 lines
6.4 KiB
C
Raw Normal View History

2025-10-10 16:07:00 +08:00
// Copyright 2024-2025 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <psa/crypto.h>
#include <psa/crypto_extra.h>
#define APP_SUCCESS (0)
#define APP_ERROR (-1)
#define APP_SUCCESS_MESSAGE "Example finished successfully!\r\n"
#define APP_ERROR_MESSAGE "Example exited with error!\r\n"
#define TAG "mbedtls"
#define CRYPTO_EXAMPLE_ECDSA_TEXT_SIZE (100)
#define CRYPTO_EXAMPLE_ECDSA_PUBLIC_KEY_SIZE (65)
#define CRYPTO_EXAMPLE_ECDSA_SIGNATURE_SIZE (64)
#define CRYPTO_EXAMPLE_ECDSA_HASH_SIZE (32)
/* Below text is used as plaintext for signing/verification */
static uint8_t m_plain_text[CRYPTO_EXAMPLE_ECDSA_TEXT_SIZE] = {
"Example string to demonstrate basic usage of ECDSA."
};
static uint8_t m_pub_key[CRYPTO_EXAMPLE_ECDSA_PUBLIC_KEY_SIZE];
static uint8_t m_signature[CRYPTO_EXAMPLE_ECDSA_SIGNATURE_SIZE];
static uint8_t m_hash[CRYPTO_EXAMPLE_ECDSA_HASH_SIZE];
static psa_key_id_t keypair_id;
static psa_key_id_t pub_key_id;
static int crypto_init(void)
{
psa_status_t status;
/* Initialize PSA Crypto */
status = psa_crypto_init();
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_crypto_init failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
return APP_SUCCESS;
}
static int crypto_finish(void)
{
psa_status_t status;
/* Destroy the key handle */
status = psa_destroy_key(keypair_id);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_destroy_key failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
status = psa_destroy_key(pub_key_id);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_destroy_key failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
return APP_SUCCESS;
}
static int generate_ecdsa_keypair(void)
{
psa_status_t status;
size_t olen;
BK_LOGI(TAG, "Generating random ECDSA keypair...\r\n");
/* Configure the key attributes */
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
/* Configure the key attributes */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_HASH);
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attributes, 256);
/* Generate a random keypair. The keypair is not exposed to the application,
* we can use it to sign hashes.
*/
status = psa_generate_key(&key_attributes, &keypair_id);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_generate_key failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
/* Export the public key */
status = psa_export_public_key(keypair_id, m_pub_key, sizeof(m_pub_key), &olen);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_export_public_key failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
/* Reset key attributes and free any allocated resources. */
psa_reset_key_attributes(&key_attributes);
return APP_SUCCESS;
}
static int import_ecdsa_pub_key(void)
{
/* Configure the key attributes */
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_status_t status;
/* Configure the key attributes */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY_HASH);
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDSA(PSA_ALG_SHA_256));
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attributes, 256);
status = psa_import_key(&key_attributes, m_pub_key, sizeof(m_pub_key), &pub_key_id);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_import_key failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
/* Reset key attributes and free any allocated resources. */
psa_reset_key_attributes(&key_attributes);
return APP_SUCCESS;
}
static int sign_message(void)
{
uint32_t output_len;
psa_status_t status;
BK_LOGI(TAG, "Signing a message using ECDSA...\r\n");
/* Compute the SHA256 hash*/
status = psa_hash_compute(PSA_ALG_SHA_256,
m_plain_text,
sizeof(m_plain_text),
m_hash,
sizeof(m_hash),
(size_t *)&output_len);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_hash_compute failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
/* Sign the hash */
status = psa_sign_hash(keypair_id,
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
m_hash,
sizeof(m_hash),
m_signature,
sizeof(m_signature),
(size_t *)&output_len);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_sign_hash failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
BK_LOGI(TAG, "Message signed successfully!\r\n");
return APP_SUCCESS;
}
static int verify_message(void)
{
psa_status_t status;
BK_LOGI(TAG, "Verifying ECDSA signature...\r\n");
/* Verify the signature of the hash */
status = psa_verify_hash(pub_key_id,
PSA_ALG_ECDSA(PSA_ALG_SHA_256),
m_hash,
sizeof(m_hash),
m_signature,
sizeof(m_signature));
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_verify_hash failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
BK_LOGI(TAG, "Signature verification was successful!\r\n");
return APP_SUCCESS;
}
int ecdsa_main(void)
{
int status;
BK_LOGI(TAG, "Starting ECDSA example...\r\n");
status = crypto_init();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
status = generate_ecdsa_keypair();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
status = import_ecdsa_pub_key();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
status = sign_message();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
status = verify_message();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
status = crypto_finish();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
BK_LOGI(TAG, APP_SUCCESS_MESSAGE);
return APP_SUCCESS;
}