//------------------------------------------------------------------------------
// File:          libtomcrypt.h
// Function:      Firmware encryption using libTomCrypt
// Supported chip(s):
//    - AT91SAM7XC128
//    - AT91SAM7XC256
// Supported toolchain(s):
//    - IAR Embedded Workbench
// Date created:  05 June 2006
// Created by:    JJo
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include "libtomcrypt.h"

#if defined(USE_ENCRYPTION) && (defined(ENCRYPTION_AES_LTC) || defined(ENCRYPTION_3DES_LTC))

//------------------------------------------------------------------------------
// Global variables
//------------------------------------------------------------------------------

#if defined(ENCRYPTION_ECB)
  symmetric_ECB sECB;
#elif defined(ENCRYPTION_CBC)
  symmetric_CBC sCBC;
#elif defined(ENCRYPTION_CTR)
  symmetric_CTR sCTR;
#endif

//------------------------------------------------------------------------------
// Inline functions
//------------------------------------------------------------------------------

/**
 * Name:     ASCII2Hex
 * Purpose:  Converts an ASCII string to an hexadecimal value
 * Input(s):
 *  - ASCII string to convert
 *  - Buffer to store converted value
 *  - Length of buffer
 */
void ASCII2Hex(const char * ascii, unsigned char * hex, unsigned int length) {
  
  for (unsigned int i=0; i < length; i++, ascii++, hex++) {

    if (*ascii >= 'A') {

      *hex = *ascii - 'A' + 10;
    }
    else {

      *hex = *ascii - '0';
    }

    *hex <<= 4;
    ascii++;
  
    if (*ascii >= 'A') {

      *hex += *ascii - 'A' + 10;
    }
    else {

      *hex += *ascii - '0';
    }
  }
}

//------------------------------------------------------------------------------
// Functions
//------------------------------------------------------------------------------

/**
 * Name:      ltc_init
 * Purpose:   Initializes the decryption process
 */
void ltc_init(void) {

  // Local variables
  int cipherID;
  unsigned char key[ENCRYPTION_KEY_LENGTH];
#if defined(ENCRYPTION_CTR) || defined(ENCRYPTION_CBC)
  unsigned char IV[ENCRYPTION_BLOCK_LENGTH];
#endif

  debug_printf("LTC: Initializing ...\n");

  // Register cipher
  register_cipher(&CIPHER_DESC);
  cipherID = find_cipher(CIPHER_NAME);

  // Load key
  ASCII2Hex(ENCRYPTION_KEY, key, ENCRYPTION_KEY_LENGTH);
  
#if defined(ENCRYPTION_CTR) || defined(ENCRYPTION_CBC)
  // Load IV
  ASCII2Hex(ENCRYPTION_IV, IV, ENCRYPTION_BLOCK_LENGTH);
#endif

  // Start decryption mode
#if defined(ENCRYPTION_ECB)
  ecb_start(cipherID, key, ENCRYPTION_KEY_LENGTH, 0, &sECB);
#elif defined(ENCRYPTION_CBC)
  cbc_start(cipherID, IV, key, ENCRYPTION_KEY_LENGTH, 0, &sCBC);
#elif defined(ENCRYPTION_CTR)
  ctr_start(cipherID, IV, key, ENCRYPTION_KEY_LENGTH, 0, CTR_COUNTER_BIG_ENDIAN, &sCTR);
#endif

  debug_printf("LTC: Initialization done.\n");
}

/**
 * Name:      ltc_cleanup
 * Purpose:   Terminates the decryption process
 */
void ltc_cleanup(void) {

  debug_printf("LTC: Cleaning up ...\n");

#if defined(ENCRYPTION_ECB)
  ecb_done(&sECB);
#elif defined(ENCRYPTION_CBC)
  cbc_done(&sCBC);
#elif defined(ENCRYPTION_CTR)
  ctr_done(&sCTR);
#endif

  debug_printf("LTC: Cleanup done.\n");
}

/**
 * Name:      ltc_decrypt
 * Purpose:   Decrypts a block of data
 * Input(s):
 *  - Data to decrypt
 *  - Buffer to store decrypted data
 *  - Length of data
 * Output:    OK if successful, ERROR otherwise.
 */
int ltc_decrypt(const unsigned char * cipherText, unsigned char * plainText, unsigned int length) {

#if defined(ENCRYPTION_ECB)
  if (ecb_decrypt(cipherText, plainText, length, &sECB) != CRYPT_OK) {
#elif defined(ENCRYPTION_CBC)
  if (cbc_decrypt(cipherText, plainText, length, &sCBC) != CRYPT_OK) {
#elif defined(ENCRYPTION_CTR)
  if (ctr_decrypt(cipherText, plainText, length, &sCTR) != CRYPT_OK) {
#endif

    return ERROR;
  }
  else {

    return OK;
  }
}

#endif // defined(USE_ENCRYPTION) && (defined(ENCRYPTION_AES_LTC) || defined(ENCRYPTION_3DES_LTC))
