Radiator Server Documentation — v10.33.4

Password Hashing

Secure password storage using cryptographic hashing algorithms

Table of Contents
  • How It Works
  • Generating Hashes with password_hash(...)
  • Basic syntax
  • Parameterized syntax
  • Supported Algorithms
  • Argon2 (Highest security)
  • PBKDF2 (SHA-512 / SHA-256 / SHA-1)
  • Crypt SHA-512
  • Crypt SHA-256
  • NT Hash
  • Plaintext
  • Usage Examples
  • JSON File Backend
  • SQL Backend
  • Backend Configuration
  • Security Recommendations
  • Performance Considerations
  • Related Documentation

Radiator Server supports multiple password hashing algorithms for secure credential storage. When user passwords are loaded from backends (SQL, JSON files, etc.), Radiator automatically detects the hashing algorithm based on the password format prefix and uses the appropriate verification method during authentication.

How It Works

  1. Passwords stored in backends include a prefix that identifies the hashing algorithm: {argon2}, {crypt-sha256}, etc.
  2. When a backend loads user data, the password format is detected automatically
  3. During authentication, Radiator compares the provided plaintext password against the stored hash using the appropriate algorithm
  4. No configuration is needed - the algorithm is determined by the password prefix

Radiator can also generate password hashes inside pipelines with the password_hash(...) filter when you need to migrate or update stored credentials.

If you want a step-by-step login-time migration pattern, see Password Rehashing During Login.

Generating Hashes with password_hash(...)

Use the password_hash(...) value filter to transform cleartext input into a canonical Radiator password value ({algorithm}<hash-body>).

This is useful when you want to:

  • Keep authentication and rehash logic in Radconf
  • Migrate users from plaintext to hashed storage after successful login
  • Standardize hash format before writing back to a backend

Basic syntax

auth.password | password_hash("argon2")
auth.password | password_hash("pbkdf2-sha512")

The first argument is the algorithm name. The generated value includes the matching prefix, for example {argon2}... or {pbkdf2-sha512}....

The pipe expression transforms the value on the left and returns the transformed value. By itself, it does not write anything to a backend.

To persist the hash, use the result on the right-hand side of an assignment or backend binding.

Store to a variable (for use later in the same policy):

modify {
  vars.new_password_hash = auth.password | password_hash("argon2");
}

Store directly to a backend field:

query "UPDATE_PASSWORD" {
  put {
    key "%{aaa.identity}";
    collection "customers";
    bindings {
      password_hash = auth.password | password_hash("argon2");
    }
  }
}

Parameterized syntax

password_hash(...) also supports named key=value options after the algorithm.

PBKDF2 example:

auth.password | password_hash("pbkdf2-sha512", rounds=300000)

Argon2 example:

auth.password | password_hash("argon2", memory_kib=8192, iterations=2, parallelism=1)

Supported options:

  • rounds: PBKDF2 iteration count. Supported only with pbkdf2-sha1, pbkdf2-sha256, and pbkdf2-sha512.
  • iterations: Argon2 time cost (t). Supported only with argon2.
  • memory_kib: Argon2 memory cost in KiB (m). Supported only with argon2.
  • parallelism: Argon2 parallelism (p). Supported only with argon2.

Validation and compatibility rules:

  • Options must use = assignment syntax, for example rounds=300000.
  • Option values must be positive integers.
  • rounds, iterations, memory_kib, and parallelism are each bounded by an upper limit set several orders of magnitude above current OWASP/RFC 9106 recommendations. Values within realistic security guidance are always accepted; pathological values are rejected to protect server resources.
  • Do not combine rounds with Argon2 options (iterations, memory_kib, parallelism).
  • If no options are provided, Radiator uses the algorithm defaults.

The same Argon2 limits apply when verifying a stored {argon2} hash: a hash whose embedded cost parameters exceed the limits is rejected as if the password were incorrect. This protects authentication paths from DoS via attacker-supplied or corrupted hash strings.

Supported Algorithms

Radiator supports the following password hashing algorithms:

AlgorithmPrefixSecurity LevelUse Case
Argon2{argon2}HighestStrongest GPU/ASIC resistance; needs the CPU and memory budget to match
PBKDF2-SHA512{pbkdf2-sha512}HighFIPS 140-approved KDF; LDAP/RFC 2307bis interoperability
PBKDF2-SHA256{pbkdf2-sha256}HighFIPS 140-approved KDF; LDAP/RFC 2307bis interoperability
PBKDF2-SHA1{pbkdf2-sha1} or {pbkdf2}MediumLegacy LDAP/Dovecot stores (use SHA-256/512 for new data)
Crypt SHA-512{crypt-sha512}MediumLegacy systems, Linux/Unix compatibility
Crypt SHA-256{crypt-sha256}MediumLegacy systems, Linux/Unix compatibility
NT Hash{nthash}LowWindows compatibility (not recommended for new systems)
Plaintext(no prefix)NoneRequired for protocols that need the cleartext password (CHAP, MS-CHAP/MS-CHAPv2, EAP-MD5); development/testing

Prefix matching is case-insensitive, so LDAP RFC 2307bis style values like {PBKDF2-SHA512} work alongside the lowercase {pbkdf2-sha512} form.

Argon2 (Highest security)

Argon2 offers the strongest resistance against brute-force attacks among the supported algorithms, including GPU- and ASIC-based cracking. Radiator uses the Argon2id variant for balanced protection against side-channel and GPU attacks.

Argon2 is memory-hard by design, so each verification allocates the configured memory budget (e.g. 16 MiB at m=16384). Under high authentication volume this becomes the limiting factor: peak concurrent requests times m must fit in the server's RAM budget, and CPU stays busy for the full verification time. For example, 10 concurrent verifications at m=4096 reserve ~40 MB, and at m=16384 ~160 MB. If the deployment cannot guarantee that headroom, choose a lower-memory PBKDF2 variant rather than under-tuning Argon2.

Format:

{argon2}$argon2id$v=19$m=16384,t=2,p=1$<salt>$<hash>

Parameters:

  • m=4096 (4 MiB), m=16384 (16 MiB), or m=32768 (32 MiB) - Memory cost in KiB (specified via -m 12/14/15 where 2^n KiB)
  • t=2 or t=3 - Time cost (number of iterations through memory)
  • p=1 or p=2 - Parallelism (number of parallel threads)
  • Salt and hash are base64-encoded

Recommended settings:

  • Standard: t=2, p=1, m=4096 (4 MiB) - Good balance for most use cases
  • High security: t=2, p=1, m=16384 (16 MiB) - Better protection against attacks
  • Very high security: t=3, p=1, m=16384 (16 MiB) - Excellent protection

See "Performance Considerations" section below for detailed timing benchmarks.

Generate Argon2 hash:

# Standard security (4 MiB)
echo -n "password" | argon2 $(openssl rand -base64 16) -id -t 2 -m 12 -p 1 -l 32 -e

# High security (16 MiB)
echo -n "password" | argon2 $(openssl rand -base64 16) -id -t 2 -m 14 -p 1 -l 32 -e

Example:

{argon2}$argon2id$v=19$m=16384,t=2,p=1$ZTM0ODY1YTUxZTQ1ZWFiNQ$MAz1wx2FHcKDw6vYVVUKTwR+Sc240NzMAQxjbtRhDbY

PBKDF2 (SHA-512 / SHA-256 / SHA-1)

PBKDF2-HMAC is the password hashing function specified in RFC 2898. Radiator supports the SHA-512, SHA-256 and SHA-1 variants. PBKDF2 is not memory-hard, so each verification needs only a few hundred bytes of working memory regardless of iteration count. This makes it well suited to high-volume authentication servers where Argon2's per-request memory budget would not fit.

When to choose PBKDF2:

  • High-volume / memory-constrained deployments. PBKDF2 scales to thousands of concurrent verifications without the multi-MiB-per-request RAM cost of Argon2.
  • FIPS 140 / NIST SP 800-132 compliance. PBKDF2 is an approved key derivation function under FIPS 140-3 and is recommended by NIST SP 800-132 for password-based key derivation; Argon2 is not (yet) on the FIPS-approved list.
  • OWASP Password Storage Cheat Sheet lists PBKDF2 as an acceptable second choice after Argon2id, particularly for FIPS-validated environments.
  • Interoperability with existing identity stores that emit {PBKDF2-SHAxxx} or {PBKDF2} hashes (OpenLDAP, 389-ds, Dovecot, Django, Synology DSM, ...).

For green-field deployments with the CPU and memory headroom to absorb Argon2's per-request cost, prefer Argon2id. Otherwise PBKDF2-HMAC-SHA512 is the next-strongest option in Radiator.

Formats accepted on input:

  • PHC string (the standard portable format for PBKDF2-SHA256 / PBKDF2-SHA512):

    {pbkdf2-sha512}$pbkdf2-sha512$i=210000,l=64$<b64-salt>$<b64-hash>
    {pbkdf2-sha256}$pbkdf2-sha256$i=600000,l=32$<b64-salt>$<b64-hash>
    
  • LDAP RFC 2307bis layout (also commonly used for PBKDF2-SHA1, which has no PHC identifier):

    {pbkdf2-sha512}<iterations>$<b64-salt>$<b64-hash>
    {pbkdf2-sha256}<iterations>$<b64-salt>$<b64-hash>
    {pbkdf2-sha1}<iterations>$<b64-salt>$<b64-hash>
    {pbkdf2}<iterations>$<b64-salt>$<b64-hash>          # alias for PBKDF2-SHA1
    

Both standard and unpadded base64 encodings are accepted. The iteration count and salt embedded in the stored value are always honoured during verification, so hashes generated against older defaults keep working.

When generating new PBKDF2 hashes for Radiator, follow the OWASP Password Storage Cheat Sheet defaults: 1 300 000 iterations for SHA-1, 600 000 for SHA-256 and 210 000 for SHA-512, with at least a 16-byte CSPRNG salt. Hashes can be produced by the identity store (LDAP, application database, password manager, ...) or generated inside a Radiator pipeline with password_hash(...).

Example:

{pbkdf2-sha512}$pbkdf2-sha512$i=210000,l=64$Z2QuoEKKKa3xJ3OQM/CR6w$Q1qfeq43...
{pbkdf2-sha1}2$c2FsdA==$6mwBTcctb4zNHtkqzh1B8NjeiVc=

Crypt SHA-512

SHA-512 based crypt hashing, commonly used in Linux/Unix systems. Provides reasonable security for legacy applications.

Format:

{crypt-sha512}$6$rounds=5000$<salt>$<hash>

Example:

{crypt-sha512}$6$rounds=5000$saltsaltsal$hash...

Crypt SHA-256

SHA-256 based crypt hashing, similar to SHA-512 but with shorter hash length.

Format:

{crypt-sha256}$5$rounds=5000$<salt>$<hash>

Example:

{crypt-sha256}$5$rounds=5000$saltsaltsal$hash...

NT Hash

NT hash (MD4-based) used in Windows systems. Provided for compatibility but not recommended for new deployments due to weak security.

Format:

{nthash}<hex-encoded-hash>

Plaintext

Passwords without a prefix are treated as plaintext. Plaintext storage is required for authentication protocols where the server cannot verify the credential without knowing the actual cleartext password:

  • CHAP (RFC 1994) - the server must compute MD5(ident || password || challenge) to compare against the client response.
  • MS-CHAP / MS-CHAPv2 - the server must derive the NT hash from the cleartext at verification time (a stored {nthash} is also accepted; see above).
  • EAP-MD5 - same MD5 challenge/response construction as CHAP.
  • Digest authentication variants that hash the cleartext into HA1 per request.

For PAP and any protocol that only needs to compare a presented password against a stored value, prefer a hashed format (Argon2, PBKDF2, crypt-sha512) over plaintext.

Example:

mypassword123

Warning: Never use plaintext passwords in production environments.

Warning: If a plaintext password contains text that looks like a hash prefix (e.g., {argon2}, {crypt-sha256}), Radiator will attempt to parse it as a hashed password, causing authentication to fail. Always use hashed passwords to avoid this ambiguity.

Usage Examples

JSON File Backend

{
  "users": [
    {
      "username": "alice",
      "password": "{argon2}$argon2id$v=19$m=16384,t=2,p=1$..."
    },
    {
      "username": "bob",
      "password": "{crypt-sha512}$6$rounds=5000$..."
    }
  ]
}

SQL Backend

CREATE TABLE users (
    username VARCHAR(255) PRIMARY KEY,
    password TEXT NOT NULL
);

INSERT INTO users (username, password) VALUES
    ('alice', '{argon2}$argon2id$v=19$m=16384,t=2,p=1$...'),
    ('bob', '{crypt-sha256}$5$rounds=5000$...');

Backend Configuration

No special configuration is needed. The password format is detected automatically:

backends {
    sqlite "USERS" {
        filename "users.db";
        query "FIND_USER" {
            statement "SELECT username, password FROM users WHERE username = ?";
            bindings { aaa.identity; }
            mapping {
                user.username = username;
                user.password = password;  # Format auto-detected from prefix
            }
        }
    }
}

Security Recommendations

  1. Pick the strongest algorithm your capacity supports: Argon2id gives the best resistance against modern attacks but is memory-hard; under high authentication volume, prefer PBKDF2-HMAC-SHA512 if the server cannot sustain Argon2's per-request memory and CPU cost
  2. Choose appropriate parameters: Use t=2, p=1, m=4096 (4 MiB) for standard security, or m=16384 (16 MiB) for higher security. See "Performance Considerations" for sizing examples.
  3. Generate unique salts: Always use cryptographically random salts (use openssl rand or equivalent)
  4. Migrate legacy hashes: If using crypt-sha256/512, consider migrating to Argon2, or to PBKDF2-HMAC-SHA512 where interoperability with LDAP-style password stores is required
  5. Never use plaintext: Always hash passwords, even for development databases
  6. Avoid NT Hash: Only use for Windows integration where absolutely required

Performance Considerations

Password hashing is intentionally slow to prevent brute-force attacks. The longer the time to verify, the more resistant to brute-force attacks the hash is. It also costs more CPU time on Radiator server, so it is usually the dominant sizing guideline.

The following figures are example measurements. Measure on the target hardware before choosing production parameters.

AlgorithmParametersCPU per verificationCPUs for 1k TPSComments
Argon2idt=2, p=1, m=16384 (16 MiB)~19 ms~19Higher memory-cost Argon2 setting
Argon2idt=2, p=1, m=32768 (32 MiB)~38 ms~38Higher memory-cost Argon2 setting
PBKDF2-SHA1i=1 300 000 (OWASP default)~133 ms~133Legacy interop; prefer SHA-256/512 for new data
PBKDF2-SHA256i=600 000 (OWASP default)~64 ms~64FIPS 140-approved KDF
PBKDF2-SHA512i=210 000 (OWASP default)~101 ms~101FIPS 140-approved KDF
Crypt SHA-512rounds=5000 (default)~2.1 ms~2Legacy Linux/Unix compatibility
Crypt SHA-256rounds=5000 (default)~0.6 ms<1Legacy Linux/Unix compatibility
NT Hash-~0.05 ms<1Weak security; Windows compatibility only

The "CPUs for 1k TPS" column is cpu_per_verification_ms: a single fully busy core sustains 1000 / cpu_per_verification_ms verifications per second, so 1k TPS needs approximately that many cores. Provision additional headroom for the rest of the request pipeline and traffic bursts.

PBKDF2 cost scales linearly with i. Argon2 cost depends primarily on t and m; increasing m also increases the per-request memory budget. Increasing Argon2 p can change internal parallelism, but it does not guarantee a linear throughput increase for authentication workloads. Pick the slowest hash the available computing budget can absorb at peak load.

Navigation
  • About Radiator software development security

  • Architecture Overview

  • Backend Load Balancing

  • Basic Installation

  • Built-in Environment Variables

  • Byte Size Units

  • Certificate Revocation Lists

  • Comparison Operators

  • Configuration Editor

  • Configuration Import and Export

  • Containers

  • Cron and interval timers

  • Data Types

  • Duration Units

  • Environment Variables

  • Execution Context

  • Execution Pipelines

  • Filters

  • Getting a Radiator License

  • Health check /live and /ready

  • High Availability and Load Balancing

  • High availability identifiers

  • HTTP Basic Authentication

  • Introduction

  • Linux systemd support

  • Local AAA Backends

  • Log storage and formatting

  • Management API privilege levels

  • Namespaces

  • Password Hashing

  • Password Rehashing During Login

  • Probabilistic Sampling

  • Prometheus scraping

  • PROXY Protocol Support

  • Radiator server health and boot up logic

  • Radiator sizing

  • Radiator software releases

  • RadiatorDB

  • RadiatorDB Backup

  • RadiatorDB CLI

  • RadiatorDB Installation

  • RadiatorDB REST API

  • Rate Limiting

  • Rate Limiting Algorithms

  • Reverse Dynamic Authorization

  • Service Level Objective

  • TACACS+ Authentication, Authorization, and Accounting

  • Template Rendering CLI

  • Timestamp Format

  • Timestamps

  • Tools radiator-client

  • TOTP/HOTP Authentication

  • What is Radiator?

  • YubiKey Authentication

  • YubiKey Context Variables