xref: /openbmc/qemu/crypto/xts.c (revision e2b47666fe1544959c89bd3ed159e9e37cc9fc73)
184f7f180SDaniel P. Berrange /*
284f7f180SDaniel P. Berrange  * QEMU Crypto XTS cipher mode
384f7f180SDaniel P. Berrange  *
484f7f180SDaniel P. Berrange  * Copyright (c) 2015-2016 Red Hat, Inc.
584f7f180SDaniel P. Berrange  *
684f7f180SDaniel P. Berrange  * This library is free software; you can redistribute it and/or
784f7f180SDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
884f7f180SDaniel P. Berrange  * License as published by the Free Software Foundation; either
9*b7cbb874SThomas Huth  * version 2.1 of the License, or (at your option) any later version.
1084f7f180SDaniel P. Berrange  *
1184f7f180SDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
1284f7f180SDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1384f7f180SDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1484f7f180SDaniel P. Berrange  * Lesser General Public License for more details.
1584f7f180SDaniel P. Berrange  *
1684f7f180SDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
1784f7f180SDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1884f7f180SDaniel P. Berrange  *
1984f7f180SDaniel P. Berrange  * This code is originally derived from public domain / WTFPL code in
2084f7f180SDaniel P. Berrange  * LibTomCrypt crytographic library http://libtom.org. The XTS code
2184f7f180SDaniel P. Berrange  * was donated by Elliptic Semiconductor Inc (www.ellipticsemi.com)
2284f7f180SDaniel P. Berrange  * to the LibTom Projects
2384f7f180SDaniel P. Berrange  *
2484f7f180SDaniel P. Berrange  */
2584f7f180SDaniel P. Berrange 
2684f7f180SDaniel P. Berrange #include "qemu/osdep.h"
277dac0dd6SDaniel P. Berrangé #include "qemu/bswap.h"
2884f7f180SDaniel P. Berrange #include "crypto/xts.h"
2984f7f180SDaniel P. Berrange 
30cc36930eSDaniel P. Berrangé typedef union {
31cc36930eSDaniel P. Berrangé     uint8_t b[XTS_BLOCK_SIZE];
32cc36930eSDaniel P. Berrangé     uint64_t u[2];
33cc36930eSDaniel P. Berrangé } xts_uint128;
34cc36930eSDaniel P. Berrangé 
xts_uint128_xor(xts_uint128 * D,const xts_uint128 * S1,const xts_uint128 * S2)35db217c69SDaniel P. Berrangé static inline void xts_uint128_xor(xts_uint128 *D,
36db217c69SDaniel P. Berrangé                                    const xts_uint128 *S1,
37db217c69SDaniel P. Berrangé                                    const xts_uint128 *S2)
38db217c69SDaniel P. Berrangé {
39db217c69SDaniel P. Berrangé     D->u[0] = S1->u[0] ^ S2->u[0];
40db217c69SDaniel P. Berrangé     D->u[1] = S1->u[1] ^ S2->u[1];
41db217c69SDaniel P. Berrangé }
42cc36930eSDaniel P. Berrangé 
xts_uint128_cpu_to_les(xts_uint128 * v)437dac0dd6SDaniel P. Berrangé static inline void xts_uint128_cpu_to_les(xts_uint128 *v)
4484f7f180SDaniel P. Berrange {
457dac0dd6SDaniel P. Berrangé     cpu_to_le64s(&v->u[0]);
467dac0dd6SDaniel P. Berrangé     cpu_to_le64s(&v->u[1]);
477dac0dd6SDaniel P. Berrangé }
4884f7f180SDaniel P. Berrange 
xts_uint128_le_to_cpus(xts_uint128 * v)497dac0dd6SDaniel P. Berrangé static inline void xts_uint128_le_to_cpus(xts_uint128 *v)
507dac0dd6SDaniel P. Berrangé {
517dac0dd6SDaniel P. Berrangé     le64_to_cpus(&v->u[0]);
527dac0dd6SDaniel P. Berrangé     le64_to_cpus(&v->u[1]);
5384f7f180SDaniel P. Berrange }
547dac0dd6SDaniel P. Berrangé 
xts_mult_x(xts_uint128 * I)557dac0dd6SDaniel P. Berrangé static void xts_mult_x(xts_uint128 *I)
567dac0dd6SDaniel P. Berrangé {
577dac0dd6SDaniel P. Berrangé     uint64_t tt;
587dac0dd6SDaniel P. Berrangé 
597dac0dd6SDaniel P. Berrangé     xts_uint128_le_to_cpus(I);
607dac0dd6SDaniel P. Berrangé 
617dac0dd6SDaniel P. Berrangé     tt = I->u[0] >> 63;
627dac0dd6SDaniel P. Berrangé     I->u[0] <<= 1;
637dac0dd6SDaniel P. Berrangé 
647dac0dd6SDaniel P. Berrangé     if (I->u[1] >> 63) {
657dac0dd6SDaniel P. Berrangé         I->u[0] ^= 0x87;
6684f7f180SDaniel P. Berrange     }
677dac0dd6SDaniel P. Berrangé     I->u[1] <<= 1;
687dac0dd6SDaniel P. Berrangé     I->u[1] |= tt;
697dac0dd6SDaniel P. Berrangé 
707dac0dd6SDaniel P. Berrangé     xts_uint128_cpu_to_les(I);
7184f7f180SDaniel P. Berrange }
7284f7f180SDaniel P. Berrange 
7384f7f180SDaniel P. Berrange 
7484f7f180SDaniel P. Berrange /**
75299ec878SDaniel P. Berrangé  * xts_tweak_encdec:
7684f7f180SDaniel P. Berrange  * @param ctxt: the cipher context
7784f7f180SDaniel P. Berrange  * @param func: the cipher function
78299ec878SDaniel P. Berrangé  * @src: buffer providing the input text of XTS_BLOCK_SIZE bytes
79299ec878SDaniel P. Berrangé  * @dst: buffer to output the output text of XTS_BLOCK_SIZE bytes
8084f7f180SDaniel P. Berrange  * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes
8184f7f180SDaniel P. Berrange  *
82299ec878SDaniel P. Berrangé  * Encrypt/decrypt data with a tweak
8384f7f180SDaniel P. Berrange  */
xts_tweak_encdec(const void * ctx,xts_cipher_func * func,const xts_uint128 * src,xts_uint128 * dst,xts_uint128 * iv)84aa895bd4SDaniel P. Berrangé static inline void xts_tweak_encdec(const void *ctx,
8584f7f180SDaniel P. Berrange                                     xts_cipher_func *func,
86db217c69SDaniel P. Berrangé                                     const xts_uint128 *src,
87db217c69SDaniel P. Berrangé                                     xts_uint128 *dst,
88db217c69SDaniel P. Berrangé                                     xts_uint128 *iv)
8984f7f180SDaniel P. Berrange {
9084f7f180SDaniel P. Berrange     /* tweak encrypt block i */
91db217c69SDaniel P. Berrangé     xts_uint128_xor(dst, src, iv);
9284f7f180SDaniel P. Berrange 
93db217c69SDaniel P. Berrangé     func(ctx, XTS_BLOCK_SIZE, dst->b, dst->b);
9484f7f180SDaniel P. Berrange 
95db217c69SDaniel P. Berrangé     xts_uint128_xor(dst, dst, iv);
9684f7f180SDaniel P. Berrange 
9784f7f180SDaniel P. Berrange     /* LFSR the tweak */
987dac0dd6SDaniel P. Berrangé     xts_mult_x(iv);
9984f7f180SDaniel P. Berrange }
10084f7f180SDaniel P. Berrange 
10184f7f180SDaniel P. Berrange 
xts_decrypt(const void * datactx,const void * tweakctx,xts_cipher_func * encfunc,xts_cipher_func * decfunc,uint8_t * iv,size_t length,uint8_t * dst,const uint8_t * src)10284f7f180SDaniel P. Berrange void xts_decrypt(const void *datactx,
10384f7f180SDaniel P. Berrange                  const void *tweakctx,
10484f7f180SDaniel P. Berrange                  xts_cipher_func *encfunc,
10584f7f180SDaniel P. Berrange                  xts_cipher_func *decfunc,
10684f7f180SDaniel P. Berrange                  uint8_t *iv,
10784f7f180SDaniel P. Berrange                  size_t length,
10884f7f180SDaniel P. Berrange                  uint8_t *dst,
10984f7f180SDaniel P. Berrange                  const uint8_t *src)
11084f7f180SDaniel P. Berrange {
111cc36930eSDaniel P. Berrangé     xts_uint128 PP, CC, T;
11284f7f180SDaniel P. Berrange     unsigned long i, m, mo, lim;
11384f7f180SDaniel P. Berrange 
11484f7f180SDaniel P. Berrange     /* get number of blocks */
11584f7f180SDaniel P. Berrange     m = length >> 4;
11684f7f180SDaniel P. Berrange     mo = length & 15;
11784f7f180SDaniel P. Berrange 
11884f7f180SDaniel P. Berrange     /* must have at least one full block */
11984f7f180SDaniel P. Berrange     g_assert(m != 0);
12084f7f180SDaniel P. Berrange 
12184f7f180SDaniel P. Berrange     if (mo == 0) {
12284f7f180SDaniel P. Berrange         lim = m;
12384f7f180SDaniel P. Berrange     } else {
12484f7f180SDaniel P. Berrange         lim = m - 1;
12584f7f180SDaniel P. Berrange     }
12684f7f180SDaniel P. Berrange 
12784f7f180SDaniel P. Berrange     /* encrypt the iv */
128cc36930eSDaniel P. Berrangé     encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv);
12984f7f180SDaniel P. Berrange 
130db217c69SDaniel P. Berrangé     if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) &&
131db217c69SDaniel P. Berrangé         QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) {
132db217c69SDaniel P. Berrangé         xts_uint128 *S = (xts_uint128 *)src;
133db217c69SDaniel P. Berrangé         xts_uint128 *D = (xts_uint128 *)dst;
134db217c69SDaniel P. Berrangé         for (i = 0; i < lim; i++, S++, D++) {
135db217c69SDaniel P. Berrangé             xts_tweak_encdec(datactx, decfunc, S, D, &T);
136db217c69SDaniel P. Berrangé         }
137db217c69SDaniel P. Berrangé     } else {
138db217c69SDaniel P. Berrangé         xts_uint128 D;
13984f7f180SDaniel P. Berrange 
140db217c69SDaniel P. Berrangé         for (i = 0; i < lim; i++) {
141db217c69SDaniel P. Berrangé             memcpy(&D, src, XTS_BLOCK_SIZE);
142db217c69SDaniel P. Berrangé             xts_tweak_encdec(datactx, decfunc, &D, &D, &T);
143db217c69SDaniel P. Berrangé             memcpy(dst, &D, XTS_BLOCK_SIZE);
14484f7f180SDaniel P. Berrange             src += XTS_BLOCK_SIZE;
14584f7f180SDaniel P. Berrange             dst += XTS_BLOCK_SIZE;
14684f7f180SDaniel P. Berrange         }
147db217c69SDaniel P. Berrangé     }
14884f7f180SDaniel P. Berrange 
14984f7f180SDaniel P. Berrange     /* if length is not a multiple of XTS_BLOCK_SIZE then */
15084f7f180SDaniel P. Berrange     if (mo > 0) {
151db217c69SDaniel P. Berrangé         xts_uint128 S, D;
152cc36930eSDaniel P. Berrangé         memcpy(&CC, &T, XTS_BLOCK_SIZE);
1537dac0dd6SDaniel P. Berrangé         xts_mult_x(&CC);
15484f7f180SDaniel P. Berrange 
15584f7f180SDaniel P. Berrange         /* PP = tweak decrypt block m-1 */
156db217c69SDaniel P. Berrangé         memcpy(&S, src, XTS_BLOCK_SIZE);
157db217c69SDaniel P. Berrangé         xts_tweak_encdec(datactx, decfunc, &S, &PP, &CC);
15884f7f180SDaniel P. Berrange 
15984f7f180SDaniel P. Berrange         /* Pm = first length % XTS_BLOCK_SIZE bytes of PP */
16084f7f180SDaniel P. Berrange         for (i = 0; i < mo; i++) {
161cc36930eSDaniel P. Berrangé             CC.b[i] = src[XTS_BLOCK_SIZE + i];
162cc36930eSDaniel P. Berrangé             dst[XTS_BLOCK_SIZE + i] = PP.b[i];
16384f7f180SDaniel P. Berrange         }
16484f7f180SDaniel P. Berrange         for (; i < XTS_BLOCK_SIZE; i++) {
165cc36930eSDaniel P. Berrangé             CC.b[i] = PP.b[i];
16684f7f180SDaniel P. Berrange         }
16784f7f180SDaniel P. Berrange 
16884f7f180SDaniel P. Berrange         /* Pm-1 = Tweak uncrypt CC */
169db217c69SDaniel P. Berrangé         xts_tweak_encdec(datactx, decfunc, &CC, &D, &T);
170db217c69SDaniel P. Berrangé         memcpy(dst, &D, XTS_BLOCK_SIZE);
17184f7f180SDaniel P. Berrange     }
17284f7f180SDaniel P. Berrange 
17384f7f180SDaniel P. Berrange     /* Decrypt the iv back */
174cc36930eSDaniel P. Berrangé     decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b);
17584f7f180SDaniel P. Berrange }
17684f7f180SDaniel P. Berrange 
17784f7f180SDaniel P. Berrange 
xts_encrypt(const void * datactx,const void * tweakctx,xts_cipher_func * encfunc,xts_cipher_func * decfunc,uint8_t * iv,size_t length,uint8_t * dst,const uint8_t * src)17884f7f180SDaniel P. Berrange void xts_encrypt(const void *datactx,
17984f7f180SDaniel P. Berrange                  const void *tweakctx,
18084f7f180SDaniel P. Berrange                  xts_cipher_func *encfunc,
18184f7f180SDaniel P. Berrange                  xts_cipher_func *decfunc,
18284f7f180SDaniel P. Berrange                  uint8_t *iv,
18384f7f180SDaniel P. Berrange                  size_t length,
18484f7f180SDaniel P. Berrange                  uint8_t *dst,
18584f7f180SDaniel P. Berrange                  const uint8_t *src)
18684f7f180SDaniel P. Berrange {
187cc36930eSDaniel P. Berrangé     xts_uint128 PP, CC, T;
18884f7f180SDaniel P. Berrange     unsigned long i, m, mo, lim;
18984f7f180SDaniel P. Berrange 
19084f7f180SDaniel P. Berrange     /* get number of blocks */
19184f7f180SDaniel P. Berrange     m = length >> 4;
19284f7f180SDaniel P. Berrange     mo = length & 15;
19384f7f180SDaniel P. Berrange 
19484f7f180SDaniel P. Berrange     /* must have at least one full block */
19584f7f180SDaniel P. Berrange     g_assert(m != 0);
19684f7f180SDaniel P. Berrange 
19784f7f180SDaniel P. Berrange     if (mo == 0) {
19884f7f180SDaniel P. Berrange         lim = m;
19984f7f180SDaniel P. Berrange     } else {
20084f7f180SDaniel P. Berrange         lim = m - 1;
20184f7f180SDaniel P. Berrange     }
20284f7f180SDaniel P. Berrange 
20384f7f180SDaniel P. Berrange     /* encrypt the iv */
204cc36930eSDaniel P. Berrangé     encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv);
20584f7f180SDaniel P. Berrange 
206db217c69SDaniel P. Berrangé     if (QEMU_PTR_IS_ALIGNED(src, sizeof(uint64_t)) &&
207db217c69SDaniel P. Berrangé         QEMU_PTR_IS_ALIGNED(dst, sizeof(uint64_t))) {
208db217c69SDaniel P. Berrangé         xts_uint128 *S = (xts_uint128 *)src;
209db217c69SDaniel P. Berrangé         xts_uint128 *D = (xts_uint128 *)dst;
210db217c69SDaniel P. Berrangé         for (i = 0; i < lim; i++, S++, D++) {
211db217c69SDaniel P. Berrangé             xts_tweak_encdec(datactx, encfunc, S, D, &T);
212db217c69SDaniel P. Berrangé         }
213db217c69SDaniel P. Berrangé     } else {
214db217c69SDaniel P. Berrangé         xts_uint128 D;
215db217c69SDaniel P. Berrangé 
21684f7f180SDaniel P. Berrange         for (i = 0; i < lim; i++) {
217db217c69SDaniel P. Berrangé             memcpy(&D, src, XTS_BLOCK_SIZE);
218db217c69SDaniel P. Berrangé             xts_tweak_encdec(datactx, encfunc, &D, &D, &T);
219db217c69SDaniel P. Berrangé             memcpy(dst, &D, XTS_BLOCK_SIZE);
22084f7f180SDaniel P. Berrange 
22184f7f180SDaniel P. Berrange             dst += XTS_BLOCK_SIZE;
22284f7f180SDaniel P. Berrange             src += XTS_BLOCK_SIZE;
22384f7f180SDaniel P. Berrange         }
224db217c69SDaniel P. Berrangé     }
22584f7f180SDaniel P. Berrange 
22684f7f180SDaniel P. Berrange     /* if length is not a multiple of XTS_BLOCK_SIZE then */
22784f7f180SDaniel P. Berrange     if (mo > 0) {
228db217c69SDaniel P. Berrangé         xts_uint128 S, D;
22984f7f180SDaniel P. Berrange         /* CC = tweak encrypt block m-1 */
230db217c69SDaniel P. Berrangé         memcpy(&S, src, XTS_BLOCK_SIZE);
231db217c69SDaniel P. Berrangé         xts_tweak_encdec(datactx, encfunc, &S, &CC, &T);
23284f7f180SDaniel P. Berrange 
23384f7f180SDaniel P. Berrange         /* Cm = first length % XTS_BLOCK_SIZE bytes of CC */
23484f7f180SDaniel P. Berrange         for (i = 0; i < mo; i++) {
235cc36930eSDaniel P. Berrangé             PP.b[i] = src[XTS_BLOCK_SIZE + i];
236cc36930eSDaniel P. Berrangé             dst[XTS_BLOCK_SIZE + i] = CC.b[i];
23784f7f180SDaniel P. Berrange         }
23884f7f180SDaniel P. Berrange 
23984f7f180SDaniel P. Berrange         for (; i < XTS_BLOCK_SIZE; i++) {
240cc36930eSDaniel P. Berrangé             PP.b[i] = CC.b[i];
24184f7f180SDaniel P. Berrange         }
24284f7f180SDaniel P. Berrange 
24384f7f180SDaniel P. Berrange         /* Cm-1 = Tweak encrypt PP */
244db217c69SDaniel P. Berrangé         xts_tweak_encdec(datactx, encfunc, &PP, &D, &T);
245db217c69SDaniel P. Berrangé         memcpy(dst, &D, XTS_BLOCK_SIZE);
24684f7f180SDaniel P. Berrange     }
24784f7f180SDaniel P. Berrange 
24884f7f180SDaniel P. Berrange     /* Decrypt the iv back */
249cc36930eSDaniel P. Berrangé     decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b);
25084f7f180SDaniel P. Berrange }
251