.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.45) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "Crypt::Mode::XTS 3" .TH Crypt::Mode::XTS 3 2026-08-10 "perl v5.42.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Crypt::Mode::XTS \- Block cipher mode XTS [XEX\-based tweaked\-codebook mode with ciphertext stealing] .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use Crypt::Mode::XTS; \& \& my $xts = Crypt::Mode::XTS\->new(\*(AqAES\*(Aq, $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, "\ex02" . "\ex00" 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++); \& } .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" This module implements the XTS cipher mode as specified by IEEE 1619\-2007 and NIST SP 800\-38E, including ciphertext stealing for data units that are not a multiple of the block size. \fBNote:\fR It works only with 128\-bit block ciphers from CryptX (\*(AqAES\*(Aq, \*(AqTwofish\*(Aq, \*(AqSerpent\*(Aq, \*(AqCamellia\*(Aq, \*(AqARIA\*(Aq, \*(AqSM4\*(Aq, ...). .PP \&\fBBEWARE: XTS provides confidentiality only \- no integrity, no authentication.\fR A bit\-flip in the ciphertext garbles exactly the corresponding 16\-byte plaintext block, predictably positioned \- that\*(Aqs malleability by design. XTS is for encrypting storage in place, where the tweak is implicit in the location and there is no room for a MAC. For anything that travels \- files, messages, backups \- use an AEAD mode (\f(CW\*(C`Crypt::AuthEnc::*\*(C'\fR) instead. Also be aware that an attacker with two snapshots of the same device sees which blocks changed. .PP Unlike the other \f(CW\*(C`Crypt::Mode::*\*(C'\fR modules, XTS is not an online mode (ciphertext stealing needs the complete data unit), so there is no \&\f(CW\*(C`start_encrypt\*(C'\fR/\f(CW\*(C`add\*(C'\fR/\f(CW\*(C`finish\*(C'\fR API and this module does not subclass Crypt::Mode. One \f(CW\*(C`encrypt\*(C'\fR/\f(CW\*(C`decrypt\*(C'\fR call processes exactly one complete data unit. Ciphertext length always equals plaintext length. .SH METHODS .IX Header "METHODS" .SS new .IX Subsection "new" .Vb 3 \& 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. \*(AqAES\*(Aq, \*(AqTwofish\*(Aq, \& # \*(AqSerpent\*(Aq, \*(AqCamellia\*(Aq, \*(AqARIA\*(Aq, \*(AqSM4\*(Aq \& # or any for which there is a Crypt::Cipher:: \& # 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\*(Aqs standard number of rounds) .Ve .PP Both key schedules are computed here, exactly once; \f(CW\*(C`encrypt\*(C'\fR/\f(CW\*(C`decrypt\*(C'\fR only use the schedules. The raw key is not stored in the object and the schedules are zeroized on object destruction. .PP Croaks if the cipher does not have 128\-bit blocks, if either key half is not a valid key size for the cipher, and \- per FIPS 140 Implementation Guidance A.9 \- if \f(CW\*(C`key1\*(C'\fR equals \f(CW\*(C`key2\*(C'\fR (that configuration degrades XTS toward ECB on single\-block data units). .PP The returned object is direction\-free: the same object encrypts and decrypts. .SS encrypt .IX Subsection "encrypt" .Vb 1 \& my $ct = $xts\->encrypt($plaintext, $tweak); .Ve .PP Encrypts one complete data unit (e.g. one disk sector). Returns the ciphertext as a binary string of the same length as the plaintext. .PP \&\f(CW$plaintext\fR must be at least 16 bytes (one full cipher block); any length above that is fine, including lengths that are not a multiple of 16 (ciphertext stealing handles the final partial block). Croaks above 2^20 blocks (16MiB) \- the NIST SP 800\-38E bound per data unit. .PP \&\f(CW$tweak\fR is either exactly 16 binary bytes, or a non\-negative integer < 2^64 that is 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). \fBNote:\fR a 16\-byte string is always taken as a raw binary tweak, even if it consists of digits. .SS decrypt .IX Subsection "decrypt" .Vb 1 \& my $pt = $xts\->decrypt($ciphertext, $tweak); .Ve .PP Decrypts one complete data unit. Returns the plaintext as a binary string of the same length as the ciphertext. Same rules for \f(CW$ciphertext\fR and \&\f(CW$tweak\fR as in "encrypt". .SH "SEE ALSO" .IX Header "SEE ALSO" .IP \(bu 4 CryptX, Crypt::Cipher .IP \(bu 4 Crypt::AuthEnc::GCM, Crypt::AuthEnc::ChaCha20Poly1305 \- authenticated encryption, for data that travels .IP \(bu 4 .IP \(bu 4