Microchip® Advanced Software Framework

Quick Start Guide for AES - DMA

The supported board list:

  • SAM L21 Xplained Pro
  • SAM L22 Xplained Pro

This example demonstrates how to use the AES driver to perform:

  • ECB encryption with DMA

Upon startup, the program uses the USART driver to display application output message from which ECB DMA encryption modes can be tested.

Quick Start

Prerequisites

There are no prerequisites for this use case.

Code

Add to the main application source file, outside of any functions:

#define AES_EXAMPLE_REFBUF_SIZE 4
uint32_t ref_plain_text[AES_EXAMPLE_REFBUF_SIZE] = {
0xe2bec16b,
0x969f402e,
0x117e3de9,
0x2a179373
};
uint32_t ref_cipher_text_ecb[AES_EXAMPLE_REFBUF_SIZE] = {
0xb47bd73a,
0x60367a0d,
0xf3ca9ea8,
0x97ef6624
};
const uint32_t key128[4] = {
0x16157e2b,
0xa6d2ae28,
0x8815f7ab,
0x3c4fcf09
};

Add to the main application source file, outside of any functions:

/* Output data array */
static uint32_t output_data[AES_EXAMPLE_REFBUF_SIZE];
/* State indicate */
volatile bool state = false;
struct aes_config g_aes_cfg;
struct aes_module aes_instance;
struct usart_module usart_instance;

Copy-paste the following setup code to your user application:

static void configure_usart(void)
{
struct usart_config config_usart;
usart_get_config_defaults(&config_usart);
config_usart.baudrate = 38400;
config_usart.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;
config_usart.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;
config_usart.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;
config_usart.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;
config_usart.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;
stdio_serial_init(&usart_instance, EDBG_CDC_MODULE, &config_usart);
usart_enable(&usart_instance);
}
static void ecb_mode_test_dma(void)
{
printf("\r\n-----------------------------------\r\n");
printf("- 128bit cryptographic key\r\n");
printf("- ECB cipher mode\r\n");
printf("- DMA mode\r\n");
printf("- 4 32bit words with DMA\r\n");
printf("-----------------------------------\r\n");
state = false;
/* Configure the AES. */
g_aes_cfg.encrypt_mode = AES_ENCRYPTION;
g_aes_cfg.key_size = AES_KEY_SIZE_128;
g_aes_cfg.start_mode = AES_AUTO_START;
g_aes_cfg.opmode = AES_ECB_MODE;
g_aes_cfg.cfb_size = AES_CFB_SIZE_128;
g_aes_cfg.lod = false;
aes_set_config(&aes_instance,AES, &g_aes_cfg);
/* Set the cryptographic key. */
aes_write_key(&aes_instance, key128);
/* The initialization vector is not used by the ECB cipher mode. */
dma_start_transfer_job(&example_resource_tx);
aes_set_new_message(&aes_instance);
aes_clear_new_message(&aes_instance);
/* Wait DMA transfer */
while (false == state) {
}
/* Wait for the end of the encryption process. */
while (!(aes_get_status(&aes_instance) & AES_ENCRYPTION_COMPLETE)) {
}
state = false;
dma_start_transfer_job(&example_resource_rx);
/* Wait DMA transfer */
while (false == state) {
}
if ((ref_cipher_text_ecb[0] != output_data[0]) ||
(ref_cipher_text_ecb[1] != output_data[1]) ||
(ref_cipher_text_ecb[2] != output_data[2]) ||
(ref_cipher_text_ecb[3] != output_data[3])) {
printf("\r\nKO!!!\r\n");
} else {
printf("\r\nOK!!!\r\n");
}
}
static void transfer_tx_rx_done(struct dma_resource* const resource )
{
state = true;
}
static void configure_dma_aes_wr(void)
{
struct dma_resource_config tx_config;
tx_config.peripheral_trigger = AES_DMAC_ID_WR;
tx_config.trigger_action = DMA_TRIGGER_ACTION_BLOCK;
dma_allocate(&example_resource_tx, &tx_config);
struct dma_descriptor_config tx_descriptor_config;
dma_descriptor_get_config_defaults(&tx_descriptor_config);
tx_descriptor_config.beat_size = DMA_BEAT_SIZE_WORD;
tx_descriptor_config.dst_increment_enable = false;
tx_descriptor_config.block_transfer_count = AES_EXAMPLE_REFBUF_SIZE;
tx_descriptor_config.source_address = (uint32_t)ref_plain_text + sizeof(ref_plain_text);
tx_descriptor_config.destination_address =(uint32_t) &(AES->INDATA);
dma_descriptor_create(&example_descriptor_tx, &tx_descriptor_config);
dma_add_descriptor(&example_resource_tx, &example_descriptor_tx);
}
static void configure_dma_aes_rd(void)
{
struct dma_resource_config rx_config;
rx_config.peripheral_trigger = AES_DMAC_ID_RD;
rx_config.trigger_action = DMA_TRIGGER_ACTION_BLOCK;
dma_allocate(&example_resource_rx, &rx_config);
struct dma_descriptor_config rx_descriptor_config;
dma_descriptor_get_config_defaults(&rx_descriptor_config);
rx_descriptor_config.beat_size = DMA_BEAT_SIZE_WORD;
rx_descriptor_config.src_increment_enable = false;
rx_descriptor_config.block_transfer_count = AES_EXAMPLE_REFBUF_SIZE;
rx_descriptor_config.source_address = (uint32_t)&(AES->INDATA);
rx_descriptor_config.destination_address =
(uint32_t)output_data + sizeof(output_data);
dma_descriptor_create(&example_descriptor_rx, &rx_descriptor_config);
dma_add_descriptor(&example_resource_rx, &example_descriptor_rx);
}

Add to user application initialization (typically the start of main()):

/* Initialize the system and console*/
configure_usart();
/* Configure AES DMA and enable callback */
configure_dma_aes_wr();
configure_dma_aes_rd();
dma_register_callback(&example_resource_tx, transfer_tx_rx_done,
dma_register_callback(&example_resource_rx, transfer_tx_rx_done,
aes_init(&aes_instance,AES, &g_aes_cfg);
aes_enable(&aes_instance);

Workflow

  1. Define sample data from NIST-800-38A appendix F for ECB mode.
    #define AES_EXAMPLE_REFBUF_SIZE 4
    uint32_t ref_plain_text[AES_EXAMPLE_REFBUF_SIZE] = {
    0xe2bec16b,
    0x969f402e,
    0x117e3de9,
    0x2a179373
    };
    uint32_t ref_cipher_text_ecb[AES_EXAMPLE_REFBUF_SIZE] = {
    0xb47bd73a,
    0x60367a0d,
    0xf3ca9ea8,
    0x97ef6624
    };
    const uint32_t key128[4] = {
    0x16157e2b,
    0xa6d2ae28,
    0x8815f7ab,
    0x3c4fcf09
    };
  2. Create related module variable and software instance structure.
    /* Output data array */
    static uint32_t output_data[AES_EXAMPLE_REFBUF_SIZE];
    /* State indicate */
    volatile bool state = false;
    struct aes_config g_aes_cfg;
    struct aes_module aes_instance;
    struct usart_module usart_instance;
  3. Create DMA resource struct and descriptor.
    struct dma_resource example_resource_tx;
    struct dma_resource example_resource_rx;
    DmacDescriptor example_descriptor_tx SECTION_DMAC_DESCRIPTOR;
    DmacDescriptor example_descriptor_rx SECTION_DMAC_DESCRIPTOR;
  4. Configure, initialize, and enable AES module.
    1. Configuration AES DMA module, which can be used for AES.
      /* Configure AES DMA and enable callback */
      configure_dma_aes_wr();
      configure_dma_aes_rd();
      dma_register_callback(&example_resource_tx, transfer_tx_rx_done,
      dma_register_callback(&example_resource_rx, transfer_tx_rx_done,
    2. Configuration AES struct, which can be filled out to adjust the configuration of a physical AES peripheral.
    3. Initialize the AES configuration struct with the module's default values.
      aes_init(&aes_instance,AES, &g_aes_cfg);
    4. Enable the AES module.
      aes_enable(&aes_instance);

Use Case

Code

Copy-paste the following code to your user application:

/* ECB mode encryption test with DMA */
ecb_mode_test_dma();

Workflow

  1. Configure ECB mode encryption with DMA and run test.
    state = false;
    /* Configure the AES. */
    g_aes_cfg.encrypt_mode = AES_ENCRYPTION;
    g_aes_cfg.key_size = AES_KEY_SIZE_128;
    g_aes_cfg.start_mode = AES_AUTO_START;
    g_aes_cfg.opmode = AES_ECB_MODE;
    g_aes_cfg.cfb_size = AES_CFB_SIZE_128;
    g_aes_cfg.lod = false;
    aes_set_config(&aes_instance,AES, &g_aes_cfg);
    /* Set the cryptographic key. */
    aes_write_key(&aes_instance, key128);
    /* The initialization vector is not used by the ECB cipher mode. */
    dma_start_transfer_job(&example_resource_tx);
    aes_set_new_message(&aes_instance);
    aes_clear_new_message(&aes_instance);
    /* Wait DMA transfer */
    while (false == state) {
    }
    /* Wait for the end of the encryption process. */
    while (!(aes_get_status(&aes_instance) & AES_ENCRYPTION_COMPLETE)) {
    }
    state = false;
    dma_start_transfer_job(&example_resource_rx);
    /* Wait DMA transfer */
    while (false == state) {
    }
    if ((ref_cipher_text_ecb[0] != output_data[0]) ||
    (ref_cipher_text_ecb[1] != output_data[1]) ||
    (ref_cipher_text_ecb[2] != output_data[2]) ||
    (ref_cipher_text_ecb[3] != output_data[3])) {
    printf("\r\nKO!!!\r\n");
    } else {
    printf("\r\nOK!!!\r\n");
    }