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