#include "spn.h"

#include <stdio.h>
#include <stdlib.h>

// Applique la permutation définie par perm à l'octet w
unsigned char do_perm(unsigned char w, unsigned char perm[8]) {
    unsigned char res = 0;
    for (int i = 0; i < 8; i++) {
        if (w & (1 << i)) {
            res |= (1 << perm[i]);
        }
    }
    return res;
}

// Applique la substitution définie par subst sur chaque moitié de w
unsigned char do_subst(unsigned char w, unsigned char subst[16]) {
    unsigned char left = (w >> 4) & 0x0F; // 4 bits de poids fort
    unsigned char right = w & 0x0F;       // 4 bits de poids faible
    return (subst[left] << 4) | subst[right];
}

// Chiffre un bloc de 8 bits avec une clé de 16 bits
unsigned char encrypt(
    unsigned char w,
    unsigned short key,
    unsigned char perm[8],
    unsigned char subst[16]
) {
    unsigned char subkey1 = (key >> 8) & 0xFF;
    unsigned char subkey2 = key & 0xFF;

    // Tour 1 : XOR avec la clé, substitution, permutation
    w ^= subkey1;
    w = do_subst(w, subst);
    w = do_perm(w, perm);

    // Tour 2 : XOR avec la clé, substitution, XOR avec la sous-clé finale
    w ^= subkey2;
    w = do_subst(w, subst);
    w ^= subkey1;

    return w;
}

// Déchiffre un bloc de 8 bits avec une clé de 16 bits
unsigned char decrypt(
    unsigned char w,
    unsigned short key,
    unsigned char perm[8],
    unsigned char subst[16]
) {
    unsigned char subkey1 = (key >> 8) & 0xFF;
    unsigned char subkey2 = key & 0xFF;

    // Table de substitution inverse
    unsigned char inv_subst[16];
    for (int i = 0; i < 16; i++) {
        inv_subst[subst[i]] = i;
    }

    // Tour inverse 2 : XOR avec la clé, substitution inverse, XOR avec la sous-clé
    w ^= subkey1;
    w = do_subst(w, inv_subst);
    w ^= subkey2;

    // Tour inverse 1 : permutation inverse, substitution inverse, XOR avec la clé
    unsigned char inv_perm[8];
    for (int i = 0; i < 8; i++) {
        inv_perm[perm[i]] = i;
    }
    w = do_perm(w, inv_perm);
    w = do_subst(w, inv_subst);
    w ^= subkey1;

    return w;
}

void read_key(const char *filename, unsigned short *key) {
    FILE *file = fopen(filename, "r");
    if (!file) {
        perror("Erreur ouverture fichier clé");
        exit(EXIT_FAILURE);
    }
    fscanf(file, "%hx", key); // Lire un entier hexadécimal (16 bits)
    fclose(file);
}

void read_subst(const char *filename, unsigned char subst[16]) {
    FILE *file = fopen(filename, "r");
    if (!file) {
        perror("Erreur ouverture fichier substitution");
        exit(EXIT_FAILURE);
    }
    for (int i = 0; i < 16; i++) {
        fscanf(file, "%hhu", &subst[i]); // Lire un entier 8 bits
    }
    fclose(file);
}

void read_perm(const char *filename, unsigned char perm[8]) {
    FILE *file = fopen(filename, "r");
    if (!file) {
        perror("Erreur ouverture fichier permutation");
        exit(EXIT_FAILURE);
    }
    for (int i = 0; i < 8; i++) {
        fscanf(file, "%hhu", &perm[i]); // Lire un entier 8 bits
    }
    fclose(file);
}