2025-10-10 16:07:00 +08:00

224 lines
5.7 KiB
C

// 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 <string.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!"
#define APP_ERROR_MESSAGE "Example exited with error!"
#define TAG "mbedtls"
#define CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE (100)
#define CRYPTO_EXAMPLE_AES_BLOCK_SIZE (16)
#define CRYPTO_EXAMPLE_AES_IV_SIZE (12)
#define CRYPTO_EXAMPLE_AES_ADDITIONAL_SIZE (35)
#define CRYPTO_EXAMPLE_AES_GCM_TAG_LENGTH (16)
/* AES sample IV, DO NOT USE IN PRODUCTION */
static uint8_t m_iv[CRYPTO_EXAMPLE_AES_IV_SIZE];
/* Below text is used as plaintext for encryption/decryption */
static uint8_t m_plain_text[CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE] = {
"Example string to demonstrate basic usage of AES GCM mode."
};
/* Below text is used as additional data for authentication */
static uint8_t m_additional_data[CRYPTO_EXAMPLE_AES_ADDITIONAL_SIZE] = {
"Example string of additional data"
};
static uint8_t m_encrypted_text[CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE +
CRYPTO_EXAMPLE_AES_GCM_TAG_LENGTH];
static uint8_t m_decrypted_text[CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE];
static psa_key_id_t key_id;
static int crypto_init(void)
{
psa_status_t status;
/* Initialize PSA Crypto */
status = psa_crypto_init();
if (status != PSA_SUCCESS) {
return APP_ERROR;
}
return APP_SUCCESS;
}
static int crypto_finish(void)
{
psa_status_t status;
/* Destroy the key handle */
status = psa_destroy_key(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_key(void)
{
psa_status_t status;
BK_LOGI(TAG, "Generating random AES key...\r\n");
/* Configure the key attributes */
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT);
psa_set_key_lifetime(&key_attributes, PSA_KEY_LIFETIME_VOLATILE);
psa_set_key_algorithm(&key_attributes, PSA_ALG_GCM);
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&key_attributes, 128);
/* Generate a random key. The key is not exposed to the application,
* we can use it to encrypt/decrypt using the key handle
*/
status = psa_generate_key(&key_attributes, &key_id);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_generate_key failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
/* After the key handle is acquired the attributes are not needed */
psa_reset_key_attributes(&key_attributes);
BK_LOGI(TAG, "AES key generated successfully!\r\n");
return 0;
}
static int encrypt_aes_gcm(void)
{
uint32_t output_len;
psa_status_t status;
BK_LOGI(TAG, "Encrypting using AES GCM MODE...\r\n");
/* Generate a random IV */
status = psa_generate_random(m_iv, CRYPTO_EXAMPLE_AES_IV_SIZE);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_generate_random failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
/* Encrypt the plaintext and create the authentication tag */
status = psa_aead_encrypt(key_id,
PSA_ALG_GCM,
m_iv,
sizeof(m_iv),
m_additional_data,
sizeof(m_additional_data),
m_plain_text,
sizeof(m_plain_text),
m_encrypted_text,
sizeof(m_encrypted_text),
(size_t *)&output_len);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_aead_encrypt failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
BK_LOGI(TAG, "Encryption successful!\r\n");
return APP_SUCCESS;
}
static int decrypt_aes_gcm(void)
{
uint32_t output_len;
psa_status_t status;
BK_LOGI(TAG, "Decrypting using AES GCM MODE...\r\n");
/* Decrypt and authenticate the encrypted data */
status = psa_aead_decrypt(key_id,
PSA_ALG_GCM,
m_iv,
sizeof(m_iv),
m_additional_data,
sizeof(m_additional_data),
m_encrypted_text,
sizeof(m_encrypted_text),
m_decrypted_text,
sizeof(m_decrypted_text),
(size_t *)&output_len);
if (status != PSA_SUCCESS) {
BK_LOGI(TAG, "psa_aead_decrypt failed! (Error: %d)\r\n", status);
return APP_ERROR;
}
/* Check the validity of the decryption */
if (memcmp(m_decrypted_text, m_plain_text, CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE) != 0) {
BK_LOGI(TAG, "Error: Decrypted text doesn't match the plaintext\r\n");
return APP_ERROR;
}
BK_LOGI(TAG, "Decryption and authentication successful!\r\n");
return APP_SUCCESS;
}
int aes_gcm_main(void)
{
int status;
BK_LOGI(TAG, "Starting AES-GCM example...\r\n");
status = crypto_init();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
status = generate_key();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
status = encrypt_aes_gcm();
if (status != APP_SUCCESS) {
BK_LOGI(TAG, APP_ERROR_MESSAGE);
return APP_ERROR;
}
status = decrypt_aes_gcm();
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;
}