Generates partially mnemonic addresses for Duniter cryptocurrencies. https://github.com/jytou/vanitygen
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vanity_scrypt.c 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. #include "include/paste.h"
  2. /***************** MAIN PROGRAM ****************************/
  3. #define crypto_sign_ed25519_PUBLICKEYBYTES 32U
  4. #define crypto_sign_ed25519_SECRETKEYBYTES (32U + 32U)
  5. #define crypto_sign_ed25519_SEEDBYTES 32U
  6. #define SEED_SIZE 32U
  7. #define B58_SEED_SIZE 45U
  8. #define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
  9. // Used for checking the time took by the different calculations
  10. //#define MEASURE_TIME
  11. // Compute a B58 encoded public key using the password and salt provided, also return the raw public and secret keys found
  12. int computeB58PK(const uint8_t *pass, size_t passlen, const uint8_t *salt, size_t saltlen, uint8_t *seed, uint8_t *pk, uint8_t *sk, char *b58pk)
  13. {
  14. static const uint64_t N = 4096U;
  15. static const uint32_t r = 16U;
  16. static const uint32_t p = 1U;
  17. #ifdef MEASURE_TIME
  18. clock_t before = clock();
  19. #endif
  20. // Go ahead and encrypt the seed from pass+salt with scrypt
  21. if (crypto_pwhash_scryptsalsa208sha256_ll((const uint8_t *)pass, passlen, (const uint8_t *)salt, saltlen, N, r, p, seed, SEED_SIZE) != 0)
  22. {
  23. fprintf(stderr, "Error %i\n", errno);
  24. fflush(stderr);
  25. return 1;
  26. }
  27. #ifdef MEASURE_TIME
  28. clock_t middle = clock();
  29. #endif
  30. // Calculate the PK and SK from the seed
  31. crypto_sign_ed25519_seed_keypair(pk, sk, seed);
  32. #ifdef MEASURE_TIME
  33. clock_t end = clock();
  34. fprintf(stdout, "\nscrypt %d ed %d\n", (int)(middle - before), (int)(end - middle));
  35. fflush(stdout);
  36. #endif
  37. // Encode the seed in B58 encoding
  38. size_t b58pk_size = B58_SEED_SIZE;
  39. b58enc(b58pk, &b58pk_size, pk, crypto_sign_ed25519_PUBLICKEYBYTES);
  40. return 0;
  41. }
  42. // Regex (globals not pretty but does the job)
  43. const char** allregexs;
  44. regex_t * regex;
  45. int nbregexlines;
  46. #include <pthread.h>
  47. #include <unistd.h>
  48. // All threads currently active (this is totally reinstatiated when adding/removing a thread)
  49. pthread_t * all_threads;
  50. unsigned char ** thread_signals;
  51. // Nb of active threads
  52. int nb_threads = 0;
  53. // Nb of explored combinations
  54. int nb_explored = 0;
  55. // Nb found
  56. int nb_found = 0;
  57. // To make sure we don't write in "nb_explored" simultaneously
  58. pthread_mutex_t mutex_lock_explored;
  59. // To make sure we don't write on stdout simultaneously
  60. pthread_mutex_t mutex_lock_stdout;
  61. // 1 = generates pass+salt, 0 = only generate from seed (much faster but you won't be able to connect with cesium or sakia
  62. char generatePwdSalt = 1;
  63. int minCharsPwd = 16;
  64. int maxCharsPwd = 32;
  65. int minCharsSalt = 16;
  66. int maxCharsSalt = 32;
  67. int minWordsPwd = 6;
  68. int maxWordsPwd = 10;
  69. int minWordsSalt = 6;
  70. int maxWordsSalt = 10;
  71. #define BETWEEN_SPACES 0
  72. #define BETWEEN_SPECIAL 1
  73. #define BETWEEN_NONE 2
  74. // The file to which results should be written to. If null, only write to stdout
  75. FILE * resultfile;
  76. // Show to stdout. If this is 0, then only a "found" will be shown (with a timestamp).
  77. char resultStdout = 1;
  78. int betweenWords = BETWEEN_SPACES;
  79. // If 0 no capitalizing, if 1 capitalize all words
  80. char capitalize = 0;
  81. char * allwords = 0;
  82. int allwordssize;
  83. char * specialChars = "[]!@#$%^&*(){}=/+?-_',.;:0123456789";
  84. int specialCharsLen;
  85. // Generate a sentence from words
  86. int generateSentence(int minWords, int maxWords, char * result)
  87. {
  88. int numWords;
  89. if (minWords < maxWords)
  90. numWords = randint(maxWords - minWords) + minWords;
  91. else
  92. numWords = maxWords;
  93. int pos = 0, i;
  94. for (i = 0; i < numWords; i++)
  95. {
  96. int wordPos = randint(allwordssize);
  97. if (allwords[wordPos] == 0)
  98. // we have to go back until there is no 0
  99. while ((wordPos > 0) && (allwords[wordPos] == 0))
  100. wordPos--;
  101. while ((wordPos > 0) && (allwords[wordPos - 1] != 0))
  102. // We're not at the beginning of a word, look for it!
  103. wordPos--;
  104. int wordLen = strlen(allwords + wordPos);
  105. if (wordLen == 0)
  106. {
  107. // this is weird, we couldn't find a word
  108. i--;
  109. continue;
  110. }
  111. if (i > 0)
  112. {
  113. // Add some "glue"
  114. if (betweenWords == BETWEEN_SPACES)
  115. result[pos++] = ' ';
  116. else if (betweenWords == BETWEEN_SPECIAL)
  117. {
  118. int whichSpecial = randint(specialCharsLen);
  119. result[pos++] = specialChars[whichSpecial];
  120. }
  121. }
  122. memccpy(result + pos, allwords + wordPos, 0, wordLen);
  123. if (capitalize == 1)
  124. result[pos] = toupper(result[pos]);
  125. pos += wordLen;
  126. }
  127. result[pos] = 0;
  128. return pos;
  129. }
  130. // Shows the current time, along with statistics on number of keys found vs searched
  131. void showTimeAndDateFound()
  132. {
  133. time_t timer;
  134. char buffer[26];
  135. struct tm* tm_info;
  136. time(&timer);
  137. tm_info = localtime(&timer);
  138. strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
  139. pthread_mutex_lock(&mutex_lock_explored);
  140. int explored = nb_explored;
  141. pthread_mutex_unlock(&mutex_lock_explored);
  142. fprintf(stdout, "\r%s - %d found %d tried, %f %% total\n", buffer, nb_found, explored, (100.0 * nb_found) / explored);
  143. }
  144. // Find some nice public keys. Stop the process when "active" becomes false
  145. void findSome(unsigned char *active)
  146. {
  147. unsigned char pk[crypto_sign_ed25519_PUBLICKEYBYTES];
  148. unsigned char sk[crypto_sign_ed25519_SECRETKEYBYTES];
  149. uint8_t seed[SEED_SIZE];
  150. char b58pk[B58_SEED_SIZE];
  151. #define MAX_PASS_LEN 1024
  152. #define MAX_SALT_LEN 1024
  153. char pass[MAX_PASS_LEN];
  154. char salt[MAX_SALT_LEN];
  155. static const char* allowed = "1234567890[]!@#$%^&*(){}=/+?-_',.;:pyfgcrlaoeuidhtnsqjkxbmwvzAOEUIDHTNSQJKXBMWVZ";
  156. const int allowedlen = strlen(allowed);
  157. int reti, i;
  158. // Research loop
  159. do
  160. {
  161. if (generatePwdSalt)
  162. {
  163. int pass_len, salt_len;
  164. // Generate password and salt and everything from them
  165. if (allwords != 0)
  166. {
  167. // Generate from a list of words
  168. pass_len = generateSentence(minWordsPwd, maxWordsPwd, pass);
  169. salt_len = generateSentence(minWordsSalt, maxWordsSalt, salt);
  170. // fprintf(stdout, "generated pass %s, length %d\n", pass, pass_len);
  171. // fprintf(stdout, "generated salt %s, length %d\n", salt, salt_len);
  172. }
  173. else
  174. {
  175. // Generate pass + salt from random characters
  176. if (maxCharsPwd > minCharsPwd)
  177. pass_len = randint(maxCharsPwd - minCharsPwd) + minCharsPwd;
  178. else
  179. pass_len = maxCharsPwd;
  180. for (i = 0; i < pass_len; ++i)
  181. pass[i] = allowed[randint(allowedlen)];
  182. pass[pass_len] = 0;
  183. if (maxCharsSalt > minCharsSalt)
  184. salt_len = randint(maxCharsSalt - minCharsSalt) + minCharsSalt;
  185. else
  186. salt_len = maxCharsSalt;
  187. for (i = 0; i < salt_len; ++i)
  188. salt[i] = allowed[randint(allowedlen)];
  189. salt[salt_len] = 0;
  190. }
  191. int result = computeB58PK((const uint8_t *)pass, pass_len, (const uint8_t *)salt, salt_len, seed, pk, sk, b58pk);
  192. if (result != 0)
  193. break;
  194. }
  195. else
  196. {
  197. // Generate directly a seed and pk and sk from it
  198. for (i = 0; i < SEED_SIZE; ++i)
  199. seed[i] = randint(256) - 128;
  200. crypto_sign_ed25519_seed_keypair(pk, sk, seed);
  201. size_t b58pk_size = B58_SEED_SIZE;
  202. b58enc(b58pk, &b58pk_size, pk, crypto_sign_ed25519_PUBLICKEYBYTES);
  203. }
  204. // Look if it matches any regex
  205. for (i = 0; i < nbregexlines; ++i)
  206. {
  207. reti = regexec(&regex[i], b58pk, 0, NULL, 0);
  208. if (!reti)
  209. {
  210. // One match found!
  211. // Transform pk/sk into hex for humans - not really needed but keeping it in case
  212. // char hexsk[crypto_sign_ed25519_SECRETKEYBYTES * 2 + 1];
  213. // sodium_bin2hex(hexsk, crypto_sign_ed25519_SECRETKEYBYTES * 2 + 1, sk, crypto_sign_ed25519_SECRETKEYBYTES);
  214. // char hexpk[crypto_sign_ed25519_PUBLICKEYBYTES * 2 + 1];
  215. // sodium_bin2hex(hexpk, crypto_sign_ed25519_PUBLICKEYBYTES * 2 + 1, pk, crypto_sign_ed25519_PUBLICKEYBYTES);
  216. // Make sure we don't write at the same time than someone else
  217. pthread_mutex_lock(&mutex_lock_stdout);
  218. nb_found++;
  219. if (generatePwdSalt)
  220. {
  221. if (resultStdout == 1)
  222. fprintf(stdout, "\r\"%s\" \"%s\" \"%s\" \"%s\"\n", allregexs[i], b58pk, pass, salt);
  223. else
  224. showTimeAndDateFound();
  225. if (resultfile != NULL)
  226. fprintf(resultfile, "\"%s\" \"%s\" \"%s\" \"%s\"\n", allregexs[i], b58pk, pass, salt);
  227. }
  228. else
  229. {
  230. // Need to transform the seed to hex for readability
  231. char hexseed[SEED_SIZE * 2 + 1];
  232. sodium_bin2hex(hexseed, sizeof hexseed, seed, SEED_SIZE);
  233. if (resultStdout == 1)
  234. fprintf(stdout, "\r\"%s\" \"%s\" \"%s\"\n", allregexs[i], b58pk, hexseed);
  235. else
  236. showTimeAndDateFound();
  237. if (resultfile != NULL)
  238. fprintf(resultfile, "\"%s\" \"%s\" \"%s\"\n", allregexs[i], b58pk, hexseed);
  239. }
  240. fflush(stdout);
  241. if (resultfile != NULL)
  242. fflush(resultfile);
  243. // Release stdout for others
  244. pthread_mutex_unlock(&mutex_lock_stdout);
  245. }
  246. else if (reti != REG_NOMATCH)
  247. {
  248. // Woops something bad happened
  249. char msgbuf[100];
  250. regerror(reti, &regex[i], msgbuf, sizeof(msgbuf));
  251. fprintf(stderr, "Regex match failed for %s: %s\n", allregexs[i], msgbuf);
  252. fflush(stderr);
  253. exit(1);
  254. } // else no match, ignore this
  255. }
  256. // Explored one more possibility
  257. pthread_mutex_lock(&mutex_lock_explored);
  258. nb_explored++;
  259. pthread_mutex_unlock(&mutex_lock_explored);
  260. }
  261. while (*active == 1);
  262. }
  263. // Do a sample computation to make sure that we're not computing garbage (depending on the plotform, compilers, etc. this might avoid some bad surprise)
  264. void verifyB58Generation()
  265. {
  266. unsigned char pk[crypto_sign_ed25519_PUBLICKEYBYTES];
  267. unsigned char sk[crypto_sign_ed25519_SECRETKEYBYTES];
  268. uint8_t seed[SEED_SIZE];
  269. char b58pk[B58_SEED_SIZE];
  270. static char * pass = "mypass";
  271. static char * salt = "mysalt";
  272. int result = computeB58PK((const uint8_t *)pass, strlen(pass), (const uint8_t *)salt, strlen(salt), seed, pk, sk, b58pk);
  273. if (result != 0)
  274. {
  275. fprintf(stderr, "Could not compute test B58PK\n");
  276. fflush(stderr);
  277. exit(1);
  278. }
  279. char *expectedB58pk = "AS5AYWFoetUztuEZX6sNNTYusz2n7QccPBQBkhteBUfX";
  280. if (strcmp(b58pk, expectedB58pk) != 0)
  281. {
  282. fprintf(stderr, "Test B58PK failed, it produced %s but expecting %s\n", b58pk, expectedB58pk);
  283. fflush(stderr);
  284. exit(1);
  285. }
  286. else
  287. {
  288. fprintf(stdout, "Test B58PK successful\n");
  289. fflush(stdout);
  290. }
  291. }
  292. #ifdef __WIN32__
  293. #include <windows.h>
  294. #elif __MACOS__
  295. #include <sys/param.h>
  296. #include <sys/sysctl.h>
  297. #else
  298. #include <unistd.h>
  299. #endif
  300. // Retrieves the number of cores on the system to know how many threads we can launch
  301. int getNumCores()
  302. {
  303. #ifdef __WIN32__
  304. SYSTEM_INFO sysinfo;
  305. GetSystemInfo(&sysinfo);
  306. return sysinfo.dwNumberOfProcessors;
  307. #elif __MACOS__
  308. int nm[2];
  309. size_t len = 4;
  310. uint32_t count;
  311. nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
  312. sysctl(nm, 2, &count, &len, NULL, 0);
  313. if(count < 1) {
  314. nm[1] = HW_NCPU;
  315. sysctl(nm, 2, &count, &len, NULL, 0);
  316. if(count < 1) { count = 1; }
  317. }
  318. return count;
  319. #else
  320. return sysconf(_SC_NPROCESSORS_ONLN);
  321. #endif
  322. }
  323. #include <unistd.h>
  324. #include <termios.h>
  325. #include <sys/ioctl.h>
  326. #ifdef __SOLARIS__
  327. #include <sys/filio.h>
  328. #endif
  329. // Capture input so that the user can interact with the console
  330. void captureStdin()
  331. {
  332. struct termios old = {0};
  333. if (tcgetattr(0, &old) < 0)
  334. perror("tcsetattr()");
  335. old.c_lflag &= ~ICANON;
  336. old.c_lflag &= ~ECHO;
  337. old.c_cc[VMIN] = 1;
  338. old.c_cc[VTIME] = 0;
  339. if (tcsetattr(0, TCSANOW, &old) < 0)
  340. perror("tcsetattr ICANON");
  341. }
  342. // Release it when we stop the program
  343. void releaseStdin()
  344. {
  345. struct termios old = {0};
  346. if (tcgetattr(0, &old) < 0)
  347. perror("tcsetattr()");
  348. old.c_lflag |= ICANON;
  349. old.c_lflag |= ECHO;
  350. if (tcsetattr(0, TCSADRAIN, &old) < 0)
  351. perror ("tcsetattr ~ICANON");
  352. }
  353. // Utility: read a character from stdin
  354. char getch()
  355. {
  356. char buf = 0;
  357. int nbAvail;
  358. ioctl(0, FIONREAD, &nbAvail);
  359. if (nbAvail > 0)
  360. if (read(0, &buf, 1) < 0)
  361. perror ("read()");
  362. return (buf);
  363. }
  364. // Launches the thread number "iLong" and populate all_threads
  365. void launch_thread(long iLong)
  366. {
  367. thread_signals[iLong] = malloc(sizeof(unsigned char));
  368. *thread_signals[iLong] = 1;
  369. pthread_create(&all_threads[iLong], NULL, (void*)&findSome, (void*)thread_signals[iLong]);
  370. }
  371. // Add one new thread, recalculate all_threads
  372. void add_thread()
  373. {
  374. unsigned char** old_signals = thread_signals;
  375. thread_signals = malloc((nb_threads + 1) * sizeof(unsigned char*));
  376. memcpy(thread_signals, old_signals, nb_threads * sizeof(unsigned char*));
  377. free(old_signals);
  378. pthread_t * old_array = all_threads;
  379. all_threads = malloc((nb_threads + 1) * sizeof(pthread_t*));
  380. memcpy(all_threads, old_array, nb_threads * sizeof(pthread_t*));
  381. free(old_array);
  382. launch_thread(nb_threads);
  383. nb_threads++;
  384. }
  385. // Signal thread number "iLong" to stop
  386. void stop_thread(long iLong)
  387. {
  388. *thread_signals[iLong] = 0;
  389. }
  390. // Removes the last thread and recalculate all_threads
  391. void remove_thread()
  392. {
  393. stop_thread(nb_threads - 1);
  394. unsigned char ** old_signals = thread_signals;
  395. thread_signals = malloc((nb_threads - 1) * sizeof(unsigned char*));
  396. memcpy(thread_signals, old_signals, (nb_threads - 1) * sizeof(unsigned char*));
  397. free(old_signals);
  398. pthread_t * old_array = all_threads;
  399. all_threads = malloc((nb_threads - 1) * sizeof(pthread_t*));
  400. memcpy(all_threads, old_array, (nb_threads - 1) * sizeof(pthread_t*));
  401. nb_threads--;
  402. free(old_array);
  403. }
  404. void usage()
  405. {
  406. fprintf(stdout, "Usage: [-s][-n min max][-r|-R resultfile][-w wordfile [-f filler_type][-c]] regexfile\n\n");
  407. fprintf(stdout, "\t-n min,max (optional): minimum and maximum number of characters/words to use to generate passwords.\n");
  408. fprintf(stdout, "\t-w wordfile (optional): generate passwords/salt using a list of words contained in the file \"wordfile\", rather than simply random characters.\n");
  409. fprintf(stdout, "\t\t-f type (optional) filler type between words: 0=spaces (default), 1=special characters and numbers, 2=none.\n");
  410. fprintf(stdout, "\t\t-c (optional): capitalize words (non capitalized by default - you can also capitalize the words in the given file).\n");
  411. fprintf(stdout, "\t-t threads (optional): start with \"threads\" parallel threads (the default is half the number of cores found).\n");
  412. fprintf(stdout, "\t-r resultfile (optional): a file to which the results should be written to.\n");
  413. fprintf(stdout, "\t-R resultfile (optional): same as -r, but do not show the results found on the standard output.\n");
  414. fprintf(stdout, "\t-s (optional): Do not generate password/salt, but only a seed (!!!WARNING!!! You will not be able to connect with Sakia or Cesium with this).\n");
  415. fprintf(stdout, "\t regexfile (required): a file containing a list of regex (one per line). Lines beginning by a tab are ignored.\n");
  416. fprintf(stdout, "\nRegex examples:\n");
  417. fprintf(stdout, "\tPublic Key starting with \"duniter\" not case sensitive: \"^[Dd][Uu][Nn][Ii][Tt][Ee][rR]\"\n");
  418. fprintf(stdout, "\tPublic Key containing \"Duniter\" case sensitive: \"Duniter\"\n");
  419. fprintf(stdout, "\tPublic Key ending with \"Freedom\" (including hacker style :p ): \"[fF][rR][eE3][eE3][dD][oO0][mM]$\"\n\n");
  420. fprintf(stdout, "Usage examples:\n");
  421. fprintf(stdout, "\tBasic with regex: regex.txt\n");
  422. fprintf(stdout, "\t\tExample of generated password/salt: \"q,d/dQ[i6-?_w$,#I/yu\"\n\n");
  423. fprintf(stdout, "\tGenerate with a word file, using from 6 to 10 words, capitalized: -w words.txt -n 6,10 -c regex.txt\n");
  424. fprintf(stdout, "\t\tExample of generated password/salt: \"Apple Factory Jump Music Truck Buddha Movie Fountain\"\n\n");
  425. fprintf(stdout, "\tGenerate with a word file, using random and numeric characters as separators: -w words.txt -f 1 regex.txt\n");
  426. fprintf(stdout, "\t\tExample of generated password/salt: \"apple!factory5jump;music-truck9buddha<movie(fountain\"\n\n");
  427. fflush(stdout);
  428. }
  429. void warning() {
  430. fprintf(stdout, " *****************************************************************************************\n");
  431. fprintf(stdout, " *** !!!WARNING!!! GENERATING FROM SEEDS DOES NOT ALLOW TO CONNECT VIA SAKIA OR CESIUM ***\n");
  432. fprintf(stdout, " *** USE AT YOUR OWN RISK ***\n");
  433. fprintf(stdout, " *****************************************************************************************\n");
  434. return;
  435. }
  436. #include <stdbool.h>
  437. #include <getopt.h>
  438. #include <stdlib.h>
  439. // settings to run the generator on
  440. struct Settings {
  441. int min;
  442. int max;
  443. char *words; // wordfile
  444. int filler;
  445. bool caps;
  446. char *results; // results file
  447. bool nowrite; // is -R flag set?
  448. bool seed;
  449. char *regex;
  450. int threads;
  451. };
  452. // note: allocates memory to buffer - use free when done.
  453. char *readfile(const char *filename) {
  454. char *buffer = NULL;
  455. FILE *fp = fopen(filename, "r");
  456. if (fp == NULL) {
  457. fprintf(stderr, "Could not find file %s, exiting.\n", filename);
  458. fflush(stderr);
  459. return NULL;
  460. }
  461. fseek(fp, 0L, SEEK_END);
  462. int filesize = ftell(fp);
  463. fseek(fp, 0L, SEEK_SET);
  464. buffer = malloc(sizeof(char) * filesize + 1);
  465. if (buffer == NULL) {
  466. fprintf(stderr, "Error: buffer not initialized.\n");
  467. return NULL;
  468. }
  469. size_t len = fread(buffer, sizeof(char), filesize, fp);
  470. if (ferror(fp) != 0) {
  471. fprintf(stderr, "Error while reading file.\n");
  472. return NULL;
  473. } else {
  474. buffer[len + 1] = '\0';
  475. }
  476. fclose(fp);
  477. return buffer;
  478. }
  479. int countlines(const char * const buf, int len) {
  480. #define DELIM "\n"
  481. #define IGNORE '\t'
  482. char *copy = malloc(sizeof(char) * len);
  483. strcpy(copy, buf);
  484. char *t = strtok(copy, DELIM);
  485. int count = 0;
  486. while (t != NULL) {
  487. // check first element of token for tab character
  488. if (t[0] != IGNORE) {
  489. count++;
  490. }
  491. t = strtok(NULL, DELIM);
  492. }
  493. free(copy);
  494. return count;
  495. }
  496. bool readregex(const char *regexfile) {
  497. fprintf(stdout, "Reading file %s...\n", regexfile);
  498. char * buf = readfile(regexfile);
  499. if (buf == NULL || regexfile == NULL) {
  500. return false;
  501. }
  502. int filesize = strlen(buf);
  503. int count = countlines(buf, filesize);
  504. fprintf(stdout, "%d regex found\n", count);
  505. fflush(stdout);
  506. nbregexlines = count;
  507. // Now read, interpret them and store them as pure regex
  508. allregexs = malloc(nbregexlines * sizeof(char*));
  509. regex = malloc(nbregexlines * sizeof(regex_t));
  510. int curregex = 0;
  511. int reti;
  512. char *t = strtok(buf, "\n");
  513. while (t != NULL) {
  514. if (t[0] != '\t') {
  515. char *oneregex;
  516. allregexs[curregex] = oneregex = t;
  517. // Compile regular expression
  518. reti = regcomp(&regex[curregex], allregexs[curregex], 0);
  519. if (reti) {
  520. fprintf(stderr, "Could not compile regex\n");
  521. fflush(stderr);
  522. exit(1);
  523. }
  524. fprintf(stdout, "Searching for \"%s\"\n", oneregex);
  525. fflush(stdout);
  526. curregex++;
  527. }
  528. t = strtok(NULL, "\n");
  529. }
  530. // do not free 'buf' - contents are now pointed by allregexs
  531. return true;
  532. }
  533. bool parseargs(const int argc, char * const *argv, struct Settings *s) {
  534. bool is_ok = true;
  535. int c = 0;
  536. struct option long_options[] = {
  537. {"number", required_argument, NULL, 'n'},
  538. {"wordfile", required_argument, NULL, 'w'},
  539. {"filler", required_argument, NULL, 'f'},
  540. {"capitalize", no_argument, NULL, 'c'},
  541. {"results", required_argument, NULL, 'r'}, // write results to file
  542. {"results2", required_argument, NULL, 'R'}, // above w/o console out
  543. {"seed", no_argument, NULL, 's'},
  544. {"help", no_argument, NULL, 'h'},
  545. {"threads", required_argument, NULL, 't'},
  546. {0, 0, 0, 0}
  547. };
  548. // char *optarg;
  549. // char optopt;
  550. while(optind < argc) {
  551. int options_index = 0;
  552. c = getopt_long (argc,
  553. argv,
  554. "n:w:f:cr:R:sx:ht:",
  555. long_options,
  556. &options_index
  557. );
  558. if (c == -1) {
  559. s -> regex = argv[optind];
  560. optind++;
  561. continue;
  562. } else if (c == 'x') {
  563. s -> regex = optarg;
  564. continue;
  565. } else if (c == 'c') {
  566. s -> caps = true;
  567. continue;
  568. } else if (c == 's') {
  569. s -> seed = true;
  570. continue;
  571. } else if (c == 'h') {
  572. usage();
  573. exit(1);
  574. }
  575. if (optarg == NULL) {
  576. fprintf(stderr, "error: %c arg is NULL\n", c);
  577. return false;
  578. }
  579. switch(c) {
  580. case 'n':;
  581. #define min(a,b) (a<b?a:b)
  582. #define max(a,b) (a>b?a:b)
  583. char seps[] = ",";
  584. if (strchr(optarg, ',') == NULL) {
  585. return false;
  586. }
  587. int a = atoi(strtok(optarg, seps));
  588. int b = atoi(strtok(NULL, seps));
  589. if (a * b == 0) {
  590. is_ok = false;
  591. } else {
  592. s -> min = min(a, b);
  593. s -> max = max(a, b);
  594. }
  595. break;
  596. case 'w':
  597. s -> words = optarg;
  598. break;
  599. case 'f':
  600. s -> filler = atoi(optarg);
  601. break;
  602. case 'r':
  603. s -> results = optarg;
  604. break;
  605. case 'R':
  606. s -> results = optarg;
  607. s -> nowrite = true;
  608. break;
  609. case 't':
  610. s -> threads = atoi(optarg);
  611. break;
  612. }
  613. } //end while
  614. return is_ok;
  615. }
  616. int main(int argc, char *argv[])
  617. {
  618. if (argc == 1) {
  619. fprintf(stdout, "This is vanitygen. ");
  620. fflush(stdout);
  621. fprintf(stderr, "At least one argument required. See -h for help.\n");
  622. return 0;
  623. }
  624. struct Settings s = {
  625. 0, 0, NULL, 0, false, NULL, false, false, NULL, 0
  626. };
  627. if (parseargs(argc, argv, &s) == false) {
  628. fprintf(stderr, "Initialization failed.\n");
  629. return -1;
  630. }
  631. if (s.regex == NULL) {
  632. fprintf(stderr, "Exiting: no regex file specified.\n");
  633. return -1;
  634. }
  635. specialCharsLen = strlen(specialChars);// TODO move to the place where we specify special chars
  636. #ifdef CHECK_MEMORY
  637. nb_threads = 1;
  638. #else
  639. nb_threads = getNumCores() / 2;
  640. #endif
  641. // -h, --help is handled by parseargs()
  642. if (s.results != NULL) {
  643. // open the file and read it.
  644. resultfile = fopen(s.results, "a");
  645. if (resultfile == NULL) {
  646. fprintf(stderr, "Could not open file %s for writing, exiting\n", s.results);
  647. fflush(stderr);
  648. return -1;
  649. }
  650. }
  651. if (s.threads > 0) {
  652. // -t is not in the readme.
  653. nb_threads = s.threads;
  654. }
  655. if (s.seed) {
  656. // display warning
  657. // set global variable
  658. warning();
  659. generatePwdSalt = 0;
  660. }
  661. if (s.words != NULL) {
  662. // global var to hold file contents is 'allwords'
  663. #define LF 10 // ASCII line feed
  664. #define CR 13 // ASCII carriage return
  665. #define NUL 0 // ASCII nul
  666. char *buf = readfile(s.words);
  667. if (buf == NULL) {
  668. exit(1);
  669. }
  670. unsigned int len = strlen(buf);
  671. allwordssize = len;
  672. allwords = malloc(len);
  673. for (unsigned int i = 0; i < len; ++i) {
  674. char c = buf[i];
  675. allwords[i] = (c == LF || c == CR) ? NUL : c;
  676. }
  677. free(buf);
  678. }
  679. if (s.min * s.max > 0) {
  680. // display warning for s.min < 6
  681. if (s.min < 6) {
  682. fprintf(stdout, "**** !!! WARNING !!! IT IS HIGHLY DISCOURAGED TO USE LESS THAN 6 ELEMENTS ****\n\n");
  683. fflush(stdout);
  684. }
  685. // set global variable
  686. minCharsPwd = minCharsSalt = minWordsPwd = minWordsSalt = s.min;
  687. maxCharsPwd = maxCharsSalt = maxWordsPwd = maxWordsSalt = s.max;
  688. ;
  689. }
  690. if (s.filler > 0) {
  691. // set global variable 'betweenWords'
  692. betweenWords = s.filler;
  693. }
  694. if (s.caps) {
  695. // set the global variable.
  696. capitalize = 1;
  697. }
  698. // Verify that the compiled version generates correct B58 pub key for a given pair of pass/salt (some platforms may need some extra touch - eg big endian for instance)
  699. verifyB58Generation();
  700. // Read and interpret regex from a file for matching
  701. if (readregex(s.regex) == false) {
  702. fprintf(stdout, "Exiting: no regex detected.");
  703. return 0;
  704. }
  705. fprintf(stdout, "\nStarting search. Press + and - to add/remove threads, q to quit\n");
  706. if (generatePwdSalt)
  707. fprintf(stdout, "Output is in the form \"matching regex\" \"public key\" \"password\" \"salt\"\n");
  708. else
  709. fprintf(stdout, "Output is in the form \"matching regex\" \"public key\" \"seed\"\n");
  710. fflush(stdout);
  711. // Tricks so that the user can directly type the keyboard without affecting the output
  712. captureStdin();
  713. srand(time(NULL));
  714. // Initialize semaphores
  715. pthread_mutex_init(&mutex_lock_explored, NULL);
  716. pthread_mutex_init(&mutex_lock_stdout, NULL);
  717. all_threads = malloc(nb_threads * sizeof(pthread_t*));
  718. thread_signals = malloc(nb_threads * sizeof(char*));
  719. long iLong;
  720. for (iLong = 0; iLong < nb_threads; ++iLong)
  721. launch_thread(iLong);
  722. // The number of last keys found to take into account for speed statistics
  723. #define STAT_WINDOW_SIZE 10
  724. // Structures to make statistics on the speed
  725. int nbGen[STAT_WINDOW_SIZE + 1];
  726. nbGen[0] = 0;
  727. struct timespec clocks[STAT_WINDOW_SIZE + 1];
  728. clock_gettime(CLOCK_MONOTONIC, &clocks[0]);
  729. int startStat = 0;
  730. int curClock = 0;
  731. int curWaitingChar = 0;
  732. // Nice waiting animation ASCII-style
  733. char waitingChars[] = "/-\\|";
  734. int iteration = 0;
  735. int maxWaitingChars = strlen(waitingChars);
  736. int i;
  737. // Loop of showing stats / waiting for user input
  738. do
  739. {
  740. sleep(1);
  741. if (curWaitingChar >= maxWaitingChars)
  742. curWaitingChar = 0;
  743. iteration++;
  744. // Where we are in the different times in the stat window
  745. curClock++;
  746. if (curClock > STAT_WINDOW_SIZE)
  747. curClock = 0;
  748. if (iteration > STAT_WINDOW_SIZE)
  749. startStat++;
  750. if (startStat > STAT_WINDOW_SIZE)
  751. startStat = 0;
  752. // Retrieve current achievement...
  753. pthread_mutex_lock(&mutex_lock_explored);
  754. nbGen[curClock] = nb_explored;
  755. pthread_mutex_unlock(&mutex_lock_explored);
  756. // ... and current time
  757. clock_gettime(CLOCK_MONOTONIC, &clocks[curClock]);
  758. // Show stats
  759. if (iteration >= STAT_WINDOW_SIZE)
  760. {
  761. // Compute the diff between first and last in the window
  762. double time_elapsed_in_seconds = (clocks[curClock].tv_sec - clocks[startStat].tv_sec);
  763. time_elapsed_in_seconds += (clocks[curClock].tv_nsec - clocks[startStat].tv_nsec)/1000000000.0;
  764. double nbPerSecond = (nbGen[curClock] - nbGen[startStat]) / time_elapsed_in_seconds;
  765. // Show the result
  766. pthread_mutex_lock(&mutex_lock_stdout);
  767. fprintf(stdout, "\r%c %d threads at %f / s", waitingChars[curWaitingChar++], nb_threads, nbPerSecond);
  768. fflush(stdout);
  769. pthread_mutex_unlock(&mutex_lock_stdout);
  770. }
  771. else
  772. {
  773. // Not enough data yet, initializing
  774. pthread_mutex_lock(&mutex_lock_stdout);
  775. fprintf(stdout, "\r%c initializing...", waitingChars[curWaitingChar++]);
  776. fflush(stdout);
  777. pthread_mutex_unlock(&mutex_lock_stdout);
  778. }
  779. // Ugly fix to remove any extra characters from previous displays
  780. for (i = 0; i < 30; ++i)
  781. fprintf(stdout, " ");
  782. for (i = 0; i < 30; ++i)
  783. fprintf(stdout, "\b");
  784. // Listen to what the user has to say
  785. int c;
  786. if ((c = getch()) != 0)
  787. {
  788. if (c == 'q')
  789. {
  790. // TODO signal threads should stop and wait to quit in a cleaner manner
  791. fprintf(stdout, "\nQuitting.\n");
  792. fflush(stdout);
  793. break;
  794. }
  795. else if (c == '+')
  796. {
  797. // One more thread
  798. pthread_mutex_lock(&mutex_lock_stdout);
  799. fprintf(stdout, " Adding a new thread...");
  800. fflush(stdout);
  801. pthread_mutex_unlock(&mutex_lock_stdout);
  802. add_thread();
  803. }
  804. else if (c == '-')
  805. {
  806. // One thread less
  807. if (nb_threads > 0)
  808. {
  809. pthread_mutex_lock(&mutex_lock_stdout);
  810. fprintf(stdout, " Removing a thread...");
  811. fflush(stdout);
  812. pthread_mutex_unlock(&mutex_lock_stdout);
  813. remove_thread();
  814. }
  815. }
  816. }
  817. } while (1);
  818. if (resultfile != NULL)
  819. {
  820. pthread_mutex_lock(&mutex_lock_stdout);
  821. fclose(resultfile);
  822. resultfile = NULL;
  823. pthread_mutex_unlock(&mutex_lock_stdout);
  824. }
  825. // Don't forget to release stdin otherwise the terminal will behave incorrectly
  826. releaseStdin();
  827. exit(0);
  828. }