Skip to main content

crackie

A simple, silly library to generate combinations.

I wrote this when I forgot part of a password, and decided to try run ~500,000 combinations on the parts I remembered. It worked! Also I decided to publish it because I had never created a Python package before, so this would learn me something.

Usage

Say you have forgotten a password, but remember the basics of it. For example, you remember that it was made up of two words, with some characters altered.

Let's see how to use this library to try all potential combinations:

# Of course we start with some imports.

# We'll be using `each_possible_combination`
from crackie import each_possible_combination

# And we'll use an external program to test each individual
# combination. We'll call this program with `Popen`.
from subprocess import Popen, DEVNULL

# I forgot my password! I remember it was made up of
# the words "verd" and "uberous". Not sure how I mixed up
# lower and upper case... oh, and there might have been
# some additional spicy characters. It could be `VERDUBEROUS`,
# `V3rd_ubEr0U5`, `v3rd ub3r0U5!`... something along those
# lines.

# This list of lists models the possibilities for each
# character in the password string. First there's a "V",
# not sure if big or small. Then the same with "E", but
# this could instead be a "3"? Etc.
variations = [
    ["V", "v"],
    ["E", "e", "3"],
    ["R", "r"],
    ["D", "d"],
    ["", "-", "_", " "],
    ["U", "u"],
    ["B", "b", "8"],
    ["E", "e", "3"],
    ["R", "r"],
    ["O", "o", "0"],
    ["U", "u"],
    ["S", "s", "5", "$"],
    ["", "!", "1"],
]

# Provide a way to test each individual combination. In this
# example we want to find out a gpg key, so here's some code
# to make that work. In your case it'll be completely different.
# Or not.
def try_password(password):
    p = Popen(
        ['gpg', '--pinentry-mode', 'loopback', '--decrypt', '--passphrase', password, 'e2e_tests/tmp/cryptext'],
        stderr=DEVNULL,
        stdout=DEVNULL
    )
    p.wait()
    return p.returncode == 0

# Some printing out to reassure us that the program
# is running. The `count` will increment as we go
# and be shown at the end.
count = 0
print("Testing combinations...")

# This is the actual search for combinations, using
# `each_possible_combination`.
for candidate in each_possible_combination(variations):
    # Print out some dots to show progress
    print(".", end="", flush=True)
    count += 1

    # Each variation is given as a list. We'll need it
    # as a string.
    candidate_string = ''.join(candidate)

    # Finally, we check if the combination is good!
    # If not, the loop will move on to the next one.
    if try_password(candidate_string):
        # On success, announce victory and exit.
        print(f"\nFound the password: `{candidate_string}`. Tried {count} combinations");
        break

Development

This project uses uv. End-to-end tests use Docker.

There is a Makefile with shortcuts to run the tests, as follows:

$ make # Runs pytests, doctests, and end-to-end tests
$ make test # Runs pytests and doctests
$ make test_e2e # Runs end-to-end tests

The so-called "e2e test" extracts the example shown above in this document, and runs it to make sure it reflects reality. It sets up a Docker container with the required tools (GnuPG) and an old-ish version of Python (to ensure compatibility). Perhaps overkill, but for some time the example had some mistakes and I wanted to ensure it didn't happen again.

Release files for crackie 1.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for crackie 1.0.3
File Size Uploaded
crackie-1.0.3.tar.gz 3.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for crackie 1.0.3
File Interpreter ABI Platform
crackie-1.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 7.6 kB

Release files / crackie-1.0.3.tar.gz

Download URL crackie-1.0.3.tar.gz
Size 3.6 kB
Tags Source
SHA-256 checksum
How to use checksums
ff850b4b0efc34bcc078524583eeecd231c4d413de39f04f10856b4d550ab228
BLAKE2b-256 checksum
How to use checksums
79afab64ef1db80a4ff469927cd0baad0dea1407326ef2b0f33d32920e8d4621
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / crackie-1.0.3-py3-none-any.whl

Download URL crackie-1.0.3-py3-none-any.whl
Size 4.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0307b6e695b7705a9b4d008c50c42ce4d1bf8d4c7ad066f9a494c40219944736
BLAKE2b-256 checksum
How to use checksums
6e092934ec3d63f659debff9d8cf72cf8116bccd922f77f1497c5ce38bb844e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

1.0.3 This release

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page