/*
	SKS, by M.Pancorbo
	version 0.93 Changed math lib to "tomfastmath" who gives full-word alignment
				for the unit container (so, the number of bits/coefficients a unit
				has is actually 32 or 64 instead of 28 or 60). General improvement of
				'gflib' with noteworthy performance gain. Among others, Karatsuba's 
				techniques was introduced. Also, its code was a bit cleaned up.
	version 0.92c Corrected a bug when compiled in a 64-bit box.
	version 0.92b Corrected a bug when trying to encrypt small files. Now, gcc
				does not complain about rigourous warnings. 
				Conversion UTF-8 -> iso-8859-1 has been avoided in linux
	version 0.92 Changed 'get_entropy'. Now it will use the prng-file, even with
				DEVRANDOM. In this case, the content of prng-file is XOR-ed with
				the output of the random device before hashing. The prng-file is
				restored/created at the end of the process. With no DEVRANDOM,
				'get_entropy' makes the work as usual. LTM 'updated' to 0.35 
				and 'zlib' to 1.2.2
				Improved 'gfMultiply' and 'gfSquare' functions; also 'ecMultiply' is
				a bit improved by using Minimal Average Weight representations. 
				Gained a lot of performance!
	version 0.91 Changed point multiplication algorithm. Projective coordinates
				are introduced and pre-calculation of 16 first values. A bit
				of performance has been gained.
	version 0.90 Now, HMAC and encrypt keys are	different. Backward
				compatibility is guaranteed
	version 0.86 Added binary filtering by '-b' flag. Only for encryption
	version 0.85 Changed 'get_entropy' when it uses no DEVRANDOM. Now, the junk 
				post-buffer is saved in file and serves as initial junk buffer
				for further entropy requierements
	version 0.84 Now, fingerprint uses the less significant base-36 digits
	version 0.83 Improving of makefiles
	version 0.82 Stream decryption (-fd) accepts various blocks of encrypted
				text in the same stream. It applies the same input key to all of them.
				It only outputs the blocks with matching key after decryption.
	version 0.81 Source files rearranged
	version 0.80 Changed field to GF(2^191). Changed computation of key id.
				Added public key integrity check
	version 0.71 Added automatic UTF-8 -> iso-8859-1 conversion for
	            error output. Also added iso-8859-1 -> CP851 conv.
				for DOS/Windows
	version 0.70 Added 'salt' to passwords. Passwords are pasted over
	            a table containig first 2048 bits of PI; the remaining
				digits after pasting serve as 'salt'; the full buffer is
				hashed.
	version 0.60 AES and TIGER now builds their tables at "*_init()" first
				call. Longint numbers are now written in UTF-like fashion.
	version 0.50 Added 'TIGER' hash (instead of SHA256)
				P.K definition changes; old keys does not work
	version 0.40 Added compression (zlib) in a rough way (to be improved)
				Slight redefinition of interface
	version 0.30 First working application
	Public-Key cryptographic application
		PK-module: 	elliptic curve on GF(2^191), 95-bit strength (since version 0.80)
		Enc/dec:	symmetric key: k·Q / public msg.: k·P = k·(d·Q)
					k: random multiplier / Q: point curve / P: public key,
					d: priv. key
		Signature	DSA signature r-s: r = (k·Q)x, s = (k)·((m + d.r)^-1)
					Q: point curve / d: priv. key / m: MAC / k: random multiplier
		Hash:		TIGER, 192 bits (firstly, sha256)
		Sym. mod.:	CRT-aes128 -> C_i = P_i ^ AES128(K, IV + i);
		PRNG:		/dev/random, wincrypt or ANSI-RNG


	Copyright (C) 2004-2007  Manuel Pancorbo Castro

	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

	Manuel Pancorbo Castro <mpancorbo@gmail.com>
*/


#include "mycrypt.h"
#include "binasc.h"
#include "sks.h"

#if (SKS_LANG==ES)
#include "sks_msg_es.h"
#else
#include "sks_msg_en.h"
#endif

const char begin_armour [] = "###";
const char end_clearsign [] =
		"###-------------------------SKS SIG--------------------------###\n";
const char end_armour [] =
		"###-------------------------SKS CRYPT------------------------###\n\n";

extern keyring default_kr;
const unsigned long pubkey_mode_id = 0x9e37799b;	/** First 32 bits of golden ratio **/
const unsigned long symkey_mode_id = 0xc90fdaa2;	/** First 32 bits of PI **/


ERROR do_make_pubkey(FILE *in, PubKey copy)
{
/*  stores public key into keyring */
	PrivKey priv;
	ERROR err;
	int coincid = 0;
	
	char *pattern[2];
	keychain a;

	assert(in != NULL); 
	
	if(copy == NULL){
		get_text(in, a.lab, CHCONV(ask_label));
		if(in == stdin) strcat(a.lab, "\n");
	}
	
	while(1){
		if((err = get_privkey(in, priv, CHCONV(ask_passw)))) return err;
		if(!eccMakePublicKey(a.val, priv)){ break;}
		else {fputs(CHCONV(err_improper_privkey), stderr);}
	}
	zerokey(priv);
	
	if(copy == NULL){	/* Put in keyring (rightly in file) */
		/** Look for coincidences in actual keyring **/
		int i;
		for(i = 0; i < default_kr.N; ++i){
			if(!memcmp(a.val, default_kr.vector[i].val, KEY_SIZE)){
				coincid = 1;
				break;
			}
		}
		
		get_keyid(a.val, &(a.id));
		if(coincid){
			fprintf(stderr, CHCONV(msg_key_exists));
			fprintf(stderr, " [%08lx]: ", a.id); 
			fputs(default_kr.vector[i].lab, stderr);
			fputs("\n", stderr);
		}
  		else /*(coincid == 0)*/ {
			/** Add to keyring **/
			add_to_keyring(&default_kr, &a );
			/** Add to file **/
			write_keyring();
			pattern[1] = NULL;
			pattern[0] = &(a.lab[0]);
			search_pubkey(&default_kr, NULL, pattern, stdout, 'e');
		}
	}
	else memcpy(copy, a.val, KEY_SIZE);

	burn_stack(500);
	return 0;
}


ERROR do_signature(FILE *f_inp, FILE *f_out, FILE *f_key, char **pattern)
{
	PrivKey priv;
	vlPoint session, mac;
	time_t now;
	sgPair sig;
	ERROR err;
	unsigned long int id;
	int only_hash = 0;
	
	/** 1st, get the input priv. or pub. key and check **/
	if(f_key != NULL){
		get_privkey(f_key, priv, CHCONV(ask_passw)); /** Straightly get priv. key **/
	}
	else if (pattern != NULL){
		hash_password(pattern[0], priv);
	}
	else{
		only_hash = 1;
	}
	
	if(!only_hash){
		PubKey pub;
		int i, match = 0;
		
		/** 3. Get pub. key and  id. **/
		eccMakePublicKey(pub, priv);
		get_keyid(pub, &id);
	
		/** 3.b Checks if it matchs with some public key in keyring **/
		if((err = load_keyring(NULL, &default_kr))){goto DO_SIGNATURE_BYE;}
		for(i = 0; i < default_kr.N; ++i){
			if(id == default_kr.vector[i].id){
				fprintf(stderr, "%s:", msg_sign_key);
				match = 1;
				break;
			}
		}
		fprintf(stderr, "  [%08lx]\n", id);
		/** Anyway, go on **/
		if(!match) fputs(msg_no_sign_key, stderr);
	}
	
	/** 4. Hash the input file **/
	if(f_out != stdout){ /* operation == 's' or 'r' */
		hash_binary_file(f_inp);
	}
	else{ /* operation == 'S' */
		fprintf(f_out, "%s\n", begin_armour);
		hash_ascii_text(f_inp, f_out, 1);
		fputs(end_clearsign,f_out);
	}

	if(only_hash){
		int i;
		hash_time(mac, 0L);		/** Time = 0 means no hash_time. Only closes hash and returns **/
		for(i = 0; i < HASH_SIZE; ++i){
			fprintf(stdout, "%02x", (unsigned char) mac[i]);
		}
		return 0;
	}
	/** 5. Get the time, hash it and harvest the result **/
	now = time(NULL);
	hash_time(mac, now);	/** "mac" has the hash-concatenation of file+time **/

	/** 6. Sign it! **/
	do{
		if(!get_entropy(session, KEY_SIZE)){ err = -1; goto DO_SIGNATURE_BYE;}
		err = eccSign(priv, session, mac, &sig);
	} while (err);

	/** 7. Output it **/
	write_longint(f_out, id, 0); /** First, key id. **/
	write_timestamp(f_out, now);
	write_signature(f_out, &sig);

DO_SIGNATURE_BYE:
	zerokey(priv);
	burn_stack(200);
	return err;
}

ERROR do_verify(int operation, FILE *f_inp, FILE *f_out, FILE *f_sec)
{
	vlPoint mc;
	
	sgPair sig;
	ERROR err;
	int ver = 0, coincid, *index;;
	time_t now;
	unsigned long int id;
	char idstring[16], *pattern[2];
	FILE *sfile;
	
	/** 0. Load key ring **/
	if((err = load_keyring(NULL, &default_kr))) return err;
	
	/** 1. Hash the input file & read key id., timestamp and signature **/
	if(operation == 'v'){
		hash_binary_file(/*c,*/ f_inp);
		sfile = f_sec;
	}
	else{ /* operation == 'V' */
		if((err = position(f_inp, begin_armour))){
			fputs( CHCONV(err_clearsig_header_not_found), stderr );
			return err;
		}
		hash_ascii_text( f_inp, f_out, 0);
		sfile = f_inp;
		
	}
	read_longint(sfile, &id, 0);
	read_timestamp(sfile, &now);
	read_signature(sfile, &sig, 0);
	
	hash_time(mc, now);	/** "mc" has the hash-concatenation of file+time **/
	
	/** 2. Look for key in keyring **/
	sprintf(idstring, "%08lx", id);
	pattern[0] = &(idstring[0]);
	pattern[1] = NULL;
	index = malloc(default_kr.N * sizeof(int));
	coincid = search_pubkey(&default_kr, index, pattern, stderr, 'l');
	if(coincid == -1) return -1;
  	else if (coincid == 0){
		fprintf(stderr, "[%08lx]: %s", id, CHCONV(err_no_key));
		return -1;
	}
	
	/** 3. Check signature **/
	while(coincid){ /** Normally, coincid = 1 **/
		ver |= eccVerify(default_kr.vector[index[coincid - 1]].val, mc, &sig);
		if(ver) break;
		--coincid;
	}
	free(index);
		
	if(!ver){
		fputs(CHCONV(err_signature), stderr);
		err = -3;
	}
	else{
		char buf[SMALL_BUF];
		fputs(CHCONV(msg_signature_verifies), stderr);
		/*strftime(buf, SMALL_BUF, "%F, %R",  gmtime(&now));*/
		strftime(buf, SMALL_BUF, "%Y-%m-%d, %H:%M",  gmtime(&now));
		fputs(buf, stderr);
		/*fputs(ctime(&now), stderr); */
		
		fputs("\n", stderr);
		err = 0;
	}
	
	burn_stack(200);
	return err;
}

ERROR do_encrypt(FILE *f_inp, FILE *f_out, FILE *f_key, char **pattern, int ciph_mode)
{
	vlPoint session, *msg;
	PubKey *pub;
	int sym_mode, binmode, coincid, i, *index;
	ERROR err = 0;

	/** 0. Load key ring **/
	if((err = load_keyring(NULL, &default_kr))) return err;
	/** 1. Write the header **/
	binmode = (ciph_mode & BINARY_FLAG);
	/*(f_inp == stdin)? 0: 1;*/
	if(!binmode)
		fprintf(f_out, "%s\n", begin_armour);

	sym_mode = ciph_mode & SYM_MODE;
	/*ciph_mode = ciph_mode & 0xff;*/
	
	/** 2. get the input pub. key **/
	if(sym_mode == PK_MODE){ /** public-key mode **/
		fputs(CHCONV(msg_elected_keys), stderr);
		 /** Firstly, identify file as pk-encrypted by 'sks' **/
		write_longint(f_out, pubkey_mode_id, binmode);
		index = malloc(default_kr.N * sizeof(int));
		coincid = search_pubkey(&default_kr, /*&pub*/ index, pattern, stderr, 'l');
		if(coincid < 0) return -1; /** This cannot happen **/
		if(coincid == 0) {fputs(CHCONV(err_no_key), stderr); return -1;}
		write_longint(f_out, (long) coincid /*pub.N*/, binmode);
		
		pub = malloc(coincid * sizeof(PubKey));
		msg = malloc(coincid * sizeof(PubKey));
		
		for(i = 0; i < /*pub.N*/ coincid; ++i){
			memcpy(pub[i], default_kr.vector[index[i]].val, KEY_SIZE);
			write_longint(f_out, default_kr.vector[index[i]].id, binmode);
		}
		/** 3. random junk **/
		if(!get_entropy(session, KEY_SIZE)) return -1;

		/** 4. encode secret **/
		eccEncode(pub /*.val*/, msg /*.val*/, session, /*pub.N*/ coincid);
		
		/** 5. Write the coded secrets **/
		for(i = 0; i < /*msg.N*/ coincid; ++i){
			fwritePlus( msg[i], 1, KEY_SIZE, f_out, binmode);
		}
		free(pub); free(msg); free(index);
	}
	
	else{ /** Symmetric mode **/
		if(f_key != NULL){
			if((err = get_privkey(f_key, session, CHCONV(ask_passw)))) return err;
		}
		else if(pattern != NULL){
			if((err = hash_password(pattern[0], session))) return err;
		}
		else fputs("This cannot happen!!\n", stderr);
		hash_binary(session, session, KEY_SIZE); /** One more hashing **/
		write_longint(f_out, symkey_mode_id, binmode);
	}
		
	/** 6. Call sym. cipher **/
	err = sym_encrypt(f_inp, f_out, session, ciph_mode);
	zerokey(session);

	/** 7. Write termination and bye **/
	if(!binmode) fputs(end_armour,f_out);

	burn_stack(200);
	return err;
}

ERROR do_decrypt(FILE *f_inp, FILE *f_out, FILE *f_key, char **passw, int binmode)
{
	PrivKey priv;
	ecPoint msg;
	vlPoint session;
	char buf[SMALL_BUF];
	int size, i, index = -1, /*binmode, */
		found_armour = 0,
		found_id = 0,
		found_key = 0,
		got_priv = 0;
	unsigned long int nkeys, id, prov_id = 0;
	ERROR err = 0;

	/** 1. Read the header **/
	/*binmode = (f_inp == stdin)? 0: 1; */
DO_DECRYPT_CONTINUE:
	if(!binmode){

		if((position(f_inp, begin_armour))){
			/*fputs( CHCONV(err_clearsig_header_not_found), stderr );
			return err; */
			goto DO_DECRYPT_ERROR;
			/*break;*/
		}
		if(!found_armour){
			++found_armour;
		}
	}	
		
	/** 2. get the priv. key **/
	if(f_inp == stdin){
		if(!got_priv){
			hash_password(passw[0], priv);
			got_priv = 1;
		}
	}
	else{
		get_privkey(f_key, priv, CHCONV(ask_passw)); 
	}
	
	read_longint(f_inp, &id, binmode);
	/*fprintf(stderr, "Identificador: %lx\n", id);*/
	if (id == pubkey_mode_id){
		++found_id;
		/** 3. Read the header data **/
		read_longint(f_inp, &nkeys, binmode);
		
		/** 4. Make the pub. key for provided priv. key **/
		if(prov_id == 0){
			eccMakePublicKey(msg, priv); /** 'msg' is provisional pub. key **/
			get_keyid(msg, &prov_id);
			zerokey(msg);
		}
		/** 5. Check with in-file pub. keys **/
		index = -1;
		for(i = 0; i < nkeys; ++i){
			read_longint(f_inp, &id, binmode);
			fprintf(stderr, "[%08lx]: ", id);
			if(id == prov_id){
				index = i;
				fputs("*", stderr);
			}
			fputs("\n", stderr);

		}
		
		if(index == -1){
			fputs(CHCONV(err_no_key), stderr);
			/*return -1;*/
			err = -1;
			if(!binmode){
				while(!feof(f_inp)){
					fgets(buf, SMALL_BUF, f_inp);
					/*fprintf(stderr, "Línea: %s\n", buf);*/
					if(!strncasecmp(buf, end_armour, strlen(end_armour) - 2)) break;
				}
				burnBinasc();
				goto DO_DECRYPT_CONTINUE;
			}
			else return -1;
		}
		++found_key;
		
		/** 6. Read the encoded secret **/
		for(i = 0; i < nkeys; ++i){
			size = KEY_SIZE;
			freadPlus(buf, 1, size, f_inp, binmode);
			if(i == index) memcpy(msg, buf, size);
		}

		/** 7. Decode secret **/
		eccDecode(priv, msg, session);
		zerokey(msg);
	}
	else if (id == symkey_mode_id){
		++found_id;
		hash_binary(session, priv, KEY_SIZE);
	}
	else{
		err = -1;
		/*goto DO_DECRYPT_ERROR;*/
	}

	/** 8. Call sym. cipher and bye **/
	if(found_key > 1) fputs("\n\t\t* * *\n", f_out);
	err = sym_decrypt(f_inp, f_out, session, binmode);
	zerokey(session);
	if(err) fputs(CHCONV(err_data_corrupted), stderr);
	
	if(!binmode){
		zeromem(buf, SMALL_BUF);
		fgets(buf, SMALL_BUF, f_inp);
		/*fprintf(stderr, "Resto de fichero: - %s\n", buf);*/
		goto DO_DECRYPT_CONTINUE;
	}
	
DO_DECRYPT_ERROR:
	zerokey(priv);
	if(!found_armour && !binmode){
		fputs( CHCONV(err_clearsig_header_not_found), stderr );
	}
	else if(!found_id && err){
		fputs(CHCONV(err_bad_encrypted_file), stderr);
	}
	/*else if(!found_key && err){
		fputs(CHCONV(err_no_key), stderr);
	}*/
	else if(!binmode){
		fprintf(stderr, "%s%d\n", CHCONV(msg_num_decrypt_messages), found_key);
	}
	
	burn_stack(200);
	return err;
}
  
int main( int argc, char ** argv/*, char *envp[] */)
{
  int err = 0, operation, filter=0, binary=BINARY_FLAG;
  FILE * f_key = NULL, * f_inp, * f_out, *f_sec = NULL;
  char openForRead [3] = "rb";
  char openForWrite [3] = "wb";
  /*char openKey[3] = "r";*/
  char **pattern = NULL;
  
  /** I've blocked this checking until charset conversion is improved **/
  /*test_charset();*/
  
  /*if((err = load_keyring(NULL, &default_kr))) return err;*/
  if ( argc<2 || argv[1][0] != '-')
  {
    error:
    if(filter) goto filterError;
    fputs( CHCONV(  manual), stderr);
    /**err = 1;
	goto adios;**/
	return 5;
  }
 
  operation = argv[1][1];

  if(('f' == operation) || ('b' == operation))
  {
  	  int pos = 2;
      if ('f' == operation){
	  	filter = 1;
		binary = 0;
	  }
	  else{
	  	filter = 2;
	  }
      operation = argv[1][pos];
		
      if(0 == argv[1][pos]){
         filterError:
         fputs(CHCONV(filterManual), stderr);
         err = 1;
		 goto adios;
      }
	  
  }
  else if ( operation == 'l' ){
  	fputs(CHCONV(gplDisclaimer), stderr);
	goto adios;
  }
  else if ( operation == 'k' ){
	if((err = load_keyring(NULL, &default_kr))) return err;
	if('g' == argv[1][2]){
		if((err = do_make_pubkey(stdin, NULL))){
			fputs(CHCONV(err_key), stderr);
			goto adios;
		}
		search_pubkey(&default_kr, NULL, NULL, stderr, 'l');
	}
	else if(('e' == argv[1][2]) || ('l' == argv[1][2]) || ('f' == argv[1][2])){
		
		if (argc > 2)
			search_pubkey(&default_kr, NULL, argv + 2, stdout, argv[1][2]);
		else
			search_pubkey(&default_kr, NULL, NULL, stdout, argv[1][2]);
	}
	
	else if('i' == argv[1][2]){
		if(argc == 3){
			if((f_inp = chkopen(argv[2], openForRead)) == NULL) {err = -1; goto adios;}
		}
		else
			f_inp = stdin;

		err = import_keyring(f_inp);
	}
	else if('d' == argv[1][2]){
		char *num;
		if(argc == 3) num = argv[2];
		else num = NULL;
		if((err = delete_element(num))) fputs(CHCONV(err_no_key), stderr);
	}
	else{
		fputs(CHCONV(keyManual), stderr);
		char buf[SMALL_BUF];

		get_full_path(KEYRING, buf);
		fprintf(stderr, " %s: %s\n", keyfile_title, buf);
        err = 1;
      }
	  goto adios;
  }
  else if (argv[1][2] != 0) goto error;

	/** Check expected parameters and assign streams **/
	if(1 == filter){
		if((operation == 'e') || (operation == 'E') ){
			if(argc < 2) goto error;
			else if(argc == 2) pattern = NULL;
			else pattern = argv + 2;
		}
		
		else if((operation != 'd') && (operation != 'D') && (operation != 'S') 
		  && (operation != 'V')  && (operation != 'c') && (operation != 'C') ){
			goto error;
		}
		else if(operation != 'V'){
			if(argc < 3) goto error;
			pattern = argv + 2;
		}
		f_inp = stdin;
		f_out = stdout;

		f_key = NULL;
  	}
	else if(2 == filter){
		if((operation == 'e') || (operation == 'E') ){
			if(argc < 2) goto error;
			else if(argc == 2) pattern = NULL;
			else pattern = argv + 2;
		}
		
		else if((operation != 'd') && (operation != 'D') && 
		(operation != 'c') && (operation != 'C') ){
			goto error;
		}
		else{
			if(argc < 3) goto error;
			pattern = argv + 2;
		}
		f_inp = stdin;
		f_out = stdout;

		f_key = NULL;
	
	}
  	else{

		
		if((operation == 'S') || (operation == 'V')){
			if(argc != 3) goto error;
			f_out = stdout;
			f_key = stdin;
		}
		else if(operation == 'v'){
			if(argc != 4) goto error;
			if((f_sec = chkopen(argv[3], openForRead)) == NULL){err = -1; goto adios;}
			f_out = NULL;
		}

		else if((operation == 'c') ||(operation == 'C') ||
				(operation == 'd') || (operation == 'D') ||(operation == 's') ) {
			if(argc != 4) goto error;
			f_key = stdin;
			if((f_out = chkopen(argv[3], openForWrite)) == NULL){err = -1; goto adios;}
			pattern = NULL;
		}
		else if(operation == 'r'){
			if(argc < 3) goto error;
			f_out = NULL;
			f_key = NULL;
			pattern = NULL;
		}
		else if ((operation == 'e') || (operation == 'E') ) { 
			if(argc < 4) goto error;
			f_key = NULL;
			if((f_out = chkopen(argv[3], openForWrite)) == NULL){err = -1; goto adios;}
			if(argc == 4) pattern = NULL;
			else pattern = argv + 4;
		}

		else goto error;

		if((f_inp = chkopen(argv[2], openForRead)) == NULL){err = -1; goto adios;}
  }
  
  	/**** Operations ****/
		
	/** SIGN **/
	if((operation == 's') || (operation == 'S') ){
		err = do_signature(f_inp, f_out, f_key, pattern);
	}
	
	/** HASH **/
	else if(operation == 'r'){
		int i;
		for( i = 2; i < argc; ++i){
			if((f_inp = chkopen(argv[i], openForRead)) == NULL){err = -1; continue;}
			if((err = do_signature(f_inp, f_out, f_key, pattern))) goto adios;
			fclose(f_inp);
			fprintf(stdout, "  %s\n", argv[i]);
		}
	}

	/** VERIFY **/
	else if((operation == 'v') || (operation == 'V'))
		err = do_verify(operation, f_inp, f_out, f_sec);

	/** CRYPTO **/
	else if(operation == 'e') 
		{err = do_encrypt(f_inp, f_out, f_key, pattern, PK_MODE | AES128_CTR2 | binary);}
	else if(operation == 'E') 
		{err = do_encrypt(f_inp, f_out, f_key, pattern, PK_MODE | AES128_CTR2 | COMPRESS_FLAG | binary);}
	else if((operation == 'd') || (operation == 'D') ) 
		{err = do_decrypt(f_inp, f_out, f_key, pattern, binary);}

	/** SYMETRIC OPERATIONS **/
	else if(operation == 'c') 
		{err = do_encrypt(f_inp, f_out, f_key, pattern, SYM_MODE | AES128_CTR2 | binary);}
	else if(operation == 'C') 
		{err = do_encrypt(f_inp, f_out, f_key, pattern, SYM_MODE | AES128_CTR2 | COMPRESS_FLAG | binary);}
	/** This cannot happen **/
	else goto error;

adios:
	eccQuit();
	close_keyring(&default_kr);
	burn_stack(2000);
	burnBinasc();

	return err;
}

