[openssl-users] issue with EVP_EncryptUpdate in XTS mode?

Matt Caswell matt at openssl.org
Sat Jan 26 00:17:56 UTC 2019

On 25/01/2019 20:16, Andrew Tucker wrote:
> I was doing some comparisons of XTS and GCM mode using the EVP APIs and found a
> discrepancy that seems to be an issue with XTS.
> In GCM mode if the buffer is encrypted in one call to EVP_EncryptUpdate or with
> several calls with smaller buffers the resulting ciphertext is the same, as I
> would expect.   With XTS mode, calling EVP_EncryptUpdate results in the same
> ciphertext for the same plaintext and does not match the results when the buffer
> is encrypted with one call to EVP_EncryptUpdate.
> I would expect that the counter is incremented in both XTS and GCM mode in the
> same way and that in both cases the output would match regardless of the
> encryption block size.
> A simple repro test is attached.    If you run it you can see that the output
> "GCM in one block" matches the output for "GCM in 16 byte blocks" and the
> outputs do not match for XTS.
> I am using OpenSSL v1.02p but I have tried with other versions and got the same
> results.
> Am I misunderstanding the use of XTS mode or is this an issue with OpenSSL?

The documentation for XTS mode seems to be particularly dreadful (i.e.
practically non-existent).

XTS mode was designed for disk encryption and works quite differently to modes
like GCM. XTS encrypts blocks at a time where each block has a separate "tweak"
value (and by "block" here I'm talking about disk blocks not encryption blocks).
There is no "streaming" concept - there is not necessarily any relationship with
the tweak from one block to be encrypted to the next one. AFAICT from code
inspection you are expected to set the tweak in the IV field and then encrypt an
entire (disk) block in one go with EVP_EncryptUpdate().

This seems to be supported by this post from Steve Henson where he describes the
XTS implementation as not being able to stream and as a "one shot" version:


In this later post in the same thread Steve talks about calling
EVP_EncryptInit_ex again with all the params set to NULL except the ctx and iv
(i.e. tweak) in order to set a new tweak and then call EVP_EncryptUpdate again.


In other words I think you are supposed to use it something like this (error
handling omitted for brevity):


EVP_EncryptInit_ex(ctx, EVP_aes_256_xts(), NULL, aes_key, NULL);

EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, tweak1);
EVP_EncryptUpdate(ctx, out, &outl, block1, blocklen1);
EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, tweak2);
EVP_EncryptUpdate(ctx, out, &outl, block2, blocklen2);
EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, tweak3);
EVP_EncryptUpdate(ctx, out, &outl, block3, blocklen3);

That really needs to go in the man pages.


More information about the openssl-users mailing list