ExkPasswd (ExkPasswd v0.1.1)

View Source

ExkPasswd is a highly optimized password generation and analysis library for Elixir.

This library provides secure, customizable password generation based on the XKPasswd concept - creating memorable yet strong passwords by combining random words with numbers, symbols, and various transformations.

Quick Start

# Generate a password with default settings
ExkPasswd.generate()
#=> "28?heavy?SOUND?later?94"

# Use a preset
ExkPasswd.generate(:xkcd)
#=> "correct-horse-battery-staple-amazing"

# Custom configuration using keyword list
ExkPasswd.generate(num_words: 4, separator: "-")
#=> "12-Happy-Forest-Dance-56"

# Custom configuration using Config struct
config = ExkPasswd.Config.new!(
  num_words: 4,
  separator: "-",
  case_transform: :capitalize
)
ExkPasswd.generate(config)
#=> "12-Happy-Forest-Dance-56"

# Analyze password strength
password = ExkPasswd.generate()
ExkPasswd.analyze_strength(password, ExkPasswd.Config.new!())
#=> %{rating: :good, entropy_bits: 59.2, ...}

# Generate multiple passwords in batch
ExkPasswd.generate_batch(100)
#=> ["password1", "password2", ...]

Features

  • Efficient generation: Constant-time word selection using tuple indexing
  • Entropy calculation: Security analysis with blind and seen entropy metrics
  • Character substitutions: Leetspeak-style transformations for added complexity
  • Custom dictionaries: Load your own word lists for any language or domain
  • Batch generation: Optimized for generating multiple passwords
  • Strength analysis: Password feedback and improvement suggestions
  • Extensibility: Transform protocol for custom password transformations
  • Zero dependencies: Only uses Elixir stdlib and :crypto

Performance

  • Tuple-based lookups: Constant-time word selection
  • Cached transformations: Pre-computed case variants
  • Buffered random generation: Reduced syscalls for batch operations

Available Presets

  • :default - Balanced security and memorability (~59 bits entropy)
  • :web32 - For websites allowing up to 32 characters (~65 bits)
  • :web16 - For websites with 16 character limit (~42 bits - ⚠️ low security)
  • :wifi - 63 character WPA2 keys (~85 bits)
  • :apple_id - Meets Apple ID requirements (~55 bits)
  • :security - For security questions (~77 bits)
  • :xkcd - Similar to the famous XKCD comic (~65 bits)

See ExkPasswd.Config.Presets for more details on each preset.

Extensibility

Custom transforms can be added using the Transform protocol.

Example: Japanese Romaji Transform for cross-keyboard compatibility:

defmodule MyApp.RomajiTransform do
  @moduledoc """
  Converts Japanese hiragana/katakana to romaji for keyboard portability.

  Enables passwords created on Japanese keyboard layouts to be typed on
  English QWERTY keyboards (e.g., international travel, shared workstations).
  """
  defstruct [:mode]

  @hiragana_to_romaji %{
    "あ" => "a", "い" => "i", "う" => "u", "さ" => "sa", "き" => "ki"
  }

  defimpl ExkPasswd.Transform do
    def apply(%{mode: _mode}, word, _config) do
      @hiragana_to_romaji
      |> Enum.reduce(word, fn {japanese, romaji}, acc ->
        String.replace(acc, japanese, romaji)
      end)
    end

    def entropy_bits(%{mode: _mode}, _config), do: 0.0
  end
end

# Use with Japanese dictionary
ExkPasswd.Dictionary.load_custom(:japanese, ["さくら", "やま", "うみ"])

config = ExkPasswd.Config.new!(
  num_words: 2,
  dictionary: :japanese,
  meta: %{
    transforms: [%MyApp.RomajiTransform{mode: :hiragana}]
  }
)

ExkPasswd.generate(config)
#=> "45-sakura-yama-89"  # Typeable on any keyboard

Summary

Functions

Analyze password strength with user-friendly feedback.

Calculate entropy metrics for a password and config.

Generate a password using default settings.

Generate a password using a preset, keyword options, or a Config struct.

Generate a password from a preset with overrides.

Generate multiple passwords in batch with optimized performance.

Generate passwords in parallel using multiple processes.

Generate unique passwords in batch.

Quick strength rating check.

Returns the current version of ExkPasswd.

Functions

analyze_strength(password, config)

@spec analyze_strength(String.t(), ExkPasswd.Config.t()) :: map()

Analyze password strength with user-friendly feedback.

Returns a map with rating, score, and entropy bits.

Parameters

  • password - Password to analyze
  • config - Config used to generate it

Examples

password = ExkPasswd.generate()
config = ExkPasswd.Config.new!()
ExkPasswd.analyze_strength(password, config)
#=> %{rating: :good, score: 59, entropy_bits: 59.2}

calculate_entropy(password, config)

@spec calculate_entropy(String.t(), ExkPasswd.Config.t()) :: map()

Calculate entropy metrics for a password and config.

Returns detailed entropy analysis including both blind entropy (brute force) and seen entropy (attacker knows dictionary/config).

Parameters

  • password - The password to analyze
  • config - Config used to generate it

Examples

password = ExkPasswd.generate()
config = ExkPasswd.Config.new!()
ExkPasswd.calculate_entropy(password, config)
#=> %{blind: 49.2, seen: 59.1, status: :good, ...}

generate()

@spec generate() :: String.t()

Generate a password using default settings.

This is equivalent to calling generate(:default).

Examples

ExkPasswd.generate()
#=> "28?heavy?SOUND?later?94"

generate(preset)

@spec generate(atom() | keyword() | ExkPasswd.Config.t()) :: String.t()

Generate a password using a preset, keyword options, or a Config struct.

Examples

# With a preset atom
ExkPasswd.generate(:xkcd)
#=> "correct-horse-battery-staple-amazing"

# With keyword list
ExkPasswd.generate(num_words: 4, separator: "-")
#=> "word-word-word-word"

# With Config struct
config = Config.new!(num_words: 2, separator: "_")
ExkPasswd.generate(config)
#=> "45_HAPPY_forest_23"

generate(preset, overrides)

@spec generate(
  atom(),
  keyword()
) :: String.t()

Generate a password from a preset with overrides.

Examples

# Extend preset with overrides
ExkPasswd.generate(:xkcd, num_words: 6)
#=> "word-word-word-word-word-word"

ExkPasswd.generate(:default, separator: "_", num_words: 5)
#=> "12_word_WORD_word_WORD_89"

generate_batch(count, config \\ Config.new!())

@spec generate_batch(pos_integer(), ExkPasswd.Config.t()) :: [String.t()]

Generate multiple passwords in batch with optimized performance.

For generating 100+ passwords, this is approximately 30% faster than calling generate/1 multiple times due to reduced cryptographic overhead.

Parameters

  • count - Number of passwords to generate
  • config - Config to use (default: default preset)

Examples

ExkPasswd.generate_batch(10)
#=> ["password1", "password2", ...]

config = ExkPasswd.Config.new!(num_words: 4)
ExkPasswd.generate_batch(5, config)
#=> ["word-word-word-word", ...]

generate_parallel(count, config \\ Config.new!())

@spec generate_parallel(pos_integer(), ExkPasswd.Config.t()) :: [String.t()]

Generate passwords in parallel using multiple processes.

Best for very large batches (1000+) on multi-core systems.

Parameters

  • count - Number of passwords
  • config - Config to use (default: default preset)

Examples

ExkPasswd.generate_parallel(1000)
#=> [... 1000 passwords ...]

generate_unique_batch(count, config \\ Config.new!())

@spec generate_unique_batch(pos_integer(), ExkPasswd.Config.t()) :: [String.t()]

Generate unique passwords in batch.

Ensures all returned passwords are unique by regenerating duplicates.

Parameters

  • count - Number of unique passwords
  • config - Config to use (default: default preset)

Examples

passwords = ExkPasswd.generate_unique_batch(10)
length(Enum.uniq(passwords)) == 10
#=> true

strength_rating(password, config)

@spec strength_rating(String.t(), ExkPasswd.Config.t()) :: ExkPasswd.Strength.rating()

Quick strength rating check.

Returns just the rating without full analysis.

Parameters

  • password - Password to check
  • config - Config used

Returns

One of: :excellent, :good, :fair, :weak

Examples

password = ExkPasswd.generate()
config = ExkPasswd.Config.new!()
ExkPasswd.strength_rating(password, config)
#=> :good

version()

@spec version() :: String.t()

Returns the current version of ExkPasswd.

Examples

iex> ExkPasswd.version() =~ ~r/^\d+\.\d+\.\d+/
true