NAME

Crypt::Sodium::XS::ipcrypt - IP address encryption

SYNOPSIS

use Crypt::Sodium::XS;
use Crypt::Sodium::XS::Util qw(sodium_bin2ip sodium_ip2bin);

my $ipcrypt = Crypt::Sodium::XS->ipcrypt;

die "no libsodium ipcrypt support" unless $ipcrypt->available;

my $ip = "172.18.37.43"; # ipv4 or ipv6 address

my $key = $ipcrypt->keygen;

my $encrypted = $ipcrypt->encrypt(sodium_ip2bin($ip), $key);

$ip eq sodium_bin2ip($ipcrypt->decrypt($encrypted, $key)); # true

DESCRIPTION

The ipcrypt API provides efficient, secure encryption of IP addresses (IPv4 and IPv6) for privacy-preserving storage, logging, and analytics.

Unlike truncation (which irreversibly destroys data) or hashing (which prevents decryption), ipcrypt provides reversible encryption with well-defined security properties while maintaining operational utility.

Use cases

Privacy-preserving logs

Encrypt IP addresses in web server access logs, DNS query logs, or application logs while retaining the ability to decrypt when needed.

Rate limiting and abuse detection

Count requests per client, detect brute-force attempts, or implement request throttling using deterministic encryption.

Analytics without exposure

Count unique visitors, analyze geographic traffic patterns, or build user behavior analytics without revealing actual addresses.

Data sharing

Share network data with security researchers, cloud providers, or partner organizations without exposing actual client addresses.

Database storage

Store encrypted IP addresses in databases with indexes on the encrypted values (deterministic mode). Query, group, and sort by client without exposing actual addresses.

CONSTRUCTOR

The constructor is called with the Crypt::Sodium::XS->ipcrypt method.

my $ipcrypt = Crypt::Sodium::XS->ipcrypt;
my $ipcrypt = Crypt::Sodium::XS->ipcrypt(primitive => 'ndx');

Returns a new ipcrypt object.

Implementation detail: the returned object is blessed into Crypt::Sodium::XS::OO::ipcrypt.

ATTRIBUTES

primitive

my $variant = $ipcrypt->primitive;
$ipcrypt->primitive('pfx');

Gets or sets the variant used for all operations by this object. Must be one of the variant names listed in "VARIANTS", including default.

The attribute name primitive is used for consistency with all other modules, even though for ipcrypt these are called variants.

METHODS

available

my $has_ipcrypt = $ipcrypt->available;

Returns true if Crypt::Sodium::XS supports ipcrypt, false otherwise. ipcrypt will only be supported if Crypt::Sodium::XS was built with a new enough (>= 1.0.21) version of libsodium.

primitives

my @variants = $ipcrypt->primitives;
my @variants = Crypt::Sodium::XS::ipcrypt->primitives;

Returns a list of all supported variant names, including default.

Can be called as a class method.

decrypt

my $binip = $ipcrypt->decrypt($encrypted, $key);

$encrypted is the encrypted IP data to decrypt.

$key is the secret key used to encrypt the data. It must be "KEYBYTES" bytes. It may be a Crypt::Sodium::XS::MemVault.

Returns the decrypted IP address as a 16-byte packed value. See "sodium_bin2ip" in Crypt::Sodium::XS::Util for details of this packed value, including how to generate an IP string from it (example above in "SYNOPSIS").

encrypt

my $encrypted = $ipcrypt->encrypt($binip, $key, $tweak);

$binip is an IP address packed as a 16-byte value. See "sodium_ip2bin" in Crypt::Sodium::XS::Util for details of this packed value, including how to generate it from an IP string (example above in "SYNOPSIS").

$key is the secret key used to encrypt the IP. It must be "KEYBYTES" bytes. It may be a Crypt::Sodium::XS::MemVault.

$tweak is optional. It is used in non-deterministic (nd and ndx) variants to ensure the same address encrypts to different outputs. It should be randomly generated and must be "TWEAKBYTES" bytes in size. If not given, it will be generated randomly. For deterministic and prefix-preserving variants, it is ignored. It is unlikely you would ever want to provide this argument explicitly.

Returns the encrypted output, which is "OUTPUTBYTES" in size.

Note that there is no need to keep the tweak value. It is included in the output.

keygen

my $key = $ipcrypt->keygen($flags);

$flags is optional. It is the flags used for the $key Crypt::Sodium::XS::MemVault. See Crypt::Sodium::XS::Protmem.

Returns a Crypt::Sodium::XS::MemVault: a secret key of "ipcrypt_KEYBYTES" bytes.

BYTES

my $plaintext_and_encrypted_size = $ipcrypt->BYTES;

(deterministic and prefix-preserving variants only) Returns the size, in bytes, of both encryption input and output. Defined to be 16.

INPUTBYTES

my $plaintext_size = $ipcrypt->INPUTBYTES;

Returns the size, in bytes, of encryption input. Defined to be 16.

KEYBYTES

my $key_size = $ipcrypt->KEYBYTES;

Returns the size, in bytes, of a secret key.

OUTPUTBYTES

my $output_size = $ipcrypt->OUTPUTBYTES;

Returns the size, in bytes, of encryption output.

TWEAKBYTES

my $tweak_size = $ipcrypt->TWEAKBYTES;

Returns the size, in bytes, of a tweak value. For deterministic and prefix-preserving variants, this is always 0 as they do not use a tweak value.

VARIANTS

ipcrypt provides four variants with different security and format trade-offs. The variant is chosen by the "primitive" attribute. It can be set to one of these four variants by the name listed in parentheses:

default (Deterministic)

* 16 byte key

* 16 byte output

* Same input always produces same output; format-preserving

* Algorithm: Single-block AES-128

nd (Non-Deterministic)

* 16 byte key

* 24 byte output

* Different output each time; 8-byte random tweak

* Algorithm: KIASU-BC (tweakable AES-128 with 64-bit tweak)

ndx (Extended Non-Deterministic)

* 32 byte key

* 32 byte output

* Different output each time; 16-byte random tweak

* Algorithm: AES-XTS (IEEE 1619-2007) with 128-bit tweak

pfx (Prefix-Preserving)

* 32 byte key

* 16 byte output

* Preserves network prefix relationships

* Algorithm: Bit-by-bit format-preserving encryption using XOR of two AES-128 permutations

Choosing the right variant

Use deterministic mode for rate limiting, deduplication, unique visitor counting, database indexing, or anywhere you need to identify the same address across multiple observations. Fastest option. Trade-off: identical inputs produce identical outputs.

Use ND mode when sharing data externally or when preventing correlation across observations matters. Each encryption produces a different ciphertext, so an observer cannot tell if two records came from the same address. Good for log archival, third-party analytics, or data exports.

Use NDX mode for maximum security when you need the non-deterministic property and will perform very large numbers of encryptions (billions) with the same key. The larger tweak space provides a higher birthday bound.

Use PFX mode for network analysis applications: DDoS research, traffic studies, packet trace anonymization, or any scenario where understanding which addresses belong to the same network matters more than hiding that relationship.

All implementations use hardware acceleration when available (AES-NI on x86-64, ARM Crypto extensions on ARM).

FUNCTIONS

The object API above is the recommended way to use this module. The functions and constants documented below can be imported instead (or in addition, though that's unlikely to be necessary).

Nothing is exported by default. A :default tag imports the functions and constants documented below. A :features tag imports the ipcrypt_available feature test function. A separate :<variant> import tag is provided for each of the variants listed in "VARIANTS". These tags import the iprypt_<variant>_* functions and constants for that variant.

ipcrypt_available

my $has_ipcrypt = ipcrypt_available();

Same as "available".

ipcrypt_decrypt

ipcrypt_<variant>_decrypt

my $binip = ipcrypt_decrypt($encrypted, $key);

Same as "decrypt".

ipcrypt_encrypt

ipcrypt_<variant>_encrypt

my $encrypted = ipcrypt_encrypt($binip, $key, $tweak);

Same as "encrypt".

ipcrypt_keygen

ipcrypt_<variant>_keygen

my $key = ipcrypt_keygen($flags);

Same as "keygen".

CONSTANTS

ipcrypt_BYTES

ipcrypt_pfx_BYTES

my $plaintext_and_encrypted_size = ipcrypt_BYTES();

Same as "BYTES".

ipcrypt_INPUTBYTES

ipcrypt_<variant>_INPUTBYTES

my $plaintext_size = ipcrypt_INPUTBYTES();

Same as "INPUTBYTES".

ipcrypt_KEYBYTES

ipcrypt_<variant>_KEYBYTES

my $key_size = ipcrypt_KEYBYTES();

Same as "KEYBYTES".

ipcrypt_OUTPUTBYTES

ipcrypt_<variant>_OUTPUTBYTES

my $output_size = ipcrypt_OUTPUTBYTES();

Same as "OUTPUTBYTES".

ipcrypt_TWEAKBYTES

ipcrypt_<variant>_TWEAKBYTES

my $tweak_size = ipcrypt_TWEAKBYTES();

Same as "TWEAKBYTES".

Security considerations

What ipcrypt protects against

* Unauthorized parties learning original addresses without the key

* Statistical analysis revealing traffic patterns (non-deterministic modes)

* Brute-force attacks on the address space (128-bit AES security)

What ipcrypt does not protect against

* Active attackers modifying, reordering, or removing encrypted addresses

* Correlation of identical addresses (deterministic mode)

* Traffic analysis based on volume and timing metadata

Key management

* Generate keys using "ipcrypt_keygen".

* Never reuse keys across different variants; use Crypt::Sodium::XS::hkdf to derive separate keys if needed

* Rotate keys based on usage volume and security requirements

Tweak generation (ND/NDX modes)

* Tweaks can be randomly generated using "sodium_random_bytes" in Crypt::Sodium::XS::Util.

SEE ALSO

Crypt::Sodium::XS
https://doc.libsodium.org/doc/secret-key_cryptography/ip_address_encryption
https://ipcrypt-std.github.io/
https://datatracker.ietf.org/doc/draft-denis-ipcrypt/

FEEDBACK

For reporting bugs, giving feedback, submitting patches, etc. please use the following:

AUTHOR

Brad Barden <perlmodules@5c30.org>

COPYRIGHT & LICENSE

Copyright (c) 2026 Brad Barden. All rights reserved.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.