/*
 utils.c

 Copyright NTT MCL, 2000.

 Duncan S Wong   
 Security Group, NTT MCL
 July 2000
*/

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <gmp.h>
#include "epoc3.h"
#include "utils.h"

/*
Read public key info from a file
return 1 if succeed, otherwise 0
*/
int get_pubKey(EPOC3_PUB_KEY *publicKey, FILE *fp)
{
char one_line[2*MAX_MODULUS_LEN/8+15];
char field_id[10];
char field_body[2*MAX_MODULUS_LEN/8+2];
char **endptr = NULL;
unsigned char sign;
long digits;

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read n: %s\n", strerror(errno));
		return 0;
	}

	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	mpz_set_str(publicKey->n, field_body, 0);

	/*
	printf("get_pubKey: publicKey->n =\n");
	printf("%s\n", mpz_get_str(NULL, 16, publicKey->n));
	*/

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read g: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	mpz_set_str(publicKey->g, field_body, 0);

	/*
	printf("get_pubKey: publicKey->g =\n");
	printf("%s\n", mpz_get_str(NULL, 16, publicKey->g));
	*/

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read h: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	mpz_set_str(publicKey->h, field_body, 0);

	/*
	printf("get_pubKey: publicKey->h =\n");
	printf("%s\n", mpz_get_str(NULL, 16, publicKey->h));
	*/

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read Gid: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	publicKey->Gid = atoi(field_body);

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read Hid: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	publicKey->Hid = atoi(field_body);

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read pLen: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	publicKey->pLen = strtoul(field_body, endptr, 10);

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read hLen: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	publicKey->hLen = strtoul(field_body, endptr, 10);

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read gLen: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	publicKey->gLen = strtoul(field_body, endptr, 10);

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read RLen: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	publicKey->RLen = strtoul(field_body, endptr, 10);

	if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_pubKey cannot read rLen: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	publicKey->rLen = strtoul(field_body, endptr, 10);

	return 1;
}

/*
Read private key info from a file
return 1 if succeed, otherwise 0
*/
int get_privKey(EPOC3_PRIV_KEY *privateKey, FILE *fp)
{
char one_line[2*2*MAX_PRIME_LEN/8+15];
char field_id[10];
char field_body[2*2*MAX_PRIME_LEN/8+2];
char **endptr = NULL;
unsigned char sign;
long digits;

	if ( fgets(one_line, 2*2*MAX_PRIME_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_privkey cannot read p: %s\n", strerror(errno));
		return 0;
	}

	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	mpz_set_str(privateKey->p, field_body, 0);

	/*
	printf("get_privKey: privateKey->p =\n");
	printf("%s\n", mpz_get_str(NULL, 16, privateKey->p));
	*/

	if ( fgets(one_line, 2*2*MAX_PRIME_LEN/8+14, fp) == NULL ) {
		fprintf(stderr, "get_privKey cannot read g_p: %s\n", strerror(errno));
		return 0;
	}
	if ( !parse_field(one_line, field_id, field_body) ) return 0;
	mpz_set_str(privateKey->g_p, field_body, 0);

	/*
	printf("get_privKey: privateKey->g_p =\n");
	printf("%s\n", mpz_get_str(NULL, 16, privateKey->g_p));
	*/

	return 1;
}

/* read EPOC3 ciphertext info from a file */
int get_ciphertext(EPOC3_CIPHERTEXT *ciphertext, EPOC3_PUB_KEY *publicKey,
                   CIPHER_INFO *cipherInfo, FILE *fp)
{
char one_line[2*MAX_MODULUS_LEN/8+15];
char field_id[10];
char field_body[2*MAX_MODULUS_LEN/8+2];
char **endptr = NULL;
unsigned char sign;
long i;
   
   if ( fgets(one_line, 2*MAX_MODULUS_LEN/8+14, fp) == NULL ) {
      fprintf(stderr, "get_ciphertext cannot read c1: %s\n", strerror(errno));
      return 0;
   }

   if ( !parse_field(one_line, field_id, field_body) ) return 0;
   mpz_set_str(ciphertext->c1, field_body, 0);
   
	/*
   printf("get_ciphertext: ciphertext->c1 =\n");
   printf("%s\n", mpz_get_str(NULL, 16, ciphertext->c1));
	*/

   fread(ciphertext->c2, cipherInfo->mLen/8, 1, fp);
	/*
   printf("get_ciphertext: ciphertext->c2 =\n");
   for(i=0; i<cipherInfo->mLen/8; i++)
      printf("%02x ", ciphertext->c2[i]);
   printf("\n\n");
	*/
	ciphertext->cipherLen = cipherInfo->mLen/8;

   fread(ciphertext->c3, publicKey->hLen/8, 1, fp);

	/*
   printf("get_ciphertext: ciphertext->c3 =\n");
   for(i=0; i<publicKey->hLen/8; i++)
      printf("%02x ", ciphertext->c3[i]);
   printf("\n\n");
	*/

   return 1;
}


/* open filename for read, return NULL if problem */
FILE *open_input(const char *filename)
{
FILE *fp;
errno = 0;

	if(filename == NULL) filename = "\0";
	fp = fopen(filename,"r");
	if (fp == NULL)
		fprintf(stderr, "open_input(\"%s\") failed: %s\n",
		        filename, strerror(errno));

	return fp;
}

/* open filenmae for write, return NULL if problem */
FILE *open_output(const char *filename)
{
FILE *fp;
errno = 0;

	if(filename == NULL) filename = "\0";
   fp = fopen(filename,"w+");
   if (fp == NULL)
      fprintf(stderr, "open_output(\"%s\") failed: %s\n",
              filename, strerror(errno));

   return fp;
}

/* parse a line in the format "field_id = field_body" */
int parse_field(char *one_line, char *field_id, char *field_body)
{
const char SEPCHARS[] = " \n";
char *tmp1, *tmp2, *tmp3;

	tmp1 = strtok(one_line, SEPCHARS);
	tmp2 = strtok(NULL, " ");
	tmp3 = strtok(NULL, SEPCHARS);
	if(tmp1 == NULL || tmp2 == NULL || tmp3 == NULL) {
		fprintf(stderr, "parse_field finds unrecognized line structure: %s\n",
		        strerror(errno));
		return 0;
	}
	strcpy(field_id, tmp1);
	strcpy(field_body, tmp3);
	/*
	printf("parse_field: field_id = %s\n",field_id);
	printf("parse_field: field_body = %s\n",field_body);
	*/

	return 1;
}


/* convert xp to a sequence of bytes in big-endian called xp_raw */
void WORD2BYTE(BYTE *xp_raw, mp_srcptr xp, mp_size_t xsize)
{   
long i;
BYTE *tmp_p;

   tmp_p = xp_raw;
   for(i=xsize-1; i>=0; i--) {
      tmp_p[0] = xp[i] >> 24;
      tmp_p[1] = (xp[i] >> 16) & 0xff;
      tmp_p[2] = (xp[i] >> 8) & 0xff;
      tmp_p[3] = xp[i] & 0xff;
      tmp_p += 4;
   }
}


mp_size_t BYTE2WORD(mpz_ptr x, BYTE *raw, mp_size_t size)
{
long i;
BYTE *raw_ascii, *tmp_p;

   raw_ascii = (BYTE *) malloc (size*2+1);
   tmp_p = raw_ascii;

   for(i=0; i<size; i++) {
      sprintf(tmp_p,"%02x", raw[i]);
      tmp_p+=2;
   }
   /* printf("BYTE2WORD: raw_ascii =\n\t%s\n\n", raw_ascii); */

   mpz_set_str(x, raw_ascii, 16);

	memset(raw_ascii, 0, size*2+1);
	free(raw_ascii);

   return mpz_size(x);
}


/* one-time pad */
WORD Vernam(BYTE *K, WORD kLen, BYTE *in, BYTE *out)
{ 
unsigned char c;
WORD i;

   /* printf("Vernam: input =\n"); */
   i = 0;
   while(kLen>0) {
      out[i] = in[i] ^ K[i];
      /* printf("%02x ", in[i]); */
      kLen -= 8;
      i++;
   }
   /* printf("\n\n"); */

   return i;
}


/* copy len BYTEs from from to to */
void assignBYTE(BYTE *to, BYTE *from, WORD len)
{
WORD i;

   for(i=0; i<len; i++)
      to[i] = from[i];
}
