ExkPasswd.Entropy (ExkPasswd v0.1.1)

View Source

Password entropy calculation and strength analysis.

This module provides comprehensive entropy metrics to assess password strength from two perspectives:

  • Blind Entropy: Assumes attacker uses brute force with no knowledge of how the password was generated. Based on character set size and length.

  • Seen Entropy: Assumes attacker knows the dictionary and configuration used. Based on the actual number of possible password combinations.

Security Model

Password strength comes from entropy (number of possible combinations) and cryptographically secure randomness, not from keeping the generation method secret.

Entropy Thresholds

Based on NIST and OWASP guidelines:

  • < 40 bits: Weak - DO NOT USE (crackable in minutes/hours)
  • 40-52 bits: Fair - Minimal acceptable (crackable in days/months)
  • 52-78 bits: Good - Recommended for most uses (years to centuries)
  • 78+ bits: Excellent - High security (millennia+)

Examples

iex> config = ExkPasswd.Config.new!(num_words: 3)
...> password = ExkPasswd.generate(config)
...> result = ExkPasswd.Entropy.calculate(password, config)
...> result.blind > 40
true
iex> result.seen > 50
true

iex> ExkPasswd.Entropy.calculate_seen(ExkPasswd.Config.new!(num_words: 6))
...> # Returns entropy in bits (float)

Summary

Functions

Calculate comprehensive entropy metrics for a password and settings.

Calculate blind entropy from a password string.

Calculate seen entropy from settings.

Calculate seen entropy with detailed breakdown of entropy sources.

Determine strength status based on entropy values.

Calculate effective entropy from blind and seen values.

Estimate time to crack password based on entropy.

Types

entropy_result()

@type entropy_result() :: %{
  blind: float(),
  seen: float(),
  status: :excellent | :good | :fair | :weak,
  blind_crack_time: String.t(),
  seen_crack_time: String.t(),
  details: map()
}

Functions

calculate(password, settings)

@spec calculate(String.t(), ExkPasswd.Config.t()) :: entropy_result()

Calculate comprehensive entropy metrics for a password and settings.

Returns detailed entropy analysis including both blind and seen entropy, strength status, crack time estimates, and breakdown of entropy sources.

Parameters

  • password - The generated password string
  • config - The Config struct used to generate the password

Returns

A map containing:

  • :blind - Blind entropy in bits (float)
  • :seen - Seen entropy in bits (float)
  • :status - Overall strength (:excellent, :good, :fair, :weak)
  • :blind_crack_time - Human-readable crack time estimate for blind attack
  • :seen_crack_time - Human-readable crack time estimate for seen attack
  • :details - Breakdown of entropy components

Examples

iex> config = ExkPasswd.Config.new!(num_words: 4)
...> password = "12-HAPPY-forest-DANCE-bird-56"
...> result = ExkPasswd.Entropy.calculate(password, config)
...> is_float(result.blind) and is_float(result.seen)
true

calculate_blind(password)

@spec calculate_blind(String.t()) :: float()

Calculate blind entropy from a password string.

Analyzes the actual password to determine alphabet size (character types used) and calculates entropy based on brute-force attack assumptions.

Formula: Eb = log₂(A^L)

  • A = alphabet size (number of unique character types)
  • L = password length

Parameters

  • password - The password string to analyze

Returns

Entropy in bits (float)

Examples

iex> ExkPasswd.Entropy.calculate_blind("aB3!")
...> # ~26.3 bits for 4-char with mixed types

iex> blind = ExkPasswd.Entropy.calculate_blind("correcthorsebatterystaple")
...> blind > 100
true

calculate_seen(settings)

@spec calculate_seen(ExkPasswd.Config.t()) :: float()

Calculate seen entropy from settings.

Calculates entropy assuming attacker knows the dictionary and configuration. This is the "true" entropy based on the number of possible combinations.

Parameters

  • config - The Config struct

Returns

Entropy in bits (float)

Examples

iex> config = ExkPasswd.Config.new!(num_words: 3)
...> seen = ExkPasswd.Entropy.calculate_seen(config)
...> seen > 40
true

calculate_seen_detailed(settings)

@spec calculate_seen_detailed(ExkPasswd.Config.t()) :: map()

Calculate seen entropy with detailed breakdown of entropy sources.

Returns a map showing how each component contributes to total entropy.

Parameters

  • config - The Config struct

Returns

Map with entropy breakdown and total

Examples

iex> config = ExkPasswd.Config.new!(num_words: 3)
...> result = ExkPasswd.Entropy.calculate_seen_detailed(config)
...> is_float(result.total)
true

determine_status(blind, seen)

@spec determine_status(float(), float()) :: :excellent | :good | :fair | :weak

Determine strength status based on entropy values.

Parameters

  • blind - Blind entropy in bits
  • seen - Seen entropy in bits

Returns

Status atom: :excellent, :good, :fair, or :weak

Examples

iex> ExkPasswd.Entropy.determine_status(80, 80)
:excellent

iex> ExkPasswd.Entropy.determine_status(60, 55)
:good

effective_entropy(blind, seen)

@spec effective_entropy(float(), float()) :: float()

Calculate effective entropy from blind and seen values.

Uses the lower of the two as the limiting factor for security assessment.

Parameters

  • blind - Blind entropy in bits
  • seen - Seen entropy in bits

Returns

Effective entropy in bits (float)

Examples

iex> ExkPasswd.Entropy.effective_entropy(80.0, 65.0)
65.0

iex> ExkPasswd.Entropy.effective_entropy(50.0, 70.0)
50.0

estimate_crack_time(entropy_bits)

@spec estimate_crack_time(float()) :: String.t()

Estimate time to crack password based on entropy.

Assumes 1 billion guesses per second (modern GPU capability).

Parameters

  • entropy_bits - Entropy in bits

Returns

Human-readable time estimate string

Examples

iex> time = ExkPasswd.Entropy.estimate_crack_time(40)
...> String.contains?(time, "minute") or String.contains?(time, "second")
true

iex> time = ExkPasswd.Entropy.estimate_crack_time(80)
...> String.contains?(time, "year") or String.contains?(time, "centur")
true