17d969014SDaniel P. Berrange /* 27d969014SDaniel P. Berrange * QEMU Crypto block device encryption 37d969014SDaniel P. Berrange * 47d969014SDaniel P. Berrange * Copyright (c) 2015-2016 Red Hat, Inc. 57d969014SDaniel P. Berrange * 67d969014SDaniel P. Berrange * This library is free software; you can redistribute it and/or 77d969014SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public 87d969014SDaniel P. Berrange * License as published by the Free Software Foundation; either 9b7cbb874SThomas Huth * version 2.1 of the License, or (at your option) any later version. 107d969014SDaniel P. Berrange * 117d969014SDaniel P. Berrange * This library is distributed in the hope that it will be useful, 127d969014SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of 137d969014SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 147d969014SDaniel P. Berrange * Lesser General Public License for more details. 157d969014SDaniel P. Berrange * 167d969014SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public 177d969014SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>. 187d969014SDaniel P. Berrange * 197d969014SDaniel P. Berrange */ 207d969014SDaniel P. Berrange 217d969014SDaniel P. Berrange #include "qemu/osdep.h" 22da34e65cSMarkus Armbruster #include "qapi/error.h" 23*af206c28SStefan Hajnoczi #include "qemu/lockable.h" 24986bc8deSMichael S. Tsirkin #include "blockpriv.h" 25986bc8deSMichael S. Tsirkin #include "block-qcow.h" 26986bc8deSMichael S. Tsirkin #include "block-luks.h" 277d969014SDaniel P. Berrange 287d969014SDaniel P. Berrange static const QCryptoBlockDriver *qcrypto_block_drivers[] = { 297d969014SDaniel P. Berrange [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow, 303e308f20SDaniel P. Berrange [Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks, 317d969014SDaniel P. Berrange }; 327d969014SDaniel P. Berrange 337d969014SDaniel P. Berrange 347d969014SDaniel P. Berrange bool qcrypto_block_has_format(QCryptoBlockFormat format, 357d969014SDaniel P. Berrange const uint8_t *buf, 367d969014SDaniel P. Berrange size_t len) 377d969014SDaniel P. Berrange { 387d969014SDaniel P. Berrange const QCryptoBlockDriver *driver; 397d969014SDaniel P. Berrange 407d969014SDaniel P. Berrange if (format >= G_N_ELEMENTS(qcrypto_block_drivers) || 417d969014SDaniel P. Berrange !qcrypto_block_drivers[format]) { 427d969014SDaniel P. Berrange return false; 437d969014SDaniel P. Berrange } 447d969014SDaniel P. Berrange 457d969014SDaniel P. Berrange driver = qcrypto_block_drivers[format]; 467d969014SDaniel P. Berrange 477d969014SDaniel P. Berrange return driver->has_format(buf, len); 487d969014SDaniel P. Berrange } 497d969014SDaniel P. Berrange 507d969014SDaniel P. Berrange 517d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, 521cd9a787SDaniel P. Berrange const char *optprefix, 537d969014SDaniel P. Berrange QCryptoBlockReadFunc readfunc, 547d969014SDaniel P. Berrange void *opaque, 557d969014SDaniel P. Berrange unsigned int flags, 56c972fa12SVladimir Sementsov-Ogievskiy size_t n_threads, 577d969014SDaniel P. Berrange Error **errp) 587d969014SDaniel P. Berrange { 597d969014SDaniel P. Berrange QCryptoBlock *block = g_new0(QCryptoBlock, 1); 607d969014SDaniel P. Berrange 61*af206c28SStefan Hajnoczi qemu_mutex_init(&block->mutex); 62*af206c28SStefan Hajnoczi 637d969014SDaniel P. Berrange block->format = options->format; 647d969014SDaniel P. Berrange 657d969014SDaniel P. Berrange if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || 667d969014SDaniel P. Berrange !qcrypto_block_drivers[options->format]) { 6790d6f60dSDaniel P. Berrange error_setg(errp, "Unsupported block driver %s", 68977c736fSMarkus Armbruster QCryptoBlockFormat_str(options->format)); 697d969014SDaniel P. Berrange g_free(block); 707d969014SDaniel P. Berrange return NULL; 717d969014SDaniel P. Berrange } 727d969014SDaniel P. Berrange 737d969014SDaniel P. Berrange block->driver = qcrypto_block_drivers[options->format]; 747d969014SDaniel P. Berrange 751cd9a787SDaniel P. Berrange if (block->driver->open(block, options, optprefix, 76c972fa12SVladimir Sementsov-Ogievskiy readfunc, opaque, flags, n_threads, errp) < 0) 77c972fa12SVladimir Sementsov-Ogievskiy { 787d969014SDaniel P. Berrange g_free(block); 797d969014SDaniel P. Berrange return NULL; 807d969014SDaniel P. Berrange } 817d969014SDaniel P. Berrange 827d969014SDaniel P. Berrange return block; 837d969014SDaniel P. Berrange } 847d969014SDaniel P. Berrange 857d969014SDaniel P. Berrange 867d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, 871cd9a787SDaniel P. Berrange const char *optprefix, 887d969014SDaniel P. Berrange QCryptoBlockInitFunc initfunc, 897d969014SDaniel P. Berrange QCryptoBlockWriteFunc writefunc, 907d969014SDaniel P. Berrange void *opaque, 91d74523a3SHyman Huang unsigned int flags, 927d969014SDaniel P. Berrange Error **errp) 937d969014SDaniel P. Berrange { 947d969014SDaniel P. Berrange QCryptoBlock *block = g_new0(QCryptoBlock, 1); 957d969014SDaniel P. Berrange 96*af206c28SStefan Hajnoczi qemu_mutex_init(&block->mutex); 97*af206c28SStefan Hajnoczi 987d969014SDaniel P. Berrange block->format = options->format; 997d969014SDaniel P. Berrange 1007d969014SDaniel P. Berrange if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || 1017d969014SDaniel P. Berrange !qcrypto_block_drivers[options->format]) { 10290d6f60dSDaniel P. Berrange error_setg(errp, "Unsupported block driver %s", 103977c736fSMarkus Armbruster QCryptoBlockFormat_str(options->format)); 1047d969014SDaniel P. Berrange g_free(block); 1057d969014SDaniel P. Berrange return NULL; 1067d969014SDaniel P. Berrange } 1077d969014SDaniel P. Berrange 1087d969014SDaniel P. Berrange block->driver = qcrypto_block_drivers[options->format]; 109d74523a3SHyman Huang block->detached_header = flags & QCRYPTO_BLOCK_CREATE_DETACHED; 1107d969014SDaniel P. Berrange 1111cd9a787SDaniel P. Berrange if (block->driver->create(block, options, optprefix, initfunc, 1127d969014SDaniel P. Berrange writefunc, opaque, errp) < 0) { 1137d969014SDaniel P. Berrange g_free(block); 1147d969014SDaniel P. Berrange return NULL; 1157d969014SDaniel P. Berrange } 1167d969014SDaniel P. Berrange 1177d969014SDaniel P. Berrange return block; 1187d969014SDaniel P. Berrange } 1197d969014SDaniel P. Berrange 1207d969014SDaniel P. Berrange 121757dda54SAlberto Faria static int qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block, 1226d49d3a8SStefan Hajnoczi size_t headerlen, void *opaque, Error **errp) 1236d49d3a8SStefan Hajnoczi { 1246d49d3a8SStefan Hajnoczi size_t *headerlenp = opaque; 1256d49d3a8SStefan Hajnoczi 1266d49d3a8SStefan Hajnoczi /* Stash away the payload size */ 1276d49d3a8SStefan Hajnoczi *headerlenp = headerlen; 1286d49d3a8SStefan Hajnoczi return 0; 1296d49d3a8SStefan Hajnoczi } 1306d49d3a8SStefan Hajnoczi 1316d49d3a8SStefan Hajnoczi 132757dda54SAlberto Faria static int qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block, 1336d49d3a8SStefan Hajnoczi size_t offset, const uint8_t *buf, size_t buflen, 1346d49d3a8SStefan Hajnoczi void *opaque, Error **errp) 1356d49d3a8SStefan Hajnoczi { 1366d49d3a8SStefan Hajnoczi /* Discard the bytes, we're not actually writing to an image */ 137757dda54SAlberto Faria return 0; 1386d49d3a8SStefan Hajnoczi } 1396d49d3a8SStefan Hajnoczi 1406d49d3a8SStefan Hajnoczi 1416d49d3a8SStefan Hajnoczi bool 1426d49d3a8SStefan Hajnoczi qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts, 1436d49d3a8SStefan Hajnoczi const char *optprefix, 1446d49d3a8SStefan Hajnoczi size_t *len, 1456d49d3a8SStefan Hajnoczi Error **errp) 1466d49d3a8SStefan Hajnoczi { 1476d49d3a8SStefan Hajnoczi /* Fake LUKS creation in order to determine the payload size */ 1486d49d3a8SStefan Hajnoczi g_autoptr(QCryptoBlock) crypto = 1496d49d3a8SStefan Hajnoczi qcrypto_block_create(create_opts, optprefix, 1506d49d3a8SStefan Hajnoczi qcrypto_block_headerlen_hdr_init_func, 1516d49d3a8SStefan Hajnoczi qcrypto_block_headerlen_hdr_write_func, 152d74523a3SHyman Huang len, 0, errp); 1536d49d3a8SStefan Hajnoczi return crypto != NULL; 1546d49d3a8SStefan Hajnoczi } 1556d49d3a8SStefan Hajnoczi 15643cbd06dSMaxim Levitsky int qcrypto_block_amend_options(QCryptoBlock *block, 15743cbd06dSMaxim Levitsky QCryptoBlockReadFunc readfunc, 15843cbd06dSMaxim Levitsky QCryptoBlockWriteFunc writefunc, 15943cbd06dSMaxim Levitsky void *opaque, 16043cbd06dSMaxim Levitsky QCryptoBlockAmendOptions *options, 16143cbd06dSMaxim Levitsky bool force, 16243cbd06dSMaxim Levitsky Error **errp) 16343cbd06dSMaxim Levitsky { 16443cbd06dSMaxim Levitsky if (options->format != block->format) { 16543cbd06dSMaxim Levitsky error_setg(errp, 16643cbd06dSMaxim Levitsky "Cannot amend encryption format"); 16743cbd06dSMaxim Levitsky return -1; 16843cbd06dSMaxim Levitsky } 16943cbd06dSMaxim Levitsky 17043cbd06dSMaxim Levitsky if (!block->driver->amend) { 17143cbd06dSMaxim Levitsky error_setg(errp, 17243cbd06dSMaxim Levitsky "Crypto format %s doesn't support format options amendment", 17343cbd06dSMaxim Levitsky QCryptoBlockFormat_str(block->format)); 17443cbd06dSMaxim Levitsky return -1; 17543cbd06dSMaxim Levitsky } 17643cbd06dSMaxim Levitsky 17743cbd06dSMaxim Levitsky return block->driver->amend(block, 17843cbd06dSMaxim Levitsky readfunc, 17943cbd06dSMaxim Levitsky writefunc, 18043cbd06dSMaxim Levitsky opaque, 18143cbd06dSMaxim Levitsky options, 18243cbd06dSMaxim Levitsky force, 18343cbd06dSMaxim Levitsky errp); 18443cbd06dSMaxim Levitsky } 1856d49d3a8SStefan Hajnoczi 18640c85028SDaniel P. Berrange QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block, 18740c85028SDaniel P. Berrange Error **errp) 18840c85028SDaniel P. Berrange { 18940c85028SDaniel P. Berrange QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1); 19040c85028SDaniel P. Berrange 19140c85028SDaniel P. Berrange info->format = block->format; 19240c85028SDaniel P. Berrange 19340c85028SDaniel P. Berrange if (block->driver->get_info && 19440c85028SDaniel P. Berrange block->driver->get_info(block, info, errp) < 0) { 19540c85028SDaniel P. Berrange g_free(info); 19640c85028SDaniel P. Berrange return NULL; 19740c85028SDaniel P. Berrange } 19840c85028SDaniel P. Berrange 19940c85028SDaniel P. Berrange return info; 20040c85028SDaniel P. Berrange } 20140c85028SDaniel P. Berrange 20240c85028SDaniel P. Berrange 2037d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block, 2044609742aSDaniel P. Berrange uint64_t offset, 2057d969014SDaniel P. Berrange uint8_t *buf, 2067d969014SDaniel P. Berrange size_t len, 2077d969014SDaniel P. Berrange Error **errp) 2087d969014SDaniel P. Berrange { 2094609742aSDaniel P. Berrange return block->driver->decrypt(block, offset, buf, len, errp); 2107d969014SDaniel P. Berrange } 2117d969014SDaniel P. Berrange 2127d969014SDaniel P. Berrange 2137d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block, 2144609742aSDaniel P. Berrange uint64_t offset, 2157d969014SDaniel P. Berrange uint8_t *buf, 2167d969014SDaniel P. Berrange size_t len, 2177d969014SDaniel P. Berrange Error **errp) 2187d969014SDaniel P. Berrange { 2194609742aSDaniel P. Berrange return block->driver->encrypt(block, offset, buf, len, errp); 2207d969014SDaniel P. Berrange } 2217d969014SDaniel P. Berrange 2227d969014SDaniel P. Berrange 2237d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block) 2247d969014SDaniel P. Berrange { 225c972fa12SVladimir Sementsov-Ogievskiy /* Ciphers should be accessed through pop/push method to be thread-safe. 226c972fa12SVladimir Sementsov-Ogievskiy * Better, they should not be accessed externally at all (note, that 227c972fa12SVladimir Sementsov-Ogievskiy * pop/push are static functions) 228c972fa12SVladimir Sementsov-Ogievskiy * This function is used only in test with one thread (it's safe to skip 229c972fa12SVladimir Sementsov-Ogievskiy * pop/push interface), so it's enough to assert it here: 230c972fa12SVladimir Sementsov-Ogievskiy */ 231*af206c28SStefan Hajnoczi assert(block->max_free_ciphers <= 1); 232*af206c28SStefan Hajnoczi return block->free_ciphers ? block->free_ciphers[0] : NULL; 2337d969014SDaniel P. Berrange } 2347d969014SDaniel P. Berrange 2357d969014SDaniel P. Berrange 236*af206c28SStefan Hajnoczi static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block, 237*af206c28SStefan Hajnoczi Error **errp) 238c972fa12SVladimir Sementsov-Ogievskiy { 239*af206c28SStefan Hajnoczi /* Usually there is a free cipher available */ 240*af206c28SStefan Hajnoczi WITH_QEMU_LOCK_GUARD(&block->mutex) { 241*af206c28SStefan Hajnoczi if (block->n_free_ciphers > 0) { 242c972fa12SVladimir Sementsov-Ogievskiy block->n_free_ciphers--; 243*af206c28SStefan Hajnoczi return block->free_ciphers[block->n_free_ciphers]; 244*af206c28SStefan Hajnoczi } 245*af206c28SStefan Hajnoczi } 246c972fa12SVladimir Sementsov-Ogievskiy 247*af206c28SStefan Hajnoczi /* Otherwise allocate a new cipher */ 248*af206c28SStefan Hajnoczi return qcrypto_cipher_new(block->alg, block->mode, block->key, 249*af206c28SStefan Hajnoczi block->nkey, errp); 250c972fa12SVladimir Sementsov-Ogievskiy } 251c972fa12SVladimir Sementsov-Ogievskiy 252c972fa12SVladimir Sementsov-Ogievskiy 253c972fa12SVladimir Sementsov-Ogievskiy static void qcrypto_block_push_cipher(QCryptoBlock *block, 254c972fa12SVladimir Sementsov-Ogievskiy QCryptoCipher *cipher) 255c972fa12SVladimir Sementsov-Ogievskiy { 256*af206c28SStefan Hajnoczi QEMU_LOCK_GUARD(&block->mutex); 257c972fa12SVladimir Sementsov-Ogievskiy 258*af206c28SStefan Hajnoczi if (block->n_free_ciphers == block->max_free_ciphers) { 259*af206c28SStefan Hajnoczi block->max_free_ciphers++; 260*af206c28SStefan Hajnoczi block->free_ciphers = g_renew(QCryptoCipher *, 261*af206c28SStefan Hajnoczi block->free_ciphers, 262*af206c28SStefan Hajnoczi block->max_free_ciphers); 263*af206c28SStefan Hajnoczi } 264*af206c28SStefan Hajnoczi 265*af206c28SStefan Hajnoczi block->free_ciphers[block->n_free_ciphers] = cipher; 266c972fa12SVladimir Sementsov-Ogievskiy block->n_free_ciphers++; 267c972fa12SVladimir Sementsov-Ogievskiy } 268c972fa12SVladimir Sementsov-Ogievskiy 269c972fa12SVladimir Sementsov-Ogievskiy 270c972fa12SVladimir Sementsov-Ogievskiy int qcrypto_block_init_cipher(QCryptoBlock *block, 271c972fa12SVladimir Sementsov-Ogievskiy QCryptoCipherAlgorithm alg, 272c972fa12SVladimir Sementsov-Ogievskiy QCryptoCipherMode mode, 273c972fa12SVladimir Sementsov-Ogievskiy const uint8_t *key, size_t nkey, 274*af206c28SStefan Hajnoczi Error **errp) 275c972fa12SVladimir Sementsov-Ogievskiy { 276*af206c28SStefan Hajnoczi QCryptoCipher *cipher; 277c972fa12SVladimir Sementsov-Ogievskiy 278*af206c28SStefan Hajnoczi assert(!block->free_ciphers && !block->max_free_ciphers && 279*af206c28SStefan Hajnoczi !block->n_free_ciphers); 280c972fa12SVladimir Sementsov-Ogievskiy 281*af206c28SStefan Hajnoczi /* Stash away cipher parameters for qcrypto_block_pop_cipher() */ 282*af206c28SStefan Hajnoczi block->alg = alg; 283*af206c28SStefan Hajnoczi block->mode = mode; 284*af206c28SStefan Hajnoczi block->key = g_memdup2(key, nkey); 285*af206c28SStefan Hajnoczi block->nkey = nkey; 286c972fa12SVladimir Sementsov-Ogievskiy 287*af206c28SStefan Hajnoczi /* 288*af206c28SStefan Hajnoczi * Create a new cipher to validate the parameters now. This reduces the 289*af206c28SStefan Hajnoczi * chance of cipher creation failing at I/O time. 290*af206c28SStefan Hajnoczi */ 291*af206c28SStefan Hajnoczi cipher = qcrypto_block_pop_cipher(block, errp); 292*af206c28SStefan Hajnoczi if (!cipher) { 293*af206c28SStefan Hajnoczi g_free(block->key); 294*af206c28SStefan Hajnoczi block->key = NULL; 295c972fa12SVladimir Sementsov-Ogievskiy return -1; 296c972fa12SVladimir Sementsov-Ogievskiy } 297c972fa12SVladimir Sementsov-Ogievskiy 298*af206c28SStefan Hajnoczi qcrypto_block_push_cipher(block, cipher); 299c972fa12SVladimir Sementsov-Ogievskiy return 0; 300c972fa12SVladimir Sementsov-Ogievskiy } 301c972fa12SVladimir Sementsov-Ogievskiy 302c972fa12SVladimir Sementsov-Ogievskiy 303c972fa12SVladimir Sementsov-Ogievskiy void qcrypto_block_free_cipher(QCryptoBlock *block) 304c972fa12SVladimir Sementsov-Ogievskiy { 305c972fa12SVladimir Sementsov-Ogievskiy size_t i; 306c972fa12SVladimir Sementsov-Ogievskiy 307*af206c28SStefan Hajnoczi g_free(block->key); 308*af206c28SStefan Hajnoczi block->key = NULL; 309*af206c28SStefan Hajnoczi 310*af206c28SStefan Hajnoczi if (!block->free_ciphers) { 311c972fa12SVladimir Sementsov-Ogievskiy return; 312c972fa12SVladimir Sementsov-Ogievskiy } 313c972fa12SVladimir Sementsov-Ogievskiy 314*af206c28SStefan Hajnoczi /* All popped ciphers were eventually pushed back */ 315*af206c28SStefan Hajnoczi assert(block->n_free_ciphers == block->max_free_ciphers); 316c972fa12SVladimir Sementsov-Ogievskiy 317*af206c28SStefan Hajnoczi for (i = 0; i < block->max_free_ciphers; i++) { 318*af206c28SStefan Hajnoczi qcrypto_cipher_free(block->free_ciphers[i]); 319c972fa12SVladimir Sementsov-Ogievskiy } 320c972fa12SVladimir Sementsov-Ogievskiy 321*af206c28SStefan Hajnoczi g_free(block->free_ciphers); 322*af206c28SStefan Hajnoczi block->free_ciphers = NULL; 323*af206c28SStefan Hajnoczi block->max_free_ciphers = block->n_free_ciphers = 0; 324c972fa12SVladimir Sementsov-Ogievskiy } 325c972fa12SVladimir Sementsov-Ogievskiy 3267d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block) 3277d969014SDaniel P. Berrange { 328c972fa12SVladimir Sementsov-Ogievskiy /* ivgen should be accessed under mutex. However, this function is used only 329c972fa12SVladimir Sementsov-Ogievskiy * in test with one thread, so it's enough to assert it here: 330c972fa12SVladimir Sementsov-Ogievskiy */ 331*af206c28SStefan Hajnoczi assert(block->max_free_ciphers <= 1); 3327d969014SDaniel P. Berrange return block->ivgen; 3337d969014SDaniel P. Berrange } 3347d969014SDaniel P. Berrange 3357d969014SDaniel P. Berrange 3367d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block) 3377d969014SDaniel P. Berrange { 3387d969014SDaniel P. Berrange return block->kdfhash; 3397d969014SDaniel P. Berrange } 3407d969014SDaniel P. Berrange 3417d969014SDaniel P. Berrange 3427d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block) 3437d969014SDaniel P. Berrange { 3447d969014SDaniel P. Berrange return block->payload_offset; 3457d969014SDaniel P. Berrange } 3467d969014SDaniel P. Berrange 3477d969014SDaniel P. Berrange 348850f49deSDaniel P. Berrange uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block) 349850f49deSDaniel P. Berrange { 350850f49deSDaniel P. Berrange return block->sector_size; 351850f49deSDaniel P. Berrange } 352850f49deSDaniel P. Berrange 353850f49deSDaniel P. Berrange 3547d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block) 3557d969014SDaniel P. Berrange { 3567d969014SDaniel P. Berrange if (!block) { 3577d969014SDaniel P. Berrange return; 3587d969014SDaniel P. Berrange } 3597d969014SDaniel P. Berrange 3607d969014SDaniel P. Berrange block->driver->cleanup(block); 3617d969014SDaniel P. Berrange 362c972fa12SVladimir Sementsov-Ogievskiy qcrypto_block_free_cipher(block); 3637d969014SDaniel P. Berrange qcrypto_ivgen_free(block->ivgen); 364c972fa12SVladimir Sementsov-Ogievskiy qemu_mutex_destroy(&block->mutex); 3657d969014SDaniel P. Berrange g_free(block); 3667d969014SDaniel P. Berrange } 3677d969014SDaniel P. Berrange 3687d969014SDaniel P. Berrange 3691dc57b60SVladimir Sementsov-Ogievskiy typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher, 3701dc57b60SVladimir Sementsov-Ogievskiy const void *in, 3711dc57b60SVladimir Sementsov-Ogievskiy void *out, 3721dc57b60SVladimir Sementsov-Ogievskiy size_t len, 3731dc57b60SVladimir Sementsov-Ogievskiy Error **errp); 3741dc57b60SVladimir Sementsov-Ogievskiy 3750270417cSVladimir Sementsov-Ogievskiy static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher, 3767d969014SDaniel P. Berrange size_t niv, 3777d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 378c972fa12SVladimir Sementsov-Ogievskiy QemuMutex *ivgen_mutex, 3797d969014SDaniel P. Berrange int sectorsize, 3804609742aSDaniel P. Berrange uint64_t offset, 3817d969014SDaniel P. Berrange uint8_t *buf, 3827d969014SDaniel P. Berrange size_t len, 3831dc57b60SVladimir Sementsov-Ogievskiy QCryptoCipherEncDecFunc func, 3847d969014SDaniel P. Berrange Error **errp) 3857d969014SDaniel P. Berrange { 38657b9f113SDaniel P. Berrangé g_autofree uint8_t *iv = niv ? g_new0(uint8_t, niv) : NULL; 3877d969014SDaniel P. Berrange int ret = -1; 3884609742aSDaniel P. Berrange uint64_t startsector = offset / sectorsize; 3894609742aSDaniel P. Berrange 3904609742aSDaniel P. Berrange assert(QEMU_IS_ALIGNED(offset, sectorsize)); 3914609742aSDaniel P. Berrange assert(QEMU_IS_ALIGNED(len, sectorsize)); 3927d969014SDaniel P. Berrange 3937d969014SDaniel P. Berrange while (len > 0) { 3947d969014SDaniel P. Berrange size_t nbytes; 3957d969014SDaniel P. Berrange if (niv) { 396c972fa12SVladimir Sementsov-Ogievskiy if (ivgen_mutex) { 397c972fa12SVladimir Sementsov-Ogievskiy qemu_mutex_lock(ivgen_mutex); 398c972fa12SVladimir Sementsov-Ogievskiy } 399c972fa12SVladimir Sementsov-Ogievskiy ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp); 400c972fa12SVladimir Sementsov-Ogievskiy if (ivgen_mutex) { 401c972fa12SVladimir Sementsov-Ogievskiy qemu_mutex_unlock(ivgen_mutex); 402c972fa12SVladimir Sementsov-Ogievskiy } 403c972fa12SVladimir Sementsov-Ogievskiy 404c972fa12SVladimir Sementsov-Ogievskiy if (ret < 0) { 40557b9f113SDaniel P. Berrangé return -1; 4067d969014SDaniel P. Berrange } 4077d969014SDaniel P. Berrange 4087d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 4097d969014SDaniel P. Berrange iv, niv, 4107d969014SDaniel P. Berrange errp) < 0) { 41157b9f113SDaniel P. Berrangé return -1; 4127d969014SDaniel P. Berrange } 4137d969014SDaniel P. Berrange } 4147d969014SDaniel P. Berrange 4157d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 4161dc57b60SVladimir Sementsov-Ogievskiy if (func(cipher, buf, buf, nbytes, errp) < 0) { 41757b9f113SDaniel P. Berrangé return -1; 4187d969014SDaniel P. Berrange } 4197d969014SDaniel P. Berrange 4207d969014SDaniel P. Berrange startsector++; 4217d969014SDaniel P. Berrange buf += nbytes; 4227d969014SDaniel P. Berrange len -= nbytes; 4237d969014SDaniel P. Berrange } 4247d969014SDaniel P. Berrange 42557b9f113SDaniel P. Berrangé return 0; 4267d969014SDaniel P. Berrange } 4277d969014SDaniel P. Berrange 4287d969014SDaniel P. Berrange 4290270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher, 4301dc57b60SVladimir Sementsov-Ogievskiy size_t niv, 4311dc57b60SVladimir Sementsov-Ogievskiy QCryptoIVGen *ivgen, 4321dc57b60SVladimir Sementsov-Ogievskiy int sectorsize, 4331dc57b60SVladimir Sementsov-Ogievskiy uint64_t offset, 4341dc57b60SVladimir Sementsov-Ogievskiy uint8_t *buf, 4351dc57b60SVladimir Sementsov-Ogievskiy size_t len, 4361dc57b60SVladimir Sementsov-Ogievskiy Error **errp) 4371dc57b60SVladimir Sementsov-Ogievskiy { 438c972fa12SVladimir Sementsov-Ogievskiy return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize, 4390270417cSVladimir Sementsov-Ogievskiy offset, buf, len, 4400270417cSVladimir Sementsov-Ogievskiy qcrypto_cipher_decrypt, errp); 4411dc57b60SVladimir Sementsov-Ogievskiy } 4421dc57b60SVladimir Sementsov-Ogievskiy 4431dc57b60SVladimir Sementsov-Ogievskiy 4440270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher, 4457d969014SDaniel P. Berrange size_t niv, 4467d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 4477d969014SDaniel P. Berrange int sectorsize, 4484609742aSDaniel P. Berrange uint64_t offset, 4497d969014SDaniel P. Berrange uint8_t *buf, 4507d969014SDaniel P. Berrange size_t len, 4517d969014SDaniel P. Berrange Error **errp) 4527d969014SDaniel P. Berrange { 453c972fa12SVladimir Sementsov-Ogievskiy return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize, 4540270417cSVladimir Sementsov-Ogievskiy offset, buf, len, 4550270417cSVladimir Sementsov-Ogievskiy qcrypto_cipher_encrypt, errp); 4567d969014SDaniel P. Berrange } 4570f0d596cSVladimir Sementsov-Ogievskiy 4580f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_decrypt_helper(QCryptoBlock *block, 4590f0d596cSVladimir Sementsov-Ogievskiy int sectorsize, 4600f0d596cSVladimir Sementsov-Ogievskiy uint64_t offset, 4610f0d596cSVladimir Sementsov-Ogievskiy uint8_t *buf, 4620f0d596cSVladimir Sementsov-Ogievskiy size_t len, 4630f0d596cSVladimir Sementsov-Ogievskiy Error **errp) 4640f0d596cSVladimir Sementsov-Ogievskiy { 465c972fa12SVladimir Sementsov-Ogievskiy int ret; 466*af206c28SStefan Hajnoczi QCryptoCipher *cipher = qcrypto_block_pop_cipher(block, errp); 467*af206c28SStefan Hajnoczi if (!cipher) { 468*af206c28SStefan Hajnoczi return -1; 469*af206c28SStefan Hajnoczi } 4700f0d596cSVladimir Sementsov-Ogievskiy 471c972fa12SVladimir Sementsov-Ogievskiy ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen, 472c972fa12SVladimir Sementsov-Ogievskiy &block->mutex, sectorsize, offset, buf, 473c972fa12SVladimir Sementsov-Ogievskiy len, qcrypto_cipher_decrypt, errp); 474c972fa12SVladimir Sementsov-Ogievskiy 475c972fa12SVladimir Sementsov-Ogievskiy qcrypto_block_push_cipher(block, cipher); 476c972fa12SVladimir Sementsov-Ogievskiy 477c972fa12SVladimir Sementsov-Ogievskiy return ret; 478c972fa12SVladimir Sementsov-Ogievskiy } 4790f0d596cSVladimir Sementsov-Ogievskiy 4800f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_encrypt_helper(QCryptoBlock *block, 4810f0d596cSVladimir Sementsov-Ogievskiy int sectorsize, 4820f0d596cSVladimir Sementsov-Ogievskiy uint64_t offset, 4830f0d596cSVladimir Sementsov-Ogievskiy uint8_t *buf, 4840f0d596cSVladimir Sementsov-Ogievskiy size_t len, 4850f0d596cSVladimir Sementsov-Ogievskiy Error **errp) 4860f0d596cSVladimir Sementsov-Ogievskiy { 487c972fa12SVladimir Sementsov-Ogievskiy int ret; 488*af206c28SStefan Hajnoczi QCryptoCipher *cipher = qcrypto_block_pop_cipher(block, errp); 489*af206c28SStefan Hajnoczi if (!cipher) { 490*af206c28SStefan Hajnoczi return -1; 491*af206c28SStefan Hajnoczi } 492c972fa12SVladimir Sementsov-Ogievskiy 493c972fa12SVladimir Sementsov-Ogievskiy ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen, 494c972fa12SVladimir Sementsov-Ogievskiy &block->mutex, sectorsize, offset, buf, 495c972fa12SVladimir Sementsov-Ogievskiy len, qcrypto_cipher_encrypt, errp); 496c972fa12SVladimir Sementsov-Ogievskiy 497c972fa12SVladimir Sementsov-Ogievskiy qcrypto_block_push_cipher(block, cipher); 498c972fa12SVladimir Sementsov-Ogievskiy 499c972fa12SVladimir Sementsov-Ogievskiy return ret; 5000f0d596cSVladimir Sementsov-Ogievskiy } 501