/**
 *--------------------------------------------------------------------\n
 *          HSLU T&A Hochschule Luzern Technik+Architektur            \n
 *--------------------------------------------------------------------\n
 *
 * \brief         model solution for ASYD assignment crypto 01
 * \file
 * \author        Stefano Nicora, stefano.nicora@hslu.ch
 * \date          12.10.22
 *
 *--------------------------------------------------------------------
 */

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "XTEA-CBC.h"

void encrypt(uint32_t key[4], uint8_t numberOfCycles);
void decrypt(uint32_t key[4], uint8_t numberOfCycles);

/* source: https://en.wikipedia.org/wiki/XTEA */

/* filenames as of this code:
 * plaintext.txt => holds the message you want to encrypt
 * encrypted.cip => holds the encrypted message
 * decrypted.txt => holds the decrypted output from "encrypted.cip"
 */

void main(void) {
    uint32_t key[4] = { 1, 2, 3, 4};
    encrypt(key, 32);
    decrypt(key, 32);
}

void encrypt(uint32_t key[4], uint8_t numberOfCycles) {

    /* duplicate code that hasn't been moved to a separate function for readability reasons */
    /* -------------------------------------------------------------------- */

    /* variables */
    uint32_t amountOfCharsInFile = 0;
    /* https://www.programiz.com/c-programming/c-file-input-output */
    FILE* fileHandle = fopen("plaintext.txt", "r");
    if (fileHandle == NULL) {
        return;
    }

    /* get total number of characters in file to encrypt */
    while (getc(fileHandle) != EOF) {
        amountOfCharsInFile++;
    }

    /* allocate enough memory for the whole file to be read */
    char* inputText = (char*)calloc(amountOfCharsInFile + 8, sizeof(char)); /* add 8 for extra padding in case the file contains some sort of rest in regards to amountOfCharsInFile % 8 */
    if (inputText == NULL) {
        return;
    }

    /* close and reopen file to start at the beginning of the file again */
    fclose(fileHandle);
    fileHandle = fopen("plaintext.txt", "r");
    if (fileHandle == NULL) {
        return;
    }

    /* read the whole file into memory */
    for (uint32_t i = 0; i < amountOfCharsInFile; i++) {
        inputText[i] = getc(fileHandle);
    }
    fclose(fileHandle);
    /* -------------------------------------------------------------------- */

    /*  loop through the whole array to encrypt the whole message
        This happens two blocks of 32bit (= 8 characters) at a time
        Hence the increase of "i" by 8
    */
    for (uint32_t i = 0; i < amountOfCharsInFile; i += 8) { /* + 8 to compensate for the requested element size of the encipher function (32 bit) */
        /* dereferencing and forwarding the address of the key ensures, 
         * that we don't ready from a random address in memory. Rookie mistakes happen :) */
        encipher_CBC(numberOfCycles, &(inputText[i]), &(*key));
    }

    /* generate new file where encryption is stored */
    fileHandle = fopen("encrypted.cip", "w");
    if (fileHandle == NULL) {
        return;
    }
    /* fill new file with content */
    /* to get the extra character padding we might unintentionally drop
     * we need to read up to a multiple of 8 (32 bit)
     */
    for (uint32_t i = 0; i < (amountOfCharsInFile + (8-(amountOfCharsInFile%8))); i++) {
        putc(inputText[i], fileHandle);
    }
    fclose(fileHandle);
    free(inputText);
}

void decrypt(uint32_t key[4], uint8_t numberOfCycles) {

    /* duplicate code that hasn't been moved to a separate function for readability reasons */
    /* -------------------------------------------------------------------- */

    /* variables */
    uint32_t amountOfCharsInFile = 0;

    /* https://www.programiz.com/c-programming/c-file-input-output */
    FILE* fileHandle = fopen("encrypted.cip", "r");
    if (fileHandle == NULL) {
        return;
    }

    /* get total number of characters in file to decrypt */
    while (getc(fileHandle) != EOF) {
        amountOfCharsInFile++;
    }

    /* allocate memory for the whole file to be read */
    char* inputText = (char*)calloc(amountOfCharsInFile + 10, sizeof(char)); /* add 10 for extra padding */
    if (inputText == NULL) {
        return;
    }

    /* close and reopen file to start at the beginning of the file again */
    fclose(fileHandle);
    fileHandle = fopen("encrypted.cip", "r");
    if (fileHandle == NULL) {
        return;
    }

    /* read the whole file into memory */
    for (uint32_t i = 0; i < amountOfCharsInFile; i++) {
        inputText[i] = getc(fileHandle);
    }
    fclose(fileHandle);

    /* -------------------------------------------------------------------- */

    /*  loop through the whole array to encrypt the whole message
        This happens two blocks of 32bit (= 4 characters) at a time
        Hence the increase of "i" by 8
    */

    for (uint32_t i = 0; i < amountOfCharsInFile; i += 8) { /* i += 8*/
        /* dereferencing and forwarding the address of the key ensures,
         * that we don't ready from a random address in memory. Rookie mistakes happen :) */
        decipher_CBC(numberOfCycles, &(inputText[i]), &(*key));
    }

    /* generate new file where the decryption is stored */
    fileHandle = fopen("decrypted.txt", "w");
    if (fileHandle == NULL) {
        return;
    }
    /* fill new file with content */
    for (uint32_t i = 0; i < amountOfCharsInFile; i++) {
        putc(inputText[i], fileHandle);
    }
    fclose(fileHandle);
    free(inputText);
}