SnmpKit.SnmpLib.Security.Keys (snmpkit v0.6.6)
Key derivation and management for SNMPv3 User Security Model.
Implements RFC 3414 compliant key derivation functions for converting user passwords into cryptographic keys suitable for authentication and privacy operations.
Key Derivation Process
SNMPv3 uses a two-step key derivation process:
- Password Localization: Transform user password into a localized key using the authoritative engine ID
- Key Expansion: Derive authentication and privacy keys from the localized key based on protocol requirements
Security Properties
- Keys are derived deterministically from passwords and engine IDs
- Different engine IDs produce different keys for the same password
- Key derivation uses cryptographic hash functions for security
- Derived keys cannot be used to recover original passwords
- Each protocol type (auth/priv) uses different key derivation parameters
Supported Algorithms
Authentication Key Derivation
- MD5: RFC 3414 compliant (deprecated)
- SHA-1: RFC 3414 compliant (deprecated)
- SHA-224: RFC 7860 compliant
- SHA-256: RFC 7860 compliant (recommended)
- SHA-384: RFC 7860 compliant
- SHA-512: RFC 7860 compliant
Privacy Key Derivation
- DES: 8-byte keys from authentication keys
- AES-128: 16-byte keys with salt mixing
- AES-192: 24-byte keys with salt mixing
- AES-256: 32-byte keys with salt mixing
Usage Examples
Authentication Key Derivation
# Derive SHA-256 authentication key
engine_id = <<0x80, 0x00, 0x1f, 0x88, 0x80, 0x01, 0x02, 0x03, 0x04>>
password = "authentication_password"
{:ok, auth_key} = SnmpKit.SnmpLib.Security.Keys.derive_auth_key(:sha256, password, engine_id)
Privacy Key Derivation
# Derive AES-256 privacy key
{:ok, priv_key} = SnmpKit.SnmpLib.Security.Keys.derive_priv_key(:aes256, password, engine_id)
# Or derive from existing authentication key
{:ok, priv_key} = SnmpKit.SnmpLib.Security.Keys.derive_priv_key_from_auth(:aes256, auth_key, engine_id)
Key Validation
# Validate key strength
:ok = SnmpKit.SnmpLib.Security.Keys.validate_password_strength(password)
{:error, :too_short} = SnmpKit.SnmpLib.Security.Keys.validate_password_strength("weak")
Summary
Functions
Derives authentication key from password and engine ID.
Derives multiple authentication keys for different protocols from the same password.
Derives privacy key from password and engine ID.
Derives privacy key from an existing authentication key.
Exports derived key in a secure format for storage or transmission.
Generates a cryptographically secure random password.
Securely compares two derived keys to prevent timing attacks.
Securely wipes sensitive key material from memory.
Validates imported key against expected parameters.
Validates password strength according to SNMPv3 security guidelines.
Types
Functions
@spec derive_auth_key(auth_protocol(), password(), engine_id()) :: {:ok, derived_key()} | {:error, atom()}
Derives authentication key from password and engine ID.
Implements RFC 3414 key localization algorithm for authentication protocols. The derived key is specific to the combination of password, protocol, and engine ID.
Parameters
protocol
: Authentication protocol (:md5, :sha1, :sha256, etc.)password
: User password (minimum 8 characters recommended)engine_id
: Authoritative engine ID (5-32 bytes)
Returns
{:ok, key}
: Successfully derived authentication key{:error, reason}
: Key derivation failed
Examples
# SHA-256 authentication key (recommended)
{:ok, key} = SnmpKit.SnmpLib.Security.Keys.derive_auth_key(
:sha256, "my_secure_password", engine_id
)
# Legacy MD5 key derivation
{:ok, key} = SnmpKit.SnmpLib.Security.Keys.derive_auth_key(
:md5, "legacy_password", engine_id
)
@spec derive_auth_keys_multi([auth_protocol()], password(), engine_id()) :: {:ok, %{required(auth_protocol()) => derived_key()}} | {:error, atom()}
Derives multiple authentication keys for different protocols from the same password.
Useful when supporting multiple authentication protocols simultaneously.
Examples
protocols = [:sha256, :sha384, :sha512]
{:ok, keys} = SnmpKit.SnmpLib.Security.Keys.derive_auth_keys_multi(protocols, password, engine_id)
# Returns: %{sha256: key1, sha384: key2, sha512: key3}
@spec derive_priv_key(priv_protocol(), password(), engine_id()) :: {:ok, derived_key()} | {:error, atom()}
Derives privacy key from password and engine ID.
Privacy keys are derived using a combination of authentication key derivation and protocol-specific key expansion techniques.
Parameters
protocol
: Privacy protocol (:des, :aes128, :aes192, :aes256)password
: User password for privacyengine_id
: Authoritative engine ID
Returns
{:ok, key}
: Successfully derived privacy key{:error, reason}
: Key derivation failed
Examples
# AES-256 privacy key (recommended)
{:ok, key} = SnmpKit.SnmpLib.Security.Keys.derive_priv_key(
:aes256, "privacy_password", engine_id
)
# DES privacy key (legacy)
{:ok, key} = SnmpKit.SnmpLib.Security.Keys.derive_priv_key(
:des, "legacy_privacy_password", engine_id
)
@spec derive_priv_key_from_auth(priv_protocol(), derived_key(), engine_id()) :: {:ok, derived_key()} | {:error, atom()}
Derives privacy key from an existing authentication key.
More efficient when both authentication and privacy keys are needed, as it avoids repeating the expensive key localization process.
Examples
# First derive authentication key
{:ok, auth_key} = derive_auth_key(:sha256, password, engine_id)
# Then derive privacy key from auth key
{:ok, priv_key} = SnmpKit.SnmpLib.Security.Keys.derive_priv_key_from_auth(
:aes256, auth_key, engine_id
)
@spec export_key(derived_key(), auth_protocol() | priv_protocol(), engine_id()) :: map()
Exports derived key in a secure format for storage or transmission.
The exported format includes metadata for proper key reconstruction while maintaining security properties.
@spec generate_secure_password(pos_integer()) :: password()
Generates a cryptographically secure random password.
Examples
password = SnmpKit.SnmpLib.Security.Keys.generate_secure_password(16)
# Returns: "K7mN9pQ2rT8vW3xZ" (example)
@spec secure_compare(derived_key(), derived_key()) :: boolean()
Securely compares two derived keys to prevent timing attacks.
Examples
true = SnmpKit.SnmpLib.Security.Keys.secure_compare(key1, key1)
false = SnmpKit.SnmpLib.Security.Keys.secure_compare(key1, key2)
@spec secure_wipe(derived_key()) :: :ok
Securely wipes sensitive key material from memory.
Note: This provides best-effort memory clearing but cannot guarantee complete removal due to Erlang VM memory management.
@spec validate_imported_key(derived_key(), map()) :: :ok | {:error, atom()}
Validates imported key against expected parameters.
Validates password strength according to SNMPv3 security guidelines.
Requirements
- Minimum 8 characters (RFC recommendation)
- Should contain mix of character types for security
- Should not be based on dictionary words
Examples
:ok = SnmpKit.SnmpLib.Security.Keys.validate_password_strength("strong_password_123")
{:error, :too_short} = SnmpKit.SnmpLib.Security.Keys.validate_password_strength("weak")
{:warning, :weak_complexity} = SnmpKit.SnmpLib.Security.Keys.validate_password_strength("password")