qemu/crypto/block.c
<<
>>
Prefs
   1/*
   2 * QEMU Crypto block device encryption
   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#include "qemu/osdep.h"
  22#include "qapi/error.h"
  23#include "blockpriv.h"
  24#include "block-qcow.h"
  25#include "block-luks.h"
  26
  27static const QCryptoBlockDriver *qcrypto_block_drivers[] = {
  28    [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow,
  29    [Q_CRYPTO_BLOCK_FORMAT_LUKS] = &qcrypto_block_driver_luks,
  30};
  31
  32
  33bool qcrypto_block_has_format(QCryptoBlockFormat format,
  34                              const uint8_t *buf,
  35                              size_t len)
  36{
  37    const QCryptoBlockDriver *driver;
  38
  39    if (format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
  40        !qcrypto_block_drivers[format]) {
  41        return false;
  42    }
  43
  44    driver = qcrypto_block_drivers[format];
  45
  46    return driver->has_format(buf, len);
  47}
  48
  49
  50QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options,
  51                                 const char *optprefix,
  52                                 QCryptoBlockReadFunc readfunc,
  53                                 void *opaque,
  54                                 unsigned int flags,
  55                                 size_t n_threads,
  56                                 Error **errp)
  57{
  58    QCryptoBlock *block = g_new0(QCryptoBlock, 1);
  59
  60    block->format = options->format;
  61
  62    if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
  63        !qcrypto_block_drivers[options->format]) {
  64        error_setg(errp, "Unsupported block driver %s",
  65                   QCryptoBlockFormat_str(options->format));
  66        g_free(block);
  67        return NULL;
  68    }
  69
  70    block->driver = qcrypto_block_drivers[options->format];
  71
  72    if (block->driver->open(block, options, optprefix,
  73                            readfunc, opaque, flags, n_threads, errp) < 0)
  74    {
  75        g_free(block);
  76        return NULL;
  77    }
  78
  79    qemu_mutex_init(&block->mutex);
  80
  81    return block;
  82}
  83
  84
  85QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options,
  86                                   const char *optprefix,
  87                                   QCryptoBlockInitFunc initfunc,
  88                                   QCryptoBlockWriteFunc writefunc,
  89                                   void *opaque,
  90                                   Error **errp)
  91{
  92    QCryptoBlock *block = g_new0(QCryptoBlock, 1);
  93
  94    block->format = options->format;
  95
  96    if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) ||
  97        !qcrypto_block_drivers[options->format]) {
  98        error_setg(errp, "Unsupported block driver %s",
  99                   QCryptoBlockFormat_str(options->format));
 100        g_free(block);
 101        return NULL;
 102    }
 103
 104    block->driver = qcrypto_block_drivers[options->format];
 105
 106    if (block->driver->create(block, options, optprefix, initfunc,
 107                              writefunc, opaque, errp) < 0) {
 108        g_free(block);
 109        return NULL;
 110    }
 111
 112    qemu_mutex_init(&block->mutex);
 113
 114    return block;
 115}
 116
 117
 118QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
 119                                         Error **errp)
 120{
 121    QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
 122
 123    info->format = block->format;
 124
 125    if (block->driver->get_info &&
 126        block->driver->get_info(block, info, errp) < 0) {
 127        g_free(info);
 128        return NULL;
 129    }
 130
 131    return info;
 132}
 133
 134
 135int qcrypto_block_decrypt(QCryptoBlock *block,
 136                          uint64_t offset,
 137                          uint8_t *buf,
 138                          size_t len,
 139                          Error **errp)
 140{
 141    return block->driver->decrypt(block, offset, buf, len, errp);
 142}
 143
 144
 145int qcrypto_block_encrypt(QCryptoBlock *block,
 146                          uint64_t offset,
 147                          uint8_t *buf,
 148                          size_t len,
 149                          Error **errp)
 150{
 151    return block->driver->encrypt(block, offset, buf, len, errp);
 152}
 153
 154
 155QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
 156{
 157    /* Ciphers should be accessed through pop/push method to be thread-safe.
 158     * Better, they should not be accessed externally at all (note, that
 159     * pop/push are static functions)
 160     * This function is used only in test with one thread (it's safe to skip
 161     * pop/push interface), so it's enough to assert it here:
 162     */
 163    assert(block->n_ciphers <= 1);
 164    return block->ciphers ? block->ciphers[0] : NULL;
 165}
 166
 167
 168static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block)
 169{
 170    QCryptoCipher *cipher;
 171
 172    qemu_mutex_lock(&block->mutex);
 173
 174    assert(block->n_free_ciphers > 0);
 175    block->n_free_ciphers--;
 176    cipher = block->ciphers[block->n_free_ciphers];
 177
 178    qemu_mutex_unlock(&block->mutex);
 179
 180    return cipher;
 181}
 182
 183
 184static void qcrypto_block_push_cipher(QCryptoBlock *block,
 185                                      QCryptoCipher *cipher)
 186{
 187    qemu_mutex_lock(&block->mutex);
 188
 189    assert(block->n_free_ciphers < block->n_ciphers);
 190    block->ciphers[block->n_free_ciphers] = cipher;
 191    block->n_free_ciphers++;
 192
 193    qemu_mutex_unlock(&block->mutex);
 194}
 195
 196
 197int qcrypto_block_init_cipher(QCryptoBlock *block,
 198                              QCryptoCipherAlgorithm alg,
 199                              QCryptoCipherMode mode,
 200                              const uint8_t *key, size_t nkey,
 201                              size_t n_threads, Error **errp)
 202{
 203    size_t i;
 204
 205    assert(!block->ciphers && !block->n_ciphers && !block->n_free_ciphers);
 206
 207    block->ciphers = g_new0(QCryptoCipher *, n_threads);
 208
 209    for (i = 0; i < n_threads; i++) {
 210        block->ciphers[i] = qcrypto_cipher_new(alg, mode, key, nkey, errp);
 211        if (!block->ciphers[i]) {
 212            qcrypto_block_free_cipher(block);
 213            return -1;
 214        }
 215        block->n_ciphers++;
 216        block->n_free_ciphers++;
 217    }
 218
 219    return 0;
 220}
 221
 222
 223void qcrypto_block_free_cipher(QCryptoBlock *block)
 224{
 225    size_t i;
 226
 227    if (!block->ciphers) {
 228        return;
 229    }
 230
 231    assert(block->n_ciphers == block->n_free_ciphers);
 232
 233    for (i = 0; i < block->n_ciphers; i++) {
 234        qcrypto_cipher_free(block->ciphers[i]);
 235    }
 236
 237    g_free(block->ciphers);
 238    block->ciphers = NULL;
 239    block->n_ciphers = block->n_free_ciphers = 0;
 240}
 241
 242QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
 243{
 244    /* ivgen should be accessed under mutex. However, this function is used only
 245     * in test with one thread, so it's enough to assert it here:
 246     */
 247    assert(block->n_ciphers <= 1);
 248    return block->ivgen;
 249}
 250
 251
 252QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
 253{
 254    return block->kdfhash;
 255}
 256
 257
 258uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
 259{
 260    return block->payload_offset;
 261}
 262
 263
 264uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
 265{
 266    return block->sector_size;
 267}
 268
 269
 270void qcrypto_block_free(QCryptoBlock *block)
 271{
 272    if (!block) {
 273        return;
 274    }
 275
 276    block->driver->cleanup(block);
 277
 278    qcrypto_block_free_cipher(block);
 279    qcrypto_ivgen_free(block->ivgen);
 280    qemu_mutex_destroy(&block->mutex);
 281    g_free(block);
 282}
 283
 284
 285typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
 286                                        const void *in,
 287                                        void *out,
 288                                        size_t len,
 289                                        Error **errp);
 290
 291static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
 292                                          size_t niv,
 293                                          QCryptoIVGen *ivgen,
 294                                          QemuMutex *ivgen_mutex,
 295                                          int sectorsize,
 296                                          uint64_t offset,
 297                                          uint8_t *buf,
 298                                          size_t len,
 299                                          QCryptoCipherEncDecFunc func,
 300                                          Error **errp)
 301{
 302    uint8_t *iv;
 303    int ret = -1;
 304    uint64_t startsector = offset / sectorsize;
 305
 306    assert(QEMU_IS_ALIGNED(offset, sectorsize));
 307    assert(QEMU_IS_ALIGNED(len, sectorsize));
 308
 309    iv = niv ? g_new0(uint8_t, niv) : NULL;
 310
 311    while (len > 0) {
 312        size_t nbytes;
 313        if (niv) {
 314            if (ivgen_mutex) {
 315                qemu_mutex_lock(ivgen_mutex);
 316            }
 317            ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
 318            if (ivgen_mutex) {
 319                qemu_mutex_unlock(ivgen_mutex);
 320            }
 321
 322            if (ret < 0) {
 323                goto cleanup;
 324            }
 325
 326            if (qcrypto_cipher_setiv(cipher,
 327                                     iv, niv,
 328                                     errp) < 0) {
 329                goto cleanup;
 330            }
 331        }
 332
 333        nbytes = len > sectorsize ? sectorsize : len;
 334        if (func(cipher, buf, buf, nbytes, errp) < 0) {
 335            goto cleanup;
 336        }
 337
 338        startsector++;
 339        buf += nbytes;
 340        len -= nbytes;
 341    }
 342
 343    ret = 0;
 344 cleanup:
 345    g_free(iv);
 346    return ret;
 347}
 348
 349
 350int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
 351                                        size_t niv,
 352                                        QCryptoIVGen *ivgen,
 353                                        int sectorsize,
 354                                        uint64_t offset,
 355                                        uint8_t *buf,
 356                                        size_t len,
 357                                        Error **errp)
 358{
 359    return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
 360                                          offset, buf, len,
 361                                          qcrypto_cipher_decrypt, errp);
 362}
 363
 364
 365int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
 366                                        size_t niv,
 367                                        QCryptoIVGen *ivgen,
 368                                        int sectorsize,
 369                                        uint64_t offset,
 370                                        uint8_t *buf,
 371                                        size_t len,
 372                                        Error **errp)
 373{
 374    return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
 375                                          offset, buf, len,
 376                                          qcrypto_cipher_encrypt, errp);
 377}
 378
 379int qcrypto_block_decrypt_helper(QCryptoBlock *block,
 380                                 int sectorsize,
 381                                 uint64_t offset,
 382                                 uint8_t *buf,
 383                                 size_t len,
 384                                 Error **errp)
 385{
 386    int ret;
 387    QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
 388
 389    ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
 390                                         &block->mutex, sectorsize, offset, buf,
 391                                         len, qcrypto_cipher_decrypt, errp);
 392
 393    qcrypto_block_push_cipher(block, cipher);
 394
 395    return ret;
 396}
 397
 398int qcrypto_block_encrypt_helper(QCryptoBlock *block,
 399                                 int sectorsize,
 400                                 uint64_t offset,
 401                                 uint8_t *buf,
 402                                 size_t len,
 403                                 Error **errp)
 404{
 405    int ret;
 406    QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
 407
 408    ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
 409                                         &block->mutex, sectorsize, offset, buf,
 410                                         len, qcrypto_cipher_encrypt, errp);
 411
 412    qcrypto_block_push_cipher(block, cipher);
 413
 414    return ret;
 415}
 416