PageRenderTime 27ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main.c

https://gitlab.com/xkcd-936/xkcd-936
C | 351 lines | 269 code | 73 blank | 9 comment | 44 complexity | bc15cb0f20903f53a2f419eee83133b0 MD5 | raw file
  1. #include <getopt.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <limits.h>
  5. #include <string.h>
  6. #include <math.h>
  7. #define DEFAULT_VALUE (4)
  8. const char * const DICT_PATH[] = {
  9. "/usr/share/dict/cracklib-small", /* Arch Linux */
  10. "/usr/share/dict/words" /* Fedora */
  11. };
  12. #define Sll_PUSH(ptr_head_, ptr_, ptr_next_) \
  13. do{ \
  14. if ( !ptr_head_ ) {\
  15. ptr_head_ = ptr_; ptr_->ptr_next_ = NULL;\
  16. } else {\
  17. ptr_->ptr_next_ = ptr_head_; ptr_head_ = ptr_;\
  18. }\
  19. } while (0)
  20. #define MALLOC_PTR(ptr_, size_, NAME) \
  21. do{\
  22. ptr_ = malloc(size_);\
  23. \
  24. if ( size_ && !ptr_ ) {\
  25. fprintf(stderr,"error: memory allocation - %s\n", NAME);\
  26. exit(1);\
  27. }\
  28. \
  29. } while(0)
  30. typedef struct dict_word dict_word;
  31. struct options_set {
  32. int size; /* min letters per words */
  33. int log_flag; /* write log? */
  34. int quick_flag; /* strong or weak entropy? */
  35. int words; /* number of words */
  36. };
  37. struct dict_word {
  38. char *word;
  39. int no;
  40. dict_word *ptr_next;
  41. };
  42. static void print_usage(struct option *, const char *);
  43. static void init_options(struct options_set *, int, char **);
  44. static void solve(struct options_set *);
  45. static int log_flag;
  46. static int quick_flag;
  47. static unsigned int seed_random(int, int);
  48. static void read_dict(int, int, int, int);
  49. static int comp(const void *, const void *);
  50. static int nb_word_dict(int);
  51. int main(int argc, char **argv);
  52. int main (int argc, char **argv)
  53. {
  54. struct options_set *ptr_opt_set;
  55. MALLOC_PTR(ptr_opt_set, sizeof(struct options_set), "options");
  56. ptr_opt_set->size = DEFAULT_VALUE; /* default is 4 letter words */
  57. ptr_opt_set->words = DEFAULT_VALUE; /* default is 4 words */
  58. ptr_opt_set->log_flag = 0;
  59. ptr_opt_set->quick_flag = 0;
  60. init_options(ptr_opt_set, argc, argv);
  61. solve(ptr_opt_set);
  62. return 0;
  63. }
  64. static void print_usage(struct option *long_option, const char *prog_name)
  65. {
  66. int opt_index;
  67. fprintf(stdout, "Usage: %s",prog_name);
  68. for ( opt_index = 0 ; opt_index < 5 ; opt_index++ ) {
  69. fprintf(stdout, " --%s",long_option[opt_index].name);
  70. if ( long_option[opt_index].val ) {
  71. fprintf(stdout, " (-%c)",long_option[opt_index].val);
  72. }
  73. if ( long_option[opt_index].has_arg )
  74. fprintf(stdout, " <value>");
  75. }
  76. fprintf(stdout, "\n");
  77. }
  78. static void init_options(struct options_set *ptr_opt_set, int argc, char **argv)
  79. {
  80. int cmd_line_opt;
  81. int value;
  82. static struct option long_options[] =
  83. {
  84. /* These options set a flag. */
  85. {"quick", no_argument, &quick_flag, 'q'},
  86. {"log", no_argument, &log_flag, 'l'},
  87. {"help", no_argument, 0, 'h'},
  88. /* These options don't set a flag.
  89. We distinguish them by their indices. */
  90. {"words", required_argument, 0, 'w'},
  91. {"size", required_argument, 0, 's'},
  92. {0, 0, 0, 0}
  93. };
  94. while (1)
  95. {
  96. /* getopt_long stores the option index here. */
  97. int option_index = 0;
  98. cmd_line_opt = getopt_long (argc, argv, "qlhw:s:",
  99. long_options, &option_index);
  100. /* Detect the end of the options. */
  101. if ( cmd_line_opt == -1 )
  102. break;
  103. if(log_flag)
  104. ptr_opt_set->log_flag = 1;
  105. if(quick_flag)
  106. ptr_opt_set->quick_flag = 1;
  107. switch ( cmd_line_opt )
  108. {
  109. case 0:
  110. /* If this option set a flag, do nothing else now. */
  111. if ( long_options[option_index].flag != 0 )
  112. break;
  113. if ( !strcmp(long_options[option_index].name,"help") ) {
  114. print_usage(long_options,argv[0]);
  115. exit(0);
  116. }
  117. if ( !strcmp(long_options[option_index].name,"words") ){
  118. value = atoi(optarg);
  119. if(value > 0)
  120. ptr_opt_set->words = atoi(optarg);
  121. }
  122. if ( !strcmp(long_options[option_index].name,"size") ) {
  123. value = atoi(optarg);
  124. if(value > 0)
  125. ptr_opt_set->size = atoi(optarg);
  126. }
  127. break;
  128. case 'w':
  129. value = atoi(optarg);
  130. if(value > 0)
  131. ptr_opt_set->words = atoi(optarg);
  132. break;
  133. case 's':
  134. value = atoi(optarg);
  135. if(value > 0)
  136. ptr_opt_set->size = atoi(optarg);
  137. break;
  138. case 'l':
  139. ptr_opt_set->log_flag = 1;
  140. break;
  141. case 'q':
  142. ptr_opt_set->quick_flag = 1;
  143. break;
  144. case 'h':
  145. print_usage(long_options,argv[0]);
  146. exit(0);
  147. case '?':
  148. /* getopt_long already printed an error message. */
  149. break;
  150. default:
  151. abort ();
  152. }
  153. }
  154. /* Print any remaining command line arguments (not options). */
  155. if ( optind < argc )
  156. {
  157. fprintf(stderr,"error: unknown option:\n");
  158. print_usage(long_options,argv[0]);
  159. exit (1);
  160. }
  161. }
  162. static void solve(struct options_set *ptr_opt_set)
  163. {
  164. read_dict(ptr_opt_set->words, ptr_opt_set->size, ptr_opt_set->log_flag, ptr_opt_set->quick_flag);
  165. }
  166. static unsigned int seed_random(int max_val, int quick)
  167. {
  168. /* generate a random */
  169. FILE *pfile = NULL;
  170. int size_of_read = sizeof(unsigned int);
  171. unsigned int random_number;
  172. double mapping_inv = (double)UINT_MAX/(double)max_val;
  173. double mapping = 1.0/mapping_inv;
  174. while(!pfile){
  175. if(quick)
  176. pfile = fopen("/dev/urandom","r");
  177. else
  178. pfile = fopen("/dev/random","r");
  179. }
  180. fread(&random_number, 1, size_of_read, pfile);
  181. fclose(pfile);
  182. return mapping * random_number;
  183. }
  184. static void read_dict(int nb_words, int nb_ltr, int flag, int flag2)
  185. {
  186. FILE *pfile = NULL;
  187. char *word = NULL;
  188. ssize_t read;
  189. size_t len = 0;
  190. int i,j,k;
  191. int ran;
  192. int no = 0;
  193. int pw_size = 0;
  194. int wd_size;
  195. int *numpw;
  196. int *snumpw;
  197. dict_word *ptr_dict = NULL;
  198. dict_word *ptr = NULL;
  199. dict_word **ptr_pw = NULL;
  200. double ent_bf;
  201. double ent_dc;
  202. MALLOC_PTR(numpw, nb_words*sizeof(int), "password array");
  203. MALLOC_PTR(snumpw,nb_words*sizeof(int), "sorted password array");
  204. MALLOC_PTR(ptr_pw,nb_words*sizeof(dict_word *), "password ref password array");
  205. pfile = NULL;
  206. no = nb_word_dict(nb_ltr);
  207. for(i = 0; i < nb_words ; i++)
  208. numpw[i] = seed_random(no,flag2);
  209. memcpy(snumpw,numpw,nb_words*sizeof(int));
  210. qsort(snumpw,nb_words,sizeof(int),comp);
  211. i = 0;
  212. do {
  213. pfile = fopen(DICT_PATH[i], "r");
  214. i++;
  215. } while(!pfile);
  216. i = 0;
  217. no = 0;
  218. while((read = getline(&word, &len, pfile)) != -1 && i < nb_words){
  219. if( (int) read < nb_ltr ) continue;
  220. if(no == snumpw[i]){
  221. MALLOC_PTR(ptr, sizeof(dict_word), "word list element");
  222. MALLOC_PTR(ptr->word, read, "the word");
  223. strncpy(ptr->word,word,read - 1);
  224. ptr->ptr_next = NULL;
  225. ptr->no = no;
  226. ptr_pw[i] = ptr;
  227. ++i;
  228. }
  229. ++no;
  230. }
  231. fclose(pfile);
  232. if(flag) fprintf(stdout, "your xkcd-936 password is: \n\n");
  233. for(i = 0; i < nb_words; i++){
  234. ptr = ptr_pw[i];
  235. for (j = 0; j < nb_words; j++)
  236. if(ptr_pw[j]->no == numpw[i]){
  237. wd_size = strlen(ptr->word);
  238. pw_size += wd_size;
  239. for(k = 0; k < wd_size; k++)
  240. fprintf(stdout, "%c",ptr->word[k]);
  241. break;
  242. }
  243. if(i < nb_words - 1 && flag) fprintf(stdout, "_");
  244. }
  245. fprintf(stdout, "\n");
  246. if(flag) fprintf(stdout, "\n The \"_\" should be removed. They are added for readability only\n");
  247. ent_bf = log(95.0)/log(2.0);
  248. ent_dc = log(1.0 * no)/log(2.0);
  249. if(flag){
  250. fprintf(stdout, "Brute force entropy is %f bits (total ; per symbol is %f)\n",1.0 * pw_size * ent_bf, ent_bf);
  251. fprintf(stdout, "Dictionary entropy is %f bits (total ; per symbol is %f)\n", 4.0 * ent_dc, ent_dc);
  252. }
  253. }
  254. static int comp(const void* pa, const void* pb)
  255. {
  256. int a = *(const int*)pa;
  257. int b = *(const int*)pb;
  258. if(a <= b)
  259. return -1;
  260. return 1;
  261. }
  262. static int nb_word_dict(int nb_ltr)
  263. {
  264. FILE *pfile;
  265. int no = 0;
  266. ssize_t read;
  267. size_t len;
  268. char *word = NULL;
  269. int i = 0;
  270. do {
  271. pfile = fopen(DICT_PATH[i], "r");
  272. i++;
  273. } while(!pfile);
  274. while((read = getline(&word, &len, pfile)) != -1)
  275. if( (int) read >= nb_ltr ) ++no;
  276. fclose(pfile);
  277. return no;
  278. }