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" 22*da34e65cSMarkus 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 1087d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block, 1097d969014SDaniel P. Berrange uint64_t startsector, 1107d969014SDaniel P. Berrange uint8_t *buf, 1117d969014SDaniel P. Berrange size_t len, 1127d969014SDaniel P. Berrange Error **errp) 1137d969014SDaniel P. Berrange { 1147d969014SDaniel P. Berrange return block->driver->decrypt(block, startsector, buf, len, errp); 1157d969014SDaniel P. Berrange } 1167d969014SDaniel P. Berrange 1177d969014SDaniel P. Berrange 1187d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block, 1197d969014SDaniel P. Berrange uint64_t startsector, 1207d969014SDaniel P. Berrange uint8_t *buf, 1217d969014SDaniel P. Berrange size_t len, 1227d969014SDaniel P. Berrange Error **errp) 1237d969014SDaniel P. Berrange { 1247d969014SDaniel P. Berrange return block->driver->encrypt(block, startsector, buf, len, errp); 1257d969014SDaniel P. Berrange } 1267d969014SDaniel P. Berrange 1277d969014SDaniel P. Berrange 1287d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block) 1297d969014SDaniel P. Berrange { 1307d969014SDaniel P. Berrange return block->cipher; 1317d969014SDaniel P. Berrange } 1327d969014SDaniel P. Berrange 1337d969014SDaniel P. Berrange 1347d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block) 1357d969014SDaniel P. Berrange { 1367d969014SDaniel P. Berrange return block->ivgen; 1377d969014SDaniel P. Berrange } 1387d969014SDaniel P. Berrange 1397d969014SDaniel P. Berrange 1407d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block) 1417d969014SDaniel P. Berrange { 1427d969014SDaniel P. Berrange return block->kdfhash; 1437d969014SDaniel P. Berrange } 1447d969014SDaniel P. Berrange 1457d969014SDaniel P. Berrange 1467d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block) 1477d969014SDaniel P. Berrange { 1487d969014SDaniel P. Berrange return block->payload_offset; 1497d969014SDaniel P. Berrange } 1507d969014SDaniel P. Berrange 1517d969014SDaniel P. Berrange 1527d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block) 1537d969014SDaniel P. Berrange { 1547d969014SDaniel P. Berrange if (!block) { 1557d969014SDaniel P. Berrange return; 1567d969014SDaniel P. Berrange } 1577d969014SDaniel P. Berrange 1587d969014SDaniel P. Berrange block->driver->cleanup(block); 1597d969014SDaniel P. Berrange 1607d969014SDaniel P. Berrange qcrypto_cipher_free(block->cipher); 1617d969014SDaniel P. Berrange qcrypto_ivgen_free(block->ivgen); 1627d969014SDaniel P. Berrange g_free(block); 1637d969014SDaniel P. Berrange } 1647d969014SDaniel P. Berrange 1657d969014SDaniel P. Berrange 1667d969014SDaniel P. Berrange int qcrypto_block_decrypt_helper(QCryptoCipher *cipher, 1677d969014SDaniel P. Berrange size_t niv, 1687d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 1697d969014SDaniel P. Berrange int sectorsize, 1707d969014SDaniel P. Berrange uint64_t startsector, 1717d969014SDaniel P. Berrange uint8_t *buf, 1727d969014SDaniel P. Berrange size_t len, 1737d969014SDaniel P. Berrange Error **errp) 1747d969014SDaniel P. Berrange { 1757d969014SDaniel P. Berrange uint8_t *iv; 1767d969014SDaniel P. Berrange int ret = -1; 1777d969014SDaniel P. Berrange 1787d969014SDaniel P. Berrange iv = niv ? g_new0(uint8_t, niv) : NULL; 1797d969014SDaniel P. Berrange 1807d969014SDaniel P. Berrange while (len > 0) { 1817d969014SDaniel P. Berrange size_t nbytes; 1827d969014SDaniel P. Berrange if (niv) { 1837d969014SDaniel P. Berrange if (qcrypto_ivgen_calculate(ivgen, 1847d969014SDaniel P. Berrange startsector, 1857d969014SDaniel P. Berrange iv, niv, 1867d969014SDaniel P. Berrange errp) < 0) { 1877d969014SDaniel P. Berrange goto cleanup; 1887d969014SDaniel P. Berrange } 1897d969014SDaniel P. Berrange 1907d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 1917d969014SDaniel P. Berrange iv, niv, 1927d969014SDaniel P. Berrange errp) < 0) { 1937d969014SDaniel P. Berrange goto cleanup; 1947d969014SDaniel P. Berrange } 1957d969014SDaniel P. Berrange } 1967d969014SDaniel P. Berrange 1977d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 1987d969014SDaniel P. Berrange if (qcrypto_cipher_decrypt(cipher, buf, buf, 1997d969014SDaniel P. Berrange nbytes, errp) < 0) { 2007d969014SDaniel P. Berrange goto cleanup; 2017d969014SDaniel P. Berrange } 2027d969014SDaniel P. Berrange 2037d969014SDaniel P. Berrange startsector++; 2047d969014SDaniel P. Berrange buf += nbytes; 2057d969014SDaniel P. Berrange len -= nbytes; 2067d969014SDaniel P. Berrange } 2077d969014SDaniel P. Berrange 2087d969014SDaniel P. Berrange ret = 0; 2097d969014SDaniel P. Berrange cleanup: 2107d969014SDaniel P. Berrange g_free(iv); 2117d969014SDaniel P. Berrange return ret; 2127d969014SDaniel P. Berrange } 2137d969014SDaniel P. Berrange 2147d969014SDaniel P. Berrange 2157d969014SDaniel P. Berrange int qcrypto_block_encrypt_helper(QCryptoCipher *cipher, 2167d969014SDaniel P. Berrange size_t niv, 2177d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 2187d969014SDaniel P. Berrange int sectorsize, 2197d969014SDaniel P. Berrange uint64_t startsector, 2207d969014SDaniel P. Berrange uint8_t *buf, 2217d969014SDaniel P. Berrange size_t len, 2227d969014SDaniel P. Berrange Error **errp) 2237d969014SDaniel P. Berrange { 2247d969014SDaniel P. Berrange uint8_t *iv; 2257d969014SDaniel P. Berrange int ret = -1; 2267d969014SDaniel P. Berrange 2277d969014SDaniel P. Berrange iv = niv ? g_new0(uint8_t, niv) : NULL; 2287d969014SDaniel P. Berrange 2297d969014SDaniel P. Berrange while (len > 0) { 2307d969014SDaniel P. Berrange size_t nbytes; 2317d969014SDaniel P. Berrange if (niv) { 2327d969014SDaniel P. Berrange if (qcrypto_ivgen_calculate(ivgen, 2337d969014SDaniel P. Berrange startsector, 2347d969014SDaniel P. Berrange iv, niv, 2357d969014SDaniel P. Berrange errp) < 0) { 2367d969014SDaniel P. Berrange goto cleanup; 2377d969014SDaniel P. Berrange } 2387d969014SDaniel P. Berrange 2397d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 2407d969014SDaniel P. Berrange iv, niv, 2417d969014SDaniel P. Berrange errp) < 0) { 2427d969014SDaniel P. Berrange goto cleanup; 2437d969014SDaniel P. Berrange } 2447d969014SDaniel P. Berrange } 2457d969014SDaniel P. Berrange 2467d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 2477d969014SDaniel P. Berrange if (qcrypto_cipher_encrypt(cipher, buf, buf, 2487d969014SDaniel P. Berrange nbytes, errp) < 0) { 2497d969014SDaniel P. Berrange goto cleanup; 2507d969014SDaniel P. Berrange } 2517d969014SDaniel P. Berrange 2527d969014SDaniel P. Berrange startsector++; 2537d969014SDaniel P. Berrange buf += nbytes; 2547d969014SDaniel P. Berrange len -= nbytes; 2557d969014SDaniel P. Berrange } 2567d969014SDaniel P. Berrange 2577d969014SDaniel P. Berrange ret = 0; 2587d969014SDaniel P. Berrange cleanup: 2597d969014SDaniel P. Berrange g_free(iv); 2607d969014SDaniel P. Berrange return ret; 2617d969014SDaniel P. Berrange } 262