#!/bin/bash # packages: 7zip, shred, secure-delete, cracklib-runtime, openssl, curl set -e unix_seconds=$(date +%s) key_path="./private_ed25519_${unix_seconds}" signature_tag="file-integrity" out_dir="./out" inner_dir="$out_dir/contents" checkcode() { local retcode if [ -z "$1" ]; then echo -e "\n\e[31mERROR!\033[0m checkcode missing return code parameter\n" exit 1 else retcode=$1 fi if [ $retcode -ne 0 ]; then echo -e "\e[31mERROR!\033[0m Response Code: $retcode" else printf ' \e[1;32mOK!\e[0m\n' fi } reset() { printf "autoshredding these files..." find . \( -path "./.git" -o -path "./keystore" -o -path "./archives" \) -prune -o -type f \( -name "*.sha512" -o -name "checksums*" -o -name "private_*" -o -name ".*" -o -name "*.sig" -o -name "*.7z" -o -name "anonymous_signer" \) -print -exec shred -uz {} \; checkcode $? if compgen -G "private_*"; then printf "nuking errant priv key files..." shred -uz private_* checkcode $? fi if compgen -G "attribution_passphrase_*" > /dev/null; then printf "nuking errant attribution passphrase files" shred -uz attribution_passphrase_* checkcode $? fi echo "autoshredding out..." srm -r -z -l -l "$out_dir" > /dev/null 2>&1 checkcode $? echo "rebuilding out..." printf "making out dir structure..." mkdir -p "$inner_dir" > /dev/null 2>&1 checkcode $? printf "updating $inner_dir/README.md..." echo "put files to verifiably archive in here" > "$inner_dir/README.md" checkcode $? printf "updating $out_dir/README.md..." echo "# todo: make this nice" > "$out_dir/README.md" checkcode $? printf "making $out_dir/test_validate_passphrase.sh..." cp test_validate_passphrase.txt "$out_dir/test_validate_passphrase.sh" > /dev/null 2>&1 checkcode $? printf "making $out_dir/test_validate_passphrase.sh executable..." chmod +x "$out_dir/test_validate_passphrase.sh" > /dev/null 2>&1 checkcode $? printf "making $out_dir/verify-everything.sh..." cp verify-everything.txt "$out_dir"/verify-everything.sh > /dev/null 2>&1 checkcode $? printf "making $out_dir/verify-everything.sh executable..." chmod +x "$out_dir/verify-everything.sh" > /dev/null 2>&1 checkcode $? housekeeping_dirs=("archives" "keystore") for dir in "${housekeeping_dirs[@]}"; do printf "changing ownership of $dir to ${USER}..." chown $USER:$USER -R "$dir" > /dev/null 2>&1 checkcode $? printf "changing permissions on $dir to 700..." chmod 700 "$dir" > /dev/null 2>&1 checkcode $? printf "finding and shredding erroneous dirs in ${dir}..." find "$dir" -mindepth 1 -type d -exec srm -r -z -l -l "{}" \; > /dev/null 2>&1 checkcode $? printf "finding and shredding erroneous files in ${dir}..." find "$dir" -type f \( -name "private_ed25519_*" -o -name "attribution_passphrase_*" \) -exec shred -uz "{}" \; > /dev/null 2>&1 checkcode $? printf "changing perms of files in $dir to 600..." find "$dir" -type f -exec chmod 600 "{}" \; > /dev/null 2>&1 checkcode $? done } # some heinously vibe coded shit pls forgiv audit_passphrase() { local raw_password="$1" local check_password="$2" if [[ -z "$raw_password" ]]; then echo "[ERROR] No passphrase provided for validation." >&2 return 2 fi if [[ -z "$check_password" ]]; then echo "[ERROR] No check passphrase provided for validation." >&2 return 2 fi if [[ "$raw_password" != "$check_password" ]]; then echo "[ERROR] Passphrases do not match!" >&2 return 2 fi unset check_password # -------------------------------------------------------------------------- # GATE 1: Minimum Length Verification (35+ Characters) # -------------------------------------------------------------------------- local pass_len="${#raw_password}" if [ "$pass_len" -lt 35 ]; then echo "❌ REJECTED: Passphrase is too short ($pass_len characters). Minimum length required is 35." return 1 fi echo "[PASS] Length verification satisfied ($pass_len characters)." # -------------------------------------------------------------------------- # GATE 2: Local Dictionary Check (cracklib-check) # -------------------------------------------------------------------------- # cracklib-check reads from stdin and outputs 'password: status' # If secure, the status string reads "OK" if ! command -v cracklib-check &> /dev/null; then echo "[WARN] cracklib-check binary not found. Skipping dictionary audit." >&2 else local cracklib_result cracklib_result=$(echo "$raw_password" | cracklib-check | cut -d':' -f2 | xargs) if [[ "$cracklib_result" != "OK" ]]; then echo "❌ REJECTED by cracklib-check: $cracklib_result" return 1 fi echo "[PASS] Local dictionary and structural complexity audit clear." fi # -------------------------------------------------------------------------- # GATE 3: Remote Anonymized Leak Check (HIBP API via k-Anonymity) # -------------------------------------------------------------------------- local full_hash full_hash=$(echo -n "$raw_password" | openssl dgst -sha1 | awk '{print toupper($2)}') local prefix="${full_hash:0:5}" local suffix="${full_hash:5}" local api_url="https://api.pwnedpasswords.com/range/$prefix" local response if ! response=$(curl -s -H "User-Agent: Bash-Passphrase-Audit-Script" "$api_url"); then echo "[FATAL] Failed to communicate with HIBP API." >&2 return 3 fi local match match=$(echo "$response" | grep -i "^$suffix:") if [[ -n "$match" ]]; then local pwn_count pwn_count=$(echo "$match" | cut -d':' -f2 | tr -d $'\r') echo "❌ VULNERABLE: This passphrase has appeared in $pwn_count known public breaches." return 1 else echo "✅ SUCCESS: Passphrase meets all local criteria and was not found in HIBP records." return 0 fi } exit_cleanup() { reset for var in $(compgen -v); do printf "unsetting $var" unset "$var" 2>/dev/null checkcode $? done } trap exit_cleanup EXIT printf "setting up environment..." reset # wait for keypress echo echo read -n 1 -s -r -p "In another terminal/window, fill $inner_dir with whatever you please then press any key to continue..." printf "ssh-keygen: makin new key: ${key_path}..." ssh-keygen -t ed25519 -f "$key_path" -C "anonymous" -N "" > /dev/null 2>&1 checkcode $? printf "ssh-keygen: changing ownership on $key_path and $key_path.pub..." chown $USER:$USER "$key_path" "$key_path.pub" > /dev/null 2>&1 checkcode $? printf "ssh-keygen: fixing perms on $key_path and $key_path.pub..." chmod 600 "$key_path" "$key_path.pub" > /dev/null 2>&1 checkcode $? printf "ssh-keygen: creating $out_dir/anonymous_signer..." echo "anonymous namespaces=\"$signature_tag\" $(cat "${key_path}.pub")" > "$out_dir/anonymous_signer" checkcode $? echo "inject random data y/n (default n)" read random #why dafuck is this opposite world? if [[ "$random" == "" || "$random" =~ ^[nN]{1}$ ]]; then echo -e 'no random... \e[1;32mOK!\e[0m\n' else printf "random: adding 1/2 random blocks of data (1024 bits, 128 bytes) to outer archive..." openssl rand -out "$out_dir/.$RANDOM" 128 > /dev/null 2>&1 checkcode $? printf "random: adding 2/2 random blocks of data (1024 bits, 128 bytes) to inner archive..." openssl rand -out "$inner_dir/.$RANDOM" 128 > /dev/null 2>&1 checkcode $? fi printf "7z: compressing inner volume..." 7z a "$out_dir/contents.7z" "$inner_dir" > /dev/null 2>&1 checkcode $? printf "deleting ${inner_dir}..." rm -rf "$inner_dir" > /dev/null 2>&1 checkcode $? printf "ssh: signing out/contents.7z..." ssh-keygen -Y sign -f "$key_path" -n "$signature_tag" "$out_dir/contents.7z" > /dev/null 2>&1 checkcode $? printf "changing directory to ${out_dir}..." cd "$out_dir" > /dev/null 2>&1 checkcode $? printf "sha512: generating sha512 checksums of files in out..." sha512sum * > "checksums.sha512" checkcode $? printf "changing directory back..." cd .. > /dev/null 2>&1 checkcode $? echo echo "Enter attribution passphrase:" read -r -s attribution_passphrase echo echo "Enter attribution passphrase again:" read -r -s attribution_passphrase_check echo printf "auditing attribution passphrase" ret=$(audit_passphrase "$attribution_passphrase" "$attribution_passphrase_check") echo $ret printf "unsetting attribution_passphrase_check" unset attribution_passphrase_check > /dev/null 2>&1 checkcode $? printf "calculating attribution passphrase and hash, then placing it" { printf "$attribution_passphrase" cat "$out_dir/contents.7z" } | sha512sum | awk '{print $1}' > "$out_dir/attribution-checksum.sha512" checkcode $? printf "sanity checking: changing working directory to ${out_dir}..." cd "$out_dir" > /dev/null 2>&1 checkcode $? printf "sanity checking: verification..." bash verify-everything.sh "$attribution_passphrase" checkcode $? printf "sanity checking: validate attribution passphrase..." bash test_validate_passphrase.sh "$attribution_passphrase" checkcode $? printf "sanity checking: returning..." cd .. checkcode $? printf "unsetting attribution_passphrase" unset attribution_passphrase > /dev/null 2>&1 checkcode $? printf "7z archiving outer dir..." 7z a "./out.7z" "$out_dir" > /dev/null 2>&1 checkcode $? printf "moving out.7z to archives..." mv out.7z "archives/verifiable_archive_${unix_seconds}.7z" > /dev/null 2>&1 checkcode $? echo echo "input keystore passphrase:" read -r -s keystore_passphrase echo echo "input keystore passphrase (again):" read -r -s keystore_passphrase_check echo printf "auditing keystore passphrase..." ret=$(audit_passphrase "$keystore_passphrase" "$keystore_passphrase_check") echo -e "$ret" printf "unsetting keystore passphrase check" unset keystore_passphrase_check > /dev/null 2>&1 checkcode $? printf "archiving keys..." 7z a "keystore/keystore_${unix_seconds}.7z" "private_*" "attribution_passphrase_*" -p"$keystore_passphrase" -mhe=on > /dev/null 2>&1 checkcode $? printf "testing key archive..." 7z t "keystore/keystore_${unix_seconds}.7z" -p"$keystore_passphrase" > /dev/null 2>&1 checkcode $? printf "unsetting keystore passphrase..." unset keystore_passphrase > /dev/null 2>&1 checkcode $? echo -e "\033[0;32mdone :3\033[0m"