/src/main.c
C | 351 lines | 269 code | 73 blank | 9 comment | 44 complexity | bc15cb0f20903f53a2f419eee83133b0 MD5 | raw file
- #include <getopt.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <limits.h>
- #include <string.h>
- #include <math.h>
- #define DEFAULT_VALUE (4)
- const char * const DICT_PATH[] = {
- "/usr/share/dict/cracklib-small", /* Arch Linux */
- "/usr/share/dict/words" /* Fedora */
- };
- #define Sll_PUSH(ptr_head_, ptr_, ptr_next_) \
- do{ \
- if ( !ptr_head_ ) {\
- ptr_head_ = ptr_; ptr_->ptr_next_ = NULL;\
- } else {\
- ptr_->ptr_next_ = ptr_head_; ptr_head_ = ptr_;\
- }\
- } while (0)
- #define MALLOC_PTR(ptr_, size_, NAME) \
- do{\
- ptr_ = malloc(size_);\
- \
- if ( size_ && !ptr_ ) {\
- fprintf(stderr,"error: memory allocation - %s\n", NAME);\
- exit(1);\
- }\
- \
- } while(0)
- typedef struct dict_word dict_word;
- struct options_set {
- int size; /* min letters per words */
- int log_flag; /* write log? */
- int quick_flag; /* strong or weak entropy? */
- int words; /* number of words */
- };
- struct dict_word {
- char *word;
- int no;
- dict_word *ptr_next;
- };
- static void print_usage(struct option *, const char *);
- static void init_options(struct options_set *, int, char **);
- static void solve(struct options_set *);
- static int log_flag;
- static int quick_flag;
- static unsigned int seed_random(int, int);
- static void read_dict(int, int, int, int);
- static int comp(const void *, const void *);
- static int nb_word_dict(int);
- int main(int argc, char **argv);
- int main (int argc, char **argv)
- {
- struct options_set *ptr_opt_set;
- MALLOC_PTR(ptr_opt_set, sizeof(struct options_set), "options");
- ptr_opt_set->size = DEFAULT_VALUE; /* default is 4 letter words */
- ptr_opt_set->words = DEFAULT_VALUE; /* default is 4 words */
- ptr_opt_set->log_flag = 0;
- ptr_opt_set->quick_flag = 0;
- init_options(ptr_opt_set, argc, argv);
- solve(ptr_opt_set);
- return 0;
- }
- static void print_usage(struct option *long_option, const char *prog_name)
- {
- int opt_index;
- fprintf(stdout, "Usage: %s",prog_name);
- for ( opt_index = 0 ; opt_index < 5 ; opt_index++ ) {
- fprintf(stdout, " --%s",long_option[opt_index].name);
- if ( long_option[opt_index].val ) {
- fprintf(stdout, " (-%c)",long_option[opt_index].val);
- }
- if ( long_option[opt_index].has_arg )
- fprintf(stdout, " <value>");
- }
- fprintf(stdout, "\n");
- }
- static void init_options(struct options_set *ptr_opt_set, int argc, char **argv)
- {
- int cmd_line_opt;
- int value;
- static struct option long_options[] =
- {
- /* These options set a flag. */
- {"quick", no_argument, &quick_flag, 'q'},
- {"log", no_argument, &log_flag, 'l'},
- {"help", no_argument, 0, 'h'},
- /* These options don't set a flag.
- We distinguish them by their indices. */
- {"words", required_argument, 0, 'w'},
- {"size", required_argument, 0, 's'},
- {0, 0, 0, 0}
- };
- while (1)
- {
- /* getopt_long stores the option index here. */
- int option_index = 0;
- cmd_line_opt = getopt_long (argc, argv, "qlhw:s:",
- long_options, &option_index);
- /* Detect the end of the options. */
- if ( cmd_line_opt == -1 )
- break;
- if(log_flag)
- ptr_opt_set->log_flag = 1;
- if(quick_flag)
- ptr_opt_set->quick_flag = 1;
- switch ( cmd_line_opt )
- {
- case 0:
- /* If this option set a flag, do nothing else now. */
- if ( long_options[option_index].flag != 0 )
- break;
- if ( !strcmp(long_options[option_index].name,"help") ) {
- print_usage(long_options,argv[0]);
- exit(0);
- }
- if ( !strcmp(long_options[option_index].name,"words") ){
- value = atoi(optarg);
- if(value > 0)
- ptr_opt_set->words = atoi(optarg);
- }
- if ( !strcmp(long_options[option_index].name,"size") ) {
- value = atoi(optarg);
- if(value > 0)
- ptr_opt_set->size = atoi(optarg);
- }
- break;
- case 'w':
- value = atoi(optarg);
- if(value > 0)
- ptr_opt_set->words = atoi(optarg);
- break;
- case 's':
- value = atoi(optarg);
- if(value > 0)
- ptr_opt_set->size = atoi(optarg);
- break;
- case 'l':
- ptr_opt_set->log_flag = 1;
- break;
- case 'q':
- ptr_opt_set->quick_flag = 1;
- break;
- case 'h':
- print_usage(long_options,argv[0]);
- exit(0);
- case '?':
- /* getopt_long already printed an error message. */
- break;
- default:
- abort ();
- }
- }
- /* Print any remaining command line arguments (not options). */
- if ( optind < argc )
- {
- fprintf(stderr,"error: unknown option:\n");
- print_usage(long_options,argv[0]);
- exit (1);
- }
- }
- static void solve(struct options_set *ptr_opt_set)
- {
- read_dict(ptr_opt_set->words, ptr_opt_set->size, ptr_opt_set->log_flag, ptr_opt_set->quick_flag);
- }
- static unsigned int seed_random(int max_val, int quick)
- {
- /* generate a random */
- FILE *pfile = NULL;
- int size_of_read = sizeof(unsigned int);
- unsigned int random_number;
- double mapping_inv = (double)UINT_MAX/(double)max_val;
- double mapping = 1.0/mapping_inv;
- while(!pfile){
- if(quick)
- pfile = fopen("/dev/urandom","r");
- else
- pfile = fopen("/dev/random","r");
- }
- fread(&random_number, 1, size_of_read, pfile);
- fclose(pfile);
- return mapping * random_number;
- }
- static void read_dict(int nb_words, int nb_ltr, int flag, int flag2)
- {
- FILE *pfile = NULL;
- char *word = NULL;
- ssize_t read;
- size_t len = 0;
- int i,j,k;
- int ran;
- int no = 0;
- int pw_size = 0;
- int wd_size;
- int *numpw;
- int *snumpw;
- dict_word *ptr_dict = NULL;
- dict_word *ptr = NULL;
- dict_word **ptr_pw = NULL;
- double ent_bf;
- double ent_dc;
- MALLOC_PTR(numpw, nb_words*sizeof(int), "password array");
- MALLOC_PTR(snumpw,nb_words*sizeof(int), "sorted password array");
- MALLOC_PTR(ptr_pw,nb_words*sizeof(dict_word *), "password ref password array");
- pfile = NULL;
- no = nb_word_dict(nb_ltr);
- for(i = 0; i < nb_words ; i++)
- numpw[i] = seed_random(no,flag2);
- memcpy(snumpw,numpw,nb_words*sizeof(int));
- qsort(snumpw,nb_words,sizeof(int),comp);
- i = 0;
- do {
- pfile = fopen(DICT_PATH[i], "r");
- i++;
- } while(!pfile);
- i = 0;
- no = 0;
- while((read = getline(&word, &len, pfile)) != -1 && i < nb_words){
- if( (int) read < nb_ltr ) continue;
- if(no == snumpw[i]){
- MALLOC_PTR(ptr, sizeof(dict_word), "word list element");
- MALLOC_PTR(ptr->word, read, "the word");
- strncpy(ptr->word,word,read - 1);
- ptr->ptr_next = NULL;
- ptr->no = no;
- ptr_pw[i] = ptr;
- ++i;
- }
- ++no;
- }
- fclose(pfile);
- if(flag) fprintf(stdout, "your xkcd-936 password is: \n\n");
- for(i = 0; i < nb_words; i++){
- ptr = ptr_pw[i];
- for (j = 0; j < nb_words; j++)
- if(ptr_pw[j]->no == numpw[i]){
- wd_size = strlen(ptr->word);
- pw_size += wd_size;
- for(k = 0; k < wd_size; k++)
- fprintf(stdout, "%c",ptr->word[k]);
- break;
- }
- if(i < nb_words - 1 && flag) fprintf(stdout, "_");
- }
- fprintf(stdout, "\n");
- if(flag) fprintf(stdout, "\n The \"_\" should be removed. They are added for readability only\n");
- ent_bf = log(95.0)/log(2.0);
- ent_dc = log(1.0 * no)/log(2.0);
- if(flag){
- fprintf(stdout, "Brute force entropy is %f bits (total ; per symbol is %f)\n",1.0 * pw_size * ent_bf, ent_bf);
- fprintf(stdout, "Dictionary entropy is %f bits (total ; per symbol is %f)\n", 4.0 * ent_dc, ent_dc);
- }
- }
- static int comp(const void* pa, const void* pb)
- {
- int a = *(const int*)pa;
- int b = *(const int*)pb;
- if(a <= b)
- return -1;
- return 1;
- }
- static int nb_word_dict(int nb_ltr)
- {
- FILE *pfile;
- int no = 0;
- ssize_t read;
- size_t len;
- char *word = NULL;
- int i = 0;
- do {
- pfile = fopen(DICT_PATH[i], "r");
- i++;
- } while(!pfile);
- while((read = getline(&word, &len, pfile)) != -1)
- if( (int) read >= nb_ltr ) ++no;
- fclose(pfile);
- return no;
- }