■ 🕑 1. tripex tripcode finding software
│ releasing version 1.0 of my tripcode finding program, 'tripex'
│
│ compile the program as follows:
│ gcc tripex.c -o tripex -O3 -lcrypt
│
│ example #1; find tripcodes containing 'nice' (case insensitive):
│ ./tripex -n $(nproc) -i nice
│
│ example #2; find tripcodes starting with either 'giko' or 'mona':
│ ./tripex -n $(nproc) ^giko ^mona
│
│ example #3; find fully lowercase tripcodes with quads:
│ ./tripex -s -n $(nproc) "^[a-z]*$" "\(.\)\1\{3,\}"
│
│ untested on anything but GNU/Linux with glibc, but it would probably work on FreeBSD too.
│ don't trust any update posts unless they have my tripcode or you can audit them yourself!
│
│ -----BEGIN FILE tripex.c-----
│ /* CC0-1.0 */
│
│ #include <err.h>
│ #include <crypt.h>
│ #include <regex.h>
│ #include <stdio.h>
│ #include <stdlib.h>
│ #include <string.h>
│ #include <unistd.h>
│
│ #include <sys/random.h>
│
│ #define ARRAY_SIZE(x) (sizeof((x)) / sizeof((x)[0]))
│
│ static unsigned char saltFilter[256];
│ static unsigned char rngFilter[256];
│ char *tripcode(const char *key);
│
│ void usage(void)
│ {
│ fprintf(stderr, "usage: tripex [-Ehilnmsv] expressions\n"
│ " -E\tuse extended regular expressions\n"
│ " -h\tshow usage\n"
│ " -i\tignore case\n"
│ " -l\tkey length\n"
│ " -n\tnumber of threads\n"
│ " -m\tmax number of tries (per thread!)\n"
│ " -s\tstack expressions (logical AND)\n");
│ }
│
│ int main(int argc, char *argv[])
│ {
│ int re_flags = 0;
│ int sflag = 0;
│ size_t n_procs = 1;
│ size_t key_len = 8;
│ size_t max_tries = 0;
│
│ int opt;
│ while ((opt = getopt(argc, argv, "E:hil:m:n:sv")) != -1) {
│ switch(opt) {
│ case 'E':
│ re_flags |= REG_EXTENDED;
│ break;
│ case 'i':
│ re_flags |= REG_ICASE;
│ break;
│ case 'l':
│ key_len = atol(optarg);
│ if (key_len < 1)
│ errx(EXIT_FAILURE, "key length must be at least 1");
│ break;
│ case 'n':
│ n_procs = atol(optarg);
│ if (n_procs < 1)
│ errx(EXIT_FAILURE, "need at least one process");
│ break;
│ case 'm': /* ! PER THREAD ! */
│ max_tries = atol(optarg);
│ if (max_tries < 1)
│ errx(EXIT_FAILURE, "need at least one try");
│ break;
│ case 's':
│ sflag = 1;
│ break;
│ case 'v':
│ printf("tripex 1.0 by taocana\n");
│ return EXIT_SUCCESS;
│ case 'h':
│ /* FALLTHROUGH */
│ default:
│ usage();
│
│ return EXIT_FAILURE;
│ }
│ }
│
│ argc -= optind;
│ argv += optind;
│
│ if (argc < 1) {
│ usage();
│ errx(EXIT_FAILURE, "need at least one expression");
│ }
│
│ size_t n_exps = argc;
│ regex_t *exps = malloc(sizeof(regex_t) * n_exps);
│ for (size_t i = 0; i < n_exps; i++)
│ if (regcomp(&exps[i], argv[i], re_flags))
│ errx(EXIT_FAILURE, "failed to compile regex");
│
│ for (int i = 1; i < n_procs; i++)
│ if (!fork())
│ break;
│
│ regmatch_t pmatch[1];
│ unsigned char key[key_len + 1]; /* dynamic array, bad form but i'm lazy */
│ key[key_len] = 0;
│
│ for (size_t n = 0; !max_tries || n < max_tries ; n++) {
│ if (getrandom(key, key_len, 0) < 0)
│ err(EXIT_FAILURE, "failed to get random key");
│
│ for (int i = 0; i < key_len; i++)
│ key[i] = rngFilter[key[i]];
│
│ char *trip = tripcode(key);
│ if (!trip)
│ err(EXIT_FAILURE, "failed to generate tripcode");
│
│ for (size_t i = 0; i < n_exps; i++)
│ if (regexec(&exps[i], trip, ARRAY_SIZE(pmatch), pmatch, 0))
│ if (sflag)
│ break;
│ else
│ continue;
│ else if (!sflag || i >= n_exps - 1)
│ printf("%s %s\n", trip, key);
│
│ free(trip);
│ }
│
│ for (size_t i = 0; i < n_exps; i++)
│ regfree(&exps[i]);
│ free(exps);
│ return EXIT_SUCCESS;
│ }
│
│ char *tripcode(const char *key)
│ {
│ /* we don't do any sjis conversion, but who cares anyway? */
│ if (strlen(key) == 0)
│ return NULL;
│
│ unsigned char *tempKey = malloc(strlen(key) + 2);
│ if (!tempKey)
│ return NULL;
│ strcpy(tempKey, key);
│ strcat(tempKey, "H.");
│
│ unsigned char salt[3];
│ for (int i = 0; i < 3; i++)
│ salt[i] = saltFilter[tempKey[i+1]];
│ salt[2] = 0;
│ free(tempKey);
│
│ struct crypt_data data;
│ bzero(&data, sizeof(struct crypt_data));
│
│ char *tempCode = crypt_r(key, salt, &data);
│ unsigned char *code = malloc(strlen(tempCode) - 3);
│ if (!code)
│ return NULL;
│ strcpy(code, tempCode + 3);
│ return code;
│ }
│
│ static unsigned char saltFilter[256] =
│ "................................"
│ ".............../0123456789......"
│ ".ABCDEFGHIJKLMNOPQRSTUVWXYZ....."
│ ".abcdefghijklmnopqrstuvwxyz....."
│ "................................"
│ "................................"
│ "................................"
│ "................................";
│
│ static unsigned char rngFilter[256] =
│ "{dDOFByx8Jdo=C.{hFw:'p%m+]E-*}~4"
│ "O)YiM99y?%A)tldRIN4!fat`J|(iI+}h"
│ "]59P#T_Qx#h0q8w+F,$}Vo5Gq;<rw]Y~"
│ "k6>O~Ge,.DW9`hqhaSf#A.vrnhy`[2Ct"
│ "Bb6|7Mr+iJZG5.&7>?K@{D~6*Vs'H_*>"
│ "$Mh3R-F$Sp^.E5R-W1DnQzXC@Tf']xxt"
│ "o`GLO'Ui`S/v,aegU2HkE3Y6y!WZm%?k"
│ "aD/H=yH4vQg7dC*(Gx$vV[<vV?jw8s^d";
│
│
├─■ 🕑 2. tripex 1.1
│ │ version 1.1, cryptography patch.
│ │ i forgot to audit the cryptography; i made a huge boneheaded mistake
│ │ with the key filter (thing that turns pure random bytes into printable
│ │ ascii) where it was skewing a lot. now it uses an 85 character subset
│ │ (256 % 85 = 1) which has a very tiny amount of skew but doesn't lose
│ │ as much entropy as an unskewed 64 character subset of ascii would.
│ │ the default key length is also increased to 10, so that it would be
│ │ ~64 shannons of entropy total (a tripcode has 60 shannons.)
│ │
│ │ here is the patch file, apply it to the original as follows:
│ │ patch tripex.c tripex-1.1.patch
│ │
│ │ then recompile the program as follows:
│ │ gcc tripex.c -o tripex -O3 -lcrypt
│ │
│ │ -----BEGIN FILE tripex-1.1.patch-----
│ │ 36c36
│ │ < size_t key_len = 8;
│ │ ---
│ │ > size_t key_len = 10;
│ │ 67c67
│ │ < printf("tripex 1.0 by taocana\n");
│ │ ---
│ │ > printf("tripex 1.1 by taocana\n");
│ │ 167a168,175
│ │ > /* we must get printable ascii from a random byte,
│ │ > * but 256 % 94 = 68 which leaves too much skew.
│ │ > * quantizing into 64 chars won't skew at all, but
│ │ > * it only has 6 shannons of entropy per character.
│ │ > * an 85 character quantization only skews by a
│ │ > * remainder of one, which is miniscule enough and
│ │ > * we average 6.41 shannons per character.
│ │ > */
│ │ 169,176c177,192
│ │ < "{dDOFByx8Jdo=C.{hFw:'p%m+]E-*}~4"
│ │ < "O)YiM99y?%A)tldRIN4!fat`J|(iI+}h"
│ │ < "]59P#T_Qx#h0q8w+F,$}Vo5Gq;<rw]Y~"
│ │ < "k6>O~Ge,.DW9`hqhaSf#A.vrnhy`[2Ct"
│ │ < "Bb6|7Mr+iJZG5.&7>?K@{D~6*Vs'H_*>"
│ │ < "$Mh3R-F$Sp^.E5R-W1DnQzXC@Tf']xxt"
│ │ < "o`GLO'Ui`S/v,aegU2HkE3Y6y!WZm%?k"
│ │ < "aD/H=yH4vQg7dC*(Gx$vV[<vV?jw8s^d";
│ │ ---
│ │ > "!#$%&'()*+,-./012"
│ │ > "3456789:;<=>?@ABC"
│ │ > "DEFGHIJKLMNOPQRST"
│ │ > "UVWXYZ^abcdefghij"
│ │ > "klmnopqrstuvwxyz~"
│ │ > "!#$%&'()*+,-./012"
│ │ > "3456789:;<=>?@ABC"
│ │ > "DEFGHIJKLMNOPQRST"
│ │ > "UVWXYZ^abcdefghij"
│ │ > "klmnopqrstuvwxyz~"
│ │ > "!#$%&'()*+,-./012"
│ │ > "3456789:;<=>?@ABC"
│ │ > "DEFGHIJKLMNOPQRST"
│ │ > "UVWXYZ^abcdefghij"
│ │ > "klmnopqrstuvwxyz~"
│ │ > "~";
│ │
│ │
│ └─■ 🕑 3. tripex 1.2
│ tripex 1.2 release notes
│ + -f flag to read a list of expressions from a file
│ * -s flag now takes an argument for when to begin/end stacking. negative values mean to stop stacking after the absolute value of the index.
│
│ apply the patch as follows (make sure to apply the previous patch first:)
│ patch tripex.c tripex-1.2.patch
│
│ then recompile the software as follows:
│ gcc tripex.c -o tripex -O3 -lcrypt
│
│ here's an example of the new features combined for efficient dictionary searches.
│ because expressions from argv are parsed after files, we have to put our first expression in it's own file :(.
│ '-s -1' means to stop stacking after the first expression, so it will first check if it is even possible to match with any of the dictionary expressions.
│
│ aspell -d en dump master | grep "^[a-z]\{5,5\}$" > len5dict.txt
│ echo "[a-z]\{5,5\}" > 5a-z.txt
│ ./tripex -n $(nproc) -s -1 -f 5a-z.txt -f len5dict.txt
│
│ -----BEGIN FILE tripex-1.2.patch-----
│ 13a14
│ > #define MAX_EXPRS 262144
│ 18a20,23
│ > /* if i put this garbage on the stack instead of bss, it will segfault. */
│ > size_t n_exprs = 0;
│ > regex_t exprs[MAX_EXPRS];
│ >
│ 21c26
│ < fprintf(stderr, "usage: tripex [-Ehilnmsv] expressions\n"
│ ---
│ > fprintf(stderr, "usage: tripex [-Ef:hil:n:m:s:v] expressions\n"
│ 22a28
│ > " -f\tread expressions from file (use '-' for stdin)\n"
│ 28c34,46
│ < " -s\tstack expressions (logical AND)\n");
│ ---
│ > " -s\tstack (logical AND) expressions before/after expr #n (negative for before)\n");
│ > }
│ >
│ > void appendExpr(regex_t exprs[], size_t *i, char *str, int re_flags)
│ > {
│ > /* avoiding malloc like the plague, simple and fast shitware!
│ > * if you somehow need more than MAX_EXPRS, change it & recompile.
│ > */
│ > if (*i >= MAX_EXPRS)
│ > errx(EXIT_FAILURE, "no %s-kun! it's too many exprs, it wont fit!", getlogin());
│ > if (regcomp(&exprs[*i], str, re_flags))
│ > errx(EXIT_FAILURE, "failed to compile regex '%s'", str);
│ > (*i)++;
│ 34a53
│ > long stack_after = 0;
│ 40c59
│ < while ((opt = getopt(argc, argv, "E:hil:m:n:sv")) != -1) {
│ ---
│ > while ((opt = getopt(argc, argv, "E:f:hil:m:M:n:s:v")) != -1) {
│ 44a64,81
│ > case 'f':
│ > FILE *fp = stdin;
│ > if (strcmp(optarg, "-") != 0)
│ > fp = fopen(optarg, "r");
│ > if (!fp)
│ > err(EXIT_FAILURE, "couldn't open regex file '%s'", optarg);
│ >
│ > char *line = NULL;
│ > size_t len = 0;
│ > ssize_t nread;
│ > while ((nread = getline(&line, &len, fp)) != -1) {
│ > *strchr(line, '\n') = '\0';
│ > appendExpr(exprs, &n_exprs, line, re_flags);
│ > }
│ >
│ > free(line);
│ > fclose(fp);
│ > break;
│ 64a102
│ > stack_after = atol(optarg);
│ 67c105
│ < printf("tripex 1.1 by taocana\n");
│ ---
│ > printf("tripex 1.2 by taocana\n");
│ 73d110
│ <
│ 81c118,121
│ < if (argc < 1) {
│ ---
│ > for (size_t i = 0; i < argc; i++)
│ > appendExpr(exprs, &n_exprs, argv[i], re_flags);
│ >
│ > if (n_exprs < 1) {
│ 86,91d125
│ < size_t n_exps = argc;
│ < regex_t *exps = malloc(sizeof(regex_t) * n_exps);
│ < for (size_t i = 0; i < n_exps; i++)
│ < if (regcomp(&exps[i], argv[i], re_flags))
│ < errx(EXIT_FAILURE, "failed to compile regex");
│ <
│ 97c131
│ < unsigned char key[key_len + 1]; /* dynamic array, bad form but i'm lazy */
│ ---
│ > unsigned char key[key_len + 1];
│ 100c134
│ < for (size_t n = 0; !max_tries || n < max_tries ; n++) {
│ ---
│ > for (size_t n = 0; !max_tries || n < max_tries; n++) {
│ 111,113c145,151
│ < for (size_t i = 0; i < n_exps; i++)
│ < if (regexec(&exps[i], trip, ARRAY_SIZE(pmatch), pmatch, 0))
│ < if (sflag)
│ ---
│ > for (size_t i = 0; i < n_exprs; i++) {
│ > int stacking = (sflag
│ > && ((stack_after >= 0 && i >= stack_after)
│ > || (stack_after < 0 && i < -stack_after)));
│ >
│ > if (regexec(&exprs[i], trip, ARRAY_SIZE(pmatch), pmatch, 0))
│ > if (stacking)
│ 117c155
│ < else if (!sflag || i >= n_exps - 1)
│ ---
│ > else if (!stacking || i >= n_exprs - 1) {
│ 118a157,159
│ > break;
│ > }
│ > }
│ 123,125c164,165
│ < for (size_t i = 0; i < n_exps; i++)
│ < regfree(&exps[i]);
│ < free(exps);
│ ---
│ > for (size_t i = 0; i < n_exprs; i++)
│ > regfree(&exprs[i]);
│ 134a175
│ > /* unsigned for array lookups by character */
│ 152c193
│ < if (!code)
│ ---
│ > if (!code) /* doesn't fully handle crypt_r(3) errors yet */
│
│
└─■ 🕑 4.
│ What does this do
│
└─■ 🕑 5.
A program to search for 2ch style tripcodes via regular expressions.