/* ---------------------------------------------------------------------------- * 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. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ // Function: Firmware encryption using TDES hardware acceleration //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Includes //------------------------------------------------------------------------------ #include "tdes_hardware.h" #if defined(USE_ENCRYPTION) && defined(ENCRYPTION_3DES_HARD) #include #include #include #include #include #include //------------------------------------------------------------------------------ // Global variables //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Inline functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// Converts an ASCII value to an hexadecimal one /// \param ASCII string /// \param Buffer to store integer value /// \param Length of string //------------------------------------------------------------------------------ static inline void ASCII2Hex(const unsigned char * ascii, unsigned char * binary, unsigned int length) { unsigned int i; for (i=0; i < length; i++) { if (ascii[i*2] >= 'A') { binary[i] = ascii[i*2] - 'A' + 10; } else { binary[i] = ascii[i*2] - '0'; } binary[i] <<= 4; if (ascii[i*2+1] >= 'A') { binary[i] += ascii[i*2+1] - 'A' + 10; } else { binary[i] += ascii[i*2+1] - '0'; } } } //------------------------------------------------------------------------------ // Functions //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// Initializes the TDES peripheral //------------------------------------------------------------------------------ #ifdef ONLY_ONE_ENCRYPTION void tdes_hard_init(void) { unsigned char key[ENCRYPTION_KEY_LENGTH]; TRACE_DEBUG("TDES/HARD: Initializing ...\n\r"); // Activate peripheral clock #ifdef AT91C_ID_AES PMC_EnablePeripheral( AT91C_ID_AES ); #elif AT91C_ID_AESTDES PMC_EnablePeripheral( AT91C_ID_AESTDES ); #elif AT91C_ID_TDES PMC_EnablePeripheral( AT91C_ID_TDES ); #else #error AES/TDES undefined #endif // Load mode #if (ENCRYPTION_KEY_LENGTH == 24) AT91C_BASE_TDES->TDES_MR = AT91C_TDES_SMOD_MANUAL | TDES_MODE | AT91C_TDES_TDESMOD | TDES_CIPHER; #else AT91C_BASE_TDES->TDES_MR = AT91C_TDES_SMOD_MANUAL | TDES_MODE | AT91C_TDES_KEYMOD | AT91C_TDES_TDESMOD | TDES_CIPHER; #endif // Convert and load key ASCII2Hex((unsigned char*)ENCRYPTION_KEY, key, ENCRYPTION_KEY_LENGTH); AT91C_BASE_TDES->TDES_KEY1WxR[0] = ((int *) key)[0]; AT91C_BASE_TDES->TDES_KEY1WxR[1] = ((int *) key)[1]; AT91C_BASE_TDES->TDES_KEY2WxR[0] = ((int *) key)[2]; AT91C_BASE_TDES->TDES_KEY2WxR[1] = ((int *) key)[3]; #if (ENCRYPTION_KEY_LENGTH == 24) AT91C_BASE_TDES->TDES_KEY3WxR[0] = ((int *) key)[4]; AT91C_BASE_TDES->TDES_KEY3WxR[1] = ((int *) key)[5]; #endif #if defined(ENCRYPTION_CBC) unsigned char IV[8]; ASCII2Hex((unsigned char*)ENCRYPTION_IV, IV, ENCRYPTION_BLOCK_LENGTH); AT91C_BASE_TDES->TDES_IVxR[0] = ((int *) IV)[0]; AT91C_BASE_TDES->TDES_IVxR[1] = ((int *) IV)[1]; #elif defined(ENCRYPTION_CTR) // Convert IV ASCII2Hex((unsigned char*)ENCRYPTION_IV, CTR, ENCRYPTION_BLOCK_LENGTH); #endif TRACE_DEBUG("TDES/HARD: Initialization done.\n\r"); } #endif //------------------------------------------------------------------------------ /// Initializes the DES peripheral for CBC mode //------------------------------------------------------------------------------ #ifndef ONLY_ONE_ENCRYPTION void tdes_hard_init_CBC(void) { unsigned char key[TDES_ENCRYPTION_KEY_LENGTH]; unsigned char IV[8]; TRACE_DEBUG("tdes_hard_init_CBC\n\r"); // Activate peripheral clock #ifdef AT91C_ID_AES PMC_EnablePeripheral( AT91C_ID_AES ); #elif AT91C_ID_AESTDES PMC_EnablePeripheral( AT91C_ID_AESTDES ); #elif AT91C_ID_TDES PMC_EnablePeripheral( AT91C_ID_TDES ); #else #error AES undefined #endif // Reset AT91C_BASE_TDES->TDES_CR = AT91C_TDES_SWRST; // Load mode #if (TDES_ENCRYPTION_KEY_LENGTH == 8) AT91C_BASE_TDES->TDES_MR = AT91C_TDES_SMOD_MANUAL // Manual Mode. | AT91C_TDES_OPMOD_CBC; // Cipher Block Chaining mode #elif (TDES_ENCRYPTION_KEY_LENGTH == 16) AT91C_BASE_TDES->TDES_MR = AT91C_TDES_SMOD_MANUAL // Manual Mode. | AT91C_TDES_OPMOD_CBC // Cipher Block Chaining mode | AT91C_TDES_KEYMOD // Two-key algorithm is selected. // There is no need to write TDES_KEY3WxR registers. | AT91C_TDES_TDESMOD; // Triple DES processing using TDES_KEY1WxR, TDES_KEY2WxR and TDES_KEY3WxR registers. #elif (TDES_ENCRYPTION_KEY_LENGTH == 24) AT91C_BASE_TDES->TDES_MR = AT91C_TDES_SMOD_MANUAL // Manual Mode. | AT91C_TDES_OPMOD_CBC // Cipher Block Chaining mode // Need to write TDES_KEY3WxR registers. | AT91C_TDES_TDESMOD; // Triple DES processing using TDES_KEY1WxR, TDES_KEY2WxR and TDES_KEY3WxR registers. #else #error TDES_ENCRYPTION_KEY_LENGTH #endif // Convert and load key ASCII2Hex((unsigned char*)TDES_ENCRYPTION_KEY, key, TDES_ENCRYPTION_KEY_LENGTH); AT91C_BASE_TDES->TDES_KEY1WxR[0] = ((int *) key)[0]; AT91C_BASE_TDES->TDES_KEY1WxR[1] = ((int *) key)[1]; AT91C_BASE_TDES->TDES_KEY2WxR[0] = ((int *) key)[2]; AT91C_BASE_TDES->TDES_KEY2WxR[1] = ((int *) key)[3]; #if (TDES_ENCRYPTION_KEY_LENGTH == 24) AT91C_BASE_TDES->TDES_KEY3WxR[0] = ((int *) key)[4]; AT91C_BASE_TDES->TDES_KEY3WxR[1] = ((int *) key)[5]; #endif ASCII2Hex((unsigned char*)ENCRYPTION_IV, IV, ENCRYPTION_BLOCK_LENGTH); AT91C_BASE_TDES->TDES_IVxR[0] = ((int *) IV)[0]; AT91C_BASE_TDES->TDES_IVxR[1] = ((int *) IV)[1]; } #endif //------------------------------------------------------------------------------ /// Initializes the DES peripheral for ECB mode //------------------------------------------------------------------------------ #ifndef ONLY_ONE_ENCRYPTION void tdes_hard_init_ECB(void) { unsigned char key[TDES_ENCRYPTION_KEY_LENGTH]; TRACE_DEBUG("tdes_hard_init_ECB\n\r"); // Activate peripheral clock #ifdef AT91C_ID_AES PMC_EnablePeripheral( AT91C_ID_AES ); #elif AT91C_ID_AESTDES PMC_EnablePeripheral( AT91C_ID_AESTDES ); #elif AT91C_ID_TDES PMC_EnablePeripheral( AT91C_ID_TDES ); #else #error AES undefined #endif // Load mode #if (TDES_ENCRYPTION_KEY_LENGTH == 8) AT91C_BASE_TDES->TDES_MR = AT91C_TDES_SMOD_MANUAL // Manual Mode. | AT91C_TDES_OPMOD_ECB; // ECB Electronic CodeBook mode #elif (TDES_ENCRYPTION_KEY_LENGTH == 16) AT91C_BASE_TDES->TDES_MR = AT91C_TDES_SMOD_MANUAL // Manual Mode. | AT91C_TDES_OPMOD_ECB // ECB Electronic CodeBook mode | AT91C_TDES_KEYMOD // Two-key algorithm is selected. // There is no need to write TDES_KEY3WxR registers. | AT91C_TDES_TDESMOD; // Triple DES processing using TDES_KEY1WxR, TDES_KEY2WxR and TDES_KEY3WxR registers. #elif (TDES_ENCRYPTION_KEY_LENGTH == 24) AT91C_BASE_TDES->TDES_MR = AT91C_TDES_SMOD_MANUAL // Manual Mode. | AT91C_TDES_OPMOD_ECB // ECB Electronic CodeBook mode // Need to write TDES_KEY3WxR registers. | AT91C_TDES_TDESMOD; // Triple DES processing using TDES_KEY1WxR, TDES_KEY2WxR and TDES_KEY3WxR registers. #else #error TDES_ENCRYPTION_KEY_LENGTH #endif // Convert and load key ASCII2Hex((unsigned char*)TDES_ENCRYPTION_KEY, key, TDES_ENCRYPTION_KEY_LENGTH); AT91C_BASE_TDES->TDES_KEY1WxR[0] = ((int *) key)[0]; AT91C_BASE_TDES->TDES_KEY1WxR[1] = ((int *) key)[1]; AT91C_BASE_TDES->TDES_KEY2WxR[0] = ((int *) key)[2]; AT91C_BASE_TDES->TDES_KEY2WxR[1] = ((int *) key)[3]; #if (TDES_ENCRYPTION_KEY_LENGTH == 24) AT91C_BASE_TDES->TDES_KEY3WxR[0] = ((int *) key)[4]; AT91C_BASE_TDES->TDES_KEY3WxR[1] = ((int *) key)[5]; #endif } #endif //------------------------------------------------------------------------------ /// Cleans up the DES peripheral //------------------------------------------------------------------------------ void tdes_hard_cleanup(void) { TRACE_DEBUG("TDES/HARD: Cleaning up ...\n\r"); AT91C_BASE_TDES->TDES_MR = 0; #ifdef AT91C_ID_AES PMC_DisablePeripheral( AT91C_ID_AES ); #elif AT91C_ID_AESTDES PMC_DisablePeripheral( AT91C_ID_AESTDES ); #elif AT91C_ID_TDES PMC_DisablePeripheral( AT91C_ID_TDES ); #else #error AES undefined #endif TRACE_DEBUG("TDES/HARD: Cleanup done.\n\r"); } //------------------------------------------------------------------------------ /// Decrypts a variable-length cipher text /// \param Cipher text to decrypt /// \param Buffer to store plain text /// \param Length of cipher text (in bytes) //------------------------------------------------------------------------------ #ifdef ONLY_ONE_ENCRYPTION int tdes_hard_decrypt(const unsigned char * cipherText, unsigned char * plainText, unsigned int length) { unsigned int l; TRACE_DEBUG("tdes_hard_decrypt\n\r"); #if defined(ENCRYPTION_ECB) || defined(ENCRYPTION_CBC) for (l=0; l < length;) { // Load counter and encrypt it AT91C_BASE_TDES->TDES_IDATAxR[0] = ((int *) &cipherText[l])[0]; AT91C_BASE_TDES->TDES_IDATAxR[1] = ((int *) &cipherText[l])[1]; // Start processing AT91C_BASE_TDES->TDES_CR = AT91C_TDES_START; while (!((AT91C_BASE_TDES->TDES_ISR) & AT91C_TDES_DATRDY)); ((int *) &plainText[l])[0] = AT91C_BASE_TDES->TDES_ODATAxR[0]; ((int *) &plainText[l])[1] = AT91C_BASE_TDES->TDES_ODATAxR[1]; l += ENCRYPTION_BLOCK_LENGTH; } #elif defined(ENCRYPTION_CTR) unsigned int bytes; unsigned char block[ENCRYPTION_BLOCK_LENGTH]; unsigned int e; unsigned int i; int k; // Decrypt for (e=0; e < length;) { // Load counter and encrypt it AT91C_BASE_TDES->TDES_IDATAxR[0] = ((int *) CTR)[0]; AT91C_BASE_TDES->TDES_IDATAxR[1] = ((int *) CTR)[1]; AT91C_BASE_TDES->TDES_CR = AT91C_TDES_START; while (!(AT91C_BASE_TDES->TDES_ISR & AT91C_TDES_DATRDY)); ((int *) block)[0] = AT91C_BASE_TDES->TDES_ODATAxR[0]; ((int *) block)[1] = AT91C_BASE_TDES->TDES_ODATAxR[1]; // XOR current plain text block with encrypted counter if ((length-e) < ENCRYPTION_BLOCK_LENGTH) { bytes = length - e; } else { bytes = ENCRYPTION_BLOCK_LENGTH; } for (i=0; i < bytes; i++) { plainText[e+i] = cipherText[e+i] ^ ((char *) block)[i]; } // Increment counter (big-endian) and number of encrypted bytes for (k=ENCRYPTION_BLOCK_LENGTH-1; k >= 0; k--) { if (++((char *) CTR)[k] != 0) { break; } } e += bytes; } #endif // ENCRYPTION_CTR return 1; } #endif //------------------------------------------------------------------------------ /// Decrypts a variable-length cipher text for CBC mode /// \param Cipher text to decrypt /// \param Buffer to store plain text /// \param Length of cipher text (in bytes) //------------------------------------------------------------------------------ #ifndef ONLY_ONE_ENCRYPTION int tdes_hard_decrypt_CBC(const unsigned char * cipherText, unsigned char * plainText, unsigned int length) { unsigned int l; TRACE_DEBUG("tdes_hard_decrypt_CBC\n\r"); for (l=0; l < length;) { // Load counter and encrypt it AT91C_BASE_TDES->TDES_IDATAxR[0] = ((int *) &cipherText[l])[0]; AT91C_BASE_TDES->TDES_IDATAxR[1] = ((int *) &cipherText[l])[1]; // Start processing AT91C_BASE_TDES->TDES_CR = AT91C_TDES_START; while (!((AT91C_BASE_TDES->TDES_ISR) & AT91C_TDES_DATRDY)); ((int *) &plainText[l])[0] = AT91C_BASE_TDES->TDES_ODATAxR[0]; ((int *) &plainText[l])[1] = AT91C_BASE_TDES->TDES_ODATAxR[1]; l += ENCRYPTION_BLOCK_LENGTH; } return 1; } #endif //------------------------------------------------------------------------------ /// Decrypts a variable-length cipher text for ECB mode /// \param Cipher text to decrypt /// \param Buffer to store plain text /// \param Length of cipher text (in bytes) //------------------------------------------------------------------------------ #ifndef ONLY_ONE_ENCRYPTION int tdes_hard_decrypt_ECB(const unsigned char * cipherText, unsigned char * plainText, unsigned int length) { unsigned int l; TRACE_DEBUG("tdes_hard_decrypt_ECB\n\r"); for (l=0; l < length;) { // Load counter and encrypt it AT91C_BASE_TDES->TDES_IDATAxR[0] = ((int *) &cipherText[l])[0]; AT91C_BASE_TDES->TDES_IDATAxR[1] = ((int *) &cipherText[l])[1]; // Start processing AT91C_BASE_TDES->TDES_CR = AT91C_TDES_START; while (!((AT91C_BASE_TDES->TDES_ISR) & AT91C_TDES_DATRDY)); ((int *) &plainText[l])[0] = AT91C_BASE_TDES->TDES_ODATAxR[0]; ((int *) &plainText[l])[1] = AT91C_BASE_TDES->TDES_ODATAxR[1]; l += ENCRYPTION_BLOCK_LENGTH; } return 1; } #endif #endif // defined(USE_ENCRYPTION) && defined(ENCRYPTION_3DES_HARD)