xref: /openbmc/qemu/crypto/block.c (revision 43cbd06df2dcdfe236e68351bb3c350e0d1d857a)
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 
1186d49d3a8SStefan Hajnoczi static ssize_t qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block,
1196d49d3a8SStefan Hajnoczi         size_t headerlen, void *opaque, Error **errp)
1206d49d3a8SStefan Hajnoczi {
1216d49d3a8SStefan Hajnoczi     size_t *headerlenp = opaque;
1226d49d3a8SStefan Hajnoczi 
1236d49d3a8SStefan Hajnoczi     /* Stash away the payload size */
1246d49d3a8SStefan Hajnoczi     *headerlenp = headerlen;
1256d49d3a8SStefan Hajnoczi     return 0;
1266d49d3a8SStefan Hajnoczi }
1276d49d3a8SStefan Hajnoczi 
1286d49d3a8SStefan Hajnoczi 
1296d49d3a8SStefan Hajnoczi static ssize_t qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block,
1306d49d3a8SStefan Hajnoczi         size_t offset, const uint8_t *buf, size_t buflen,
1316d49d3a8SStefan Hajnoczi         void *opaque, Error **errp)
1326d49d3a8SStefan Hajnoczi {
1336d49d3a8SStefan Hajnoczi     /* Discard the bytes, we're not actually writing to an image */
1346d49d3a8SStefan Hajnoczi     return buflen;
1356d49d3a8SStefan Hajnoczi }
1366d49d3a8SStefan Hajnoczi 
1376d49d3a8SStefan Hajnoczi 
1386d49d3a8SStefan Hajnoczi bool
1396d49d3a8SStefan Hajnoczi qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
1406d49d3a8SStefan Hajnoczi                                        const char *optprefix,
1416d49d3a8SStefan Hajnoczi                                        size_t *len,
1426d49d3a8SStefan Hajnoczi                                        Error **errp)
1436d49d3a8SStefan Hajnoczi {
1446d49d3a8SStefan Hajnoczi     /* Fake LUKS creation in order to determine the payload size */
1456d49d3a8SStefan Hajnoczi     g_autoptr(QCryptoBlock) crypto =
1466d49d3a8SStefan Hajnoczi         qcrypto_block_create(create_opts, optprefix,
1476d49d3a8SStefan Hajnoczi                              qcrypto_block_headerlen_hdr_init_func,
1486d49d3a8SStefan Hajnoczi                              qcrypto_block_headerlen_hdr_write_func,
1496d49d3a8SStefan Hajnoczi                              len, errp);
1506d49d3a8SStefan Hajnoczi     return crypto != NULL;
1516d49d3a8SStefan Hajnoczi }
1526d49d3a8SStefan Hajnoczi 
153*43cbd06dSMaxim Levitsky int qcrypto_block_amend_options(QCryptoBlock *block,
154*43cbd06dSMaxim Levitsky                                 QCryptoBlockReadFunc readfunc,
155*43cbd06dSMaxim Levitsky                                 QCryptoBlockWriteFunc writefunc,
156*43cbd06dSMaxim Levitsky                                 void *opaque,
157*43cbd06dSMaxim Levitsky                                 QCryptoBlockAmendOptions *options,
158*43cbd06dSMaxim Levitsky                                 bool force,
159*43cbd06dSMaxim Levitsky                                 Error **errp)
160*43cbd06dSMaxim Levitsky {
161*43cbd06dSMaxim Levitsky     if (options->format != block->format) {
162*43cbd06dSMaxim Levitsky         error_setg(errp,
163*43cbd06dSMaxim Levitsky                    "Cannot amend encryption format");
164*43cbd06dSMaxim Levitsky         return -1;
165*43cbd06dSMaxim Levitsky     }
166*43cbd06dSMaxim Levitsky 
167*43cbd06dSMaxim Levitsky     if (!block->driver->amend) {
168*43cbd06dSMaxim Levitsky         error_setg(errp,
169*43cbd06dSMaxim Levitsky                    "Crypto format %s doesn't support format options amendment",
170*43cbd06dSMaxim Levitsky                    QCryptoBlockFormat_str(block->format));
171*43cbd06dSMaxim Levitsky         return -1;
172*43cbd06dSMaxim Levitsky     }
173*43cbd06dSMaxim Levitsky 
174*43cbd06dSMaxim Levitsky     return block->driver->amend(block,
175*43cbd06dSMaxim Levitsky                                 readfunc,
176*43cbd06dSMaxim Levitsky                                 writefunc,
177*43cbd06dSMaxim Levitsky                                 opaque,
178*43cbd06dSMaxim Levitsky                                 options,
179*43cbd06dSMaxim Levitsky                                 force,
180*43cbd06dSMaxim Levitsky                                 errp);
181*43cbd06dSMaxim Levitsky }
1826d49d3a8SStefan Hajnoczi 
18340c85028SDaniel P. Berrange QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
18440c85028SDaniel P. Berrange                                          Error **errp)
18540c85028SDaniel P. Berrange {
18640c85028SDaniel P. Berrange     QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
18740c85028SDaniel P. Berrange 
18840c85028SDaniel P. Berrange     info->format = block->format;
18940c85028SDaniel P. Berrange 
19040c85028SDaniel P. Berrange     if (block->driver->get_info &&
19140c85028SDaniel P. Berrange         block->driver->get_info(block, info, errp) < 0) {
19240c85028SDaniel P. Berrange         g_free(info);
19340c85028SDaniel P. Berrange         return NULL;
19440c85028SDaniel P. Berrange     }
19540c85028SDaniel P. Berrange 
19640c85028SDaniel P. Berrange     return info;
19740c85028SDaniel P. Berrange }
19840c85028SDaniel P. Berrange 
19940c85028SDaniel P. Berrange 
2007d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block,
2014609742aSDaniel P. Berrange                           uint64_t offset,
2027d969014SDaniel P. Berrange                           uint8_t *buf,
2037d969014SDaniel P. Berrange                           size_t len,
2047d969014SDaniel P. Berrange                           Error **errp)
2057d969014SDaniel P. Berrange {
2064609742aSDaniel P. Berrange     return block->driver->decrypt(block, offset, buf, len, errp);
2077d969014SDaniel P. Berrange }
2087d969014SDaniel P. Berrange 
2097d969014SDaniel P. Berrange 
2107d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block,
2114609742aSDaniel P. Berrange                           uint64_t offset,
2127d969014SDaniel P. Berrange                           uint8_t *buf,
2137d969014SDaniel P. Berrange                           size_t len,
2147d969014SDaniel P. Berrange                           Error **errp)
2157d969014SDaniel P. Berrange {
2164609742aSDaniel P. Berrange     return block->driver->encrypt(block, offset, buf, len, errp);
2177d969014SDaniel P. Berrange }
2187d969014SDaniel P. Berrange 
2197d969014SDaniel P. Berrange 
2207d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
2217d969014SDaniel P. Berrange {
222c972fa12SVladimir Sementsov-Ogievskiy     /* Ciphers should be accessed through pop/push method to be thread-safe.
223c972fa12SVladimir Sementsov-Ogievskiy      * Better, they should not be accessed externally at all (note, that
224c972fa12SVladimir Sementsov-Ogievskiy      * pop/push are static functions)
225c972fa12SVladimir Sementsov-Ogievskiy      * This function is used only in test with one thread (it's safe to skip
226c972fa12SVladimir Sementsov-Ogievskiy      * pop/push interface), so it's enough to assert it here:
227c972fa12SVladimir Sementsov-Ogievskiy      */
228c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers <= 1);
229c972fa12SVladimir Sementsov-Ogievskiy     return block->ciphers ? block->ciphers[0] : NULL;
2307d969014SDaniel P. Berrange }
2317d969014SDaniel P. Berrange 
2327d969014SDaniel P. Berrange 
233c972fa12SVladimir Sementsov-Ogievskiy static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block)
234c972fa12SVladimir Sementsov-Ogievskiy {
235c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher;
236c972fa12SVladimir Sementsov-Ogievskiy 
237c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_lock(&block->mutex);
238c972fa12SVladimir Sementsov-Ogievskiy 
239c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_free_ciphers > 0);
240c972fa12SVladimir Sementsov-Ogievskiy     block->n_free_ciphers--;
241c972fa12SVladimir Sementsov-Ogievskiy     cipher = block->ciphers[block->n_free_ciphers];
242c972fa12SVladimir Sementsov-Ogievskiy 
243c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_unlock(&block->mutex);
244c972fa12SVladimir Sementsov-Ogievskiy 
245c972fa12SVladimir Sementsov-Ogievskiy     return cipher;
246c972fa12SVladimir Sementsov-Ogievskiy }
247c972fa12SVladimir Sementsov-Ogievskiy 
248c972fa12SVladimir Sementsov-Ogievskiy 
249c972fa12SVladimir Sementsov-Ogievskiy static void qcrypto_block_push_cipher(QCryptoBlock *block,
250c972fa12SVladimir Sementsov-Ogievskiy                                       QCryptoCipher *cipher)
251c972fa12SVladimir Sementsov-Ogievskiy {
252c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_lock(&block->mutex);
253c972fa12SVladimir Sementsov-Ogievskiy 
254c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_free_ciphers < block->n_ciphers);
255c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers[block->n_free_ciphers] = cipher;
256c972fa12SVladimir Sementsov-Ogievskiy     block->n_free_ciphers++;
257c972fa12SVladimir Sementsov-Ogievskiy 
258c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_unlock(&block->mutex);
259c972fa12SVladimir Sementsov-Ogievskiy }
260c972fa12SVladimir Sementsov-Ogievskiy 
261c972fa12SVladimir Sementsov-Ogievskiy 
262c972fa12SVladimir Sementsov-Ogievskiy int qcrypto_block_init_cipher(QCryptoBlock *block,
263c972fa12SVladimir Sementsov-Ogievskiy                               QCryptoCipherAlgorithm alg,
264c972fa12SVladimir Sementsov-Ogievskiy                               QCryptoCipherMode mode,
265c972fa12SVladimir Sementsov-Ogievskiy                               const uint8_t *key, size_t nkey,
266c972fa12SVladimir Sementsov-Ogievskiy                               size_t n_threads, Error **errp)
267c972fa12SVladimir Sementsov-Ogievskiy {
268c972fa12SVladimir Sementsov-Ogievskiy     size_t i;
269c972fa12SVladimir Sementsov-Ogievskiy 
270c972fa12SVladimir Sementsov-Ogievskiy     assert(!block->ciphers && !block->n_ciphers && !block->n_free_ciphers);
271c972fa12SVladimir Sementsov-Ogievskiy 
272c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers = g_new0(QCryptoCipher *, n_threads);
273c972fa12SVladimir Sementsov-Ogievskiy 
274c972fa12SVladimir Sementsov-Ogievskiy     for (i = 0; i < n_threads; i++) {
275c972fa12SVladimir Sementsov-Ogievskiy         block->ciphers[i] = qcrypto_cipher_new(alg, mode, key, nkey, errp);
276c972fa12SVladimir Sementsov-Ogievskiy         if (!block->ciphers[i]) {
277c972fa12SVladimir Sementsov-Ogievskiy             qcrypto_block_free_cipher(block);
278c972fa12SVladimir Sementsov-Ogievskiy             return -1;
279c972fa12SVladimir Sementsov-Ogievskiy         }
280c972fa12SVladimir Sementsov-Ogievskiy         block->n_ciphers++;
281c972fa12SVladimir Sementsov-Ogievskiy         block->n_free_ciphers++;
282c972fa12SVladimir Sementsov-Ogievskiy     }
283c972fa12SVladimir Sementsov-Ogievskiy 
284c972fa12SVladimir Sementsov-Ogievskiy     return 0;
285c972fa12SVladimir Sementsov-Ogievskiy }
286c972fa12SVladimir Sementsov-Ogievskiy 
287c972fa12SVladimir Sementsov-Ogievskiy 
288c972fa12SVladimir Sementsov-Ogievskiy void qcrypto_block_free_cipher(QCryptoBlock *block)
289c972fa12SVladimir Sementsov-Ogievskiy {
290c972fa12SVladimir Sementsov-Ogievskiy     size_t i;
291c972fa12SVladimir Sementsov-Ogievskiy 
292c972fa12SVladimir Sementsov-Ogievskiy     if (!block->ciphers) {
293c972fa12SVladimir Sementsov-Ogievskiy         return;
294c972fa12SVladimir Sementsov-Ogievskiy     }
295c972fa12SVladimir Sementsov-Ogievskiy 
296c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers == block->n_free_ciphers);
297c972fa12SVladimir Sementsov-Ogievskiy 
298c972fa12SVladimir Sementsov-Ogievskiy     for (i = 0; i < block->n_ciphers; i++) {
299c972fa12SVladimir Sementsov-Ogievskiy         qcrypto_cipher_free(block->ciphers[i]);
300c972fa12SVladimir Sementsov-Ogievskiy     }
301c972fa12SVladimir Sementsov-Ogievskiy 
302c972fa12SVladimir Sementsov-Ogievskiy     g_free(block->ciphers);
303c972fa12SVladimir Sementsov-Ogievskiy     block->ciphers = NULL;
304c972fa12SVladimir Sementsov-Ogievskiy     block->n_ciphers = block->n_free_ciphers = 0;
305c972fa12SVladimir Sementsov-Ogievskiy }
306c972fa12SVladimir Sementsov-Ogievskiy 
3077d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
3087d969014SDaniel P. Berrange {
309c972fa12SVladimir Sementsov-Ogievskiy     /* ivgen should be accessed under mutex. However, this function is used only
310c972fa12SVladimir Sementsov-Ogievskiy      * in test with one thread, so it's enough to assert it here:
311c972fa12SVladimir Sementsov-Ogievskiy      */
312c972fa12SVladimir Sementsov-Ogievskiy     assert(block->n_ciphers <= 1);
3137d969014SDaniel P. Berrange     return block->ivgen;
3147d969014SDaniel P. Berrange }
3157d969014SDaniel P. Berrange 
3167d969014SDaniel P. Berrange 
3177d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
3187d969014SDaniel P. Berrange {
3197d969014SDaniel P. Berrange     return block->kdfhash;
3207d969014SDaniel P. Berrange }
3217d969014SDaniel P. Berrange 
3227d969014SDaniel P. Berrange 
3237d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
3247d969014SDaniel P. Berrange {
3257d969014SDaniel P. Berrange     return block->payload_offset;
3267d969014SDaniel P. Berrange }
3277d969014SDaniel P. Berrange 
3287d969014SDaniel P. Berrange 
329850f49deSDaniel P. Berrange uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
330850f49deSDaniel P. Berrange {
331850f49deSDaniel P. Berrange     return block->sector_size;
332850f49deSDaniel P. Berrange }
333850f49deSDaniel P. Berrange 
334850f49deSDaniel P. Berrange 
3357d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block)
3367d969014SDaniel P. Berrange {
3377d969014SDaniel P. Berrange     if (!block) {
3387d969014SDaniel P. Berrange         return;
3397d969014SDaniel P. Berrange     }
3407d969014SDaniel P. Berrange 
3417d969014SDaniel P. Berrange     block->driver->cleanup(block);
3427d969014SDaniel P. Berrange 
343c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_free_cipher(block);
3447d969014SDaniel P. Berrange     qcrypto_ivgen_free(block->ivgen);
345c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_destroy(&block->mutex);
3467d969014SDaniel P. Berrange     g_free(block);
3477d969014SDaniel P. Berrange }
3487d969014SDaniel P. Berrange 
3497d969014SDaniel P. Berrange 
3501dc57b60SVladimir Sementsov-Ogievskiy typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
3511dc57b60SVladimir Sementsov-Ogievskiy                                         const void *in,
3521dc57b60SVladimir Sementsov-Ogievskiy                                         void *out,
3531dc57b60SVladimir Sementsov-Ogievskiy                                         size_t len,
3541dc57b60SVladimir Sementsov-Ogievskiy                                         Error **errp);
3551dc57b60SVladimir Sementsov-Ogievskiy 
3560270417cSVladimir Sementsov-Ogievskiy static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
3577d969014SDaniel P. Berrange                                           size_t niv,
3587d969014SDaniel P. Berrange                                           QCryptoIVGen *ivgen,
359c972fa12SVladimir Sementsov-Ogievskiy                                           QemuMutex *ivgen_mutex,
3607d969014SDaniel P. Berrange                                           int sectorsize,
3614609742aSDaniel P. Berrange                                           uint64_t offset,
3627d969014SDaniel P. Berrange                                           uint8_t *buf,
3637d969014SDaniel P. Berrange                                           size_t len,
3641dc57b60SVladimir Sementsov-Ogievskiy                                           QCryptoCipherEncDecFunc func,
3657d969014SDaniel P. Berrange                                           Error **errp)
3667d969014SDaniel P. Berrange {
36757b9f113SDaniel P. Berrangé     g_autofree uint8_t *iv = niv ? g_new0(uint8_t, niv) : NULL;
3687d969014SDaniel P. Berrange     int ret = -1;
3694609742aSDaniel P. Berrange     uint64_t startsector = offset / sectorsize;
3704609742aSDaniel P. Berrange 
3714609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(offset, sectorsize));
3724609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(len, sectorsize));
3737d969014SDaniel P. Berrange 
3747d969014SDaniel P. Berrange     while (len > 0) {
3757d969014SDaniel P. Berrange         size_t nbytes;
3767d969014SDaniel P. Berrange         if (niv) {
377c972fa12SVladimir Sementsov-Ogievskiy             if (ivgen_mutex) {
378c972fa12SVladimir Sementsov-Ogievskiy                 qemu_mutex_lock(ivgen_mutex);
379c972fa12SVladimir Sementsov-Ogievskiy             }
380c972fa12SVladimir Sementsov-Ogievskiy             ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
381c972fa12SVladimir Sementsov-Ogievskiy             if (ivgen_mutex) {
382c972fa12SVladimir Sementsov-Ogievskiy                 qemu_mutex_unlock(ivgen_mutex);
383c972fa12SVladimir Sementsov-Ogievskiy             }
384c972fa12SVladimir Sementsov-Ogievskiy 
385c972fa12SVladimir Sementsov-Ogievskiy             if (ret < 0) {
38657b9f113SDaniel P. Berrangé                 return -1;
3877d969014SDaniel P. Berrange             }
3887d969014SDaniel P. Berrange 
3897d969014SDaniel P. Berrange             if (qcrypto_cipher_setiv(cipher,
3907d969014SDaniel P. Berrange                                      iv, niv,
3917d969014SDaniel P. Berrange                                      errp) < 0) {
39257b9f113SDaniel P. Berrangé                 return -1;
3937d969014SDaniel P. Berrange             }
3947d969014SDaniel P. Berrange         }
3957d969014SDaniel P. Berrange 
3967d969014SDaniel P. Berrange         nbytes = len > sectorsize ? sectorsize : len;
3971dc57b60SVladimir Sementsov-Ogievskiy         if (func(cipher, buf, buf, nbytes, errp) < 0) {
39857b9f113SDaniel P. Berrangé             return -1;
3997d969014SDaniel P. Berrange         }
4007d969014SDaniel P. Berrange 
4017d969014SDaniel P. Berrange         startsector++;
4027d969014SDaniel P. Berrange         buf += nbytes;
4037d969014SDaniel P. Berrange         len -= nbytes;
4047d969014SDaniel P. Berrange     }
4057d969014SDaniel P. Berrange 
40657b9f113SDaniel P. Berrangé     return 0;
4077d969014SDaniel P. Berrange }
4087d969014SDaniel P. Berrange 
4097d969014SDaniel P. Berrange 
4100270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
4111dc57b60SVladimir Sementsov-Ogievskiy                                         size_t niv,
4121dc57b60SVladimir Sementsov-Ogievskiy                                         QCryptoIVGen *ivgen,
4131dc57b60SVladimir Sementsov-Ogievskiy                                         int sectorsize,
4141dc57b60SVladimir Sementsov-Ogievskiy                                         uint64_t offset,
4151dc57b60SVladimir Sementsov-Ogievskiy                                         uint8_t *buf,
4161dc57b60SVladimir Sementsov-Ogievskiy                                         size_t len,
4171dc57b60SVladimir Sementsov-Ogievskiy                                         Error **errp)
4181dc57b60SVladimir Sementsov-Ogievskiy {
419c972fa12SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
4200270417cSVladimir Sementsov-Ogievskiy                                           offset, buf, len,
4210270417cSVladimir Sementsov-Ogievskiy                                           qcrypto_cipher_decrypt, errp);
4221dc57b60SVladimir Sementsov-Ogievskiy }
4231dc57b60SVladimir Sementsov-Ogievskiy 
4241dc57b60SVladimir Sementsov-Ogievskiy 
4250270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
4267d969014SDaniel P. Berrange                                         size_t niv,
4277d969014SDaniel P. Berrange                                         QCryptoIVGen *ivgen,
4287d969014SDaniel P. Berrange                                         int sectorsize,
4294609742aSDaniel P. Berrange                                         uint64_t offset,
4307d969014SDaniel P. Berrange                                         uint8_t *buf,
4317d969014SDaniel P. Berrange                                         size_t len,
4327d969014SDaniel P. Berrange                                         Error **errp)
4337d969014SDaniel P. Berrange {
434c972fa12SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
4350270417cSVladimir Sementsov-Ogievskiy                                           offset, buf, len,
4360270417cSVladimir Sementsov-Ogievskiy                                           qcrypto_cipher_encrypt, errp);
4377d969014SDaniel P. Berrange }
4380f0d596cSVladimir Sementsov-Ogievskiy 
4390f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_decrypt_helper(QCryptoBlock *block,
4400f0d596cSVladimir Sementsov-Ogievskiy                                  int sectorsize,
4410f0d596cSVladimir Sementsov-Ogievskiy                                  uint64_t offset,
4420f0d596cSVladimir Sementsov-Ogievskiy                                  uint8_t *buf,
4430f0d596cSVladimir Sementsov-Ogievskiy                                  size_t len,
4440f0d596cSVladimir Sementsov-Ogievskiy                                  Error **errp)
4450f0d596cSVladimir Sementsov-Ogievskiy {
446c972fa12SVladimir Sementsov-Ogievskiy     int ret;
447c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
4480f0d596cSVladimir Sementsov-Ogievskiy 
449c972fa12SVladimir Sementsov-Ogievskiy     ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
450c972fa12SVladimir Sementsov-Ogievskiy                                          &block->mutex, sectorsize, offset, buf,
451c972fa12SVladimir Sementsov-Ogievskiy                                          len, qcrypto_cipher_decrypt, errp);
452c972fa12SVladimir Sementsov-Ogievskiy 
453c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_push_cipher(block, cipher);
454c972fa12SVladimir Sementsov-Ogievskiy 
455c972fa12SVladimir Sementsov-Ogievskiy     return ret;
456c972fa12SVladimir Sementsov-Ogievskiy }
4570f0d596cSVladimir Sementsov-Ogievskiy 
4580f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_encrypt_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;
466c972fa12SVladimir Sementsov-Ogievskiy     QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
467c972fa12SVladimir Sementsov-Ogievskiy 
468c972fa12SVladimir Sementsov-Ogievskiy     ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
469c972fa12SVladimir Sementsov-Ogievskiy                                          &block->mutex, sectorsize, offset, buf,
470c972fa12SVladimir Sementsov-Ogievskiy                                          len, qcrypto_cipher_encrypt, errp);
471c972fa12SVladimir Sementsov-Ogievskiy 
472c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_push_cipher(block, cipher);
473c972fa12SVladimir Sementsov-Ogievskiy 
474c972fa12SVladimir Sementsov-Ogievskiy     return ret;
4750f0d596cSVladimir Sementsov-Ogievskiy }
476