Added eschalot-1.2.0.tar.gz
This commit is contained in:
commit
ad5089d6cf
|
@ -0,0 +1,81 @@
|
|||
|
||||
Changes from shallot to eschalot-1.2.0:
|
||||
|
||||
* Support both BSD and GNU makes;
|
||||
* Combined (for now) the source files into one to ease code shuffling;
|
||||
* Adjusted includes a bit;
|
||||
* Dropped the automatic CPUs detection and some options;
|
||||
* Simplified the code somewhat;
|
||||
* Limited public exponent 'e' to 4 bytes long (performance gain);
|
||||
* Removed some defines, added some new ones;
|
||||
* Rewrote base32 encoding function to improve performance;
|
||||
* Rewrote error handling and diagnostic messages handling;
|
||||
* Rewrote error handling and diagnostic messages handling again because
|
||||
Linux has poor support for BSD's err(3) family of functions;
|
||||
* Rearranged the code to be more in line with style(9);
|
||||
|
||||
* Changed a bunch of stuff, experimented for a few weeks, put it on hold
|
||||
for some time, lost track of all the changes...
|
||||
|
||||
* Imlemented three search modes: single prefix, regular expression,
|
||||
and wordlist search;
|
||||
* Changed the wordlist mode to be more universal - massive performance
|
||||
gains compared to the first few versions. Settled on some kind of
|
||||
hybrid hashed tree for the words storage;
|
||||
* Wrote a word generator (worgen) to simplify making custom wordlists;
|
||||
* Reworked args and options handling - using getopt now;
|
||||
* Added ifdefs and local versions of strnlen and a htobe32 macro to please
|
||||
Linuxes and FreeBSD;
|
||||
* Added a check for memory corruption (or some other bug - not sure yet);
|
||||
* Added a routine to generate the final onion name from the final
|
||||
RSA key using the same procedure as the official tor project;
|
||||
* Checked the source with several versions of gcc, with pcc, and
|
||||
with clang static analizer on OpenBSD, DragonFlyBSD, FreeBSD, and Linux
|
||||
on 32 and 64bit platforms and on little and big endian platforms,
|
||||
fixed the errors and warnings found.
|
||||
|
||||
|
||||
|
||||
Changed from shallot-0.0.2 to shallot-0.0.3:
|
||||
|
||||
* Fixed some memory leaks.
|
||||
* More efficient use of memory.
|
||||
* Added '-o' option to optimize prime size for SHA-1 hashing.
|
||||
|
||||
|
||||
|
||||
Changed from shallot-0.0.1 to shallot-0.0.2:
|
||||
|
||||
* Corrected some things in the README.
|
||||
* Removed redundant PEM generation.
|
||||
* Improved SHA-1 hashing performance.
|
||||
* The previous two performance enhancements give us a ~4.6x speed boost.
|
||||
That's right, ~4.6 TIMES as fast.
|
||||
* Added a "sanity" limit to e, so it doesn't get insanely high during
|
||||
long hashing sessions. It's adjustable, too.
|
||||
* Allowed the number of threads to be specified during startup.
|
||||
* Added a "monitor" mode (try it out! -m)
|
||||
* Added an option to automatically daemonize
|
||||
* Added file output option
|
||||
* Added a verbose flag (for debugging)
|
||||
* Now configures for BSD-style build on OS X.
|
||||
* Allows for building on unidentified systems, in a slightly crippled form
|
||||
(defaults to 1 thread unless specified).
|
||||
* OpenBSD is now officially supported and tested (it lacks support
|
||||
for sysctlbyname(3), wtf?).
|
||||
* Removed a (small) buffer overflow.
|
||||
|
||||
|
||||
|
||||
Changes from onionhash-0.0.2 to shallot-0.0.1:
|
||||
|
||||
* Fixed a 1KB memory leak.
|
||||
* Removed irrelevant code.
|
||||
* Brute force loop no longer mallocs/frees, giving a ~1% increase in
|
||||
hashing speed.
|
||||
* Now completely multithreaded, allowing systems with several CPUs to
|
||||
take full advantage of all of them to hash!
|
||||
* Now follows PKCS#1 v2.1 for satisfactory public keys
|
||||
(previously on a version prior to v2.0, i.e. v1.5).
|
||||
* BSD and Linux ports (required due to autodetecting core count).
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
Copyright (c) 2013 Unperson Hiro
|
||||
|
||||
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.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
This software is based on shallot which bears the following license:
|
||||
|
||||
Copyright (c) 2007 `Orum <http://hangman5naigg7rr.onion/>
|
||||
<irc://irc.oftc.net:6667/shallot>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
This software is based on onionhash-0.0.2 which bears the following license:
|
||||
|
||||
If you believe in the ideology of "copyright" and what some folks call
|
||||
"interlectual property" you might consider reading the following license
|
||||
agreement.
|
||||
|
||||
However, if you're - like me - a non-believer, a "copyright atheist",
|
||||
someone who thinks that information belongs to mankind itself and
|
||||
cannot be posessed by a person, you're free to simply ignore it :-)
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006 Cowboy Bebop <bebop@torlandypjxiligx.onion>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
The X.Org Foundation BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,67 @@
|
|||
# eschalot Makefile
|
||||
|
||||
# If you modify the Makefile, please make sure it works with
|
||||
# both BSD and GNU makes. Avoid the fancy features.
|
||||
|
||||
PROG1 ?= eschalot
|
||||
PROG2 ?= worgen
|
||||
PROG3 ?= typecard
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR ?= ${PREFIX}/bin
|
||||
|
||||
LIBS += -lpthread -lssl -lcrypto
|
||||
|
||||
WARNINGS += -Wall -W -Wunused -pedantic -Wpointer-arith \
|
||||
-Wreturn-type -Wstrict-prototypes \
|
||||
-Wmissing-prototypes -Wshadow -Wcast-qual -Wextra
|
||||
|
||||
CFLAGS += -std=c99
|
||||
CFLAGS += -O2
|
||||
CFLAGS += -fPIC
|
||||
CFLAGS += -finline-functions
|
||||
#CFLAGS += -fomit-frame-pointer
|
||||
#CFLAGS += -m64
|
||||
#CFLAGS += -mtune=native -march=native
|
||||
#CFLAGS += -g
|
||||
|
||||
CC ?= cc
|
||||
INSTALL ?= install -c -o root -g bin -m 755
|
||||
RM ?= /bin/rm -f
|
||||
|
||||
all: ${PROG1} ${PROG2}
|
||||
|
||||
${PROG1}: ${PROG1}.c Makefile
|
||||
${CC} ${CFLAGS} ${WARNINGS} -o $@ ${PROG1}.c ${LIBS}
|
||||
|
||||
${PROG2}: ${PROG2}.c Makefile
|
||||
${CC} ${CFLAGS} ${WARNINGS} -o $@ ${PROG2}.c
|
||||
|
||||
# make typecard - quick overview of the basic types on the system
|
||||
${PROG3}: ${PROG3}.c Makefile
|
||||
${CC} ${CFLAGS} -o $@ ${PROG3}.c
|
||||
./${PROG3}
|
||||
|
||||
install: all
|
||||
${INSTALL} ${PROG1} ${BINDIR}
|
||||
${INSTALL} ${PROG2} ${BINDIR}
|
||||
|
||||
clean:
|
||||
${RM} ${PROG1} ${PROG2} ${PROG3} *.o *.p *.d *.s *.S *~ *.core .depend
|
||||
|
||||
# Simple procedure to speed up basic testing on multiple platforms
|
||||
WF1 = top150adjectives.txt
|
||||
WF2 = top400nouns.txt
|
||||
WF3 = top1000.txt
|
||||
WLIST = wordlist.txt
|
||||
RESULTS = results.txt
|
||||
|
||||
test: all
|
||||
./${PROG2} 8-16 ${WF1} 3-16 ${WF2} 3-16 ${WF3} 3-16 > ${WLIST}
|
||||
./${PROG1} -vct4 -f ${WLIST} > ${RESULTS}
|
||||
|
||||
cleantest:
|
||||
${RM} ${WLIST} ${RESULTS}
|
||||
|
||||
cleanall: clean cleantest
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
About:
|
||||
------
|
||||
|
||||
Eschalot is a TOR hidden service name generator, it allows one to produce
|
||||
a (partially) customized vanity .onion address using a brute-force method.
|
||||
|
||||
See http://torproject.org for more information about the TOR network
|
||||
and http://torproject.org/docs/hidden-services for the hidden services
|
||||
documentation.
|
||||
|
||||
Why eschalot? Well, eschalot is a different name for shallot and it is
|
||||
a fork of an older .onion names generator called shallot.
|
||||
|
||||
See http://github.com/katmagic/Shallot for information about the shallot
|
||||
and also see the History section at the end of this document.
|
||||
|
||||
Eschalot is distributed in source form under BSD license. It should compile
|
||||
on any Unix or Linux system, but might need some minor modifications.
|
||||
|
||||
It was developed and most extensively tested on OpenBSD, but was also tested
|
||||
to compile and run on DragonFlyBSD, FreeBSD, CentOS Linux, and couple other
|
||||
mainstream Linux distributions whose names I do not recall at the moment.
|
||||
Various combinations of big/little endian platforms, 32bit/64bit platforms,
|
||||
and gcc/pcc/llvm/clang static analizer were tested. Many bugs were uncovered,
|
||||
some were fixed, some are still there - see TODO list if interested.
|
||||
|
||||
|
||||
|
||||
Compilation:
|
||||
------------
|
||||
|
||||
Eschalot requires OpenSSL-0.9.7-or-later libraries with source headers.
|
||||
|
||||
You will also need a make utility (either BSD or GNU make will do) and
|
||||
a C compiler (gcc, pcc, or llvm/clang).
|
||||
|
||||
Download the latest version of eschalot (currently eschalot-1.2.0), open a
|
||||
terminal emulator, such as xterm, and change directory to where you saved
|
||||
the eschalot-1.2.0.tar.gz archive (for examle /home/username/Download);
|
||||
|
||||
$ cd Download
|
||||
$ tar xzvf eschalot-1.2.0.tar.gz
|
||||
$ cd eschalot-1.2.0
|
||||
$ make
|
||||
|
||||
To use a different (other than your system default) C compiler (such as pcc):
|
||||
|
||||
$ make clean
|
||||
$ env CC=pcc make
|
||||
|
||||
If compilation fails, see some hints below under "Compilation Troubleshooting"
|
||||
close to the end of this document.
|
||||
|
||||
If make succeeds, you might want to run a simple functionality test/demo with
|
||||
|
||||
$ make test
|
||||
|
||||
This will use the included worgen utility to create a test wordlist out of the
|
||||
three small wordlists included with the distribution, will save the list to
|
||||
'wordlist.txt', and will launch eschalot running with 4 threads to start
|
||||
looking for the onion names with the prefixes in the wordlist.txt file.
|
||||
The results will be redirected to the 'results.txt' file. This test needs
|
||||
a fairly fast machine with at least 250Mb of RAM.
|
||||
|
||||
To remove the test files execute
|
||||
|
||||
$ make cleantest
|
||||
|
||||
To remove the compiled binaries execute
|
||||
|
||||
$ make clean
|
||||
|
||||
To cleanup everything execute
|
||||
|
||||
$ make cleanall
|
||||
|
||||
|
||||
|
||||
Example output from 'make test':
|
||||
--------------------------------
|
||||
|
||||
$ make test
|
||||
cc -std=c99 -O2 -fPIC -finline-functions -Wall -W -Wunused -pedantic -Wpointer-arith -Wreturn-type -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wcast-qual -Wextra -o eschalot eschalot.c -lpthread -lssl -lcrypto
|
||||
cc -std=c99 -O2 -fPIC -finline-functions -Wall -W -Wunused -pedantic -Wpointer-arith -Wreturn-type -Wstrict-prototypes -Wmissing-prototypes -Wshadow -Wcast-qual -Wextra -o worgen worgen.c
|
||||
|
||||
./worgen 8-16 top150adjectives.txt 3-16 top400nouns.txt 3-16 top1000.txt 3-16 > wordlist.txt
|
||||
Will be producing 8-16 character long word combinations.
|
||||
Reading 3-16 characters words from top150adjectives.txt.
|
||||
Reading 3-16 characters words from top400nouns.txt.
|
||||
Reading 3-16 characters words from top1000.txt.
|
||||
Loading words from top150adjectives.txt.
|
||||
Loaded 150 words from top150adjectives.txt.
|
||||
Loading words from top400nouns.txt.
|
||||
Loaded 400 words from top400nouns.txt.
|
||||
Loading words from top1000.txt.
|
||||
Loaded 974 words from top1000.txt.
|
||||
Working. 100% complete, 31122412 words (approximately 377Mb) produced.
|
||||
Final count: 31366539 word combinations.
|
||||
|
||||
./eschalot -vct4 -f wordlist.txt > results.txt
|
||||
Verbose, continuous, no digits, 4 threads, prefixes 8-16 characters long.
|
||||
Reading words from wordlist.txt, please wait...
|
||||
Loaded 31366539 words.
|
||||
Sorting the word hashes and removing duplicates.
|
||||
Final word count: 31363570.
|
||||
Thread #1 started.
|
||||
Thread #2 started.
|
||||
Thread #3 started.
|
||||
Thread #4 started.
|
||||
Running, collecting performance data...
|
||||
Found a key for acidfall (8) - acidfalleyt3kkva.onion
|
||||
Total hashes: 131241356, running time: 10 seconds, hashes per second: 13124135
|
||||
Found a key for redglass (8) - redglass6i2pxool.onion
|
||||
Found a key for loudwalk (8) - loudwalk72kvhr4n.onion
|
||||
Found a key for illarteye (9) - illarteyedjxf3pj.onion
|
||||
Total hashes: 394606458, running time: 30 seconds, hashes per second: 13153548
|
||||
Found a key for cutcolor (8) - cutcolorxqxz7ck4.onion
|
||||
Found a key for safefold (8) - safefold7hmcigr7.onion
|
||||
Found a key for tallidea (8) - tallideac5zyn3f7.onion
|
||||
Found a key for wetactago (9) - wetactagot7b42kx.onion
|
||||
Found a key for pooryear (8) - pooryearxutsizhe.onion
|
||||
^C*** Signal SIGINT in eschalot-1.2.0 (test)
|
||||
|
||||
|
||||
|
||||
Usage:
|
||||
------
|
||||
|
||||
Type
|
||||
$ ./eschalot
|
||||
and
|
||||
$ ./worgen
|
||||
|
||||
without any options to get a quick usage information.
|
||||
|
||||
|
||||
To search using 4 threads (if your CPU has 4 cores), in a verbose mode,
|
||||
continuing to search after an .onion address is found, looking for a single
|
||||
prefix "test":
|
||||
|
||||
$ ./eschalot -t4 -v -c -p test
|
||||
|
||||
or simply
|
||||
|
||||
$ ./eschalot -vct4 -p test
|
||||
|
||||
To search using a regular expression looking for names starting with "test"
|
||||
or ending with "exam":
|
||||
|
||||
$ ./eschalot -vct4 -r "^test|exam$"
|
||||
|
||||
To search for a single prefix "hello" using one thread, redirecting the
|
||||
output to a file named "results.txt", exiting after the first name is found:
|
||||
|
||||
$ ./eschalot -p hello >> results.txt
|
||||
|
||||
To search for prefixes from 8 to 10 characters long from a file named
|
||||
"wordlist.txt" using 6 threads, in continuous and verbose mode,
|
||||
redirecting the results to a file:
|
||||
|
||||
$ ./eschalot -vct6 -l8-10 -f wordlist.txt >> results.txt
|
||||
|
||||
|
||||
|
||||
Generating a wordlist:
|
||||
----------------------
|
||||
|
||||
You can use the included utility "worgen" to generate large wordlists for
|
||||
eschalot. This utility is far from complete and is not very user friendly,
|
||||
but can be used if needed. To demonstrate by example:
|
||||
|
||||
Generate a (relatively small) list of 8 to 12 character long words by
|
||||
mixing 3-10 character words from top1000.txt file, 3-6 character words
|
||||
from top400nouns.txt, and 3-6 character words from top140adjectives.txt,
|
||||
redirect the results to wordlist.txt:
|
||||
|
||||
$ ./worgen 8-12 top1000.txt 3-10 top400nouns.txt \
|
||||
3-6 top150adjectives.txt 3-6 > wordlist.txt
|
||||
|
||||
|
||||
Generate a large (~1.2Gb) file of 10 character long words by mixing twice
|
||||
words from a single file:
|
||||
|
||||
$ ./worgen 10-10 nouns.txt 3-10 nouns.txt 3-10 > wordlist.txt
|
||||
|
||||
At this point you might want to try running
|
||||
|
||||
$ ./eschalot -vct6 -l 10-10 -f wordlist.txt > results.txt
|
||||
|
||||
to test if your system can load a large file into memory.
|
||||
|
||||
The result should look something like this:
|
||||
|
||||
$ ./eschalot -vct6 -l 10-10 -f wordlist.txt > results.txt
|
||||
Verbose, continuous, no digits, 6 threads, prefixes 10-10 characters long.
|
||||
Reading words from wordlist.txt, please wait...
|
||||
Loaded 110792061 words.
|
||||
Sorting the word hashes and removing duplicates.
|
||||
Final word count: 110558812.
|
||||
Thread #1 started.
|
||||
Thread #2 started.
|
||||
Thread #3 started.
|
||||
Thread #4 started.
|
||||
Thread #5 started.
|
||||
Thread #6 started.
|
||||
Running, collecting performance data...
|
||||
Found a key for museumazof (10) - museumazofgsihx2.onion
|
||||
Found a key for balzacnick (10) - balzacnickaxtbd4.onion
|
||||
Found a key for methodmoor (10) - methodmooraudcft.onion
|
||||
Found a key for gneissbutt (10) - gneissbuttieicps.onion
|
||||
Found a key for todcorypha (10) - todcoryphadr7zv4.onion
|
||||
Found a key for pleveniyar (10) - pleveniyarpa3hlx.onion
|
||||
Found a key for caputwight (10) - caputwightz46r3n.onion
|
||||
Found a key for mervensalp (10) - mervensalpskbwad.onion
|
||||
Found a key for hallelenid (10) - hallelenidmhln6o.onion
|
||||
Found a key for quotalysis (10) - quotalysisadbc57.onion
|
||||
Found a key for longabarth (10) - longabarthvvdjpw.onion
|
||||
Found a key for vannlozier (10) - vannlozierwqadcv.onion
|
||||
Found a key for uriahcadre (10) - uriahcadreac7ujz.onion
|
||||
Found a key for denmarkjew (10) - denmarkjewfyozqj.onion
|
||||
Found a key for kochiiclod (10) - kochiiclodifftuw.onion
|
||||
Found a key for fondusamba (10) - fondusambaialjro.onion
|
||||
^C
|
||||
|
||||
As you see, it finds a lot of prefixes in just a few seconds, but most of them
|
||||
are useless - that's the downside of using a really large wordlist with either
|
||||
junk or extremely uncommon words combinations in it. Experiment with it! :)
|
||||
|
||||
|
||||
|
||||
Security of generated keys:
|
||||
---------------------------
|
||||
|
||||
Original note from Shallot:
|
||||
|
||||
It is sometimes claimed that private keys generated by Shallot are less
|
||||
secure than those generated by Tor. This is false. Although Shallot generates
|
||||
a keypair with an unusually large public exponent e, it performs all of the
|
||||
sanity checks specified by PKCS #1 v2.1 (directly in sane_key), and then
|
||||
performs all of the sanity checks that Tor does when it generates an RSA
|
||||
keypair (by calling the OpenSSL function RSA_check_key).
|
||||
|
||||
|
||||
Eschalot additions:
|
||||
|
||||
Now the public exponent is limited to the range of
|
||||
(0xFFFFFF + 2) to (0xFFFFFFFF) - basically, odd values that take at least,
|
||||
and no more than, 4 bytes.
|
||||
|
||||
In addition, unlike shallot, after the RSA key has been finalized, the
|
||||
.onion name is regenerated using the same procedure as used in the official
|
||||
TOR client - this filters out the occasional bogus .onions that shallot
|
||||
generated occasionally (and eschalot does too - this is a bug I have not
|
||||
tracked down yet).
|
||||
|
||||
Now, there is nothing stopping the TOR developers from modifying the TOR
|
||||
client to only accept manually imported keys with public exponent equal,
|
||||
lets say, 65537 and nothing else, but that would be silly of them. It would
|
||||
not improve TOR's performance much or serve any other purpose, but to
|
||||
knock offline several well established hidden websites that have been using
|
||||
shallot-generated keys for years. I would not worry about it.
|
||||
|
||||
|
||||
|
||||
Performance:
|
||||
------------
|
||||
|
||||
Depends on how fast your CPU is and how many cores you have, but generally
|
||||
speaking it's a bit faster than shallot. Up to twice as fast in some cases,
|
||||
but it depends greatly on how fast the OpenSSL's SHA1 implementation is on
|
||||
the system. Some use hand-optimized assembly, some use C versions.
|
||||
|
||||
Wordlist mode is obviously slower than a single fixed prefix mode, but not
|
||||
by much. The difference between searching in a 100 words list and a 100 million
|
||||
words list is negligible due to the binary search and hashed tree data
|
||||
storage. Of course, that is if the whole wordlist fits in RAM completely.
|
||||
|
||||
Memory needed is approximately 0.5-0.7 of the size of the wordlist size
|
||||
on disk (yes, eschalot needs less memory than the file takes due to the words
|
||||
getting converted into binary format and stored in a sort of a hashed tree).
|
||||
|
||||
|
||||
|
||||
Compilation Troubleshooting:
|
||||
----------------------------
|
||||
|
||||
1). Does the error message you are getting give you any hints?
|
||||
|
||||
|
||||
2). If the error message complains that make/gmake/gcc/cc cannot be found,
|
||||
you will need to install the make/gmake utility and gcc or some other C
|
||||
compiler. Some of the Linuxes split the gcc package into several smaller ones
|
||||
- you will need the one that says "GNU C Compiler" or something like that.
|
||||
|
||||
Note: most of the mainstream Linuxes do not come with a compiler by default
|
||||
theese days even if you choose a complete - often 5-10Gb - installation.
|
||||
(Yeah, that was a shock for me too), but it's fairly easy to install it by
|
||||
using your operating system's software manager.
|
||||
|
||||
|
||||
3). If it says something like "SHA1*** / RSA*** /BN_*** function not defined"
|
||||
or "missing <openssl/***.h> header", you will need to make sure you not
|
||||
only have the dynamic OpenSSL libraries installed, but also the header files.
|
||||
On Linuxes, they are sometimes distributed in a different package from the
|
||||
main OpenSSL and are called something like "OpenSSL-development" or
|
||||
"OpenSSL-sources-and-headers" or something like that - look around.
|
||||
|
||||
|
||||
4). If you get an error message about 'htobe32' function not being defined,
|
||||
you can try using a locally-supplied copy by compiling with
|
||||
|
||||
$ env CFLAGS=-DNEED_HTOBE32 make
|
||||
|
||||
Same if your system does not have strnlen - try
|
||||
|
||||
$ env CFLAGS=-DNEED_STRNLEN make
|
||||
|
||||
Or might even have to define both like this:
|
||||
|
||||
$ env CFLAGS="-DNEED_HTOBE32 -DNEED_STRNLEN" make
|
||||
|
||||
|
||||
5). If all of the above fails, take a look inside the Makefile, and see if
|
||||
you need to disable or enable some additional C flags.
|
||||
|
||||
|
||||
6). If your error message says something about endian.h, take a look at the
|
||||
beginning of the eschalot.c file, see how that file is being included.
|
||||
You might need to adjust it a bit (that part needs work - see TODO list).
|
||||
|
||||
|
||||
7). If all else fails, send me an email or post something on the feedback
|
||||
forum. I'll be happy to hear any feedback, positive or negative, and will try
|
||||
to help.
|
||||
|
||||
|
||||
|
||||
Bugs and ToDo list:
|
||||
-------------------
|
||||
|
||||
0). Highest priority bug:
|
||||
Every so often, while searching in a wordlist mode, eschalot finds the
|
||||
right prefix, but then, after finalizing the key and regenerating the .onion
|
||||
name, the result is garbage. I suspected my CPU or RAM overheating at first,
|
||||
but now I tend to think it's a bug in the program (or OpenSSL) somewhere.
|
||||
It gets detected and rejected and a message is printed on STDERR, but it's
|
||||
a big waste of hash cycles. Have to track it down.
|
||||
|
||||
1). worgen dumps core on 32-bit OpenBSD when using fairly large input
|
||||
wordlists (triggers stack smash protection). Works fine on 64-bit systems.
|
||||
|
||||
2). I tried to optimize the main loop somewhat, but the wordlist loading
|
||||
could use some improvement - realloc'ing 8 bytes at a time is slow (was
|
||||
concerned about total memory used when loading large files when I did it).
|
||||
|
||||
3). Need better statistics with estimated time needed predictions.
|
||||
|
||||
4). Half the variables are global - does not hurt in this case, but is ugly.
|
||||
|
||||
5). Print out the public exponent used when a key is found.
|
||||
|
||||
6). Write a manpage.
|
||||
|
||||
7). Optimize and improve the worgen utility, it was a quick hack.
|
||||
|
||||
8). More testing on different OSes, finalize the htobe32/strnlen defines mess.
|
||||
|
||||
9). Attempt to implement a GPU hashing mode for Linux.
|
||||
|
||||
10). Add a local SHA1 function written in assembly for sparc/sparc64.
|
||||
|
||||
11). Make it compile on windows and provide windows binary.
|
||||
|
||||
12). Go over the numerous TODOs in the code and address them.
|
||||
|
||||
13). Generate one ultimate wordlist with good word combinations 8-16 chars
|
||||
long, about 5-10Gb in size total, so it could be used to search for a
|
||||
specific lengths even if the whole thing cannot fit in RAM at once. Perhaps
|
||||
grab all the phrases and word combinations from a few hundred ebooks
|
||||
instead of generating randomly mixed rubbish?
|
||||
|
||||
14). Move the defines, includes, and functions shared between eschalot and
|
||||
worgen into "common.h/common.c" files.
|
||||
|
||||
15). Add a real self-test with fixed initial RSA key, compare a few hundred
|
||||
generated .onion names to a known good file. Or something like that.
|
||||
Make it all driven through the Makefile to simplify testing on different
|
||||
platforms.
|
||||
|
||||
|
||||
History:
|
||||
--------
|
||||
|
||||
Circa 2006, a person with a nickname Cowboy Bebop created the original
|
||||
onionhash-0.0.1, which evolved into onionhash-0.0.2 and 0.0.3, until Bebop
|
||||
and his home at torlandypjxiligx.onion mysteriously vanished.
|
||||
|
||||
At this point, it was picked up by someone called Orum, who renamed the
|
||||
onionhash to shallot and went through three versions until Orum's site at
|
||||
hangman5naigg7rr.onion disappeared.
|
||||
|
||||
Another concerned OnionLand citizen Katmagic got shallot's sources from
|
||||
taswebqlseworuhc.onion and put them into a Git repository. Made a few
|
||||
modifications, wrote a new README, and put the whole thing up on GitHub.
|
||||
|
||||
I stumbled on the project at some point and had a few ideas on how to make
|
||||
it more flexible. However, the changes I planned to make were too extensive
|
||||
to consider simply patching shallot, so I decided to fork it and work on
|
||||
it for my own private use. After messing with it (very) occasionally for
|
||||
couple of months, I figured it might be of use to some other TOR enthusiasts,
|
||||
even though I would not call my remake of shallot "production ready".
|
||||
|
||||
Initially I named my project "scallion", however, just a few days ago, I have
|
||||
learned of yet another .onion names generator recently released which was,
|
||||
unsurprisingly, named scallion, so I renamed my project to "eschalot".
|
||||
|
||||
See http://github.com/lachesis/scallion for more details on scallion.
|
||||
|
||||
It's all about choices and now you have several!
|
||||
|
||||
P.S. Following the tradition set forth by the previous authors, I will
|
||||
remain anonymous for the time being.
|
||||
|
||||
P.P.S. Sending my greetings and thanks to all the people who worked on this
|
||||
project before me and kept it alive over the years!
|
||||
|
||||
--Unperson Hiro
|
||||
19 February 2013
|
||||
|
|
@ -0,0 +1,791 @@
|
|||
/* eschalot - generates vanity .onion names using brute-force hashing.
|
||||
* A fork of shallot, which was a fork of onionhash. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Unperson Hiro <blacksunhq56imku.onion>
|
||||
* Copyright (c) 2007 Orum <hangman5naigg7rr.onion>
|
||||
* Copyright (c) 2006 Cowboy Bebop <torlandypjxiligx.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.
|
||||
*/
|
||||
|
||||
/* Lets agree on 100 characters line limit, tab is 8 spaces long, second level ident is 4 spaces. */
|
||||
/* ---------- This wide ------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef __linux__
|
||||
# define _GNU_SOURCE
|
||||
# include <endian.h>
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
# include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <regex.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
/* Define NEED_HTOBE32 if htobe32() is not available on your platform. */
|
||||
/* #define NEED_HTOBE32 */
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
# ifdef NEED_HTOBE32
|
||||
# define HTOBE32(x) (((uint32_t)(x) & 0xffu) << 24 | \
|
||||
((uint32_t)(x) & 0xff00u) << 8 | \
|
||||
((uint32_t)(x) & 0xff0000u) >> 8 | \
|
||||
((uint32_t)(x) & 0xff000000u) >> 24)
|
||||
# else
|
||||
# define HTOBE32(x) htobe32(x)
|
||||
# endif
|
||||
#else
|
||||
# define HTOBE32(x) (x)
|
||||
#endif
|
||||
|
||||
/* Define NEED_STRNLEN if strnlen() is not available on your platform. */
|
||||
/* #define NEED_STRNLEN */
|
||||
#ifdef NEED_STRNLEN
|
||||
static size_t strnlen(const char *, size_t);
|
||||
size_t
|
||||
strnlen(const char *s, size_t ml)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; *(s + i) != '\0' && i < ml; i++)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define VERSION "1.2.0"
|
||||
#define SHA_REL_CTX_LEN 10 * sizeof(SHA_LONG) /* 40 bytes */
|
||||
#define RSA_KEYS_BITLEN 1024 /* RSA key length to use */
|
||||
#define SIZE_OF_E 4 /* Limit public exponent to 4 bytes */
|
||||
#define RSA_E_START 0xFFFFFFu + 2 /* Min e */
|
||||
#define RSA_E_LIMIT 0xFFFFFFFFu /* Max e */
|
||||
#define ONION_LENP1 17 /* Onion name length plus 1 */
|
||||
#define MAX_THREADS 100 /* Maximum number of threads */
|
||||
#define MAX_WORDS 0xFFFFFFFFu /* Maximum words to read from file */
|
||||
#define BASE32_ALPHABET "abcdefghijklmnopqrstuvwxyz234567"
|
||||
|
||||
extern char *__progname;
|
||||
|
||||
/* Error and debug functions */
|
||||
static void usage(void);
|
||||
static void error(char *, ...);
|
||||
static void verbose(char *, ...);
|
||||
static void normal(char *, ...);
|
||||
static void (*msg)(char *, ...);
|
||||
/* User IO functions */
|
||||
static void setoptions(int, char *[]);
|
||||
static void readfile(void);
|
||||
static void printresult(RSA *, uint8_t *, uint8_t *);
|
||||
/* Math and search functions */
|
||||
static _Bool fsearch(uint8_t *, uint8_t *);
|
||||
static _Bool psearch(uint8_t *, uint8_t *);
|
||||
static _Bool rsearch(uint8_t *, uint8_t *);
|
||||
static _Bool (*search)(uint8_t *, uint8_t *);
|
||||
static _Bool validkey(RSA *);
|
||||
static signed int compare(const void *, const void *);
|
||||
static void base32_enc(uint8_t *, uint8_t *);
|
||||
static void base32_dec(uint8_t *, uint8_t *);
|
||||
static void onion_enc(uint8_t *, RSA *);
|
||||
static void zerobits(uint16_t * ind, uint64_t * word,
|
||||
uint8_t * buffer, unsigned int length);
|
||||
/* Main thread routine */
|
||||
static void *worker(void *);
|
||||
|
||||
/* Global variables */
|
||||
/* TODO: perhaps getting rid of so many globals is in order... */
|
||||
_Bool done, cflag, fflag, nflag, pflag, rflag, vflag;
|
||||
unsigned int minlen, maxlen, threads, prefixlen, wordcount;
|
||||
char fn[FILENAME_MAX + 1], prefix[ONION_LENP1];
|
||||
regex_t *regex;
|
||||
|
||||
struct {
|
||||
unsigned int count;
|
||||
uint64_t *branch;
|
||||
} tree[65536] = { {0, NULL} };
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
pthread_t babies[MAX_THREADS];
|
||||
uint64_t count[MAX_THREADS];
|
||||
unsigned int i, j, dupcount = 0;
|
||||
|
||||
/* Initialize global flags */
|
||||
wordcount = done = cflag = fflag = nflag = pflag = rflag = vflag = 0;
|
||||
minlen = 8;
|
||||
maxlen = 16;
|
||||
threads = 1;
|
||||
msg = normal; /* Default: non-verbose */
|
||||
search = NULL; /* No default search, has to be specified */
|
||||
|
||||
setoptions(argc, argv);
|
||||
|
||||
if (fflag) {
|
||||
readfile();
|
||||
msg("Sorting the word hashes and removing duplicates.\n");
|
||||
wordcount = 0;
|
||||
for (i = 0; i < 65536; i++) {
|
||||
dupcount = 0;
|
||||
qsort(tree[i].branch, tree[i].count, sizeof(tree[i].branch[0]), &compare);
|
||||
for (j = 1; j < tree[i].count ; j++) {
|
||||
if (tree[i].branch[j] == tree[i].branch[j - 1]) {
|
||||
tree[i].branch[j - 1] = 0xFFFFFFFFFFFFFFFFu;
|
||||
dupcount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dupcount > 0) {
|
||||
qsort(tree[i].branch, tree[i].count, sizeof(tree[i].branch[0]),
|
||||
&compare);
|
||||
tree[i].count -= dupcount;
|
||||
}
|
||||
wordcount += tree[i].count;
|
||||
}
|
||||
msg("Final word count: %d.\n", wordcount);
|
||||
}
|
||||
|
||||
/* Start our threads */
|
||||
for (i = 1; i <= threads; i++) {
|
||||
count[i] = 0;
|
||||
if (pthread_create(&babies[i], NULL, worker, (void *)&count[i]) != 0)
|
||||
error("Failed to start thread!\n");
|
||||
msg("Thread #%d started.\n", i);
|
||||
}
|
||||
|
||||
/* Monitor performance
|
||||
* TODO: redo this whole thing, add estimate time for keys */
|
||||
if (vflag) {
|
||||
uint64_t loops;
|
||||
time_t elapsed, start = time(NULL);
|
||||
unsigned int delay = 5;
|
||||
|
||||
msg("Running, collecting performance data...\n");
|
||||
for(;;) {
|
||||
sleep(delay *= 2);
|
||||
if (done)
|
||||
return 0;
|
||||
|
||||
/* Collect our thread's counters */
|
||||
loops = 0;
|
||||
i = threads;
|
||||
do {
|
||||
loops += count[i];
|
||||
} while (--i);
|
||||
|
||||
/* On a really slow machine the initial delay might not be
|
||||
* enough to generate the first RSA key, so give it more time. */
|
||||
if (loops == 0)
|
||||
continue;
|
||||
|
||||
elapsed = time(NULL) - start;
|
||||
|
||||
/* Bug here somewhere - with pcc compiler only. */
|
||||
/* TODO: Fix. */
|
||||
msg("Total hashes: %" PRIu64
|
||||
", running time: %d seconds, hashes per second: %" PRIu64 "\n",
|
||||
loops, elapsed, (uint64_t)(loops / elapsed));
|
||||
}
|
||||
}
|
||||
/* Wait for all the threads to exit */
|
||||
for (i = 1; i <= threads; i++)
|
||||
pthread_join(babies[i], NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Main hashing thread */
|
||||
void *
|
||||
worker(void *arg)
|
||||
{
|
||||
SHA_CTX hash, copy;
|
||||
RSA *rsa;
|
||||
uint8_t *tmp, *der,
|
||||
buf[SHA_DIGEST_LENGTH],
|
||||
onion[ONION_LENP1],
|
||||
onionfinal[ONION_LENP1];
|
||||
signed int derlen;
|
||||
uint64_t *counter;
|
||||
/* Public exponent and the "big-endian" version of it */
|
||||
unsigned int e, e_be;
|
||||
|
||||
counter = (uint64_t *)arg;
|
||||
|
||||
while (!done) {
|
||||
/* Generate a new RSA key every time e reaches RSA_E_LIMIT */
|
||||
rsa = RSA_generate_key(RSA_KEYS_BITLEN, RSA_E_START,
|
||||
NULL, NULL);
|
||||
if (!rsa)
|
||||
error("RSA Key Generation failed!\n");
|
||||
|
||||
/* Too chatty - disable. */
|
||||
/* msg("Generated a new RSA key pair.\n"); */
|
||||
|
||||
/* Encode RSA key in X.690 DER format */
|
||||
if((derlen = i2d_RSAPublicKey(rsa, NULL)) < 0)
|
||||
error("DER encoding failed!\n");
|
||||
if ((der = tmp = (uint8_t *)malloc(derlen)) == NULL)
|
||||
error("malloc(derlen) failed!\n");
|
||||
if (i2d_RSAPublicKey(rsa, &tmp) != derlen)
|
||||
error("DER encoding failed!\n");
|
||||
|
||||
/* Prepare the hash context */
|
||||
SHA1_Init(&hash);
|
||||
SHA1_Update(&hash, der, derlen - SIZE_OF_E);
|
||||
free(der);
|
||||
e = RSA_E_START - 2; /* public exponent */
|
||||
|
||||
/* Main loop */
|
||||
while ((e < RSA_E_LIMIT) && !done) {
|
||||
e += 2;
|
||||
/* Convert e to big-endian format. */
|
||||
e_be = HTOBE32(e);
|
||||
/* Copy the relevant parts of already set up context. */
|
||||
memcpy(©, &hash, SHA_REL_CTX_LEN); /* 40 bytes */
|
||||
copy.num = hash.num;
|
||||
/* Compute SHA1 digest (the real bottleneck) */
|
||||
SHA1_Update(©, &e_be, SIZE_OF_E);
|
||||
SHA1_Final(buf, ©);
|
||||
(*counter)++;
|
||||
/* This is fairly fast, but can be faster if inlined. */
|
||||
base32_enc(onion, buf);
|
||||
|
||||
/* The search speed varies based on the mode we are in.
|
||||
* Regex's performance depends on the expression used.
|
||||
* Fixed prefix is as fast as memcmp(3).
|
||||
* Wordlist performance depends on (mostly):
|
||||
* number of "lengths" to search for (-l from-to);
|
||||
* number of unique words loaded from file.
|
||||
*
|
||||
* Inlining everything and optimizing for one mode and
|
||||
* fixed word length improved the performance somewhat
|
||||
* when I tried it, but it's not worth it. */
|
||||
if (search(buf, onion)) {
|
||||
/* Found a possible key,
|
||||
* from here on down performance is not critical. */
|
||||
if (!BN_bin2bn((uint8_t *)&e_be, SIZE_OF_E, rsa->e))
|
||||
error("Failed to set e in RSA key!\n");
|
||||
if (!validkey(rsa))
|
||||
error("A bad key was found!\n");
|
||||
if (pflag)
|
||||
onion[prefixlen] = '\0';
|
||||
|
||||
onion_enc(onionfinal, rsa);
|
||||
|
||||
/* Every so often the onion found matches
|
||||
* whatever we were looking for, but the final
|
||||
* generated onion is garbage. I suspect a CPU
|
||||
* or RAM overheating, but it could be a subtle
|
||||
* bug somewhere. Hard to pin-point. According
|
||||
* to the reports I've seen, shallot has had a
|
||||
* similar problem.
|
||||
*
|
||||
* Happens most often in a wordlist search mode,
|
||||
* but I think I have seen it in a regex mode
|
||||
* as well. Does not seem to happen in a fixed
|
||||
* prefix mode.
|
||||
*
|
||||
* Adding this check to avoid producing garbage
|
||||
* results and to alleviate the problem a bit. */
|
||||
if (strncmp((char *)onion, (char *)onionfinal,
|
||||
(!rflag ? strnlen((char *)onion, ONION_LENP1) : 16))) {
|
||||
msg("\nWARNING! Error detected! CPU/RAM overheating?\n");
|
||||
msg("Found %s, but finalized to %s.\n",
|
||||
(char *)onion, (char *)onionfinal);
|
||||
msg("Suspending this thread for 30 seconds.\n");
|
||||
sleep(30);
|
||||
msg("Generating new RSA key.\n\n");
|
||||
break;
|
||||
} else
|
||||
printresult(rsa, onion, onionfinal);
|
||||
|
||||
if (!cflag)
|
||||
done = 1; /* Notify other threads. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
RSA_free(rsa);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read words from file */
|
||||
void
|
||||
readfile(void)
|
||||
{
|
||||
FILE *file;
|
||||
uint8_t w[ONION_LENP1] = { 0 }, buf[10];
|
||||
uint8_t len, j;
|
||||
uint16_t ind;
|
||||
signed int c;
|
||||
uint64_t wrd;
|
||||
_Bool inword;
|
||||
|
||||
if ((file = fopen(fn,"r")) == NULL)
|
||||
error("Failed to open %s!\n", fn);
|
||||
msg("Reading words from %s, please wait...\n", fn);
|
||||
|
||||
/* We have to inspect each character individually anyway,
|
||||
* so lets just use fgetc here and let the OS buffer stuff. */
|
||||
j = 0;
|
||||
while ((c = fgetc(file)) != EOF) {
|
||||
c = tolower(c);
|
||||
inword = 0;
|
||||
/* Only load words with digits if the -n option was used. */
|
||||
if ((c >= 'a' && c <= 'z') || (nflag && c >= '2' && c <= '7')) {
|
||||
w[j++] = c;
|
||||
inword = 1;
|
||||
}
|
||||
|
||||
if ((!inword && j > 0) || j > 16) {
|
||||
/* We clip the words longer than 16 characters here. */
|
||||
w[j] = '\0';
|
||||
j = 0;
|
||||
/* Only pick the words of the length we need. */
|
||||
len = strnlen((char *)w, ONION_LENP1);
|
||||
if (len >= minlen && len <= maxlen && wordcount < MAX_WORDS) {
|
||||
base32_dec(buf, w);
|
||||
memset(w, 0, sizeof(w));
|
||||
zerobits(&ind, &wrd, buf, len);
|
||||
|
||||
if ((tree[ind].branch = (uint64_t *)realloc(tree[ind].branch,
|
||||
sizeof(uint64_t) * (tree[ind].count + 1))) == NULL)
|
||||
error("realloc() failed!\n");
|
||||
|
||||
tree[ind].branch[tree[ind].count] = wrd;
|
||||
tree[ind].count++;
|
||||
wordcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
if (wordcount == 0 )
|
||||
error("Could not find any valid words in %s!\n", fn);
|
||||
else
|
||||
msg("Loaded %d words.\n", wordcount);
|
||||
}
|
||||
|
||||
/* Check if the RSA key is ok (PKCS#1 v2.1). */
|
||||
_Bool
|
||||
validkey(RSA *rsa)
|
||||
{
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
BIGNUM *p1 = BN_CTX_get(ctx), /* p - 1 */
|
||||
*q1 = BN_CTX_get(ctx), /* q - 1 */
|
||||
*gcd = BN_CTX_get(ctx), /* GCD(p - 1, q - 1) */
|
||||
*lambda = BN_CTX_get(ctx), /* LCM(p - 1, q - 1) */
|
||||
*tmp = BN_CTX_get(ctx); /* temporary storage */
|
||||
|
||||
BN_sub(p1, rsa->p, BN_value_one()); /* p - 1 */
|
||||
BN_sub(q1, rsa->q, BN_value_one()); /* q - 1 */
|
||||
BN_gcd(gcd, p1, q1, ctx); /* gcd(p - 1, q - 1) */
|
||||
|
||||
BN_div(tmp, NULL, p1, gcd, ctx);
|
||||
BN_mul(lambda, q1, tmp, ctx); /* lambda(n) */
|
||||
|
||||
/* Check if e is coprime to lambda(n). */
|
||||
BN_gcd(tmp, lambda, rsa->e, ctx);
|
||||
if (!BN_is_one(tmp)) {
|
||||
verbose("WARNING: Key check failed - e is coprime to lambda!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if public exponent e is less than n - 1. */
|
||||
/* Subtract n from e to avoid checking BN_is_zero. */
|
||||
BN_sub(tmp, rsa->e, rsa->n);
|
||||
if (!tmp->neg) {
|
||||
verbose("WARNING: Key check failed - e is less than (n - 1)!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
BN_mod_inverse(rsa->d, rsa->e, lambda, ctx); /* d */
|
||||
BN_mod(rsa->dmp1, rsa->d, p1, ctx); /* d mod(p - 1) */
|
||||
BN_mod(rsa->dmq1, rsa->d, q1, ctx); /* d mod(q - 1) */
|
||||
BN_mod_inverse(rsa->iqmp, rsa->q, rsa->p, ctx); /* q ^ -1 mod p */
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
/* In theory this should never be true,
|
||||
* unless the guy before me made a mistake ;). */
|
||||
if (RSA_check_key(rsa) != 1) {
|
||||
verbose("WARNING: OpenSSL's RSA_check_key(rsa) failed!\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Base32 encode 10 byte long 'src' into 16 character long 'dst' */
|
||||
/* Experimental, unroll everything. So far, it seems to be the fastest of the
|
||||
* algorithms that I've tried. TODO: review and decide if it's final.*/
|
||||
void
|
||||
base32_enc (uint8_t *dst, uint8_t *src)
|
||||
{
|
||||
dst[ 0] = BASE32_ALPHABET[ (src[0] >> 3) ];
|
||||
dst[ 1] = BASE32_ALPHABET[((src[0] << 2) | (src[1] >> 6)) & 31];
|
||||
dst[ 2] = BASE32_ALPHABET[ (src[1] >> 1) & 31];
|
||||
dst[ 3] = BASE32_ALPHABET[((src[1] << 4) | (src[2] >> 4)) & 31];
|
||||
dst[ 4] = BASE32_ALPHABET[((src[2] << 1) | (src[3] >> 7)) & 31];
|
||||
dst[ 5] = BASE32_ALPHABET[ (src[3] >> 2) & 31];
|
||||
dst[ 6] = BASE32_ALPHABET[((src[3] << 3) | (src[4] >> 5)) & 31];
|
||||
dst[ 7] = BASE32_ALPHABET[ src[4] & 31];
|
||||
|
||||
dst[ 8] = BASE32_ALPHABET[ (src[5] >> 3) ];
|
||||
dst[ 9] = BASE32_ALPHABET[((src[5] << 2) | (src[6] >> 6)) & 31];
|
||||
dst[10] = BASE32_ALPHABET[ (src[6] >> 1) & 31];
|
||||
dst[11] = BASE32_ALPHABET[((src[6] << 4) | (src[7] >> 4)) & 31];
|
||||
dst[12] = BASE32_ALPHABET[((src[7] << 1) | (src[8] >> 7)) & 31];
|
||||
dst[13] = BASE32_ALPHABET[ (src[8] >> 2) & 31];
|
||||
dst[14] = BASE32_ALPHABET[((src[8] << 3) | (src[9] >> 5)) & 31];
|
||||
dst[15] = BASE32_ALPHABET[ src[9] & 31];
|
||||
|
||||
dst[16] = '\0';
|
||||
}
|
||||
|
||||
/* Decode base32 16 character long 'src' into 10 byte long 'dst'. */
|
||||
/* TODO: Revisit and review, would like to shrink it down a bit.
|
||||
* However, it has to stay endian-safe and be fast. */
|
||||
void
|
||||
base32_dec (uint8_t *dst, uint8_t *src)
|
||||
{
|
||||
uint8_t tmp[ONION_LENP1];
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (src[i] >= 'a' && src[i] <= 'z') {
|
||||
tmp[i] = src[i] - 'a';
|
||||
} else {
|
||||
if (src[i] >= '2' && src[i] <= '7')
|
||||
tmp[i] = src[i] - '1' + ('z' - 'a');
|
||||
else {
|
||||
/* Bad character detected.
|
||||
* This should not happen, but just in case
|
||||
* we will replace it with 'z' character. */
|
||||
tmp[i] = 26;
|
||||
}
|
||||
}
|
||||
}
|
||||
dst[0] = (tmp[ 0] << 3) | (tmp[1] >> 2);
|
||||
dst[1] = (tmp[ 1] << 6) | (tmp[2] << 1) | (tmp[3] >> 4);
|
||||
dst[2] = (tmp[ 3] << 4) | (tmp[4] >> 1);
|
||||
dst[3] = (tmp[ 4] << 7) | (tmp[5] << 2) | (tmp[6] >> 3);
|
||||
dst[4] = (tmp[ 6] << 5) | tmp[7];
|
||||
dst[5] = (tmp[ 8] << 3) | (tmp[9] >> 2);
|
||||
dst[6] = (tmp[ 9] << 6) | (tmp[10] << 1) | (tmp[11] >> 4);
|
||||
dst[7] = (tmp[11] << 4) | (tmp[12] >> 1);
|
||||
dst[8] = (tmp[12] << 7) | (tmp[13] << 2) | (tmp[14] >> 3);
|
||||
dst[9] = (tmp[14] << 5) | tmp[15];
|
||||
}
|
||||
|
||||
/* Print found .onion name and PEM formatted RSA key. */
|
||||
void
|
||||
printresult(RSA *rsa, uint8_t *target, uint8_t *actual)
|
||||
{
|
||||
uint8_t *dst;
|
||||
BUF_MEM *buf;
|
||||
BIO *b;
|
||||
|
||||
b = BIO_new(BIO_s_mem());
|
||||
|
||||
PEM_write_bio_RSAPrivateKey(b, rsa, NULL, NULL, 0, NULL, NULL);
|
||||
BIO_get_mem_ptr(b, &buf);
|
||||
(void)BIO_set_close(b, BIO_NOCLOSE);
|
||||
BIO_free(b);
|
||||
|
||||
if ((dst = (uint8_t *)malloc(buf->length + 1)) == NULL)
|
||||
error("malloc(buf->length + 1) failed!\n");
|
||||
memcpy(dst, buf->data, buf->length);
|
||||
|
||||
dst[buf->length] = '\0';
|
||||
|
||||
msg("Found a key for %s (%d) - %s.onion\n",
|
||||
target, strnlen((char *)target, ONION_LENP1), actual);
|
||||
printf("----------------------------------------------------------------\n");
|
||||
printf("%s.onion\n", actual);
|
||||
printf("%s\n", dst);
|
||||
fflush(stdout);
|
||||
|
||||
BUF_MEM_free(buf);
|
||||
free(dst);
|
||||
}
|
||||
|
||||
/* Generate .onion name from the RSA key. */
|
||||
/* (using the same method as the official TOR client) */
|
||||
void
|
||||
onion_enc(uint8_t *onion, RSA *rsa)
|
||||
{
|
||||
uint8_t *bufa, *bufb, digest[SHA_DIGEST_LENGTH];
|
||||
signed int derlen;
|
||||
|
||||
if((derlen = i2d_RSAPublicKey(rsa, NULL)) < 0)
|
||||
error("DER encoding failed!\n");
|
||||
|
||||
if ((bufa = bufb = (uint8_t *)malloc(derlen)) == NULL)
|
||||
error("malloc(derlen) failed!\n");
|
||||
|
||||
if (i2d_RSAPublicKey(rsa, &bufb) != derlen)
|
||||
error("DER encoding failed!\n");
|
||||
|
||||
SHA1(bufa, derlen, digest);
|
||||
free(bufa);
|
||||
base32_enc(onion, digest);
|
||||
}
|
||||
|
||||
/* Compare function for qsort(3). */
|
||||
signed int
|
||||
compare (const void *a, const void *b)
|
||||
{
|
||||
if (*((const uint64_t*)a) > *((const uint64_t*)b))
|
||||
return 1;
|
||||
if (*((const uint64_t*)a) < *((const uint64_t*)b))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wordlist mode search. */
|
||||
_Bool
|
||||
fsearch(uint8_t *buf, uint8_t *onion)
|
||||
{
|
||||
unsigned int i;
|
||||
uint16_t ind;
|
||||
uint64_t wrd;
|
||||
|
||||
if (!nflag)
|
||||
for (i = 0; i < minlen; i++)
|
||||
if (onion[i] < 'a')
|
||||
return 0;
|
||||
|
||||
for (i = minlen; i <= maxlen; i++) {
|
||||
if (!nflag && onion[i - 1] < 'a')
|
||||
return 0;
|
||||
|
||||
zerobits(&ind, &wrd, buf, i);
|
||||
|
||||
if (tree[ind].branch != NULL &&
|
||||
bsearch(&wrd, tree[ind].branch, tree[ind].count,
|
||||
sizeof(tree[ind].branch[0]), &compare)) {
|
||||
onion[i] = '\0';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Regex mode search. */
|
||||
_Bool
|
||||
rsearch(__attribute__((unused)) uint8_t *buf, uint8_t *onion)
|
||||
{
|
||||
return !regexec(regex, (char *)onion, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Fixed prefix mode search. */
|
||||
_Bool
|
||||
psearch(__attribute__((unused)) uint8_t *buf, uint8_t *onion)
|
||||
{
|
||||
return !memcmp(onion, prefix, prefixlen);
|
||||
}
|
||||
|
||||
/* Zero unused bits, split 10 byte 'buffer' into 2 byte 'ind' and 8 byte 'word'. */
|
||||
/* TODO: currently doing '1' fill instead of zeroes - decide if it's final. */
|
||||
void
|
||||
zerobits(uint16_t * ind, uint64_t * word, uint8_t * buffer, unsigned int length)
|
||||
{
|
||||
uint8_t bufcopy[10];
|
||||
unsigned int usedbytes, usedbits;
|
||||
|
||||
memcpy(bufcopy, buffer, 10);
|
||||
usedbytes = length * 5 / 8;
|
||||
usedbits = length * 5 % 8;
|
||||
|
||||
if (usedbits) {
|
||||
/* Lets try '1' fill instead of zeroes.. */
|
||||
/* bufcopy[usedbytes] &= (0xFFu << (8 - usedbits)); */
|
||||
bufcopy[usedbytes] |= (0xFFu >> usedbits);
|
||||
usedbytes++;
|
||||
}
|
||||
|
||||
if (usedbytes < 10) {
|
||||
/* Lets try '1' fill instead of zeroes.. */
|
||||
/* memset(&bufcopy[usedbytes], 0, 10 - usedbytes); */
|
||||
memset(&bufcopy[usedbytes], 0xFFu, 10 - usedbytes);
|
||||
}
|
||||
|
||||
memcpy(ind, &bufcopy[0], 2);
|
||||
memcpy(word, &bufcopy[2], 8);
|
||||
}
|
||||
|
||||
/* Read arguments and set global variables. */
|
||||
void
|
||||
setoptions(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
|
||||
while ((ch = getopt(argc, argv, "cnvt:l:f:p:r:")) != -1)
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
cflag = 1;
|
||||
break;
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
msg = verbose;
|
||||
break;
|
||||
case 't':
|
||||
threads = strtoul(optarg, NULL, 0);
|
||||
if (threads < 1)
|
||||
usage();
|
||||
if (threads > MAX_THREADS)
|
||||
threads = MAX_THREADS;
|
||||
break;
|
||||
case 'l':
|
||||
minlen = strtoul(optarg, NULL, 0);
|
||||
if (minlen < 8 || minlen > 16 || !strchr(optarg, '-'))
|
||||
usage();
|
||||
maxlen = strtoul(strchr(optarg, '-') + 1, NULL, 0);
|
||||
if (maxlen < 8 || maxlen > 16 || minlen > maxlen)
|
||||
usage();
|
||||
break;
|
||||
case 'f':
|
||||
fflag = 1;
|
||||
strncpy(fn, optarg, FILENAME_MAX);
|
||||
search = fsearch;
|
||||
break;
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
strncpy(prefix, optarg, ONION_LENP1);
|
||||
minlen = maxlen = prefixlen = strnlen(prefix, ONION_LENP1);
|
||||
if (prefixlen > 16 || prefixlen < 1)
|
||||
usage();
|
||||
for (unsigned int i = 0; i < prefixlen; i++) {
|
||||
prefix[i] = tolower(prefix[i]);
|
||||
if (!isalpha(prefix[i]) && (!nflag || !isdigit(prefix[i]) ||
|
||||
prefix[i] < '2' || prefix[i] > '7'))
|
||||
usage();
|
||||
}
|
||||
search = psearch;
|
||||
break;
|
||||
case 'r':
|
||||
rflag = 1;
|
||||
minlen = 1;
|
||||
maxlen = 16;
|
||||
if ((regex = (regex_t *)malloc(sizeof(regex_t))) == NULL)
|
||||
error("malloc(sizeof(regex_t)) failed!\n");;
|
||||
|
||||
/* Do not use ICASE - too slow. */
|
||||
if (regcomp(regex, optarg, REG_EXTENDED | REG_NOSUB))
|
||||
error("Failed to compile regex expression!\n");
|
||||
search = rsearch;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
if (fflag + rflag + pflag != 1)
|
||||
usage();
|
||||
|
||||
msg("Verbose, ");
|
||||
cflag ? msg("continuous, ") : msg("single result, ");
|
||||
nflag ? msg("digits ok, ") : msg("no digits, ");
|
||||
msg("%d threads, prefixes %d-%d characters long.\n",
|
||||
threads, minlen, maxlen);
|
||||
}
|
||||
|
||||
/* Print usage information and exit. */
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Version: %s\n"
|
||||
"\n"
|
||||
"usage:\n"
|
||||
"%s [-c] [-v] [-t count] ([-n] [-l min-max] -f filename) | (-r regex) | (-p prefix)\n"
|
||||
" -v : verbose mode - print extra information to STDERR\n"
|
||||
" -c : continue searching after the hash is found\n"
|
||||
" -t count : number of threads to spawn default is one)\n"
|
||||
" -l min-max : look for prefixes that are from 'min' to 'max' characters long\n"
|
||||
" -n : Allow digits to be part of the prefix (affects wordlist mode only)\n"
|
||||
" -f filename: name of the text file with a list of prefixes\n"
|
||||
" -p prefix : single prefix to look for (1-16 characters long)\n"
|
||||
" -r regex : search for a POSIX-style regular expression\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
" %s -cvt4 -l8-12 -f wordlist.txt >> results.txt\n"
|
||||
" %s -v -r '^test|^exam'\n"
|
||||
" %s -ct5 -p test\n\n",
|
||||
VERSION, __progname, __progname, __progname, __progname);
|
||||
|
||||
fprintf(stderr,
|
||||
" base32 alphabet allows letters [a-z] and digits [2-7]\n"
|
||||
" Regex pattern examples:\n"
|
||||
" xxx must contain 'xxx'\n"
|
||||
" ^foo must begin with 'foo'\n"
|
||||
" bar$ must end with 'bar'\n"
|
||||
" b[aoeiu]r must have a vowel between 'b' and 'r'\n"
|
||||
" '^ab|^cd' must begin with 'ab' or 'cd'\n"
|
||||
" [a-z]{16} must contain letters only, no digits\n"
|
||||
" ^dusk.*dawn$ must begin with 'dusk' and end with 'dawn'\n"
|
||||
" [a-z2-7]{16} any name - will succeed after one iteration\n");
|
||||
|
||||
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 *unused, ...)
|
||||
{
|
||||
}
|
||||
|
||||
/* Print error message and exit. */
|
||||
/* (Not all Linuxes implement the err/errx functions properly.) */
|
||||
void
|
||||
error(char *message, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, message);
|
||||
fprintf(stderr, "ERROR: ");
|
||||
vfprintf(stderr, message, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
Binary file not shown.
|
@ -0,0 +1,988 @@
|
|||
Africa
|
||||
America
|
||||
British
|
||||
England
|
||||
English
|
||||
Europe
|
||||
France
|
||||
French
|
||||
God
|
||||
Greek
|
||||
Indian
|
||||
Japanese
|
||||
Washington
|
||||
able
|
||||
about
|
||||
above
|
||||
across
|
||||
act
|
||||
action
|
||||
actually
|
||||
add
|
||||
addition
|
||||
adjective
|
||||
afraid
|
||||
after
|
||||
again
|
||||
against
|
||||
age
|
||||
ago
|
||||
agreed
|
||||
ahead
|
||||
air
|
||||
all
|
||||
allow
|
||||
almost
|
||||
alone
|
||||
along
|
||||
already
|
||||
also
|
||||
although
|
||||
always
|
||||
among
|
||||
amount
|
||||
and
|
||||
angle
|
||||
animal
|
||||
another
|
||||
answer
|
||||
any
|
||||
anything
|
||||
appear
|
||||
apple
|
||||
are
|
||||
area
|
||||
arms
|
||||
army
|
||||
around
|
||||
arrived
|
||||
art
|
||||
ask
|
||||
ass
|
||||
away
|
||||
baby
|
||||
back
|
||||
bad
|
||||
ball
|
||||
bank
|
||||
base
|
||||
bear
|
||||
beat
|
||||
beautiful
|
||||
became
|
||||
because
|
||||
become
|
||||
bed
|
||||
been
|
||||
before
|
||||
began
|
||||
begin
|
||||
behind
|
||||
being
|
||||
believe
|
||||
bell
|
||||
belong
|
||||
below
|
||||
beside
|
||||
best
|
||||
better
|
||||
between
|
||||
big
|
||||
bill
|
||||
birds
|
||||
bit
|
||||
black
|
||||
block
|
||||
blood
|
||||
blow
|
||||
blue
|
||||
board
|
||||
boat
|
||||
body
|
||||
bones
|
||||
book
|
||||
boris
|
||||
born
|
||||
both
|
||||
bottom
|
||||
box
|
||||
boy
|
||||
branches
|
||||
break
|
||||
bright
|
||||
bring
|
||||
broken
|
||||
brother
|
||||
brought
|
||||
brown
|
||||
bruce
|
||||
build
|
||||
building
|
||||
built
|
||||
burning
|
||||
business
|
||||
but
|
||||
buy
|
||||
call
|
||||
came
|
||||
can
|
||||
cannot
|
||||
capital
|
||||
captain
|
||||
car
|
||||
care
|
||||
carefully
|
||||
carry
|
||||
case
|
||||
cat
|
||||
catch
|
||||
cattle
|
||||
caught
|
||||
cause
|
||||
cells
|
||||
center
|
||||
cents
|
||||
century
|
||||
certain
|
||||
chance
|
||||
change
|
||||
chart
|
||||
check
|
||||
chief
|
||||
child
|
||||
children
|
||||
choose
|
||||
church
|
||||
circle
|
||||
city
|
||||
class
|
||||
clean
|
||||
clear
|
||||
climbed
|
||||
close
|
||||
clothes
|
||||
cloud
|
||||
coast
|
||||
cold
|
||||
color
|
||||
column
|
||||
come
|
||||
common
|
||||
company
|
||||
compare
|
||||