/* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2008, Atmel Corporation * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ #include "aes_p.h" #include #include #include //------------------------------------------------------------------------------ // Global functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// Configures the AES peripheral to encrypt/decrypt, start mode (manual, auto, /// PDC) and operating mode (ECB, CBC, OFB, CFB, CTR). /// \param cipher Indicates if the peripheral should encrypt or decrypt data. /// \param smode Start mode. /// \param opmode Operating mode. //------------------------------------------------------------------------------ void AES_Configure( unsigned char cipher, unsigned int smode, unsigned int opmode) { TRACE_DEBUG("AES_Configure()\n\r"); SANITY_CHECK((cipher & 0xFFFFFFFE) == 0); SANITY_CHECK((smode & 0xFFFFFCFF) == 0); SANITY_CHECK((opmode & 0xFFFF8FFF) == 0); // Reset the peripheral first AT91C_BASE_AES->AES_CR = AT91C_AES_SWRST; // Configure mode register AT91C_BASE_AES->AES_MR = cipher | smode | opmode; } //------------------------------------------------------------------------------ /// Sets the key used by the AES algorithm to cipher the plain text or /// decipher the encrypted text. /// \param pKey Pointer to a 16/24/32 bytes cipher key. //------------------------------------------------------------------------------ void AES_SetKey(const unsigned int *pKey, unsigned char keyLength) { TRACE_DEBUG("AES_SetKey()\n\r"); SANITY_CHECK(pKey); AT91C_BASE_AES->AES_KEYWxR[0] = pKey[0]; AT91C_BASE_AES->AES_KEYWxR[1] = pKey[1]; AT91C_BASE_AES->AES_KEYWxR[2] = pKey[2]; AT91C_BASE_AES->AES_KEYWxR[3] = pKey[3]; if( keyLength >= 24 ) { AT91C_BASE_AES->AES_KEYWxR[4] = pKey[4]; AT91C_BASE_AES->AES_KEYWxR[5] = pKey[5]; } if( keyLength == 32 ) { AT91C_BASE_AES->AES_KEYWxR[6] = pKey[6]; AT91C_BASE_AES->AES_KEYWxR[7] = pKey[7]; } } //------------------------------------------------------------------------------ /// Sets the initialization vector that is used to encrypt the plain text or /// decrypt the cipher text in chained block modes (CBC, CFB, OFB & CTR). /// \param pVector Pointer to a 16-bytes initialization vector. //------------------------------------------------------------------------------ void AES_SetVector(const unsigned int *pVector) { TRACE_DEBUG("AES_SetVector()\n\r"); SANITY_CHECK(pVector); AT91C_BASE_AES->AES_IVxR[0] = pVector[0]; AT91C_BASE_AES->AES_IVxR[1] = pVector[1]; AT91C_BASE_AES->AES_IVxR[2] = pVector[2]; AT91C_BASE_AES->AES_IVxR[3] = pVector[3]; } //------------------------------------------------------------------------------ /// Sets the input data of the AES algorithm (i.e. plain text in cipher mode, /// ciphered text in decipher mode). If auto mode is active, the encryption is /// started automatically after writing the last word. /// \param pData Pointer to the 16-bytes data to cipher/decipher. //------------------------------------------------------------------------------ void AES_SetInputData(const unsigned int *pData) { TRACE_DEBUG("AES_SetInputData()\n\r"); SANITY_CHECK(pData); AT91C_BASE_AES->AES_IDATAxR[0] = pData[0]; AT91C_BASE_AES->AES_IDATAxR[1] = pData[1]; AT91C_BASE_AES->AES_IDATAxR[2] = pData[2]; AT91C_BASE_AES->AES_IDATAxR[3] = pData[3]; } //------------------------------------------------------------------------------ /// Stores the result of the last AES operation (encrypt/decrypt) in the /// provided buffer. /// \param pData Pointer to a 16-bytes buffer. //------------------------------------------------------------------------------ void AES_GetOutputData(unsigned int *pData) { TRACE_DEBUG("AES_GetOutputData()\n\r"); SANITY_CHECK(pData); pData[0] = AT91C_BASE_AES->AES_ODATAxR[0]; pData[1] = AT91C_BASE_AES->AES_ODATAxR[1]; pData[2] = AT91C_BASE_AES->AES_ODATAxR[2]; pData[3] = AT91C_BASE_AES->AES_ODATAxR[3]; } //------------------------------------------------------------------------------ /// Sets the input buffer to use when in PDC mode. /// \param pInput Pointer to the input buffer. //------------------------------------------------------------------------------ void AES_SetInputBuffer(const unsigned int *pInput, unsigned char length) { TRACE_DEBUG("AES_SetInputBuffer()\n\r"); SANITY_CHECK(pInput); #ifdef AT91C_BASE_PDC_AES // Transmit Pointer Register AT91C_BASE_AES->AES_TPR = (unsigned int) pInput; // Transmit Counter Registers AT91C_BASE_AES->AES_TCR = length; #else //Start address AT91C_BASE_HDMA->HDMA_CH[0].HDMA_SADDR = (unsigned int)pInput; //Width and size AT91C_BASE_HDMA->HDMA_CH[0].HDMA_CTRLA = ( length | AT91C_HDMA_SCSIZE_1 | AT91C_HDMA_DCSIZE_4 | AT91C_HDMA_SRC_WIDTH_WORD | AT91C_HDMA_DST_WIDTH_WORD ); #endif } //------------------------------------------------------------------------------ /// Sets the output buffer to use when in PDC mode. /// \param pOutput Pointer to the output buffer. //------------------------------------------------------------------------------ void AES_SetOutputBuffer(unsigned int *pOutput, unsigned char length) { TRACE_DEBUG("AES_SetOutputBuffer()\n\r"); SANITY_CHECK(pOutput); #ifdef AT91C_BASE_PDC_AES // Receive Pointer Register AT91C_BASE_AES->AES_RPR = (unsigned int) pOutput; // Receive Counter Registers AT91C_BASE_AES->AES_RCR = length; #else //Destination address AT91C_BASE_HDMA->HDMA_CH[1].HDMA_DADDR = (unsigned int)pOutput; //Width and size AT91C_BASE_HDMA->HDMA_CH[1].HDMA_CTRLA = ( length | AT91C_HDMA_SCSIZE_4 | AT91C_HDMA_DCSIZE_1 | AT91C_HDMA_SRC_WIDTH_WORD | AT91C_HDMA_DST_WIDTH_WORD ); #endif } //------------------------------------------------------------------------------ /// Starts the encryption/decryption process when in manual or PDC mode. In /// manual mode, the key and input data must have been entered using /// AES_SetKey() and AES_SetInputData(). In PDC mode, the key, input & output /// buffer must have been set using AES_SetKey(), AES_SetInputBuffer() and /// AES_SetOutputBuffer(). //------------------------------------------------------------------------------ void AES_Start(void) { TRACE_DEBUG("AES_Start()\n\r"); SANITY_CHECK(((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_MANUAL) || ((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_PDC)); // Manual mode if ((AT91C_BASE_AES->AES_MR & AT91C_AES_SMOD) == AT91C_AES_SMOD_MANUAL) { AT91C_BASE_AES->AES_CR = AT91C_AES_START; } // PDC else { #ifdef AT91C_BASE_PDC_AES AT91C_BASE_AES->AES_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN; #else //Enable DMA chanels AT91C_BASE_HDMA->HDMA_CHER = (1<<0) | (1<<1); #endif } } //------------------------------------------------------------------------------ /// Returns the current value of the AES interrupt status register. //------------------------------------------------------------------------------ unsigned int AES_GetStatus(void) { return AT91C_BASE_AES->AES_ISR; }