xref: /openbmc/qemu/crypto/block.c (revision 6d49d3a859b0f19226dbb0df5e7f50267b42f45c)
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,
907d969014SDaniel P. Berrange                                    Error **errp)
917d969014SDaniel P. Berrange {
927d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
937d969014SDaniel P. Berrange 
947d969014SDaniel P. Berrange     block->format = options->format;
957d969014SDaniel P. Berrange 
967d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
977d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
9890d6f60dSDaniel P. Berrange         error_setg(errp, "Unsupported block driver %s",
99977c736fSMarkus Armbruster                    QCryptoBlockFormat_str(options->format));
1007d969014SDaniel P. Berrange         g_free(block);
1017d969014SDaniel P. Berrange         return NULL;
1027d969014SDaniel P. Berrange     }
1037d969014SDaniel P. Berrange 
1047d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
1057d969014SDaniel P. Berrange 
1061cd9a787SDaniel P. Berrange     if (block->driver->create(block, options, optprefix, initfunc,
1077d969014SDaniel P. Berrange                               writefunc, opaque, errp) < 0) {
1087d969014SDaniel P. Berrange         g_free(block);
1097d969014SDaniel P. Berrange         return NULL;
1107d969014SDaniel P. Berrange     }
1117d969014SDaniel P. Berrange 
112c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_init(&block->mutex);
113c972fa12SVladimir Sementsov-Ogievskiy 
1147d969014SDaniel P. Berrange     return block;
1157d969014SDaniel P. Berrange }
1167d969014SDaniel P. Berrange 
1177d969014SDaniel P. Berrange 
118*6d49d3a8SStefan Hajnoczi static ssize_t qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block,
119*6d49d3a8SStefan Hajnoczi         size_t headerlen, void *opaque, Error **errp)
120*6d49d3a8SStefan Hajnoczi {
121*6d49d3a8SStefan Hajnoczi     size_t *headerlenp = opaque;
122*6d49d3a8SStefan Hajnoczi 
123*6d49d3a8SStefan Hajnoczi     /* Stash away the payload size */
124*6d49d3a8SStefan Hajnoczi     *headerlenp = headerlen;
125*6d49d3a8SStefan Hajnoczi     return 0;
126*6d49d3a8SStefan Hajnoczi }
127*6d49d3a8SStefan Hajnoczi 
128*6d49d3a8SStefan Hajnoczi 
129*6d49d3a8SStefan Hajnoczi static ssize_t qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block,
130*6d49d3a8SStefan Hajnoczi         size_t offset, const uint8_t *buf, size_t buflen,
131*6d49d3a8SStefan Hajnoczi         void *opaque, Error **errp)
132*6d49d3a8SStefan Hajnoczi {
133*6d49d3a8SStefan Hajnoczi     /* Discard the bytes, we're not actually writing to an image */
134*6d49d3a8SStefan Hajnoczi     return buflen;
135*6d49d3a8SStefan Hajnoczi }
136*6d49d3a8SStefan Hajnoczi 
137*6d49d3a8SStefan Hajnoczi 
138*6d49d3a8SStefan Hajnoczi bool
139*6d49d3a8SStefan Hajnoczi qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
140*6d49d3a8SStefan Hajnoczi                                        const char *optprefix,
141*6d49d3a8SStefan Hajnoczi                                        size_t *len,
142*6d49d3a8SStefan Hajnoczi                                        Error **errp)
143*6d49d3a8SStefan Hajnoczi {
144*6d49d3a8SStefan Hajnoczi     /* Fake LUKS creation in order to determine the payload size */
145*6d49d3a8SStefan Hajnoczi     g_autoptr(QCryptoBlock) crypto =
146*6d49d3a8SStefan Hajnoczi         qcrypto_block_create(create_opts, optprefix,
147*6d49d3a8SStefan Hajnoczi                              qcrypto_block_headerlen_hdr_init_func,
148*6d49d3a8SStefan Hajnoczi                              qcrypto_block_headerlen_hdr_write_func,
149*6d49d3a8SStefan Hajnoczi                              len, errp);
150*6d49d3a8SStefan Hajnoczi     return crypto != NULL;
151*6d49d3a8SStefan Hajnoczi }
152*6d49d3a8SStefan Hajnoczi 
153*6d49d3a8SStefan Hajnoczi 
15440c85028SDaniel P. Berrange QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
15540c85028SDaniel P. Berrange                                          Error **errp)
15640c85028SDaniel P. Berrange {
15740c85028SDaniel P. Berrange     QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
15840c85028SDaniel P. Berrange 
15940c85028SDaniel P. Berrange     info->format = block->format;
16040c85028SDaniel P. Berrange 
16140c85028SDaniel P. Berrange     if (block->driver->get_info &&
16240c85028SDaniel P. Berrange         block->driver->get_info(block, info, errp) < 0) {
16340c85028SDaniel P. Berrange         g_free(info);
16440c85028SDaniel P. Berrange         return NULL;
16540c85028SDaniel P. Berrange     }
16640c85028SDaniel P. Berrange 
16740c85028SDaniel P. Berrange     return info;
16840c85028SDaniel P. Berrange }
16940c85028SDaniel P. Berrange 
17040c85028SDaniel P. Berrange 
1717d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block,
1724609742aSDaniel P. Berrange                           uint64_t offset,
1737d969014SDaniel P. Berrange                           uint8_t *buf,
1747d969014SDaniel P. Berrange                           size_t len,
1757d969014SDaniel P. Berrange                           Error **errp)
1767d969014SDaniel P. Berrange {
1774609742aSDaniel P. Berrange     return block->driver->decrypt(block, offset, buf, len, errp);
1787d969014SDaniel P. Berrange }
1797d969014SDaniel P. Berrange 
1807d969014SDaniel P. Berrange 
1817d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block,
1824609742aSDaniel P. Berrange                           uint64_t offset,
1837d969014SDaniel P. Berrange                           uint8_t *buf,
1847d969014SDaniel P. Berrange                           size_t len,
1857d969014SDaniel P. Berrange                           Error **errp)
1867d969014SDaniel P. Berrange {
1874609742aSDaniel P. Berrange     return block->driver->encrypt(block, offset, buf, len, errp);
1887d969014SDaniel P. Berrange }
1897d969014SDaniel P. Berrange 
1907d969014SDaniel P. Berrange 
1917d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
1927d969014SDaniel P. Berrange {
193c972fa12SVladimir Sementsov-Ogievskiy     /* Ciphers should be accessed through pop/push method to be thread-safe.
194c972fa12SVladimir Sementsov-Ogievskiy      * Better, they should not be accessed externally at all (note, that
195c972fa12SVladimir Sementsov-Ogievskiy      * pop/push are static functions)
196c972fa12SVladimir Sementsov-Ogievskiy      * This function is used only in test with one thread (it's safe to skip
197c972fa12SVladimir Sementsov-Ogievskiy      * pop/push interface), so it's enough to assert it here:
198c972fa12SVladimir Sementsov-Ogievskiy      */
199c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers <= 1);
200c972fa12SVladimir Sementsov-Ogievskiy     return block->ciphers ? block->ciphers[0] : NULL;
2017d969014SDaniel P. Berrange }
2027d969014SDaniel P. Berrange 
2037d969014SDaniel P. Berrange 
204c972fa12SVladimir Sementsov-Ogievskiy static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block)
205c972fa12SVladimir Sementsov-Ogievskiy {
206c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher;
207c972fa12SVladimir Sementsov-Ogievskiy 
208c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_lock(&block->mutex);
209c972fa12SVladimir Sementsov-Ogievskiy 
210c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_free_ciphers > 0);
211c972fa12SVladimir Sementsov-Ogievskiy     block->n_free_ciphers--;
212c972fa12SVladimir Sementsov-Ogievskiy     cipher = block->ciphers[block->n_free_ciphers];
213c972fa12SVladimir Sementsov-Ogievskiy 
214c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_unlock(&block->mutex);
215c972fa12SVladimir Sementsov-Ogievskiy 
216c972fa12SVladimir Sementsov-Ogievskiy     return cipher;
217c972fa12SVladimir Sementsov-Ogievskiy }
218c972fa12SVladimir Sementsov-Ogievskiy 
219c972fa12SVladimir Sementsov-Ogievskiy 
220c972fa12SVladimir Sementsov-Ogievskiy static void qcrypto_block_push_cipher(QCryptoBlock *block,
221c972fa12SVladimir Sementsov-Ogievskiy                                       QCryptoCipher *cipher)
222c972fa12SVladimir Sementsov-Ogievskiy {
223c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_lock(&block->mutex);
224c972fa12SVladimir Sementsov-Ogievskiy 
225c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_free_ciphers < block->n_ciphers);
226c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers[block->n_free_ciphers] = cipher;
227c972fa12SVladimir Sementsov-Ogievskiy     block->n_free_ciphers++;
228c972fa12SVladimir Sementsov-Ogievskiy 
229c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_unlock(&block->mutex);
230c972fa12SVladimir Sementsov-Ogievskiy }
231c972fa12SVladimir Sementsov-Ogievskiy 
232c972fa12SVladimir Sementsov-Ogievskiy 
233c972fa12SVladimir Sementsov-Ogievskiy int qcrypto_block_init_cipher(QCryptoBlock *block,
234c972fa12SVladimir Sementsov-Ogievskiy                               QCryptoCipherAlgorithm alg,
235c972fa12SVladimir Sementsov-Ogievskiy                               QCryptoCipherMode mode,
236c972fa12SVladimir Sementsov-Ogievskiy                               const uint8_t *key, size_t nkey,
237c972fa12SVladimir Sementsov-Ogievskiy                               size_t n_threads, Error **errp)
238c972fa12SVladimir Sementsov-Ogievskiy {
239c972fa12SVladimir Sementsov-Ogievskiy     size_t i;
240c972fa12SVladimir Sementsov-Ogievskiy 
241c972fa12SVladimir Sementsov-Ogievskiy     assert(!block->ciphers && !block->n_ciphers && !block->n_free_ciphers);
242c972fa12SVladimir Sementsov-Ogievskiy 
243c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers = g_new0(QCryptoCipher *, n_threads);
244c972fa12SVladimir Sementsov-Ogievskiy 
245c972fa12SVladimir Sementsov-Ogievskiy     for (i = 0; i < n_threads; i++) {
246c972fa12SVladimir Sementsov-Ogievskiy         block->ciphers[i] = qcrypto_cipher_new(alg, mode, key, nkey, errp);
247c972fa12SVladimir Sementsov-Ogievskiy         if (!block->ciphers[i]) {
248c972fa12SVladimir Sementsov-Ogievskiy             qcrypto_block_free_cipher(block);
249c972fa12SVladimir Sementsov-Ogievskiy             return -1;
250c972fa12SVladimir Sementsov-Ogievskiy         }
251c972fa12SVladimir Sementsov-Ogievskiy         block->n_ciphers++;
252c972fa12SVladimir Sementsov-Ogievskiy         block->n_free_ciphers++;
253c972fa12SVladimir Sementsov-Ogievskiy     }
254c972fa12SVladimir Sementsov-Ogievskiy 
255c972fa12SVladimir Sementsov-Ogievskiy     return 0;
256c972fa12SVladimir Sementsov-Ogievskiy }
257c972fa12SVladimir Sementsov-Ogievskiy 
258c972fa12SVladimir Sementsov-Ogievskiy 
259c972fa12SVladimir Sementsov-Ogievskiy void qcrypto_block_free_cipher(QCryptoBlock *block)
260c972fa12SVladimir Sementsov-Ogievskiy {
261c972fa12SVladimir Sementsov-Ogievskiy     size_t i;
262c972fa12SVladimir Sementsov-Ogievskiy 
263c972fa12SVladimir Sementsov-Ogievskiy     if (!block->ciphers) {
264c972fa12SVladimir Sementsov-Ogievskiy         return;
265c972fa12SVladimir Sementsov-Ogievskiy     }
266c972fa12SVladimir Sementsov-Ogievskiy 
267c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers == block->n_free_ciphers);
268c972fa12SVladimir Sementsov-Ogievskiy 
269c972fa12SVladimir Sementsov-Ogievskiy     for (i = 0; i < block->n_ciphers; i++) {
270c972fa12SVladimir Sementsov-Ogievskiy         qcrypto_cipher_free(block->ciphers[i]);
271c972fa12SVladimir Sementsov-Ogievskiy     }
272c972fa12SVladimir Sementsov-Ogievskiy 
273c972fa12SVladimir Sementsov-Ogievskiy     g_free(block->ciphers);
274c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers = NULL;
275c972fa12SVladimir Sementsov-Ogievskiy     block->n_ciphers = block->n_free_ciphers = 0;
276c972fa12SVladimir Sementsov-Ogievskiy }
277c972fa12SVladimir Sementsov-Ogievskiy 
2787d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
2797d969014SDaniel P. Berrange {
280c972fa12SVladimir Sementsov-Ogievskiy     /* ivgen should be accessed under mutex. However, this function is used only
281c972fa12SVladimir Sementsov-Ogievskiy      * in test with one thread, so it's enough to assert it here:
282c972fa12SVladimir Sementsov-Ogievskiy      */
283c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers <= 1);
2847d969014SDaniel P. Berrange     return block->ivgen;
2857d969014SDaniel P. Berrange }
2867d969014SDaniel P. Berrange 
2877d969014SDaniel P. Berrange 
2887d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
2897d969014SDaniel P. Berrange {
2907d969014SDaniel P. Berrange     return block->kdfhash;
2917d969014SDaniel P. Berrange }
2927d969014SDaniel P. Berrange 
2937d969014SDaniel P. Berrange 
2947d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
2957d969014SDaniel P. Berrange {
2967d969014SDaniel P. Berrange     return block->payload_offset;
2977d969014SDaniel P. Berrange }
2987d969014SDaniel P. Berrange 
2997d969014SDaniel P. Berrange 
300850f49deSDaniel P. Berrange uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
301850f49deSDaniel P. Berrange {
302850f49deSDaniel P. Berrange     return block->sector_size;
303850f49deSDaniel P. Berrange }
304850f49deSDaniel P. Berrange 
305850f49deSDaniel P. Berrange 
3067d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block)
3077d969014SDaniel P. Berrange {
3087d969014SDaniel P. Berrange     if (!block) {
3097d969014SDaniel P. Berrange         return;
3107d969014SDaniel P. Berrange     }
3117d969014SDaniel P. Berrange 
3127d969014SDaniel P. Berrange     block->driver->cleanup(block);
3137d969014SDaniel P. Berrange 
314c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_free_cipher(block);
3157d969014SDaniel P. Berrange     qcrypto_ivgen_free(block->ivgen);
316c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_destroy(&block->mutex);
3177d969014SDaniel P. Berrange     g_free(block);
3187d969014SDaniel P. Berrange }
3197d969014SDaniel P. Berrange 
3207d969014SDaniel P. Berrange 
3211dc57b60SVladimir Sementsov-Ogievskiy typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
3221dc57b60SVladimir Sementsov-Ogievskiy                                         const void *in,
3231dc57b60SVladimir Sementsov-Ogievskiy                                         void *out,
3241dc57b60SVladimir Sementsov-Ogievskiy                                         size_t len,
3251dc57b60SVladimir Sementsov-Ogievskiy                                         Error **errp);
3261dc57b60SVladimir Sementsov-Ogievskiy 
3270270417cSVladimir Sementsov-Ogievskiy static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
3287d969014SDaniel P. Berrange                                           size_t niv,
3297d969014SDaniel P. Berrange                                           QCryptoIVGen *ivgen,
330c972fa12SVladimir Sementsov-Ogievskiy                                           QemuMutex *ivgen_mutex,
3317d969014SDaniel P. Berrange                                           int sectorsize,
3324609742aSDaniel P. Berrange                                           uint64_t offset,
3337d969014SDaniel P. Berrange                                           uint8_t *buf,
3347d969014SDaniel P. Berrange                                           size_t len,
3351dc57b60SVladimir Sementsov-Ogievskiy                                           QCryptoCipherEncDecFunc func,
3367d969014SDaniel P. Berrange                                           Error **errp)
3377d969014SDaniel P. Berrange {
33857b9f113SDaniel P. Berrangé     g_autofree uint8_t *iv = niv ? g_new0(uint8_t, niv) : NULL;
3397d969014SDaniel P. Berrange     int ret = -1;
3404609742aSDaniel P. Berrange     uint64_t startsector = offset / sectorsize;
3414609742aSDaniel P. Berrange 
3424609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(offset, sectorsize));
3434609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(len, sectorsize));
3447d969014SDaniel P. Berrange 
3457d969014SDaniel P. Berrange     while (len > 0) {
3467d969014SDaniel P. Berrange         size_t nbytes;
3477d969014SDaniel P. Berrange         if (niv) {
348c972fa12SVladimir Sementsov-Ogievskiy             if (ivgen_mutex) {
349c972fa12SVladimir Sementsov-Ogievskiy                 qemu_mutex_lock(ivgen_mutex);
350c972fa12SVladimir Sementsov-Ogievskiy             }
351c972fa12SVladimir Sementsov-Ogievskiy             ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
352c972fa12SVladimir Sementsov-Ogievskiy             if (ivgen_mutex) {
353c972fa12SVladimir Sementsov-Ogievskiy                 qemu_mutex_unlock(ivgen_mutex);
354c972fa12SVladimir Sementsov-Ogievskiy             }
355c972fa12SVladimir Sementsov-Ogievskiy 
356c972fa12SVladimir Sementsov-Ogievskiy             if (ret < 0) {
35757b9f113SDaniel P. Berrangé                 return -1;
3587d969014SDaniel P. Berrange             }
3597d969014SDaniel P. Berrange 
3607d969014SDaniel P. Berrange             if (qcrypto_cipher_setiv(cipher,
3617d969014SDaniel P. Berrange                                      iv, niv,
3627d969014SDaniel P. Berrange                                      errp) < 0) {
36357b9f113SDaniel P. Berrangé                 return -1;
3647d969014SDaniel P. Berrange             }
3657d969014SDaniel P. Berrange         }
3667d969014SDaniel P. Berrange 
3677d969014SDaniel P. Berrange         nbytes = len > sectorsize ? sectorsize : len;
3681dc57b60SVladimir Sementsov-Ogievskiy         if (func(cipher, buf, buf, nbytes, errp) < 0) {
36957b9f113SDaniel P. Berrangé             return -1;
3707d969014SDaniel P. Berrange         }
3717d969014SDaniel P. Berrange 
3727d969014SDaniel P. Berrange         startsector++;
3737d969014SDaniel P. Berrange         buf += nbytes;
3747d969014SDaniel P. Berrange         len -= nbytes;
3757d969014SDaniel P. Berrange     }
3767d969014SDaniel P. Berrange 
37757b9f113SDaniel P. Berrangé     return 0;
3787d969014SDaniel P. Berrange }
3797d969014SDaniel P. Berrange 
3807d969014SDaniel P. Berrange 
3810270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
3821dc57b60SVladimir Sementsov-Ogievskiy                                         size_t niv,
3831dc57b60SVladimir Sementsov-Ogievskiy                                         QCryptoIVGen *ivgen,
3841dc57b60SVladimir Sementsov-Ogievskiy                                         int sectorsize,
3851dc57b60SVladimir Sementsov-Ogievskiy                                         uint64_t offset,
3861dc57b60SVladimir Sementsov-Ogievskiy                                         uint8_t *buf,
3871dc57b60SVladimir Sementsov-Ogievskiy                                         size_t len,
3881dc57b60SVladimir Sementsov-Ogievskiy                                         Error **errp)
3891dc57b60SVladimir Sementsov-Ogievskiy {
390c972fa12SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
3910270417cSVladimir Sementsov-Ogievskiy                                           offset, buf, len,
3920270417cSVladimir Sementsov-Ogievskiy                                           qcrypto_cipher_decrypt, errp);
3931dc57b60SVladimir Sementsov-Ogievskiy }
3941dc57b60SVladimir Sementsov-Ogievskiy 
3951dc57b60SVladimir Sementsov-Ogievskiy 
3960270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
3977d969014SDaniel P. Berrange                                         size_t niv,
3987d969014SDaniel P. Berrange                                         QCryptoIVGen *ivgen,
3997d969014SDaniel P. Berrange                                         int sectorsize,
4004609742aSDaniel P. Berrange                                         uint64_t offset,
4017d969014SDaniel P. Berrange                                         uint8_t *buf,
4027d969014SDaniel P. Berrange                                         size_t len,
4037d969014SDaniel P. Berrange                                         Error **errp)
4047d969014SDaniel P. Berrange {
405c972fa12SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
4060270417cSVladimir Sementsov-Ogievskiy                                           offset, buf, len,
4070270417cSVladimir Sementsov-Ogievskiy                                           qcrypto_cipher_encrypt, errp);
4087d969014SDaniel P. Berrange }
4090f0d596cSVladimir Sementsov-Ogievskiy 
4100f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_decrypt_helper(QCryptoBlock *block,
4110f0d596cSVladimir Sementsov-Ogievskiy                                  int sectorsize,
4120f0d596cSVladimir Sementsov-Ogievskiy                                  uint64_t offset,
4130f0d596cSVladimir Sementsov-Ogievskiy                                  uint8_t *buf,
4140f0d596cSVladimir Sementsov-Ogievskiy                                  size_t len,
4150f0d596cSVladimir Sementsov-Ogievskiy                                  Error **errp)
4160f0d596cSVladimir Sementsov-Ogievskiy {
417c972fa12SVladimir Sementsov-Ogievskiy     int ret;
418c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
4190f0d596cSVladimir Sementsov-Ogievskiy 
420c972fa12SVladimir Sementsov-Ogievskiy     ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
421c972fa12SVladimir Sementsov-Ogievskiy                                          &block->mutex, sectorsize, offset, buf,
422c972fa12SVladimir Sementsov-Ogievskiy                                          len, qcrypto_cipher_decrypt, errp);
423c972fa12SVladimir Sementsov-Ogievskiy 
424c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_push_cipher(block, cipher);
425c972fa12SVladimir Sementsov-Ogievskiy 
426c972fa12SVladimir Sementsov-Ogievskiy     return ret;
427c972fa12SVladimir Sementsov-Ogievskiy }
4280f0d596cSVladimir Sementsov-Ogievskiy 
4290f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_encrypt_helper(QCryptoBlock *block,
4300f0d596cSVladimir Sementsov-Ogievskiy                                  int sectorsize,
4310f0d596cSVladimir Sementsov-Ogievskiy                                  uint64_t offset,
4320f0d596cSVladimir Sementsov-Ogievskiy                                  uint8_t *buf,
4330f0d596cSVladimir Sementsov-Ogievskiy                                  size_t len,
4340f0d596cSVladimir Sementsov-Ogievskiy                                  Error **errp)
4350f0d596cSVladimir Sementsov-Ogievskiy {
436c972fa12SVladimir Sementsov-Ogievskiy     int ret;
437c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
438c972fa12SVladimir Sementsov-Ogievskiy 
439c972fa12SVladimir Sementsov-Ogievskiy     ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
440c972fa12SVladimir Sementsov-Ogievskiy                                          &block->mutex, sectorsize, offset, buf,
441c972fa12SVladimir Sementsov-Ogievskiy                                          len, qcrypto_cipher_encrypt, errp);
442c972fa12SVladimir Sementsov-Ogievskiy 
443c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_push_cipher(block, cipher);
444c972fa12SVladimir Sementsov-Ogievskiy 
445c972fa12SVladimir Sementsov-Ogievskiy     return ret;
4460f0d596cSVladimir Sementsov-Ogievskiy }
447