File 0001-Vendor-in-XTS-functionality-from-Nettle.patch of Package gnutls.18748

From ea46e149b69cf1c4b963e6d156a6b3e38d710894 Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Fri, 19 Oct 2018 15:53:27 -0400
Subject: [PATCH] Vendor in XTS functionality from Nettle

If nettle's XTS is not available, use a vendored in version from master.
This is necessary as long as we need to link against 3.4 for ABI
compatibility reasons.

Signed-off-by: Simo Sorce <simo@redhat.com>
---
 configure.ac                    |   7 +
 lib/algorithms/ciphers.c        |  15 ++
 lib/crypto-selftests.c          |  51 ++++++
 lib/fips.c                      |   6 +
 lib/fips.h                      |   2 +
 lib/includes/gnutls/gnutls.h.in |   8 +
 lib/nettle/Makefile.am          |   1 +
 lib/nettle/backport/xts.c       | 273 ++++++++++++++++++++++++++++++++
 lib/nettle/backport/xts.h       | 122 ++++++++++++++
 lib/nettle/cipher.c             |  51 ++++++
 10 files changed, 536 insertions(+)
 create mode 100644 lib/nettle/backport/xts.c
 create mode 100644 lib/nettle/backport/xts.h

diff --git a/configure.ac b/configure.ac
index b686726d1b..f9d40b4ea2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -563,6 +563,13 @@ LIBS="$LIBS $NETTLE_LIBS"
 AC_CHECK_FUNCS(nettle_cmac128_update)
 LIBS=$save_LIBS
 
+# Check if nettle has XTS support
+save_LIBS=$LIBS
+LIBS="$LIBS $NETTLE_LIBS"
+AC_CHECK_FUNCS(xts_encrypt_message)
+LIBS=$save_LIBS
+
+
 AC_MSG_CHECKING([whether to build libdane])
 AC_ARG_ENABLE(libdane,
     AS_HELP_STRING([--disable-libdane],
diff --git a/lib/algorithms/ciphers.c b/lib/algorithms/ciphers.c
index 9fa6f0d805..6f503fd0b2 100644
--- a/lib/algorithms/ciphers.c
+++ b/lib/algorithms/ciphers.c
@@ -219,6 +219,7 @@ static const cipher_entry_st algorithms[] = {
 	  .type = CIPHER_STREAM,
 	  .implicit_iv = 8,
 	  .cipher_iv = 8},
+
 	{ .name = "AES-128-CFB8",
 	  .id = GNUTLS_CIPHER_AES_128_CFB8,
 	  .blocksize = 16,
@@ -240,6 +241,20 @@ static const cipher_entry_st algorithms[] = {
 	  .type = CIPHER_BLOCK,
 	  .explicit_iv = 16,
 	  .cipher_iv = 16},
+	{ .name = "AES-128-XTS",
+	  .id = GNUTLS_CIPHER_AES_128_XTS,
+	  .blocksize = 16,
+	  .keysize = 32,
+	  .type = CIPHER_BLOCK,
+	  .explicit_iv = 16,
+	  .cipher_iv = 16},
+	{ .name = "AES-256-XTS",
+	  .id = GNUTLS_CIPHER_AES_256_XTS,
+	  .blocksize = 16,
+	  .keysize = 64,
+	  .type = CIPHER_BLOCK,
+	  .explicit_iv = 16,
+	  .cipher_iv = 16},
 	{ .name = "3DES-CBC",
 	  .id = GNUTLS_CIPHER_3DES_CBC,
 	  .blocksize = 8,
diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
index d5475d2ffd..5d040fb603 100644
--- a/lib/crypto-selftests.c
+++ b/lib/crypto-selftests.c
@@ -499,6 +499,51 @@ const struct cipher_vectors_st gost28147_tc26z_cfb_vectors[] = {
 	},
 };
 
+const struct cipher_vectors_st aes128_xts_vectors[] = {
+	{
+	 STR(key, key_size,
+	     "\xa1\xb9\x0c\xba\x3f\x06\xac\x35\x3b\x2c\x34\x38\x76\x08\x17\x62"
+             "\x09\x09\x23\x02\x6e\x91\x77\x18\x15\xf2\x9d\xab\x01\x93\x2f\x2f"),
+	 STR(plaintext, plaintext_size,
+	     "\xeb\xab\xce\x95\xb1\x4d\x3c\x8d\x6f\xb3\x50\x39\x07\x90\x31\x1c"),
+	 .ciphertext = (uint8_t *)
+	     "\x77\x8a\xe8\xb4\x3c\xb9\x8d\x5a\x82\x50\x81\xd5\xbe\x47\x1c\x63",
+	 STR(iv, iv_size,
+	     "\x4f\xae\xf7\x11\x7c\xda\x59\xc6\x6e\x4b\x92\x01\x3e\x76\x8a\xd5"),
+	 },
+	{
+	 STR(key, key_size,
+	     "\x75\x03\x72\xc3\xd8\x2f\x63\x38\x28\x67\xbe\x66\x62\xac\xfa\x4a"
+             "\x25\x9b\xe3\xfa\x9b\xc6\x62\xa1\x15\x4f\xfa\xae\xd8\xb4\x48\xa5"),
+	 STR(plaintext, plaintext_size,
+	     "\xd8\xe3\xa5\x65\x59\xa4\x36\xce\x0d\x8b\x21\x2c\x80\xa8\x8b\x23"
+             "\xaf\x62\xb0\xe5\x98\xf2\x08\xe0\x3c\x1f\x2e\x9f\xa5\x63\xa5\x4b"),
+	 .ciphertext = (uint8_t *)
+	     "\x49\x5f\x78\x55\x53\x5e\xfd\x13\x34\x64\xdc\x9a\x9a\xbf\x8a\x0f"
+             "\x28\xfa\xcb\xce\x21\xbd\x3c\x22\x17\x8e\xc4\x89\xb7\x99\xe4\x91",
+	 STR(iv, iv_size,
+	     "\x93\xa2\x92\x54\xc4\x7e\x42\x60\x66\x96\x21\x30\x7d\x4f\x5c\xd3"),
+	 },
+};
+
+const struct cipher_vectors_st aes256_xts_vectors[] = {
+	{
+	 STR(key, key_size,
+             "\x1e\xa6\x61\xc5\x8d\x94\x3a\x0e\x48\x01\xe4\x2f\x4b\x09\x47\x14"
+             "\x9e\x7f\x9f\x8e\x3e\x68\xd0\xc7\x50\x52\x10\xbd\x31\x1a\x0e\x7c"
+             "\xd6\xe1\x3f\xfd\xf2\x41\x8d\x8d\x19\x11\xc0\x04\xcd\xa5\x8d\xa3"
+             "\xd6\x19\xb7\xe2\xb9\x14\x1e\x58\x31\x8e\xea\x39\x2c\xf4\x1b\x08"),
+	 STR(plaintext, plaintext_size,
+	     "\x2e\xed\xea\x52\xcd\x82\x15\xe1\xac\xc6\x47\xe8\x10\xbb\xc3\x64"
+             "\x2e\x87\x28\x7f\x8d\x2e\x57\xe3\x6c\x0a\x24\xfb\xc1\x2a\x20\x2e"),
+	 .ciphertext = (uint8_t *)
+	     "\xcb\xaa\xd0\xe2\xf6\xce\xa3\xf5\x0b\x37\xf9\x34\xd4\x6a\x9b\x13"
+             "\x0b\x9d\x54\xf0\x7e\x34\xf3\x6a\xf7\x93\xe8\x6f\x73\xc6\xd7\xdb",
+	 STR(iv, iv_size,
+	     "\xad\xf8\xd9\x26\x27\x46\x4a\xd2\xf0\x42\x8e\x84\xa9\xf8\x75\x64"),
+	 },
+};
+
 static int test_cipher(gnutls_cipher_algorithm_t cipher,
 		       const struct cipher_vectors_st *vectors,
 		       size_t vectors_size, unsigned flags)
@@ -1582,6 +1627,12 @@ int gnutls_cipher_self_test(unsigned flags, gnutls_cipher_algorithm_t cipher)
 		FALLTHROUGH;
 		CASE(GNUTLS_CIPHER_AES_256_CFB8, test_cipher,
 		     aes256_cfb8_vectors);
+		FALLTHROUGH;
+		CASE(GNUTLS_CIPHER_AES_128_XTS, test_cipher,
+		     aes128_xts_vectors);
+		FALLTHROUGH;
+		CASE(GNUTLS_CIPHER_AES_256_XTS, test_cipher,
+		     aes256_xts_vectors);
 #if ENABLE_GOST
 		FALLTHROUGH;
 		NON_FIPS_CASE(GNUTLS_CIPHER_GOST28147_CPA_CFB, test_cipher,
diff --git a/lib/fips.c b/lib/fips.c
index 32436ad1f8..ef1f7cbc35 100644
--- a/lib/fips.c
+++ b/lib/fips.c
@@ -323,6 +323,12 @@ int _gnutls_fips_perform_self_checks2(void)
 		goto error;
 	}
 
+	ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_XTS);
+	if (ret < 0) {
+		gnutls_assert();
+		goto error;
+	}
+
 	/* Digest tests */
 	ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_224);
 	if (ret < 0) {
diff --git a/lib/fips.h b/lib/fips.h
index beb540f76b..97f1c26219 100644
--- a/lib/fips.h
+++ b/lib/fips.h
@@ -144,6 +144,8 @@ static unsigned is_cipher_algo_forbidden(gnutls_cipher_algorithm_t algo)
 			case GNUTLS_CIPHER_AES_128_CFB8:
 			case GNUTLS_CIPHER_AES_192_CFB8:
 			case GNUTLS_CIPHER_AES_256_CFB8:
+			case GNUTLS_CIPHER_AES_128_XTS:
+			case GNUTLS_CIPHER_AES_256_XTS:
 				return 0;
 			default:
 				if (mode == GNUTLS_FIPS140_LAX)
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 20e9784754..5b5d9bab8a 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -119,6 +119,12 @@ extern "C" {
  * @GNUTLS_CIPHER_GOST28147_CPB_CFB: GOST 28147-89 (Magma) cipher in CFB mode with CryptoPro B S-box.
  * @GNUTLS_CIPHER_GOST28147_CPC_CFB: GOST 28147-89 (Magma) cipher in CFB mode with CryptoPro C S-box.
  * @GNUTLS_CIPHER_GOST28147_CPD_CFB: GOST 28147-89 (Magma) cipher in CFB mode with CryptoPro D S-box.
+ * @GNUTLS_CIPHER_AES_128_XTS: AES in XTS mode with 128-bit key + 128bit tweak key.
+ * @GNUTLS_CIPHER_AES_256_XTS: AES in XTS mode with 256-bit key + 256bit tweak key.
+ *                             Note that the XTS ciphers are message oriented.
+ *                             The whole message needs to be provided with a single call, because
+ *                             cipher-stealing requires to know where the message actually terminates
+ *                             in order to be able to compute where the stealing occurs.
  * @GNUTLS_CIPHER_IDEA_PGP_CFB: IDEA in CFB mode (placeholder - unsupported).
  * @GNUTLS_CIPHER_3DES_PGP_CFB: 3DES in CFB mode (placeholder - unsupported).
  * @GNUTLS_CIPHER_CAST5_PGP_CFB: CAST5 in CFB mode (placeholder - unsupported).
@@ -164,6 +170,8 @@ typedef enum gnutls_cipher_algorithm {
 	GNUTLS_CIPHER_AES_128_CFB8 = 29,
 	GNUTLS_CIPHER_AES_192_CFB8 = 30,
 	GNUTLS_CIPHER_AES_256_CFB8 = 31,
+	GNUTLS_CIPHER_AES_128_XTS = 32,
+	GNUTLS_CIPHER_AES_256_XTS = 33,
 
 	/* used only for PGP internals. Ignored in TLS/SSL
 	 */
diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am
index 4dbce087f6..1c60d3244b 100644
--- a/lib/nettle/Makefile.am
+++ b/lib/nettle/Makefile.am
@@ -42,6 +42,7 @@ libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c init.c \
 	gnettle.h rnd-common.h prf.c \
 	backport/cfb8.c backport/cfb8.h \
 	backport/cmac.c backport/cmac.h \
+	backport/xts.c backport/xts.h \
 	rnd.c int/rsa-fips.h int/rsa-keygen-fips186.c int/provable-prime.c \
 	int/dsa-fips.h int/dsa-keygen-fips186.c int/dsa-validate.c \
 	int/tls1-prf.c int/tls1-prf.h
diff --git a/lib/nettle/backport/xts.c b/lib/nettle/backport/xts.c
new file mode 100644
index 0000000000..a7ef120aa0
--- /dev/null
+++ b/lib/nettle/backport/xts.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Simo Sorce
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* #############################################
+ * THIS IS A BACKPORT FROM NETTLE, DO NOT MODIFY
+ * #############################################
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef HAVE_XTS_ENCRYPT_MESSAGE
+#include "xts.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <nettle/macros.h>
+#include <nettle/memxor.h>
+
+/* An aligned 16-byte block. */
+union _backport_nettle_block16
+{
+  uint8_t b[16];
+  unsigned long w[16 / sizeof(unsigned long)];
+  uint64_t u64[2];
+};
+
+/* shift left one and XOR with 0x87 if there is carry. */
+/* the algorithm reads this as a 128bit Little Endian number */
+/* src and dest can point to the same buffer for in-place operations */
+#if WORDS_BIGENDIAN
+#define BE_SHIFT(x) ((((x) & 0x7f7f7f7f7f7f7f7f) << 1) | \
+                     (((x) & 0x8080808080808080) >> 15))
+static void
+xts_shift(union _backport_nettle_block16 *dst,
+          const union _backport_nettle_block16 *src)
+{
+  uint64_t carry = (src->u64[1] & 0x80) >> 7;
+  dst->u64[1] = BE_SHIFT(src->u64[1]) | ((src->u64[0] & 0x80) << 49);
+  dst->u64[0] = BE_SHIFT(src->u64[0]);
+  dst->u64[0] ^= 0x8700000000000000 & -carry;
+}
+#else /* !WORDS_BIGENDIAN */
+static void
+xts_shift(union _backport_nettle_block16 *dst,
+          const union _backport_nettle_block16 *src)
+{
+  uint64_t carry = src->u64[1] >> 63;
+  dst->u64[1] = (src->u64[1] << 1) | (src->u64[0] >> 63);
+  dst->u64[0] = src->u64[0] << 1;
+  dst->u64[0] ^= 0x87 & -carry;
+}
+#endif /* !WORDS_BIGNDIAN */
+
+static void
+check_length(size_t length, uint8_t *dst)
+{
+  assert(length >= XTS_BLOCK_SIZE);
+  /* asserts may be compiled out, try to save the user by zeroing the dst in
+   * case the buffer contains sensitive data (like the clear text for inplace
+   * encryption) */
+  if (length < XTS_BLOCK_SIZE)
+    memset(dst, '\0', length);
+}
+
+/* works also for inplace encryption/decryption */
+
+void
+xts_encrypt_message(const void *enc_ctx, const void *twk_ctx,
+	            nettle_cipher_func *encf,
+	            const uint8_t *tweak, size_t length,
+	            uint8_t *dst, const uint8_t *src)
+{
+  union _backport_nettle_block16 T;
+  union _backport_nettle_block16 P;
+
+  check_length(length, dst);
+
+  encf(twk_ctx, XTS_BLOCK_SIZE, T.b, tweak);
+
+  /* the zeroth power of alpha is the initial ciphertext value itself, so we
+   * skip shifting and do it at the end of each block operation instead */
+  for (;length >= 2 * XTS_BLOCK_SIZE || length == XTS_BLOCK_SIZE;
+       length -= XTS_BLOCK_SIZE, src += XTS_BLOCK_SIZE, dst += XTS_BLOCK_SIZE)
+    {
+      memxor3(P.b, src, T.b, XTS_BLOCK_SIZE);	/* P -> PP */
+      encf(enc_ctx, XTS_BLOCK_SIZE, dst, P.b);  /* CC */
+      memxor(dst, T.b, XTS_BLOCK_SIZE);	        /* CC -> C */
+
+      /* shift T for next block if any */
+      if (length > XTS_BLOCK_SIZE)
+          xts_shift(&T, &T);
+    }
+
+  /* if the last block is partial, handle via stealing */
+  if (length)
+    {
+      /* S Holds the real C(n-1) (Whole last block to steal from) */
+      union _backport_nettle_block16 S;
+
+      memxor3(P.b, src, T.b, XTS_BLOCK_SIZE);	/* P -> PP */
+      encf(enc_ctx, XTS_BLOCK_SIZE, S.b, P.b);  /* CC */
+      memxor(S.b, T.b, XTS_BLOCK_SIZE);	        /* CC -> S */
+
+      /* shift T for next block */
+      xts_shift(&T, &T);
+
+      length -= XTS_BLOCK_SIZE;
+      src += XTS_BLOCK_SIZE;
+
+      memxor3(P.b, src, T.b, length);           /* P |.. */
+      /* steal ciphertext to complete block */
+      memxor3(P.b + length, S.b + length, T.b + length,
+              XTS_BLOCK_SIZE - length);         /* ..| S_2 -> PP */
+
+      encf(enc_ctx, XTS_BLOCK_SIZE, dst, P.b);  /* CC */
+      memxor(dst, T.b, XTS_BLOCK_SIZE);         /* CC -> C(n-1) */
+
+      /* Do this after we read src so inplace operations do not break */
+      dst += XTS_BLOCK_SIZE;
+      memcpy(dst, S.b, length);                 /* S_1 -> C(n) */
+    }
+}
+
+void
+xts_decrypt_message(const void *dec_ctx, const void *twk_ctx,
+	            nettle_cipher_func *decf, nettle_cipher_func *encf,
+	            const uint8_t *tweak, size_t length,
+	            uint8_t *dst, const uint8_t *src)
+{
+  union _backport_nettle_block16 T;
+  union _backport_nettle_block16 C;
+
+  check_length(length, dst);
+
+  encf(twk_ctx, XTS_BLOCK_SIZE, T.b, tweak);
+
+  for (;length >= 2 * XTS_BLOCK_SIZE || length == XTS_BLOCK_SIZE;
+       length -= XTS_BLOCK_SIZE, src += XTS_BLOCK_SIZE, dst += XTS_BLOCK_SIZE)
+    {
+      memxor3(C.b, src, T.b, XTS_BLOCK_SIZE);	/* c -> CC */
+      decf(dec_ctx, XTS_BLOCK_SIZE, dst, C.b);  /* PP */
+      memxor(dst, T.b, XTS_BLOCK_SIZE);	        /* PP -> P */
+
+      /* shift T for next block if any */
+      if (length > XTS_BLOCK_SIZE)
+          xts_shift(&T, &T);
+    }
+
+  /* if the last block is partial, handle via stealing */
+  if (length)
+    {
+      union _backport_nettle_block16 T1;
+      /* S Holds the real P(n) (with part of stolen ciphertext) */
+      union _backport_nettle_block16 S;
+
+      /* we need the last T(n) and save the T(n-1) for later */
+      xts_shift(&T1, &T);
+
+      memxor3(C.b, src, T1.b, XTS_BLOCK_SIZE);	/* C -> CC */
+      decf(dec_ctx, XTS_BLOCK_SIZE, S.b, C.b);  /* PP */
+      memxor(S.b, T1.b, XTS_BLOCK_SIZE);	/* PP -> S */
+
+      /* process next block (Pn-1) */
+      length -= XTS_BLOCK_SIZE;
+      src += XTS_BLOCK_SIZE;
+
+      /* Prepare C, P holds the real P(n) */
+      memxor3(C.b, src, T.b, length);	        /* C_1 |.. */
+      memxor3(C.b + length, S.b + length, T.b + length,
+              XTS_BLOCK_SIZE - length);         /* ..| S_2 -> CC */
+      decf(dec_ctx, XTS_BLOCK_SIZE, dst, C.b);  /* PP */
+      memxor(dst, T.b, XTS_BLOCK_SIZE);	        /* PP -> P(n-1) */
+
+      /* Do this after we read src so inplace operations do not break */
+      dst += XTS_BLOCK_SIZE;
+      memcpy(dst, S.b, length);                 /* S_1 -> P(n) */
+    }
+}
+
+void
+xts_aes128_set_encrypt_key(struct xts_aes128_key *xts_key, const uint8_t *key)
+{
+    aes128_set_encrypt_key(&xts_key->cipher, key);
+    aes128_set_encrypt_key(&xts_key->tweak_cipher, &key[AES128_KEY_SIZE]);
+}
+
+void
+xts_aes128_set_decrypt_key(struct xts_aes128_key *xts_key, const uint8_t *key)
+{
+    aes128_set_decrypt_key(&xts_key->cipher, key);
+    aes128_set_encrypt_key(&xts_key->tweak_cipher, &key[AES128_KEY_SIZE]);
+}
+
+void
+xts_aes128_encrypt_message(struct xts_aes128_key *xts_key,
+                           const uint8_t *tweak, size_t length,
+                           uint8_t *dst, const uint8_t *src)
+{
+    xts_encrypt_message(&xts_key->cipher, &xts_key->tweak_cipher,
+                        (nettle_cipher_func *) aes128_encrypt,
+                        tweak, length, dst, src);
+}
+
+void
+xts_aes128_decrypt_message(struct xts_aes128_key *xts_key,
+                           const uint8_t *tweak, size_t length,
+                           uint8_t *dst, const uint8_t *src)
+{
+    xts_decrypt_message(&xts_key->cipher, &xts_key->tweak_cipher,
+                        (nettle_cipher_func *) aes128_decrypt,
+                        (nettle_cipher_func *) aes128_encrypt,
+                        tweak, length, dst, src);
+}
+
+void
+xts_aes256_set_encrypt_key(struct xts_aes256_key *xts_key, const uint8_t *key)
+{
+    aes256_set_encrypt_key(&xts_key->cipher, key);
+    aes256_set_encrypt_key(&xts_key->tweak_cipher, &key[AES256_KEY_SIZE]);
+}
+
+void
+xts_aes256_set_decrypt_key(struct xts_aes256_key *xts_key, const uint8_t *key)
+{
+    aes256_set_decrypt_key(&xts_key->cipher, key);
+    aes256_set_encrypt_key(&xts_key->tweak_cipher, &key[AES256_KEY_SIZE]);
+}
+
+void
+xts_aes256_encrypt_message(struct xts_aes256_key *xts_key,
+                           const uint8_t *tweak, size_t length,
+                           uint8_t *dst, const uint8_t *src)
+{
+    xts_encrypt_message(&xts_key->cipher, &xts_key->tweak_cipher,
+                        (nettle_cipher_func *) aes256_encrypt,
+                        tweak, length, dst, src);
+}
+
+void
+xts_aes256_decrypt_message(struct xts_aes256_key *xts_key,
+                           const uint8_t *tweak, size_t length,
+                           uint8_t *dst, const uint8_t *src)
+{
+    xts_decrypt_message(&xts_key->cipher, &xts_key->tweak_cipher,
+                        (nettle_cipher_func *) aes256_decrypt,
+                        (nettle_cipher_func *) aes256_encrypt,
+                        tweak, length, dst, src);
+}
+
+#endif /* HAVE_XTS_ENCRYPT_MESSAGE */
diff --git a/lib/nettle/backport/xts.h b/lib/nettle/backport/xts.h
new file mode 100644
index 0000000000..5111af0f38
--- /dev/null
+++ b/lib/nettle/backport/xts.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2018 Red Hat, Inc.
+ *
+ * Author: Simo Sorce
+ *
+ * This file is part of GnuTLS.
+ *
+ * The GnuTLS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef _BACKPORT_NETTLE_XTS_H_INCLUDED
+#define _BACKPORT_NETTLE_XTS_H_INCLUDED
+
+#ifdef HAVE_XTS_ENCRYPT_MESSAGE
+#include <nettle/xts.h>
+
+#else /* Nettle version is old, use a vendored version instead */
+
+#ifndef NETTLE_XTS_H_INCLUDED
+#define NETTLE_XTS_H_INCLUDED
+
+#include <nettle/nettle-types.h>
+#include <nettle/aes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Name mangling */
+#define xts_encrypt_message nettle_xts_encrypt_message
+#define xts_decrypt_message nettle_xts_decrypt_message
+#define xts_aes128_set_encrypt_key nettle_xts_aes128_set_encrypt_key
+#define xts_aes128_set_decrypt_key nettle_xts_aes128_set_decrypt_key
+#define xts_aes128_encrypt_message nettle_xts_aes128_encrypt_message
+#define xts_aes128_decrypt_message nettle_xts_aes128_decrypt_message
+#define xts_aes256_set_encrypt_key nettle_xts_aes256_set_encrypt_key
+#define xts_aes256_set_decrypt_key nettle_xts_aes256_set_decrypt_key
+#define xts_aes256_encrypt_message nettle_xts_aes256_encrypt_message
+#define xts_aes256_decrypt_message nettle_xts_aes256_decrypt_message
+
+#define XTS_BLOCK_SIZE 16
+
+void
+xts_encrypt_message(const void *enc_ctx, const void *twk_ctx,
+                nettle_cipher_func *encf,
+                const uint8_t *tweak, size_t length,
+                uint8_t *dst, const uint8_t *src);
+void
+xts_decrypt_message(const void *dec_ctx, const void *twk_ctx,
+                    nettle_cipher_func *decf, nettle_cipher_func *encf,
+                    const uint8_t *tweak, size_t length,
+                    uint8_t *dst, const uint8_t *src);
+
+/* XTS Mode with AES-128 */
+struct xts_aes128_key {
+    struct aes128_ctx cipher;
+    struct aes128_ctx tweak_cipher;
+};
+
+void
+xts_aes128_set_encrypt_key(struct xts_aes128_key *xts_key,
+                           const uint8_t *key);
+
+void
+xts_aes128_set_decrypt_key(struct xts_aes128_key *xts_key,
+                           const uint8_t *key);
+
+void
+xts_aes128_encrypt_message(struct xts_aes128_key *xtskey,
+                           const uint8_t *tweak, size_t length,
+                           uint8_t *dst, const uint8_t *src);
+
+void
+xts_aes128_decrypt_message(struct xts_aes128_key *xts_key,
+                           const uint8_t *tweak, size_t length,
+                           uint8_t *dst, const uint8_t *src);
+
+/* XTS Mode with AES-256 */
+struct xts_aes256_key {
+    struct aes256_ctx cipher;
+    struct aes256_ctx tweak_cipher;
+};
+
+void
+xts_aes256_set_encrypt_key(struct xts_aes256_key *xts_key,
+                           const uint8_t *key);
+
+void
+xts_aes256_set_decrypt_key(struct xts_aes256_key *xts_key,
+                           const uint8_t *key);
+
+void
+xts_aes256_encrypt_message(struct xts_aes256_key *xts_key,
+                           const uint8_t *tweak, size_t length,
+                           uint8_t *dst, const uint8_t *src);
+
+void
+xts_aes256_decrypt_message(struct xts_aes256_key *xts_key,
+                           const uint8_t *tweak, size_t length,
+                           uint8_t *dst, const uint8_t *src);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETTLE_XTS_H_INCLUDED */
+
+#endif /* HAVE_XTS_ENCRYPT_MESSAGE */
+
+#endif /* _BACKPORT_NETTLE_XTS_H_INCLUDED */
diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c
index da33099974..9194fb750c 100644
--- a/lib/nettle/cipher.c
+++ b/lib/nettle/cipher.c
@@ -47,6 +47,7 @@
 #else
 #include "cfb8.h"
 #endif /* HAVE_NETTLE_CFB8_ENCRYPT */
+#include "xts.h"
 #include <fips.h>
 
 struct nettle_cipher_ctx;
@@ -280,6 +281,34 @@ _cfb8_decrypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst,
 		     length, dst, src);
 }
 
+static void
+_xts_aes128_encrypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst,
+		    const uint8_t * src)
+{
+	xts_aes128_encrypt_message(ctx->ctx_ptr, ctx->iv, length, dst, src);
+}
+
+static void
+_xts_aes128_decrypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst,
+		    const uint8_t * src)
+{
+	xts_aes128_decrypt_message(ctx->ctx_ptr, ctx->iv, length, dst, src);
+}
+
+static void
+_xts_aes256_encrypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst,
+		    const uint8_t * src)
+{
+	xts_aes256_encrypt_message(ctx->ctx_ptr, ctx->iv, length, dst, src);
+}
+
+static void
+_xts_aes256_decrypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst,
+		    const uint8_t * src)
+{
+	xts_aes256_decrypt_message(ctx->ctx_ptr, ctx->iv, length, dst, src);
+}
+
 static const struct nettle_cipher_st builtin_ciphers[] = {
 	{  .algo = GNUTLS_CIPHER_AES_128_GCM,
 	   .block_size = AES_BLOCK_SIZE,
@@ -677,6 +706,28 @@ static const struct nettle_cipher_st builtin_ciphers[] = {
 	   .set_decrypt_key = (nettle_set_key_func*)aes256_set_encrypt_key,
 	   .max_iv_size = AES_BLOCK_SIZE,
 	},
+	{  .algo = GNUTLS_CIPHER_AES_128_XTS,
+	   .block_size = AES_BLOCK_SIZE,
+	   .key_size = AES128_KEY_SIZE * 2,
+
+	   .ctx_size = sizeof(struct xts_aes128_key),
+	   .encrypt = _xts_aes128_encrypt,
+	   .decrypt = _xts_aes128_decrypt,
+	   .set_encrypt_key = (nettle_set_key_func*)xts_aes128_set_encrypt_key,
+	   .set_decrypt_key = (nettle_set_key_func*)xts_aes128_set_decrypt_key,
+	   .max_iv_size = AES_BLOCK_SIZE,
+	},
+	{  .algo = GNUTLS_CIPHER_AES_256_XTS,
+	   .block_size = AES_BLOCK_SIZE,
+	   .key_size = AES256_KEY_SIZE * 2,
+
+	   .ctx_size = sizeof(struct xts_aes256_key),
+	   .encrypt = _xts_aes256_encrypt,
+	   .decrypt = _xts_aes256_decrypt,
+	   .set_encrypt_key = (nettle_set_key_func*)xts_aes256_set_encrypt_key,
+	   .set_decrypt_key = (nettle_set_key_func*)xts_aes256_set_decrypt_key,
+	   .max_iv_size = AES_BLOCK_SIZE,
+	},
 };
 
 static int wrap_nettle_cipher_exists(gnutls_cipher_algorithm_t algo)
-- 
2.25.0

openSUSE Build Service is sponsored by