1/* 2 * Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10#include <openssl/crypto.h> 11#include "modes_local.h" 12#include <string.h> 13 14#ifndef STRICT_ALIGNMENT 15# ifdef __GNUC__ 16typedef u64 u64_a1 __attribute((__aligned__(1))); 17# else 18typedef u64 u64_a1; 19# endif 20#endif 21 22int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx, 23 const unsigned char iv[16], 24 const unsigned char *inp, unsigned char *out, 25 size_t len, int enc) 26{ 27 const union { 28 long one; 29 char little; 30 } is_endian = { 31 1 32 }; 33 union { 34 u64 u[2]; 35 u32 d[4]; 36 u8 c[16]; 37 } tweak, scratch; 38 unsigned int i; 39 40 if (len < 16) 41 return -1; 42 43 memcpy(tweak.c, iv, 16); 44 45 (*ctx->block2) (tweak.c, tweak.c, ctx->key2); 46 47 if (!enc && (len % 16)) 48 len -= 16; 49 50 while (len >= 16) { 51#if defined(STRICT_ALIGNMENT) 52 memcpy(scratch.c, inp, 16); 53 scratch.u[0] ^= tweak.u[0]; 54 scratch.u[1] ^= tweak.u[1]; 55#else 56 scratch.u[0] = ((u64_a1 *)inp)[0] ^ tweak.u[0]; 57 scratch.u[1] = ((u64_a1 *)inp)[1] ^ tweak.u[1]; 58#endif 59 (*ctx->block1) (scratch.c, scratch.c, ctx->key1); 60#if defined(STRICT_ALIGNMENT) 61 scratch.u[0] ^= tweak.u[0]; 62 scratch.u[1] ^= tweak.u[1]; 63 memcpy(out, scratch.c, 16); 64#else 65 ((u64_a1 *)out)[0] = scratch.u[0] ^= tweak.u[0]; 66 ((u64_a1 *)out)[1] = scratch.u[1] ^= tweak.u[1]; 67#endif 68 inp += 16; 69 out += 16; 70 len -= 16; 71 72 if (len == 0) 73 return 0; 74 75 if (is_endian.little) { 76 unsigned int carry, res; 77 78 res = 0x87 & (((int)tweak.d[3]) >> 31); 79 carry = (unsigned int)(tweak.u[0] >> 63); 80 tweak.u[0] = (tweak.u[0] << 1) ^ res; 81 tweak.u[1] = (tweak.u[1] << 1) | carry; 82 } else { 83 size_t c; 84 85 for (c = 0, i = 0; i < 16; ++i) { 86 /* 87 * + substitutes for |, because c is 1 bit 88 */ 89 c += ((size_t)tweak.c[i]) << 1; 90 tweak.c[i] = (u8)c; 91 c = c >> 8; 92 } 93 tweak.c[0] ^= (u8)(0x87 & (0 - c)); 94 } 95 } 96 if (enc) { 97 for (i = 0; i < len; ++i) { 98 u8 c = inp[i]; 99 out[i] = scratch.c[i]; 100 scratch.c[i] = c; 101 } 102 scratch.u[0] ^= tweak.u[0]; 103 scratch.u[1] ^= tweak.u[1]; 104 (*ctx->block1) (scratch.c, scratch.c, ctx->key1); 105 scratch.u[0] ^= tweak.u[0]; 106 scratch.u[1] ^= tweak.u[1]; 107 memcpy(out - 16, scratch.c, 16); 108 } else { 109 union { 110 u64 u[2]; 111 u8 c[16]; 112 } tweak1; 113 114 if (is_endian.little) { 115 unsigned int carry, res; 116 117 res = 0x87 & (((int)tweak.d[3]) >> 31); 118 carry = (unsigned int)(tweak.u[0] >> 63); 119 tweak1.u[0] = (tweak.u[0] << 1) ^ res; 120 tweak1.u[1] = (tweak.u[1] << 1) | carry; 121 } else { 122 size_t c; 123 124 for (c = 0, i = 0; i < 16; ++i) { 125 /* 126 * + substitutes for |, because c is 1 bit 127 */ 128 c += ((size_t)tweak.c[i]) << 1; 129 tweak1.c[i] = (u8)c; 130 c = c >> 8; 131 } 132 tweak1.c[0] ^= (u8)(0x87 & (0 - c)); 133 } 134#if defined(STRICT_ALIGNMENT) 135 memcpy(scratch.c, inp, 16); 136 scratch.u[0] ^= tweak1.u[0]; 137 scratch.u[1] ^= tweak1.u[1]; 138#else 139 scratch.u[0] = ((u64_a1 *)inp)[0] ^ tweak1.u[0]; 140 scratch.u[1] = ((u64_a1 *)inp)[1] ^ tweak1.u[1]; 141#endif 142 (*ctx->block1) (scratch.c, scratch.c, ctx->key1); 143 scratch.u[0] ^= tweak1.u[0]; 144 scratch.u[1] ^= tweak1.u[1]; 145 146 for (i = 0; i < len; ++i) { 147 u8 c = inp[16 + i]; 148 out[16 + i] = scratch.c[i]; 149 scratch.c[i] = c; 150 } 151 scratch.u[0] ^= tweak.u[0]; 152 scratch.u[1] ^= tweak.u[1]; 153 (*ctx->block1) (scratch.c, scratch.c, ctx->key1); 154#if defined(STRICT_ALIGNMENT) 155 scratch.u[0] ^= tweak.u[0]; 156 scratch.u[1] ^= tweak.u[1]; 157 memcpy(out, scratch.c, 16); 158#else 159 ((u64_a1 *)out)[0] = scratch.u[0] ^ tweak.u[0]; 160 ((u64_a1 *)out)[1] = scratch.u[1] ^ tweak.u[1]; 161#endif 162 } 163 164 return 0; 165} 166