blob: d4a49fdb709b934e7c7c438313cd2ffd91a0b569 [file] [log] [blame]
Daniel P. Berrange84f7f182016-02-11 14:00:17 +00001/*
2 * QEMU Crypto XTS cipher mode
3 *
4 * Copyright (c) 2015-2016 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
Thomas Huthb7cbb872019-02-13 16:54:59 +01009 * version 2.1 of the License, or (at your option) any later version.
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000010 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 * This code is originally derived from public domain / WTFPL code in
20 * LibTomCrypt crytographic library http://libtom.org. The XTS code
21 * was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
22 * to the LibTom Projects
23 *
24 */
25
26#include "qemu/osdep.h"
Daniel P. Berrangé7dac0dd2018-10-09 10:55:14 +010027#include "qemu/bswap.h"
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000028#include "crypto/xts.h"
29
Daniel P. Berrangécc369302018-10-09 10:45:41 +010030typedef union {
31 uint8_t b[XTS_BLOCK_SIZE];
32 uint64_t u[2];
33} xts_uint128;
34
Daniel P. Berrangédb217c62018-10-09 10:50:43 +010035static inline void xts_uint128_xor(xts_uint128 *D,
36 const xts_uint128 *S1,
37 const xts_uint128 *S2)
38{
39 D->u[0] = S1->u[0] ^ S2->u[0];
40 D->u[1] = S1->u[1] ^ S2->u[1];
41}
Daniel P. Berrangécc369302018-10-09 10:45:41 +010042
Daniel P. Berrangé7dac0dd2018-10-09 10:55:14 +010043static inline void xts_uint128_cpu_to_les(xts_uint128 *v)
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000044{
Daniel P. Berrangé7dac0dd2018-10-09 10:55:14 +010045 cpu_to_le64s(&v->u[0]);
46 cpu_to_le64s(&v->u[1]);
47}
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000048
Daniel P. Berrangé7dac0dd2018-10-09 10:55:14 +010049static inline void xts_uint128_le_to_cpus(xts_uint128 *v)
50{
51 le64_to_cpus(&v->u[0]);
52 le64_to_cpus(&v->u[1]);
53}
54
55static void xts_mult_x(xts_uint128 *I)
56{
57 uint64_t tt;
58
59 xts_uint128_le_to_cpus(I);
60
61 tt = I->u[0] >> 63;
62 I->u[0] <<= 1;
63
64 if (I->u[1] >> 63) {
65 I->u[0] ^= 0x87;
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000066 }
Daniel P. Berrangé7dac0dd2018-10-09 10:55:14 +010067 I->u[1] <<= 1;
68 I->u[1] |= tt;
69
70 xts_uint128_cpu_to_les(I);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000071}
72
73
74/**
Daniel P. Berrangé299ec872018-10-08 14:13:28 +010075 * xts_tweak_encdec:
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000076 * @param ctxt: the cipher context
77 * @param func: the cipher function
Daniel P. Berrangé299ec872018-10-08 14:13:28 +010078 * @src: buffer providing the input text of XTS_BLOCK_SIZE bytes
79 * @dst: buffer to output the output text of XTS_BLOCK_SIZE bytes
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000080 * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
81 *
Daniel P. Berrangé299ec872018-10-08 14:13:28 +010082 * Encrypt/decrypt data with a tweak
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000083 */
Daniel P. Berrangéaa895bd2018-10-09 10:50:43 +010084static inline void xts_tweak_encdec(const void *ctx,
85 xts_cipher_func *func,
86 const xts_uint128 *src,
87 xts_uint128 *dst,
88 xts_uint128 *iv)
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000089{
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000090 /* tweak encrypt block i */
Daniel P. Berrangédb217c62018-10-09 10:50:43 +010091 xts_uint128_xor(dst, src, iv);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000092
Daniel P. Berrangédb217c62018-10-09 10:50:43 +010093 func(ctx, XTS_BLOCK_SIZE, dst->b, dst->b);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000094
Daniel P. Berrangédb217c62018-10-09 10:50:43 +010095 xts_uint128_xor(dst, dst, iv);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000096
97 /* LFSR the tweak */
Daniel P. Berrangé7dac0dd2018-10-09 10:55:14 +010098 xts_mult_x(iv);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +000099}
100
101
102void xts_decrypt(const void *datactx,
103 const void *tweakctx,
104 xts_cipher_func *encfunc,
105 xts_cipher_func *decfunc,
106 uint8_t *iv,
107 size_t length,
108 uint8_t *dst,
109 const uint8_t *src)
110{
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100111 xts_uint128 PP, CC, T;
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000112 unsigned long i, m, mo, lim;
113
114 /* get number of blocks */
115 m = length >> 4;
116 mo = length & 15;
117
118 /* must have at least one full block */
119 g_assert(m != 0);
120
121 if (mo == 0) {
122 lim = m;
123 } else {
124 lim = m - 1;
125 }
126
127 /* encrypt the iv */
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100128 encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000129
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100130 if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) &&
131 QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) {
132 xts_uint128 *S = (xts_uint128 *)src;
133 xts_uint128 *D = (xts_uint128 *)dst;
134 for (i = 0; i < lim; i++, S++, D++) {
135 xts_tweak_encdec(datactx, decfunc, S, D, &T);
136 }
137 } else {
138 xts_uint128 D;
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000139
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100140 for (i = 0; i < lim; i++) {
141 memcpy(&D, src, XTS_BLOCK_SIZE);
142 xts_tweak_encdec(datactx, decfunc, &D, &D, &T);
143 memcpy(dst, &D, XTS_BLOCK_SIZE);
144 src += XTS_BLOCK_SIZE;
145 dst += XTS_BLOCK_SIZE;
146 }
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000147 }
148
149 /* if length is not a multiple of XTS_BLOCK_SIZE then */
150 if (mo > 0) {
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100151 xts_uint128 S, D;
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100152 memcpy(&CC, &T, XTS_BLOCK_SIZE);
Daniel P. Berrangé7dac0dd2018-10-09 10:55:14 +0100153 xts_mult_x(&CC);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000154
155 /* PP = tweak decrypt block m-1 */
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100156 memcpy(&S, src, XTS_BLOCK_SIZE);
157 xts_tweak_encdec(datactx, decfunc, &S, &PP, &CC);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000158
159 /* Pm = first length % XTS_BLOCK_SIZE bytes of PP */
160 for (i = 0; i < mo; i++) {
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100161 CC.b[i] = src[XTS_BLOCK_SIZE + i];
162 dst[XTS_BLOCK_SIZE + i] = PP.b[i];
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000163 }
164 for (; i < XTS_BLOCK_SIZE; i++) {
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100165 CC.b[i] = PP.b[i];
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000166 }
167
168 /* Pm-1 = Tweak uncrypt CC */
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100169 xts_tweak_encdec(datactx, decfunc, &CC, &D, &T);
170 memcpy(dst, &D, XTS_BLOCK_SIZE);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000171 }
172
173 /* Decrypt the iv back */
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100174 decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000175}
176
177
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000178void xts_encrypt(const void *datactx,
179 const void *tweakctx,
180 xts_cipher_func *encfunc,
181 xts_cipher_func *decfunc,
182 uint8_t *iv,
183 size_t length,
184 uint8_t *dst,
185 const uint8_t *src)
186{
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100187 xts_uint128 PP, CC, T;
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000188 unsigned long i, m, mo, lim;
189
190 /* get number of blocks */
191 m = length >> 4;
192 mo = length & 15;
193
194 /* must have at least one full block */
195 g_assert(m != 0);
196
197 if (mo == 0) {
198 lim = m;
199 } else {
200 lim = m - 1;
201 }
202
203 /* encrypt the iv */
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100204 encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000205
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100206 if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) &&
207 QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) {
208 xts_uint128 *S = (xts_uint128 *)src;
209 xts_uint128 *D = (xts_uint128 *)dst;
210 for (i = 0; i < lim; i++, S++, D++) {
211 xts_tweak_encdec(datactx, encfunc, S, D, &T);
212 }
213 } else {
214 xts_uint128 D;
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000215
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100216 for (i = 0; i < lim; i++) {
217 memcpy(&D, src, XTS_BLOCK_SIZE);
218 xts_tweak_encdec(datactx, encfunc, &D, &D, &T);
219 memcpy(dst, &D, XTS_BLOCK_SIZE);
220
221 dst += XTS_BLOCK_SIZE;
222 src += XTS_BLOCK_SIZE;
223 }
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000224 }
225
226 /* if length is not a multiple of XTS_BLOCK_SIZE then */
227 if (mo > 0) {
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100228 xts_uint128 S, D;
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000229 /* CC = tweak encrypt block m-1 */
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100230 memcpy(&S, src, XTS_BLOCK_SIZE);
231 xts_tweak_encdec(datactx, encfunc, &S, &CC, &T);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000232
233 /* Cm = first length % XTS_BLOCK_SIZE bytes of CC */
234 for (i = 0; i < mo; i++) {
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100235 PP.b[i] = src[XTS_BLOCK_SIZE + i];
236 dst[XTS_BLOCK_SIZE + i] = CC.b[i];
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000237 }
238
239 for (; i < XTS_BLOCK_SIZE; i++) {
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100240 PP.b[i] = CC.b[i];
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000241 }
242
243 /* Cm-1 = Tweak encrypt PP */
Daniel P. Berrangédb217c62018-10-09 10:50:43 +0100244 xts_tweak_encdec(datactx, encfunc, &PP, &D, &T);
245 memcpy(dst, &D, XTS_BLOCK_SIZE);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000246 }
247
248 /* Decrypt the iv back */
Daniel P. Berrangécc369302018-10-09 10:45:41 +0100249 decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b);
Daniel P. Berrange84f7f182016-02-11 14:00:17 +0000250}