xref: /openbmc/qemu/crypto/block-qcow.c (revision b8eada54b2ad8a7d98d93d5ab4d3e888c5880097)
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