Skip to content

Instantly share code, notes, and snippets.

@m-rey
Created March 28, 2023 11:56
Show Gist options
  • Save m-rey/2452cad1a015f67e8bed128cf307f94f to your computer and use it in GitHub Desktop.
Save m-rey/2452cad1a015f67e8bed128cf307f94f to your computer and use it in GitHub Desktop.
use this to generate a hashed URI of your pgp fingerprint for keyoxide
#!/usr/bin/env python3
import sys
import secrets
import re
import argon2
import os
import base64
import logging
import argparse
from concurrent.futures import ProcessPoolExecutor, wait, FIRST_COMPLETED
from typing import Optional
def create_argon2id_hash(secret: str, time_cost: int = 512, memory_cost: int = 64,
parallelism: int = 2, hash_len: int = 16, version: int = 19) -> str:
salt = secrets.token_bytes(16)
hash = argon2.low_level.hash_secret_raw(
secret=secret.encode(),
salt=salt,
time_cost=time_cost,
memory_cost=memory_cost,
parallelism=parallelism,
hash_len=hash_len,
type=argon2.low_level.Type.ID,
version=version
)
encoded_salt = base64.b64encode(salt).decode().rstrip('=')
encoded_hash = base64.b64encode(hash).decode().rstrip('=')
return f"$argon2id$v={version}$m={memory_cost},t={time_cost},p={parallelism}${encoded_salt}${encoded_hash}"
def worker(secret: str, vanity_pattern: re.Pattern, verbose: bool, continuous: bool, progress: bool) -> Optional[str]:
while True:
argon2id_hash = create_argon2id_hash(secret)
if vanity_pattern and vanity_pattern.search(argon2id_hash):
logging.info(f"Vanity hash found: {argon2id_hash}")
if not continuous:
return argon2id_hash
elif verbose:
logging.debug(f"Hash generated: {argon2id_hash}")
if progress:
print(".", end="", flush=True)
def main(args: argparse.Namespace) -> None:
log_level = logging.DEBUG if args.verbose else logging.INFO
logging.basicConfig(level=log_level, format='%(levelname)s: %(message)s')
flags = re.IGNORECASE if args.ignore_case else 0
vanity_pattern = re.compile(args.regex, flags=flags) if args.regex else None
try:
with ProcessPoolExecutor(max_workers=args.num_workers) as executor:
futures = {executor.submit(worker, args.secret, vanity_pattern, args.verbose, args.continuous, args.progress)}
if not args.continuous:
done, _ = wait(futures, return_when=FIRST_COMPLETED)
vanity_hash = done.pop().result()
print(f"\nVanity hash found: {vanity_hash}")
for future in futures:
future.cancel()
except KeyboardInterrupt:
logging.debug("\nStopping script and workers.")
for future in futures:
future.cancel()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Generate vanity Argon2id hashes using regex matching.')
parser.add_argument('secret', type=str, help='The secret string to be hashed.')
parser.add_argument('--regex', type=str, default=None, help='The regex pattern to match in the vanity hash.')
parser.add_argument('--num-workers', type=int, default=os.cpu_count(),
help='The number of worker processes to use. Default is the number of CPU cores.')
parser.add_argument('--ignore-case', action='store_true', help='Ignore case when matching the regex pattern.')
parser.add_argument('--verbose', action='store_true', help='Display DEBUG log messages in the terminal.')
parser.add_argument('--progress', action='store_true', help='Show progress indicator.')
parser.add_argument('--continuous', action='store_true', help='Continuously generate hashes even after finding a vanity hash.')
args = parser.parse_args()
main(args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment