u8 GetHiddenVolumeKeyFromUserpassword (u8 * Userpassword_pu8, u8 * DecryptedHiddenVolumeKey_au8)
{
u8 ret_u8;

    // Expand user password to 256 bit size

    CI_LocalPrintf ("User password               : "******"\r\n");

    ret_u8 = GetHiddenVolumeDataKeyFromUserpassword (Userpassword_pu8, DecryptedHiddenVolumeKey_au8);
    if (HIDDEN_VOLUME_OUTPUT_STATUS_OK != ret_u8)
    {
        return (ret_u8);
    }

    CI_LocalPrintf ("Uncrypted hidden volume key  : ");
    HexPrint (AES_KEYSIZE_256_BIT, DecryptedHiddenVolumeKey_au8);
    CI_LocalPrintf ("\r\n");

    // Clear the critical memory
    memset (Userpassword_pu8, 0, strlen ((char *) Userpassword_pu8));

    return (ret_u8);
}
u8 GetHiddenVolumeSlotKey (u8 * HiddenVolumeKey_pu8, u8 * Password_pu8, u32 PasswordLen_u32, u8 * Salt_pu8, u32 SaltLen_u32)
{
u8 output_au8[64];

#ifdef LOCAL_DEBUG
    CI_LocalPrintf ("Password_pu8 : Len %2d -%s-\r\n", PasswordLen_u32, Password_pu8);
    CI_LocalPrintf ("Salt         : ");
    HexPrint (SaltLen_u32, Salt_pu8);
    CI_LocalPrintf ("\r\n");
#endif

#ifndef SAVE_FLASH_MEMORY_NO_PBKDF2
    pbkdf2 (output_au8, Password_pu8, PasswordLen_u32, Salt_pu8, SaltLen_u32);
    memcpy (HiddenVolumeKey_pu8, output_au8, AES_KEYSIZE_256_BIT);  // copy 256 bit from the 512 bit output
#else
    CI_LocalPrintf ("*** WARNING low security for hidden volumes ***\r\n");
    // use the base key as the key
#endif


#ifdef LOCAL_DEBUG
    CI_LocalPrintf ("Key          : ");
    HexPrint (32, HiddenVolumeKey_pu8);
    CI_LocalPrintf ("\r\n");
#endif


    return (TRUE);
}
u8 HV_WriteSlot_u8 (u8 SlotNr_u8, HiddenVolumeKeySlot_tst * SlotData_st, u8 * SlotKey_pu8)
{
u32 i;
u8 Buffer_au8[HV_SLOT_SIZE];
    // u8 HiddenVolumeSlotsKey_au8[AES_KEYSIZE_256_BIT];

    if (FALSE == DecryptedHiddenVolumeSlotsActive_u8)
    {
        return (FALSE); // Slot data is not in ram
    }


    // Fill buffer with random numbers
    for (i = 0; i < HV_SLOT_SIZE; i++)
    {
        Buffer_au8[i] = rand () % 256;
    }

    // Set magic number
    // SlotData_st->MagicNumber_u32 = HV_MAGIC_NUMBER_SLOT_ENTRY;

    // Set CRC32
    SlotData_st->Crc_u32 = generateCRC_len ((u8 *) SlotData_st, (sizeof (HiddenVolumeKeySlot_tst) / 4) - 1);    // -1 for CRC variable

#ifdef DEBUG_KEYS
    CI_LocalPrintf ("HV_WriteSlot_u8 %d - CRC 0x%08x\r\n", SlotNr_u8, SlotData_st->Crc_u32);
    CI_LocalPrintf ("Decrypted data :\r\n");
    HexPrint (sizeof (HiddenVolumeKeySlot_tst), SlotData_st);
    CI_LocalPrintf ("\r\n");
#endif

    memcpy (Buffer_au8, (u8 *) SlotData_st, sizeof (HiddenVolumeKeySlot_tst));
    // Encrypt slot data
    AES_KeyEncryption (HV_SLOT_SIZE, Buffer_au8, SlotKey_pu8, AES_PMODE_CIPHER, SlotNr_u8);

    // Write encrypted slot data into ram
    memcpy ((u8 *) (DecryptedHiddenVolumeSlotsData_au8 + HV_SALT_SIZE + SlotNr_u8 * HV_SLOT_SIZE), Buffer_au8, HV_SLOT_SIZE);

#ifdef DEBUG_KEYS
    CI_LocalPrintf ("Encrypted data :\r\n");
    HexPrint (HV_SLOT_SIZE, &DecryptedHiddenVolumeSlotsData_au8[HV_SALT_SIZE + SlotNr_u8 * HV_SLOT_SIZE]);
    CI_LocalPrintf ("\r\n");
#endif

    // Encrypt all slots data (max 256 byte per encryption)
    AES_KeyEncryption (HV_SLOT_COUNT * HV_SLOT_SIZE, &DecryptedHiddenVolumeSlotsData_au8[HV_SALT_SIZE], DecryptedHiddenVolumeSlotsKey_au8,
                       AES_PMODE_CIPHER, SlotNr_u8);

    // Write ram data to flash
    flashc_memcpy ((u8 *) (HV_SALT_START_ADDRESS + HV_SALT_SIZE), &DecryptedHiddenVolumeSlotsData_au8[HV_SALT_SIZE], HV_SLOT_SIZE * HV_SLOT_COUNT,
                   TRUE);



    return (TRUE);
}
u8 HV_InitAllSlotData (void)
{
    // u8 RandomCharArray_au8[16];
u32 i;

    // Create salt
    for (i = 0; i < 2; i++)
    {
        // Get a random number from smart card
        if (FALSE == GetRandomNumber_u32 (16, &DecryptedHiddenVolumeSlotsData_au8[i * 16]))
        {
            CI_LocalPrintf ("GetRandomNumber fails\n\r");
            return (FALSE);
        }
    }


    // Fill hidden volume flash page with random chars
    for (i = 0; i < 16; i++)
    {
        // Get a random number from smart card
        if (FALSE == GetRandomNumber_u32 (16, &DecryptedHiddenVolumeSlotsData_au8[HV_SALT_SIZE + i * 16]))
        {
            CI_LocalPrintf ("GetRandomNumber fails\n\r");
            return (FALSE);
        }
    }

    // Write magic number to flash
    DecryptedHiddenVolumeMagicNumber_u32 = HV_MAGIC_NUMBER_INIT;
    flashc_memcpy ((u8 *) HV_MAGIC_NUMBER_ADDRESS, &DecryptedHiddenVolumeMagicNumber_u32, HV_MAGIC_NUMBER_SIZE, TRUE);

    // Write ram data to flash
    flashc_memcpy ((u8 *) HV_SALT_START_ADDRESS, DecryptedHiddenVolumeSlotsData_au8, HV_SALT_SIZE + HV_SLOT_SIZE * HV_SLOT_COUNT, TRUE);

    CI_LocalPrintf ("Init hidden volume slot data\r\n");

    CI_LocalPrintf ("Salt\r\n");
    CI_LocalPrintf ("Encrypted data :\r\n");
    HexPrint (HV_SALT_SIZE, DecryptedHiddenVolumeSlotsData_au8);
    CI_LocalPrintf ("\r\n\r\n");

    for (i = 0; i < HV_SLOT_COUNT; i++)
    {
        CI_LocalPrintf ("Slot %d\r\n", i);
        CI_LocalPrintf ("Encrypted data :\r\n");
        HexPrint (HV_SLOT_SIZE, DecryptedHiddenVolumeSlotsData_au8 + HV_SALT_SIZE + i * HV_SLOT_SIZE);
        CI_LocalPrintf ("\r\n\r\n");
    }

    return (TRUE);
}
u8 InitRamdomBaseForHiddenKey (void)
{
u8 BaseKey_au8[AES_KEYSIZE_256_BIT];

    LA_SC_StartSmartcard ();

    CI_TickLocalPrintf ("InitRamdomBaseForHiddenKey\r\n");

    // Get a random number for the base key
    if (FALSE == GetRandomNumber_u32 (AES_KEYSIZE_256_BIT / 2, BaseKey_au8))
    {
        CI_LocalPrintf ("GetRandomNumber fails\n\r");
        return (FALSE);
    }

    // Get a random number for the storage key
    if (FALSE == GetRandomNumber_u32 (AES_KEYSIZE_256_BIT / 2, &BaseKey_au8[AES_KEYSIZE_256_BIT / 2]))
    {
        CI_LocalPrintf ("GetRandomNumber fails\n\r");
        return (FALSE);
    }

    CI_LocalPrintf ("Base key       : ");
    HexPrint (AES_KEYSIZE_256_BIT, BaseKey_au8);
    CI_LocalPrintf ("\r\n");

    // Save base key
    WriteHiddenVolumeSlotKey (BaseKey_au8);

    // Invalidate hidden volume data
    DecryptedHiddenVolumeSlotsActive_u8 = FALSE;

    return (TRUE);
}
u8 GetHiddenVolumeDataKeyFromUserpassword (u8 * Userpassword_pu8, u8 * DecryptedHiddenVolumeKey_pu8)
{
u32 i;
u8 HiddenVolumeSlotKey_u8[AES_KEYSIZE_256_BIT];
HiddenVolumeKeySlot_tst SlotData_st;

    // Are the hidden volume slots decrypted ?
    if (TRUE != DecryptedHiddenVolumeSlotsActive_u8)
    {
        CI_LocalPrintf ("Slot data not encrypted\r\n");
        return (HIDDEN_VOLUME_OUTPUT_STATUS_NO_USER_PASSWORD_UNLOCK);   // No
    }

    GetHiddenVolumeSlotKey (HiddenVolumeSlotKey_u8, Userpassword_pu8, strlen ((char *) Userpassword_pu8), DecryptedHiddenVolumeSlotsData_au8,
                            HV_SALT_SIZE);

    CI_LocalPrintf ("Hidden volume slot key : ");
    HexPrint (AES_KEYSIZE_256_BIT, HiddenVolumeSlotKey_u8);
    CI_LocalPrintf ("\r\n");

    // Test HiddenVolumeKey for each slot
    for (i = 0; i < HV_SLOT_COUNT; i++)
    {
        if (TRUE == HV_ReadSlot_u8 (i, &SlotData_st, HiddenVolumeSlotKey_u8))
        {
            memcpy (DecryptedHiddenVolumeKey_pu8, SlotData_st.AesKey_au8, AES_KEYSIZE_256_BIT);

            SetHiddenVolumeSizes_u32 (SlotData_st.StartBlock_u32, SlotData_st.EndBlock_u32);

            CI_LocalPrintf ("Hidden volume key found - slot %d\r\n", i);
            CI_LocalPrintf ("Volume size %d MB\r\n", (SlotData_st.EndBlock_u32 - SlotData_st.StartBlock_u32) / 2048);
            CI_LocalPrintf ("StartBlock  %9d - %5d MB - %03d %%\r\n", SlotData_st.StartBlock_u32, SlotData_st.StartBlock_u32 / 2048,
                            (u32) ((u64) SlotData_st.StartBlock_u32 * (u64) 100 / (u64) gSdEndOfCard_u32));
            CI_LocalPrintf ("EndBlock    %9d - %5d MB - %03d %%\r\n", SlotData_st.EndBlock_u32, SlotData_st.EndBlock_u32 / 2048,
                            (u32) ((u64) (SlotData_st.EndBlock_u32 + 1) * (u64) 100 / (u64) gSdEndOfCard_u32));
            return (HIDDEN_VOLUME_OUTPUT_STATUS_OK);
        }
    }

    CI_LocalPrintf ("Can't find slot from password\r\n");
    return (HIDDEN_VOLUME_OUTPUT_STATUS_WRONG_PASSWORD);

    /*
       u32 i,n,i1; u8 pointer_u8; u8 Slot_u8;* // shake it a little bit pointer_u8 = 0; for (i=0;i<1000;i++) { srand (i +
       AESKey_pu8[pointer_u8]*119); for (i1=0;i1<n;i1++) { AESKey_pu8[pointer_u8] = (u8)((u16)AESKey_pu8[pointer_u8] + (u16)Userpassword_pu8[i1] +
       (u16)(rand () % 256)); pointer_u8 += (u8)((u16)AESKey_pu8[pointer_u8] + (u16)Userpassword_pu8[i1] + (u16)(rand () % 256)); pointer_u8 =
       pointer_u8 % AES_KEYSIZE_256_BIT; } }

     */

}
u8 HV_PrintSlotData_u8 (u8 SlotNr_u8, HiddenVolumeKeySlot_tst * SlotData_st)
{
#ifdef LOCAL_DEBUG
    CI_LocalPrintf ("Hidden volume slot %d\r\n", SlotNr_u8);
    // CI_LocalPrintf ("MagicNumber 0x%08x\r\n",SlotData_st->MagicNumber_u32);
    CI_LocalPrintf ("StartBlock  %9d - %5d MB - %03d %%\r\n", SlotData_st->StartBlock_u32, SlotData_st->StartBlock_u32 / 2048,
                    (u32) ((u64) SlotData_st->StartBlock_u32 * (u64) 100 / (u64) gSdEndOfCard_u32));
    CI_LocalPrintf ("EndBlock    %9d - %5d MB - %03d %%\r\n", SlotData_st->EndBlock_u32, SlotData_st->EndBlock_u32 / 2048,
                    (u32) ((u64) (SlotData_st->EndBlock_u32 + 1) * (u64) 100 / (u64) gSdEndOfCard_u32));
    CI_LocalPrintf ("AesKey      ");
    HexPrint (32, SlotData_st->AesKey_au8);
    CI_LocalPrintf ("\r\n");
    CI_LocalPrintf ("Crc_u32     0x%08x\r\n", SlotData_st->Crc_u32);
#endif

    return (TRUE);
}
void IBN_DFU_Tests (unsigned char nParamsGet_u8,unsigned char CMD_u8,unsigned int Param_u32,unsigned char *String_pu8)
{
  u8 DFU_String_au8[4];

  if (0 == nParamsGet_u8)
  {
    CI_LocalPrintf ("DFU test functions\r\n");
    CI_LocalPrintf ("\r\n");
    CI_LocalPrintf ("0   Show ISP Config 1 word\r\n");
    CI_LocalPrintf ("1   Enable DFU at next start\r\n");
    CI_LocalPrintf ("2   Disable DFU at next start\r\n");
    CI_LocalPrintf ("3   Show security bit\r\n");
    CI_LocalPrintf ("4   Set security bit\r\n");
    CI_LocalPrintf ("5   Show bootloader protected size\r\n");
    CI_LocalPrintf ("6   Set bootloader protected size = 0x2000\r\n");
    CI_LocalPrintf ("7   Reset system\r\n");
    CI_LocalPrintf ("\r\n");
    return;
  }

  switch (CMD_u8)
  {
    case 0:
      memcpy (DFU_String_au8,(void*)TOOL_DFU_ISP_CONFIG_ADDR_1,4);
      CI_LocalPrintf ("ISP Config 1 word : ");
      HexPrint (4,DFU_String_au8);
      CI_LocalPrintf ("\r\n");
      break;

    case 1 :
      CI_LocalPrintf ("Enable DFU\r\n");
      DFU_EnableFirmwareUpdate ();
      break;

    case 2 :
      CI_LocalPrintf ("Disable DFU\r\n");
      DFU_DisableFirmwareUpdate ();
      break;

    case 3 :
      CI_LocalPrintf ("Security bit : %d\r\n",flashc_is_security_bit_active ());
      break;

    case 4 :
      CI_LocalPrintf ("Activate security bit\r\n");
      flashc_activate_security_bit ();
      break;

    case 5 :
      CI_LocalPrintf ("Bootloader protected : 0x%04x\r\n",flashc_get_bootloader_protected_size ());
      break;

    case 6 :
      CI_LocalPrintf ("Set bootloader protected 0x2000\r\n");
      flashc_set_bootloader_protected_size (0x2000);
      break;

    case 7 :
      DFU_ResetCPU ();
      break;

  }
}
u8 PWS_EraseSlot (u8 Slot_u8)
{
u8* WritePointer_pu8;

u8* AesKeyPointer_pu8;

void* p;

#if (defined __GNUC__) && (defined __AVR32__)
    __attribute__ ((__aligned__ (4)))
#elif (defined __ICCAVR32__)
#pragma data_alignment = 4
#endif
typePasswordSafeSlot_st Slot_st;

    CI_LocalPrintf ("PWS_EraseSlot: Slot %d\r\n", Slot_u8);

    if (PWS_SLOT_COUNT <= Slot_u8)
    {
        CI_LocalPrintf ("PWS_EraseSlot: Wrong slot nr %d\r\n", Slot_u8);
        return (FALSE);
    }

    // Check for unlock
    if (FALSE == PWS_GetDecryptedPasswordSafeKey (&AesKeyPointer_pu8))
    {
        CI_LocalPrintf ("PWS_EraseSlot: user password not entered\r\n");
        return (FALSE);
    }

    // //LED_GreenOn ();

    // Clear data in slot
    memset ((char *) &Slot_st, 0, PWS_SLOT_LENGTH);
    Slot_st.SlotActiv_u8 = PWS_SLOT_INACTIV_TOKEN;

#ifdef ENABLE_IBN_PWS_TESTS_ENCRYPTION
    CI_LocalPrintf ("PWS_EraseSlot decrypted  : ");
    HexPrint (PWS_SLOT_LENGTH, &Slot_st);
    CI_LocalPrintf ("\n\r");
#endif

    // Encrypt data (max 256 byte per encryption)
unsigned char Slot_st_encrypted[PWS_SLOT_LENGTH];

aes_context aes_ctx;

    aes_setkey_enc (&aes_ctx, AesKeyPointer_pu8, 256);
int i;

    for (i = 0; i < PWS_SLOT_LENGTH; i += 16)
    {
        aes_crypt_ecb (&aes_ctx, AES_ENCRYPT, &(((unsigned char *) (&Slot_st))[i]), &(Slot_st_encrypted[i]));
    }

    memcpy ((char *) &Slot_st, Slot_st_encrypted, PWS_SLOT_LENGTH);

#ifdef ENABLE_IBN_PWS_TESTS_ENCRYPTION
    CI_LocalPrintf ("PWS_EraseSlot encrypted  : ");
    HexPrint (PWS_SLOT_LENGTH, Slot_st_encrypted);
    CI_LocalPrintf ("\n\r");
#endif

    // Get write address
    WritePointer_pu8 = (u8 *) (PWS_FLASH_START_ADDRESS + (PWS_SLOT_LENGTH * Slot_u8));

    // Write to flash
uint8_t page_buffer[FLASH_PAGE_SIZE];

uint8_t* page = (uint8_t *) PWS_FLASH_START_ADDRESS;

    memcpy (page_buffer, page, FLASH_PAGE_SIZE);
    memcpy (page_buffer + (PWS_SLOT_LENGTH * Slot_u8), Slot_st_encrypted, PWS_SLOT_LENGTH);

    p = (void *) Slot_st_encrypted;
    FLASH_Unlock ();
    FLASH_ErasePage (PWS_FLASH_START_ADDRESS);
    write_data_to_flash (page_buffer, FLASH_PAGE_SIZE, PWS_FLASH_START_ADDRESS);
    FLASH_Lock ();

    // LED_GreenOff ();
    return (TRUE);
}
u8 PWS_WriteSlot (u8 Slot_u8, typePasswordSafeSlot_st * Slot_st)
{
u8* WritePointer_pu8;

u8* AesKeyPointer_pu8;

void* p;

    CI_LocalPrintf
        ("PWS_WriteSlot: Slot %d. Name -%s- Loginname -%s- PW -%s-\r\n",
         Slot_u8, Slot_st->SlotName_au8, Slot_st->SlotLoginName_au8, Slot_st->SlotPassword_au8);

    if (PWS_SLOT_COUNT <= Slot_u8)
    {
        CI_LocalPrintf ("PWS_WriteSlot: Wrong slot nr %d\r\n", Slot_u8);
        return (FALSE);
    }

    if (FALSE == PWS_GetDecryptedPasswordSafeKey (&AesKeyPointer_pu8))
    {
        CI_LocalPrintf ("PWS_WriteSlot: Key not decrypted\r\n");
        return (FALSE);
    }

    // LED_GreenOn ();

    // Activate data in slot
    Slot_st->SlotActiv_u8 = PWS_SLOT_ACTIV_TOKEN;

#ifdef ENABLE_IBN_PWS_TESTS_ENCRYPTION
    CI_LocalPrintf ("PWS_WriteSlot decrypted  : ");
    HexPrint (PWS_SLOT_LENGTH, &Slot_st);
    CI_LocalPrintf ("\n\r");
#endif

    // Encrypt data (max 256 byte per encryption)
unsigned char Slot_st_encrypted[PWS_SLOT_LENGTH];

aes_context aes_ctx;

    aes_setkey_enc (&aes_ctx, AesKeyPointer_pu8, 256);
int i;

    for (i = 0; i < PWS_SLOT_LENGTH; i += 16)
    {
        aes_crypt_ecb (&aes_ctx, AES_ENCRYPT, &(((unsigned char *) (Slot_st))[i]), &(Slot_st_encrypted[i]));
    }

    memcpy (Slot_st, Slot_st_encrypted, PWS_SLOT_LENGTH);

#ifdef ENABLE_IBN_PWS_TESTS_ENCRYPTION
    CI_LocalPrintf ("PWS_WriteSlot encrypted  : ");
    HexPrint (PWS_SLOT_LENGTH, Slot_st_encrypted);
    CI_LocalPrintf ("\n\r");
#endif

    // Get write address
    WritePointer_pu8 = (u8 *) (PWS_FLASH_START_ADDRESS + (PWS_SLOT_LENGTH * Slot_u8));

    // Write to flash
uint8_t page_buffer[FLASH_PAGE_SIZE];

uint8_t* page = (uint8_t *) PWS_FLASH_START_ADDRESS;

    memcpy (page_buffer, page, FLASH_PAGE_SIZE);
    memcpy (page_buffer + (PWS_SLOT_LENGTH * Slot_u8), Slot_st_encrypted, PWS_SLOT_LENGTH);

    p = (void *) Slot_st_encrypted;
    FLASH_Unlock ();
    FLASH_ErasePage (PWS_FLASH_START_ADDRESS);
    write_data_to_flash (page_buffer, FLASH_PAGE_SIZE, PWS_FLASH_START_ADDRESS);
    FLASH_Lock ();

    // LED_GreenOff ();
    return (TRUE);
}
void IBN_OTP_Tests (unsigned char nParamsGet_u8, unsigned char CMD_u8, unsigned int Param_u32, unsigned char* String_pu8)
{
    u8 DFU_String_au8[4];
    u32 Ret_u32;
    u32 i;
#ifdef TIME_MEASURING_ENABLE
    u32 Runtime_u32;
#endif
    u8* Data_pu8;
    u8 slot_no;
    u8 is_programmed;
    u32 result;

    if (0 == nParamsGet_u8)
    {
        CI_LocalPrintf ("OTP test functions\r\n");
        CI_LocalPrintf ("\r\n");
        CI_LocalPrintf ("0   ??\r\n");
        CI_LocalPrintf ("1   Send char\r\n");
        CI_LocalPrintf ("2 x CRC32 Check x=String\r\n");
        CI_LocalPrintf ("3   Show hotp config [slot nr]\r\n");
        CI_LocalPrintf ("4   Get HOTP [slot]\r\n");
        CI_LocalPrintf ("5   Show HOTP counter page [slot]\r\n");
        CI_LocalPrintf ("6   Show TOTP config [slot nr]\r\n");
        CI_LocalPrintf ("7   Get TOTP time\r\n");
        CI_LocalPrintf ("8   Set TOTP time\r\n");
        CI_LocalPrintf ("\r\n");
        return;
    }

    switch (CMD_u8)
    {
        case 0:
            CI_LocalPrintf ("ISP Config 1 word : ");

            check_backups ();

            HexPrint (4, DFU_String_au8);
            CI_LocalPrintf ("\r\n");
            break;

        case 1:
            sendChar ('a');
            sendChar ('b');
            sendChar ('c');

            break;

        case 2:
            // String_pu8 = "123456789";
            CI_LocalPrintf ("CRC32 check : -%s- = ", String_pu8);
#ifdef TIME_MEASURING_ENABLE
            TIME_MEASURING_Start (TIME_MEASURING_TIME_15);
#endif
            CRC_InitCRC32 ();
            CRC_CalcBlockCRC32 (String_pu8, strlen ((char *) String_pu8));
            Ret_u32 = CRC_GetCRC32 ();
#ifdef TIME_MEASURING_ENABLE
            Runtime_u32 = TIME_MEASURING_Stop (TIME_MEASURING_TIME_15);
#endif
            CI_LocalPrintf ("0x%08x\r\n", Ret_u32);
#ifdef TIME_MEASURING_ENABLE
            CI_LocalPrintf ("CRC32 Runtime %ld usec\n\r", Runtime_u32 / TIME_MEASURING_TICKS_IN_USEC);
#endif
            break;

        case 3:    // Print hopt slot header
            /*
               slot structure: 1b 0x01 if slot is used (programmed) 15b slot name 20b secret 1b configuration flags: MSB [x|x|x|x|x|send token
               id|send enter after code?|no. of digits 6/8] LSB 12b token id 1b keyboard layout */
            Data_pu8 = get_hotp_slot_addr (Param_u32);
            if (NULL == Data_pu8)
            {
                CI_LocalPrintf ("Wrong hopt slot %d\n\r", Param_u32);
                return;
            }

            if (0x01 == Data_pu8[0])
            {
                CI_LocalPrintf ("slot %d is used\n\r", Param_u32);
            }
            else
            {
                CI_LocalPrintf ("slot %d is not used\n\r", Param_u32);
            }

            CI_LocalPrintf ("slot name -%.15.15s-\n\r", &Data_pu8[1]);
            CI_LocalPrintf ("        : ");
            HexPrint (15, &Data_pu8[1]);
            CI_LocalPrintf ("\n\r");


            CI_LocalPrintf ("Secret  : ");
            HexPrint (20, &Data_pu8[16]);
            CI_LocalPrintf ("\n\r");

            CI_LocalPrintf ("Config  : ");
            HexPrint (1, &Data_pu8[36]);
            CI_LocalPrintf ("\n\r");

            CI_LocalPrintf ("Token   : ");
            HexPrint (12, &Data_pu8[37]);
            CI_LocalPrintf ("\n\r");

            CI_LocalPrintf ("Keyboard: ");
            HexPrint (1, &Data_pu8[39]);
            CI_LocalPrintf ("\n\r");

            CI_LocalPrintf ("slot name -%.15.15s-\n\r", &Data_pu8[1]);

            break;

        case 4:    // Get hopt slot
            slot_no = Param_u32;
            if (slot_no < NUMBER_OF_HOTP_SLOTS) // HOTP slot
            {
                is_programmed = *((u8 *) (hotp_slots[slot_no]));
                if (is_programmed == 0x01)
                {
                    result = get_code_from_hotp_slot (slot_no);
                    change_endian_u32 (result);
                    CI_LocalPrintf ("HOPT %ld\n\r", result);
                }
                else
                {
                    CI_LocalPrintf ("Slot %d not programmed\n\r", slot_no);
                }
            }
            else
            {
                CI_LocalPrintf ("Slot %d not a hopt slot\n\r", slot_no);
            }
            break;

        case 5:    // Show hopt counter slot
            slot_no = Param_u32;
            if (slot_no < NUMBER_OF_HOTP_SLOTS) // HOTP slot
            {
                is_programmed = *((u8 *) (hotp_slots[slot_no]));

                Data_pu8 = (u8 *) hotp_slot_counters[slot_no];

                CI_LocalPrintf ("Slot %d\n\r", slot_no);
                CI_LocalPrintf ("Counter %lld\n\r", get_counter_value ((u32) Data_pu8));
                CI_LocalPrintf ("Addr 0x%08x - Page %d\n\r", Data_pu8, ((u32) Data_pu8 - FLASH_START) / FLASH_PAGE_SIZE);
                CI_LocalPrintf ("Programmed flag = %d (1 = true)\n\r", is_programmed);

                for (i = 0; i < 16; i++)
                {
                    CI_LocalPrintf ("0x%03x ", i * 32);
                    HexPrint (32, &Data_pu8[i * 32]);
                    CI_LocalPrintf ("\n\r");
                }
            }

            break;
        case 6:    // Print topt slot header
            /*
               slot structure: 1b 0x01 if slot is used (programmed) 15b slot name 20b secret 1b configuration flags: MSB [x|x|x|x|x|send token
               id|send enter after code?|no. of digits 6/8] LSB 12b token id 1b keyboard layout */
            Data_pu8 = get_totp_slot_addr (Param_u32);
            if (NULL == Data_pu8)
            {
                CI_LocalPrintf ("Wrong topt slot %d\n\r", Param_u32);
                return;
            }

            if (0x01 == Data_pu8[0])
            {
                CI_LocalPrintf ("slot %d is used\n\r", Param_u32);
            }
            else
            {
                CI_LocalPrintf ("slot %d is not used\n\r", Param_u32);
            }

            CI_LocalPrintf ("slot name -%.15.15s-\n\r", &Data_pu8[1]);
            CI_LocalPrintf ("        : ");
            HexPrint (15, &Data_pu8[1]);
            CI_LocalPrintf ("\n\r");


            CI_LocalPrintf ("Secret  : ");
            HexPrint (20, &Data_pu8[16]);
            CI_LocalPrintf ("\n\r");

            CI_LocalPrintf ("Config  : ");
            HexPrint (1, &Data_pu8[36]);
            CI_LocalPrintf ("\n\r");

            CI_LocalPrintf ("Token   : ");
            HexPrint (12, &Data_pu8[37]);
            CI_LocalPrintf ("\n\r");

            CI_LocalPrintf ("Keyboard: ");
            HexPrint (1, &Data_pu8[39]);
            CI_LocalPrintf ("\n\r");

            CI_LocalPrintf ("slot name -%.15.15s-\n\r", &Data_pu8[1]);
            break;

        case 7:    // Show topt time
            result = get_flash_time_value ();
            CI_LocalPrintf ("Flash time : 0x%08x - %ld\n\r", result, result);
            break;

        case 8:    // Set topt time
            CI_LocalPrintf ("Set flash time : to 0x%08x - %ld\n\r", 100, 100);
            set_time_value (100);
            result = get_flash_time_value ();
            CI_LocalPrintf ("Flash time : 0x%08x - %ld\n\r", result, result);
            break;


        case 11:
            // parse_report (NULL,NULL);
            break;


    }
}
void IBN_HV_Tests (unsigned char nParamsGet_u8, unsigned char CMD_u8, unsigned int Param_u32, unsigned char* String_pu8)
{
    HiddenVolumeKeySlot_tst SlotData_st;
    u8 HiddenVolumeSlotKey_u8[32];
    u8 DummyKey_au8[32];
    u8 i;

    if (0 == nParamsGet_u8)
    {
        CI_LocalPrintf ("Hidden volume test functions\r\n");
        CI_LocalPrintf ("\r\n");
        // CI_LocalPrintf ("0 nr Init slot [nr]\r\n");
        CI_LocalPrintf ("1 nr     Read slot [nr]\r\n");
        // CI_LocalPrintf ("2 Test key generation\r\n");
#ifdef TEST_PBKDF2
        CI_LocalPrintf ("3        PBKDF2 test\r\n");
#endif
        CI_LocalPrintf ("4        Get hidden volume slot key\r\n");
        CI_LocalPrintf ("5 [pw]   Get AES key. pw = password\r\n");
        CI_LocalPrintf ("6        Init hidden slots\r\n");
        CI_LocalPrintf ("7        Hidden slots status\r\n");
        CI_LocalPrintf ("8 nr pw  Write slot [nr] [password]\r\n");
        CI_LocalPrintf ("\r\n");
        return;
    }

    switch (CMD_u8)
    {
        case 0:
            break;

        case 1:
            CI_LocalPrintf ("Read slot : %d\r\n", Param_u32);

            if (FALSE == DecryptedHiddenVolumeSlotsActive_u8)
            {
                CI_LocalPrintf ("\r\nHidden slots key not decrypted\r\n");
                break;
            }
            if (NULL == String_pu8)
            {
                String_pu8 = "aaaa";
                CI_LocalPrintf ("No password set. Set it to -%s-\r\n", String_pu8);
            }
            CI_LocalPrintf ("Check for password : %s\r\n", String_pu8);


            CI_LocalPrintf ("Decrypted slots key : ");
            HexPrint (AES_KEYSIZE_256_BIT, DecryptedHiddenVolumeSlotsKey_au8);
            CI_LocalPrintf ("\r\n");

            GetHiddenVolumeSlotKey (HiddenVolumeSlotKey_u8, String_pu8, strlen ((char *) String_pu8), DecryptedHiddenVolumeSlotsData_au8,
                                    HV_SALT_SIZE);

            CI_LocalPrintf ("Hidden volume slot key : ");
            HexPrint (AES_KEYSIZE_256_BIT, HiddenVolumeSlotKey_u8);
            CI_LocalPrintf ("\r\n");

            HV_ReadSlot_u8 (Param_u32, &SlotData_st, (u8 *) HiddenVolumeSlotKey_u8);
            HV_PrintSlotData_u8 (Param_u32, &SlotData_st);
            break;

        case 2:
            break;
#ifdef TEST_PBKDF2
        case 3:
            pbkdf2_test ();
            break;
#endif
        case 4:
            DecryptedHiddenVolumeSlotsData ();
            break;

        case 5:
            CI_LocalPrintf ("Get key for password : %s\r\n", String_pu8);
            GetHiddenVolumeDataKeyFromUserpassword (String_pu8, DummyKey_au8);
            break;

        case 6:
            CI_LocalPrintf ("Init hidden slots\r\n");
            InitHiddenSlots ();
            break;

        case 7:
            CI_LocalPrintf ("Hidden slots status\r\n");
            if (NULL == String_pu8)
            {
                String_pu8 = "aaaa";
                CI_LocalPrintf ("No password set. Set it to -%s-\r\n", String_pu8);
            }
            CI_LocalPrintf ("Check for password : %s\r\n", String_pu8);

            if (FALSE == DecryptedHiddenVolumeSlotsActive_u8)
            {
                CI_LocalPrintf ("\r\nHidden slots key not decrypted\r\n");
                break;
            }


            CI_LocalPrintf ("Decrypted slots key : ");
            HexPrint (AES_KEYSIZE_256_BIT, DecryptedHiddenVolumeSlotsKey_au8);
            CI_LocalPrintf ("\r\n");

            GetHiddenVolumeSlotKey (HiddenVolumeSlotKey_u8, String_pu8, strlen ((char *) String_pu8), DecryptedHiddenVolumeSlotsData_au8,
                                    HV_SALT_SIZE);

            CI_LocalPrintf ("Hidden volume slot key : ");
            HexPrint (AES_KEYSIZE_256_BIT, HiddenVolumeSlotKey_u8);
            CI_LocalPrintf ("\r\n");

            for (i = 0; i < HV_SLOT_COUNT; i++)
            {
                CI_LocalPrintf ("Slot %d\r\n", i);
                if (TRUE == HV_ReadSlot_u8 (i, &SlotData_st, HiddenVolumeSlotKey_u8))
                {
                    HV_PrintSlotData_u8 (i, &SlotData_st);
                }
                else
                {
                    CI_LocalPrintf ("*** Invalid data ***\r\n");
                }
            }

            break;

        case 8:
            CI_LocalPrintf ("Write slots status\r\n");

            if (FALSE == DecryptedHiddenVolumeSlotsActive_u8)
            {
                CI_LocalPrintf ("\r\nHidden slots key not decrypted\r\n");
                break;
            }
            if (NULL == String_pu8)
            {
                String_pu8 = "aaaa";
                CI_LocalPrintf ("No password set. Set it to -%s-\r\n", String_pu8);
            }
            CI_LocalPrintf ("Check for password : %s\r\n", String_pu8);


            CI_LocalPrintf ("Decrypted slots key : ");
            HexPrint (AES_KEYSIZE_256_BIT, DecryptedHiddenVolumeSlotsKey_au8);
            CI_LocalPrintf ("\r\n");

            GetHiddenVolumeSlotKey (HiddenVolumeSlotKey_u8, String_pu8, strlen ((char *) String_pu8), DecryptedHiddenVolumeSlotsData_au8,
                                    HV_SALT_SIZE);

            CI_LocalPrintf ("Hidden volume slot key : ");
            HexPrint (AES_KEYSIZE_256_BIT, HiddenVolumeSlotKey_u8);
            CI_LocalPrintf ("\r\n");

            SlotData_st.StartBlock_u32 = 1000000;
            SlotData_st.EndBlock_u32 = 2000000;

            // Get a random number for the data key
            if (FALSE == GetRandomNumber_u32 (AES_KEYSIZE_256_BIT / 2, SlotData_st.AesKey_au8))
            {
                CI_LocalPrintf ("GetRandomNumber fails\n\r");
                return;
            }

            // Get a random number for the data key
            if (FALSE == GetRandomNumber_u32 (AES_KEYSIZE_256_BIT / 2, &SlotData_st.AesKey_au8[AES_KEYSIZE_256_BIT / 2]))
            {
                CI_LocalPrintf ("GetRandomNumber fails\n\r");
                return;
            }

            HV_WriteSlot_u8 (Param_u32, &SlotData_st, HiddenVolumeSlotKey_u8);

            break;

    }
}
u8 SetupUpHiddenVolumeSlot (HiddenVolumeSetup_tst * HV_Setup_st)
{
u8 HiddenVolumeSlotKey_u8[AES_KEYSIZE_256_BIT];
HiddenVolumeKeySlot_tst SlotData_st;

    HV_Setup_st->HiddenVolumePassword_au8[MAX_HIDDEN_VOLUME_PASSOWORD_SIZE] = 0;

    CI_LocalPrintf ("SetupUpHiddenVolumeSlot %d\r\n", HV_Setup_st->SlotNr_u8);
    CI_LocalPrintf ("Start block at %d %% of sd size\r\n", HV_Setup_st->StartBlockPercent_u8);
    CI_LocalPrintf ("End   block at %d %% of sd size\r\n", HV_Setup_st->EndBlockPercent_u8);
    CI_LocalPrintf ("Password : -%s-\r\n", HV_Setup_st->HiddenVolumePassword_au8);

    // Is the hidden volume system initialised ?
    if (FALSE == HV_CheckFlashPageIsInitiated ())
    {
        CI_LocalPrintf ("Hidden volume flash page isn't initiated\r\n");
        InitHiddenSlots ();
    }

    // Are the hidden volume slots decrypted ?
    if (TRUE != DecryptedHiddenVolumeSlotsActive_u8)
    {
        if (FALSE == DecryptedHiddenVolumeSlotsData ()) // Decrypt new keys
        {
            CI_LocalPrintf ("Slot data not encrypted - used smartcard user password\r\n");
            return (HIDDEN_VOLUME_OUTPUT_STATUS_NO_USER_PASSWORD_UNLOCK);
        }
    }

    if (HV_SLOT_COUNT <= HV_Setup_st->SlotNr_u8)
    {
        CI_LocalPrintf ("Wrong slot nr\r\n");
        return (HIDDEN_VOLUME_OUTPUT_STATUS_WRONG_PASSWORD);
    }

    CI_LocalPrintf ("Decrypted slots key : ");
    HexPrint (AES_KEYSIZE_256_BIT, DecryptedHiddenVolumeSlotsKey_au8);
    CI_LocalPrintf ("\r\n");

    // Get AES key for slot
    GetHiddenVolumeSlotKey (HiddenVolumeSlotKey_u8, HV_Setup_st->HiddenVolumePassword_au8, strlen ((char *) HV_Setup_st->HiddenVolumePassword_au8),
                            DecryptedHiddenVolumeSlotsData_au8, HV_SALT_SIZE);

    CI_LocalPrintf ("Hidden volume slot key : ");
    HexPrint (AES_KEYSIZE_256_BIT, HiddenVolumeSlotKey_u8);
    CI_LocalPrintf ("\r\n");

    SlotData_st.StartBlock_u32 = (u32) ((u64) gSdEndOfCard_u32 * (u64) HV_Setup_st->StartBlockPercent_u8 / (u64) 100) + 1;
    SlotData_st.EndBlock_u32 = (u32) ((u64) gSdEndOfCard_u32 * (u64) HV_Setup_st->EndBlockPercent_u8 / (u64) 100) - 1;

    // Get a random number for the data key
    if (FALSE == GetRandomNumber_u32 (AES_KEYSIZE_256_BIT / 2, SlotData_st.AesKey_au8))
    {
        CI_LocalPrintf ("GetRandomNumber fails\n\r");
        return (HIDDEN_VOLUME_OUTPUT_STATUS_SMARTCARD_ERROR);
    }

    // Get a random number for the data key
    if (FALSE == GetRandomNumber_u32 (AES_KEYSIZE_256_BIT / 2, &SlotData_st.AesKey_au8[AES_KEYSIZE_256_BIT / 2]))
    {
        CI_LocalPrintf ("GetRandomNumber fails\n\r");
        return (HIDDEN_VOLUME_OUTPUT_STATUS_SMARTCARD_ERROR);
    }

    HV_PrintSlotData_u8 (HV_Setup_st->SlotNr_u8, &SlotData_st);

    HV_WriteSlot_u8 (HV_Setup_st->SlotNr_u8, &SlotData_st, HiddenVolumeSlotKey_u8);

    return (HIDDEN_VOLUME_OUTPUT_STATUS_OK);
}
u8 HV_ReadSlot_u8 (u8 SlotNr_u8, HiddenVolumeKeySlot_tst * SlotData_st, u8 * SlotKey_pu8)
{
u32 Crc32_u32;
#if (defined __GNUC__) && (defined __AVR32__)
    __attribute__ ((__aligned__ (4)))
#elif (defined __ICCAVR32__)
#pragma data_alignment = 4
#endif
u8 Buffer_au8[HV_SLOT_SIZE];

    if (FALSE == DecryptedHiddenVolumeSlotsActive_u8)
    {
        return (FALSE); // Slot key is not in ram
    }

#ifdef DEBUG_KEYS
    CI_LocalPrintf ("HV_ReadSlot_u8 %d\r\n", SlotNr_u8);

    CI_LocalPrintf ("Slot key       :\r\n");
    HexPrint (32, SlotKey_pu8);
    CI_LocalPrintf ("\r\n");
#endif

    // Read all slots data from flash
    memcpy (&DecryptedHiddenVolumeSlotsData_au8[HV_SALT_SIZE], (u8 *) (HV_SALT_START_ADDRESS + HV_SALT_SIZE), HV_SLOT_SIZE * HV_SLOT_COUNT);
    // Decrypted data with slots key
    AES_KeyEncryption (HV_SLOT_COUNT * HV_SLOT_SIZE, &DecryptedHiddenVolumeSlotsData_au8[HV_SALT_SIZE], DecryptedHiddenVolumeSlotsKey_au8,
                       AES_PMODE_DECIPHER, SlotNr_u8);

#ifdef DEBUG_KEYS
    CI_LocalPrintf ("Encrypted data :\r\n");
    HexPrint (HV_SLOT_SIZE, DecryptedHiddenVolumeSlotsData_au8 + HV_SALT_SIZE + SlotNr_u8 * HV_SLOT_SIZE);
    CI_LocalPrintf ("\r\n");
#endif


    // Read encrypted slot data from ram
    memcpy ((u8 *) Buffer_au8, (u8 *) (DecryptedHiddenVolumeSlotsData_au8 + HV_SALT_SIZE + SlotNr_u8 * HV_SLOT_SIZE), HV_SLOT_SIZE);

    // Decrypt slot data
    AES_KeyEncryption (HV_SLOT_SIZE, (u8 *) Buffer_au8, SlotKey_pu8, AES_PMODE_DECIPHER, SlotNr_u8);

    memcpy ((u8 *) SlotData_st, Buffer_au8, sizeof (HiddenVolumeKeySlot_tst));

#ifdef DEBUG_KEYS
    CI_LocalPrintf ("Decrypted data :\r\n");
    HexPrint (sizeof (HiddenVolumeKeySlot_tst), SlotData_st);
    CI_LocalPrintf ("\r\n");
#endif

    /*
       // Check magic number if (HV_MAGIC_NUMBER_SLOT_ENTRY != SlotData_st->MagicNumber_u32) { return (FALSE); } */

    // Check CRC
    Crc32_u32 = generateCRC_len ((u8 *) SlotData_st, (sizeof (HiddenVolumeKeySlot_tst) / 4) - 1);
    if (Crc32_u32 != SlotData_st->Crc_u32)
    {
        return (FALSE);
    }

    return (TRUE);
}