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