Search documentation of snmpkit

# SnmpKit.SnmpLib.Security.Priv (snmpkit v1.3.17)

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

## Types

auth_key()
ciphertext()
initialization_vector()
plaintext()
priv_key()
priv_params()
priv_protocol()

## Functions

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

Benchmarks the performance of a given privacy protocol.

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

Decrypts ciphertext using the specified privacy protocol.

decrypt_batch(protocol, priv_key, auth_key, encrypted_list)

Decrypts a batch of ciphertexts efficiently.

encrypt(protocol, priv_key, auth_key, plaintext)

Encrypts plaintext using the specified privacy protocol.

encrypt_batch(protocol, priv_key, auth_key, plaintexts)

Encrypts a batch of plaintexts efficiently.

protocol_info(protocol)

Retrieves the specification for a given privacy protocol.

secure_protocol?(protocol)

Checks if a protocol is considered cryptographically secure.

secure_protocols()

Returns a list of cryptographically secure protocols.

supported_protocols()

Returns a list of all supported privacy protocols.

validate_key(protocol, key)

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}