Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
GPGMELIBS := $(shell pkg-config --libs gpgme)

bruteforce-gpg: src/main.c bruteforce_gpg.o log.o agent.o
gcc -pthread -l gpgme -o bruteforce-gpg src/main.c bruteforce_gpg.o log.o agent.o
gcc -o bruteforce-gpg src/main.c bruteforce_gpg.o log.o agent.o -pthread $(GPGMELIBS)
bruteforce_gpg.o: src/bruteforce_gpg.c src/bruteforce_gpg.h
gcc -c src/bruteforce_gpg.c -o bruteforce_gpg.o
agent.o: src/agent.c src/agent.h
gcc -c src/agent.c -o agent.o
log.o: src/log.c src/log.h
gcc -c src/log.c -o log.o
clean:
rm --force bruteforce-gpg bruteforce_gpg.o log.o
rm --force bruteforce-gpg *.o
install:
install bruteforce-gpg /usr/local/bin/
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ bruteforce-gpg [-h] [-v] [-t NUM_THREADS] -f WORDLIST GPG_SECRET_KEY
## Setup
### 1. Install Dependencies

This tool depends on the [libgpgme](https://www.gnupg.org/software/gpgme/index.html) library.
This tool depends on the [libgpgme](https://www.gnupg.org/software/gpgme/index.html) library and [pkg-config](http://pkg-config.freedesktop.org) tool.

On Kali
```bash
$ sudo apt install libgpgme-dev
$ sudo apt install libgpgme-dev pkg-config
```

On Arch Linux
```bash
$ sudo pacman -S gpgme
$ sudo pacman -S gpgme pkg-config
```

### 2. Download
Expand All @@ -41,7 +41,7 @@ $ make
`bruteforce-gpg` will be installed in the `/usr/local/bin/` directory, so you may want to ensure it is included in your `PATH` environment variable.

```bash
make install
# make install
```

## Examples
Expand Down
43 changes: 37 additions & 6 deletions src/bruteforce_gpg.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include <stdbool.h>

#include "bruteforce_gpg.h"
#include "log.h"

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

char *bruteforce_gpg_load_secret_key(char *secret_key_filename, char **fingerprint) {
char *bruteforce_gpg_import_secret_key(char *secret_key_filename, char **fingerprint) {
gpgme_ctx_t context;
gpgme_error_t err;
gpgme_data_t secret_key_data;
Expand Down Expand Up @@ -76,12 +78,45 @@ char *bruteforce_gpg_load_secret_key(char *secret_key_filename, char **fingerpri
*fingerprint = strndup(result->imports->fpr, 40);
else
strncpy(*fingerprint, result->imports->fpr, 40);

gpgme_data_release(secret_key_data);
gpgme_release(context);
return *fingerprint;
}

bool bruteforce_gpg_delete_secret_key(char const *fingerprint)
{
gpgme_ctx_t context;
gpgme_error_t err;
gpgme_key_t key;
bool ret = true;

err = gpgme_new(&context);
if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
fprintf(stderr, "Context creation failed: %s\n", gpgme_strerror(err));
return false;
}

err = gpgme_get_key(context, fingerprint, &key, true); // secret: true
if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
fprintf(stderr, "Failed to get secret key: %s\n", gpgme_strerror(err));
ret = false;
goto release_context;
}

err = gpgme_op_delete_ext(context, key, GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE);
if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
fprintf(stderr, "Failed to delete key: %s\n", gpgme_strerror(err));
ret = false;
goto release_context;
}

release_context:
gpgme_release(context);
return ret;
}


gpgme_error_t bruteforce_gpg_read_passphrases_from_file(void *hook, const char *uid_hint, const char *passphrase_info, int prev_was_bad, int fd) {
struct callback_data *data = (struct callback_data *) hook;

Expand Down Expand Up @@ -196,7 +231,6 @@ void *bruteforce_gpg_crack_passphrase(void *args) {
/* Set key as signing key */
err = gpgme_signers_add(context, secret_key);
if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
gpgme_op_delete_ext(context, secret_key, GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE);
gpgme_release(context);
free(data);
gpgme_strerror_r(err, err_buf, ERR_BUF_LEN);
Expand All @@ -211,7 +245,6 @@ void *bruteforce_gpg_crack_passphrase(void *args) {
err = gpgme_data_new_from_mem(&signing_data, "test", 4, 0);
if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
gpgme_signers_clear(context);
gpgme_op_delete_ext(context, secret_key, GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE);
free(data);
gpgme_release(context);
gpgme_strerror_r(err, err_buf, ERR_BUF_LEN);
Expand All @@ -226,7 +259,6 @@ void *bruteforce_gpg_crack_passphrase(void *args) {
if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
gpgme_data_release(signing_data);
gpgme_signers_clear(context);
gpgme_op_delete_ext(context, secret_key, GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE);
free(data);
gpgme_release(context);
gpgme_strerror_r(err, err_buf, ERR_BUF_LEN);
Expand Down Expand Up @@ -267,7 +299,6 @@ void *bruteforce_gpg_crack_passphrase(void *args) {

gpgme_data_release(signature);
gpgme_data_release(signing_data);
gpgme_op_delete_ext(context, secret_key, GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE);
gpgme_signers_clear(context);
free(data);
gpgme_release(context);
Expand Down
11 changes: 7 additions & 4 deletions src/bruteforce_gpg.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#include <gpgme.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>

#include <pthread.h>
#include <gpgme.h>

#include "log.h"

#define USAGE "%s [-h] [-v] [-t NUM_THREADS] -f WORDLIST GPG_SECRET_KEY\n"
#define USAGE "%s [-h] [-v] [-t NUM_THREADS] -f WORDLIST GPG_SECRET_KEYFILE | FINGERPRINT\n"
#define ERR_BUF_LEN 500

struct callback_data {
Expand All @@ -27,5 +29,6 @@ struct thread_args {
char *passphrase;
};

char *bruteforce_gpg_load_secret_key(char *secret_key_filename, char **fingerprint);
char *bruteforce_gpg_import_secret_key(char *secret_key_filename, char **fingerprint);
bool bruteforce_gpg_delete_secret_key(char const *fingerprint);
void *bruteforce_gpg_crack_passphrase(void *args);
34 changes: 24 additions & 10 deletions src/main.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include <getopt.h>
#include <unistd.h>
#include <stdbool.h>

#include "bruteforce_gpg.h"
#include "log.h"
#include "agent.h"
Expand All @@ -14,12 +17,13 @@ int main(int argc, char *argv[argc])
{
int option;
long num_threads;
char *password_filename = NULL, *secret_key_filename, *endptr, *ttl = NULL;
char *password_filename = NULL, *secret_key, *endptr, *ttl = NULL;
pthread_t *workers;
gpgme_error_t err;
void *worker_err;
struct thread_args gpg_data;
time_t start_time;
bool import_keyfile = false;

num_threads = 1;
debug = opterr = 0;
Expand Down Expand Up @@ -60,11 +64,13 @@ int main(int argc, char *argv[argc])
fprintf(stderr, USAGE, argv[0]);
exit(1);
}
secret_key_filename = argv[optind];
secret_key = argv[optind];
import_keyfile = (access(secret_key, F_OK) == 0);

log_debug("wordlist: %s\nkey file: %s\n",
log_debug("wordlist: %s\n%s: %s\n",
password_filename,
secret_key_filename);
import_keyfile? "secret_key_filename": "fingerprint",
secret_key);

if (!(gpg_data.wordlist = fopen(password_filename, "r"))) {
fprintf(stderr,
Expand All @@ -85,21 +91,25 @@ int main(int argc, char *argv[argc])
gpgme_strerror(err));
exit(gpgme_err_code(err));
}

log_debug("%s engine supported!\n",
gpgme_get_protocol_name(GPGME_PROTOCOL_OPENPGP));

gpg_data.fingerprint = NULL;
if (!bruteforce_gpg_load_secret_key(secret_key_filename, &gpg_data.fingerprint))
exit(1);
if (import_keyfile) {
if (!bruteforce_gpg_import_secret_key(secret_key, &gpg_data.fingerprint))
exit(1);
} else {
gpg_data.fingerprint = strndup(secret_key, 40);
}

gpg_data.attempt = 0;
gpg_data.passphrase = NULL;
gpg_data.num_workers = 0;
workers = calloc(num_threads, sizeof(pthread_t));
gpg_data.workers = workers;


get_gpg_agent_cache_info(&ttl);
log_debug("Got existing gpg-agent default-cache-ttl: %s\n", ttl);
set_gpg_agent_cache_info("0");
Expand All @@ -118,7 +128,7 @@ int main(int argc, char *argv[argc])
for (int i = 0; i < num_threads; i++)
if (pthread_join(workers[i], &worker_err))
perror("Failed to join to worker thread");

if (gpg_data.passphrase) {
printf("\nFound passphrase: %s\n", gpg_data.passphrase);
}
Expand All @@ -128,11 +138,15 @@ int main(int argc, char *argv[argc])
}
printf("Duration: %lu seconds\n", gpg_data.end_time - start_time);

// delete imported_key
if (import_keyfile) {
bruteforce_gpg_delete_secret_key(gpg_data.fingerprint);
}
set_gpg_agent_cache_info(ttl);
log_debug("Reverted gpg-agent default-cache-ttl to %s\n", ttl);
free(ttl);
fclose(gpg_data.wordlist);
free(gpg_data.fingerprint);
free(workers);
return gpg_data.passphrase != NULL;
return gpg_data.passphrase == NULL; // 0: ok, 1: failure
}