Skip Navigation

Whitespace password generator in Bash

#!/bin/bash

# Generate a purely whitespace password with 128 bits of symmetric security.
#
# Characters are strictly non-control, non-graphical spaces/blanks. Both
# nonzero- and zero-width characters are used. Two characters are technically
# vertical characters, but aren't interpreted as such in the shell. They are
# "\u2028" and "\u2029". You might need a font with good Unicode support to
# prevent some of these characters creating tofu.

rng() {
    # Cryptographically secure RNG
    local min=$((2 ** 32 % 30)) # 30 = size of $s below
    local r=$SRANDOM
    while [ "$r" -lt "$min" ]; do r=$SRANDOM; done # Modulo with rejection
    echo "$(($r % 30))"
}

s=(
    # Non-zero width characters
    "\u0009" # Character tabulation
    "\u0020" # Space
    "\u00A0" # Non-breaking space
    "\u2000" # En quad
    "\u2001" # Em quad
    "\u2002" # En space
    "\u2003" # Em space
    "\u2004" # Three-per-em space
    "\u2005" # Four-per-em space
    "\u2006" # Six-per-em space
    "\u2007" # Figure space
    "\u2008" # Punctuation space
    "\u2009" # Thin space
    "\u200A" # Hair space
    "\u2028" # Line separator
    "\u2029" # Paragraph separator
    "\u202F" # Narrow no-break space
    "\u205F" # Medium mathematical space
    "\u2800" # Braille pattern blank
    "\u3000" # Ideographic space
    "\u3164" # Hangul filler
    "\uFFA0" # Halfwidth hangul filler
    # Zero width characters
    "\u115F" # Hangul choseong filler
    "\u1160" # Hangul jungseong filler
    "\u180E" # Mongolian vowel separator
    "\u200B" # Zero width space
    "\u200C" # Zero width non-joiner
    "\u200D" # Zero width joiner
    "\u2060" # Word joiner
    "\uFEFF" # Zero width non-breaking space
)
p=""

# Generate 27 characters for at least 128 bits security
for i in {1..27}; do
    r=$(rng)
    c=${s[$r]}
    p="${p}${c}"
done

tabs -1 # Tab width of 1 space

# Wrap the password in braille pattern blanks for correctly handling zero-width
# characters and to prevent whitespace stripping by the auth form.
echo -e "\"\u2800${p}\u2800\""

Example:

$ bash whitespace.bash
"⠀        ᅠ        ⠀  ᅟ ᅠ​⠀"
1