/* rijn2 permet de crypter un fichier zip en un fichier bin (code 'c', 'e')   */
/*              de décrypter un fichier bin en un fichier zip (code 'd')      */
/*    1er argument = code c, C (Crypter), e, E (Encrypt), d, D (Decrypter)    */
/*    2eme arg = fichier input                                                */
/*                (fichier output -> input auquel on aura changé l'extension) */
/*    3eme arg = clef                                                         */
/*    4eme (optionnel dans le cas du decryptage)                              */
/*             = iv                                                           */
/*      (si n'existe pas == 16 (ou 32 si hexa) premiers caractères du fichier */
#include "fullSpec.h"
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
#include <dos.h>
#include <dir.h>
#include <mem.h>

#include "alg-fst.c"
#include "api-fst.c"
#include "encdec.c"
#include "enckeys.c"
#include "encmac.c"
#include "hashcomp.c"
#include "maccomp.c"

#define IV_FILE_HEXA 0

static unsigned int BLOCK_CRYPT = 16 * 1024;

int handel_Read  = -1;
int handel_Write = -1;

BYTE *point;
BYTE errmsg[100];
BYTE pathlogerr[256];

BYTE *cipherData = NULL;

void Erreur(char *);
Rstr(char *chaine);

void Decrypt_File(char *, char *, BYTE *, BYTE *);
void Encrypt_File(char *, char *, BYTE *, BYTE *);
void Get_IV_From_File(char *, BYTE *, int);
void Hexa_To_Byte(char *, BYTE *);
int  Read_Param(int, char **, char *, char *, char *, char *);

/******************************/
int main(int argc, char **argv)
/******************************/
{
  char code[2];
  char filename_input[256];
  char filename_output[256];
  char KEY_HEXA[33];
  char IV_HEXA[33];
  BYTE key[17];
  BYTE iv[17];
  char drive[8];
  char dir[256];
  char file[16];
  char ext[8];
  FILE *fps;

  /* Debug */
  point = errmsg;

  /* Read_Param */
  memset(code, 0, sizeof(code));
  memset(filename_input, 0, sizeof(filename_input));
  memset(filename_output, 0, sizeof(filename_output));
  memset(KEY_HEXA, 0, sizeof(KEY_HEXA));
  memset(IV_HEXA, 0, sizeof(IV_HEXA));
  memset(key, 0, sizeof(key));
  memset(iv,  0, sizeof(iv));

  Read_Param(argc, argv, code, filename_input, KEY_HEXA, IV_HEXA);
  fnsplit(filename_input, drive, dir, file, ext);
  /* pathlogerr */
  fnmerge(pathlogerr, drive, dir, "log", ".err");
  unlink(pathlogerr);
  /* Creation du fichier log.err
     Si tout se passe bien, sera detruit */
  fps = fopen(pathlogerr,"a");
  fputs("Problem with rijn2\n",fps);
  fclose(fps);
/*
  printf("code: %s\n", code);
  printf("filename_input: %s\n", filename_input);
  printf("filename_output: %s\n", filename_output);
  printf("KEY_HEXA: %s\n", KEY_HEXA);
  printf("IV_HEXA: %s\n", IV_HEXA);
*/
  Hexa_To_Byte(KEY_HEXA, key);
  if(IV_HEXA[0]) Hexa_To_Byte(IV_HEXA, iv);

  switch(code[0])
  {
    case 'c':
    case 'C': /* 'C'rypt */
    case 'e': /* 'E'ncrypt */
    case 'E': /* fichier source .zip -> fichier crypté .bin */
      /* IV */
      if(!iv[0]) /* Get from file */
      {
        /*if(!IV_FILE_HEXA)*/
          Get_IV_From_File(filename_input, iv, 16);
        /*else
        {
          Get_IV_From_File(filename_input, IV_HEXA, 32);
          Hexa_To_Byte(IV_HEXA, iv);
        }*/
      }
      /* filename_output */
      fnmerge(filename_output, drive, dir, file, ".bin");
      Encrypt_File(filename_input, filename_output, key, iv);
      break;
    case 'd':
    case 'D': /* fichier crypté .bin -> fichier decrypté .zip */
      /* filename_output */
      /* filename_output */
      fnmerge(filename_output, drive, dir, file, ".zip");
      Decrypt_File(filename_input, filename_output, key, iv);
      break;
  }

  /* No problem delete log.err */
  unlink(pathlogerr);

 return(0);
}

/***********************/
void Erreur(char *msg)
/***********************/
{
  FILE *fps;
  fps = fopen(pathlogerr,"a");
  fputs(msg,fps);
  fclose(fps);

  /* Fermeture des fichiers succeptibles d'etre restes ouverts */
  if(handel_Read != -1)
    close(handel_Read);

  if(handel_Write != -1)
    close(handel_Write);

  exit(0);
}

/*****************************************************************************/
void Encrypt_File(char *_input, char *_output, BYTE *_key, BYTE *_iv)
/*****************************************************************************/
{
  unsigned long cipherDataLen,plainDataLen;
  register int Carry;
  keyInstance encKeyInst;       /* state of the decryption engine */
  cipherInstance encCipherInst; /* specifies the decryption mode */
  int stat;
  int last_block;
  unsigned int i, iCptSplit;
  unsigned long cipherDataLenOri;

  last_block = 0;

  stat = makeKeyBinary (&encKeyInst, DIR_ENCRYPT, _key);
  if(stat != 0)
  {
    sprintf(errmsg,"Fichier %s\n\tErreur makeKeyBinary\n",_input);
    Erreur(point);
  }
  stat = cipherInitBinary (&encCipherInst, _iv);
  if(stat != 0)
  {
    sprintf(errmsg,"Fichier %s\n\tErreur cipherInitBinary\n",_input);
    Erreur(point);
  }

  /* Lecture du fichier à crypter */
  handel_Read = open(_input, O_RDWR | O_BINARY,0x0100 | 0x0080);
  if(handel_Read == -1)
  {
    sprintf(errmsg,"Erreur d'ouverture du fichier %s\n",_input);
    Erreur(point);
  }
  cipherDataLen = /*(int)*/filelength(handel_Read);

  iCptSplit = 1;
  if(cipherDataLen > BLOCK_CRYPT)
  {
    cipherDataLenOri = cipherDataLen;
    iCptSplit += (int)(cipherDataLenOri / BLOCK_CRYPT);
    if(((unsigned long)iCptSplit-1)*(unsigned long)BLOCK_CRYPT == cipherDataLenOri)
    {
      BLOCK_CRYPT += 16;
      iCptSplit = 1 + (int)(cipherDataLenOri / BLOCK_CRYPT);
    }
  }

  /* _output */
  unlink(_output);
  handel_Write = open(_output,O_CREAT | O_APPEND | O_BINARY,0x0100 | 0x0080);
  if(handel_Write == -1)
  {
    sprintf(errmsg,"Erreur d'ouverture du fichier %s\n",_output);
    Erreur(point);
  }

  cipherData = malloc(BLOCK_CRYPT);
  for(i=0; i<iCptSplit; ++i)
  {
    if(iCptSplit > 1)
    {
      if(i != iCptSplit-1)
        cipherDataLen = BLOCK_CRYPT;
      else
        cipherDataLen = cipherDataLenOri - i * BLOCK_CRYPT;
    }
    cipherData[0] = 0x00;
    cipherDataLen = read(handel_Read,cipherData,cipherDataLen);
    if(cipherDataLen == -1)
    {
      sprintf(errmsg,"Erreur de lecture du fichier %s\n",_input);
      Erreur(point);
    }
    if(i==iCptSplit-1)
      last_block = 1;

    stat = encryptData(cipherData, &encCipherInst, &encKeyInst,
                       cipherData, cipherDataLen, last_block);

    if (stat < 0)
    {
      sprintf(errmsg,"encryption routine returns error code <%i>\n", stat);
      Erreur(point);
    }

    if(!last_block)
      Carry = write(handel_Write,cipherData,cipherDataLen);
    else
    {
      Carry = write(handel_Write,cipherData,stat);
      cipherDataLen = stat;
    }

    if(Carry != cipherDataLen)
    {
      sprintf(errmsg,"Erreur d'‚criture du fichier %s\n",_output);
      Erreur(point);
    }
  }
  free(cipherData);
  close(handel_Read); handel_Read = -1;
  close(handel_Write); handel_Write = -1;
}


/*****************************************************************************/
void Decrypt_File(char *_input, char *_output, BYTE *_key, BYTE *_iv)
/*****************************************************************************/
{
  unsigned long cipherDataLen,plainDataLen;
  register int Carry;
  keyInstance decKeyInst;       /* state of the decryption engine */
  cipherInstance decCipherInst; /* specifies the decryption mode */
  int stat;
  int last_block;
  unsigned int i, iCptSplit;
  unsigned long cipherDataLenOri;

  last_block = 0;

  stat = makeKeyBinary (&decKeyInst, DIR_DECRYPT, _key);
  if(stat != 0)
  {
    sprintf(errmsg,"Fichier %s\n\tErreur makeKeyBinary\n",_input);
    Erreur(point);
  }
  stat = cipherInitBinary (&decCipherInst, _iv);
  if(stat != 0)
  {
    sprintf(errmsg,"Fichier %s\n\tErreur cipherInitBinary\n",_input);
    Erreur(point);
  }

  /* Lecture du fichier à crypter */
  handel_Read = open(_input, O_RDWR | O_BINARY,0x0100 | 0x0080);
  if(handel_Read == -1)
  {
    sprintf(errmsg,"Erreur d'ouverture du fichier %s\n",_input);
    Erreur(point);
  }
  cipherDataLen = /*(int)*/filelength(handel_Read);

  iCptSplit = 1;
  if(cipherDataLen > BLOCK_CRYPT)
  {
    cipherDataLenOri = cipherDataLen;
    iCptSplit += (int)(cipherDataLenOri / BLOCK_CRYPT);
    if(((unsigned long)iCptSplit-1)*(unsigned long)BLOCK_CRYPT == cipherDataLenOri)
    {
      BLOCK_CRYPT += 16;
      iCptSplit = 1 + (int)(cipherDataLenOri / BLOCK_CRYPT);
    }
  }

  /* _output */
  unlink(_output);
  handel_Write = open(_output,O_CREAT | O_APPEND | O_BINARY,0x0100 | 0x0080);
  if(handel_Write == -1)
  {
    sprintf(errmsg,"Erreur d'ouverture du fichier %s\n",_output);
    Erreur(point);
  }

  cipherData = malloc(BLOCK_CRYPT);
  for(i=0; i<iCptSplit; ++i)
  {
    if(iCptSplit > 1)
    {
      if(i != iCptSplit-1)
        cipherDataLen = BLOCK_CRYPT;
      else
        cipherDataLen = cipherDataLenOri - i * BLOCK_CRYPT;
    }
    cipherData[0] = 0x00;
    cipherDataLen = read(handel_Read,cipherData,cipherDataLen);
    /*printf("cipherDataLen: %d\n", cipherDataLen);*/
    if(cipherDataLen == -1)
    {
      sprintf(errmsg,"Erreur de lecture du fichier %s\n",_input);
      Erreur(point);
    }

    if(i==iCptSplit-1)
      last_block = 1;

    stat = decryptData(cipherData, &decCipherInst, &decKeyInst,
                       cipherData, cipherDataLen, last_block);
    if(stat < 0)
    {
      sprintf(errmsg,"decryption routine returns error code <%i>\n", stat);
      Erreur(point);
    }
    if(last_block)
      cipherDataLen = stat;

    Carry = write(handel_Write,cipherData,cipherDataLen);

    if(Carry != cipherDataLen)
    {
      sprintf(errmsg,"Erreur d'‚criture du fichier %s\n",_output);
      Erreur(point);
    }
  }
  free(cipherData);
  close(handel_Read); handel_Read = -1;
  close(handel_Write); handel_Write = -1;
}

/***************************************/
int Read_Param(int _argc, char **_argv,
               char *_code,
               char *_filename,
               char *_KEY_HEXA,
               char *_IV_HEXA)
/***************************************/
{
  /* _code */
  if(_argc >= 2) strcpy(_code, _argv[1]);
  /* _filename_to_encrypt */
  if(_argc >= 3) strcpy(_filename, _argv[2]);
  /* _KEY_HEXA */
  if(_argc >= 4) strcpy(_KEY_HEXA, _argv[3]);
  /* _IV_HEXA */
  if(_argc >= 5) strcpy(_IV_HEXA, _argv[4]);
}

/*****************************************************************************/
void Hexa_To_Byte(char *_in, BYTE *_out)
/*****************************************************************************/
{
  BYTE Bffer[100],C1,C2;
  int i,j,n,Carry;

  strcpy(Bffer,_in);

  for ( i = 0 ; i <  64 ; i++)
  {
    if(Bffer[i] < 58) Bffer[i] -= 48;
    else              Bffer[i] -= 55;
  }

  for(i = 0, j = 0; j < 32 / 2; j++)
  {
    _out[j]   = Bffer[i++] << 4;
    _out[j]   = Bffer[i++] | _out[j];
  }
  _out[j] = 0x00;
}

/*****************************************************************************/
void Get_IV_From_File(char *_filename, BYTE *_iv, int _iNbc)
/*****************************************************************************/
{
  int fin, fout;
  BYTE *Bffer = NULL;
  unsigned long Bfferlen;

  /* get iv */
  if((fin = open(_filename, O_RDWR | O_BINARY,0x0100 | 0x0080)) == -1)
  {
    sprintf(errmsg,"error opening %s",_filename);
    Erreur(point);
  }
  Bfferlen = filelength(fin);
  /*printf("Bfferlen: %ld\n", Bfferlen);*/
  Bffer = malloc(Bfferlen);
  read(fin,Bffer,Bfferlen);
  close(fin);

  /* Remove Iv from file */
  unlink(_filename);
  if((fout = open(_filename, O_CREAT | O_RDWR | O_BINARY,0x0100 | 0x0080)) == -1)
  {
    sprintf(errmsg,"error opening %s",_filename);
    Erreur(point);
  }
  write(fout,Bffer+_iNbc,Bfferlen-_iNbc);
  close(fout);

  /* iv */
  memcpy(_iv, Bffer, _iNbc);
}
