xts.c (6831B)
1/* 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 9 * version 2.1 of the License, or (at your option) any later version. 10 * 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" 27#include "qemu/bswap.h" 28#include "crypto/xts.h" 29 30typedef union { 31 uint8_t b[XTS_BLOCK_SIZE]; 32 uint64_t u[2]; 33} xts_uint128; 34 35static 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} 42 43static inline void xts_uint128_cpu_to_les(xts_uint128 *v) 44{ 45 cpu_to_le64s(&v->u[0]); 46 cpu_to_le64s(&v->u[1]); 47} 48 49static 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; 66 } 67 I->u[1] <<= 1; 68 I->u[1] |= tt; 69 70 xts_uint128_cpu_to_les(I); 71} 72 73 74/** 75 * xts_tweak_encdec: 76 * @param ctxt: the cipher context 77 * @param func: the cipher function 78 * @src: buffer providing the input text of XTS_BLOCK_SIZE bytes 79 * @dst: buffer to output the output text of XTS_BLOCK_SIZE bytes 80 * @iv: the initialization vector tweak of XTS_BLOCK_SIZE bytes 81 * 82 * Encrypt/decrypt data with a tweak 83 */ 84static 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) 89{ 90 /* tweak encrypt block i */ 91 xts_uint128_xor(dst, src, iv); 92 93 func(ctx, XTS_BLOCK_SIZE, dst->b, dst->b); 94 95 xts_uint128_xor(dst, dst, iv); 96 97 /* LFSR the tweak */ 98 xts_mult_x(iv); 99} 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{ 111 xts_uint128 PP, CC, T; 112 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 */ 128 encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv); 129 130 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; 139 140 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 } 147 } 148 149 /* if length is not a multiple of XTS_BLOCK_SIZE then */ 150 if (mo > 0) { 151 xts_uint128 S, D; 152 memcpy(&CC, &T, XTS_BLOCK_SIZE); 153 xts_mult_x(&CC); 154 155 /* PP = tweak decrypt block m-1 */ 156 memcpy(&S, src, XTS_BLOCK_SIZE); 157 xts_tweak_encdec(datactx, decfunc, &S, &PP, &CC); 158 159 /* Pm = first length % XTS_BLOCK_SIZE bytes of PP */ 160 for (i = 0; i < mo; i++) { 161 CC.b[i] = src[XTS_BLOCK_SIZE + i]; 162 dst[XTS_BLOCK_SIZE + i] = PP.b[i]; 163 } 164 for (; i < XTS_BLOCK_SIZE; i++) { 165 CC.b[i] = PP.b[i]; 166 } 167 168 /* Pm-1 = Tweak uncrypt CC */ 169 xts_tweak_encdec(datactx, decfunc, &CC, &D, &T); 170 memcpy(dst, &D, XTS_BLOCK_SIZE); 171 } 172 173 /* Decrypt the iv back */ 174 decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b); 175} 176 177 178void 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{ 187 xts_uint128 PP, CC, T; 188 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 */ 204 encfunc(tweakctx, XTS_BLOCK_SIZE, T.b, iv); 205 206 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; 215 216 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 } 224 } 225 226 /* if length is not a multiple of XTS_BLOCK_SIZE then */ 227 if (mo > 0) { 228 xts_uint128 S, D; 229 /* CC = tweak encrypt block m-1 */ 230 memcpy(&S, src, XTS_BLOCK_SIZE); 231 xts_tweak_encdec(datactx, encfunc, &S, &CC, &T); 232 233 /* Cm = first length % XTS_BLOCK_SIZE bytes of CC */ 234 for (i = 0; i < mo; i++) { 235 PP.b[i] = src[XTS_BLOCK_SIZE + i]; 236 dst[XTS_BLOCK_SIZE + i] = CC.b[i]; 237 } 238 239 for (; i < XTS_BLOCK_SIZE; i++) { 240 PP.b[i] = CC.b[i]; 241 } 242 243 /* Cm-1 = Tweak encrypt PP */ 244 xts_tweak_encdec(datactx, encfunc, &PP, &D, &T); 245 memcpy(dst, &D, XTS_BLOCK_SIZE); 246 } 247 248 /* Decrypt the iv back */ 249 decfunc(tweakctx, XTS_BLOCK_SIZE, iv, T.b); 250}