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