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" 237d969014SDaniel P. Berrange #include "crypto/blockpriv.h" 247d969014SDaniel P. Berrange #include "crypto/block-qcow.h" 253e308f20SDaniel P. Berrange #include "crypto/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, 1307d969014SDaniel P. Berrange uint64_t startsector, 1317d969014SDaniel P. Berrange uint8_t *buf, 1327d969014SDaniel P. Berrange size_t len, 1337d969014SDaniel P. Berrange Error **errp) 1347d969014SDaniel P. Berrange { 1357d969014SDaniel P. Berrange return block->driver->decrypt(block, startsector, buf, len, errp); 1367d969014SDaniel P. Berrange } 1377d969014SDaniel P. Berrange 1387d969014SDaniel P. Berrange 1397d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block, 1407d969014SDaniel P. Berrange uint64_t startsector, 1417d969014SDaniel P. Berrange uint8_t *buf, 1427d969014SDaniel P. Berrange size_t len, 1437d969014SDaniel P. Berrange Error **errp) 1447d969014SDaniel P. Berrange { 1457d969014SDaniel P. Berrange return block->driver->encrypt(block, startsector, 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 173*850f49deSDaniel P. Berrange uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block) 174*850f49deSDaniel P. Berrange { 175*850f49deSDaniel P. Berrange return block->sector_size; 176*850f49deSDaniel P. Berrange } 177*850f49deSDaniel P. Berrange 178*850f49deSDaniel 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 1937d969014SDaniel P. Berrange int qcrypto_block_decrypt_helper(QCryptoCipher *cipher, 1947d969014SDaniel P. Berrange size_t niv, 1957d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 1967d969014SDaniel P. Berrange int sectorsize, 1977d969014SDaniel P. Berrange uint64_t startsector, 1987d969014SDaniel P. Berrange uint8_t *buf, 1997d969014SDaniel P. Berrange size_t len, 2007d969014SDaniel P. Berrange Error **errp) 2017d969014SDaniel P. Berrange { 2027d969014SDaniel P. Berrange uint8_t *iv; 2037d969014SDaniel P. Berrange int ret = -1; 2047d969014SDaniel P. Berrange 2057d969014SDaniel P. Berrange iv = niv ? g_new0(uint8_t, niv) : NULL; 2067d969014SDaniel P. Berrange 2077d969014SDaniel P. Berrange while (len > 0) { 2087d969014SDaniel P. Berrange size_t nbytes; 2097d969014SDaniel P. Berrange if (niv) { 2107d969014SDaniel P. Berrange if (qcrypto_ivgen_calculate(ivgen, 2117d969014SDaniel P. Berrange startsector, 2127d969014SDaniel P. Berrange iv, niv, 2137d969014SDaniel P. Berrange errp) < 0) { 2147d969014SDaniel P. Berrange goto cleanup; 2157d969014SDaniel P. Berrange } 2167d969014SDaniel P. Berrange 2177d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 2187d969014SDaniel P. Berrange iv, niv, 2197d969014SDaniel P. Berrange errp) < 0) { 2207d969014SDaniel P. Berrange goto cleanup; 2217d969014SDaniel P. Berrange } 2227d969014SDaniel P. Berrange } 2237d969014SDaniel P. Berrange 2247d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 2257d969014SDaniel P. Berrange if (qcrypto_cipher_decrypt(cipher, buf, buf, 2267d969014SDaniel P. Berrange nbytes, errp) < 0) { 2277d969014SDaniel P. Berrange goto cleanup; 2287d969014SDaniel P. Berrange } 2297d969014SDaniel P. Berrange 2307d969014SDaniel P. Berrange startsector++; 2317d969014SDaniel P. Berrange buf += nbytes; 2327d969014SDaniel P. Berrange len -= nbytes; 2337d969014SDaniel P. Berrange } 2347d969014SDaniel P. Berrange 2357d969014SDaniel P. Berrange ret = 0; 2367d969014SDaniel P. Berrange cleanup: 2377d969014SDaniel P. Berrange g_free(iv); 2387d969014SDaniel P. Berrange return ret; 2397d969014SDaniel P. Berrange } 2407d969014SDaniel P. Berrange 2417d969014SDaniel P. Berrange 2427d969014SDaniel P. Berrange int qcrypto_block_encrypt_helper(QCryptoCipher *cipher, 2437d969014SDaniel P. Berrange size_t niv, 2447d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 2457d969014SDaniel P. Berrange int sectorsize, 2467d969014SDaniel P. Berrange uint64_t startsector, 2477d969014SDaniel P. Berrange uint8_t *buf, 2487d969014SDaniel P. Berrange size_t len, 2497d969014SDaniel P. Berrange Error **errp) 2507d969014SDaniel P. Berrange { 2517d969014SDaniel P. Berrange uint8_t *iv; 2527d969014SDaniel P. Berrange int ret = -1; 2537d969014SDaniel P. Berrange 2547d969014SDaniel P. Berrange iv = niv ? g_new0(uint8_t, niv) : NULL; 2557d969014SDaniel P. Berrange 2567d969014SDaniel P. Berrange while (len > 0) { 2577d969014SDaniel P. Berrange size_t nbytes; 2587d969014SDaniel P. Berrange if (niv) { 2597d969014SDaniel P. Berrange if (qcrypto_ivgen_calculate(ivgen, 2607d969014SDaniel P. Berrange startsector, 2617d969014SDaniel P. Berrange iv, niv, 2627d969014SDaniel P. Berrange errp) < 0) { 2637d969014SDaniel P. Berrange goto cleanup; 2647d969014SDaniel P. Berrange } 2657d969014SDaniel P. Berrange 2667d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 2677d969014SDaniel P. Berrange iv, niv, 2687d969014SDaniel P. Berrange errp) < 0) { 2697d969014SDaniel P. Berrange goto cleanup; 2707d969014SDaniel P. Berrange } 2717d969014SDaniel P. Berrange } 2727d969014SDaniel P. Berrange 2737d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 2747d969014SDaniel P. Berrange if (qcrypto_cipher_encrypt(cipher, buf, buf, 2757d969014SDaniel P. Berrange nbytes, errp) < 0) { 2767d969014SDaniel P. Berrange goto cleanup; 2777d969014SDaniel P. Berrange } 2787d969014SDaniel P. Berrange 2797d969014SDaniel P. Berrange startsector++; 2807d969014SDaniel P. Berrange buf += nbytes; 2817d969014SDaniel P. Berrange len -= nbytes; 2827d969014SDaniel P. Berrange } 2837d969014SDaniel P. Berrange 2847d969014SDaniel P. Berrange ret = 0; 2857d969014SDaniel P. Berrange cleanup: 2867d969014SDaniel P. Berrange g_free(iv); 2877d969014SDaniel P. Berrange return ret; 2887d969014SDaniel P. Berrange } 289