From 6a722bb1eb866602b8fbf744869b2cd7afecb8f6 Mon Sep 17 00:00:00 2001 From: Guillaume LE VAILLANT Date: Fri, 17 Jul 2015 14:19:56 +0200 Subject: [PATCH] Support the characters of the current locale. This allows specifying characters other than ASCII characters in the 'charset', 'prefix' and 'suffix' options. For example, if you use a utf-8 locale, you can try to find a password containing utf-8 characters. --- ChangeLog | 4 + NEWS | 3 + README | 39 +++-- configure.ac | 7 +- .../bruteforce-wallet-1.3.ebuild | 33 ++++ src/bruteforce-wallet.c | 153 +++++++++++++----- src/version.h | 2 +- 7 files changed, 186 insertions(+), 55 deletions(-) create mode 100644 contrib/gentoo/app-crypt/bruteforce-wallet/bruteforce-wallet-1.3.ebuild diff --git a/ChangeLog b/ChangeLog index 60ec84c..414e2e5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2015-07-16 Guillaume LE VAILLANT + Version 1.3 + Support all the characters of the current locale (e.g. utf-8). + 2015-07-06 Guillaume LE VAILLANT Version 1.2 Print progress info when sending a USR1 signal to the process. diff --git a/NEWS b/NEWS index fffd85b..58814b7 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +Version 1.3 + 2015-07-16 + Version 1.2 2015-07-06 diff --git a/README b/README index e02e11e..c40605f 100644 --- a/README +++ b/README @@ -1,16 +1,23 @@ -bruteforce-wallet -================= +# bruteforce-wallet The purpose of this program is to try to find the password of an encrypted -Peercoin (or Bitcoin, Litecoin, etc...) wallet file (i.e.: wallet.dat). +Peercoin (or Bitcoin, Litecoin, etc...) wallet file (i.e. wallet.dat). The program tries to decrypt one of the encrypted addresses in the wallet by -trying all the possible passwords. -The minimum and maximum password length to try can be indicated as option -on the command line. -The beginning and the end of the password can be specified too. -There are also options to indicate the character set and number of threads -to use. +trying all the possible passwords. It is especially useful if you know +something about the password (i.e. you forgot a part of your password but still +remember most of it). Finding the password of a wallet without knowing +anything about it would take way too much time (unless the password is really +short and/or weak). + +There are command line options to specify: + + - the minimum password length to try + - the maximum password length to try + - the beginning of the password + - the end of the password + - the character set to use (among the characters of the current locale) + - the number of threads to use Sending a USR1 signal to a running bruteforce-wallet process makes it print progress info to standard error and continue. @@ -23,6 +30,8 @@ The program requires the OpenSSL and BerkeleyDB libraries. ## Limitations +The program currently only works on unix-like POSIX systems (e.g. GNU/Linux). + Different versions of BerkeleyDB are usually not compatible with each other. Therefore, for the program to work, you will have to check that the BerkeleyDB version you are using can read the databases created by the BerkeleyDB version @@ -43,9 +52,21 @@ only passwords with 5 to 10 characters beginning with "W4l" and ending with "z": bruteforce-wallet -t 8 -l 5 -m 10 -b "W4l" -e "z" wallet.dat +Try to find the password of an encrypted wallet file using 8 threads, trying +only passwords with 10 characters using the character set "P情8ŭ": + + bruteforce-wallet -t 8 -l 10 -m 10 -s "P情8ŭ" wallet.dat + + +Print progress info: + + pkill -USR1 -f bruteforce-wallet + + ## Donations If you find this program useful and want to make a donation, you can send coins to one of the following addresses: + - Peercoin: PWFNV1Cvq7nQBRyRueuYzwmDNXUGpgNkBC - Bitcoin: 1F1ZfM7XtggHsShK4vwuy9zv98a9wt7nXx diff --git a/configure.ac b/configure.ac index 645d243..905b28d 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(bruteforce_wallet, 1.2) +AC_INIT(bruteforce_wallet, 1.3) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR(src/bruteforce-wallet.c) @@ -7,13 +7,14 @@ AC_PROG_CC AC_PROG_INSTALL dnl Check for standard headers -AC_CHECK_HEADERS([math.h signal.h stdio.h stdlib.h string.h unistd.h]) +AC_CHECK_HEADERS([math.h locale.h signal.h stdio.h stdlib.h string.h unistd.h wchar.h]) dnl Check for functions AC_CHECK_FUNCS([calloc malloc free]) AC_CHECK_FUNCS([perror printf fprintf]) AC_CHECK_FUNCS([atoi]) -AC_CHECK_FUNCS([memcmp memset strlen strncpy]) +AC_CHECK_FUNCS([memcmp memset]) +AC_CHECK_FUNCS([setlocale mbstowcs wcsncpy wcstombs]) AC_CHECK_FUNCS([getopt]) AC_CHECK_FUNCS([signal]) diff --git a/contrib/gentoo/app-crypt/bruteforce-wallet/bruteforce-wallet-1.3.ebuild b/contrib/gentoo/app-crypt/bruteforce-wallet/bruteforce-wallet-1.3.ebuild new file mode 100644 index 0000000..78bda96 --- /dev/null +++ b/contrib/gentoo/app-crypt/bruteforce-wallet/bruteforce-wallet-1.3.ebuild @@ -0,0 +1,33 @@ +# Copyright 2014-2015 Guillaume LE VAILLANT +# Distributed under the terms of the GNU General Public License v3 + +EAPI="5" + +inherit eutils autotools + +DESCRIPTION="A bruteforce cracker for Peercoin (and Bitcoin, Litecoin, etc...) encrypted wallet files." +HOMEPAGE="https://github.com/glv2/${PN}" +SRC_URI="https://github.com/glv2/${PN}/archive/${PV}.tar.gz -> ${P}.tar.gz" + +LICENSE="GPL-3" +SLOT="0" +KEYWORDS="~amd64 ~arm ~x86" + +DEPEND=" + dev-libs/openssl + sys-libs/db +" +RDEPEND="${DEPEND}" + +src_prepare() { + eautoreconf +} + +src_configure() { + econf +} + +src_install() { + dobin "${PN}" + dodoc AUTHORS ChangeLog COPYING NEWS README +} diff --git a/src/bruteforce-wallet.c b/src/bruteforce-wallet.c index 60c5064..64b22d8 100644 --- a/src/bruteforce-wallet.c +++ b/src/bruteforce-wallet.c @@ -17,8 +17,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + #include #include +#include #include #include #include @@ -27,27 +29,28 @@ along with this program. If not, see . #include #include #include +#include #include "elliptic-curve.h" #include "version.h" -struct decryption_func_locals { - unsigned int index_start; - unsigned int index_end; - unsigned long long counter; -} *thread_locals; - unsigned char *default_charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -unsigned char *charset = NULL, *prefix = NULL, *suffix = NULL; -unsigned int charset_len = 62, min_len = 1, max_len = 8, prefix_len = 0, suffix_len = 0; +wchar_t *charset = NULL, *prefix = NULL, *suffix = NULL; +unsigned int charset_len, min_len = 1, max_len = 8, prefix_len = 0, suffix_len = 0; unsigned char *pubkey, *encrypted_seckey, *encrypted_masterkey, salt[8]; unsigned int pubkey_len, encrypted_seckey_len, encrypted_masterkey_len, method, rounds; const EVP_CIPHER *cipher; const EVP_MD *digest; pthread_mutex_t found_password_lock; -char stop = 0, only_one_password = 0; +char stop = 0; unsigned int nb_threads = 1; +struct decryption_func_locals +{ + unsigned int index_start; + unsigned int index_end; + unsigned long long int counter; +} *thread_locals; /* @@ -92,8 +95,9 @@ int valid_seckey(unsigned char *seckey, unsigned int seckey_len, unsigned char * void * decryption_func(void *arg) { struct decryption_func_locals *dfargs; - unsigned char *password, *key, *iv, *masterkey, *seckey, hash[32]; - unsigned int password_len, index_start, index_end, len, i, j, k; + wchar_t *password; + unsigned char *pwd, *key, *iv, *masterkey, *seckey, hash[32]; + unsigned int password_len, pwd_len, index_start, index_end, len, i, j, k; unsigned int masterkey_len1, masterkey_len2, seckey_len1, seckey_len2; int ret; unsigned int *tab; @@ -120,16 +124,16 @@ void * decryption_func(void *arg) for(k = index_start; k <= index_end; k++) { password_len = prefix_len + 1 + len + suffix_len; - password = (unsigned char *) malloc(password_len + 1); - tab = (unsigned int *) malloc((len + 1) * sizeof(unsigned int)); + password = (wchar_t *) calloc(password_len + 1, sizeof(wchar_t)); + tab = (unsigned int *) calloc(len + 1, sizeof(unsigned int)); if((password == NULL) || (tab == NULL)) { fprintf(stderr, "Error: memory allocation failed.\n\n"); exit(EXIT_FAILURE); } - strncpy(password, prefix, prefix_len); + wcsncpy(password, prefix, prefix_len); password[prefix_len] = charset[k]; - strncpy(password + prefix_len + 1 + len, suffix, suffix_len); + wcsncpy(password + prefix_len + 1 + len, suffix, suffix_len); password[password_len] = '\0'; for(i = 0; i <= len; i++) @@ -140,9 +144,17 @@ void * decryption_func(void *arg) { for(i = 0; i < len; i++) password[prefix_len + 1 + i] = charset[tab[len - 1 - i]]; + pwd_len = wcstombs(NULL, password, 0); + pwd = (unsigned char *) malloc(pwd_len + 1); + if(pwd == NULL) + { + fprintf(stderr, "Error: memory allocation failed.\n\n"); + exit(EXIT_FAILURE); + } + wcstombs(pwd, password, pwd_len + 1); /* Decrypt the master key with the password */ - EVP_BytesToKey(cipher, digest, salt, password, password_len, rounds, key, iv); + EVP_BytesToKey(cipher, digest, salt, pwd, pwd_len, rounds, key, iv); EVP_DecryptInit(&ctx, EVP_aes_256_cbc(), key, iv); EVP_DecryptUpdate(&ctx, masterkey, &masterkey_len1, encrypted_masterkey, encrypted_masterkey_len); ret = EVP_DecryptFinal(&ctx, masterkey + masterkey_len1, &masterkey_len2); @@ -157,14 +169,15 @@ void * decryption_func(void *arg) { /* We have a positive result */ pthread_mutex_lock(&found_password_lock); - printf("Password candidate: %s\n", password); - if(only_one_password) - stop = 1; + printf("Password found: %ls\n", password); + stop = 1; pthread_mutex_unlock(&found_password_lock); } } EVP_CIPHER_CTX_cleanup(&ctx); + free(pwd); + if(len == 0) break; tab[0]++; @@ -300,7 +313,7 @@ int get_wallet_info(char *filename) void handle_signal(int signo) { - unsigned long long total_ops = 0; + unsigned long long int total_ops = 0; unsigned int i, l; unsigned int l_full = max_len - suffix_len - prefix_len; unsigned int l_skip = min_len - suffix_len - prefix_len; @@ -323,7 +336,6 @@ void usage(char *progname) fprintf(stderr, "\nbruteforce-wallet %s\n\n", VERSION_NUMBER); fprintf(stderr, "Usage: %s [options] \n\n", progname); fprintf(stderr, "Options:\n"); - fprintf(stderr, " -1 Stop the program after finding the first password candidate.\n"); fprintf(stderr, " -b Beginning of the password.\n"); fprintf(stderr, " default: \"\"\n"); fprintf(stderr, " -e End of the password.\n"); @@ -339,7 +351,7 @@ void usage(char *progname) fprintf(stderr, " -t Number of threads to use.\n"); fprintf(stderr, " default: 1\n"); fprintf(stderr, "\n"); - fprintf(stderr, "Sending a USR1 signal to a running %s process\n", progname); + fprintf(stderr, "Sending a USR1 signal to a running bruteforce-wallet process\n"); fprintf(stderr, "makes it print progress info to standard error and continue.\n"); fprintf(stderr, "\n"); } @@ -350,23 +362,44 @@ int main(int argc, char **argv) char *filename; int i, ret, c; + setlocale(LC_ALL, ""); OpenSSL_add_all_algorithms(); /* Get options and parameters. */ opterr = 0; - while((c = getopt(argc, argv, "1b:e:hl:m:s:t:")) != -1) + while((c = getopt(argc, argv, "b:e:hl:m:s:t:")) != -1) switch(c) { - case '1': - only_one_password = 1; - break; - case 'b': - prefix = optarg; + prefix_len = mbstowcs(NULL, optarg, 0); + if(prefix_len == (unsigned int) -1) + { + fprintf(stderr, "Error: invalid character in prefix.\n\n"); + exit(EXIT_FAILURE); + } + prefix = (wchar_t *) calloc(prefix_len + 1, sizeof(wchar_t)); + if(prefix == NULL) + { + fprintf(stderr, "Error: memory allocation failed.\n\n"); + exit(EXIT_FAILURE); + } + mbstowcs(prefix, optarg, prefix_len + 1); break; case 'e': - suffix = optarg; + suffix_len = mbstowcs(NULL, optarg, 0); + if(suffix_len == (unsigned int) -1) + { + fprintf(stderr, "Error: invalid character in suffix.\n\n"); + exit(EXIT_FAILURE); + } + suffix = (wchar_t *) calloc(suffix_len + 1, sizeof(wchar_t)); + if(suffix == NULL) + { + fprintf(stderr, "Error: memory allocation failed.\n\n"); + exit(EXIT_FAILURE); + } + mbstowcs(suffix, optarg, suffix_len + 1); break; case 'h': @@ -383,7 +416,24 @@ int main(int argc, char **argv) break; case 's': - charset = optarg; + charset_len = mbstowcs(NULL, optarg, 0); + if(charset_len == 0) + { + fprintf(stderr, "Error: charset must have at least one character.\n\n"); + exit(EXIT_FAILURE); + } + if(charset_len == (unsigned int) -1) + { + fprintf(stderr, "Error: invalid character in charset.\n\n"); + exit(EXIT_FAILURE); + } + charset = (wchar_t *) calloc(charset_len + 1, sizeof(wchar_t)); + if(charset == NULL) + { + fprintf(stderr, "Error: memory allocation failed.\n\n"); + exit(EXIT_FAILURE); + } + mbstowcs(charset, optarg, charset_len + 1); break; case 't': @@ -424,18 +474,37 @@ int main(int argc, char **argv) /* Check variables */ if(prefix == NULL) - prefix = ""; - prefix_len = strlen(prefix); + { + prefix_len = mbstowcs(NULL, "", 0); + prefix = (wchar_t *) calloc(prefix_len + 1, sizeof(wchar_t)); + if(prefix == NULL) + { + fprintf(stderr, "Error: memory allocation failed.\n\n"); + exit(EXIT_FAILURE); + } + mbstowcs(prefix, "", prefix_len + 1); + } if(suffix == NULL) - suffix = ""; - suffix_len = strlen(suffix); + { + suffix_len = mbstowcs(NULL, "", 0); + suffix = (wchar_t *) calloc(suffix_len + 1, sizeof(wchar_t)); + if(suffix == NULL) + { + fprintf(stderr, "Error: memory allocation failed.\n\n"); + exit(EXIT_FAILURE); + } + mbstowcs(suffix, "", suffix_len + 1); + } if(charset == NULL) - charset = default_charset; - charset_len = strlen(charset); - if(charset_len == 0) { - fprintf(stderr, "Error: charset must have at least one character.\n\n"); - exit(EXIT_FAILURE); + charset_len = mbstowcs(NULL, default_charset, 0); + charset = (wchar_t *) calloc(charset_len + 1, sizeof(wchar_t)); + if(charset == NULL) + { + fprintf(stderr, "Error: memory allocation failed.\n\n"); + exit(EXIT_FAILURE); + } + mbstowcs(charset, default_charset, charset_len + 1); } if(nb_threads > charset_len) { @@ -444,12 +513,12 @@ int main(int argc, char **argv) } if(min_len < prefix_len + suffix_len + 1) { - fprintf(stderr, "Warning: minimum length (%u) isn't bigger than the length of specified password characters (%u). Setting minimum length to %u.\n\n", min_len, prefix_len + suffix_len, prefix_len + suffix_len + 1); + fprintf(stderr, "Warning: minimum length (%u) smaller than the length of specified password characters (%u). Setting minimum length to %u.\n\n", min_len, prefix_len + suffix_len, prefix_len + suffix_len + 1); min_len = prefix_len + suffix_len + 1; } if(max_len < min_len) { - fprintf(stderr, "Warning: maximum length (%u) is smaller than minimum length (%u). Setting maximum length to %u.\n\n", max_len, min_len, min_len); + fprintf(stderr, "Warning: maximum length (%u) smaller than minimum length (%u). Setting maximum length to %u.\n\n", max_len, min_len, min_len); max_len = min_len; } @@ -466,7 +535,7 @@ int main(int argc, char **argv) pthread_mutex_init(&found_password_lock, NULL); /* Start decryption threads. */ - decryption_threads = (pthread_t *) malloc(nb_threads * sizeof(pthread_t)); + decryption_threads = (pthread_t *) calloc(nb_threads, sizeof(pthread_t)); thread_locals = (struct decryption_func_locals *) calloc(nb_threads, sizeof(struct decryption_func_locals)); if((decryption_threads == NULL) || (thread_locals == NULL)) { diff --git a/src/version.h b/src/version.h index f65f25f..559c417 100644 --- a/src/version.h +++ b/src/version.h @@ -20,6 +20,6 @@ along with this program. If not, see . #ifndef VERSION_H #define VERSION_H 1 -#define VERSION_NUMBER "1.2" +#define VERSION_NUMBER "1.3" #endif