๐ Linux Password Generator
6/1/2015
Secure Linux Password Generator (password_generator.sh)
๐ Key Features
- Cryptographically Secure: Draws raw entropy directly from Linux
/dev/urandom. - Flexible Complexity Modes:
plain: Alphabetic characters only (a-z,A-Z).numeric: Digits only (0-9).alpha-numeric: Alphabetic characters + Digits (a-z,A-Z,0-9).alpha-special-numeric: Letters + Digits + Special Symbols (!@#$%^&*()_+-=[]{}|;:,.<>?).
- Custom Character Counts: Allows exact specification of special characters and numeric digit counts.
- Uniform Character Shuffling: Employs
shufor a Fisher-Yates shuffle to prevent predictable character groupings. - Entropy Calculation: Computes and reports password strength in bits of entropy ($H = L \times \log_2(N)$).
- Dual Operation Modes: Interactive step-by-step wizard or non-interactive CLI flags.
๐ Script Code (password_generator.sh)
#!/usr/bin/env bash
# ==============================================================================
# Script: password_generator.sh
# Purpose: Interactive & CLI Password Generator for Linux Hosts
# Features: Cryptographically secure (/dev/urandom), custom length, special
# character counts, complexity presets, Fisher-Yates/shuf randomizer,
# and password entropy calculation.
# ==============================================================================
set -euo pipefail
# Character Set Definitions
ALPHA_LOWER="abcdefghijklmnopqrstuvwxyz"
ALPHA_UPPER="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
NUMERIC="0123456789"
SPECIAL='!@#$%^&*()_+-=[]{}|;:,.<>?'
# Default Values
LENGTH=16
TYPE="alpha-special-numeric"
USE_SPECIAL="y"
SPECIAL_COUNT=4
NUMERIC_COUNT=4
COUNT=1
INTERACTIVE=true
# Helper Functions
print_banner() {
echo "======================================================================="
echo " SECURE LINUX PASSWORD GENERATOR UTILITY "
echo "======================================================================="
}
usage() {
print_banner
cat << EOF
Usage: $0 [OPTIONS]
Non-Interactive Flag Mode:
-l, --length <NUM> Total length of the password (default: 16)
-t, --type <TYPE> Password complexity type:
- plain (Letters only)
- numeric (Digits only)
- alpha-numeric (Letters + Digits)
- alpha-special-numeric (Letters + Digits + Symbols) [default]
-s, --special-count <NUM> Exact number of special characters to include
-n, --numeric-count <NUM> Exact number of numeric characters to include
-c, --count <NUM> Number of passwords to generate (default: 1)
-i, --interactive Force interactive prompt mode
-h, --help Show this help menu
Examples:
Interactive Mode:
$0
Non-Interactive Examples:
$0 -l 20 -t alpha-special-numeric -s 5 -n 4
$0 -l 12 -t alpha-numeric -c 5
$0 --length 24 --special-count 6
EOF
exit 0
}
# Parse Command Line Arguments
parse_args() {
if [ "$#" -gt 0 ]; then
INTERACTIVE=false
fi
while [ "$#" -gt 0 ]; do
case "$1" in
-l|--length)
LENGTH="$2"; shift 2 ;;
-t|--type)
TYPE="$2"; shift 2 ;;
-s|--special-count)
SPECIAL_COUNT="$2"; USE_SPECIAL="y"; shift 2 ;;
-n|--numeric-count)
NUMERIC_COUNT="$2"; shift 2 ;;
-c|--count)
COUNT="$2"; shift 2 ;;
-i|--interactive)
INTERACTIVE=true; shift 1 ;;
-h|--help)
usage ;;
*)
echo "[-] Unknown option: $1" >&2
usage ;;
esac
done
}
# Interactive Prompt Interface
prompt_user() {
print_banner
echo "[+] Running in Interactive Mode..."
echo ""
# 1. Total Password Length
read -rp "1. Enter total password length [default: 16]: " input_len
if [[ -n "${input_len}" ]]; then
if [[ "${input_len}" =~ ^[0-9]+$ ]] && [ "${input_len}" -ge 4 ]; then
LENGTH="${input_len}"
else
echo "[!] Invalid length. Defaulting to 16 characters (minimum is 4)."
LENGTH=16
fi
fi
# 2. Select Password Type / Complexity
echo ""
echo "2. Select Password Type / Complexity:"
echo " 1) Plain Alpha (Letters only: a-z, A-Z)"
echo " 2) Alpha-Numeric (Letters + Digits: a-z, A-Z, 0-9)"
echo " 3) Alpha-Special-Numeric (Letters + Digits + Special Symbols) [Default]"
read -rp " Choice [1-3, default: 3]: " type_choice
case "${type_choice}" in
1)
TYPE="plain"
USE_SPECIAL="n"
SPECIAL_COUNT=0
NUMERIC_COUNT=0
;;
2)
TYPE="alpha-numeric"
USE_SPECIAL="n"
SPECIAL_COUNT=0
;;
3|"")
TYPE="alpha-special-numeric"
USE_SPECIAL="y"
;;
*)
echo "[!] Invalid choice. Defaulting to Alpha-Special-Numeric."
TYPE="alpha-special-numeric"
USE_SPECIAL="y"
;;
esac
# 3. Special Character Count Prompt (if applicable)
if [ "${TYPE}" == "alpha-special-numeric" ]; then
echo ""
read -rp "3. Include special characters? (y/n) [default: y]: " input_spec_yn
input_spec_yn=$(echo "${input_spec_yn}" | tr '[:upper:]' '[:lower:]')
if [[ "${input_spec_yn}" == "n" ]]; then
USE_SPECIAL="n"
SPECIAL_COUNT=0
TYPE="alpha-numeric"
else
USE_SPECIAL="y"
read -rp " How many special characters? [default: 4, max: $((LENGTH - 2))]: " input_spec_cnt
if [[ -n "${input_spec_cnt}" ]]; then
if [[ "${input_spec_cnt}" =~ ^[0-9]+$ ]] && [ "${input_spec_cnt}" -le "$((LENGTH - 2))" ]; then
SPECIAL_COUNT="${input_spec_cnt}"
else
echo "[!] Invalid count. Defaulting to 4 special characters."
SPECIAL_COUNT=4
fi
fi
fi
fi
# 4. Numeric Count Prompt (if applicable)
if [[ "${TYPE}" == "alpha-numeric" || "${TYPE}" == "alpha-special-numeric" ]]; then
MAX_NUM=$((LENGTH - SPECIAL_COUNT - 1))
[ "${MAX_NUM}" -lt 1 ] && MAX_NUM=1
read -rp "4. How many numeric digits? [default: 4, max: ${MAX_NUM}]: " input_num_cnt
if [[ -n "${input_num_cnt}" ]]; then
if [[ "${input_num_cnt}" =~ ^[0-9]+$ ]] && [ "${input_num_cnt}" -le "${MAX_NUM}" ]; then
NUMERIC_COUNT="${input_num_cnt}"
else
echo "[!] Invalid count. Defaulting to 4 numeric digits."
NUMERIC_COUNT=4
fi
fi
fi
# 5. Quantity of passwords
read -rp "5. How many passwords to generate? [default: 1]: " input_count
if [[ -n "${input_count}" && "${input_count}" =~ ^[0-9]+$ ]] && [ "${input_count}" -ge 1 ]; then
COUNT="${input_count}"
fi
}
# Generate Secure Random String from character set
get_random_chars() {
local charset="$1"
local count="$2"
if [ "${count}" -le 0 ]; then
echo ""
return
fi
LC_ALL=C tr -dc "${charset}" < /dev/urandom | head -c "${count}" || true
}
# Shuffle string characters safely using shuf or Fisher-Yates fallback
shuffle_string() {
local input="$1"
if command -v shuf &>/dev/null; then
echo "${input}" | grep -o . | shuf | tr -d '\n'
else
local len=${#input}
local i j tmp
declare -a arr
for (( i=0; i<len; i++ )); do
arr[i]="${input:$i:1}"
done
for (( i=len-1; i>0; i-- )); do
j=$(( RANDOM % (i + 1) ))
tmp="${arr[i]}"
arr[i]="${arr[j]}"
arr[j]="${tmp}"
done
( IFS=""; echo "${arr[*]}" )
fi
}
# Calculate Entropy in Bits
calculate_entropy() {
local len="$1"
local pool_size="$2"
if command -v python3 &>/dev/null; then
python3 -c "import math; print(round(${len} * math.log2(${pool_size}), 1))" 2>/dev/null || echo "N/A"
else
echo "N/A"
fi
}
# Main Password Generation Engine
generate_password() {
local raw_pass=""
local charset_pool=""
local pool_size=0
case "${TYPE}" in
plain)
SPECIAL_COUNT=0
NUMERIC_COUNT=0
USE_SPECIAL="n"
charset_pool="${ALPHA_LOWER}${ALPHA_UPPER}"
pool_size=52
raw_pass=$(get_random_chars "${charset_pool}" "${LENGTH}")
;;
numeric)
SPECIAL_COUNT=0
NUMERIC_COUNT="${LENGTH}"
USE_SPECIAL="n"
charset_pool="${NUMERIC}"
pool_size=10
raw_pass=$(get_random_chars "${charset_pool}" "${LENGTH}")
;;
alpha-numeric)
SPECIAL_COUNT=0
USE_SPECIAL="n"
charset_pool="${ALPHA_LOWER}${ALPHA_UPPER}${NUMERIC}"
pool_size=62
local alpha_count=$((LENGTH - NUMERIC_COUNT))
[ "${alpha_count}" -lt 1 ] && alpha_count=1
local rand_alpha=$(get_random_chars "${ALPHA_LOWER}${ALPHA_UPPER}" "${alpha_count}")
local rand_num=$(get_random_chars "${NUMERIC}" "${NUMERIC_COUNT}")
raw_pass="${rand_alpha}${rand_num}"
;;
alpha-special-numeric)
USE_SPECIAL="y"
charset_pool="${ALPHA_LOWER}${ALPHA_UPPER}${NUMERIC}${SPECIAL}"
pool_size=94
if [ "$((SPECIAL_COUNT + NUMERIC_COUNT))" -ge "${LENGTH}" ]; then
SPECIAL_COUNT=$((LENGTH / 4))
NUMERIC_COUNT=$((LENGTH / 4))
fi
local alpha_count=$((LENGTH - SPECIAL_COUNT - NUMERIC_COUNT))
[ "${alpha_count}" -lt 1 ] && alpha_count=1
local rand_alpha=$(get_random_chars "${ALPHA_LOWER}${ALPHA_UPPER}" "${alpha_count}")
local rand_num=$(get_random_chars "${NUMERIC}" "${NUMERIC_COUNT}")
local rand_spec=$(get_random_chars "${SPECIAL}" "${SPECIAL_COUNT}")
raw_pass="${rand_alpha}${rand_num}${rand_spec}"
;;
*)
echo "[-] Error: Unsupported password type '${TYPE}'." >&2
exit 1
;;
esac
local final_password
final_password=$(shuffle_string "${raw_pass}")
local entropy
entropy=$(calculate_entropy "${LENGTH}" "${pool_size}")
echo "${final_password}|${entropy}"
}
# Main Execution Flow
main() {
parse_args "$@"
if [ "${INTERACTIVE}" = true ]; then
prompt_user
fi
# Pre-sanitize settings for header display
case "${TYPE}" in
plain)
SPECIAL_COUNT=0
NUMERIC_COUNT=0
USE_SPECIAL="n"
;;
numeric)
SPECIAL_COUNT=0
NUMERIC_COUNT="${LENGTH}"
USE_SPECIAL="n"
;;
alpha-numeric)
SPECIAL_COUNT=0
USE_SPECIAL="n"
;;
alpha-special-numeric)
USE_SPECIAL="y"
;;
esac
echo ""
echo "======================================================================="
echo " GENERATED PASSWORD(S)"
echo "======================================================================="
echo " Configuration:"
echo " - Total Length : ${LENGTH}"
echo " - Password Type : ${TYPE}"
echo " - Special Characters : ${SPECIAL_COUNT} (Enabled: ${USE_SPECIAL})"
echo " - Numeric Digits : ${NUMERIC_COUNT}"
echo "-----------------------------------------------------------------------"
for (( i=1; i<=COUNT; i++ )); do
res=$(generate_password)
pass=$(echo "${res}" | cut -d'|' -f1)
ent=$(echo "${res}" | cut -d'|' -f2)
if [ "${COUNT}" -gt 1 ]; then
echo -e " [Password #${i}] : ${pass} (Entropy: ~${ent} bits)"
else
echo -e " Generated Password : \033[1;32m${pass}\033[0m"
echo -e " Estimated Entropy : ~${ent} bits"
fi
done
echo "======================================================================="
}
main "$@"
๐ Installation & Execution
- Save the code into a file named
password_generator.sh. - Grant executable permissions:
chmod +x password_generator.sh - Run interactively:
./password_generator.sh
๐ป CLI Flags Reference Table
| Flag | Long Option | Description | Default |
|---|---|---|---|
-l |
--length |
Total length of the password | 16 |
-t |
--type |
Complexity mode (plain, numeric, alpha-numeric, alpha-special-numeric) |
alpha-special-numeric |
-s |
--special-count |
Exact count of special symbols | 4 |
-n |
--numeric-count |
Exact count of numeric digits | 4 |
-c |
--count |
Number of passwords to generate | 1 |
-i |
--interactive |
Force interactive prompt mode | true (if no args) |
-h |
--help |
Display usage menu | โ |
๐งช Usage Examples
1. Interactive Walkthrough Example
$ ./password_generator.sh
=======================================================================
SECURE LINUX PASSWORD GENERATOR UTILITY
=======================================================================
[+] Running in Interactive Mode...
1. Enter total password length [default: 16]: 20
2. Select Password Type / Complexity:
1) Plain Alpha (Letters only: a-z, A-Z)
2) Alpha-Numeric (Letters + Digits: a-z, A-Z, 0-9)
3) Alpha-Special-Numeric (Letters + Digits + Special Symbols) [Default]
Choice [1-3, default: 3]: 3
3. Include special characters? (y/n) [default: y]: y
How many special characters? [default: 4, max: 18]: 5
4. How many numeric digits? [default: 4, max: 14]: 4
5. How many passwords to generate? [default: 1]: 1
=======================================================================
GENERATED PASSWORD(S)
=======================================================================
Configuration:
- Total Length : 20
- Password Type : alpha-special-numeric
- Special Characters : 5 (Enabled: y)
- Numeric Digits : 4
-----------------------------------------------------------------------
Generated Password : F0Pb?Bj(fO,]<m8c3Aa3
Estimated Entropy : ~131.1 bits
=======================================================================
2. Non-Interactive CLI Automation Examples
-
20-character password with 5 symbols & 4 numbers:
./password_generator.sh -l 20 -t alpha-special-numeric -s 5 -n 4 -
Batch generate 5 alpha-numeric passwords of length 16:
./password_generator.sh -l 16 -t alpha-numeric -c 5 -
Generate a 12-character plain letters-only password:
./password_generator.sh -l 12 -t plain
๐ Security & Entropy Metrics
The password strength is rated in bits of entropy calculated via:
$$H = L \times \log_2(N)$$
Where:
- $L$ = Total Password Length
- $N$ = Character Set Pool Size
- Plain Alpha ($N=52$): ~5.7 bits / char
- Alpha-Numeric ($N=62$): ~5.95 bits / char
- Alpha-Special-Numeric ($N=94$): ~6.55 bits / char
[!NOTE] A password with > 80 bits of entropy is considered resilient against brute-force attacks, while > 128 bits is considered quantum-safe for general authentication.