qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 422 lines 12 kB view raw
1/* 2 * QEMU Crypto cipher libgcrypt algorithms 3 * 4 * Copyright (c) 2015 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 */ 20 21#include "qemu/osdep.h" 22#ifdef CONFIG_QEMU_PRIVATE_XTS 23#include "crypto/xts.h" 24#endif 25#include "cipherpriv.h" 26 27#include <gcrypt.h> 28 29 30bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, 31 QCryptoCipherMode mode) 32{ 33 switch (alg) { 34 case QCRYPTO_CIPHER_ALG_DES_RFB: 35 case QCRYPTO_CIPHER_ALG_3DES: 36 case QCRYPTO_CIPHER_ALG_AES_128: 37 case QCRYPTO_CIPHER_ALG_AES_192: 38 case QCRYPTO_CIPHER_ALG_AES_256: 39 case QCRYPTO_CIPHER_ALG_CAST5_128: 40 case QCRYPTO_CIPHER_ALG_SERPENT_128: 41 case QCRYPTO_CIPHER_ALG_SERPENT_192: 42 case QCRYPTO_CIPHER_ALG_SERPENT_256: 43 case QCRYPTO_CIPHER_ALG_TWOFISH_128: 44 case QCRYPTO_CIPHER_ALG_TWOFISH_256: 45 break; 46 default: 47 return false; 48 } 49 50 switch (mode) { 51 case QCRYPTO_CIPHER_MODE_ECB: 52 case QCRYPTO_CIPHER_MODE_CBC: 53 case QCRYPTO_CIPHER_MODE_XTS: 54 case QCRYPTO_CIPHER_MODE_CTR: 55 return true; 56 default: 57 return false; 58 } 59} 60 61typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; 62struct QCryptoCipherGcrypt { 63 gcry_cipher_hd_t handle; 64 size_t blocksize; 65#ifdef CONFIG_QEMU_PRIVATE_XTS 66 gcry_cipher_hd_t tweakhandle; 67 /* Initialization vector or Counter */ 68 uint8_t *iv; 69#endif 70}; 71 72static void 73qcrypto_gcrypt_cipher_free_ctx(QCryptoCipherGcrypt *ctx, 74 QCryptoCipherMode mode) 75{ 76 if (!ctx) { 77 return; 78 } 79 80 gcry_cipher_close(ctx->handle); 81#ifdef CONFIG_QEMU_PRIVATE_XTS 82 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 83 gcry_cipher_close(ctx->tweakhandle); 84 } 85 g_free(ctx->iv); 86#endif 87 g_free(ctx); 88} 89 90 91static QCryptoCipherGcrypt *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, 92 QCryptoCipherMode mode, 93 const uint8_t *key, 94 size_t nkey, 95 Error **errp) 96{ 97 QCryptoCipherGcrypt *ctx; 98 gcry_error_t err; 99 int gcryalg, gcrymode; 100 101 switch (mode) { 102 case QCRYPTO_CIPHER_MODE_ECB: 103 gcrymode = GCRY_CIPHER_MODE_ECB; 104 break; 105 case QCRYPTO_CIPHER_MODE_XTS: 106#ifdef CONFIG_QEMU_PRIVATE_XTS 107 gcrymode = GCRY_CIPHER_MODE_ECB; 108#else 109 gcrymode = GCRY_CIPHER_MODE_XTS; 110#endif 111 break; 112 case QCRYPTO_CIPHER_MODE_CBC: 113 gcrymode = GCRY_CIPHER_MODE_CBC; 114 break; 115 case QCRYPTO_CIPHER_MODE_CTR: 116 gcrymode = GCRY_CIPHER_MODE_CTR; 117 break; 118 default: 119 error_setg(errp, "Unsupported cipher mode %s", 120 QCryptoCipherMode_str(mode)); 121 return NULL; 122 } 123 124 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { 125 return NULL; 126 } 127 128 switch (alg) { 129 case QCRYPTO_CIPHER_ALG_DES_RFB: 130 gcryalg = GCRY_CIPHER_DES; 131 break; 132 133 case QCRYPTO_CIPHER_ALG_3DES: 134 gcryalg = GCRY_CIPHER_3DES; 135 break; 136 137 case QCRYPTO_CIPHER_ALG_AES_128: 138 gcryalg = GCRY_CIPHER_AES128; 139 break; 140 141 case QCRYPTO_CIPHER_ALG_AES_192: 142 gcryalg = GCRY_CIPHER_AES192; 143 break; 144 145 case QCRYPTO_CIPHER_ALG_AES_256: 146 gcryalg = GCRY_CIPHER_AES256; 147 break; 148 149 case QCRYPTO_CIPHER_ALG_CAST5_128: 150 gcryalg = GCRY_CIPHER_CAST5; 151 break; 152 153 case QCRYPTO_CIPHER_ALG_SERPENT_128: 154 gcryalg = GCRY_CIPHER_SERPENT128; 155 break; 156 157 case QCRYPTO_CIPHER_ALG_SERPENT_192: 158 gcryalg = GCRY_CIPHER_SERPENT192; 159 break; 160 161 case QCRYPTO_CIPHER_ALG_SERPENT_256: 162 gcryalg = GCRY_CIPHER_SERPENT256; 163 break; 164 165 case QCRYPTO_CIPHER_ALG_TWOFISH_128: 166 gcryalg = GCRY_CIPHER_TWOFISH128; 167 break; 168 169 case QCRYPTO_CIPHER_ALG_TWOFISH_256: 170 gcryalg = GCRY_CIPHER_TWOFISH; 171 break; 172 173 default: 174 error_setg(errp, "Unsupported cipher algorithm %s", 175 QCryptoCipherAlgorithm_str(alg)); 176 return NULL; 177 } 178 179 ctx = g_new0(QCryptoCipherGcrypt, 1); 180 181 err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0); 182 if (err != 0) { 183 error_setg(errp, "Cannot initialize cipher: %s", 184 gcry_strerror(err)); 185 goto error; 186 } 187#ifdef CONFIG_QEMU_PRIVATE_XTS 188 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 189 err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0); 190 if (err != 0) { 191 error_setg(errp, "Cannot initialize cipher: %s", 192 gcry_strerror(err)); 193 goto error; 194 } 195 } 196#endif 197 198 if (alg == QCRYPTO_CIPHER_ALG_DES_RFB) { 199 /* We're using standard DES cipher from gcrypt, so we need 200 * to munge the key so that the results are the same as the 201 * bizarre RFB variant of DES :-) 202 */ 203 uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); 204 err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey); 205 g_free(rfbkey); 206 ctx->blocksize = 8; 207 } else { 208#ifdef CONFIG_QEMU_PRIVATE_XTS 209 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 210 nkey /= 2; 211 err = gcry_cipher_setkey(ctx->handle, key, nkey); 212 if (err != 0) { 213 error_setg(errp, "Cannot set key: %s", 214 gcry_strerror(err)); 215 goto error; 216 } 217 err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey); 218 } else { 219#endif 220 err = gcry_cipher_setkey(ctx->handle, key, nkey); 221#ifdef CONFIG_QEMU_PRIVATE_XTS 222 } 223#endif 224 if (err != 0) { 225 error_setg(errp, "Cannot set key: %s", 226 gcry_strerror(err)); 227 goto error; 228 } 229 switch (alg) { 230 case QCRYPTO_CIPHER_ALG_AES_128: 231 case QCRYPTO_CIPHER_ALG_AES_192: 232 case QCRYPTO_CIPHER_ALG_AES_256: 233 case QCRYPTO_CIPHER_ALG_SERPENT_128: 234 case QCRYPTO_CIPHER_ALG_SERPENT_192: 235 case QCRYPTO_CIPHER_ALG_SERPENT_256: 236 case QCRYPTO_CIPHER_ALG_TWOFISH_128: 237 case QCRYPTO_CIPHER_ALG_TWOFISH_256: 238 ctx->blocksize = 16; 239 break; 240 case QCRYPTO_CIPHER_ALG_3DES: 241 case QCRYPTO_CIPHER_ALG_CAST5_128: 242 ctx->blocksize = 8; 243 break; 244 default: 245 g_assert_not_reached(); 246 } 247 } 248 249#ifdef CONFIG_QEMU_PRIVATE_XTS 250 if (mode == QCRYPTO_CIPHER_MODE_XTS) { 251 if (ctx->blocksize != XTS_BLOCK_SIZE) { 252 error_setg(errp, 253 "Cipher block size %zu must equal XTS block size %d", 254 ctx->blocksize, XTS_BLOCK_SIZE); 255 goto error; 256 } 257 ctx->iv = g_new0(uint8_t, ctx->blocksize); 258 } 259#endif 260 261 return ctx; 262 263 error: 264 qcrypto_gcrypt_cipher_free_ctx(ctx, mode); 265 return NULL; 266} 267 268 269static void 270qcrypto_gcrypt_cipher_ctx_free(QCryptoCipher *cipher) 271{ 272 qcrypto_gcrypt_cipher_free_ctx(cipher->opaque, cipher->mode); 273} 274 275 276#ifdef CONFIG_QEMU_PRIVATE_XTS 277static void qcrypto_gcrypt_xts_encrypt(const void *ctx, 278 size_t length, 279 uint8_t *dst, 280 const uint8_t *src) 281{ 282 gcry_error_t err; 283 err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); 284 g_assert(err == 0); 285} 286 287static void qcrypto_gcrypt_xts_decrypt(const void *ctx, 288 size_t length, 289 uint8_t *dst, 290 const uint8_t *src) 291{ 292 gcry_error_t err; 293 err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length); 294 g_assert(err == 0); 295} 296#endif 297 298static int 299qcrypto_gcrypt_cipher_encrypt(QCryptoCipher *cipher, 300 const void *in, 301 void *out, 302 size_t len, 303 Error **errp) 304{ 305 QCryptoCipherGcrypt *ctx = cipher->opaque; 306 gcry_error_t err; 307 308 if (len % ctx->blocksize) { 309 error_setg(errp, "Length %zu must be a multiple of block size %zu", 310 len, ctx->blocksize); 311 return -1; 312 } 313 314#ifdef CONFIG_QEMU_PRIVATE_XTS 315 if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { 316 xts_encrypt(ctx->handle, ctx->tweakhandle, 317 qcrypto_gcrypt_xts_encrypt, 318 qcrypto_gcrypt_xts_decrypt, 319 ctx->iv, len, out, in); 320 return 0; 321 } 322#endif 323 324 err = gcry_cipher_encrypt(ctx->handle, 325 out, len, 326 in, len); 327 if (err != 0) { 328 error_setg(errp, "Cannot encrypt data: %s", 329 gcry_strerror(err)); 330 return -1; 331 } 332 333 return 0; 334} 335 336 337static int 338qcrypto_gcrypt_cipher_decrypt(QCryptoCipher *cipher, 339 const void *in, 340 void *out, 341 size_t len, 342 Error **errp) 343{ 344 QCryptoCipherGcrypt *ctx = cipher->opaque; 345 gcry_error_t err; 346 347 if (len % ctx->blocksize) { 348 error_setg(errp, "Length %zu must be a multiple of block size %zu", 349 len, ctx->blocksize); 350 return -1; 351 } 352 353#ifdef CONFIG_QEMU_PRIVATE_XTS 354 if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) { 355 xts_decrypt(ctx->handle, ctx->tweakhandle, 356 qcrypto_gcrypt_xts_encrypt, 357 qcrypto_gcrypt_xts_decrypt, 358 ctx->iv, len, out, in); 359 return 0; 360 } 361#endif 362 363 err = gcry_cipher_decrypt(ctx->handle, 364 out, len, 365 in, len); 366 if (err != 0) { 367 error_setg(errp, "Cannot decrypt data: %s", 368 gcry_strerror(err)); 369 return -1; 370 } 371 372 return 0; 373} 374 375static int 376qcrypto_gcrypt_cipher_setiv(QCryptoCipher *cipher, 377 const uint8_t *iv, size_t niv, 378 Error **errp) 379{ 380 QCryptoCipherGcrypt *ctx = cipher->opaque; 381 gcry_error_t err; 382 383 if (niv != ctx->blocksize) { 384 error_setg(errp, "Expected IV size %zu not %zu", 385 ctx->blocksize, niv); 386 return -1; 387 } 388 389#ifdef CONFIG_QEMU_PRIVATE_XTS 390 if (ctx->iv) { 391 memcpy(ctx->iv, iv, niv); 392 return 0; 393 } 394#endif 395 396 if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) { 397 err = gcry_cipher_setctr(ctx->handle, iv, niv); 398 if (err != 0) { 399 error_setg(errp, "Cannot set Counter: %s", 400 gcry_strerror(err)); 401 return -1; 402 } 403 } else { 404 gcry_cipher_reset(ctx->handle); 405 err = gcry_cipher_setiv(ctx->handle, iv, niv); 406 if (err != 0) { 407 error_setg(errp, "Cannot set IV: %s", 408 gcry_strerror(err)); 409 return -1; 410 } 411 } 412 413 return 0; 414} 415 416 417static struct QCryptoCipherDriver qcrypto_cipher_lib_driver = { 418 .cipher_encrypt = qcrypto_gcrypt_cipher_encrypt, 419 .cipher_decrypt = qcrypto_gcrypt_cipher_decrypt, 420 .cipher_setiv = qcrypto_gcrypt_cipher_setiv, 421 .cipher_free = qcrypto_gcrypt_cipher_ctx_free, 422};