I'm testing IEEE's P1619, which is XTS mode. IEEE documents from 2007 provided both test vectors and a reference implementation. Documents from 2008 only provided the reference implementation. Here is the 2007 document with both.

The reference implementation stayed the same from 2007 and 2008. The problem is, the reference implementation does not arrive at the test vector result. I've got it tracked down to the handling of the 64-bit S parameter in XTS_EncryptSector. The test vectors call out, for example, S=0x9a78563412; but I believe it should be S=0x123456789a, which allows the reference implementation to arrive at the test vector result.

I believe one of three things is wrong but I am not sure which one:

  • The S parameter is incorrect and should be byte-reversed
  • XTS_EncryptSector, which parses S into the tweak, is incorrect
  • The test vector result is incorrect

Based on Section 5, p. 4, I believe the test vector or S parameter is incorrect because of this sentence, which seems to apply to the S parameter:

When encrypting tweak value using AES, the tweak is first converted into a little-endian 4 byte array. For example, tweak value 123456789A16 corresponds to byte array 9a16,7816,5616,3416,1216.

For anyone who wishes to try the code, see test2.cxx on GitHub. It is a copy/paste of the algorithm "C.2 Encryption of a data unit with a size that is not a multiple of 16 bytes" with OpenSSL providing AES code.

My question is, where does the problem lie?

Here's the relevant code for the handling of S:

void XTS_EncryptSector
    const AES_Key k2,               // key used for tweaking
    const AES_Key k1,               // key used for "ECB" encryption
    u64b  S,                        // sector number (64 bits)
    uint  N,                        // sector size, in bytes
    const u08b *pt,                 //  plaintext sector  input data
    u08b *ct                        // ciphertext sector output data

    for (j=0;j<AES_BLK_BYTES;j++)
    {                               // convert sector number to tweak plaintext
        T[j] = (u08b) (S & 0xFF);
        S    = S >> 8;              // also note that T[] is padded with zeroes

It takes a value like S=0x9a78563412, and converts it into a tweak 12 34 56 78 9a 00 00 00 00 00 00 00 00 00 00 00 00.

  • 3
    $\begingroup$ There is something called "endianness", if you look at 0x9a78563412, and reverse the bytes, it becomes 0x123456789a, it seems to be somewhere in the doc the endianness if the values should be explicitly defined en.wikipedia.org/wiki/Endianness $\endgroup$ Oct 9 '19 at 23:16

From §5.1 ‘Data units and tweaks’, p. 4:

Each data unit is assigned a tweak value which is a non-negative integer. The tweak values are assigned consecutively, starting from an arbitrary non-negative integer. When encrypting tweak value using AES, the tweak is first converted into a little-endian byte array. For example, tweak value 123456789A16 corresponds to byte array 9a16, 7816, 5616, 3416, 1216.

The test vectors appear to be written as byte arrays, not as integers (which in English are written big-endian), so where it says

Data unit sequence number 9a78563412

on p. 23, that presumably means the integer 0x123456789a, i.e. 78187493530 in decimal.

  • $\begingroup$ If you look at the reference implementation the data unit is a 64-bit word, not a byte array. $\endgroup$
    – user10496
    Oct 12 '19 at 13:19
  • 2
    $\begingroup$ Okay…so the reference implementation takes an integer, and the test vectors are written as byte arrays, and you now have the key to the puzzle highlighted and armed with this detail you've successfully reproduced the test vectors. Are you still unclear on anything here? If your goal is to file an editorial complaint with the IEEE P1619 working group that their document could have been worded a little more clearly, I'm afraid this is a Wendy's, sir. $\endgroup$ Oct 12 '19 at 14:59
  • $\begingroup$ Thanks @Squeamish. My goal is not to file an editorial complaint. Yet another disingenuous statement, sir. My goal is to interoperate out of the box. It is not clear to me where the test vectors take a byte array for this parameter since the sector is called a Data Unit, and that is spec'd as a 64-bit word. And I have been burned in the past due to this type of imprecision. I had to remove a block cipher in the past that arrived at the test vectors but it did not follow the description of the algorithm. $\endgroup$
    – user10496
    Oct 12 '19 at 15:57
  • 1
    $\begingroup$ @jww It's just the notation used to write the test vector. The actual logic is defined on byte arrays—nothing in XTS itself does arithmetic in $\mathbb Z/2^{128}\mathbb Z$ on the data unit sequence number. It is really just a matter of convention that you use the little-endian encoding of a disk sector number as the data unit sequence number in applications of XTS; as far as XTS itself is concerned the byte array is just an array of bytes fed into AES as a plaintext. I remain unclear on what you're asking—what is your question? How might you act differently on different answers? $\endgroup$ Oct 12 '19 at 18:18