xor_crypt.c

/*********************************************************************
*        programa de criptografia usando a tecnica xor
*
* Autor: Elgio Schlemer
* Data: 10/11/2000
* 
* Descricao: programa que criptografa um arquivo passado por parametro,
* colocando seu resultado criptografado em um outro arquivo tambem passado
* por parametro, usando uma senha de MIN caracteres no minimo e MAX no
* maximo, case sensitive.
* 
* Motivo: precisava tornar meu .fetchmailrc nao legivel.
*	  o fetchmail eh um programa que busca msg de varias caixas
*	  postais. para que funcione de forma adequada, precisa de um
*	  arquivo .fetchmailrc no home com a configuracao de cada caixa a
*	  ser usada, cada um com sua senha. pode-se omitir a senha, mas
*	  neste caso o fethmail iria requisita-la, tornando a operacao
*	  irritante (uso para quatro caixas postais).
*	  ao colocar a senha no arquivo, ela fica exposta (visivel, em modo
*	  texto) e mesmo protegida de leitura para o grupo e outros (o
*	  fetchmail exige isso), nao me sentia seguro. entao, fiz este
*	  programa e o utilizo dentro do script pega_mail:
*
* 		#!/bin/sh
* 
* 		cd ~ 
*		xor_crypt .fetchmailrc.crypt .fetchmailrc 
*		chmod 0710 .fetchmailrc 
*		fetchmail $* 
*		rm .fetchmailrc          
*
*	Assim, o arquivo fica legivel no breve momento antes de chamar o
*	fethmail e eu preciso digitar apenas uma senha, a que descritografa
*	o arquivo .fethmailrc.crypt
*
*       Porque nao usei algum programa de criptografia existente, como o
*       gpg (pgp da gnu) ou usando a propria funcao crypt() do linux?
*
*	1. Porque eles sao muito mais do que eu preciso;
*	2. Precisava fazer algo de inutil e que ninguem realmente
*	   precisasse;
*	3. Nao teria graca nenhuma...
*	4. Precisava de um exemplo para meus alunos de c. (agora posso 
*          cobrar na prova :-D)
*	
* Compatibiliade: compativel com dos e linux. no dos a senha, ao ser
* digitada, irah ecoar na tela. 
*
* Escrito usando o vi, identado automaticamente pelo padrao K&R.
*
* Ambasamento teorico: Um xor eh uma operacao bit a bit que tem como
* caracteristica deixar em ZERO o bit resultante quando ambos os bits da
* operacao forem iguais. Umas das primeiras tecnicas de criptografia, jah
* nao eh mais seguro, por ser quebrado com muita facilidade e por ter a
* senha facilmente descoberta, caso alguem possua o texto original e o
* criptografado.
*
* Tecnica usada: cada caractere da senha eh usado para encriptar um
* caractere do arquivo e assim sucessivamente. Quando todos os caracteres
* da senha forem usados, pega-se novamente o primeiro e assim por diante.
* 
* Problemas e bugs: 
* 	- Eh usado tanto para encriptar como para decriptar, mas como nao
* 	eh feito nenhum teste de CRC ou algo do tipo, se ao se decriptar o
* 	usuario errou a senha, ele ira gerar lixo na saida. O sistema nao
* 	tem condicoes de dizer se a senha eh invalida.
*
*	- Facil de descobrir ATRAVES DE CRIPTOANALISE, mas impossivel sem a
*	construcao de uma ferramenta.
*
*	- Se o arquivo a ser criptografado NAO FOR texto, contendo numeros
*	binarios, pode ser que ele contenha sequencias de 00h 00h 00h, ...
*	do mesmo tamanho da senha. Neste caso, a senha ficaria exposta no
*	arquivo criptografado, pois XOR 00h, senha resulta em senha;
*
* Compilacao:
* 	- No dos: clique naquele botaozinho que compila. Eh soh saber usar
* 	  o mouse. Ou entao, Ctrl + F9...
*	- No Linux: 
* 	     make xor_crypt 
*
*	Nao recomendado, pois nao configura o #define LINUX e ele fica
*	igualzinho ao DOS (eca) ecoando a senha na tela.
*
*            gcc -DLINUX xor_crypt.c -o xor_crypt
*
*       Muito melhor, pois configura parametros exclusivos do LINUX, como a
*       retirarda do ECHO para a tela, fazendo com que a senha nao apareca.
*
* Forma de uso:
*       Para criptografar: 
*		xor_crypt arq_texto arq_texto_criptografado
*       Para decriptografar:
*		xor_crypt arq_texto_criptografado arq_texto
*
*  	Obs: decriptografar equivale a criptografar um arquivo jah
*  	criptografado. Pense sobre o que acontece com o xor para entender
*  	isso.
*
* Nota de Copyright:
*	Direitos reservados? Para esta coisa? Nao, que nada. Apenas
*	comunique o autor se algum dia, em algum lugar, esta coisa foi
*	util. De a este autor um motivo qualquer pela sua existencia
*	:-D
*	Aplique-se a licensa gpl - nao sabe o que eh gpl?? Por favor,
*	aponte seu navegador AGORA para
*		http://www.ulbra.tche.br/~elgios/gnu  
* 	ou, no original: 
*       	http://www.gnu.org
*********************************************************************/
 

#include <stdio.h>
#define ERRO	0		/* Codigo de erro usado */
#define MAX	40		/* Tamanho maximo de senha admitido */
#define MIN	5		/* Tamanho minimo de senha admitido */

#ifdef LINUX
#include <termios.h>
#include <unistd.h>
#endif


/*------------------------------------------------
 * Funcao le_senha(). Encarregada de ler (nome sugestivo, nao?) a
 * senha...
 *
 * Parametros: endereco de um buferr onde deve ser colocada a senha
 * lida e a quantidade maxima de caracteres requisitados 
 *
 * Retorna a quantidade de caracteres efetivamente lidos.
 */
char le_senha(char *a, int t)
{

#ifdef LINUX
	struct termios t_orig, t_0;

/* As linhas abaixo servem para setar o terminal do Linux a ser orientado a
 * caractere e a nao ecoar os caracteres digitados na tela. Antes, porem,
 * pega-se a configuracao atual para recuperar posteriormente.
 */
	tcgetattr(0, &t_0);
	t_orig = t_0;
	t_0.c_lflag &= ~(ECHO | ICANON | IEXTEN);
	tcsetattr(0, TCSADRAIN, &t_0);
#endif

/* Le-se a senha (nao lhe parece obvio?) */
	fgets(a, t, stdin);

#ifdef LINUX
/* Recuperando as configuacoes originais do terminal */
	tcsetattr(0, TCSADRAIN, &t_orig);
#endif

	return (strlen(a));
}

int main(int argc, char *argv[])
{
	FILE *in, *out;
	char pass[MAX + 2];
	/* para guardar a senha. Dois caracteres a mais,
	 * porque o fgets() coloca o codigo do enter dentro da
	 * string tambem. Mais um para o final... 
	 */
	char t, i, letra;
	double check;


	/* usuario precisa digitar DOIS nomes de arquivo. Ok, ok, eu sei...
	 * Isso nao eh muito da filosofia Unix, onde a omissao dos nomes
	 * significa entrada e saida padrao (filtros). Quem sabe na versao
	 * 2.0... */
	if (argc <= 2) {
		fprintf(stderr, "ERRO! Faltou parametro\n");
		fprintf(stderr, "Chame: %s arquivo arquivo\n", argv[0]);
		exit(ERRO);
	}

	/* Abrindo origem (quem sera criptografado) para leitura */
	in = fopen(argv[1], "r");
	if (in == NULL) {
		fprintf(stderr,
			"ERRO: nao consegue abrir %s para leitura\n",
			argv[1]);
		exit(ERRO);
	}

	/* Abrindo o arquivo destino para leitura???!!
	 * Calma, nao estou louco nao. Eh apenas para verificar se o mesmo
	 * EXISTE, pedindo confirmacao do usuario para apaga-lo */
	out = fopen(argv[2], "r");
	if (out != NULL) {
		fprintf(stderr,
			"ERRO: arquivo %s jah existe!! Apaga-lo? (S/N)",
			argv[2]);
		t = fgetc(stdin);
		if ((t != 'S') && (t != 's')) {
			fclose(in);
			exit(ERRO);
		}
		fclose(in);
	}

	/* Ahhh, agora sim... abrimos o arquivo para escrita, criando se
	 * nao existe e zerando se existe */
	out = fopen(argv[2], "w");
	if (out == NULL) {
		fprintf(stderr, "ERRO: nao consegue criar arquivo %s\n",
			argv[2]);
		fclose(in);
		exit(ERRO);
	}

	/* Mensagem pedindo a senha */
	printf("Senha (de %d a %d cars): ", MIN, MAX);

	/* O "senha invalida" eh apenas para garantir que o usuario (sempre
	 * eles!!!) nao tentem digitar uma senha menor que a especificanda.
	 * Algumas frescurinhas podem ser colocadas aqui, como nao permitir
	 * senhas faceis, etc... */
	while (le_senha(pass, MAX) < MIN) {
		printf("\nInvalida!!!");
		printf("\nSenha (de %d a %d cars): ", MIN, MAX);
	}

	/* Hummm.. senha foi lida e eh valida (mesmo que seja o 
	 * ridiculo 12345678). Agora vem a parte nobre do programa: a
	 * criptografia (bem 'chinela', eh verdade) */
	letra = fgetc(in);

	/* Se nao sabe, tente man fgetc no Linux, ou
	   digite fgetc no editor borland e pegue um help 
	 */
	for (i = 0; !feof(in); i++) {
		if (i >= t) {
			i = 0;
		}
		letra = letra ^ pass[i];

		/* a letra atual eh criptografada com o caractere
		 * atual da senha. Quando todos os caraceteres de
		 * senha forem usados, comeca-se novamente. Isso eh
		 * controlado no if logo acima, comparando o i com
		 * o tamanho da senha */
		fputc(letra, out);

		/* escreve o lixinho gerado no arquivo de saida */
		letra = fgetc(in);

		/* proxima letra (pensaram que era algo
		 * complicadissimo, cheio de formulas matematicas?
		 * Desculpe pela decepcao... */
	}
	fclose(in);		/* fecha arquivo texto de entrada */
	fclose(out);		/* fecha... ah, vc jah sabe... */
	return (1);
}

Generated by GNU enscript 1.6.1.