charsets
This commit is contained in:
@@ -95,6 +95,11 @@ TEMPLATES=(
|
|||||||
| `{num:N}` | N digits | ~3.3 bits/char |
|
| `{num:N}` | N digits | ~3.3 bits/char |
|
||||||
| `{special:N}` | N from `!?@#%~=+` | ~3.0 bits/char |
|
| `{special:N}` | N from `!?@#%~=+` | ~3.0 bits/char |
|
||||||
| `{NAME:N-M}` | N to M chars from charset NAME | log2(Σ size^L) |
|
| `{NAME:N-M}` | N to M chars from charset NAME | log2(Σ size^L) |
|
||||||
|
| `{hex:N}` | `3f9a` | 4.0 bits/char |
|
||||||
|
| `{b58:N}` | `Vk2x` (Base58, no 0OIl) | ~5.9 bits/char |
|
||||||
|
| `{b64:N}` | `hG_4` (URL-safe base64) | 6.0 bits/char |
|
||||||
|
| `{alnum:N}` | `xR4x` | ~6.0 bits/char |
|
||||||
|
| `{ascii:N}` | `p/(!` (all printable, no space) | ~6.5 bits/char |
|
||||||
|
|
||||||
\* Word entropy depends on pool size. Values shown assume all built-in lists enabled (~14k words, ~13.8 bits/word).
|
\* Word entropy depends on pool size. Values shown assume all built-in lists enabled (~14k words, ~13.8 bits/word).
|
||||||
|
|
||||||
@@ -109,7 +114,7 @@ CHARSETS=(
|
|||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
Names must match `[a-z][a-z0-9_]*` and override the built-in four (alpha, safe, num, special). Avoid duplicate characters; himi warns if it sees them, since they skew the distribution and overstate entropy.
|
Names must match `[a-z][a-z0-9_]*` and override any built-in of the same name (alpha, safe, num, special, hex, b58, b64, alnum, ascii). Avoid duplicate characters; himi warns if it sees them, since they skew the distribution and overstate entropy.
|
||||||
|
|
||||||
Range tokens pick the length weighted by `size^L`, so every possible output is equally likely. `{num:1-2}` covers 0-99 plus 0-9 (110 outcomes, ~6.8 bits), not a 50/50 coin flip on length, which would tank min-entropy.
|
Range tokens pick the length weighted by `size^L`, so every possible output is equally likely. `{num:1-2}` covers 0-99 plus 0-9 (110 outcomes, ~6.8 bits), not a 50/50 coin flip on length, which would tank min-entropy.
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ WORD_MAX_LENGTH=9
|
|||||||
# {Word} — random word (Title Case)
|
# {Word} — random word (Title Case)
|
||||||
# {word!} — random lower or UPPER (+1 bit entropy)
|
# {word!} — random lower or UPPER (+1 bit entropy)
|
||||||
# {Word!} — random lower/Title/UPPER (+1.58 bits entropy)
|
# {Word!} — random lower/Title/UPPER (+1.58 bits entropy)
|
||||||
# {NAME:N} — N chars from charset NAME (alpha/safe/num/special/custom)
|
# {NAME:N} — N chars from charset NAME
|
||||||
|
# built-in: alpha safe num special hex b58 b64 alnum ascii
|
||||||
# {NAME:N-M} — N to M chars, weighted so every output is equally likely
|
# {NAME:N-M} — N to M chars, weighted so every output is equally likely
|
||||||
# (entropy = log2 of total outcomes, e.g. {num:1-2} ≈ 6.8 bits)
|
# (entropy = log2 of total outcomes, e.g. {num:1-2} ≈ 6.8 bits)
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ readonly CONFIG_SCHEMA_VERSION=2
|
|||||||
|
|
||||||
# Generic charset token: {name:N} or {name:N-M}
|
# Generic charset token: {name:N} or {name:N-M}
|
||||||
readonly TOKEN_RE='\{([a-z][a-z0-9_]*):([0-9]+)(-([0-9]+))?\}'
|
readonly TOKEN_RE='\{([a-z][a-z0-9_]*):([0-9]+)(-([0-9]+))?\}'
|
||||||
|
# Anything that still looks like a token after expansion (typo'd or unknown).
|
||||||
|
# Shape-based so charsets containing { } (e.g. ascii) don't false-positive.
|
||||||
|
readonly LEFTOVER_RE='\{[A-Za-z][A-Za-z0-9_]*(!|:[0-9]+(-[0-9]+)?)?\}'
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
@@ -37,6 +40,11 @@ ALPHA_CHARSET='0123456789ABCDEFGHJKMNPQRSTVWXYZ' # Crockford Base32 (32 chars,
|
|||||||
SAFE_CHARSET='ACDEFGHJKMNPQRTWXY234679' # Ultra-safe (24 chars, 4.6 bits) - no B/8, 0/O, 1/I/L, 5/S
|
SAFE_CHARSET='ACDEFGHJKMNPQRTWXY234679' # Ultra-safe (24 chars, 4.6 bits) - no B/8, 0/O, 1/I/L, 5/S
|
||||||
NUM_CHARSET='0123456789'
|
NUM_CHARSET='0123456789'
|
||||||
SPECIAL_CHARSET='!?@#%~=+'
|
SPECIAL_CHARSET='!?@#%~=+'
|
||||||
|
HEX_CHARSET='0123456789abcdef' # 16 chars, 4.0 bits
|
||||||
|
B58_CHARSET='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' # Base58: no 0OIl (58 chars, 5.86 bits)
|
||||||
|
B64_CHARSET='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_' # URL-safe base64 (64 chars, 6.0 bits)
|
||||||
|
ALNUM_CHARSET='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' # 62 chars, 5.95 bits
|
||||||
|
ASCII_CHARSET='!"#$%&'\''()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~' # all printable, no space (94 chars, 6.55 bits)
|
||||||
WORD_MIN_LENGTH=4
|
WORD_MIN_LENGTH=4
|
||||||
WORD_MAX_LENGTH=8
|
WORD_MAX_LENGTH=8
|
||||||
|
|
||||||
@@ -200,6 +208,11 @@ get_charset() {
|
|||||||
safe) printf '%s' "$SAFE_CHARSET" ;;
|
safe) printf '%s' "$SAFE_CHARSET" ;;
|
||||||
num) printf '%s' "$NUM_CHARSET" ;;
|
num) printf '%s' "$NUM_CHARSET" ;;
|
||||||
special) printf '%s' "$SPECIAL_CHARSET" ;;
|
special) printf '%s' "$SPECIAL_CHARSET" ;;
|
||||||
|
hex) printf '%s' "$HEX_CHARSET" ;;
|
||||||
|
b58) printf '%s' "$B58_CHARSET" ;;
|
||||||
|
b64) printf '%s' "$B64_CHARSET" ;;
|
||||||
|
alnum) printf '%s' "$ALNUM_CHARSET" ;;
|
||||||
|
ascii) printf '%s' "$ASCII_CHARSET" ;;
|
||||||
*) return 1 ;;
|
*) return 1 ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -521,6 +534,9 @@ cmd_list() {
|
|||||||
# Uninstall: remove himi and all data
|
# Uninstall: remove himi and all data
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
cmd_uninstall() {
|
cmd_uninstall() {
|
||||||
|
local purge="false"
|
||||||
|
[[ "${1:-}" == "--purge" ]] && purge="true"
|
||||||
|
|
||||||
read -p "Are you sure you want to remove himi and all custom wordlists? (y/N) " -n 1 -r
|
read -p "Are you sure you want to remove himi and all custom wordlists? (y/N) " -n 1 -r
|
||||||
echo
|
echo
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
@@ -543,23 +559,43 @@ cmd_uninstall() {
|
|||||||
# Linux/GNU
|
# Linux/GNU
|
||||||
sed -i.bak "/$start_marker/,/$end_marker/d" "$HOME/$p"
|
sed -i.bak "/$start_marker/,/$end_marker/d" "$HOME/$p"
|
||||||
fi
|
fi
|
||||||
ok "Cleaned up $p (backup created as $p.bak)"
|
if [[ "$purge" == "true" ]]; then
|
||||||
|
rm -f "$HOME/$p.bak"
|
||||||
|
ok "Cleaned up $p (no backup, --purge)"
|
||||||
|
else
|
||||||
|
ok "Cleaned up $p (backup created as $p.bak)"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# 2. Remove completions
|
# 2. Remove completions (and the .zfunc dir if we leave it empty)
|
||||||
rm -f "${HOME}/.zfunc/_himi"
|
rm -f "${HOME}/.zfunc/_himi"
|
||||||
|
rmdir "${HOME}/.zfunc" 2>/dev/null || true
|
||||||
rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions/himi"
|
rm -f "${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion/completions/himi"
|
||||||
|
|
||||||
# 3. Remove data and binary
|
# 3. Remove data and binary
|
||||||
rm -rf "$CONFIG_DIR"
|
rm -rf "$CONFIG_DIR"
|
||||||
ok "Removed configuration and wordlists."
|
ok "Removed configuration and wordlists."
|
||||||
|
|
||||||
# Final step: Binary deletes itself
|
# Final step: binary deletes itself. Prefer the file actually running
|
||||||
local self
|
# (works for ./himi too); fall back to PATH lookup without tripping set -e.
|
||||||
self=$(command -v himi)
|
local self="${BASH_SOURCE[0]}"
|
||||||
rm -f "$self"
|
if [[ ! -f "$self" ]]; then
|
||||||
|
self=$(command -v himi) || self=""
|
||||||
|
fi
|
||||||
|
[[ -n "$self" ]] && rm -f "$self"
|
||||||
|
|
||||||
|
# Flag any other copies still lurking in PATH
|
||||||
|
local leftover
|
||||||
|
if leftover=$(command -v himi 2>/dev/null) && [[ -n "$leftover" ]]; then
|
||||||
|
warn "another himi remains at: $leftover — remove it manually"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$purge" != "true" ]]; then
|
||||||
|
dim "Profile backups (*.bak) were kept; use 'himi uninstall --purge' for none."
|
||||||
|
printf "\n"
|
||||||
|
fi
|
||||||
|
|
||||||
ok "himi has been uninstalled."
|
ok "himi has been uninstalled."
|
||||||
}
|
}
|
||||||
@@ -953,7 +989,7 @@ cmd_test() {
|
|||||||
local example leftovers=""
|
local example leftovers=""
|
||||||
for ((i = 0; i < 5; i++)); do
|
for ((i = 0; i < 5; i++)); do
|
||||||
example=$(expand_template "$pattern")
|
example=$(expand_template "$pattern")
|
||||||
[[ "$example" == *'{'* && "$example" == *'}'* ]] && leftovers="true"
|
[[ "$example" =~ $LEFTOVER_RE ]] && leftovers="true"
|
||||||
printf " %s\n" "$example"
|
printf " %s\n" "$example"
|
||||||
done
|
done
|
||||||
printf "\n"
|
printf "\n"
|
||||||
@@ -1012,7 +1048,7 @@ cmd_generate() {
|
|||||||
secrets+=$(expand_template "$pattern")
|
secrets+=$(expand_template "$pattern")
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ "$secrets" == *'{'* && "$secrets" == *'}'* ]]; then
|
if [[ "$secrets" =~ $LEFTOVER_RE ]]; then
|
||||||
warn "output contains unexpanded {token}s — check the template ('himi test' helps)"
|
warn "output contains unexpanded {token}s — check the template ('himi test' helps)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -1054,7 +1090,7 @@ Usage:
|
|||||||
himi entropy [name] Show entropy for template(s)
|
himi entropy [name] Show entropy for template(s)
|
||||||
himi test '{pattern}' Test a custom pattern
|
himi test '{pattern}' Test a custom pattern
|
||||||
himi config Edit config in \$EDITOR
|
himi config Edit config in \$EDITOR
|
||||||
himi uninstall Remove himi and all data
|
himi uninstall Remove himi and all data (--purge: no profile backups)
|
||||||
himi -h, --help Show this help
|
himi -h, --help Show this help
|
||||||
|
|
||||||
Templates (configure in $CONFIG_FILE):
|
Templates (configure in $CONFIG_FILE):
|
||||||
@@ -1082,6 +1118,11 @@ EOF
|
|||||||
printf " %-12s %s\n" "safe" "$SAFE_CHARSET"
|
printf " %-12s %s\n" "safe" "$SAFE_CHARSET"
|
||||||
printf " %-12s %s\n" "num" "$NUM_CHARSET"
|
printf " %-12s %s\n" "num" "$NUM_CHARSET"
|
||||||
printf " %-12s %s\n" "special" "$SPECIAL_CHARSET"
|
printf " %-12s %s\n" "special" "$SPECIAL_CHARSET"
|
||||||
|
printf " %-12s %s\n" "hex" "$HEX_CHARSET"
|
||||||
|
printf " %-12s %s\n" "b58" "$B58_CHARSET"
|
||||||
|
printf " %-12s %s\n" "b64" "$B64_CHARSET"
|
||||||
|
printf " %-12s %s\n" "alnum" "$ALNUM_CHARSET"
|
||||||
|
printf " %-12s %s\n" "ascii" "$ASCII_CHARSET"
|
||||||
for entry in ${CHARSETS[@]+"${CHARSETS[@]}"}; do
|
for entry in ${CHARSETS[@]+"${CHARSETS[@]}"}; do
|
||||||
IFS='|' read -r name pattern <<< "$entry"
|
IFS='|' read -r name pattern <<< "$entry"
|
||||||
printf " %-12s %s\n" "$name" "$pattern"
|
printf " %-12s %s\n" "$name" "$pattern"
|
||||||
|
|||||||
Reference in New Issue
Block a user