17d969014SDaniel P. Berrange /*
27d969014SDaniel P. Berrange * QEMU Crypto block device encryption QCow/QCow2 AES-CBC format
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
9b7cbb874SThomas Huth * version 2.1 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 /*
227d969014SDaniel P. Berrange * Note that the block encryption implemented in this file is broken
237d969014SDaniel P. Berrange * by design. This exists only to allow data to be liberated from
247d969014SDaniel P. Berrange * existing qcow[2] images and should not be used in any new areas.
257d969014SDaniel P. Berrange */
267d969014SDaniel P. Berrange
277d969014SDaniel P. Berrange #include "qemu/osdep.h"
28da34e65cSMarkus Armbruster #include "qapi/error.h"
297d969014SDaniel P. Berrange
30986bc8deSMichael S. Tsirkin #include "block-qcow.h"
317d969014SDaniel P. Berrange #include "crypto/secret.h"
327d969014SDaniel P. Berrange
337d969014SDaniel P. Berrange #define QCRYPTO_BLOCK_QCOW_SECTOR_SIZE 512
347d969014SDaniel P. Berrange
357d969014SDaniel P. Berrange
367d969014SDaniel P. Berrange static bool
qcrypto_block_qcow_has_format(const uint8_t * buf G_GNUC_UNUSED,size_t buf_size G_GNUC_UNUSED)377d969014SDaniel P. Berrange qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED,
387d969014SDaniel P. Berrange size_t buf_size G_GNUC_UNUSED)
397d969014SDaniel P. Berrange {
407d969014SDaniel P. Berrange return false;
417d969014SDaniel P. Berrange }
427d969014SDaniel P. Berrange
437d969014SDaniel P. Berrange
447d969014SDaniel P. Berrange static int
qcrypto_block_qcow_init(QCryptoBlock * block,const char * keysecret,Error ** errp)457d969014SDaniel P. Berrange qcrypto_block_qcow_init(QCryptoBlock *block,
467d969014SDaniel P. Berrange const char *keysecret,
477d969014SDaniel P. Berrange Error **errp)
487d969014SDaniel P. Berrange {
497d969014SDaniel P. Berrange char *password;
507d969014SDaniel P. Berrange int ret;
517d969014SDaniel P. Berrange uint8_t keybuf[16];
527d969014SDaniel P. Berrange int len;
537d969014SDaniel P. Berrange
547d969014SDaniel P. Berrange memset(keybuf, 0, 16);
557d969014SDaniel P. Berrange
567d969014SDaniel P. Berrange password = qcrypto_secret_lookup_as_utf8(keysecret, errp);
577d969014SDaniel P. Berrange if (!password) {
587d969014SDaniel P. Berrange return -1;
597d969014SDaniel P. Berrange }
607d969014SDaniel P. Berrange
617d969014SDaniel P. Berrange len = strlen(password);
627d969014SDaniel P. Berrange memcpy(keybuf, password, MIN(len, sizeof(keybuf)));
637d969014SDaniel P. Berrange g_free(password);
647d969014SDaniel P. Berrange
65a092c513SMarkus Armbruster block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALGO_AES_128,
667d969014SDaniel P. Berrange QCRYPTO_CIPHER_MODE_CBC);
67*5e0e5102SMarkus Armbruster block->ivgen = qcrypto_ivgen_new(QCRYPTO_IV_GEN_ALGO_PLAIN64,
687d969014SDaniel P. Berrange 0, 0, NULL, 0, errp);
697d969014SDaniel P. Berrange if (!block->ivgen) {
707d969014SDaniel P. Berrange ret = -ENOTSUP;
717d969014SDaniel P. Berrange goto fail;
727d969014SDaniel P. Berrange }
737d969014SDaniel P. Berrange
74a092c513SMarkus Armbruster ret = qcrypto_block_init_cipher(block, QCRYPTO_CIPHER_ALGO_AES_128,
757d969014SDaniel P. Berrange QCRYPTO_CIPHER_MODE_CBC,
767d969014SDaniel P. Berrange keybuf, G_N_ELEMENTS(keybuf),
77af206c28SStefan Hajnoczi errp);
78c972fa12SVladimir Sementsov-Ogievskiy if (ret < 0) {
797d969014SDaniel P. Berrange ret = -ENOTSUP;
807d969014SDaniel P. Berrange goto fail;
817d969014SDaniel P. Berrange }
827d969014SDaniel P. Berrange
83850f49deSDaniel P. Berrange block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
847d969014SDaniel P. Berrange block->payload_offset = 0;
857d969014SDaniel P. Berrange
867d969014SDaniel P. Berrange return 0;
877d969014SDaniel P. Berrange
887d969014SDaniel P. Berrange fail:
89c972fa12SVladimir Sementsov-Ogievskiy qcrypto_block_free_cipher(block);
907d969014SDaniel P. Berrange qcrypto_ivgen_free(block->ivgen);
917d969014SDaniel P. Berrange return ret;
927d969014SDaniel P. Berrange }
937d969014SDaniel P. Berrange
947d969014SDaniel P. Berrange
957d969014SDaniel P. Berrange static int
qcrypto_block_qcow_open(QCryptoBlock * block,QCryptoBlockOpenOptions * options,const char * optprefix,QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,unsigned int flags,Error ** errp)967d969014SDaniel P. Berrange qcrypto_block_qcow_open(QCryptoBlock *block,
977d969014SDaniel P. Berrange QCryptoBlockOpenOptions *options,
981cd9a787SDaniel P. Berrange const char *optprefix,
997d969014SDaniel P. Berrange QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
1007d969014SDaniel P. Berrange void *opaque G_GNUC_UNUSED,
1017d969014SDaniel P. Berrange unsigned int flags,
1027d969014SDaniel P. Berrange Error **errp)
1037d969014SDaniel P. Berrange {
1047d969014SDaniel P. Berrange if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
10507809a7fSDaniel P. Berrangé block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
10607809a7fSDaniel P. Berrangé block->payload_offset = 0;
1077d969014SDaniel P. Berrange return 0;
1087d969014SDaniel P. Berrange } else {
1097d969014SDaniel P. Berrange if (!options->u.qcow.key_secret) {
1107d969014SDaniel P. Berrange error_setg(errp,
1111cd9a787SDaniel P. Berrange "Parameter '%skey-secret' is required for cipher",
1121cd9a787SDaniel P. Berrange optprefix ? optprefix : "");
1137d969014SDaniel P. Berrange return -1;
1147d969014SDaniel P. Berrange }
115c972fa12SVladimir Sementsov-Ogievskiy return qcrypto_block_qcow_init(block, options->u.qcow.key_secret,
1163ab0f063SStefan Hajnoczi errp);
1177d969014SDaniel P. Berrange }
1187d969014SDaniel P. Berrange }
1197d969014SDaniel P. Berrange
1207d969014SDaniel P. Berrange
1217d969014SDaniel P. Berrange static int
qcrypto_block_qcow_create(QCryptoBlock * block,QCryptoBlockCreateOptions * options,const char * optprefix,QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,Error ** errp)1227d969014SDaniel P. Berrange qcrypto_block_qcow_create(QCryptoBlock *block,
1237d969014SDaniel P. Berrange QCryptoBlockCreateOptions *options,
1241cd9a787SDaniel P. Berrange const char *optprefix,
1257d969014SDaniel P. Berrange QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,
1267d969014SDaniel P. Berrange QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,
1277d969014SDaniel P. Berrange void *opaque G_GNUC_UNUSED,
1287d969014SDaniel P. Berrange Error **errp)
1297d969014SDaniel P. Berrange {
1307d969014SDaniel P. Berrange if (!options->u.qcow.key_secret) {
1311cd9a787SDaniel P. Berrange error_setg(errp, "Parameter '%skey-secret' is required for cipher",
1321cd9a787SDaniel P. Berrange optprefix ? optprefix : "");
1337d969014SDaniel P. Berrange return -1;
1347d969014SDaniel P. Berrange }
1357d969014SDaniel P. Berrange /* QCow2 has no special header, since everything is hardwired */
1363ab0f063SStefan Hajnoczi return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, errp);
1377d969014SDaniel P. Berrange }
1387d969014SDaniel P. Berrange
1397d969014SDaniel P. Berrange
1407d969014SDaniel P. Berrange static void
qcrypto_block_qcow_cleanup(QCryptoBlock * block)1417d969014SDaniel P. Berrange qcrypto_block_qcow_cleanup(QCryptoBlock *block)
1427d969014SDaniel P. Berrange {
1437d969014SDaniel P. Berrange }
1447d969014SDaniel P. Berrange
1457d969014SDaniel P. Berrange
1467d969014SDaniel P. Berrange static int
qcrypto_block_qcow_decrypt(QCryptoBlock * block,uint64_t offset,uint8_t * buf,size_t len,Error ** errp)1477d969014SDaniel P. Berrange qcrypto_block_qcow_decrypt(QCryptoBlock *block,
1484609742aSDaniel P. Berrange uint64_t offset,
1497d969014SDaniel P. Berrange uint8_t *buf,
1507d969014SDaniel P. Berrange size_t len,
1517d969014SDaniel P. Berrange Error **errp)
1527d969014SDaniel P. Berrange {
1534609742aSDaniel P. Berrange assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
1544609742aSDaniel P. Berrange assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
1550f0d596cSVladimir Sementsov-Ogievskiy return qcrypto_block_decrypt_helper(block,
1567d969014SDaniel P. Berrange QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
1574609742aSDaniel P. Berrange offset, buf, len, errp);
1587d969014SDaniel P. Berrange }
1597d969014SDaniel P. Berrange
1607d969014SDaniel P. Berrange
1617d969014SDaniel P. Berrange static int
qcrypto_block_qcow_encrypt(QCryptoBlock * block,uint64_t offset,uint8_t * buf,size_t len,Error ** errp)1627d969014SDaniel P. Berrange qcrypto_block_qcow_encrypt(QCryptoBlock *block,
1634609742aSDaniel P. Berrange uint64_t offset,
1647d969014SDaniel P. Berrange uint8_t *buf,
1657d969014SDaniel P. Berrange size_t len,
1667d969014SDaniel P. Berrange Error **errp)
1677d969014SDaniel P. Berrange {
1684609742aSDaniel P. Berrange assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
1694609742aSDaniel P. Berrange assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
1700f0d596cSVladimir Sementsov-Ogievskiy return qcrypto_block_encrypt_helper(block,
1717d969014SDaniel P. Berrange QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
1724609742aSDaniel P. Berrange offset, buf, len, errp);
1737d969014SDaniel P. Berrange }
1747d969014SDaniel P. Berrange
1757d969014SDaniel P. Berrange
1767d969014SDaniel P. Berrange const QCryptoBlockDriver qcrypto_block_driver_qcow = {
1777d969014SDaniel P. Berrange .open = qcrypto_block_qcow_open,
1787d969014SDaniel P. Berrange .create = qcrypto_block_qcow_create,
1797d969014SDaniel P. Berrange .cleanup = qcrypto_block_qcow_cleanup,
1807d969014SDaniel P. Berrange .decrypt = qcrypto_block_qcow_decrypt,
1817d969014SDaniel P. Berrange .encrypt = qcrypto_block_qcow_encrypt,
1827d969014SDaniel P. Berrange .has_format = qcrypto_block_qcow_has_format,
1837d969014SDaniel P. Berrange };
184