SnmpKit.SnmpLib.Security.Priv (snmpkit v0.6.4)

Implements SNMPv3 privacy protocols for message encryption and decryption.

This module provides support for standard SNMPv3 privacy protocols like DES and AES, ensuring data confidentiality in SNMP communications.

Supported Protocols

  • :none - No privacy
  • :des - DES-CBC (56-bit)
  • :aes128 - AES-CFB128 (128-bit)
  • :aes192 - AES-CFB128 (192-bit)
  • :aes256 - AES-CFB128 (256-bit)

Security Considerations

  • DES is considered weak and should only be used for compatibility with legacy devices.
  • AES protocols are recommended for strong encryption.
  • Keys should be derived securely using the functions in SnmpKit.SnmpLib.Security.Keys.

Protocol Selection Guidelines

  • For new deployments, prefer :aes256 for the strongest security.
  • Use :aes128 for a balance of performance and security.
  • Use :des only when required for interoperability.

Technical Details

This module implements the privacy aspects of the User-Based Security Model (USM) as defined in RFC 3414 and RFC 3826.

Key Derivation

Privacy keys are derived from the user's password and the authoritative SNMP engine's ID. This process is handled by the Keys module.

Initialization Vectors

For CBC and CFB modes, a unique Initialization Vector (IV) is required for each encryption operation. This IV is generated and included in the privParameters field of the SNMPv3 message.

Padding

The plaintext data is padded to match the block size of the cipher before encryption. This padding is removed upon decryption.

Usage Examples

This module is typically used internally by the USM module.

Message Encryption

# Assuming keys are derived and user is configured
priv_key = derived_privacy_key
auth_key = derived_authentication_key  # Required for IV generation
plaintext = "confidential SNMP data"

{:ok, {ciphertext, priv_params}} = SnmpKit.SnmpLib.Security.Priv.encrypt(
  :aes256, priv_key, auth_key, plaintext
)

# Decrypt message
{:ok, decrypted} = SnmpKit.SnmpLib.Security.Priv.decrypt(
  :aes256, priv_key, auth_key, ciphertext, priv_params
)
assert decrypted == plaintext

Protocol Information

iex> SnmpKit.SnmpLib.Security.Priv.protocol_info(:aes128)
%{algorithm: :aes_128_cfb128, key_size: 16, iv_size: 16, block_size: 16}

Summary

Functions

Benchmarks the performance of a given privacy protocol.

Decrypts ciphertext using the specified privacy protocol.

Decrypts a batch of ciphertexts efficiently.

Encrypts plaintext using the specified privacy protocol.

Encrypts a batch of plaintexts efficiently.

Retrieves the specification for a given privacy protocol.

Checks if a protocol is considered cryptographically secure.

Returns a list of cryptographically secure protocols.

Returns a list of all supported privacy protocols.

Validates if a privacy key is compliant with the protocol's requirements.

Types

auth_key()

@type auth_key() :: binary()

ciphertext()

@type ciphertext() :: binary()

initialization_vector()

@type initialization_vector() :: binary()

plaintext()

@type plaintext() :: binary()

priv_key()

@type priv_key() :: binary()

priv_params()

@type priv_params() :: binary()

priv_protocol()

@type priv_protocol() :: :none | :des | :aes128 | :aes192 | :aes256

Functions

benchmark_protocol(protocol, priv_key, auth_key, test_plaintext, iterations \\ 1000)

@spec benchmark_protocol(
  priv_protocol(),
  priv_key(),
  auth_key(),
  plaintext(),
  non_neg_integer()
) :: %{encrypt_us: float(), decrypt_us: float(), ops_per_sec: float()}

Benchmarks the performance of a given privacy protocol.

decrypt(protocol, priv_key, auth_key, ciphertext, priv_params)

@spec decrypt(priv_protocol(), priv_key(), auth_key(), ciphertext(), priv_params()) ::
  {:ok, plaintext()} | {:error, atom()}

Decrypts ciphertext using the specified privacy protocol.

Parameters

  • protocol: Privacy protocol used for encryption
  • priv_key: Privacy key (same as used for encryption)
  • auth_key: Authentication key (used for IV validation)
  • ciphertext: Encrypted data
  • priv_params: Privacy parameters from encryption (contains IV)

Returns

  • {:ok, plaintext}: Decryption successful
  • {:error, reason}: Decryption failed

Examples

# AES-256 decryption
{:ok, plaintext} = SnmpKit.SnmpLib.Security.Priv.decrypt(
  :aes256, priv_key, auth_key, ciphertext, priv_params
)

# Handle decryption errors
case SnmpKit.SnmpLib.Security.Priv.decrypt(:des, priv_key, auth_key, ciphertext, priv_params) do
  {:ok, plaintext} -> process_plaintext(plaintext)
  {:error, :decryption_failed} -> handle_corruption()
  {:error, :invalid_padding} -> handle_padding_error()
end

decrypt_batch(protocol, priv_key, auth_key, encrypted_list)

@spec decrypt_batch(
  priv_protocol(),
  priv_key(),
  auth_key(),
  [{ciphertext(), priv_params()}]
) :: [ok: plaintext(), error: atom()]

Decrypts a batch of ciphertexts efficiently.

encrypt(protocol, priv_key, auth_key, plaintext)

@spec encrypt(priv_protocol(), priv_key(), auth_key(), plaintext()) ::
  {:ok, {ciphertext(), priv_params()}} | {:error, atom()}

Encrypts plaintext using the specified privacy protocol.

Parameters

  • protocol: Privacy protocol to use
  • priv_key: Privacy key for the chosen protocol
  • auth_key: Authentication key (used for IV generation)
  • plaintext: Data to encrypt

Returns

  • {:ok, {ciphertext, priv_params}}: Encryption successful
  • {:error, reason}: Encryption failed

Examples

# AES-128 encryption
{:ok, {ciphertext, priv_params}} = SnmpKit.SnmpLib.Security.Priv.encrypt(
  :aes128, priv_key, auth_key, "secret data"
)

encrypt_batch(protocol, priv_key, auth_key, plaintexts)

@spec encrypt_batch(priv_protocol(), priv_key(), auth_key(), [plaintext()]) ::
  {:ok, [{ciphertext(), priv_params()}]} | {:error, atom()}

Encrypts a batch of plaintexts efficiently.

Examples

iex> plaintexts = ["msg1", "msg2"]
iex> {:ok, encrypted_list} = Priv.encrypt_batch(:aes128, priv_key, auth_key, plaintexts)
iex> length(encrypted_list)
2

protocol_info(protocol)

@spec protocol_info(priv_protocol()) :: map() | nil

Retrieves the specification for a given privacy protocol.

Returns a map with :algorithm, :key_size, :iv_size, and :block_size, or nil if the protocol is unsupported.

Examples

iex> Priv.protocol_info(:aes128)
%{algorithm: :aes_128_cfb128, key_size: 16, iv_size: 16, block_size: 16}

iex> Priv.protocol_info(:unsupported)
nil

secure_protocol?(protocol)

@spec secure_protocol?(priv_protocol()) :: boolean()

Checks if a protocol is considered cryptographically secure.

secure_protocols()

@spec secure_protocols() :: [priv_protocol()]

Returns a list of cryptographically secure protocols.

supported_protocols()

@spec supported_protocols() :: [priv_protocol()]

Returns a list of all supported privacy protocols.

validate_key(protocol, key)

@spec validate_key(priv_protocol(), priv_key()) :: :ok | {:error, atom()}

Validates if a privacy key is compliant with the protocol's requirements.

Examples

iex> Priv.validate_key(:aes128, :crypto.strong_rand_bytes(16))
:ok
iex> Priv.validate_key(:des, <<1, 2, 3>>)
{:error, :invalid_key_size}