Ejemplos de memoria dinamica en cifrado de Beaufort

Iniciado por do-while, 21 Octubre 2011, 04:10 AM

0 Miembros y 1 Visitante están viendo este tema.

do-while

¡Buenas!

He visto que ultimamente hay bastantes preguntas sobre memoria dinamica. Aqui os dejo un pequeño programa que la utiliza varias veces y con distintos tipos de puntero. Espero que podais usarlo como ejemplo para resover vuestros propios problemas.

Para los interesados en criptografia, tengo que decir que es una variante del cifrado de Beaufort en el que se pueden utilizar varias claves para añadir seguridad al cifrado:


/*

    Utilidad que cifra ficheros basandose en el cifrado de Beaufort con claves multiples

    Al ultilzar claves multiples, la longitud de la clave resultante sera el minimo comun
multiplo de todas las claves utilizadas.

    cifra +|- "claves" fichero_de_entrada fichero_de_salida

    +: cifrar
    -: descifrar

*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* funcion que guarda en tokens las palabras contenidas en s y devuelve el numero de parabras extraidas */
int tokenize(char *s, char ***tokens);

/* carga en (*s) el contenido del fichero al que apunta f */
unsigned long cargar_fichero(FILE *f, unsigned char** s);

/*

calcula el coeficiente nsimo segun el siguiene criterio:

ultima_clave[posicion % longitud ultima_clave] -
penultima_clave[posicion % longitud penuultima_clave] +
antepenultima_clave[posicion % longitud antepenultima_clave] +
... + o - (segun el numero de claves) primera_clave[posicion % longitud primera_clave]
*/
int coeficiente(unsigned long posicion, char **claves, int nclaves);

/*
    cifrado[i] = coeficiente[i] + o - (depende del numero de claves) texto_plano[i] mod 256;

    tomando la clase de quivalencia positiva entre 0 y 255
*/
int cifrar(unsigned char *s, unsigned long longitud, char **claves, int nclaves);


/*
    texto_plando[i] = 1 o (-1) (depende del numero de claves) * (cifrado[i] - coeficiente[i]) mod 256;

    tomando la clase de quivalencia positiva entre 0 y 255
*/
int descifrar(unsigned char *s, unsigned long longitud, char **claves, int nclaves);

/*

    las siguientes funciones calculan el minimo comun multiplo y maximo comun divisor de dos enteros

*/
unsigned long mcm(unsigned long a, unsigned long b);
unsigned long mcd(unsigned long a, unsigned long b);

int main(int argc, char *argv[])
{
    FILE *f; /* fichero de entrada y de salida */
    char **claves = NULL; /* variable para guardar las claves introducidas */
    unsigned char *contenido = NULL; /* puntero para almacenar el contenido del fichero */
    unsigned long longitud, nclaves; /* longitud del fichero y numero de claves introducidas*/

    if(argc != 5)
    {
        printf("\ncomando: cifra +|- \"claves\" fic_entrada fic_salida\n\n+: cifrar\n-: descifrar\n");
    }
    else
    {
        if(!(f = fopen(argv[3] , "rb")))
            printf("No se puede abrir el fichero: %s\n", argv[3]);
        else
        {
            if((longitud = cargar_fichero(f,&contenido)) == (unsigned long)(-1))
            {
                printf("Ha ocurrido un error al cargar el contenido del fichero de entrada.\n");
                fclose(f);
            }
            else
            {
                if((nclaves = tokenize(argv[2] , &claves)) != (unsigned long)(-1))
                {
                    if(!strcmp(argv[1],"+"))
                    {
                        if(!cifrar(contenido,longitud,claves,nclaves))
                            printf("\nHa ocurrido un error en el proceso de cifrado.\n");
                        else
                        {
                            if(!(f = fopen(argv[4] , "wb")))
                                printf("No se puede abrir el fichero: %s\n", argv[4]);
                            else
                            {
                                fwrite(contenido,longitud,1,f);
                                fclose(f);
                            }
                        }

                        free(contenido);

                        for(longitud = 0 ; longitud < nclaves ; longitud++)
                            free(claves[longitud]);
                        free(claves);
                    }
                    else if(!strcmp(argv[1],"-"))
                    {
                        if(!descifrar(contenido,longitud,claves,nclaves))
                            printf("\nHa ocurrido un error en el proceso de descifrado.\n");
                        else
                        {
                            if(!(f = fopen(argv[4] , "wb")))
                                printf("No se puede abrir el fichero: %s\n", argv[4]);
                            else
                            {
                                fwrite(contenido,longitud,1,f);
                                fclose(f);
                            }
                        }

                        free(contenido);

                        for(longitud = 0 ; longitud < nclaves ; longitud++)
                            free(claves[longitud]);
                        free(claves);
                    }
                    else
                        printf("\ncomando: cifra +|- \"claves\" fic_entrada fic_salida\n\n+: cifrar\n-: descifrar\n");
                }
                else
                {
                    printf("\nHa ocurrido un error al cargar las claves.\n");
                    free(contenido);
                }
            }
        }
    }

    return 0;
}

unsigned long cargar_fichero(FILE *f,unsigned char **ptr)
{
    unsigned long pos, len;

    /* calculamos la longitud del fichero */
    pos = ftell(f);
    fseek(f,0,SEEK_END);
    len = ftell(f);
    fseek(f,pos,SEEK_SET);

    /* asignamos tantos bytes como tenga el fichero */
    if(((*ptr) = (unsigned char *) malloc(len * sizeof(unsigned char))) != NULL)
        /* y cargamos el contenido */
        fread((*ptr),len,1,f);
    else
        len = (unsigned long)(-1);

    return len;
}

int tokenize(char *s, char ***tokens)
{
    char **aux; /* variable auxiliar para ir añadiendo una cadena mas a la lista */
    char *palabra; /* palabra extraida de la cadena s*/
    int npalabras = 0,i; /* numero de palabras y contador para bucles */

    /* intentamos leer una palabra */
    palabra = strtok(s," ");

    (*tokens) = NULL;

    while(palabra)
    {
        /* si se ha encontrado una palabra incrementamos el recuento de palabras*/
        npalabras++;

        /* hacemos que aux contenga tantos punteros a char como paralbras haya */
        if(!(aux = (char **) realloc((*tokens) , npalabras * sizeof(char*))))
        {
            for(i = 0 ; i < npalabras - 1 ; i++)
                free((*tokens)[i]);

            free(*tokens);
            (*tokens) = NULL;

            return -1;
        }
        else
        {
            /* asignamos la ultima palabra leida */
            aux[npalabras - 1] = (char *) malloc(sizeof(char) * (strlen(palabra) + 1));
            strcpy(aux[npalabras - 1] , palabra);

            /* y hacemos que la variable de entrada/salida apunte al nuevo conjunto de palabras */
            (*tokens) = aux;
        }

        /* intentamos leer la siguiente palabra */
        palabra = strtok(NULL , " ");
    }

    return npalabras;
}

int coeficiente(unsigned long posicion, char **claves, int nclaves)
{
    int c=0;
    unsigned long j;

    for(j = 0 ; j < nclaves ; j++)
    {
        if((nclaves - 1 - j) % 2)
            c -= claves[j][posicion % strlen(claves[j])];
        else
            c += claves[j][posicion % strlen(claves[j])];
    }

    return c;
}

int cifrar(unsigned char *s, unsigned long longitud, char **claves, int nclaves)
{
    unsigned long i;
    char *clave;
    unsigned long long_clave=1;

    /* la longitud de la clave final sera el mcm de las longitudes de las claves */
    for(i = 0 ; i < nclaves ; i++)
        long_clave = mcm(long_clave , strlen(claves[i]));

    if(!(clave = (char*) malloc(long_clave * sizeof(char))))
        return 0;

    for(i = 0 ; i < long_clave ; i++)
        clave[i] = coeficiente(i,claves,nclaves);

    for(i = 0 ; i < longitud ; i++)
        s[i] = (nclaves * 256 + (clave[i % long_clave] + (1 - 2 *(nclaves % 2)) * s[i])) % 256;

    free(clave);

    return 1;
}

int descifrar(unsigned char *s, unsigned long longitud, char **claves, int nclaves)
{
    unsigned long i;
    char *clave;
    unsigned long long_clave=1;

    for(i = 0 ; i < nclaves ; i++)
        long_clave = mcm(long_clave , strlen(claves[i]));

    if(!(clave = (char*) malloc(long_clave * sizeof(char))))
        return 0;

    for(i = 0 ; i < long_clave ; i++)
        clave[i] = coeficiente(i,claves,nclaves);

    for(i = 0 ; i < longitud ; i++)
        s[i] = (nclaves * 256 + ((1 - 2 * (nclaves % 2)) * (s[i] - clave[i % long_clave]))) % 256;

    free(clave);

    return 1;
}

unsigned long mcm(unsigned long a, unsigned long b)
{
    return (a * b) / mcd(a,b);
}

unsigned long mcd(unsigned long a, unsigned long b)
{
    if(a < b)
    {
        a ^= b;
        b ^= a;
        a ^= b;
    }

    if(!b)
        return a;

    return mcd(b , a % b);
}


Se debe utilizar desde la linea de comandos, por lo que es recomendable dejar el ejecutable en c:\windows\system32 para sistemas windows, \bin en sistemas UNIX y en general, en el directorio en el que se encuentren por defecto los comandos del sistema.

Para cifrar un fichero llamado "prueba" con la clave "clave de prueba" y como fichero de salida "cifrado", se debera hacer:

cifra + "clave de prueba" prueba cifrado

suponiendo que nombre del ejecutable sea cifra.

Para obtener el texto plano se utilizara la misma sintaxis utilizando el parametro - en lugar de +.

¡Saludos y espero que os sirva de referencia!

PD: Si veis algun error avisad, que uno es humano y por lo tanto propenso a cometer errores. Lo mismo si teneis alguna sugerencia.

¡Saludos!
- Doctor, confundo los números y los colores.
- Vaya marrón.
- ¿Marrón? ¡Por el culo te la hinco!