1 /* program: shallot (based on the popular onionhash program by Bebop)
3 * purpose: brute-force customized SHA1-hashes of RSA keys for Tor's
5 * license: OSI-approved MIT License
6 * credits: Bebop, for onionhash, which credits the following:
7 * - Plasmoid (The Hacker's Choice)
8 * - Roger Dingledine (Tor Project)
9 * - Nick Mathewson (Tor Project)
10 * - Eric Young (OpenSSL Project)
12 * I would also like to thank the following testers/benchmarkers:
14 * - Cheeze- (Linux, OS X)
15 * - Tas (Linux, OS X, OpenBSD)
17 * - cybernetseraph (OpenBSD)
19 * Special thanks to nickm for some debugging assistance!
20 * Extra-special thanks to Tas for his patience and assistance
21 * in getting shallot to build on OpenBSD, OS X, and Linux
23 * contact: mention bugs to <`Orum@OFTC or `Orum@ORC>
28 * - figure out a way to allow for -p w/o a pattern being supplied
29 * - allow -m to be used with -f (use file for status output) [v0.0.3]
42 // Linux specific headers
45 #include <string.h> // included with something else on *BSD
50 // BSD specific headers
51 #include <sys/param.h> // needed on OpenBSD
52 #include <sys/sysctl.h>
59 void terminate(int signum
) { // Ctrl-C/kill handler
60 error(X_SGNL_INT_TERM
);
63 int main(int argc
, char *argv
[]) { // onions are fun, here we go
64 signal(SIGTERM
, terminate
); // always let people kill
66 if(argc
< 2) // not enough arguments
69 // set up our initial values
70 uint8_t daemon
= 0, optimum
= 0;
71 uint32_t threads
= 1, x
= 1;
73 elim
= DEFAULT_E_LIMIT
;
80 int mib
[2] = { CTL_HW
, HW_NCPU
}; // how
81 size_t size
= sizeof(threads
); // easy
82 if(sysctl(mib
, 2, &threads
, &size
, NULL
, 0)) // BSD
83 error(X_SYSCTL_FAILED
); // is
85 #elif defined(LINUX_PORT) // Oh no! We're on linux... :(
86 // ...even *Windows 95* (gasp!) has a better way of doing this...
87 // TODO: move this to linux.c
88 char cpuinfo
[CPUINFO_BUF_SIZE
] = "";
89 int fd
= open(CPUINFO_PATH
, O_RDONLY
);
92 error(X_BAD_FILE_DESC
);
94 threads
--; // reset threads to 0
96 ssize_t tmp
= 1; // must not initially be 0!
101 tmp
= read(fd
, &cpuinfo
[r
], CPUINFO_BUF_SIZE
- r
); // fill the buffer
103 if(tmp
< 0) // something went wrong
104 error(X_ABNORMAL_READ
);
106 r
+= tmp
; // add how much we read
108 if(r
< CPUINFO_BUF_SIZE
)
111 threads
+= parse_cpuinfo(&cpuinfo
[0], (uint16_t)r
, &used
);
112 r
-= used
; // subtract what we parsed
114 memmove(&cpuinfo
[0], &cpuinfo
[used
], r
);
117 close(fd
); // TODO: add error handling! (is there any point?)
119 if(!threads
) { // This is needed for Liunx/ARM (do not remove!)
120 printf("WARNING: No CPUs detected. Defaulting to 1 thread... "
121 "(or manually specify thread count with -t)\n");
125 #elif defined(GENERIC)
126 printf("WARNING: Threads will default to 1 unless specified with -t\n");
129 for(; x
< argc
- 1; x
++) { // options parsing
130 if(argv
[x
][0] != '-') {
131 fprintf(stderr
, "Error: Options must start with '-'\n");
135 for(; argv
[x
][y
] != '\0'; y
++) {
138 case 'd': { // daemonize
142 case 'm': { // monitor
146 case 'o': { // prime optimization
150 case 'p': { // pattern help
154 case 'v': { // verbose
158 case 'f': { // file <file>
159 if((argv
[x
][y
+ 1] != '\0') || (x
+ 1 > argc
)) {
160 fprintf(stderr
, "Error: -f format is '-f <file>'\n");
167 case 't': { // threads
168 if((argv
[x
][y
+ 1] != '\0') || (x
+ 1 > argc
)) {
169 fprintf(stderr
, "Error: -t format is '-t threads'\n");
172 threads
= strtoul(argv
[x
+ 1], NULL
, 0);
176 case 'e': { // e limit
177 if((argv
[x
][y
+ 1] != '\0') || (x
+ 1 > argc
)) {
178 fprintf(stderr
, "Error: -e format is '-e limit'\n");
181 elim
= strtoull(argv
[x
+ 1], NULL
, 0);
185 default: { // unrecognized
186 fprintf(stderr
, "Error: Unrecognized option - '%c'\n", argv
[x
][y
]);
188 break; // redundant... but safe :)
192 x
++; //skip the next param
198 // now for our sanity checks
200 error(X_INVALID_THRDS
);
202 if((monitor
&& file
) || (monitor
&& verbose
))
203 error(X_EXCLUSIVE_OPT
);
205 if(!(elim
& 1) || (elim
< RSA_PK_EXPONENT
) || (elim
> MAXIMUM_E_LIMIT
))
206 error(X_INVALID_E_LIM
);
209 error(X_NEED_FILE_OUT
);
212 printf("Options parsed successfully.\nCompiling regex...\n");
214 // compile regular expression from argument
215 char *pattern
= argv
[argc
- 1];
218 error(X_REGEX_INVALID
);
220 regex
= malloc(REGEX_COMP_LMAX
);
222 if(regcomp(regex
, pattern
, REG_EXTENDED
| REG_NOSUB
))
223 error(X_REGEX_COMPILE
);
226 printf("Regex compiled successfully.\n");
230 printf("Redirecting output to file...\n");
232 umask(077); // remove permissions to be safe
236 (freopen(file
, "w", stdout
) == NULL
) ||
237 (freopen(file
, "w", stderr
) == NULL
)
238 ) error(X_FILE_OPEN_ERR
);
241 if(daemon
&& (getppid() != 1)) { // daemonize if we should
243 printf("Daemonizing...\n");
247 if(pid
< 0) // fork failed
248 error(X_DAEMON_FAILED
);
250 if(pid
) // exit on the parent process
253 if(setsid() < 0) // get a new SID
254 error(X_DAEMON_FAILED
);
256 if(chdir("/") < 0) // cd to root
257 error(X_DAEMON_FAILED
);
260 if (freopen("/dev/null", "r", stdin
) == NULL
)
261 error(X_FILE_OPEN_ERR
);
263 // ignore certain signals
264 signal(SIGCHLD
, SIG_IGN
);
265 signal(SIGTSTP
, SIG_IGN
);
266 signal(SIGTTOU
, SIG_IGN
);
267 signal(SIGTTIN
, SIG_IGN
);
268 signal(SIGHUP
, SIG_IGN
);
271 printf("Daemonization completed successfully!\n");
272 } else signal(SIGINT
, terminate
); // die on CTRL-C
277 printf("Spawning threads... (Total: %u)\n", threads
);
279 // create our threads for 2+ cores
280 for(x
= 1; x
< threads
; x
++) {
282 printf("Additional thread spawning (%u)...\n", x
);
284 if(pthread_create(&thrd
, NULL
, worker
, &optimum
))
285 error(X_THREAD_CREATE
);
289 // TODO: when support is added for -mv, put a message here
290 if(pthread_create(&thrd
, NULL
, monitor_proc
, NULL
))
291 error(X_THREAD_CREATE
);
295 printf("All additional threads (if any) spawned.\n"
296 "Main thread (ID: 0x%X) entering loop...\n",
297 (uint32_t)pthread_self());
299 worker(&optimum
); // use main thread for brute forcing too
301 if(pthread_self() != lucky_thread
) { // be safe and avoid EDEADLK
303 printf("Main thread waiting on lucky thread (ID: 0x%X) to exit...\n",
304 (uint32_t)lucky_thread
);
306 pthread_join(lucky_thread
, NULL
); // wait for the lucky thread to exit
310 printf("Lucky thread exited loop.\nCleaning up and exiting...\n");