cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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
     36static bool
     37qcrypto_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
     44static int
     45qcrypto_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
     96static int
     97qcrypto_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
    123static int
    124qcrypto_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
    142static void
    143qcrypto_block_qcow_cleanup(QCryptoBlock *block)
    144{
    145}
    146
    147
    148static int
    149qcrypto_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
    163static int
    164qcrypto_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
    178const 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};