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:
RT queue at https://rt.cpan.org/Dist/Display.html?Name=Crypt-Sodium-XS
IRC channel
#sodiumonirc.perl.org.Email the author directly.
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.