AES module - DMA and Key issues

Go To Last Post
3 posts / 0 new
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm using an XMega32A4U as a USB Mass Storage device. I got the whole thing functional, and it interoperates properly, but in doing so, I've had to do some things that give me pause.


What I really wanted to do is set up two DMA channels to make a disk block's worth of cipher material. So the idea is that channel 1 loads the STATE register, and then the completion ISR hits the AES START bit. Channel 0 is triggered by AES and copies the STATE register out to a buffer. The ISR for channel 0 checks for completion, alters the iv buffer according to the algorithm and then manually triggers channel 1.


What's happening is that when I hit the AES start bit in the channel 1 ISR is that the AES ERROR bit turns on and that's all she wrote.


        // Set up DMA channel 0 to do 16 byte blocks from AES
        // to our pre_ct, advancing forward every time.
        DMA.CH0.CTRLA &= ~(DMA_CH_ENABLE_bm);
        DMA.CH0.CTRLA |= DMA_CH_RESET_bm;
        DMA.CH0.CTRLA |= DMA_CH_ENABLE_bm;
        //DMA.CH0.CTRLA = 0;
        DMA.CH0.CTRLB |= DMA_CH_TRNINTLVL_MED_gc; // lower than USB, higher than background
        DMA.CH0.TRFCNTH = 0;
        // Going from a single address to a constantly moving forward buffer every time
        DMA.CH0.REPCNT = 0;
        // Going from the AES state register to our pre_ct buffer
        DMA.CH0.SRCADDR0 = (uint8_t)((uint16_t)&AES.STATE >> 0);
        DMA.CH0.SRCADDR1 = (uint8_t)((uint16_t)&AES.STATE >> 8);
        DMA.CH0.SRCADDR2 = 0;
        DMA.CH0.DESTADDR0 = (uint8_t)(((uint16_t)pre_ct) >> 0);
        DMA.CH0.DESTADDR1 = (uint8_t)(((uint16_t)pre_ct) >> 8);
        DMA.CH0.DESTADDR2 = 0;

        // Set up DMA channel 1 to do 16 bytes from the nonce buffer to AES,
        // repeating the same thing every time.
        DMA.CH1.CTRLA &= ~(DMA_CH_ENABLE_bm);
        DMA.CH1.CTRLA |= DMA_CH_RESET_bm;
        DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm;
        //DMA.CH1.CTRLA = 0;
        DMA.CH1.CTRLB |= DMA_CH_TRNINTLVL_MED_gc; // lower than USB, higher than background
        DMA.CH1.TRFCNTH = 0;
        // Going from the same buffer every time to just a single address
        DMA.CH1.REPCNT = 0;
        // Going from our nonce buffer to the AES state register
        DMA.CH1.SRCADDR0 = (uint8_t)(((uint16_t)nonce) >> 0);
        DMA.CH1.SRCADDR1 = (uint8_t)(((uint16_t)nonce) >> 8);
        DMA.CH1.SRCADDR2 = 0;
        DMA.CH1.DESTADDR0 = (uint8_t)((uint16_t)&AES.STATE >> 0);
        DMA.CH1.DESTADDR1 = (uint8_t)((uint16_t)&AES.STATE >> 8);
        DMA.CH1.DESTADDR2 = 0;

        // And go!
        //DMA.CH1.CTRLA |= DMA_CH_ENABLE_bm;
        DMA.CH1.CTRLA |= DMA_CH_TRFREQ_bm;

In the meantime, I've foregone DMA and am just using a for() loop to copy the state material in and out in an AES ISR. That's working, sort of, but brings me to my other concern - it seems like I have to load the key every time or it gets corrupted. Can't the AES system just keep reusing the key? If I have to reload the key every time, then that's going to be a third DMA channel just to do that. No me gusta.



Last Edited: Thu. Apr 27, 2017 - 05:27 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

nsayer wrote:
Can't the AES system just keep reusing the key?

(page 306)

The following setup and use procedure is recommended:
1. Enable the AES interrupt (optional).
2. Select the AES direction to encryption or decryption.
3. Load the key data block into the AES key memory.
4. Load the data block into the AES state memory.
5. Start the encryption/decryption operation.
If more than one block is to be encrypted or decrypted, repeat the procedure from step 3.


"Dare to be naïve." - Buckminster Fuller

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks. Earlier this evening I got the whole thing working. I did, indeed, go with three DMA channels - one for the key, one for the block going in, and the third for the block coming out. I managed to make it so that the first two actually run at the same time. Going from interrupt driven AES to DMA increased the throughput by around 20%, so I'm pretty happy.


P.s. I think what fixed the DMA issue was that I needed to clear the TRNIF flag on the channel. Not doing so seems like it was preventing the *next* transfer from triggering its own interrupt. Most interrupt sources clear the flag for you, but since the DMA doesn't have separate vectors for error or complete, they left the flags behind for you, but it's on you to explicitly acknowledge them yourself.

Last Edited: Sat. Apr 29, 2017 - 08:26 AM