qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

block-qcow.c (5855B)


      1 /*
      2  * QEMU Crypto block device encryption QCow/QCow2 AES-CBC format
      3  *
      4  * Copyright (c) 2015-2016 Red Hat, Inc.
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2.1 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General Public
     17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     18  *
     19  */
     20 
     21 /*
     22  * Note that the block encryption implemented in this file is broken
     23  * by design. This exists only to allow data to be liberated from
     24  * existing qcow[2] images and should not be used in any new areas.
     25  */
     26 
     27 #include "qemu/osdep.h"
     28 #include "qapi/error.h"
     29 
     30 #include "block-qcow.h"
     31 #include "crypto/secret.h"
     32 
     33 #define QCRYPTO_BLOCK_QCOW_SECTOR_SIZE 512
     34 
     35 
     36 static bool
     37 qcrypto_block_qcow_has_format(const uint8_t *buf G_GNUC_UNUSED,
     38                               size_t buf_size G_GNUC_UNUSED)
     39 {
     40     return false;
     41 }
     42 
     43 
     44 static int
     45 qcrypto_block_qcow_init(QCryptoBlock *block,
     46                         const char *keysecret,
     47                         size_t n_threads,
     48                         Error **errp)
     49 {
     50     char *password;
     51     int ret;
     52     uint8_t keybuf[16];
     53     int len;
     54 
     55     memset(keybuf, 0, 16);
     56 
     57     password = qcrypto_secret_lookup_as_utf8(keysecret, errp);
     58     if (!password) {
     59         return -1;
     60     }
     61 
     62     len = strlen(password);
     63     memcpy(keybuf, password, MIN(len, sizeof(keybuf)));
     64     g_free(password);
     65 
     66     block->niv = qcrypto_cipher_get_iv_len(QCRYPTO_CIPHER_ALG_AES_128,
     67                                            QCRYPTO_CIPHER_MODE_CBC);
     68     block->ivgen = qcrypto_ivgen_new(QCRYPTO_IVGEN_ALG_PLAIN64,
     69                                      0, 0, NULL, 0, errp);
     70     if (!block->ivgen) {
     71         ret = -ENOTSUP;
     72         goto fail;
     73     }
     74 
     75     ret = qcrypto_block_init_cipher(block, QCRYPTO_CIPHER_ALG_AES_128,
     76                                     QCRYPTO_CIPHER_MODE_CBC,
     77                                     keybuf, G_N_ELEMENTS(keybuf),
     78                                     n_threads, errp);
     79     if (ret < 0) {
     80         ret = -ENOTSUP;
     81         goto fail;
     82     }
     83 
     84     block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
     85     block->payload_offset = 0;
     86 
     87     return 0;
     88 
     89  fail:
     90     qcrypto_block_free_cipher(block);
     91     qcrypto_ivgen_free(block->ivgen);
     92     return ret;
     93 }
     94 
     95 
     96 static int
     97 qcrypto_block_qcow_open(QCryptoBlock *block,
     98                         QCryptoBlockOpenOptions *options,
     99                         const char *optprefix,
    100                         QCryptoBlockReadFunc readfunc G_GNUC_UNUSED,
    101                         void *opaque G_GNUC_UNUSED,
    102                         unsigned int flags,
    103                         size_t n_threads,
    104                         Error **errp)
    105 {
    106     if (flags & QCRYPTO_BLOCK_OPEN_NO_IO) {
    107         block->sector_size = QCRYPTO_BLOCK_QCOW_SECTOR_SIZE;
    108         block->payload_offset = 0;
    109         return 0;
    110     } else {
    111         if (!options->u.qcow.key_secret) {
    112             error_setg(errp,
    113                        "Parameter '%skey-secret' is required for cipher",
    114                        optprefix ? optprefix : "");
    115             return -1;
    116         }
    117         return qcrypto_block_qcow_init(block, options->u.qcow.key_secret,
    118                                        n_threads, errp);
    119     }
    120 }
    121 
    122 
    123 static int
    124 qcrypto_block_qcow_create(QCryptoBlock *block,
    125                           QCryptoBlockCreateOptions *options,
    126                           const char *optprefix,
    127                           QCryptoBlockInitFunc initfunc G_GNUC_UNUSED,
    128                           QCryptoBlockWriteFunc writefunc G_GNUC_UNUSED,
    129                           void *opaque G_GNUC_UNUSED,
    130                           Error **errp)
    131 {
    132     if (!options->u.qcow.key_secret) {
    133         error_setg(errp, "Parameter '%skey-secret' is required for cipher",
    134                    optprefix ? optprefix : "");
    135         return -1;
    136     }
    137     /* QCow2 has no special header, since everything is hardwired */
    138     return qcrypto_block_qcow_init(block, options->u.qcow.key_secret, 1, errp);
    139 }
    140 
    141 
    142 static void
    143 qcrypto_block_qcow_cleanup(QCryptoBlock *block)
    144 {
    145 }
    146 
    147 
    148 static int
    149 qcrypto_block_qcow_decrypt(QCryptoBlock *block,
    150                            uint64_t offset,
    151                            uint8_t *buf,
    152                            size_t len,
    153                            Error **errp)
    154 {
    155     assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
    156     assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
    157     return qcrypto_block_decrypt_helper(block,
    158                                         QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
    159                                         offset, buf, len, errp);
    160 }
    161 
    162 
    163 static int
    164 qcrypto_block_qcow_encrypt(QCryptoBlock *block,
    165                            uint64_t offset,
    166                            uint8_t *buf,
    167                            size_t len,
    168                            Error **errp)
    169 {
    170     assert(QEMU_IS_ALIGNED(offset, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
    171     assert(QEMU_IS_ALIGNED(len, QCRYPTO_BLOCK_QCOW_SECTOR_SIZE));
    172     return qcrypto_block_encrypt_helper(block,
    173                                         QCRYPTO_BLOCK_QCOW_SECTOR_SIZE,
    174                                         offset, buf, len, errp);
    175 }
    176 
    177 
    178 const QCryptoBlockDriver qcrypto_block_driver_qcow = {
    179     .open = qcrypto_block_qcow_open,
    180     .create = qcrypto_block_qcow_create,
    181     .cleanup = qcrypto_block_qcow_cleanup,
    182     .decrypt = qcrypto_block_qcow_decrypt,
    183     .encrypt = qcrypto_block_qcow_encrypt,
    184     .has_format = qcrypto_block_qcow_has_format,
    185 };