xref: /openbmc/qemu/crypto/block.c (revision b8eada54b2ad8a7d98d93d5ab4d3e888c5880097)
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"
23af206c28SStefan 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[] = {
29d23d2ef3SMarkus Armbruster     [QCRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
30d23d2ef3SMarkus Armbruster     [QCRYPTO_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,
567d969014SDaniel P. Berrange                                  Error **errp)
577d969014SDaniel P. Berrange {
587d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
597d969014SDaniel P. Berrange 
60af206c28SStefan Hajnoczi     qemu_mutex_init(&block->mutex);
61af206c28SStefan Hajnoczi 
627d969014SDaniel P. Berrange     block->format = options->format;
637d969014SDaniel P. Berrange 
647d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
657d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
6690d6f60dSDaniel P. Berrange         error_setg(errp, "Unsupported block driver %s",
67977c736fSMarkus Armbruster                    QCryptoBlockFormat_str(options->format));
687d969014SDaniel P. Berrange         g_free(block);
697d969014SDaniel P. Berrange         return NULL;
707d969014SDaniel P. Berrange     }
717d969014SDaniel P. Berrange 
727d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
737d969014SDaniel P. Berrange 
741cd9a787SDaniel P. Berrange     if (block->driver->open(block, options, optprefix,
753ab0f063SStefan Hajnoczi                             readfunc, opaque, flags, errp) < 0)
76c972fa12SVladimir Sementsov-Ogievskiy     {
777d969014SDaniel P. Berrange         g_free(block);
787d969014SDaniel P. Berrange         return NULL;
797d969014SDaniel P. Berrange     }
807d969014SDaniel P. Berrange 
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,
90d74523a3SHyman Huang                                    unsigned int flags,
917d969014SDaniel P. Berrange                                    Error **errp)
927d969014SDaniel P. Berrange {
937d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
947d969014SDaniel P. Berrange 
95af206c28SStefan Hajnoczi     qemu_mutex_init(&block->mutex);
96af206c28SStefan Hajnoczi 
977d969014SDaniel P. Berrange     block->format = options->format;
987d969014SDaniel P. Berrange 
997d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
1007d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
10190d6f60dSDaniel P. Berrange         error_setg(errp, "Unsupported block driver %s",
102977c736fSMarkus Armbruster                    QCryptoBlockFormat_str(options->format));
1037d969014SDaniel P. Berrange         g_free(block);
1047d969014SDaniel P. Berrange         return NULL;
1057d969014SDaniel P. Berrange     }
1067d969014SDaniel P. Berrange 
1077d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
108d74523a3SHyman Huang     block->detached_header = flags & QCRYPTO_BLOCK_CREATE_DETACHED;
1097d969014SDaniel P. Berrange 
1101cd9a787SDaniel P. Berrange     if (block->driver->create(block, options, optprefix, initfunc,
1117d969014SDaniel P. Berrange                               writefunc, opaque, errp) < 0) {
1127d969014SDaniel P. Berrange         g_free(block);
1137d969014SDaniel P. Berrange         return NULL;
1147d969014SDaniel P. Berrange     }
1157d969014SDaniel P. Berrange 
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,
151d74523a3SHyman 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      */
230af206c28SStefan Hajnoczi     assert(block->max_free_ciphers <= 1);
231af206c28SStefan Hajnoczi     return block->free_ciphers ? block->free_ciphers[0] : NULL;
2327d969014SDaniel P. Berrange }
2337d969014SDaniel P. Berrange 
2347d969014SDaniel P. Berrange 
235af206c28SStefan Hajnoczi static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block,
236af206c28SStefan Hajnoczi                                                Error **errp)
237c972fa12SVladimir Sementsov-Ogievskiy {
238af206c28SStefan Hajnoczi     /* Usually there is a free cipher available */
239af206c28SStefan Hajnoczi     WITH_QEMU_LOCK_GUARD(&block->mutex) {
240af206c28SStefan Hajnoczi         if (block->n_free_ciphers > 0) {
241c972fa12SVladimir Sementsov-Ogievskiy             block->n_free_ciphers--;
242af206c28SStefan Hajnoczi             return block->free_ciphers[block->n_free_ciphers];
243af206c28SStefan Hajnoczi         }
244af206c28SStefan Hajnoczi     }
245c972fa12SVladimir Sementsov-Ogievskiy 
246af206c28SStefan Hajnoczi     /* Otherwise allocate a new cipher */
247af206c28SStefan Hajnoczi     return qcrypto_cipher_new(block->alg, block->mode, block->key,
248af206c28SStefan Hajnoczi                               block->nkey, errp);
249c972fa12SVladimir Sementsov-Ogievskiy }
250c972fa12SVladimir Sementsov-Ogievskiy 
251c972fa12SVladimir Sementsov-Ogievskiy 
252c972fa12SVladimir Sementsov-Ogievskiy static void qcrypto_block_push_cipher(QCryptoBlock *block,
253c972fa12SVladimir Sementsov-Ogievskiy                                       QCryptoCipher *cipher)
254c972fa12SVladimir Sementsov-Ogievskiy {
255af206c28SStefan Hajnoczi     QEMU_LOCK_GUARD(&block->mutex);
256c972fa12SVladimir Sementsov-Ogievskiy 
257af206c28SStefan Hajnoczi     if (block->n_free_ciphers == block->max_free_ciphers) {
258af206c28SStefan Hajnoczi         block->max_free_ciphers++;
259af206c28SStefan Hajnoczi         block->free_ciphers = g_renew(QCryptoCipher *,
260af206c28SStefan Hajnoczi                                       block->free_ciphers,
261af206c28SStefan Hajnoczi                                       block->max_free_ciphers);
262af206c28SStefan Hajnoczi     }
263af206c28SStefan Hajnoczi 
264af206c28SStefan Hajnoczi     block->free_ciphers[block->n_free_ciphers] = cipher;
265c972fa12SVladimir Sementsov-Ogievskiy     block->n_free_ciphers++;
266c972fa12SVladimir Sementsov-Ogievskiy }
267c972fa12SVladimir Sementsov-Ogievskiy 
268c972fa12SVladimir Sementsov-Ogievskiy 
269c972fa12SVladimir Sementsov-Ogievskiy int qcrypto_block_init_cipher(QCryptoBlock *block,
270*a092c513SMarkus Armbruster                               QCryptoCipherAlgo alg,
271c972fa12SVladimir Sementsov-Ogievskiy                               QCryptoCipherMode mode,
272c972fa12SVladimir Sementsov-Ogievskiy                               const uint8_t *key, size_t nkey,
273af206c28SStefan Hajnoczi                               Error **errp)
274c972fa12SVladimir Sementsov-Ogievskiy {
275af206c28SStefan Hajnoczi     QCryptoCipher *cipher;
276c972fa12SVladimir Sementsov-Ogievskiy 
277af206c28SStefan Hajnoczi     assert(!block->free_ciphers && !block->max_free_ciphers &&
278af206c28SStefan Hajnoczi            !block->n_free_ciphers);
279c972fa12SVladimir Sementsov-Ogievskiy 
280af206c28SStefan Hajnoczi     /* Stash away cipher parameters for qcrypto_block_pop_cipher() */
281af206c28SStefan Hajnoczi     block->alg = alg;
282af206c28SStefan Hajnoczi     block->mode = mode;
283af206c28SStefan Hajnoczi     block->key = g_memdup2(key, nkey);
284af206c28SStefan Hajnoczi     block->nkey = nkey;
285c972fa12SVladimir Sementsov-Ogievskiy 
286af206c28SStefan Hajnoczi     /*
287af206c28SStefan Hajnoczi      * Create a new cipher to validate the parameters now. This reduces the
288af206c28SStefan Hajnoczi      * chance of cipher creation failing at I/O time.
289af206c28SStefan Hajnoczi      */
290af206c28SStefan Hajnoczi     cipher = qcrypto_block_pop_cipher(block, errp);
291af206c28SStefan Hajnoczi     if (!cipher) {
292af206c28SStefan Hajnoczi         g_free(block->key);
293af206c28SStefan Hajnoczi         block->key = NULL;
294c972fa12SVladimir Sementsov-Ogievskiy         return -1;
295c972fa12SVladimir Sementsov-Ogievskiy     }
296c972fa12SVladimir Sementsov-Ogievskiy 
297af206c28SStefan Hajnoczi     qcrypto_block_push_cipher(block, cipher);
298c972fa12SVladimir Sementsov-Ogievskiy     return 0;
299c972fa12SVladimir Sementsov-Ogievskiy }
300c972fa12SVladimir Sementsov-Ogievskiy 
301c972fa12SVladimir Sementsov-Ogievskiy 
302c972fa12SVladimir Sementsov-Ogievskiy void qcrypto_block_free_cipher(QCryptoBlock *block)
303c972fa12SVladimir Sementsov-Ogievskiy {
304c972fa12SVladimir Sementsov-Ogievskiy     size_t i;
305c972fa12SVladimir Sementsov-Ogievskiy 
306af206c28SStefan Hajnoczi     g_free(block->key);
307af206c28SStefan Hajnoczi     block->key = NULL;
308af206c28SStefan Hajnoczi 
309af206c28SStefan Hajnoczi     if (!block->free_ciphers) {
310c972fa12SVladimir Sementsov-Ogievskiy         return;
311c972fa12SVladimir Sementsov-Ogievskiy     }
312c972fa12SVladimir Sementsov-Ogievskiy 
313af206c28SStefan Hajnoczi     /* All popped ciphers were eventually pushed back */
314af206c28SStefan Hajnoczi     assert(block->n_free_ciphers == block->max_free_ciphers);
315c972fa12SVladimir Sementsov-Ogievskiy 
316af206c28SStefan Hajnoczi     for (i = 0; i < block->max_free_ciphers; i++) {
317af206c28SStefan Hajnoczi         qcrypto_cipher_free(block->free_ciphers[i]);
318c972fa12SVladimir Sementsov-Ogievskiy     }
319c972fa12SVladimir Sementsov-Ogievskiy 
320af206c28SStefan Hajnoczi     g_free(block->free_ciphers);
321af206c28SStefan Hajnoczi     block->free_ciphers = NULL;
322af206c28SStefan Hajnoczi     block->max_free_ciphers = block->n_free_ciphers = 0;
323c972fa12SVladimir Sementsov-Ogievskiy }
324c972fa12SVladimir Sementsov-Ogievskiy 
3257d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
3267d969014SDaniel P. Berrange {
327c972fa12SVladimir Sementsov-Ogievskiy     /* ivgen should be accessed under mutex. However, this function is used only
328c972fa12SVladimir Sementsov-Ogievskiy      * in test with one thread, so it's enough to assert it here:
329c972fa12SVladimir Sementsov-Ogievskiy      */
330af206c28SStefan Hajnoczi     assert(block->max_free_ciphers <= 1);
3317d969014SDaniel P. Berrange     return block->ivgen;
3327d969014SDaniel P. Berrange }
3337d969014SDaniel P. Berrange 
3347d969014SDaniel P. Berrange 
335ef834aa2SMarkus Armbruster QCryptoHashAlgo qcrypto_block_get_kdf_hash(QCryptoBlock *block)
3367d969014SDaniel P. Berrange {
3377d969014SDaniel P. Berrange     return block->kdfhash;
3387d969014SDaniel P. Berrange }
3397d969014SDaniel P. Berrange 
3407d969014SDaniel P. Berrange 
3417d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
3427d969014SDaniel P. Berrange {
3437d969014SDaniel P. Berrange     return block->payload_offset;
3447d969014SDaniel P. Berrange }
3457d969014SDaniel P. Berrange 
3467d969014SDaniel P. Berrange 
347850f49deSDaniel P. Berrange uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
348850f49deSDaniel P. Berrange {
349850f49deSDaniel P. Berrange     return block->sector_size;
350850f49deSDaniel P. Berrange }
351850f49deSDaniel P. Berrange 
352850f49deSDaniel P. Berrange 
3537d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block)
3547d969014SDaniel P. Berrange {
3557d969014SDaniel P. Berrange     if (!block) {
3567d969014SDaniel P. Berrange         return;
3577d969014SDaniel P. Berrange     }
3587d969014SDaniel P. Berrange 
3597d969014SDaniel P. Berrange     block->driver->cleanup(block);
3607d969014SDaniel P. Berrange 
361c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_free_cipher(block);
3627d969014SDaniel P. Berrange     qcrypto_ivgen_free(block->ivgen);
363c972fa12SVladimir Sementsov-Ogievskiy     qemu_mutex_destroy(&block->mutex);
3647d969014SDaniel P. Berrange     g_free(block);
3657d969014SDaniel P. Berrange }
3667d969014SDaniel P. Berrange 
3677d969014SDaniel P. Berrange 
3681dc57b60SVladimir Sementsov-Ogievskiy typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
3691dc57b60SVladimir Sementsov-Ogievskiy                                         const void *in,
3701dc57b60SVladimir Sementsov-Ogievskiy                                         void *out,
3711dc57b60SVladimir Sementsov-Ogievskiy                                         size_t len,
3721dc57b60SVladimir Sementsov-Ogievskiy                                         Error **errp);
3731dc57b60SVladimir Sementsov-Ogievskiy 
3740270417cSVladimir Sementsov-Ogievskiy static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
3757d969014SDaniel P. Berrange                                           size_t niv,
3767d969014SDaniel P. Berrange                                           QCryptoIVGen *ivgen,
377c972fa12SVladimir Sementsov-Ogievskiy                                           QemuMutex *ivgen_mutex,
3787d969014SDaniel P. Berrange                                           int sectorsize,
3794609742aSDaniel P. Berrange                                           uint64_t offset,
3807d969014SDaniel P. Berrange                                           uint8_t *buf,
3817d969014SDaniel P. Berrange                                           size_t len,
3821dc57b60SVladimir Sementsov-Ogievskiy                                           QCryptoCipherEncDecFunc func,
3837d969014SDaniel P. Berrange                                           Error **errp)
3847d969014SDaniel P. Berrange {
38557b9f113SDaniel P. Berrangé     g_autofree uint8_t *iv = niv ? g_new0(uint8_t, niv) : NULL;
3867d969014SDaniel P. Berrange     int ret = -1;
3874609742aSDaniel P. Berrange     uint64_t startsector = offset / sectorsize;
3884609742aSDaniel P. Berrange 
3894609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(offset, sectorsize));
3904609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(len, sectorsize));
3917d969014SDaniel P. Berrange 
3927d969014SDaniel P. Berrange     while (len > 0) {
3937d969014SDaniel P. Berrange         size_t nbytes;
3947d969014SDaniel P. Berrange         if (niv) {
395c972fa12SVladimir Sementsov-Ogievskiy             if (ivgen_mutex) {
396c972fa12SVladimir Sementsov-Ogievskiy                 qemu_mutex_lock(ivgen_mutex);
397c972fa12SVladimir Sementsov-Ogievskiy             }
398c972fa12SVladimir Sementsov-Ogievskiy             ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
399c972fa12SVladimir Sementsov-Ogievskiy             if (ivgen_mutex) {
400c972fa12SVladimir Sementsov-Ogievskiy                 qemu_mutex_unlock(ivgen_mutex);
401c972fa12SVladimir Sementsov-Ogievskiy             }
402c972fa12SVladimir Sementsov-Ogievskiy 
403c972fa12SVladimir Sementsov-Ogievskiy             if (ret < 0) {
40457b9f113SDaniel P. Berrangé                 return -1;
4057d969014SDaniel P. Berrange             }
4067d969014SDaniel P. Berrange 
4077d969014SDaniel P. Berrange             if (qcrypto_cipher_setiv(cipher,
4087d969014SDaniel P. Berrange                                      iv, niv,
4097d969014SDaniel P. Berrange                                      errp) < 0) {
41057b9f113SDaniel P. Berrangé                 return -1;
4117d969014SDaniel P. Berrange             }
4127d969014SDaniel P. Berrange         }
4137d969014SDaniel P. Berrange 
4147d969014SDaniel P. Berrange         nbytes = len > sectorsize ? sectorsize : len;
4151dc57b60SVladimir Sementsov-Ogievskiy         if (func(cipher, buf, buf, nbytes, errp) < 0) {
41657b9f113SDaniel P. Berrangé             return -1;
4177d969014SDaniel P. Berrange         }
4187d969014SDaniel P. Berrange 
4197d969014SDaniel P. Berrange         startsector++;
4207d969014SDaniel P. Berrange         buf += nbytes;
4217d969014SDaniel P. Berrange         len -= nbytes;
4227d969014SDaniel P. Berrange     }
4237d969014SDaniel P. Berrange 
42457b9f113SDaniel P. Berrangé     return 0;
4257d969014SDaniel P. Berrange }
4267d969014SDaniel P. Berrange 
4277d969014SDaniel P. Berrange 
4280270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
4291dc57b60SVladimir Sementsov-Ogievskiy                                         size_t niv,
4301dc57b60SVladimir Sementsov-Ogievskiy                                         QCryptoIVGen *ivgen,
4311dc57b60SVladimir Sementsov-Ogievskiy                                         int sectorsize,
4321dc57b60SVladimir Sementsov-Ogievskiy                                         uint64_t offset,
4331dc57b60SVladimir Sementsov-Ogievskiy                                         uint8_t *buf,
4341dc57b60SVladimir Sementsov-Ogievskiy                                         size_t len,
4351dc57b60SVladimir Sementsov-Ogievskiy                                         Error **errp)
4361dc57b60SVladimir Sementsov-Ogievskiy {
437c972fa12SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
4380270417cSVladimir Sementsov-Ogievskiy                                           offset, buf, len,
4390270417cSVladimir Sementsov-Ogievskiy                                           qcrypto_cipher_decrypt, errp);
4401dc57b60SVladimir Sementsov-Ogievskiy }
4411dc57b60SVladimir Sementsov-Ogievskiy 
4421dc57b60SVladimir Sementsov-Ogievskiy 
4430270417cSVladimir Sementsov-Ogievskiy int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
4447d969014SDaniel P. Berrange                                         size_t niv,
4457d969014SDaniel P. Berrange                                         QCryptoIVGen *ivgen,
4467d969014SDaniel P. Berrange                                         int sectorsize,
4474609742aSDaniel P. Berrange                                         uint64_t offset,
4487d969014SDaniel P. Berrange                                         uint8_t *buf,
4497d969014SDaniel P. Berrange                                         size_t len,
4507d969014SDaniel P. Berrange                                         Error **errp)
4517d969014SDaniel P. Berrange {
452c972fa12SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
4530270417cSVladimir Sementsov-Ogievskiy                                           offset, buf, len,
4540270417cSVladimir Sementsov-Ogievskiy                                           qcrypto_cipher_encrypt, errp);
4557d969014SDaniel P. Berrange }
4560f0d596cSVladimir Sementsov-Ogievskiy 
4570f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_decrypt_helper(QCryptoBlock *block,
4580f0d596cSVladimir Sementsov-Ogievskiy                                  int sectorsize,
4590f0d596cSVladimir Sementsov-Ogievskiy                                  uint64_t offset,
4600f0d596cSVladimir Sementsov-Ogievskiy                                  uint8_t *buf,
4610f0d596cSVladimir Sementsov-Ogievskiy                                  size_t len,
4620f0d596cSVladimir Sementsov-Ogievskiy                                  Error **errp)
4630f0d596cSVladimir Sementsov-Ogievskiy {
464c972fa12SVladimir Sementsov-Ogievskiy     int ret;
465af206c28SStefan Hajnoczi     QCryptoCipher *cipher = qcrypto_block_pop_cipher(block, errp);
466af206c28SStefan Hajnoczi     if (!cipher) {
467af206c28SStefan Hajnoczi         return -1;
468af206c28SStefan Hajnoczi     }
4690f0d596cSVladimir 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_decrypt, errp);
473c972fa12SVladimir Sementsov-Ogievskiy 
474c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_push_cipher(block, cipher);
475c972fa12SVladimir Sementsov-Ogievskiy 
476c972fa12SVladimir Sementsov-Ogievskiy     return ret;
477c972fa12SVladimir Sementsov-Ogievskiy }
4780f0d596cSVladimir Sementsov-Ogievskiy 
4790f0d596cSVladimir Sementsov-Ogievskiy int qcrypto_block_encrypt_helper(QCryptoBlock *block,
4800f0d596cSVladimir Sementsov-Ogievskiy                                  int sectorsize,
4810f0d596cSVladimir Sementsov-Ogievskiy                                  uint64_t offset,
4820f0d596cSVladimir Sementsov-Ogievskiy                                  uint8_t *buf,
4830f0d596cSVladimir Sementsov-Ogievskiy                                  size_t len,
4840f0d596cSVladimir Sementsov-Ogievskiy                                  Error **errp)
4850f0d596cSVladimir Sementsov-Ogievskiy {
486c972fa12SVladimir Sementsov-Ogievskiy     int ret;
487af206c28SStefan Hajnoczi     QCryptoCipher *cipher = qcrypto_block_pop_cipher(block, errp);
488af206c28SStefan Hajnoczi     if (!cipher) {
489af206c28SStefan Hajnoczi         return -1;
490af206c28SStefan Hajnoczi     }
491c972fa12SVladimir Sementsov-Ogievskiy 
492c972fa12SVladimir Sementsov-Ogievskiy     ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
493c972fa12SVladimir Sementsov-Ogievskiy                                          &block->mutex, sectorsize, offset, buf,
494c972fa12SVladimir Sementsov-Ogievskiy                                          len, qcrypto_cipher_encrypt, errp);
495c972fa12SVladimir Sementsov-Ogievskiy 
496c972fa12SVladimir Sementsov-Ogievskiy     qcrypto_block_push_cipher(block, cipher);
497c972fa12SVladimir Sementsov-Ogievskiy 
498c972fa12SVladimir Sementsov-Ogievskiy     return ret;
4990f0d596cSVladimir Sementsov-Ogievskiy }
500