xref: /openssl/crypto/modes/xts128gb.c (revision 2788b56f)
1 /*
2  * Copyright 2022 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 
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 int ossl_crypto_xts128gb_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             u8 res;
73             u64 hi, lo;
74 #ifdef BSWAP8
75             hi = BSWAP8(tweak.u[0]);
76             lo = BSWAP8(tweak.u[1]);
77 #else
78             u8 *p = tweak.c;
79 
80             hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
81             lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
82 #endif
83             res = (u8)lo & 1;
84             tweak.u[0] = (lo >> 1) | (hi << 63);
85             tweak.u[1] = hi >> 1;
86             if (res)
87                 tweak.c[15] ^= 0xe1;
88 #ifdef BSWAP8
89             hi = BSWAP8(tweak.u[0]);
90             lo = BSWAP8(tweak.u[1]);
91 #else
92             p = tweak.c;
93 
94             hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
95             lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
96 #endif
97             tweak.u[0] = lo;
98             tweak.u[1] = hi;
99         } else {
100             u8 carry, res;
101             carry = 0;
102             for (i = 0; i < 16; ++i) {
103                 res = (tweak.c[i] << 7) & 0x80;
104                 tweak.c[i] = ((tweak.c[i] >> 1) + carry) & 0xff;
105                 carry = res;
106             }
107             if (res)
108                 tweak.c[0] ^= 0xe1;
109         }
110     }
111     if (enc) {
112         for (i = 0; i < len; ++i) {
113             u8 c = inp[i];
114             out[i] = scratch.c[i];
115             scratch.c[i] = c;
116         }
117         scratch.u[0] ^= tweak.u[0];
118         scratch.u[1] ^= tweak.u[1];
119         (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
120         scratch.u[0] ^= tweak.u[0];
121         scratch.u[1] ^= tweak.u[1];
122         memcpy(out - 16, scratch.c, 16);
123     } else {
124         union {
125             u64 u[2];
126             u8 c[16];
127         } tweak1;
128 
129         if (IS_LITTLE_ENDIAN) {
130             u8 res;
131             u64 hi, lo;
132 #ifdef BSWAP8
133             hi = BSWAP8(tweak.u[0]);
134             lo = BSWAP8(tweak.u[1]);
135 #else
136             u8 *p = tweak.c;
137 
138             hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
139             lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
140 #endif
141             res = (u8)lo & 1;
142             tweak1.u[0] = (lo >> 1) | (hi << 63);
143             tweak1.u[1] = hi >> 1;
144             if (res)
145                 tweak1.c[15] ^= 0xe1;
146 #ifdef BSWAP8
147             hi = BSWAP8(tweak1.u[0]);
148             lo = BSWAP8(tweak1.u[1]);
149 #else
150             p = tweak1.c;
151 
152             hi = (u64)GETU32(p) << 32 | GETU32(p + 4);
153             lo = (u64)GETU32(p + 8) << 32 | GETU32(p + 12);
154 #endif
155             tweak1.u[0] = lo;
156             tweak1.u[1] = hi;
157         } else {
158             u8 carry, res;
159             carry = 0;
160             for (i = 0; i < 16; ++i) {
161                 res = (tweak.c[i] << 7) & 0x80;
162                 tweak1.c[i] = ((tweak.c[i] >> 1) + carry) & 0xff;
163                 carry = res;
164             }
165             if (res)
166                 tweak1.c[0] ^= 0xe1;
167         }
168 #if defined(STRICT_ALIGNMENT)
169         memcpy(scratch.c, inp, 16);
170         scratch.u[0] ^= tweak1.u[0];
171         scratch.u[1] ^= tweak1.u[1];
172 #else
173         scratch.u[0] = ((u64_a1 *)inp)[0] ^ tweak1.u[0];
174         scratch.u[1] = ((u64_a1 *)inp)[1] ^ tweak1.u[1];
175 #endif
176         (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
177         scratch.u[0] ^= tweak1.u[0];
178         scratch.u[1] ^= tweak1.u[1];
179 
180         for (i = 0; i < len; ++i) {
181             u8 c = inp[16 + i];
182             out[16 + i] = scratch.c[i];
183             scratch.c[i] = c;
184         }
185         scratch.u[0] ^= tweak.u[0];
186         scratch.u[1] ^= tweak.u[1];
187         (*ctx->block1) (scratch.c, scratch.c, ctx->key1);
188 #if defined(STRICT_ALIGNMENT)
189         scratch.u[0] ^= tweak.u[0];
190         scratch.u[1] ^= tweak.u[1];
191         memcpy(out, scratch.c, 16);
192 #else
193         ((u64_a1 *)out)[0] = scratch.u[0] ^ tweak.u[0];
194         ((u64_a1 *)out)[1] = scratch.u[1] ^ tweak.u[1];
195 #endif
196     }
197 
198     return 0;
199 }
200