├── .gitignore ├── CHANGES ├── LICENSE ├── README.md └── src ├── Makefile └── mp.c /.gitignore: -------------------------------------------------------------------------------- 1 | src/*.bin 2 | src/*.exe 3 | src/*.app 4 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | * v0.73 -> xxx: 2 | 3 | - Add a missing sanity check on startup to disallow the use of increment in combination with -s and -l 4 | 5 | * v0.72 -> v0.73: 6 | 7 | - Open Source the project 8 | - License is MIT 9 | - Moved repository to github: https://github.com/jsteube/maskprocessor 10 | - Added CHANGES 11 | - Added LICENSE 12 | - Added README.md 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2021 Jens Steube 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | maskprocessor 2 | ============== 3 | 4 | High-Performance word generator with a per-position configurable charset 5 | 6 | Mask attack 7 | -------------- 8 | 9 | Try all combinations from a given keyspace just like in Brute-Force attack, but more specific. 10 | 11 | Advantage over Brute-Force 12 | -------------- 13 | 14 | The reason for doing this and not to stick to the traditional Brute-Force is that we want to reduce the password candidate keyspace to a more efficient one. 15 | 16 | Here is a single example. We want to crack the password: Julia1984 17 | 18 | In traditional Brute-Force attack we require a charset that contains all upper-case letters, all lower-case letters and all digits (aka “mixalpha-numeric”). The Password length is 9, so we have to iterate through 62^9 (13.537.086.546.263.552) combinations. Lets say we crack with a rate of 100M/s, this requires more than 4 years to complete. 19 | 20 | In Mask attack we know about humans and how they design passwords. The above password matches a simple but common pattern. A name and year appended to it. We can also configure the attack to try the upper-case letters only on the first position. It is very uncommon to see an upper-case letter only in the second or the third position. To make it short, with Mask attack we can reduce the keyspace to 52*26*26*26*26*10*10*10*10 (237.627.520.000) combinations. With the same cracking rate of 100M/s, this requires just 40 minutes to complete. 21 | 22 | Disadvantage compared to Brute-Force 23 | -------------- 24 | 25 | There is none. One can argue that the above example is very specific but this does not matter. Even in mask attack we can configure our mask to use exactly the same keyspace as the Brute-Force attack does. The thing is just that this cannot work vice versa. 26 | 27 | Masks 28 | -------------- 29 | 30 | For each position of the generated password candidates we need to configure a placeholder. If a password we want to crack has the length 8, our mask must consist of 8 placeholders. 31 | 32 | - A mask is a simple string that configures the keyspace of the password candidate engine using placeholders. 33 | - A placeholder can be either a custom charset variable, a built-in charset variable or a static letter. 34 | - A variable is indicated by the ? letter followed by one of the built-in charset (l, u, d, s, a) or one of the custom charset variable names (1, 2, 3, 4). 35 | - A static letter is not indicated by a letter. An exception is if we want the static letter ? itself, which must be written as ??. 36 | 37 | Built-in charsets 38 | -------------- 39 | 40 | - ?l = abcdefghijklmnopqrstuvwxyz 41 | - ?u = ABCDEFGHIJKLMNOPQRSTUVWXYZ 42 | - ?d = 0123456789 43 | - ?s = «space»!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 44 | - ?a = ?l?u?d?s 45 | - ?b = 0x00 - 0xff 46 | 47 | Custom charsets 48 | -------------- 49 | 50 | There are four commandline-parameters to configure four custom charsets. 51 | 52 | - --custom-charset1=CS 53 | - --custom-charset2=CS 54 | - --custom-charset3=CS 55 | - --custom-charset4=CS 56 | 57 | These commandline-parameters have four analogue shortcuts called -1, -2, -3 and -4. You can specify the chars directly on the command line. 58 | 59 | Password length increment 60 | -------------- 61 | 62 | A Mask attack is always specific to a password length. For example, if we use the mask ”?l?l?l?l?l?l?l?l” we can only crack a password of the length 8. But if the password we try to crack has the length 7 we will not find it. Thats why we have to repeat the attack several times, each time with one placeholder added to the mask. This is transparently automated by using the ”--increment” flag. 63 | 64 | - ?l 65 | - ?l?l 66 | - ?l?l?l 67 | - ?l?l?l?l 68 | - ?l?l?l?l?l 69 | - ?l?l?l?l?l?l 70 | - ?l?l?l?l?l?l?l 71 | - ?l?l?l?l?l?l?l?l 72 | 73 | Performance 74 | -------------- 75 | 76 | Currently, it is the world's fastest word generator. Here are some stats: 77 | 78 | - AMD Athlon™ 64 X2 Dual Core Processor 3800+: 75.80 M/s (per core) 79 | - AMD FX™-6100 Six-Core Processor: 138.20 M/s (per core) 80 | - Intel(R) Xeon(R) CPU X5650 @ 2.67GHz: 97.42 M/s (per core) 81 | - Intel(R) i7-920: 71.50 M/s (per core) 82 | 83 | To avoid irregularities while testing, all output went into /dev/null. 84 | 85 | Example 86 | -------------- 87 | 88 | The following commands creates the following password candidates: 89 | 90 | - command: ?l?l?l?l?l?l?l?l 91 | - keyspace: aaaaaaaa - zzzzzzzz 92 | 93 | - command: -1 ?l?d ?1?1?1?1?1 94 | - keyspace: aaaaa - 99999 95 | 96 | - command: password?d 97 | - keyspace: password0 - password9 98 | 99 | - command: -1 ?l?u ?1?l?l?l?l?l19?d?d 100 | - keyspace: aaaaaa1900 - Zzzzzz1999 101 | 102 | - command: -1 ?dabcdef -2 ?l?u ?1?1?2?2?2?2?2 103 | - keyspace: 00aaaaa - ffZZZZZ 104 | 105 | - command: -1 efghijklmnop ?1?1?1 106 | - keyspace: eee - ppp 107 | 108 | Compile 109 | -------------- 110 | 111 | Simply run make 112 | 113 | Binary distribution 114 | -------------- 115 | 116 | Binaries for Linux, Windows and OSX: https://github.com/jsteube/maskprocessor/releases 117 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## Makefile for mp 3 | ## 4 | 5 | CFLAGS = -W -Wall -std=c99 -O2 -s 6 | #CFLAGS = -W -Wall -std=c99 -g 7 | 8 | CC_LINUX32 = gcc 9 | CC_LINUX64 = gcc 10 | CC_WINDOWS32 = /usr/bin/i686-w64-mingw32-gcc 11 | CC_WINDOWS64 = /usr/bin/x86_64-w64-mingw32-gcc 12 | CC_OSX32 = /usr/bin/i686-apple-darwin10-gcc 13 | CC_OSX64 = /usr/bin/i686-apple-darwin10-gcc 14 | 15 | CFLAGS_LINUX32 = $(CFLAGS) -m32 -DLINUX 16 | CFLAGS_LINUX64 = $(CFLAGS) -m64 -DLINUX 17 | CFLAGS_WINDOWS32 = $(CFLAGS) -m32 -DWINDOWS 18 | CFLAGS_WINDOWS64 = $(CFLAGS) -m64 -DWINDOWS 19 | CFLAGS_OSX32 = $(CFLAGS) -m32 -DOSX 20 | CFLAGS_OSX64 = $(CFLAGS) -m64 -DOSX 21 | 22 | all: mp64.bin 23 | 24 | mp32: mp32.bin mp32.exe mp32.app 25 | mp64: mp64.bin mp64.exe mp64.app 26 | 27 | clean: 28 | rm -f mp32.bin mp64.bin mp32.exe mp64.exe mp32.app mp64.app 29 | 30 | mp32.bin: mp.c 31 | $(CC_LINUX32) $(CFLAGS_LINUX32) -o $@ $^ 32 | 33 | mp64.bin: mp.c 34 | $(CC_LINUX64) $(CFLAGS_LINUX64) -o $@ $^ 35 | 36 | mp32.exe: mp.c 37 | $(CC_WINDOWS32) $(CFLAGS_WINDOWS32) -o $@ $^ 38 | 39 | mp64.exe: mp.c 40 | $(CC_WINDOWS64) $(CFLAGS_WINDOWS64) -o $@ $^ 41 | 42 | mp32.app: mp.c 43 | $(CC_OSX32) $(CFLAGS_OSX32) -o $@ $^ 44 | 45 | mp64.app: mp.c 46 | $(CC_OSX64) $(CFLAGS_OSX64) -o $@ $^ 47 | -------------------------------------------------------------------------------- /src/mp.c: -------------------------------------------------------------------------------- 1 | #define _LARGEFILE_SOURCE 2 | #define _FILE_OFFSET_BITS 64 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | /** 13 | * Name........: maskprocesspr (mp) 14 | * Description.: High-Performance word generator with a per-position configureable charset 15 | * Version.....: 0.73 16 | * Autor.......: Jens Steube 17 | * License.....: MIT 18 | */ 19 | 20 | #define CHARSIZ 0x100 21 | #define PW_MAX 0x100 22 | #define SPARE 100 23 | #define OUTBUFSZ BUFSIZ 24 | #define VERSION_BIN 73 25 | #define SEQ_MAX 0 26 | #define OCCUR_MAX 0 27 | #define OCCUR_CACHE_SIZE 3 28 | #define INCREMENT 0 29 | #define INCREMENT_MIN 1 30 | #define INCREMENT_MAX PW_MAX 31 | 32 | typedef struct __cs 33 | { 34 | char cs_buf[CHARSIZ]; 35 | char cs_uniq[CHARSIZ]; 36 | int cs_len; 37 | int cs_pos; 38 | int buf_pos; 39 | 40 | } cs_t; 41 | 42 | typedef struct 43 | { 44 | char buf[OUTBUFSZ + SPARE]; 45 | 46 | int pos; 47 | 48 | } out_t; 49 | 50 | static const char *USAGE_MINI[] = 51 | { 52 | "Usage: %s [options] mask", 53 | "", 54 | "Try --help for more help.", 55 | NULL 56 | }; 57 | 58 | static const char *USAGE_BIG[] = 59 | { 60 | "High-Performance word generator with a per-position configureable charset", 61 | "", 62 | "Usage: %s [options]... mask", 63 | "", 64 | "* Startup:", 65 | "", 66 | " -V, --version Print version", 67 | " -h, --help Print help", 68 | "", 69 | "* Increment:", 70 | "", 71 | " -i, --increment=NUM:NUM Enable increment mode. 1st NUM=start, 2nd NUM=stop", 72 | " Example: -i 4:8 searches lengths 4-8 (inclusive)", 73 | "", 74 | "* Misc:", 75 | "", 76 | " --combinations Calculate number of combinations", 77 | " --hex-charset Assume charset is given in hex", 78 | " -q, --seq-max=NUM Maximum number of multiple sequential characters", 79 | " -r, --occurrence-max=NUM Maximum number of occurrence of a character", 80 | "", 81 | "* Resources:", 82 | "", 83 | " -s, --start-at=WORD Start at specific position", 84 | " -l, --stop-at=WORD Stop at specific position", 85 | "", 86 | "* Files:", 87 | "", 88 | " -o, --output-file=FILE Output-file", 89 | "", 90 | "* Custom charsets:", 91 | "", 92 | " -1, --custom-charset1=CS User-defineable charsets", 93 | " -2, --custom-charset2=CS Example:", 94 | " -3, --custom-charset3=CS --custom-charset1=?dabcdef", 95 | " -4, --custom-charset4=CS sets charset ?1 to 0123456789abcdef", 96 | "", 97 | "* Built-in charsets:", 98 | "", 99 | " ?l = abcdefghijklmnopqrstuvwxyz", 100 | " ?u = ABCDEFGHIJKLMNOPQRSTUVWXYZ", 101 | " ?d = 0123456789", 102 | " ?s = !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", 103 | " ?a = ?l?u?d?s", 104 | " ?b = 0x00 - 0xff", 105 | "", 106 | NULL 107 | }; 108 | 109 | static void usage_mini_print (const char *progname) 110 | { 111 | int i; 112 | 113 | for (i = 0; USAGE_MINI[i] != NULL; i++) 114 | { 115 | printf (USAGE_MINI[i], progname); 116 | 117 | #ifdef OSX 118 | putchar ('\n'); 119 | #endif 120 | 121 | #ifdef LINUX 122 | putchar ('\n'); 123 | #endif 124 | 125 | #ifdef WINDOWS 126 | putchar ('\r'); 127 | putchar ('\n'); 128 | #endif 129 | } 130 | } 131 | 132 | static void usage_big_print (const char *progname) 133 | { 134 | int i; 135 | 136 | for (i = 0; USAGE_BIG[i] != NULL; i++) 137 | { 138 | printf (USAGE_BIG[i], progname); 139 | 140 | #ifdef OSX 141 | putchar ('\n'); 142 | #endif 143 | 144 | #ifdef LINUX 145 | putchar ('\n'); 146 | #endif 147 | 148 | #ifdef WINDOWS 149 | putchar ('\r'); 150 | putchar ('\n'); 151 | #endif 152 | } 153 | } 154 | 155 | static uint32_t is_valid_hex_char (const char c) 156 | { 157 | if ((c >= '0') && (c <= '9')) return 1; 158 | if ((c >= 'A') && (c <= 'F')) return 1; 159 | if ((c >= 'a') && (c <= 'f')) return 1; 160 | 161 | return 0; 162 | } 163 | 164 | static char hex_convert (char c) 165 | { 166 | return (c & 15) + (c >> 6) * 9; 167 | } 168 | 169 | static void add_cs_buf (const char *input_buf, cs_t *css, const int css_cnt) 170 | { 171 | size_t input_len = strlen (input_buf); 172 | 173 | int pos = 0; 174 | 175 | size_t i; 176 | 177 | for (i = 0; i < input_len; i++) 178 | { 179 | int u = input_buf[i]; 180 | 181 | if (css[css_cnt].cs_uniq[u] == 1) continue; 182 | 183 | css[css_cnt].cs_uniq[u] = 1; 184 | css[css_cnt].cs_buf[pos] = input_buf[i]; 185 | 186 | pos++; 187 | } 188 | 189 | css[css_cnt].cs_len = pos; 190 | css[css_cnt].cs_pos = 0; 191 | css[css_cnt].buf_pos = css_cnt; 192 | } 193 | 194 | uint64_t mp_get_sum (int css_cnt, cs_t *css) 195 | { 196 | uint64_t sum = 1; 197 | 198 | int css_pos; 199 | 200 | for (css_pos = 0; css_pos < css_cnt; css_pos++) 201 | { 202 | sum *= css[css_pos].cs_len; 203 | } 204 | 205 | return (sum); 206 | } 207 | 208 | static size_t mp_expand (const char *in_buf, const size_t in_len, char *out_buf, char *mp_sys[6], int hex_charset) 209 | { 210 | size_t in_pos; 211 | 212 | for (in_pos = 0; in_pos < in_len; in_pos++) 213 | { 214 | char p0 = in_buf[in_pos]; 215 | 216 | if (p0 == '?') 217 | { 218 | in_pos++; 219 | 220 | char p1 = in_buf[in_pos]; 221 | 222 | switch (p1) 223 | { 224 | case 'l': strcat (out_buf, mp_sys[0]); 225 | break; 226 | case 'u': strcat (out_buf, mp_sys[1]); 227 | break; 228 | case 'd': strcat (out_buf, mp_sys[2]); 229 | break; 230 | case 's': strcat (out_buf, mp_sys[3]); 231 | break; 232 | case 'a': strcat (out_buf, mp_sys[4]); 233 | break; 234 | case 'b': memcpy (out_buf, mp_sys[5], 256); 235 | break; 236 | case '?': strcat (out_buf, "?"); 237 | break; 238 | default: fprintf (stderr, "ERROR: Syntax Error: %s\n", in_buf); 239 | exit (-1); 240 | } 241 | } 242 | else 243 | { 244 | if (hex_charset) 245 | { 246 | in_pos++; 247 | 248 | if (in_pos == in_len) 249 | { 250 | fprintf (stderr, "ERROR: the hex-charset option always expects couples of exactly 2 hexadecimal chars, failed mask: %s\n", in_buf); 251 | 252 | exit (-1); 253 | } 254 | 255 | char p1 = in_buf[in_pos]; 256 | 257 | if ((is_valid_hex_char (p0) == 0) || (is_valid_hex_char (p1) == 0)) 258 | { 259 | fprintf (stderr, "ERROR: invalid hex character detected in mask %s\n", in_buf); 260 | 261 | exit (-1); 262 | } 263 | 264 | char s[2] = { 0, 0 }; 265 | 266 | s[0] = hex_convert (p1) << 0; 267 | s[0] |= hex_convert (p0) << 4; 268 | 269 | strcat (out_buf, s); 270 | } 271 | else 272 | { 273 | char s[2] = { p0, 0 }; 274 | 275 | strcat (out_buf, s); 276 | } 277 | } 278 | } 279 | 280 | return strlen (out_buf); 281 | } 282 | 283 | static int next (char *word_buf, cs_t *css_buf, const int pos, int *occurs) 284 | { 285 | int i; 286 | 287 | for (i = pos - 1; i >= 0; i--) 288 | { 289 | const int c_old = word_buf[i]; 290 | 291 | occurs[c_old]--; 292 | 293 | cs_t *cs = css_buf + i; 294 | 295 | if (cs->cs_pos < cs->cs_len) 296 | { 297 | const int c_new = cs->cs_buf[cs->cs_pos]; 298 | 299 | occurs[c_new]++; 300 | 301 | word_buf[i] = (char) c_new; 302 | 303 | cs->cs_pos++; 304 | 305 | return i; 306 | } 307 | 308 | const int c_new = cs->cs_buf[0]; 309 | 310 | occurs[c_new]++; 311 | 312 | word_buf[i] = (char) c_new; 313 | 314 | cs->cs_pos = 1; 315 | } 316 | 317 | return -1; 318 | } 319 | 320 | static int find_pos (cs_t *cs, char c) 321 | { 322 | int i; 323 | 324 | for (i = 0; i < cs->cs_len; i++) 325 | { 326 | if (cs->cs_buf[i] == c) return i; 327 | } 328 | 329 | return -1; 330 | } 331 | 332 | int main (int argc, char *argv[]) 333 | { 334 | /* usage */ 335 | 336 | int version = 0; 337 | int usage = 0; 338 | int combinations = 0; 339 | int hex_charset = 0; 340 | int seq_max = SEQ_MAX; 341 | int occur_max = OCCUR_MAX; 342 | int increment = INCREMENT; 343 | char *increment_data = NULL; 344 | int increment_min = INCREMENT_MIN; 345 | int increment_max = INCREMENT_MAX; 346 | char *start_at = NULL; 347 | char *stop_at = NULL; 348 | char *output_file = NULL; 349 | char *custom_charset_1 = NULL; 350 | char *custom_charset_2 = NULL; 351 | char *custom_charset_3 = NULL; 352 | char *custom_charset_4 = NULL; 353 | 354 | #define IDX_VERSION 'V' 355 | #define IDX_USAGE 'h' 356 | #define IDX_HEX_CHARSET 0 357 | #define IDX_COMBINATIONS 1 358 | #define IDX_INCREMENT 'i' 359 | #define IDX_START_AT 's' 360 | #define IDX_STOP_AT 'l' 361 | #define IDX_OUTPUT_FILE 'o' 362 | #define IDX_SEQ_MAX 'q' 363 | #define IDX_OCCUR_MAX 'r' 364 | #define IDX_CUSTOM_CHARSET_1 '1' 365 | #define IDX_CUSTOM_CHARSET_2 '2' 366 | #define IDX_CUSTOM_CHARSET_3 '3' 367 | #define IDX_CUSTOM_CHARSET_4 '4' 368 | 369 | struct option long_options[] = 370 | { 371 | {"version", no_argument, 0, IDX_VERSION}, 372 | {"help", no_argument, 0, IDX_USAGE}, 373 | {"hex-charset", no_argument, 0, IDX_HEX_CHARSET}, 374 | {"combinations", no_argument, 0, IDX_COMBINATIONS}, 375 | {"seq-max", required_argument, 0, IDX_SEQ_MAX}, 376 | {"occurrence-max", required_argument, 0, IDX_OCCUR_MAX}, 377 | {"increment", required_argument, 0, IDX_INCREMENT}, 378 | {"start-at", required_argument, 0, IDX_START_AT}, 379 | {"stop-at", required_argument, 0, IDX_STOP_AT}, 380 | {"output-file", required_argument, 0, IDX_OUTPUT_FILE}, 381 | {"custom-charset1", required_argument, 0, IDX_CUSTOM_CHARSET_1}, 382 | {"custom-charset2", required_argument, 0, IDX_CUSTOM_CHARSET_2}, 383 | {"custom-charset3", required_argument, 0, IDX_CUSTOM_CHARSET_3}, 384 | {"custom-charset4", required_argument, 0, IDX_CUSTOM_CHARSET_4}, 385 | {0, 0, 0, 0} 386 | }; 387 | 388 | int option_index = 0; 389 | 390 | int c; 391 | 392 | while ((c = getopt_long (argc, argv, "Vhi:q:s:l:o:1:2:3:4:r:", long_options, &option_index)) != -1) 393 | { 394 | switch (c) 395 | { 396 | case IDX_VERSION: version = 1; break; 397 | case IDX_USAGE: usage = 1; break; 398 | case IDX_HEX_CHARSET: hex_charset = 1; break; 399 | case IDX_COMBINATIONS: combinations = 1; break; 400 | case IDX_SEQ_MAX: seq_max = atoi (optarg); break; 401 | case IDX_OCCUR_MAX: occur_max = atoi (optarg); break; 402 | case IDX_INCREMENT: increment = 1; 403 | increment_data = optarg; break; 404 | case IDX_START_AT: start_at = optarg; break; 405 | case IDX_STOP_AT: stop_at = optarg; break; 406 | case IDX_OUTPUT_FILE: output_file = optarg; break; 407 | case IDX_CUSTOM_CHARSET_1: custom_charset_1 = optarg; break; 408 | case IDX_CUSTOM_CHARSET_2: custom_charset_2 = optarg; break; 409 | case IDX_CUSTOM_CHARSET_3: custom_charset_3 = optarg; break; 410 | case IDX_CUSTOM_CHARSET_4: custom_charset_4 = optarg; break; 411 | 412 | default: return (-1); 413 | } 414 | } 415 | 416 | if (usage) 417 | { 418 | usage_big_print (argv[0]); 419 | 420 | return (-1); 421 | } 422 | 423 | if (version) 424 | { 425 | printf ("v%4.02f\n", (double) VERSION_BIN / 100); 426 | 427 | return (-1); 428 | } 429 | 430 | if ((optind + 1) > argc) 431 | { 432 | usage_mini_print (argv[0]); 433 | 434 | return (-1); 435 | } 436 | 437 | if (seq_max == 1) 438 | { 439 | fprintf (stderr, "--seq-max must be set to at least 2\n"); 440 | 441 | return (-1); 442 | } 443 | 444 | if (seq_max && start_at) 445 | { 446 | fprintf (stderr, "--seq-max can not be used with --start-at\n"); 447 | 448 | return (-1); 449 | } 450 | 451 | if (seq_max && stop_at) 452 | { 453 | fprintf (stderr, "--seq-max can not be used with --stop-at\n"); 454 | 455 | return (-1); 456 | } 457 | 458 | if (seq_max && combinations) 459 | { 460 | fprintf (stderr, "--seq-max can not be used with --combinations\n"); 461 | 462 | return (-1); 463 | } 464 | 465 | if (occur_max && occur_max <= 1) 466 | { 467 | fprintf (stderr, "--occurrence-max must be set to at least 2\n"); 468 | 469 | return (-1); 470 | } 471 | 472 | if (occur_max && start_at) 473 | { 474 | fprintf (stderr, "--occurrence-max can not be used with --start-at\n"); 475 | 476 | return (-1); 477 | } 478 | 479 | if (occur_max && stop_at) 480 | { 481 | fprintf (stderr, "--occurrence-max can not be used with --stop-at\n"); 482 | 483 | return (-1); 484 | } 485 | 486 | if (occur_max && combinations) 487 | { 488 | fprintf (stderr, "--occurrence-max can not be used with --combinations\n"); 489 | 490 | return (-1); 491 | } 492 | 493 | if (increment && start_at) 494 | { 495 | fprintf (stderr, "--increment can not be used with --start-at\n"); 496 | 497 | return (-1); 498 | } 499 | 500 | if (increment && stop_at) 501 | { 502 | fprintf (stderr, "--increment can not be used with --stop-at\n"); 503 | 504 | return (-1); 505 | } 506 | 507 | /* buffers */ 508 | 509 | char *mp_sys[6]; 510 | 511 | mp_sys[0] = (char *) malloc (CHARSIZ); memset (mp_sys[0], 0, CHARSIZ); 512 | mp_sys[1] = (char *) malloc (CHARSIZ); memset (mp_sys[1], 0, CHARSIZ); 513 | mp_sys[2] = (char *) malloc (CHARSIZ); memset (mp_sys[2], 0, CHARSIZ); 514 | mp_sys[3] = (char *) malloc (CHARSIZ); memset (mp_sys[3], 0, CHARSIZ); 515 | mp_sys[4] = (char *) malloc (CHARSIZ); memset (mp_sys[4], 0, CHARSIZ); 516 | mp_sys[5] = (char *) malloc (CHARSIZ); memset (mp_sys[5], 0, CHARSIZ); 517 | 518 | char *mp_user[4]; 519 | 520 | mp_user[0] = (char *) malloc (CHARSIZ); memset (mp_user[0], 0, CHARSIZ); 521 | mp_user[1] = (char *) malloc (CHARSIZ); memset (mp_user[1], 0, CHARSIZ); 522 | mp_user[2] = (char *) malloc (CHARSIZ); memset (mp_user[2], 0, CHARSIZ); 523 | mp_user[3] = (char *) malloc (CHARSIZ); memset (mp_user[3], 0, CHARSIZ); 524 | 525 | /* builtin charsets */ 526 | 527 | char donec[CHARSIZ]; memset (donec, 0, CHARSIZ); 528 | 529 | int pos; 530 | int chr; 531 | 532 | for (pos = 0, chr = 'a'; chr <= 'z'; chr++) { donec[chr] = 1; 533 | mp_sys[0][pos++] = chr; } 534 | 535 | for (pos = 0, chr = 'A'; chr <= 'Z'; chr++) { donec[chr] = 1; 536 | mp_sys[1][pos++] = chr; } 537 | 538 | for (pos = 0, chr = '0'; chr <= '9'; chr++) { donec[chr] = 1; 539 | mp_sys[2][pos++] = chr; } 540 | 541 | for (pos = 0, chr = 0x20; chr <= 0x7e; chr++) { if (donec[chr]) continue; 542 | mp_sys[3][pos++] = chr; } 543 | 544 | for (pos = 0, chr = 0x20; chr <= 0x7e; chr++) { mp_sys[4][pos++] = chr; } 545 | 546 | for (pos = 0, chr = 0x00; chr <= 0xff; chr++) { mp_sys[5][pos++] = chr; } 547 | 548 | if (custom_charset_1) mp_expand (custom_charset_1, strlen (custom_charset_1), mp_user[0], mp_sys, hex_charset); 549 | if (custom_charset_2) mp_expand (custom_charset_2, strlen (custom_charset_2), mp_user[1], mp_sys, hex_charset); 550 | if (custom_charset_3) mp_expand (custom_charset_3, strlen (custom_charset_3), mp_user[2], mp_sys, hex_charset); 551 | if (custom_charset_4) mp_expand (custom_charset_4, strlen (custom_charset_4), mp_user[3], mp_sys, hex_charset); 552 | 553 | /* files in */ 554 | 555 | #ifdef WINDOWS 556 | setmode (fileno (stdout), O_BINARY); 557 | setmode (fileno (stderr), O_BINARY); 558 | #endif 559 | 560 | FILE *fp_out = stdout; 561 | 562 | if (output_file) 563 | { 564 | if ((fp_out = fopen (output_file, "ab")) == NULL) 565 | { 566 | fprintf (stderr, "ERROR: %s: %s\n", output_file, strerror (errno)); 567 | 568 | return (-1); 569 | } 570 | } 571 | 572 | setbuf (fp_out, NULL); 573 | 574 | /* load css */ 575 | 576 | char *line_buf = argv[optind]; 577 | 578 | size_t line_len = strlen (line_buf); 579 | 580 | cs_t css[PW_MAX]; 581 | 582 | memset (css, 0, sizeof (css)); 583 | 584 | int css_cnt = 0; 585 | 586 | size_t line_pos; 587 | 588 | for (line_pos = 0; line_pos < line_len; line_pos++) 589 | { 590 | char p0 = line_buf[line_pos]; 591 | 592 | if (p0 == '?') 593 | { 594 | line_pos++; 595 | 596 | char p1 = line_buf[line_pos]; 597 | 598 | switch (p1) 599 | { 600 | case 'l': add_cs_buf (mp_sys[0], css, css_cnt); 601 | css_cnt++; 602 | break; 603 | case 'u': add_cs_buf (mp_sys[1], css, css_cnt); 604 | css_cnt++; 605 | break; 606 | case 'd': add_cs_buf (mp_sys[2], css, css_cnt); 607 | css_cnt++; 608 | break; 609 | case 's': add_cs_buf (mp_sys[3], css, css_cnt); 610 | css_cnt++; 611 | break; 612 | case 'a': add_cs_buf (mp_sys[4], css, css_cnt); 613 | css_cnt++; 614 | break; 615 | case 'b': memcpy (css[css_cnt].cs_buf, mp_sys[5], 256); 616 | memset (css[css_cnt].cs_uniq, 1, 256); 617 | css[css_cnt].cs_len = 256; 618 | css_cnt++; 619 | break; 620 | case '1': add_cs_buf (mp_user[0], css, css_cnt); 621 | css_cnt++; 622 | break; 623 | case '2': add_cs_buf (mp_user[1], css, css_cnt); 624 | css_cnt++; 625 | break; 626 | case '3': add_cs_buf (mp_user[2], css, css_cnt); 627 | css_cnt++; 628 | break; 629 | case '4': add_cs_buf (mp_user[3], css, css_cnt); 630 | css_cnt++; 631 | break; 632 | case '?': add_cs_buf ("?", css, css_cnt); 633 | css_cnt++; 634 | break; 635 | default: fprintf (stderr, "ERROR: Syntax Error: %s\n", line_buf); 636 | return (-1); 637 | break; 638 | } 639 | } 640 | else 641 | { 642 | if (hex_charset) 643 | { 644 | line_pos++; 645 | 646 | if (line_pos == line_len) 647 | { 648 | fprintf (stderr, "ERROR: the hex-charset option always expects couples of exactly 2 hexadecimal chars, failed mask: %s\n", line_buf); 649 | 650 | exit (-1); 651 | } 652 | 653 | char p1 = line_buf[line_pos]; 654 | 655 | if ((is_valid_hex_char (p0) == 0) || (is_valid_hex_char (p1) == 0)) 656 | { 657 | fprintf (stderr, "ERROR: invalid hex character detected in mask %s\n", line_buf); 658 | 659 | exit (-1); 660 | } 661 | 662 | char s[2] = { 0, 0 }; 663 | 664 | s[0] = hex_convert (p1) << 0; 665 | s[0] |= hex_convert (p0) << 4; 666 | 667 | add_cs_buf (s, css, css_cnt); 668 | } 669 | else 670 | { 671 | char s[2] = { p0, 0 }; 672 | 673 | add_cs_buf (s, css, css_cnt); 674 | } 675 | 676 | css_cnt++; 677 | } 678 | } 679 | 680 | /* run css */ 681 | 682 | if (start_at) 683 | { 684 | int start_at_len = strlen (start_at); 685 | 686 | if (start_at_len == css_cnt) 687 | { 688 | int i; 689 | 690 | for (i = 0; i < css_cnt; i++) 691 | { 692 | int pos = find_pos (&css[i], start_at[i]); 693 | 694 | if (pos == -1) 695 | { 696 | fprintf (stderr, "ERROR: value '%c' in position '%d' of start-at parameter '%s' is not part of position '%d' in mask '%s'\n", start_at[i], i + 1, start_at, i + 1, line_buf); 697 | 698 | return (-1); 699 | } 700 | } 701 | } 702 | else 703 | { 704 | fprintf (stderr, "ERROR: size of '%s' from start-at parameter is not equal to size of mask '%s'\n", start_at, line_buf); 705 | 706 | return (-1); 707 | } 708 | } 709 | 710 | if (stop_at) 711 | { 712 | int stop_at_len = strlen (stop_at); 713 | 714 | if (stop_at_len == css_cnt) 715 | { 716 | int i; 717 | 718 | for (i = 0; i < css_cnt; i++) 719 | { 720 | int pos = find_pos (&css[i], stop_at[i]); 721 | 722 | if (pos == -1) 723 | { 724 | fprintf (stderr, "ERROR: value '%c' in position '%d' of stop-at parameter '%s' is not part of position '%d' in mask '%s'\n", stop_at[i], i + 1, stop_at, i + 1, line_buf); 725 | 726 | return (-1); 727 | } 728 | } 729 | } 730 | else 731 | { 732 | fprintf (stderr, "ERROR: size of '%s' from stop-at parameter is not equal to size of mask '%s'\n", stop_at, line_buf); 733 | 734 | return (-1); 735 | } 736 | } 737 | 738 | int min = css_cnt; 739 | int max = css_cnt; 740 | 741 | if (increment) 742 | { 743 | char *s_min = strtok (increment_data, ":"); 744 | char *s_max = strtok (NULL, ":"); 745 | 746 | if (s_min == NULL) 747 | { 748 | fprintf (stderr, "ERROR: increment syntax error\n"); 749 | 750 | return (-1); 751 | } 752 | 753 | if (s_max == NULL) 754 | { 755 | fprintf (stderr, "ERROR: increment syntax error\n"); 756 | 757 | return (-1); 758 | } 759 | 760 | increment_min = atoi (s_min); 761 | increment_max = atoi (s_max); 762 | 763 | if (increment_min < min) min = increment_min; 764 | if (increment_max < max) max = increment_max; 765 | } 766 | 767 | /** 768 | * Calculate number of combinations and quit 769 | */ 770 | 771 | if (combinations) 772 | { 773 | uint64_t cnt = 0; 774 | 775 | int len; 776 | 777 | for (len = min; len <= max; len++) 778 | { 779 | cnt += mp_get_sum (len, css); 780 | } 781 | 782 | #ifdef OSX 783 | printf ("%llu\n", (long long unsigned int) cnt); 784 | #endif 785 | 786 | #ifdef LINUX 787 | printf ("%llu\n", (long long unsigned int) cnt); 788 | #endif 789 | 790 | #ifdef WINDOWS 791 | printf ("%I64u\n", (long long unsigned int) cnt); 792 | #endif 793 | 794 | return (0); 795 | } 796 | 797 | int seq_start[PW_MAX]; 798 | 799 | int len; 800 | 801 | for (len = 0; len < PW_MAX; len++) 802 | { 803 | int off = len - seq_max + 1; 804 | 805 | seq_start[len] = (off > 0) ? off : 0; 806 | } 807 | 808 | out_t *out = (out_t *) malloc (sizeof (out_t)); 809 | 810 | for (len = min; len <= max; len++) 811 | { 812 | char word_buf[PW_MAX]; 813 | 814 | #ifdef OSX 815 | word_buf[len] = '\n'; 816 | 817 | int word_len = len + 1; 818 | #endif 819 | 820 | #ifdef LINUX 821 | word_buf[len] = '\n'; 822 | 823 | int word_len = len + 1; 824 | #endif 825 | 826 | #ifdef WINDOWS 827 | word_buf[len + 0] = '\r'; 828 | word_buf[len + 1] = '\n'; 829 | 830 | int word_len = len + 1 + 1; 831 | #endif 832 | 833 | int occurs[256]; 834 | 835 | memset (occurs, 0, sizeof (occurs)); 836 | 837 | out->pos = 0; 838 | 839 | if (start_at) 840 | { 841 | int i; 842 | 843 | for (i = 0; i < len; i++) 844 | { 845 | css[i].cs_pos = find_pos (&css[i], start_at[i]); 846 | 847 | word_buf[i] = css[i].cs_buf[css[i].cs_pos]; 848 | 849 | css[i].cs_pos++; 850 | } 851 | 852 | memcpy (out->buf + out->pos, word_buf, word_len); 853 | 854 | out->pos += word_len; 855 | 856 | start_at = NULL; 857 | } 858 | else 859 | { 860 | int i; 861 | 862 | for (i = 0; i < len; i++) 863 | { 864 | css[i].cs_pos = css[i].cs_len; 865 | } 866 | 867 | css[0].cs_pos = 0; 868 | } 869 | 870 | int first; 871 | 872 | while ((first = next (word_buf, css, len, occurs)) != -1) 873 | { 874 | if (seq_max) 875 | { 876 | int seq_cnt = 1; 877 | 878 | int i = seq_start[first]; 879 | 880 | int max_seq_possible = len - i; 881 | 882 | if (max_seq_possible >= seq_max) 883 | { 884 | char prev = word_buf[i]; 885 | 886 | for (i++; i < len; i++) 887 | { 888 | char cur = word_buf[i]; 889 | 890 | if (cur == prev) 891 | { 892 | seq_cnt++; 893 | } 894 | else 895 | { 896 | seq_cnt = 1; 897 | 898 | prev = cur; 899 | } 900 | 901 | if (seq_cnt < seq_max) continue; 902 | 903 | for (i++; i < len; i++) 904 | { 905 | css[i].cs_pos = css[i].cs_len; 906 | } 907 | 908 | break; 909 | } 910 | } 911 | 912 | if (seq_cnt == seq_max) continue; 913 | } 914 | 915 | if (occur_max) 916 | { 917 | int i; 918 | 919 | for (i = 0; i < len; i++) 920 | { 921 | char c = word_buf[i]; 922 | 923 | int occur_cnt = occurs[(int) c]; 924 | 925 | if (occur_cnt > occur_max) break; 926 | } 927 | 928 | if (i < len) continue; 929 | } 930 | 931 | memcpy (out->buf + out->pos, word_buf, word_len); 932 | 933 | out->pos += word_len; 934 | 935 | if (stop_at) 936 | { 937 | if (memcmp (word_buf + first, stop_at + first, len - first) == 0) 938 | { 939 | if (memcmp (word_buf, stop_at, len) == 0) 940 | { 941 | stop_at = NULL; 942 | 943 | break; 944 | } 945 | } 946 | } 947 | 948 | if (out->pos < OUTBUFSZ) continue; 949 | 950 | fwrite (out->buf, 1, out->pos, fp_out); 951 | 952 | out->pos = 0; 953 | } 954 | 955 | fwrite (out->buf, 1, out->pos, fp_out); 956 | 957 | out->pos = 0; 958 | } 959 | 960 | if (fp_out != stdout) fclose (fp_out); 961 | 962 | return 0; 963 | } 964 | --------------------------------------------------------------------------------