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