#include <conf.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <errno.h>
#include <utils.h>
#include <x_types.h>
#include "backup.h"

#ifndef XOR
#define XOR(a,b)	(((a) & ~(b)) | (~(a) & (b)))
#endif

#ifdef	USE_DES_ENCRYPTION

#include "des_aux.h"

static	UChar	*initstring = "Albi's encryption initialization string";

static	des_key_schedule	accesskeys[2];

Int32
set_cryptkey(UChar * filename)
{
  struct stat	statb;
  Int32		i, fd, ret = 0;
  Uns32		n, factor, prevval, newval;
  UChar		buf[100], *kptr, *endptr, *bufptr;
  des_cblock	rawkeys[2];

  buf[0] = '\0';

  if(filename){
    i = stat(filename, &statb);
    if(i)
      ret = ENOENT;
    else{
      fd = open(filename, O_RDONLY);
      if(fd < 0){
	ret = EACCES;
      }
      else{
	i = read(fd, buf, 99);
	close(fd);

	if(i < 0)
	  i = 0;
	buf[i] = '\0';
      }
    }
  }

  if(ret || !filename)
    strncpy(buf, ACCESSKEYSTRING, 99);
  if(!buf[0])
    memset(buf, 0x5a, 99);
  buf[99] = '\0';

  memset(rawkeys, 0x5a, 2 * sizeof(des_cblock));
  kptr = (UChar *) &(rawkeys[0]);
  endptr = kptr + 2 * sizeof(des_cblock);
  bufptr = buf + 1;

  prevval = buf[0] % 0x40;
  factor = 0x40;
  forever{
    if(! *bufptr)
	break;

    newval = prevval + factor * ((*bufptr) % 0x40);
    factor *= 0x40;

    if((newval & 0xff) == (prevval & 0xff) && factor >= 0x0100){
	*kptr = (prevval & 0xff);
	kptr++;
	if(kptr >= endptr)
	  break;

	factor /= 0x0100;
	newval /= 0x0100;
    }

    prevval = newval;
    bufptr++;
  }
  while(kptr < endptr && prevval){
    *(kptr++) = prevval & 0xff;
    prevval /= 0x0100;
  }

  if(des_set_key(rawkeys, accesskeys[0])
			|| des_set_key(rawkeys + 1, accesskeys[1]))
    ret = -1;

  return(ret);
}

Uns32
encrpt(UChar * buf)
{
  UChar		lbuf[20], mask, *cptr;
  des_cblock	ivec[2];
  Int32		i;

  cptr = (UChar *) ivec;
  mask = 0xdf;

  for(i = 0; i < sizeof(des_cblock) * 2; i++, cptr++){
    *cptr = XOR(mask, initstring[i]);
    mask = XOR(mask, initstring[i]);
  }

  des_3cbc_encrypt((des_cblock *) buf, (des_cblock *) lbuf,
			16 * sizeof(UChar),
			accesskeys[0], accesskeys[1], ivec, ivec + 1, 1);

  memcpy(buf, lbuf, 16 * sizeof(UChar));
}

#else	/* defined(USE_DES_ENCRYPTION) */

#define	PI_1_8		(M_PI / 8.0)
#define	PI_3_8		(M_PI / 8.0 * 3.0)
#define	S_PI_1_8	sin(PI_1_8)
#define	S_PI_3_8	sin(PI_3_8)

#define	LOG_8		log(8.0)
#define	LOG_12		log(12.0)

static Uns32	accesskey = ACCESSKEY;

Int32
set_cryptkey(UChar * filename)
{
  struct stat	statb;
  Int32		i, fd;
  Uns32		n;
  UChar		buf[10];

  if(!filename)
    return(0);

  i = stat(filename, &statb);
  if(i)
    return(ENOENT);

  fd = open(filename, O_RDONLY);
  if(fd < 0)
    return(EACCES);

  i = read(fd, buf, 5);
  close(fd);

  if(i < 5)
    return(EIO);

  n = 0;
  for(i = 0; i < 5; i++)
    n = (n * 96 + ((buf[i] & 0x7f) - 32)) & 0xffffffff;

  accesskey = n;

  return(0);
}

Uns32
encrpt(Uns32 in)
{
  Uns32	inp, a, b;

  inp = XOR(in, accesskey);

  a = inp >> 5;
  a &= (1 << 13) - 1;

  a = (Uns32) ((sin((double)a / 8192.0 * (PI_3_8 - PI_1_8) + PI_1_8)
			- S_PI_1_8) / (S_PI_3_8 - S_PI_1_8) * 8192.0);

  b = a;

  a = inp & ((1 << 5) - 1);
  a = a * a * a;

  a &= ((1 << 5) - 1);

  b |= a << 13;

  a = (inp >> 18);
  a &= (1 << 9) - 1;

  a = (Uns32) ((log((double)a / 512.0 * 4.0 + 8.0) - LOG_8)
			/ (LOG_12 - LOG_8) * 512.0);

  b |= a << 23;

  a = (inp >> 27);
  a &= (1 << 5) - 1;

  a = (Uns32) ((4.0 - sqrt((double)a / 32.0 * 7.0 + 9.0)) * 32.0);

  b |= a << 18;

  return(b);
}

#endif	/* ifelse defined(USE_DES_ENCRYPTION) */
