Crypt::Mode::XTS(3)
π Crypt::Mode::XTS β the perl manpage, but make it group chat
okay so bestie, the module you're looking at is Crypt::Mode::XTS, which lives in the User Contributed Perl Documentation section (section 3, iykyk). It's the XEX-based tweaked-codebook mode with ciphertext stealing β say that five times fast, or don't, honestly nobody does. π
β¨ NAME β¨
Crypt::Mode::XTS β Block cipher mode XTS [XEX-based tweaked-codebook mode with ciphertext stealing] π
π¦ SYNOPSIS π¦
use Crypt::Mode::XTS;
my $xts = Crypt::Mode::XTS->new('AES', $key); # $key = key1 || key2
# one complete data unit (sector) per call; same object does both directions
my $ct = $xts->encrypt($plaintext, $tweak);
my $pt = $xts->decrypt($ciphertext, $tweak);
# tweak: 16-byte string, or a data-unit number
my $ct1 = $xts->encrypt($sector, "\x02" . "\x00" x 15);
my $ct2 = $xts->encrypt($sector, 2); # same thing (64-bit LE, zero-padded)
# the canonical loop - key schedules computed exactly once, in new()
my $unit = 0;
while (my $n = sysread $in, my $sector, 4096) {
syswrite $out, $xts->encrypt($sector, $unit++);
}
like, look at that last block. that's the whole point of this module. one object, key schedules done once, loop forever. iconic. π
πΈ DESCRIPTION πΈ
So this module implements the XTS cipher mode exactly as specified by IEEE 1619-2007 and NIST SP 800-38E, ciphertext stealing included β meaning data units that aren't a multiple of the block size still get handled, no cap. π«Ά Quick heads up though: it works only with 128-bit block ciphers from CryptX β think 'AES', 'Twofish', 'Serpent', 'Camellia', 'ARIA', 'SM4', ... and friends.
BEWARE bestie, this one's important: XTS gives you confidentiality only β no integrity, no authentication, nada. A single bit-flip in the ciphertext garbles exactly the corresponding 16-byte plaintext block, and it's predictably positioned β that's malleability by design, not a bug. Don't come for me, it's literally the spec. π
XTS is for encrypting storage in place, where the tweak is implicit in the location and there is genuinely no room for a MAC. For anything that travels β files, messages, backups β please please please use an AEAD mode ("Crypt::AuthEnc::*") instead. π Also be aware that an attacker with two snapshots of the same device can see which blocks changed. that's just how it is, ngl.
And unlike the other "Crypt::Mode::*" modules, XTS is not an online mode (ciphertext stealing needs the complete data unit), so there's no "start_encrypt"/"add"/"finish" API, and this module does not subclass Crypt::Mode. One "encrypt"/"decrypt" call processes exactly one complete data unit. Ciphertext length always equals plaintext length. periodt. β¨
π§ METHODS π§
π new
my $xts = Crypt::Mode::XTS->new($cipher, $key);
#or
my $xts = Crypt::Mode::XTS->new($cipher, $key, $cipher_rounds);
# $cipher .......... [string] cipher with 128-bit blocks, e.g. 'AES', 'Twofish',
# 'Serpent', 'Camellia', 'ARIA', 'SM4'
# or any <NAME> for which there is a Crypt::Cipher::<NAME>
# module with a 16-byte block size
# $key ............. [binary string] key1 || key2, each half a valid key for the
# cipher; for AES that means 32, 48 or 64 bytes total
# $cipher_rounds ... [integer] optional, number of rounds for the given cipher
# (0 or omitted = the cipher's standard number of rounds)
Both key schedules get computed right here, exactly once β "encrypt"/"decrypt" only use the schedules afterwards. The raw key is not stored in the object, and the schedules are zeroized when the object gets destroyed. clean. π§Ό
It croaks if the cipher doesn't have 128-bit blocks, if either key half isn't a valid key size for the cipher, and β per FIPS 140 Implementation Guidance A.9 β if "key1" equals "key2" (that config degrades XTS toward ECB on single-block data units, which is giving β¨ nothing β¨).
The returned object is direction-free: the same object encrypts and decrypts. one object, both vibes. π
π₯ encrypt
my $ct = $xts->encrypt($plaintext, $tweak);
Encrypts one complete data unit (like, one disk sector, for example). Returns the ciphertext as a binary string the same length as the plaintext. π
$plaintext must be at least 16 bytes (one full cipher block); any length above that is fine, including lengths that aren't a multiple of 16 (ciphertext stealing handles the final partial block, she's got it). It croaks above 2^20 blocks (16MiB) β that's the NIST SP 800-38E bound per data unit, not me being dramatic.
$tweak is either exactly 16 binary bytes, or a non-negative integer < 2^64 that gets encoded as 64-bit little-endian and zero-padded to 16 bytes (the "data unit sequence number" convention β identical to dm-crypt plain64 and to what OpenSSL and kernel test vectors use). π
Note bestie: a 16-byte string is always taken as a raw binary tweak, even if it consists entirely of digits. no sneakiness. π
β decrypt
my $pt = $xts->decrypt($ciphertext, $tweak);
Decrypts one complete data unit. Returns the plaintext as a binary string the same length as the ciphertext. Same rules for $ciphertext and $tweak as in "encrypt". π
π SEE ALSO π
- CryptX, Crypt::Cipher
- Crypt::AuthEnc::GCM, Crypt::AuthEnc::ChaCha20Poly1305 β authenticated encryption, for data that travels πΈ
- <https://en.wikipedia.org/wiki/Disk_encryption_theory#XTS>
- <https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38e.pdf>
and that's the whole page bestie! π¦ this one's from perl v5.44.0, dated 2026-10-17, and it's filed under Crypt::Mode::XTS(3) in the User Contributed Perl Documentation. go encrypt a disk, or don't, just β use an AEAD if it travels, ily, bye! π β¨π
π¦ where this page comes from
- arch rolling: perl-cryptx 0.091-2 Β· PerlArtistic AND GPL
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms