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, 517d969014SDaniel P. Berrange QCryptoBlockReadFunc readfunc, 527d969014SDaniel P. Berrange void *opaque, 537d969014SDaniel P. Berrange unsigned int flags, 547d969014SDaniel P. Berrange Error **errp) 557d969014SDaniel P. Berrange { 567d969014SDaniel P. Berrange QCryptoBlock *block = g_new0(QCryptoBlock, 1); 577d969014SDaniel P. Berrange 587d969014SDaniel P. Berrange block->format = options->format; 597d969014SDaniel P. Berrange 607d969014SDaniel P. Berrange if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || 617d969014SDaniel P. Berrange !qcrypto_block_drivers[options->format]) { 627d969014SDaniel P. Berrange error_setg(errp, "Unsupported block driver %d", options->format); 637d969014SDaniel P. Berrange g_free(block); 647d969014SDaniel P. Berrange return NULL; 657d969014SDaniel P. Berrange } 667d969014SDaniel P. Berrange 677d969014SDaniel P. Berrange block->driver = qcrypto_block_drivers[options->format]; 687d969014SDaniel P. Berrange 697d969014SDaniel P. Berrange if (block->driver->open(block, options, 707d969014SDaniel P. Berrange readfunc, opaque, flags, errp) < 0) { 717d969014SDaniel P. Berrange g_free(block); 727d969014SDaniel P. Berrange return NULL; 737d969014SDaniel P. Berrange } 747d969014SDaniel P. Berrange 757d969014SDaniel P. Berrange return block; 767d969014SDaniel P. Berrange } 777d969014SDaniel P. Berrange 787d969014SDaniel P. Berrange 797d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, 807d969014SDaniel P. Berrange QCryptoBlockInitFunc initfunc, 817d969014SDaniel P. Berrange QCryptoBlockWriteFunc writefunc, 827d969014SDaniel P. Berrange void *opaque, 837d969014SDaniel P. Berrange Error **errp) 847d969014SDaniel P. Berrange { 857d969014SDaniel P. Berrange QCryptoBlock *block = g_new0(QCryptoBlock, 1); 867d969014SDaniel P. Berrange 877d969014SDaniel P. Berrange block->format = options->format; 887d969014SDaniel P. Berrange 897d969014SDaniel P. Berrange if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || 907d969014SDaniel P. Berrange !qcrypto_block_drivers[options->format]) { 917d969014SDaniel P. Berrange error_setg(errp, "Unsupported block driver %d", options->format); 927d969014SDaniel P. Berrange g_free(block); 937d969014SDaniel P. Berrange return NULL; 947d969014SDaniel P. Berrange } 957d969014SDaniel P. Berrange 967d969014SDaniel P. Berrange block->driver = qcrypto_block_drivers[options->format]; 977d969014SDaniel P. Berrange 987d969014SDaniel P. Berrange if (block->driver->create(block, options, initfunc, 997d969014SDaniel P. Berrange writefunc, opaque, errp) < 0) { 1007d969014SDaniel P. Berrange g_free(block); 1017d969014SDaniel P. Berrange return NULL; 1027d969014SDaniel P. Berrange } 1037d969014SDaniel P. Berrange 1047d969014SDaniel P. Berrange return block; 1057d969014SDaniel P. Berrange } 1067d969014SDaniel P. Berrange 1077d969014SDaniel P. Berrange 108*40c85028SDaniel P. Berrange QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block, 109*40c85028SDaniel P. Berrange Error **errp) 110*40c85028SDaniel P. Berrange { 111*40c85028SDaniel P. Berrange QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1); 112*40c85028SDaniel P. Berrange 113*40c85028SDaniel P. Berrange info->format = block->format; 114*40c85028SDaniel P. Berrange 115*40c85028SDaniel P. Berrange if (block->driver->get_info && 116*40c85028SDaniel P. Berrange block->driver->get_info(block, info, errp) < 0) { 117*40c85028SDaniel P. Berrange g_free(info); 118*40c85028SDaniel P. Berrange return NULL; 119*40c85028SDaniel P. Berrange } 120*40c85028SDaniel P. Berrange 121*40c85028SDaniel P. Berrange return info; 122*40c85028SDaniel P. Berrange } 123*40c85028SDaniel P. Berrange 124*40c85028SDaniel P. Berrange 1257d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block, 1267d969014SDaniel P. Berrange uint64_t startsector, 1277d969014SDaniel P. Berrange uint8_t *buf, 1287d969014SDaniel P. Berrange size_t len, 1297d969014SDaniel P. Berrange Error **errp) 1307d969014SDaniel P. Berrange { 1317d969014SDaniel P. Berrange return block->driver->decrypt(block, startsector, buf, len, errp); 1327d969014SDaniel P. Berrange } 1337d969014SDaniel P. Berrange 1347d969014SDaniel P. Berrange 1357d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block, 1367d969014SDaniel P. Berrange uint64_t startsector, 1377d969014SDaniel P. Berrange uint8_t *buf, 1387d969014SDaniel P. Berrange size_t len, 1397d969014SDaniel P. Berrange Error **errp) 1407d969014SDaniel P. Berrange { 1417d969014SDaniel P. Berrange return block->driver->encrypt(block, startsector, buf, len, errp); 1427d969014SDaniel P. Berrange } 1437d969014SDaniel P. Berrange 1447d969014SDaniel P. Berrange 1457d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block) 1467d969014SDaniel P. Berrange { 1477d969014SDaniel P. Berrange return block->cipher; 1487d969014SDaniel P. Berrange } 1497d969014SDaniel P. Berrange 1507d969014SDaniel P. Berrange 1517d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block) 1527d969014SDaniel P. Berrange { 1537d969014SDaniel P. Berrange return block->ivgen; 1547d969014SDaniel P. Berrange } 1557d969014SDaniel P. Berrange 1567d969014SDaniel P. Berrange 1577d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block) 1587d969014SDaniel P. Berrange { 1597d969014SDaniel P. Berrange return block->kdfhash; 1607d969014SDaniel P. Berrange } 1617d969014SDaniel P. Berrange 1627d969014SDaniel P. Berrange 1637d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block) 1647d969014SDaniel P. Berrange { 1657d969014SDaniel P. Berrange return block->payload_offset; 1667d969014SDaniel P. Berrange } 1677d969014SDaniel P. Berrange 1687d969014SDaniel P. Berrange 1697d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block) 1707d969014SDaniel P. Berrange { 1717d969014SDaniel P. Berrange if (!block) { 1727d969014SDaniel P. Berrange return; 1737d969014SDaniel P. Berrange } 1747d969014SDaniel P. Berrange 1757d969014SDaniel P. Berrange block->driver->cleanup(block); 1767d969014SDaniel P. Berrange 1777d969014SDaniel P. Berrange qcrypto_cipher_free(block->cipher); 1787d969014SDaniel P. Berrange qcrypto_ivgen_free(block->ivgen); 1797d969014SDaniel P. Berrange g_free(block); 1807d969014SDaniel P. Berrange } 1817d969014SDaniel P. Berrange 1827d969014SDaniel P. Berrange 1837d969014SDaniel P. Berrange int qcrypto_block_decrypt_helper(QCryptoCipher *cipher, 1847d969014SDaniel P. Berrange size_t niv, 1857d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 1867d969014SDaniel P. Berrange int sectorsize, 1877d969014SDaniel P. Berrange uint64_t startsector, 1887d969014SDaniel P. Berrange uint8_t *buf, 1897d969014SDaniel P. Berrange size_t len, 1907d969014SDaniel P. Berrange Error **errp) 1917d969014SDaniel P. Berrange { 1927d969014SDaniel P. Berrange uint8_t *iv; 1937d969014SDaniel P. Berrange int ret = -1; 1947d969014SDaniel P. Berrange 1957d969014SDaniel P. Berrange iv = niv ? g_new0(uint8_t, niv) : NULL; 1967d969014SDaniel P. Berrange 1977d969014SDaniel P. Berrange while (len > 0) { 1987d969014SDaniel P. Berrange size_t nbytes; 1997d969014SDaniel P. Berrange if (niv) { 2007d969014SDaniel P. Berrange if (qcrypto_ivgen_calculate(ivgen, 2017d969014SDaniel P. Berrange startsector, 2027d969014SDaniel P. Berrange iv, niv, 2037d969014SDaniel P. Berrange errp) < 0) { 2047d969014SDaniel P. Berrange goto cleanup; 2057d969014SDaniel P. Berrange } 2067d969014SDaniel P. Berrange 2077d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 2087d969014SDaniel P. Berrange iv, niv, 2097d969014SDaniel P. Berrange errp) < 0) { 2107d969014SDaniel P. Berrange goto cleanup; 2117d969014SDaniel P. Berrange } 2127d969014SDaniel P. Berrange } 2137d969014SDaniel P. Berrange 2147d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 2157d969014SDaniel P. Berrange if (qcrypto_cipher_decrypt(cipher, buf, buf, 2167d969014SDaniel P. Berrange nbytes, errp) < 0) { 2177d969014SDaniel P. Berrange goto cleanup; 2187d969014SDaniel P. Berrange } 2197d969014SDaniel P. Berrange 2207d969014SDaniel P. Berrange startsector++; 2217d969014SDaniel P. Berrange buf += nbytes; 2227d969014SDaniel P. Berrange len -= nbytes; 2237d969014SDaniel P. Berrange } 2247d969014SDaniel P. Berrange 2257d969014SDaniel P. Berrange ret = 0; 2267d969014SDaniel P. Berrange cleanup: 2277d969014SDaniel P. Berrange g_free(iv); 2287d969014SDaniel P. Berrange return ret; 2297d969014SDaniel P. Berrange } 2307d969014SDaniel P. Berrange 2317d969014SDaniel P. Berrange 2327d969014SDaniel P. Berrange int qcrypto_block_encrypt_helper(QCryptoCipher *cipher, 2337d969014SDaniel P. Berrange size_t niv, 2347d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 2357d969014SDaniel P. Berrange int sectorsize, 2367d969014SDaniel P. Berrange uint64_t startsector, 2377d969014SDaniel P. Berrange uint8_t *buf, 2387d969014SDaniel P. Berrange size_t len, 2397d969014SDaniel P. Berrange Error **errp) 2407d969014SDaniel P. Berrange { 2417d969014SDaniel P. Berrange uint8_t *iv; 2427d969014SDaniel P. Berrange int ret = -1; 2437d969014SDaniel P. Berrange 2447d969014SDaniel P. Berrange iv = niv ? g_new0(uint8_t, niv) : NULL; 2457d969014SDaniel P. Berrange 2467d969014SDaniel P. Berrange while (len > 0) { 2477d969014SDaniel P. Berrange size_t nbytes; 2487d969014SDaniel P. Berrange if (niv) { 2497d969014SDaniel P. Berrange if (qcrypto_ivgen_calculate(ivgen, 2507d969014SDaniel P. Berrange startsector, 2517d969014SDaniel P. Berrange iv, niv, 2527d969014SDaniel P. Berrange errp) < 0) { 2537d969014SDaniel P. Berrange goto cleanup; 2547d969014SDaniel P. Berrange } 2557d969014SDaniel P. Berrange 2567d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 2577d969014SDaniel P. Berrange iv, niv, 2587d969014SDaniel P. Berrange errp) < 0) { 2597d969014SDaniel P. Berrange goto cleanup; 2607d969014SDaniel P. Berrange } 2617d969014SDaniel P. Berrange } 2627d969014SDaniel P. Berrange 2637d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 2647d969014SDaniel P. Berrange if (qcrypto_cipher_encrypt(cipher, buf, buf, 2657d969014SDaniel P. Berrange nbytes, errp) < 0) { 2667d969014SDaniel P. Berrange goto cleanup; 2677d969014SDaniel P. Berrange } 2687d969014SDaniel P. Berrange 2697d969014SDaniel P. Berrange startsector++; 2707d969014SDaniel P. Berrange buf += nbytes; 2717d969014SDaniel P. Berrange len -= nbytes; 2727d969014SDaniel P. Berrange } 2737d969014SDaniel P. Berrange 2747d969014SDaniel P. Berrange ret = 0; 2757d969014SDaniel P. Berrange cleanup: 2767d969014SDaniel P. Berrange g_free(iv); 2777d969014SDaniel P. Berrange return ret; 2787d969014SDaniel P. Berrange } 279