xref: /openbmc/qemu/crypto/block.c (revision 1dc57b60380aa430b33f9b5d776be3bc1f65081e)
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
97d969014SDaniel P. Berrange  * version 2 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,
557d969014SDaniel P. Berrange                                  Error **errp)
567d969014SDaniel P. Berrange {
577d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
587d969014SDaniel P. Berrange 
597d969014SDaniel P. Berrange     block->format = options->format;
607d969014SDaniel P. Berrange 
617d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
627d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
6390d6f60dSDaniel P. Berrange         error_setg(errp, "Unsupported block driver %s",
64977c736fSMarkus Armbruster                    QCryptoBlockFormat_str(options->format));
657d969014SDaniel P. Berrange         g_free(block);
667d969014SDaniel P. Berrange         return NULL;
677d969014SDaniel P. Berrange     }
687d969014SDaniel P. Berrange 
697d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
707d969014SDaniel P. Berrange 
711cd9a787SDaniel P. Berrange     if (block->driver->open(block, options, optprefix,
727d969014SDaniel P. Berrange                             readfunc, opaque, flags, errp) < 0) {
737d969014SDaniel P. Berrange         g_free(block);
747d969014SDaniel P. Berrange         return NULL;
757d969014SDaniel P. Berrange     }
767d969014SDaniel P. Berrange 
777d969014SDaniel P. Berrange     return block;
787d969014SDaniel P. Berrange }
797d969014SDaniel P. Berrange 
807d969014SDaniel P. Berrange 
817d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
821cd9a787SDaniel P. Berrange                                    const char *optprefix,
837d969014SDaniel P. Berrange                                    QCryptoBlockInitFunc initfunc,
847d969014SDaniel P. Berrange                                    QCryptoBlockWriteFunc writefunc,
857d969014SDaniel P. Berrange                                    void *opaque,
867d969014SDaniel P. Berrange                                    Error **errp)
877d969014SDaniel P. Berrange {
887d969014SDaniel P. Berrange     QCryptoBlock *block = g_new0(QCryptoBlock, 1);
897d969014SDaniel P. Berrange 
907d969014SDaniel P. Berrange     block->format = options->format;
917d969014SDaniel P. Berrange 
927d969014SDaniel P. Berrange     if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
937d969014SDaniel P. Berrange         !qcrypto_block_drivers[options->format]) {
9490d6f60dSDaniel P. Berrange         error_setg(errp, "Unsupported block driver %s",
95977c736fSMarkus Armbruster                    QCryptoBlockFormat_str(options->format));
967d969014SDaniel P. Berrange         g_free(block);
977d969014SDaniel P. Berrange         return NULL;
987d969014SDaniel P. Berrange     }
997d969014SDaniel P. Berrange 
1007d969014SDaniel P. Berrange     block->driver = qcrypto_block_drivers[options->format];
1017d969014SDaniel P. Berrange 
1021cd9a787SDaniel P. Berrange     if (block->driver->create(block, options, optprefix, initfunc,
1037d969014SDaniel P. Berrange                               writefunc, opaque, errp) < 0) {
1047d969014SDaniel P. Berrange         g_free(block);
1057d969014SDaniel P. Berrange         return NULL;
1067d969014SDaniel P. Berrange     }
1077d969014SDaniel P. Berrange 
1087d969014SDaniel P. Berrange     return block;
1097d969014SDaniel P. Berrange }
1107d969014SDaniel P. Berrange 
1117d969014SDaniel P. Berrange 
11240c85028SDaniel P. Berrange QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
11340c85028SDaniel P. Berrange                                          Error **errp)
11440c85028SDaniel P. Berrange {
11540c85028SDaniel P. Berrange     QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
11640c85028SDaniel P. Berrange 
11740c85028SDaniel P. Berrange     info->format = block->format;
11840c85028SDaniel P. Berrange 
11940c85028SDaniel P. Berrange     if (block->driver->get_info &&
12040c85028SDaniel P. Berrange         block->driver->get_info(block, info, errp) < 0) {
12140c85028SDaniel P. Berrange         g_free(info);
12240c85028SDaniel P. Berrange         return NULL;
12340c85028SDaniel P. Berrange     }
12440c85028SDaniel P. Berrange 
12540c85028SDaniel P. Berrange     return info;
12640c85028SDaniel P. Berrange }
12740c85028SDaniel P. Berrange 
12840c85028SDaniel P. Berrange 
1297d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block,
1304609742aSDaniel P. Berrange                           uint64_t offset,
1317d969014SDaniel P. Berrange                           uint8_t *buf,
1327d969014SDaniel P. Berrange                           size_t len,
1337d969014SDaniel P. Berrange                           Error **errp)
1347d969014SDaniel P. Berrange {
1354609742aSDaniel P. Berrange     return block->driver->decrypt(block, offset, buf, len, errp);
1367d969014SDaniel P. Berrange }
1377d969014SDaniel P. Berrange 
1387d969014SDaniel P. Berrange 
1397d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block,
1404609742aSDaniel P. Berrange                           uint64_t offset,
1417d969014SDaniel P. Berrange                           uint8_t *buf,
1427d969014SDaniel P. Berrange                           size_t len,
1437d969014SDaniel P. Berrange                           Error **errp)
1447d969014SDaniel P. Berrange {
1454609742aSDaniel P. Berrange     return block->driver->encrypt(block, offset, buf, len, errp);
1467d969014SDaniel P. Berrange }
1477d969014SDaniel P. Berrange 
1487d969014SDaniel P. Berrange 
1497d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
1507d969014SDaniel P. Berrange {
1517d969014SDaniel P. Berrange     return block->cipher;
1527d969014SDaniel P. Berrange }
1537d969014SDaniel P. Berrange 
1547d969014SDaniel P. Berrange 
1557d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
1567d969014SDaniel P. Berrange {
1577d969014SDaniel P. Berrange     return block->ivgen;
1587d969014SDaniel P. Berrange }
1597d969014SDaniel P. Berrange 
1607d969014SDaniel P. Berrange 
1617d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
1627d969014SDaniel P. Berrange {
1637d969014SDaniel P. Berrange     return block->kdfhash;
1647d969014SDaniel P. Berrange }
1657d969014SDaniel P. Berrange 
1667d969014SDaniel P. Berrange 
1677d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
1687d969014SDaniel P. Berrange {
1697d969014SDaniel P. Berrange     return block->payload_offset;
1707d969014SDaniel P. Berrange }
1717d969014SDaniel P. Berrange 
1727d969014SDaniel P. Berrange 
173850f49deSDaniel P. Berrange uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
174850f49deSDaniel P. Berrange {
175850f49deSDaniel P. Berrange     return block->sector_size;
176850f49deSDaniel P. Berrange }
177850f49deSDaniel P. Berrange 
178850f49deSDaniel P. Berrange 
1797d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block)
1807d969014SDaniel P. Berrange {
1817d969014SDaniel P. Berrange     if (!block) {
1827d969014SDaniel P. Berrange         return;
1837d969014SDaniel P. Berrange     }
1847d969014SDaniel P. Berrange 
1857d969014SDaniel P. Berrange     block->driver->cleanup(block);
1867d969014SDaniel P. Berrange 
1877d969014SDaniel P. Berrange     qcrypto_cipher_free(block->cipher);
1887d969014SDaniel P. Berrange     qcrypto_ivgen_free(block->ivgen);
1897d969014SDaniel P. Berrange     g_free(block);
1907d969014SDaniel P. Berrange }
1917d969014SDaniel P. Berrange 
1927d969014SDaniel P. Berrange 
193*1dc57b60SVladimir Sementsov-Ogievskiy typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
194*1dc57b60SVladimir Sementsov-Ogievskiy                                        const void *in,
195*1dc57b60SVladimir Sementsov-Ogievskiy                                        void *out,
196*1dc57b60SVladimir Sementsov-Ogievskiy                                        size_t len,
197*1dc57b60SVladimir Sementsov-Ogievskiy                                        Error **errp);
198*1dc57b60SVladimir Sementsov-Ogievskiy 
199*1dc57b60SVladimir Sementsov-Ogievskiy static int do_qcrypto_block_encdec(QCryptoCipher *cipher,
2007d969014SDaniel P. Berrange                                    size_t niv,
2017d969014SDaniel P. Berrange                                    QCryptoIVGen *ivgen,
2027d969014SDaniel P. Berrange                                    int sectorsize,
2034609742aSDaniel P. Berrange                                    uint64_t offset,
2047d969014SDaniel P. Berrange                                    uint8_t *buf,
2057d969014SDaniel P. Berrange                                    size_t len,
206*1dc57b60SVladimir Sementsov-Ogievskiy                                    QCryptoCipherEncDecFunc func,
2077d969014SDaniel P. Berrange                                    Error **errp)
2087d969014SDaniel P. Berrange {
2097d969014SDaniel P. Berrange     uint8_t *iv;
2107d969014SDaniel P. Berrange     int ret = -1;
2114609742aSDaniel P. Berrange     uint64_t startsector = offset / sectorsize;
2124609742aSDaniel P. Berrange 
2134609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(offset, sectorsize));
2144609742aSDaniel P. Berrange     assert(QEMU_IS_ALIGNED(len, sectorsize));
2157d969014SDaniel P. Berrange 
2167d969014SDaniel P. Berrange     iv = niv ? g_new0(uint8_t, niv) : NULL;
2177d969014SDaniel P. Berrange 
2187d969014SDaniel P. Berrange     while (len > 0) {
2197d969014SDaniel P. Berrange         size_t nbytes;
2207d969014SDaniel P. Berrange         if (niv) {
2217d969014SDaniel P. Berrange             if (qcrypto_ivgen_calculate(ivgen,
2227d969014SDaniel P. Berrange                                         startsector,
2237d969014SDaniel P. Berrange                                         iv, niv,
2247d969014SDaniel P. Berrange                                         errp) < 0) {
2257d969014SDaniel P. Berrange                 goto cleanup;
2267d969014SDaniel P. Berrange             }
2277d969014SDaniel P. Berrange 
2287d969014SDaniel P. Berrange             if (qcrypto_cipher_setiv(cipher,
2297d969014SDaniel P. Berrange                                      iv, niv,
2307d969014SDaniel P. Berrange                                      errp) < 0) {
2317d969014SDaniel P. Berrange                 goto cleanup;
2327d969014SDaniel P. Berrange             }
2337d969014SDaniel P. Berrange         }
2347d969014SDaniel P. Berrange 
2357d969014SDaniel P. Berrange         nbytes = len > sectorsize ? sectorsize : len;
236*1dc57b60SVladimir Sementsov-Ogievskiy         if (func(cipher, buf, buf, nbytes, errp) < 0) {
2377d969014SDaniel P. Berrange             goto cleanup;
2387d969014SDaniel P. Berrange         }
2397d969014SDaniel P. Berrange 
2407d969014SDaniel P. Berrange         startsector++;
2417d969014SDaniel P. Berrange         buf += nbytes;
2427d969014SDaniel P. Berrange         len -= nbytes;
2437d969014SDaniel P. Berrange     }
2447d969014SDaniel P. Berrange 
2457d969014SDaniel P. Berrange     ret = 0;
2467d969014SDaniel P. Berrange  cleanup:
2477d969014SDaniel P. Berrange     g_free(iv);
2487d969014SDaniel P. Berrange     return ret;
2497d969014SDaniel P. Berrange }
2507d969014SDaniel P. Berrange 
2517d969014SDaniel P. Berrange 
252*1dc57b60SVladimir Sementsov-Ogievskiy int qcrypto_block_decrypt_helper(QCryptoCipher *cipher,
253*1dc57b60SVladimir Sementsov-Ogievskiy                                  size_t niv,
254*1dc57b60SVladimir Sementsov-Ogievskiy                                  QCryptoIVGen *ivgen,
255*1dc57b60SVladimir Sementsov-Ogievskiy                                  int sectorsize,
256*1dc57b60SVladimir Sementsov-Ogievskiy                                  uint64_t offset,
257*1dc57b60SVladimir Sementsov-Ogievskiy                                  uint8_t *buf,
258*1dc57b60SVladimir Sementsov-Ogievskiy                                  size_t len,
259*1dc57b60SVladimir Sementsov-Ogievskiy                                  Error **errp)
260*1dc57b60SVladimir Sementsov-Ogievskiy {
261*1dc57b60SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_encdec(cipher, niv, ivgen, sectorsize, offset,
262*1dc57b60SVladimir Sementsov-Ogievskiy                                    buf, len, qcrypto_cipher_decrypt, errp);
263*1dc57b60SVladimir Sementsov-Ogievskiy }
264*1dc57b60SVladimir Sementsov-Ogievskiy 
265*1dc57b60SVladimir Sementsov-Ogievskiy 
2667d969014SDaniel P. Berrange int qcrypto_block_encrypt_helper(QCryptoCipher *cipher,
2677d969014SDaniel P. Berrange                                  size_t niv,
2687d969014SDaniel P. Berrange                                  QCryptoIVGen *ivgen,
2697d969014SDaniel P. Berrange                                  int sectorsize,
2704609742aSDaniel P. Berrange                                  uint64_t offset,
2717d969014SDaniel P. Berrange                                  uint8_t *buf,
2727d969014SDaniel P. Berrange                                  size_t len,
2737d969014SDaniel P. Berrange                                  Error **errp)
2747d969014SDaniel P. Berrange {
275*1dc57b60SVladimir Sementsov-Ogievskiy     return do_qcrypto_block_encdec(cipher, niv, ivgen, sectorsize, offset,
276*1dc57b60SVladimir Sementsov-Ogievskiy                                    buf, len, qcrypto_cipher_encrypt, errp);
2777d969014SDaniel P. Berrange }
278