xref: /openbmc/qemu/crypto/block.c (revision d74523a3b395dc8470177dcdfa13644b98494334)
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"
23986bc8deSMichael S. Tsirkin #include "blockpriv.h"
24986bc8deSMichael S. Tsirkin #include "block-qcow.h"
25986bc8deSMichael S. Tsirkin #include "block-luks.h"
267d969014SDaniel P. Berrange 
277d969014SDaniel P. Berrange static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
287d969014SDaniel P. Berrange     [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
293e308f20SDaniel P. Berrange     [Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
307d969014SDaniel P. Berrange };
317d969014SDaniel P. Berrange 
327d969014SDaniel P. Berrange 
337d969014SDaniel P. Berrange bool qcrypto_block_has_format(QCryptoBlockFormat format,
347d969014SDaniel P. Berrange                               const uint8_t *buf,
357d969014SDaniel P. Berrange                               size_t len)
367d969014SDaniel P. Berrange {
377d969014SDaniel P. Berrange     const QCryptoBlockDriver *driver;
387d969014SDaniel P. Berrange 
397d969014SDaniel P. Berrange     if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
407d969014SDaniel P. Berrange         !qcrypto_block_drivers[format]) {
417d969014SDaniel P. Berrange         return false;
427d969014SDaniel P. Berrange     }
437d969014SDaniel P. Berrange 
447d969014SDaniel P. Berrange     driver = qcrypto_block_drivers[format];
457d969014SDaniel P. Berrange 
467d969014SDaniel P. Berrange     return driver->has_format(buf, len);
477d969014SDaniel P. Berrange }
487d969014SDaniel P. Berrange 
497d969014SDaniel P. Berrange 
507d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
511cd9a787SDaniel P. Berrange                                  const char *optprefix,
527d969014SDaniel P. Berrange                                  QCryptoBlockReadFunc readfunc,
537d969014SDaniel P. Berrange                                  void *opaque,
547d969014SDaniel P. Berrange                                  unsigned int flags,
55c972fa12SVladimir Sementsov-Ogievskiy                                  size_t n_threads,
567d969014SDaniel P. Berrange                                  Error **errp)
577d969014SDaniel P. Berrange {
587d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
597d969014SDaniel P. Berrange 
607d969014SDaniel P. Berrange     block->format = options->format;
617d969014SDaniel P. Berrange 
627d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
637d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
6490d6f60dSDaniel P. Berrange         error_setg(errp, "Unsupported block driver %s",
65977c736fSMarkus Armbruster                    QCryptoBlockFormat_str(options->format));
667d969014SDaniel P. Berrange         g_free(block);
677d969014SDaniel P. Berrange         return NULL;
687d969014SDaniel P. Berrange     }
697d969014SDaniel P. Berrange 
707d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
717d969014SDaniel P. Berrange 
721cd9a787SDaniel P. Berrange     if (block->driver->open(block, options, optprefix,
73c972fa12SVladimir Sementsov-Ogievskiy                             readfunc, opaque, flags, n_threads, errp) < 0)
74c972fa12SVladimir Sementsov-Ogievskiy     {
757d969014SDaniel P. Berrange         g_free(block);
767d969014SDaniel P. Berrange         return NULL;
777d969014SDaniel P. Berrange     }
787d969014SDaniel P. Berrange 
79c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_init(&block->mutex);
80c972fa12SVladimir Sementsov-Ogievskiy 
817d969014SDaniel P. Berrange     return block;
827d969014SDaniel P. Berrange }
837d969014SDaniel P. Berrange 
847d969014SDaniel P. Berrange 
857d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
861cd9a787SDaniel P. Berrange                                    const char *optprefix,
877d969014SDaniel P. Berrange                                    QCryptoBlockInitFunc initfunc,
887d969014SDaniel P. Berrange                                    QCryptoBlockWriteFunc writefunc,
897d969014SDaniel P. Berrange                                    void *opaque,
90*d74523a3SHyman Huang                                    unsigned int flags,
917d969014SDaniel P. Berrange                                    Error **errp)
927d969014SDaniel P. Berrange {
937d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
947d969014SDaniel P. Berrange 
957d969014SDaniel P. Berrange     block->format = options->format;
967d969014SDaniel P. Berrange 
977d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
987d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
9990d6f60dSDaniel P. Berrange         error_setg(errp, "Unsupported block driver %s",
100977c736fSMarkus Armbruster                    QCryptoBlockFormat_str(options->format));
1017d969014SDaniel P. Berrange         g_free(block);
1027d969014SDaniel P. Berrange         return NULL;
1037d969014SDaniel P. Berrange     }
1047d969014SDaniel P. Berrange 
1057d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
106*d74523a3SHyman Huang     block->detached_header = flags & QCRYPTO_BLOCK_CREATE_DETACHED;
1077d969014SDaniel P. Berrange 
1081cd9a787SDaniel P. Berrange     if (block->driver->create(block, options, optprefix, initfunc,
1097d969014SDaniel P. Berrange                               writefunc, opaque, errp) < 0) {
1107d969014SDaniel P. Berrange         g_free(block);
1117d969014SDaniel P. Berrange         return NULL;
1127d969014SDaniel P. Berrange     }
1137d969014SDaniel P. Berrange 
114c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_init(&block->mutex);
115c972fa12SVladimir Sementsov-Ogievskiy 
1167d969014SDaniel P. Berrange     return block;
1177d969014SDaniel P. Berrange }
1187d969014SDaniel P. Berrange 
1197d969014SDaniel P. Berrange 
120757dda54SAlberto Faria static int qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block,
1216d49d3a8SStefan Hajnoczi         size_t headerlen, void *opaque, Error **errp)
1226d49d3a8SStefan Hajnoczi {
1236d49d3a8SStefan Hajnoczi     size_t *headerlenp = opaque;
1246d49d3a8SStefan Hajnoczi 
1256d49d3a8SStefan Hajnoczi     /* Stash away the payload size */
1266d49d3a8SStefan Hajnoczi     *headerlenp = headerlen;
1276d49d3a8SStefan Hajnoczi     return 0;
1286d49d3a8SStefan Hajnoczi }
1296d49d3a8SStefan Hajnoczi 
1306d49d3a8SStefan Hajnoczi 
131757dda54SAlberto Faria static int qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block,
1326d49d3a8SStefan Hajnoczi         size_t offset, const uint8_t *buf, size_t buflen,
1336d49d3a8SStefan Hajnoczi         void *opaque, Error **errp)
1346d49d3a8SStefan Hajnoczi {
1356d49d3a8SStefan Hajnoczi     /* Discard the bytes, we're not actually writing to an image */
136757dda54SAlberto Faria     return 0;
1376d49d3a8SStefan Hajnoczi }
1386d49d3a8SStefan Hajnoczi 
1396d49d3a8SStefan Hajnoczi 
1406d49d3a8SStefan Hajnoczi bool
1416d49d3a8SStefan Hajnoczi qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
1426d49d3a8SStefan Hajnoczi                                        const char *optprefix,
1436d49d3a8SStefan Hajnoczi                                        size_t *len,
1446d49d3a8SStefan Hajnoczi                                        Error **errp)
1456d49d3a8SStefan Hajnoczi {
1466d49d3a8SStefan Hajnoczi     /* Fake LUKS creation in order to determine the payload size */
1476d49d3a8SStefan Hajnoczi     g_autoptr(QCryptoBlock) crypto =
1486d49d3a8SStefan Hajnoczi         qcrypto_block_create(create_opts, optprefix,
1496d49d3a8SStefan Hajnoczi                              qcrypto_block_headerlen_hdr_init_func,
1506d49d3a8SStefan Hajnoczi                              qcrypto_block_headerlen_hdr_write_func,
151*d74523a3SHyman Huang                              len, 0, errp);
1526d49d3a8SStefan Hajnoczi     return crypto != NULL;
1536d49d3a8SStefan Hajnoczi }
1546d49d3a8SStefan Hajnoczi 
15543cbd06dSMaxim Levitsky int qcrypto_block_amend_options(QCryptoBlock *block,
15643cbd06dSMaxim Levitsky                                 QCryptoBlockReadFunc readfunc,
15743cbd06dSMaxim Levitsky                                 QCryptoBlockWriteFunc writefunc,
15843cbd06dSMaxim Levitsky                                 void *opaque,
15943cbd06dSMaxim Levitsky                                 QCryptoBlockAmendOptions *options,
16043cbd06dSMaxim Levitsky                                 bool force,
16143cbd06dSMaxim Levitsky                                 Error **errp)
16243cbd06dSMaxim Levitsky {
16343cbd06dSMaxim Levitsky     if (options->format != block->format) {
16443cbd06dSMaxim Levitsky         error_setg(errp,
16543cbd06dSMaxim Levitsky                    "Cannot amend encryption format");
16643cbd06dSMaxim Levitsky         return -1;
16743cbd06dSMaxim Levitsky     }
16843cbd06dSMaxim Levitsky 
16943cbd06dSMaxim Levitsky     if (!block->driver->amend) {
17043cbd06dSMaxim Levitsky         error_setg(errp,
17143cbd06dSMaxim Levitsky                    "Crypto format %s doesn't support format options amendment",
17243cbd06dSMaxim Levitsky                    QCryptoBlockFormat_str(block->format));
17343cbd06dSMaxim Levitsky         return -1;
17443cbd06dSMaxim Levitsky     }
17543cbd06dSMaxim Levitsky 
17643cbd06dSMaxim Levitsky     return block->driver->amend(block,
17743cbd06dSMaxim Levitsky                                 readfunc,
17843cbd06dSMaxim Levitsky                                 writefunc,
17943cbd06dSMaxim Levitsky                                 opaque,
18043cbd06dSMaxim Levitsky                                 options,
18143cbd06dSMaxim Levitsky                                 force,
18243cbd06dSMaxim Levitsky                                 errp);
18343cbd06dSMaxim Levitsky }
1846d49d3a8SStefan Hajnoczi 
18540c85028SDaniel P. Berrange QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
18640c85028SDaniel P. Berrange                                          Error **errp)
18740c85028SDaniel P. Berrange {
18840c85028SDaniel P. Berrange     QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
18940c85028SDaniel P. Berrange 
19040c85028SDaniel P. Berrange     info->format = block->format;
19140c85028SDaniel P. Berrange 
19240c85028SDaniel P. Berrange     if (block->driver->get_info &&
19340c85028SDaniel P. Berrange         block->driver->get_info(block, info, errp) < 0) {
19440c85028SDaniel P. Berrange         g_free(info);
19540c85028SDaniel P. Berrange         return NULL;
19640c85028SDaniel P. Berrange     }
19740c85028SDaniel P. Berrange 
19840c85028SDaniel P. Berrange     return info;
19940c85028SDaniel P. Berrange }
20040c85028SDaniel P. Berrange 
20140c85028SDaniel P. Berrange 
2027d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block,
2034609742aSDaniel P. Berrange                           uint64_t offset,
2047d969014SDaniel P. Berrange                           uint8_t *buf,
2057d969014SDaniel P. Berrange                           size_t len,
2067d969014SDaniel P. Berrange                           Error **errp)
2077d969014SDaniel P. Berrange {
2084609742aSDaniel P. Berrange     return block->driver->decrypt(block, offset, buf, len, errp);
2097d969014SDaniel P. Berrange }
2107d969014SDaniel P. Berrange 
2117d969014SDaniel P. Berrange 
2127d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block,
2134609742aSDaniel P. Berrange                           uint64_t offset,
2147d969014SDaniel P. Berrange                           uint8_t *buf,
2157d969014SDaniel P. Berrange                           size_t len,
2167d969014SDaniel P. Berrange                           Error **errp)
2177d969014SDaniel P. Berrange {
2184609742aSDaniel P. Berrange     return block->driver->encrypt(block, offset, buf, len, errp);
2197d969014SDaniel P. Berrange }
2207d969014SDaniel P. Berrange 
2217d969014SDaniel P. Berrange 
2227d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
2237d969014SDaniel P. Berrange {
224c972fa12SVladimir Sementsov-Ogievskiy     /* Ciphers should be accessed through pop/push method to be thread-safe.
225c972fa12SVladimir Sementsov-Ogievskiy      * Better, they should not be accessed externally at all (note, that
226c972fa12SVladimir Sementsov-Ogievskiy      * pop/push are static functions)
227c972fa12SVladimir Sementsov-Ogievskiy      * This function is used only in test with one thread (it's safe to skip
228c972fa12SVladimir Sementsov-Ogievskiy      * pop/push interface), so it's enough to assert it here:
229c972fa12SVladimir Sementsov-Ogievskiy      */
230c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers <= 1);
231c972fa12SVladimir Sementsov-Ogievskiy     return block->ciphers ? block->ciphers[0] : NULL;
2327d969014SDaniel P. Berrange }
2337d969014SDaniel P. Berrange 
2347d969014SDaniel P. Berrange 
235c972fa12SVladimir Sementsov-Ogievskiy static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block)
236c972fa12SVladimir Sementsov-Ogievskiy {
237c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher;
238c972fa12SVladimir Sementsov-Ogievskiy 
239c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_lock(&block->mutex);
240c972fa12SVladimir Sementsov-Ogievskiy 
241c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_free_ciphers > 0);
242c972fa12SVladimir Sementsov-Ogievskiy     block->n_free_ciphers--;
243c972fa12SVladimir Sementsov-Ogievskiy     cipher = block->ciphers[block->n_free_ciphers];
244c972fa12SVladimir Sementsov-Ogievskiy 
245c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_unlock(&block->mutex);
246c972fa12SVladimir Sementsov-Ogievskiy 
247c972fa12SVladimir Sementsov-Ogievskiy     return cipher;
248c972fa12SVladimir Sementsov-Ogievskiy }
249c972fa12SVladimir Sementsov-Ogievskiy 
250c972fa12SVladimir Sementsov-Ogievskiy 
251c972fa12SVladimir Sementsov-Ogievskiy static void qcrypto_block_push_cipher(QCryptoBlock *block,
252c972fa12SVladimir Sementsov-Ogievskiy                                       QCryptoCipher *cipher)
253c972fa12SVladimir Sementsov-Ogievskiy {
254c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_lock(&block->mutex);
255c972fa12SVladimir Sementsov-Ogievskiy 
256c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_free_ciphers < block->n_ciphers);
257c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers[block->n_free_ciphers] = cipher;
258c972fa12SVladimir Sementsov-Ogievskiy     block->n_free_ciphers++;
259c972fa12SVladimir Sementsov-Ogievskiy 
260c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_unlock(&block->mutex);
261c972fa12SVladimir Sementsov-Ogievskiy }
262c972fa12SVladimir Sementsov-Ogievskiy 
263c972fa12SVladimir Sementsov-Ogievskiy 
264c972fa12SVladimir Sementsov-Ogievskiy int qcrypto_block_init_cipher(QCryptoBlock *block,
265c972fa12SVladimir Sementsov-Ogievskiy                               QCryptoCipherAlgorithm alg,
266c972fa12SVladimir Sementsov-Ogievskiy                               QCryptoCipherMode mode,
267c972fa12SVladimir Sementsov-Ogievskiy                               const uint8_t *key, size_t nkey,
268c972fa12SVladimir Sementsov-Ogievskiy                               size_t n_threads, Error **errp)
269c972fa12SVladimir Sementsov-Ogievskiy {
270c972fa12SVladimir Sementsov-Ogievskiy     size_t i;
271c972fa12SVladimir Sementsov-Ogievskiy 
272c972fa12SVladimir Sementsov-Ogievskiy     assert(!block->ciphers && !block->n_ciphers && !block->n_free_ciphers);
273c972fa12SVladimir Sementsov-Ogievskiy 
274c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers = g_new0(QCryptoCipher *, n_threads);
275c972fa12SVladimir Sementsov-Ogievskiy 
276c972fa12SVladimir Sementsov-Ogievskiy     for (i = 0; i < n_threads; i++) {
277c972fa12SVladimir Sementsov-Ogievskiy         block->ciphers[i] = qcrypto_cipher_new(alg, mode, key, nkey, errp);
278c972fa12SVladimir Sementsov-Ogievskiy         if (!block->ciphers[i]) {
279c972fa12SVladimir Sementsov-Ogievskiy             qcrypto_block_free_cipher(block);
280c972fa12SVladimir Sementsov-Ogievskiy             return -1;
281c972fa12SVladimir Sementsov-Ogievskiy         }
282c972fa12SVladimir Sementsov-Ogievskiy         block->n_ciphers++;
283c972fa12SVladimir Sementsov-Ogievskiy         block->n_free_ciphers++;
284c972fa12SVladimir Sementsov-Ogievskiy     }
285c972fa12SVladimir Sementsov-Ogievskiy 
286c972fa12SVladimir Sementsov-Ogievskiy     return 0;
287c972fa12SVladimir Sementsov-Ogievskiy }
288c972fa12SVladimir Sementsov-Ogievskiy 
289c972fa12SVladimir Sementsov-Ogievskiy 
290c972fa12SVladimir Sementsov-Ogievskiy void qcrypto_block_free_cipher(QCryptoBlock *block)
291c972fa12SVladimir Sementsov-Ogievskiy {
292c972fa12SVladimir Sementsov-Ogievskiy     size_t i;
293c972fa12SVladimir Sementsov-Ogievskiy 
294c972fa12SVladimir Sementsov-Ogievskiy     if (!block->ciphers) {
295c972fa12SVladimir Sementsov-Ogievskiy         return;
296c972fa12SVladimir Sementsov-Ogievskiy     }
297c972fa12SVladimir Sementsov-Ogievskiy 
298c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers == block->n_free_ciphers);
299c972fa12SVladimir Sementsov-Ogievskiy 
300c972fa12SVladimir Sementsov-Ogievskiy     for (i = 0; i < block->n_ciphers; i++) {
301c972fa12SVladimir Sementsov-Ogievskiy         qcrypto_cipher_free(block->ciphers[i]);
302c972fa12SVladimir Sementsov-Ogievskiy     }
303c972fa12SVladimir Sementsov-Ogievskiy 
304c972fa12SVladimir Sementsov-Ogievskiy     g_free(block->ciphers);
305c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers = NULL;
306c972fa12SVladimir Sementsov-Ogievskiy     block->n_ciphers = block->n_free_ciphers = 0;
307c972fa12SVladimir Sementsov-Ogievskiy }
308c972fa12SVladimir Sementsov-Ogievskiy 
3097d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
3107d969014SDaniel P. Berrange {
311c972fa12SVladimir Sementsov-Ogievskiy     /* ivgen should be accessed under mutex. However, this function is used only
312c972fa12SVladimir Sementsov-Ogievskiy      * in test with one thread, so it's enough to assert it here:
313c972fa12SVladimir Sementsov-Ogievskiy      */
314c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers <= 1);
3157d969014SDaniel P. Berrange     return block->ivgen;
3167d969014SDaniel P. Berrange }
3177d969014SDaniel P. Berrange 
3187d969014SDaniel P. Berrange 
3197d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
3207d969014SDaniel P. Berrange {
3217d969014SDaniel P. Berrange     return block->kdfhash;
3227d969014SDaniel P. Berrange }
3237d969014SDaniel P. Berrange 
3247d969014SDaniel P. Berrange 
3257d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
3267d969014SDaniel P. Berrange {
3277d969014SDaniel P. Berrange     return block->payload_offset;
3287d969014SDaniel P. Berrange }
3297d969014SDaniel P. Berrange 
3307d969014SDaniel P. Berrange 
331850f49deSDaniel P. Berrange uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
332850f49deSDaniel P. Berrange {
333850f49deSDaniel P. Berrange     return block->sector_size;
334850f49deSDaniel P. Berrange }
335850f49deSDaniel P. Berrange 
336850f49deSDaniel P. Berrange 
3377d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block)
3387d969014SDaniel P. Berrange {
3397d969014SDaniel P. Berrange     if (!block) {
3407d969014SDaniel P. Berrange         return;
3417d969014SDaniel P. Berrange     }
3427d969014SDaniel P. Berrange 
3437d969014SDaniel P. Berrange     block->driver->cleanup(block);
3447d969014SDaniel P. Berrange 
345c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_free_cipher(block);
3467d969014SDaniel P. Berrange     qcrypto_ivgen_free(block->ivgen);
347c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_destroy(&block->mutex);
3487d969014SDaniel P. Berrange     g_free(block);
3497d969014SDaniel P. Berrange }
3507d969014SDaniel P. Berrange 
3517d969014SDaniel P. Berrange 
3521dc57b60SVladimir Sementsov-Ogievskiy typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
3531dc57b60SVladimir Sementsov-Ogievskiy                                         const void *in,
3541dc57b60SVladimir Sementsov-Ogievskiy                                         void *out,
3551dc57b60SVladimir Sementsov-Ogievskiy                                         size_t len,
3561dc57b60SVladimir Sementsov-Ogievskiy                                         Error **errp);
3571dc57b60SVladimir Sementsov-Ogievskiy 
3580270417cSVladimir Sementsov-Ogievskiy static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
3597d969014SDaniel P. Berrange                                           size_t niv,
3607d969014SDaniel P. Berrange                                           QCryptoIVGen *ivgen,
361c972fa12SVladimir Sementsov-Ogievskiy                                           QemuMutex *ivgen_mutex,
3627d969014SDaniel P. Berrange                                           int sectorsize,
3634609742aSDaniel P. Berrange                                           uint64_t offset,
3647d969014SDaniel P. Berrange                                           uint8_t *buf,
3657d969014SDaniel P. Berrange                                           size_t len,
3661dc57b60SVladimir Sementsov-Ogievskiy                                           QCryptoCipherEncDecFunc func,
3677d969014SDaniel P. Berrange                                           Error **errp)
3687d969014SDaniel P. Berrange {
36957b9f113SDaniel P. Berrangé     g_autofree uint8_t *iv = niv ? g_new0(uint8_t, niv) : NULL;
3707d969014SDaniel P. Berrange     int ret = -1;
3714609742aSDaniel P. Berrange     uint64_t startsector = offset / sectorsize;
3724609742aSDaniel P. Berrange 
3734609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(offset, sectorsize));
3744609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(len, sectorsize));
3757d969014SDaniel P. Berrange 
3767d969014SDaniel P. Berrange     while (len > 0) {
3777d969014SDaniel P. Berrange         size_t nbytes;
3787d969014SDaniel P. Berrange         if (niv) {
379c972fa12SVladimir Sementsov-Ogievskiy             if (ivgen_mutex) {
380c972fa12SVladimir Sementsov-Ogievskiy                 qemu_mutex_lock(ivgen_mutex);
381c972fa12SVladimir Sementsov-Ogievskiy             }
382c972fa12SVladimir Sementsov-Ogievskiy             ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
383c972fa12SVladimir Sementsov-Ogievskiy             if (ivgen_mutex) {
384c972fa12SVladimir Sementsov-Ogievskiy                 qemu_mutex_unlock(ivgen_mutex);
385c972fa12SVladimir Sementsov-Ogievskiy             }
386c972fa12SVladimir Sementsov-Ogievskiy 
387c972fa12SVladimir Sementsov-Ogievskiy             if (ret < 0) {
38857b9f113SDaniel P. Berrangé                 return -1;
3897d969014SDaniel P. Berrange             }
3907d969014SDaniel P. Berrange 
3917d969014SDaniel P. Berrange             if (qcrypto_cipher_setiv(cipher,
3927d969014SDaniel P. Berrange                                      iv, niv,
3937d969014SDaniel P. Berrange                                      errp) < 0) {
39457b9f113SDaniel P. Berrangé                 return -1;
3957d969014SDaniel P. Berrange             }
3967d969014SDaniel P. Berrange         }
3977d969014SDaniel P. Berrange 
3987d969014SDaniel P. Berrange         nbytes = len > sectorsize ? sectorsize : len;
3991dc57b60SVladimir Sementsov-Ogievskiy         if (func(cipher, buf, buf, nbytes, errp) < 0) {
40057b9f113SDaniel P. Berrangé             return -1;
4017d969014SDaniel P. Berrange         }
4027d969014SDaniel P. Berrange 
4037d969014SDaniel P. Berrange         startsector++;
4047d969014SDaniel P. Berrange         buf += nbytes;
4057d969014SDaniel P. Berrange         len -= nbytes;
4067d969014SDaniel P. Berrange     }
4077d969014SDaniel P. Berrange 
40857b9f113SDaniel P. Berrangé     return 0;
4097d969014SDaniel P. Berrange }
4107d969014SDaniel P. Berrange 
4117d969014SDaniel P. Berrange 
4120270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
4131dc57b60SVladimir Sementsov-Ogievskiy                                         size_t niv,
4141dc57b60SVladimir Sementsov-Ogievskiy                                         QCryptoIVGen *ivgen,
4151dc57b60SVladimir Sementsov-Ogievskiy                                         int sectorsize,
4161dc57b60SVladimir Sementsov-Ogievskiy                                         uint64_t offset,
4171dc57b60SVladimir Sementsov-Ogievskiy                                         uint8_t *buf,
4181dc57b60SVladimir Sementsov-Ogievskiy                                         size_t len,
4191dc57b60SVladimir Sementsov-Ogievskiy                                         Error **errp)
4201dc57b60SVladimir Sementsov-Ogievskiy {
421c972fa12SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
4220270417cSVladimir Sementsov-Ogievskiy                                           offset, buf, len,
4230270417cSVladimir Sementsov-Ogievskiy                                           qcrypto_cipher_decrypt, errp);
4241dc57b60SVladimir Sementsov-Ogievskiy }
4251dc57b60SVladimir Sementsov-Ogievskiy 
4261dc57b60SVladimir Sementsov-Ogievskiy 
4270270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
4287d969014SDaniel P. Berrange                                         size_t niv,
4297d969014SDaniel P. Berrange                                         QCryptoIVGen *ivgen,
4307d969014SDaniel P. Berrange                                         int sectorsize,
4314609742aSDaniel P. Berrange                                         uint64_t offset,
4327d969014SDaniel P. Berrange                                         uint8_t *buf,
4337d969014SDaniel P. Berrange                                         size_t len,
4347d969014SDaniel P. Berrange                                         Error **errp)
4357d969014SDaniel P. Berrange {
436c972fa12SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
4370270417cSVladimir Sementsov-Ogievskiy                                           offset, buf, len,
4380270417cSVladimir Sementsov-Ogievskiy                                           qcrypto_cipher_encrypt, errp);
4397d969014SDaniel P. Berrange }
4400f0d596cSVladimir Sementsov-Ogievskiy 
4410f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_decrypt_helper(QCryptoBlock *block,
4420f0d596cSVladimir Sementsov-Ogievskiy                                  int sectorsize,
4430f0d596cSVladimir Sementsov-Ogievskiy                                  uint64_t offset,
4440f0d596cSVladimir Sementsov-Ogievskiy                                  uint8_t *buf,
4450f0d596cSVladimir Sementsov-Ogievskiy                                  size_t len,
4460f0d596cSVladimir Sementsov-Ogievskiy                                  Error **errp)
4470f0d596cSVladimir Sementsov-Ogievskiy {
448c972fa12SVladimir Sementsov-Ogievskiy     int ret;
449c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
4500f0d596cSVladimir Sementsov-Ogievskiy 
451c972fa12SVladimir Sementsov-Ogievskiy     ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
452c972fa12SVladimir Sementsov-Ogievskiy                                          &block->mutex, sectorsize, offset, buf,
453c972fa12SVladimir Sementsov-Ogievskiy                                          len, qcrypto_cipher_decrypt, errp);
454c972fa12SVladimir Sementsov-Ogievskiy 
455c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_push_cipher(block, cipher);
456c972fa12SVladimir Sementsov-Ogievskiy 
457c972fa12SVladimir Sementsov-Ogievskiy     return ret;
458c972fa12SVladimir Sementsov-Ogievskiy }
4590f0d596cSVladimir Sementsov-Ogievskiy 
4600f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_encrypt_helper(QCryptoBlock *block,
4610f0d596cSVladimir Sementsov-Ogievskiy                                  int sectorsize,
4620f0d596cSVladimir Sementsov-Ogievskiy                                  uint64_t offset,
4630f0d596cSVladimir Sementsov-Ogievskiy                                  uint8_t *buf,
4640f0d596cSVladimir Sementsov-Ogievskiy                                  size_t len,
4650f0d596cSVladimir Sementsov-Ogievskiy                                  Error **errp)
4660f0d596cSVladimir Sementsov-Ogievskiy {
467c972fa12SVladimir Sementsov-Ogievskiy     int ret;
468c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
469c972fa12SVladimir Sementsov-Ogievskiy 
470c972fa12SVladimir Sementsov-Ogievskiy     ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
471c972fa12SVladimir Sementsov-Ogievskiy                                          &block->mutex, sectorsize, offset, buf,
472c972fa12SVladimir Sementsov-Ogievskiy                                          len, qcrypto_cipher_encrypt, errp);
473c972fa12SVladimir Sementsov-Ogievskiy 
474c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_push_cipher(block, cipher);
475c972fa12SVladimir Sementsov-Ogievskiy 
476c972fa12SVladimir Sementsov-Ogievskiy     return ret;
4770f0d596cSVladimir Sementsov-Ogievskiy }
478