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.
249 lines
6.6 KiB
249 lines
6.6 KiB
/* worgen - generates word combinations out of one to three word lists.
|
|
* A helper utility for the eschalot tor names generator. */
|
|
|
|
/*
|
|
* Copyright (c) 2013 Unperson Hiro <blacksunhq56imku.onion>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <getopt.h>
|
|
#include <inttypes.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#define VERSION "1.2.0"
|
|
|
|
/* constants */
|
|
#define MAX_WORDS 0xFFFFFFFFu
|
|
#define MAX_LEN 16
|
|
#define BASE32_ALPHABET "abcdefghijklmnopqrstuvwxyz234567"
|
|
|
|
extern char *__progname;
|
|
|
|
struct f {
|
|
unsigned int minlen;
|
|
unsigned int maxlen;
|
|
unsigned int wordcount;
|
|
char fn[FILENAME_MAX + 1];
|
|
char **words;
|
|
};
|
|
|
|
void readfile(struct f *);
|
|
void usage(void);
|
|
void error(char *, ...);
|
|
void verbose(char *, ...);
|
|
void normal(char *, ...);
|
|
void (*msg)(char *, ...) = verbose;
|
|
size_t mystrnlen(const char *, size_t);
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
struct f w[4];
|
|
signed int lists = -1;
|
|
unsigned int i, j, k, len1, len2, len3;
|
|
|
|
/* Arguments processing */
|
|
if (argc != 4 && argc != 6 && argc != 8)
|
|
usage();
|
|
|
|
for (i = 0; i < (unsigned int)argc; i += 2) {
|
|
j = i / 2;
|
|
strncpy(w[j].fn, argv[i], FILENAME_MAX);
|
|
w[j].minlen = strtoul(argv[i + 1], NULL, 0);
|
|
w[j].maxlen = strtoul(strchr(argv[i + 1], '-') + 1, NULL, 0);
|
|
w[j].wordcount = 0;
|
|
w[j].words = NULL;
|
|
lists++;
|
|
if (i == 0)
|
|
msg("Will be producing %d-%d character long word combinations.\n",
|
|
w[j].minlen, w[j].maxlen, w[j].fn);
|
|
else
|
|
msg("Reading %d-%d characters words from %s.\n",
|
|
w[j].minlen, w[j].maxlen, w[j].fn);
|
|
|
|
/* Basic sanity checks */
|
|
if (!w[j].minlen || !w[j].maxlen || w[j].maxlen > MAX_LEN)
|
|
usage();
|
|
}
|
|
|
|
/* Read words from files */
|
|
for (i = 1; i <= (unsigned int)lists; i++) {
|
|
readfile(&w[i]);
|
|
}
|
|
|
|
/* Mix it up */
|
|
for (i = 0; i < w[1].wordcount; i++) {
|
|
fprintf(stderr, "\rWorking. %d%% complete, %d words (approximately %dMb) produced.",
|
|
(i + 1) * 100 / w[1].wordcount, w[0].wordcount,
|
|
(w[0].wordcount /1024 / 1024 * ((w[0].minlen + w[0].maxlen) / 2 + 1)));
|
|
fflush(stderr);
|
|
|
|
len1 = mystrnlen(w[1].words[i], MAX_LEN);
|
|
if (len1 < w[1].minlen || len1 > w[1].maxlen)
|
|
continue;
|
|
|
|
if (len1 >= w[0].minlen && len1 <= w[0].maxlen) {
|
|
printf("%s\n", w[1].words[i]);
|
|
w[0].wordcount++;
|
|
}
|
|
|
|
for (j = 0; j < w[2].wordcount && lists > 1; j++) {
|
|
len2 = mystrnlen(w[2].words[j], MAX_LEN);
|
|
if (len2 < w[2].minlen || len2 > w[2].maxlen)
|
|
continue;
|
|
|
|
if (len1 + len2 >= w[0].minlen && len1 + len2 <= w[0].maxlen) {
|
|
printf("%s%s\n", w[1].words[i], w[2].words[j]);
|
|
w[0].wordcount++;
|
|
}
|
|
|
|
for (k = 0; k < w[3].wordcount && lists > 2; k++) {
|
|
len3 = mystrnlen(w[3].words[k], MAX_LEN);
|
|
if (len3 < w[3].minlen || len3 > w[3].maxlen)
|
|
continue;
|
|
|
|
if (len1 + len2 + len3 >= w[0].minlen && len1 + len2 + len3 <= w[0].maxlen) {
|
|
printf("%s%s%s\n", w[1].words[i], w[2].words[j], w[3].words[k]);
|
|
w[0].wordcount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
msg("\nFinal count: %d word combinations.\n", w[0].wordcount);
|
|
}
|
|
|
|
void
|
|
usage(void)
|
|
{
|
|
fprintf(stderr,
|
|
"Version: %s\n"
|
|
"\n"
|
|
"usage: %s min-max filename1 min1-max1 [filename2 min2-max2 [filename3 min3-max3]]\n"
|
|
" min-max : length limits for the output strings\n"
|
|
" filename1 : name of the first word list file (required)\n"
|
|
" min1-max1 : length limits for the words from the first file\n"
|
|
" filename2 : name of the second word list file (optional)\n"
|
|
" min2-max2 : length limits for the words from the first file\n"
|
|
" filename3 : name of the third word list file (optional)\n"
|
|
" min3-max3 : length limits for the words from the first file\n\n"
|
|
" Example: %s 8-12 wordlist1.txt 5-10 wordlist2.txt 3-5 > results.txt\n\n"
|
|
" Generates word combinations from 8 to 12 characters long\n"
|
|
" using 5-10 character long words from 'wordlist1.txt'\n"
|
|
" followed by 3-5 character long words from 'wordlist2.txt'.\n"
|
|
" Saves the results to 'results.txt'.\n",
|
|
VERSION, __progname, __progname);
|
|
exit(1);
|
|
}
|
|
|
|
/* Read words from file */
|
|
void
|
|
readfile(struct f *list)
|
|
{
|
|
FILE *file;
|
|
signed int c;
|
|
char word[MAX_LEN + 1];
|
|
unsigned int len, i, j = 0;
|
|
_Bool inword;
|
|
|
|
if ((file = fopen(list->fn, "r")) == NULL)
|
|
error("Failed to open %s!\n", list->fn);
|
|
|
|
msg("Loading words from %s.\n", list->fn);
|
|
|
|
while ((c = fgetc(file)) != EOF) {
|
|
c = tolower(c);
|
|
inword = 0;
|
|
for (i = 0; i < 32; i++) {
|
|
if (c == BASE32_ALPHABET[i]) {
|
|
word[j++] = c;
|
|
inword = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((!inword && j > 0) || j > MAX_LEN) {
|
|
word[j] = '\0';
|
|
j = 0;
|
|
len = mystrnlen(word, MAX_LEN);
|
|
if (len >= list->minlen &&
|
|
len <= list->maxlen &&
|
|
list->wordcount < MAX_WORDS) {
|
|
if ((list->words =
|
|
(char **)realloc(list->words,
|
|
(list->wordcount + 1) * sizeof(char *))) == NULL)
|
|
error("realloc() failed!\n");
|
|
|
|
if ((list->words[list->wordcount] =
|
|
(char *)malloc(mystrnlen(word, MAX_LEN) + 1)) == NULL)
|
|
error("malloc() failed!\n");
|
|
|
|
strncpy(list->words[list->wordcount], word, mystrnlen(word, MAX_LEN) + 1);
|
|
list->wordcount++;
|
|
}
|
|
}
|
|
}
|
|
fclose(file);
|
|
if (list->wordcount == 0)
|
|
error("Could not find any valid words!\n");
|
|
else
|
|
msg("Loaded %d words from %s.\n", list->wordcount, list->fn);
|
|
}
|
|
|
|
/* Print error message and exit. Not using the err/errx,
|
|
* since not all Linuxes implement them properly. */
|
|
void
|
|
error(char *message, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, message);
|
|
fprintf(stderr, "ERROR: ");
|
|
vfprintf(stderr, message, ap);
|
|
va_end(ap);
|
|
fflush(stderr);
|
|
exit(1);
|
|
}
|
|
|
|
/* Spam STDERR with diagnostic messages... */
|
|
void
|
|
verbose(char *message, ...) {
|
|
va_list ap;
|
|
va_start(ap, message);
|
|
vfprintf(stderr, message, ap);
|
|
va_end(ap);
|
|
fflush(stderr);
|
|
}
|
|
|
|
/* ...or be a very quiet thinker. */
|
|
void
|
|
normal(__attribute__((unused)) char *notused, ...) {
|
|
}
|
|
|
|
/* Local version of strnlen function for older OSes. */
|
|
size_t
|
|
mystrnlen(const char *s, size_t ml)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; *(s + i) != '\0' && i < ml; i++)
|
|
;
|
|
return i;
|
|
|
|
}
|
|
|