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
 118static ssize_t qcrypto_block_headerlen_hdr_init_func(QCryptoBlock *block,
 119        size_t headerlen, void *opaque, Error **errp)
 120{
 121    size_t *headerlenp = opaque;
 122
 123    /* Stash away the payload size */
 124    *headerlenp = headerlen;
 125    return 0;
 126}
 127
 128
 129static ssize_t qcrypto_block_headerlen_hdr_write_func(QCryptoBlock *block,
 130        size_t offset, const uint8_t *buf, size_t buflen,
 131        void *opaque, Error **errp)
 132{
 133    /* Discard the bytes, we're not actually writing to an image */
 134    return buflen;
 135}
 136
 137
 138bool
 139qcrypto_block_calculate_payload_offset(QCryptoBlockCreateOptions *create_opts,
 140                                       const char *optprefix,
 141                                       size_t *len,
 142                                       Error **errp)
 143{
 144    /* Fake LUKS creation in order to determine the payload size */
 145    g_autoptr(QCryptoBlock) crypto =
 146        qcrypto_block_create(create_opts, optprefix,
 147                             qcrypto_block_headerlen_hdr_init_func,
 148                             qcrypto_block_headerlen_hdr_write_func,
 149                             len, errp);
 150    return crypto != NULL;
 151}
 152
 153int qcrypto_block_amend_options(QCryptoBlock *block,
 154                                QCryptoBlockReadFunc readfunc,
 155                                QCryptoBlockWriteFunc writefunc,
 156                                void *opaque,
 157                                QCryptoBlockAmendOptions *options,
 158                                bool force,
 159                                Error **errp)
 160{
 161    if (options->format != block->format) {
 162        error_setg(errp,
 163                   "Cannot amend encryption format");
 164        return -1;
 165    }
 166
 167    if (!block->driver->amend) {
 168        error_setg(errp,
 169                   "Crypto format %s doesn't support format options amendment",
 170                   QCryptoBlockFormat_str(block->format));
 171        return -1;
 172    }
 173
 174    return block->driver->amend(block,
 175                                readfunc,
 176                                writefunc,
 177                                opaque,
 178                                options,
 179                                force,
 180                                errp);
 181}
 182
 183QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block,
 184                                         Error **errp)
 185{
 186    QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1);
 187
 188    info->format = block->format;
 189
 190    if (block->driver->get_info &&
 191        block->driver->get_info(block, info, errp) < 0) {
 192        g_free(info);
 193        return NULL;
 194    }
 195
 196    return info;
 197}
 198
 199
 200int qcrypto_block_decrypt(QCryptoBlock *block,
 201                          uint64_t offset,
 202                          uint8_t *buf,
 203                          size_t len,
 204                          Error **errp)
 205{
 206    return block->driver->decrypt(block, offset, buf, len, errp);
 207}
 208
 209
 210int qcrypto_block_encrypt(QCryptoBlock *block,
 211                          uint64_t offset,
 212                          uint8_t *buf,
 213                          size_t len,
 214                          Error **errp)
 215{
 216    return block->driver->encrypt(block, offset, buf, len, errp);
 217}
 218
 219
 220QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block)
 221{
 222    /* Ciphers should be accessed through pop/push method to be thread-safe.
 223     * Better, they should not be accessed externally at all (note, that
 224     * pop/push are static functions)
 225     * This function is used only in test with one thread (it's safe to skip
 226     * pop/push interface), so it's enough to assert it here:
 227     */
 228    assert(block->n_ciphers <= 1);
 229    return block->ciphers ? block->ciphers[0] : NULL;
 230}
 231
 232
 233static QCryptoCipher *qcrypto_block_pop_cipher(QCryptoBlock *block)
 234{
 235    QCryptoCipher *cipher;
 236
 237    qemu_mutex_lock(&block->mutex);
 238
 239    assert(block->n_free_ciphers > 0);
 240    block->n_free_ciphers--;
 241    cipher = block->ciphers[block->n_free_ciphers];
 242
 243    qemu_mutex_unlock(&block->mutex);
 244
 245    return cipher;
 246}
 247
 248
 249static void qcrypto_block_push_cipher(QCryptoBlock *block,
 250                                      QCryptoCipher *cipher)
 251{
 252    qemu_mutex_lock(&block->mutex);
 253
 254    assert(block->n_free_ciphers < block->n_ciphers);
 255    block->ciphers[block->n_free_ciphers] = cipher;
 256    block->n_free_ciphers++;
 257
 258    qemu_mutex_unlock(&block->mutex);
 259}
 260
 261
 262int qcrypto_block_init_cipher(QCryptoBlock *block,
 263                              QCryptoCipherAlgorithm alg,
 264                              QCryptoCipherMode mode,
 265                              const uint8_t *key, size_t nkey,
 266                              size_t n_threads, Error **errp)
 267{
 268    size_t i;
 269
 270    assert(!block->ciphers && !block->n_ciphers && !block->n_free_ciphers);
 271
 272    block->ciphers = g_new0(QCryptoCipher *, n_threads);
 273
 274    for (i = 0; i < n_threads; i++) {
 275        block->ciphers[i] = qcrypto_cipher_new(alg, mode, key, nkey, errp);
 276        if (!block->ciphers[i]) {
 277            qcrypto_block_free_cipher(block);
 278            return -1;
 279        }
 280        block->n_ciphers++;
 281        block->n_free_ciphers++;
 282    }
 283
 284    return 0;
 285}
 286
 287
 288void qcrypto_block_free_cipher(QCryptoBlock *block)
 289{
 290    size_t i;
 291
 292    if (!block->ciphers) {
 293        return;
 294    }
 295
 296    assert(block->n_ciphers == block->n_free_ciphers);
 297
 298    for (i = 0; i < block->n_ciphers; i++) {
 299        qcrypto_cipher_free(block->ciphers[i]);
 300    }
 301
 302    g_free(block->ciphers);
 303    block->ciphers = NULL;
 304    block->n_ciphers = block->n_free_ciphers = 0;
 305}
 306
 307QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block)
 308{
 309    /* ivgen should be accessed under mutex. However, this function is used only
 310     * in test with one thread, so it's enough to assert it here:
 311     */
 312    assert(block->n_ciphers <= 1);
 313    return block->ivgen;
 314}
 315
 316
 317QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block)
 318{
 319    return block->kdfhash;
 320}
 321
 322
 323uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block)
 324{
 325    return block->payload_offset;
 326}
 327
 328
 329uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block)
 330{
 331    return block->sector_size;
 332}
 333
 334
 335void qcrypto_block_free(QCryptoBlock *block)
 336{
 337    if (!block) {
 338        return;
 339    }
 340
 341    block->driver->cleanup(block);
 342
 343    qcrypto_block_free_cipher(block);
 344    qcrypto_ivgen_free(block->ivgen);
 345    qemu_mutex_destroy(&block->mutex);
 346    g_free(block);
 347}
 348
 349
 350typedef int (*QCryptoCipherEncDecFunc)(QCryptoCipher *cipher,
 351                                        const void *in,
 352                                        void *out,
 353                                        size_t len,
 354                                        Error **errp);
 355
 356static int do_qcrypto_block_cipher_encdec(QCryptoCipher *cipher,
 357                                          size_t niv,
 358                                          QCryptoIVGen *ivgen,
 359                                          QemuMutex *ivgen_mutex,
 360                                          int sectorsize,
 361                                          uint64_t offset,
 362                                          uint8_t *buf,
 363                                          size_t len,
 364                                          QCryptoCipherEncDecFunc func,
 365                                          Error **errp)
 366{
 367    g_autofree uint8_t *iv = niv ? g_new0(uint8_t, niv) : NULL;
 368    int ret = -1;
 369    uint64_t startsector = offset / sectorsize;
 370
 371    assert(QEMU_IS_ALIGNED(offset, sectorsize));
 372    assert(QEMU_IS_ALIGNED(len, sectorsize));
 373
 374    while (len > 0) {
 375        size_t nbytes;
 376        if (niv) {
 377            if (ivgen_mutex) {
 378                qemu_mutex_lock(ivgen_mutex);
 379            }
 380            ret = qcrypto_ivgen_calculate(ivgen, startsector, iv, niv, errp);
 381            if (ivgen_mutex) {
 382                qemu_mutex_unlock(ivgen_mutex);
 383            }
 384
 385            if (ret < 0) {
 386                return -1;
 387            }
 388
 389            if (qcrypto_cipher_setiv(cipher,
 390                                     iv, niv,
 391                                     errp) < 0) {
 392                return -1;
 393            }
 394        }
 395
 396        nbytes = len > sectorsize ? sectorsize : len;
 397        if (func(cipher, buf, buf, nbytes, errp) < 0) {
 398            return -1;
 399        }
 400
 401        startsector++;
 402        buf += nbytes;
 403        len -= nbytes;
 404    }
 405
 406    return 0;
 407}
 408
 409
 410int qcrypto_block_cipher_decrypt_helper(QCryptoCipher *cipher,
 411                                        size_t niv,
 412                                        QCryptoIVGen *ivgen,
 413                                        int sectorsize,
 414                                        uint64_t offset,
 415                                        uint8_t *buf,
 416                                        size_t len,
 417                                        Error **errp)
 418{
 419    return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
 420                                          offset, buf, len,
 421                                          qcrypto_cipher_decrypt, errp);
 422}
 423
 424
 425int qcrypto_block_cipher_encrypt_helper(QCryptoCipher *cipher,
 426                                        size_t niv,
 427                                        QCryptoIVGen *ivgen,
 428                                        int sectorsize,
 429                                        uint64_t offset,
 430                                        uint8_t *buf,
 431                                        size_t len,
 432                                        Error **errp)
 433{
 434    return do_qcrypto_block_cipher_encdec(cipher, niv, ivgen, NULL, sectorsize,
 435                                          offset, buf, len,
 436                                          qcrypto_cipher_encrypt, errp);
 437}
 438
 439int qcrypto_block_decrypt_helper(QCryptoBlock *block,
 440                                 int sectorsize,
 441                                 uint64_t offset,
 442                                 uint8_t *buf,
 443                                 size_t len,
 444                                 Error **errp)
 445{
 446    int ret;
 447    QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
 448
 449    ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
 450                                         &block->mutex, sectorsize, offset, buf,
 451                                         len, qcrypto_cipher_decrypt, errp);
 452
 453    qcrypto_block_push_cipher(block, cipher);
 454
 455    return ret;
 456}
 457
 458int qcrypto_block_encrypt_helper(QCryptoBlock *block,
 459                                 int sectorsize,
 460                                 uint64_t offset,
 461                                 uint8_t *buf,
 462                                 size_t len,
 463                                 Error **errp)
 464{
 465    int ret;
 466    QCryptoCipher *cipher = qcrypto_block_pop_cipher(block);
 467
 468    ret = do_qcrypto_block_cipher_encdec(cipher, block->niv, block->ivgen,
 469                                         &block->mutex, sectorsize, offset, buf,
 470                                         len, qcrypto_cipher_encrypt, errp);
 471
 472    qcrypto_block_push_cipher(block, cipher);
 473
 474    return ret;
 475}
 476