xref: /openbmc/qemu/crypto/block.c (revision af206c284e4c1b17cdfb0f17e898b288c0fc1751)
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