summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS8
-rw-r--r--configure.ac7
-rw-r--r--lib/algorithms/ciphers.c15
-rw-r--r--lib/crypto-selftests.c51
-rw-r--r--lib/fips.c6
-rw-r--r--lib/fips.h2
-rw-r--r--lib/includes/gnutls/gnutls.h.in8
-rw-r--r--lib/nettle/Makefile.am1
-rw-r--r--lib/nettle/backport/xts.c273
-rw-r--r--lib/nettle/backport/xts.h122
-rw-r--r--lib/nettle/cipher.c51
11 files changed, 544 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index 76764e8654..0be3696576 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,14 @@ Copyright (C) 2000-2016 Free Software Foundation, Inc.
Copyright (C) 2013-2019 Nikos Mavrogiannopoulos
See the end for copying conditions.
+* Version 3.6.8 (unreleased)
+
+** libgnutls: Added support for AES-XTS cipher (#354)
+
+** API and ABI modifications:
+No changes since last version.
+
+
* Version 3.6.7 (released 2019-03-27)
** libgnutls, gnutls tools: Every gnutls_free() will automatically set
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)