Présentation:

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

/* 
 * Fonction de hachage simple avec sel
 * Retourne une valeur de hash non-signée
 */
unsigned long int hash_djb2_salt(const char *str, const char *salt)
{
    unsigned long int hash = 5381;
    const char *s;
    
    if (str == NULL) 
    {
        return 0;
    }
    
    /* Appliquer d'abord le sel */
    if (salt != NULL) 
    {
        s = salt;
        while (*s != '\0') {
            hash = ((hash << 5) + hash) + (unsigned char)*s;
            s++;
        }
    }
    
    /* Puis la chaîne principale */
    s = str;
    while (*s != '\0') 
    {
        hash = ((hash << 5) + hash) + (unsigned char)*s;
        s++;
    }
    return hash;
}

/*
 * Fonction de hachage alternative type sdbm avec sel
 */
unsigned long int hash_sdbm_salt(const char *str, const char *salt)
{
    unsigned long int hash = 0;
    const char *s;
    
    if (str == NULL) 
    {
        return 0;
    }
    
    /* Appliquer d'abord le sel */
    if (salt != NULL) 
    {
        s = salt;
        while (*s != '\0') 
	{
            hash = (unsigned char)*s + (hash << 6) + (hash << 16) - hash;
            s++;
        }
    }
    
    /* Puis la chaîne principale */
    s = str;
    while (*s != '\0') 
    {
        hash = (unsigned char)*s + (hash << 6) + (hash << 16) - hash;
        s++;
    }
    return hash;
}

/*
 * Fonction de hachage très simple pour débutants avec sel
 */
unsigned long int hash_simple_salt(const char *str, const char *salt)
{
    unsigned long int hash = 0;
    const unsigned long int prime = 31;
    const char *s;
    
    if (str == NULL) 
    {
        return 0;
    }
    /* Appliquer d'abord le sel */
    if (salt != NULL) 
    {
        s = salt;
        while (*s != '\0') 
	{
            hash = (hash * prime) + (unsigned char)*s;
            s++;
        }
    }
    /* Puis la chaîne principale */
    s = str;
    while (*s != '\0') 
    {
        hash = (hash * prime) + (unsigned char)*s;
        s++;
    }
    return hash;
}

/* 
 * Version originale sans sel (pour compatibilité)
 */
unsigned long int hash_djb2(const char *str)
{
    return hash_djb2_salt(str, NULL);
}

unsigned long int hash_sdbm(const char *str)
{
    return hash_sdbm_salt(str, NULL);
}

unsigned long int hash_simple(const char *str)
{
    return hash_simple_salt(str, NULL);
}

/*
 * Convertit un hash en chaîne hexadécimale
 */
static void hash_to_hex(unsigned long int hash, char *hex_buffer, size_t buf_size)
{
    if (buf_size >= 17) 
        {
        (void)sprintf(hex_buffer, "%08lX", hash);
        } 
    else if (buf_size > 0) 
        {
        hex_buffer[0] = '\0';
        }
}

/*
 * Génère un sel aléatoire simple
 */
static void generate_salt(char *salt_buffer, size_t length)
{
    static const char charset[] = 
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "0123456789"
        "./";
    
    size_t i;
    static int seeded = 0;
    
    if (length < 1) 
    {
        return;
    }
    
    /* Initialisation simple du générateur aléatoire */
    if (!seeded) 
    {
        srand((unsigned int)time(NULL));
        seeded = 1;
    }
    
    /* Génération du sel */
    for (i = 0; i < length - 1; i++) 
    {
        int key = rand() % (int)(sizeof(charset) - 1);
        salt_buffer[i] = charset[key];
    }
    salt_buffer[length - 1] = '\0';
}

/*
 * Affiche l'utilisation du programme
 */
static void print_usage(const char *prog_name)
{
    fprintf(stderr, "Usage: %s [options] \"chaine a hasher\"\n", prog_name);
    fprintf(stderr, "Options:\n");
    fprintf(stderr, "  -s    Utiliser l'algorithme simple (defaut)\n");
    fprintf(stderr, "  -d    Utiliser l'algorithme djb2\n");
    fprintf(stderr, "  -m    Utiliser l'algorithme sdbm\n");
    fprintf(stderr, "  -a    Afficher tous les algorithmes\n");
    fprintf(stderr, "  --salt \"SEL\"  Utiliser un sel specifique\n");
    fprintf(stderr, "  --random-salt Genere un sel aleatoire\n");
    fprintf(stderr, "  -h    Afficher cette aide\n");
}

/*
 * Programme principal
 */
int main(int argc, char *argv[])
{
    const char *input_string = NULL;
    const char *salt = NULL;
    int algorithm = 0; /* 0=simple, 1=djb2, 2=sdbm */
    int show_all = 0;
    char random_salt[17]; /* 16 caractères + null */
    int i;
    
    /* Analyse des arguments */
    for (i = 1; i < argc; i++) 
    {
        if (argv[i][0] == '-') 
	{
            if (strcmp(argv[i], "--salt") == 0 && i + 1 < argc) 
	    {
                salt = argv[++i];
            } 
	    else 
		if (strcmp(argv[i], "--random-salt") == 0) 
		{
                generate_salt(random_salt, sizeof(random_salt));
                salt = random_salt;
                } 
		else 
		{
                switch (argv[i][1]) 
		   {
                    case 's':
                        algorithm = 0;
                        break;
                    case 'd':
                        algorithm = 1;
                        break;
                    case 'm':
                        algorithm = 2;
                        break;
                    case 'a':
                        show_all = 1;
                        break;
                    case 'h':
                        print_usage(argv[0]);
                        return 0;
                    default:
                        fprintf(stderr, "Option inconnue: %s\n", argv[i]);
                        print_usage(argv[0]);
                        return 1;
                   }
                }
        } 
	else 
	{
            input_string = argv[i];
        }
    }
    
    /* Si aucune chaîne fournie, on utilise un exemple */
    if (input_string == NULL) 
    {
        fprintf(stderr, "Aucune chaine fournie.\n");
        print_usage(argv[0]);
        
        printf("\nExemple d'utilisation:\n");
        input_string = "Hello, World!";
        printf("Chaine par defaut: \"%s\"\n\n", input_string);
    }
    
    /* Calcul et affichage des hashs */
    if (show_all) 
    {
        unsigned long int hash1, hash2, hash3;
        char hex_buffer[17];
        
        printf("Resultats pour: \"%s\"\n", input_string);
        if (salt != NULL) {
            printf("Sel utilise: \"%s\"\n", salt);
        }
        printf("Longueur: %lu caracteres\n", 
               (unsigned long)strlen(input_string));
        printf("\n");
        
        printf("Algorithme        Hash (decimal)      Hash (hex)\n");
        printf("-------------     ---------------     ----------\n");
        
        hash1 = hash_simple_salt(input_string, salt);
        hash_to_hex(hash1, hex_buffer, sizeof(hex_buffer));
        printf("Simple            %-19lu 0x%s\n", hash1, hex_buffer);
        
        hash2 = hash_djb2_salt(input_string, salt);
        hash_to_hex(hash2, hex_buffer, sizeof(hex_buffer));
        printf("DJB2              %-19lu 0x%s\n", hash2, hex_buffer);
        
        hash3 = hash_sdbm_salt(input_string, salt);
        hash_to_hex(hash3, hex_buffer, sizeof(hex_buffer));
        printf("SDBM              %-19lu 0x%s\n", hash3, hex_buffer);
    } 
    else 
    {
        unsigned long int hash;
        char hex_buffer[17];
        const char *algo_name;
        
        switch (algorithm) {
            case 0:
                hash = hash_simple_salt(input_string, salt);
                algo_name = "simple";
                break;
            case 1:
                hash = hash_djb2_salt(input_string, salt);
                algo_name = "djb2";
                break;
            case 2:
                hash = hash_sdbm_salt(input_string, salt);
                algo_name = "sdbm";
                break;
            default:
                hash = hash_simple_salt(input_string, salt);
                algo_name = "simple";
                break;
        }
        
        hash_to_hex(hash, hex_buffer, sizeof(hex_buffer));
        
        printf("Algorithme: %s\n", algo_name);
        printf("Chaine: \"%s\"\n", input_string);
        if (salt != NULL) {
            printf("Sel: \"%s\"\n", salt);
        }
        printf("Hash (decimal): %lu\n", hash);
        printf("Hash (hexadecimal): 0x%s\n", hex_buffer);
        printf("Taille du hash: %lu bits\n", 
               (unsigned long)sizeof(hash) * 8);
    }
    
    return EXIT_SUCCESS;
}