diff --git a/xts.c b/xts.c
index 5c37655df279ce21821a85e1d28c41017bae3105..ea2ceea90619ea2b77386d308d4dfd2e24113d74 100644
--- a/xts.c
+++ b/xts.c
@@ -45,21 +45,32 @@
 #include "memxor.h"
 #include "nettle-internal.h"
 
-/* shift one and XOR with 0x87. */
+/* 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 nettle_block16 *dst,
           const union nettle_block16 *src)
 {
-  uint8_t carry = src->b[15] >> 7;
-  uint64_t b0 = LE_READ_UINT64(src->b);
-  uint64_t b1 = LE_READ_UINT64(src->b+8);
-  b1 = (b1 << 1) | (b0 >> 63);
-  b0 = b0 << 1;
-  LE_WRITE_UINT64(dst->b, b0);
-  LE_WRITE_UINT64(dst->b+8, b1);
-  dst->b[0] ^= 0x87 & -carry;
+  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 nettle_block16 *dst,
+          const union 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)