AES CBC (or EBC) on nRF52832 & nRF54L05

So I need to decrypt a single 16 byte block of data using AES128 and a pre-shared key on the above SoCs. But PSA doesn't seem to work (I'm currently working using the nRF52DK). Even the AES CBC example application fails with an error when I run it

Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
[00:00:00.265,533] <inf> aes_cbc: Starting AES-CBC-NO-PADDING example...
[00:00:00.265,594] <inf> aes_cbc: Generating random AES key...
[00:00:00.265,625] <inf> aes_cbc: psa_generate_key failed! (Error: -141)
[00:00:00.265,625] <inf> aes_cbc: Example exited with error!

I notice there is a config option CONFIG_MBEDTLS_LEGACY_CRYPTO_C, but the description suggests it's not a great option

Enable support for legacy mbed TLS APIs.
Note that this is a configuration that may be removed at some point.
It is only provided during a transition period while PSA Crypto APIs become
the defacto front-end. Enabling this will enable nrf_oberon for all features that
are supported and builtin for the remaining functionality.

Any advice on the way forward?

Parents
  • Hi,

    The sample does not support nRF52832 out of the box, so you need to add a few configuartions for it. If you add these to prj.conf, the sample should run successfully:

    CONFIG_MBEDTLS_ENABLE_HEAP=y
    CONFIG_MBEDTLS_HEAP_SIZE=4096
    CONFIG_ENTROPY_GENERATOR=y

  • Still fails unfortunately this time with error -134 which looks like it is PSA_ERROR_NOT_SUPPORTED

    *** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
    *** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
    [00:00:00.481,872] <inf> aes_cbc: Starting AES-CBC-NO-PADDING example...
    [00:00:00.481,903] <inf> aes_cbc: Generating random AES key...
    [00:00:00.481,994] <inf> aes_cbc: psa_generate_key failed! (Error: -134)
    [00:00:00.481,994] <inf> aes_cbc: Example exited with error!

    Here is the entire prj.conf, it's the virgin file from the sample with just the lines you suggested added

    #
    # Copyright (c) 2024 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    # The Zephyr CMSIS emulation assumes that ticks are ms, currently
    CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000
    
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_HEAP_MEM_POOL_SIZE=4096
    
    # Enable logging
    CONFIG_CONSOLE=y
    CONFIG_LOG=y
    
    # Enable nordic security backend and PSA APIs
    #CONFIG_NRF_SECURITY=y
    #CONFIG_MBEDTLS_PSA_CRYPTO_C=y
    
    #CONFIG_PSA_WANT_GENERATE_RANDOM=y
    #CONFIG_PSA_WANT_KEY_TYPE_AES=y
    #CONFIG_PSA_WANT_ALG_CBC_NO_PADDING=y
    
    CONFIG_NORDIC_SECURITY_BACKEND=y
    CONFIG_MBEDTLS_ENABLE_HEAP=y
    CONFIG_MBEDTLS_HEAP_SIZE=4096
    CONFIG_ENTROPY_GENERATOR=y
    

    This was pretty simple using SDK17 using nrf_crypto_aes_crypt()...

    What about using a PSK? I was trying to use psa_import_key() but getting errors like the above, until I gave up as I think there's something fundamentally wrong (which seems to be the case as the sample doesn't work)

    For reference, here's the main.c. I want to use my custom board, but for the sake of testing I'm using nRF52DK PCA10040

    /*
     * Copyright (c) 2021 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr/kernel.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/logging/log.h>
    #include <stdio.h>
    #include <psa/crypto.h>
    #include <psa/crypto_extra.h>
    
    
    #ifdef CONFIG_BUILD_WITH_TFM
    #include <tfm_ns_interface.h>
    #endif
    
    #define APP_SUCCESS		(0)
    #define APP_ERROR		(-1)
    #define APP_SUCCESS_MESSAGE "Example finished successfully!"
    #define APP_ERROR_MESSAGE "Example exited with error!"
    
    #define PRINT_HEX(p_label, p_text, len)\
    	({\
    		LOG_INF("---- %s (len: %u): ----", p_label, len);\
    		LOG_HEXDUMP_INF(p_text, len, "Content:");\
    		LOG_INF("---- %s end  ----", p_label);\
    	})
    
    LOG_MODULE_REGISTER(aes_cbc, LOG_LEVEL_DBG);
    
    /* ====================================================================== */
    /* Global variables/defines for the AES-CBC-NO-PADDING example */
    
    #define NRF_CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE (64)
    #define NRF_CRYPTO_EXAMPLE_AES_BLOCK_SIZE (16)
    
    static uint8_t m_iv[NRF_CRYPTO_EXAMPLE_AES_BLOCK_SIZE];
    
    /* Below text is used as plaintext for encryption/decryption */
    static uint8_t m_plain_text[NRF_CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE] = {
    	"Example string to demonstrate basic usage of AES CBC mode."
    };
    
    static uint8_t m_encrypted_text[NRF_CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE];
    static uint8_t m_decrypted_text[NRF_CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE];
    
    static psa_key_id_t key_id;
    /* ====================================================================== */
    
    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;
    }
    
    int crypto_finish(void)
    {
    	psa_status_t status;
    
    	/* Destroy the key handle */
    	status = psa_destroy_key(key_id);
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_destroy_key failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	return APP_SUCCESS;
    }
    
    int generate_key(void)
    {
    	psa_status_t status;
    
    	LOG_INF("Generating random AES key...");
    
    	/* 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_CBC_NO_PADDING);
    	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) {
    		LOG_INF("psa_generate_key failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	/* After the key handle is acquired the attributes are not needed */
    	psa_reset_key_attributes(&key_attributes);
    
    	LOG_INF("AES key generated successfully!");
    
    	return APP_SUCCESS;
    }
    
    int encrypt_cbc_aes(void)
    {
    	uint32_t olen;
    	psa_status_t status;
    	psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
    
    	LOG_INF("Encrypting using AES CBC MODE...");
    
    	/* Setup the encryption operation */
    	status = psa_cipher_encrypt_setup(&operation, key_id, PSA_ALG_CBC_NO_PADDING);
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_cipher_encrypt_setup failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	/* Generate an IV */
    	status = psa_cipher_generate_iv(&operation, m_iv, sizeof(m_iv), &olen);
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_cipher_generate_iv failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	/* Perform the encryption */
    	status = psa_cipher_update(&operation, m_plain_text,
    				   sizeof(m_plain_text), m_encrypted_text,
    				   sizeof(m_encrypted_text), &olen);
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_cipher_update failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	/* Finalize the encryption */
    	status = psa_cipher_finish(&operation, m_encrypted_text + olen,
    				   sizeof(m_encrypted_text) - olen,
    				   &olen);
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_cipher_finish failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	LOG_INF("Encryption successful!");
    	PRINT_HEX("IV", m_iv, sizeof(m_iv));
    	PRINT_HEX("Plaintext", m_plain_text, sizeof(m_plain_text));
    	PRINT_HEX("Encrypted text", m_encrypted_text, sizeof(m_encrypted_text));
    
    	/* Clean up cipher operation context */
    	psa_cipher_abort(&operation);
    
    	return APP_SUCCESS;
    }
    
    int decrypt_cbc_aes(void)
    {
    	uint32_t olen;
    	psa_status_t status;
    	psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
    
    	LOG_INF("Decrypting using AES CBC MODE...");
    
    	/* Setup the decryption operation */
    	status = psa_cipher_decrypt_setup(&operation, key_id, PSA_ALG_CBC_NO_PADDING);
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_cipher_decrypt_setup failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	/* Set the IV generated in encryption */
    	status = psa_cipher_set_iv(&operation, m_iv, sizeof(m_iv));
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_cipher_set_iv failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	/* Perform the decryption */
    	status = psa_cipher_update(&operation, m_encrypted_text,
    				   sizeof(m_encrypted_text), m_decrypted_text,
    				   sizeof(m_decrypted_text), &olen);
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_cipher_update failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	/* Finalize the decryption */
    	status = psa_cipher_finish(&operation, m_decrypted_text + olen,
    				   sizeof(m_decrypted_text) - olen,
    				   &olen);
    	if (status != PSA_SUCCESS) {
    		LOG_INF("psa_cipher_finish failed! (Error: %d)", status);
    		return APP_ERROR;
    	}
    
    	PRINT_HEX("Decrypted text", m_decrypted_text, sizeof(m_decrypted_text));
    
    	/* Check the validity of the decryption */
    	if (memcmp(m_decrypted_text,
    				m_plain_text,
    				NRF_CRYPTO_EXAMPLE_AES_MAX_TEXT_SIZE) != 0){
    
    		LOG_INF("Error: Decrypted text doesn't match the plaintext");
    		return APP_ERROR;
    	}
    
    	LOG_INF("Decryption successful!");
    
    	/*  Clean up cipher operation context */
    	psa_cipher_abort(&operation);
    
    	return APP_SUCCESS;
    }
    
    
    int main(void)
    {
    	int status;
    
    	LOG_INF("Starting AES-CBC-NO-PADDING example...");
    
    	status = crypto_init();
    	if (status != APP_SUCCESS) {
    		LOG_INF(APP_ERROR_MESSAGE);
    		return APP_ERROR;
    	}
    
    	status = generate_key();
    	if (status != APP_SUCCESS) {
    		LOG_INF(APP_ERROR_MESSAGE);
    		return APP_ERROR;
    	}
    
    	status = encrypt_cbc_aes();
    	if (status != APP_SUCCESS) {
    		LOG_INF(APP_ERROR_MESSAGE);
    		return APP_ERROR;
    	}
    
    	status = decrypt_cbc_aes();
    	if (status != APP_SUCCESS) {
    		LOG_INF(APP_ERROR_MESSAGE);
    		return APP_ERROR;
    	}
    
    	status = crypto_finish();
    	if (status != APP_SUCCESS) {
    		LOG_INF(APP_ERROR_MESSAGE);
    		return APP_ERROR;
    	}
    
    	LOG_INF(APP_SUCCESS_MESSAGE);
    
    	return APP_SUCCESS;
    }
    

  • That still didn't work. This is a brand new application using "copy a sample" in VCS. Here are the steps:

    1. Create another new application from sample \nrf\samples\crypto\aes_cbc
    2. Create new build for nRF52DK (generate only)
    3. Modify prj.conf add
      1. CONFIG_MBEDTLS_ENABLE_HEAP=y
      2. CONFIG_MBEDTLS_HEAP_SIZE=4096
      3. CONFIG_ENTROPY_GENERATOR=y
    4. Pristine Build
    5. Flash
    6. Fail
    7. Add CONFIG_ENTROPY_NRF5_RNG=y
    8. Pristine Build
    9. Flash
    10. Fail

    *** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
    *** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
    [00:00:00.471,313] <inf> aes_cbc: Starting AES-CBC-NO-PADDING example...
    [00:00:00.471,343] <inf> aes_cbc: Generating random AES key...
    [00:00:00.471,435] <inf> aes_cbc: psa_generate_key failed! (Error: -134)
    [00:00:00.471,435] <inf> aes_cbc: Example exited with error!

    I am using ncs 2.9.0, and right now I am using a PCA10040 board although I started this with my own custom board which has been running code written with SDK17.1 just fine.

    Project zip attached...

    Thanks

    aes_cbc_1.zip

  • Hi,

    I see you have commented out parts of the prj.conf that include important configs. Pleaes refer the sample (and any other changes) and build with the only difference being adding the three lines to prj.conf that I suggested.

  • No I haven't commented out anything! That is exactly how the sample project was delivered (apart of course from the lines appended as you suggested).

    Edit: Here is the prj.conf after deleting the old folders and creating another new application from the sample (no build, nothing)

    #
    # Copyright (c) 2024 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    # The Zephyr CMSIS emulation assumes that ticks are ms, currently
    CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000
    
    CONFIG_MAIN_STACK_SIZE=4096
    CONFIG_HEAP_MEM_POOL_SIZE=4096
    
    # Enable logging
    CONFIG_CONSOLE=y
    CONFIG_LOG=y
    
    # Enable nordic security backend and PSA APIs
    #CONFIG_NRF_SECURITY=y
    #CONFIG_MBEDTLS_PSA_CRYPTO_C=y
    
    #CONFIG_PSA_WANT_GENERATE_RANDOM=y
    #CONFIG_PSA_WANT_KEY_TYPE_AES=y
    #CONFIG_PSA_WANT_ALG_CBC_NO_PADDING=y
    
    CONFIG_NORDIC_SECURITY_BACKEND=y
    

  • You have commented out configs that are needed and that are used in the sample here. The configs you have commented your last post should be uncommented. Specifically, these:

    # Enable nordic security backend and PSA APIs
    CONFIG_NRF_SECURITY=y
    CONFIG_MBEDTLS_PSA_CRYPTO_C=y
    
    CONFIG_PSA_WANT_GENERATE_RANDOM=y
    CONFIG_PSA_WANT_KEY_TYPE_AES=y
    CONFIG_PSA_WANT_ALG_CBC_NO_PADDING=y

  • OK so I have no idea how this happened - but I checked my ncs folder from where the samples are copied and the lines were commented. So I re-downloaded ncs 2.9.0 and replaced the aes-cbc folder entirely from Github and it's as it should be. Weird, as I've only used the "copy a sample" method from within VCS?

    So anyway now it runs :) Apologies for the hassle.

    For a pre-shared key do I generate a key using psa_import_key() ?

Reply
  • OK so I have no idea how this happened - but I checked my ncs folder from where the samples are copied and the lines were commented. So I re-downloaded ncs 2.9.0 and replaced the aes-cbc folder entirely from Github and it's as it should be. Weird, as I've only used the "copy a sample" method from within VCS?

    So anyway now it runs :) Apologies for the hassle.

    For a pre-shared key do I generate a key using psa_import_key() ?

Children
Related