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