Generate Strong Passwords Securely Using OpenSSL + Bash

Generate Strong Passwords Securely Using OpenSSL + Bash

Generate Strong Passwords Securely Using OpenSSL + Bash

 

Strong passwords are a fundamental pillar of cybersecurity hygiene, especially when you’re automating scripts, working with APIs, or building web applications. Instead of relying on weak or reused credentials, you can harness the power of OpenSSL in a Bash script to generate customizable, secure passwords on the fly.

In this post, we’ll walk through building a lightweight, flexible Bash utility for password generation using OpenSSL with customizable options like length and character sets. Whether you’re provisioning user accounts or adding credentials to configuration files, this utility has you covered.

1. Why OpenSSL? Leveraging System Tools for Security

OpenSSL is a widely used toolkit for SSL/TLS but it also offers cryptographic utilities, including the generation of secure random strings via the rand command. This makes it ideal for generating entropy-rich passwords directly from the command line.

Here’s a simple one-liner using OpenSSL to generate a random 16-character base64 password:

openssl rand -base64 12

Why 12? Because base64 encoding increases the size of the output: 12 bytes of entropy will give you 16 base64 characters. You can increase entropy by increasing the byte size passed into rand.

2. Basic Bash Utility to Generate Passwords

Let’s encapsulate this logic into a simple Bash script:

#!/bin/bash

# Default values
LENGTH=16

# Generate password using OpenSSL
openssl rand -base64 $((LENGTH * 3 / 4)) | cut -c1-$LENGTH

This will output a secure password of the specified length each time it’s run. The cut ensures output doesn’t exceed the desired character count, considering padding added by -base64.

To make it more dynamic, let’s add options for character classes: letters, digits, symbols. That requires more control than base64 provides, so we need a custom charset.

3. Advanced: Custom Character Sets

Let’s take things up a notch. Instead of relying on base64, we generate a string from a custom character set. Here’s how to build that:

#!/bin/bash

LENGTH=16
CHARS=""  # Will be built from flags

# Flags
INCLUDE_SYMBOLS=false
INCLUDE_NUMBERS=false
INCLUDE_LOWER=false
INCLUDE_UPPER=false

# Parse flags
while [[ "$#" -gt 0 ]]; do
  case $1 in
    -l|--length) LENGTH="$2"; shift 2;;
    --symbols) INCLUDE_SYMBOLS=true; shift;;
    --numbers) INCLUDE_NUMBERS=true; shift;;
    --lower) INCLUDE_LOWER=true; shift;;
    --upper) INCLUDE_UPPER=true; shift;;
    *) echo "Unknown option: $1"; exit 1;;
  esac
done

# Build character set
$INCLUDE_SYMBOLS && CHARS+="!@#%^&*()_+-=,.<>?/"
$INCLUDE_NUMBERS && CHARS+="0123456789"
$INCLUDE_LOWER && CHARS+="abcdefghijklmnopqrstuvwxyz"
$INCLUDE_UPPER && CHARS+="ABCDEFGHIJKLMNOPQRSTUVWXYZ"

# Fallback if no sets selected
[[ -z "$CHARS" ]] && CHARS="A-Za-z0-9"

# Generate password from /dev/urandom and filter to $CHARS
PASSWORD=$(tr -dc "$CHARS" < /dev/urandom | head -c "$LENGTH")
echo "$PASSWORD"

This version gives full control over what characters appear in the password, and uses /dev/urandom, which is a secure source of entropy in UNIX systems. It's useful when you want to avoid base64's limited character set or padding.

4. UX Improvements: Help Menu and Defaults

User experience even in small scripts matters. Let’s add a usage function and check for common errors:

usage() {
  echo "Usage: $0 [options]"
  echo "  -l, --length     Length of the password (default: 16)"
  echo "  --symbols        Include special characters"
  echo "  --numbers        Include digits"
  echo "  --lower          Include lowercase letters"
  echo "  --upper          Include uppercase letters"
  exit 1
}

# At beginning of script
[[ "$1" == "--help" || "$1" == "-h" ]] && usage

This makes the script more user-friendly and avoids surprises like generating only base64 letters if no flags are given. Always aim for clarity in developer tools, even the small ones.

5. Real-World Tips: Security, Portability, and Performance

  • Security: Prefer /dev/urandom or openssl rand over Bash-only solutions like $RANDOM. They're cryptographically stronger.
  • Automation Tip: Integrate this utility in CI/CD scripts to auto-provision database or API credentials securely.
  • Portability: Ensure openssl is installed. On minimal systems, fallback to /dev/urandom and document the requirement.
  • Performance: Avoid infinite loops in tr -dc and always bound input with head -c.

Sample usage in a provisioning script:

PASS=$(./genpass.sh -l 20 --symbols --numbers --upper)
echo "DB_PASSWORD=$PASS" >> .env

Conclusion

With just a few lines of Bash and the power of OpenSSL or /dev/urandom, you can build a reliable, scriptable password generation tool that’s both secure and customizable. Use it for API keys, temporary credentials, or secure user signups—and sleep soundly knowing you’ve eliminated a critical weak point in many automation processes: bad passwords.

 

Useful links: