qemu/block/crypto.c
<<
>>
Prefs
   1/*
   2 * QEMU block full disk 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 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
  23#include "block/block_int.h"
  24#include "block/qdict.h"
  25#include "sysemu/block-backend.h"
  26#include "crypto/block.h"
  27#include "qapi/opts-visitor.h"
  28#include "qapi/qapi-visit-crypto.h"
  29#include "qapi/qobject-input-visitor.h"
  30#include "qapi/error.h"
  31#include "qemu/module.h"
  32#include "qemu/option.h"
  33#include "crypto.h"
  34
  35typedef struct BlockCrypto BlockCrypto;
  36
  37struct BlockCrypto {
  38    QCryptoBlock *block;
  39};
  40
  41
  42static int block_crypto_probe_generic(QCryptoBlockFormat format,
  43                                      const uint8_t *buf,
  44                                      int buf_size,
  45                                      const char *filename)
  46{
  47    if (qcrypto_block_has_format(format, buf, buf_size)) {
  48        return 100;
  49    } else {
  50        return 0;
  51    }
  52}
  53
  54
  55static ssize_t block_crypto_read_func(QCryptoBlock *block,
  56                                      size_t offset,
  57                                      uint8_t *buf,
  58                                      size_t buflen,
  59                                      void *opaque,
  60                                      Error **errp)
  61{
  62    BlockDriverState *bs = opaque;
  63    ssize_t ret;
  64
  65    ret = bdrv_pread(bs->file, offset, buf, buflen);
  66    if (ret < 0) {
  67        error_setg_errno(errp, -ret, "Could not read encryption header");
  68        return ret;
  69    }
  70    return ret;
  71}
  72
  73
  74struct BlockCryptoCreateData {
  75    BlockBackend *blk;
  76    uint64_t size;
  77    PreallocMode prealloc;
  78};
  79
  80
  81static ssize_t block_crypto_write_func(QCryptoBlock *block,
  82                                       size_t offset,
  83                                       const uint8_t *buf,
  84                                       size_t buflen,
  85                                       void *opaque,
  86                                       Error **errp)
  87{
  88    struct BlockCryptoCreateData *data = opaque;
  89    ssize_t ret;
  90
  91    ret = blk_pwrite(data->blk, offset, buf, buflen, 0);
  92    if (ret < 0) {
  93        error_setg_errno(errp, -ret, "Could not write encryption header");
  94        return ret;
  95    }
  96    return ret;
  97}
  98
  99
 100static ssize_t block_crypto_init_func(QCryptoBlock *block,
 101                                      size_t headerlen,
 102                                      void *opaque,
 103                                      Error **errp)
 104{
 105    struct BlockCryptoCreateData *data = opaque;
 106
 107    if (data->size > INT64_MAX || headerlen > INT64_MAX - data->size) {
 108        error_setg(errp, "The requested file size is too large");
 109        return -EFBIG;
 110    }
 111
 112    /* User provided size should reflect amount of space made
 113     * available to the guest, so we must take account of that
 114     * which will be used by the crypto header
 115     */
 116    return blk_truncate(data->blk, data->size + headerlen, false,
 117                        data->prealloc, errp);
 118}
 119
 120
 121static QemuOptsList block_crypto_runtime_opts_luks = {
 122    .name = "crypto",
 123    .head = QTAILQ_HEAD_INITIALIZER(block_crypto_runtime_opts_luks.head),
 124    .desc = {
 125        BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""),
 126        { /* end of list */ }
 127    },
 128};
 129
 130
 131static QemuOptsList block_crypto_create_opts_luks = {
 132    .name = "crypto",
 133    .head = QTAILQ_HEAD_INITIALIZER(block_crypto_create_opts_luks.head),
 134    .desc = {
 135        {
 136            .name = BLOCK_OPT_SIZE,
 137            .type = QEMU_OPT_SIZE,
 138            .help = "Virtual disk size"
 139        },
 140        BLOCK_CRYPTO_OPT_DEF_LUKS_KEY_SECRET(""),
 141        BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_ALG(""),
 142        BLOCK_CRYPTO_OPT_DEF_LUKS_CIPHER_MODE(""),
 143        BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_ALG(""),
 144        BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""),
 145        BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""),
 146        BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""),
 147        { /* end of list */ }
 148    },
 149};
 150
 151
 152QCryptoBlockOpenOptions *
 153block_crypto_open_opts_init(QDict *opts, Error **errp)
 154{
 155    Visitor *v;
 156    QCryptoBlockOpenOptions *ret;
 157
 158    v = qobject_input_visitor_new_flat_confused(opts, errp);
 159    if (!v) {
 160        return NULL;
 161    }
 162
 163    visit_type_QCryptoBlockOpenOptions(v, NULL, &ret, errp);
 164
 165    visit_free(v);
 166    return ret;
 167}
 168
 169
 170QCryptoBlockCreateOptions *
 171block_crypto_create_opts_init(QDict *opts, Error **errp)
 172{
 173    Visitor *v;
 174    QCryptoBlockCreateOptions *ret;
 175
 176    v = qobject_input_visitor_new_flat_confused(opts, errp);
 177    if (!v) {
 178        return NULL;
 179    }
 180
 181    visit_type_QCryptoBlockCreateOptions(v, NULL, &ret, errp);
 182
 183    visit_free(v);
 184    return ret;
 185}
 186
 187
 188static int block_crypto_open_generic(QCryptoBlockFormat format,
 189                                     QemuOptsList *opts_spec,
 190                                     BlockDriverState *bs,
 191                                     QDict *options,
 192                                     int flags,
 193                                     Error **errp)
 194{
 195    BlockCrypto *crypto = bs->opaque;
 196    QemuOpts *opts = NULL;
 197    Error *local_err = NULL;
 198    int ret = -EINVAL;
 199    QCryptoBlockOpenOptions *open_opts = NULL;
 200    unsigned int cflags = 0;
 201    QDict *cryptoopts = NULL;
 202
 203    bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
 204                               false, errp);
 205    if (!bs->file) {
 206        return -EINVAL;
 207    }
 208
 209    bs->supported_write_flags = BDRV_REQ_FUA &
 210        bs->file->bs->supported_write_flags;
 211
 212    opts = qemu_opts_create(opts_spec, NULL, 0, &error_abort);
 213    qemu_opts_absorb_qdict(opts, options, &local_err);
 214    if (local_err) {
 215        error_propagate(errp, local_err);
 216        goto cleanup;
 217    }
 218
 219    cryptoopts = qemu_opts_to_qdict(opts, NULL);
 220    qdict_put_str(cryptoopts, "format", QCryptoBlockFormat_str(format));
 221
 222    open_opts = block_crypto_open_opts_init(cryptoopts, errp);
 223    if (!open_opts) {
 224        goto cleanup;
 225    }
 226
 227    if (flags & BDRV_O_NO_IO) {
 228        cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
 229    }
 230    crypto->block = qcrypto_block_open(open_opts, NULL,
 231                                       block_crypto_read_func,
 232                                       bs,
 233                                       cflags,
 234                                       1,
 235                                       errp);
 236
 237    if (!crypto->block) {
 238        ret = -EIO;
 239        goto cleanup;
 240    }
 241
 242    bs->encrypted = true;
 243
 244    ret = 0;
 245 cleanup:
 246    qobject_unref(cryptoopts);
 247    qapi_free_QCryptoBlockOpenOptions(open_opts);
 248    return ret;
 249}
 250
 251
 252static int block_crypto_co_create_generic(BlockDriverState *bs,
 253                                          int64_t size,
 254                                          QCryptoBlockCreateOptions *opts,
 255                                          PreallocMode prealloc,
 256                                          Error **errp)
 257{
 258    int ret;
 259    BlockBackend *blk;
 260    QCryptoBlock *crypto = NULL;
 261    struct BlockCryptoCreateData data;
 262
 263    blk = blk_new(bdrv_get_aio_context(bs),
 264                  BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
 265
 266    ret = blk_insert_bs(blk, bs, errp);
 267    if (ret < 0) {
 268        goto cleanup;
 269    }
 270
 271    if (prealloc == PREALLOC_MODE_METADATA) {
 272        prealloc = PREALLOC_MODE_OFF;
 273    }
 274
 275    data = (struct BlockCryptoCreateData) {
 276        .blk = blk,
 277        .size = size,
 278        .prealloc = prealloc,
 279    };
 280
 281    crypto = qcrypto_block_create(opts, NULL,
 282                                  block_crypto_init_func,
 283                                  block_crypto_write_func,
 284                                  &data,
 285                                  errp);
 286
 287    if (!crypto) {
 288        ret = -EIO;
 289        goto cleanup;
 290    }
 291
 292    ret = 0;
 293 cleanup:
 294    qcrypto_block_free(crypto);
 295    blk_unref(blk);
 296    return ret;
 297}
 298
 299static int coroutine_fn
 300block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
 301                         PreallocMode prealloc, Error **errp)
 302{
 303    BlockCrypto *crypto = bs->opaque;
 304    uint64_t payload_offset =
 305        qcrypto_block_get_payload_offset(crypto->block);
 306
 307    if (payload_offset > INT64_MAX - offset) {
 308        error_setg(errp, "The requested file size is too large");
 309        return -EFBIG;
 310    }
 311
 312    offset += payload_offset;
 313
 314    return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
 315}
 316
 317static void block_crypto_close(BlockDriverState *bs)
 318{
 319    BlockCrypto *crypto = bs->opaque;
 320    qcrypto_block_free(crypto->block);
 321}
 322
 323static int block_crypto_reopen_prepare(BDRVReopenState *state,
 324                                       BlockReopenQueue *queue, Error **errp)
 325{
 326    /* nothing needs checking */
 327    return 0;
 328}
 329
 330/*
 331 * 1 MB bounce buffer gives good performance / memory tradeoff
 332 * when using cache=none|directsync.
 333 */
 334#define BLOCK_CRYPTO_MAX_IO_SIZE (1024 * 1024)
 335
 336static coroutine_fn int
 337block_crypto_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
 338                       QEMUIOVector *qiov, int flags)
 339{
 340    BlockCrypto *crypto = bs->opaque;
 341    uint64_t cur_bytes; /* number of bytes in current iteration */
 342    uint64_t bytes_done = 0;
 343    uint8_t *cipher_data = NULL;
 344    QEMUIOVector hd_qiov;
 345    int ret = 0;
 346    uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
 347    uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
 348
 349    assert(!flags);
 350    assert(payload_offset < INT64_MAX);
 351    assert(QEMU_IS_ALIGNED(offset, sector_size));
 352    assert(QEMU_IS_ALIGNED(bytes, sector_size));
 353
 354    qemu_iovec_init(&hd_qiov, qiov->niov);
 355
 356    /* Bounce buffer because we don't wish to expose cipher text
 357     * in qiov which points to guest memory.
 358     */
 359    cipher_data =
 360        qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
 361                                              qiov->size));
 362    if (cipher_data == NULL) {
 363        ret = -ENOMEM;
 364        goto cleanup;
 365    }
 366
 367    while (bytes) {
 368        cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
 369
 370        qemu_iovec_reset(&hd_qiov);
 371        qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
 372
 373        ret = bdrv_co_preadv(bs->file, payload_offset + offset + bytes_done,
 374                             cur_bytes, &hd_qiov, 0);
 375        if (ret < 0) {
 376            goto cleanup;
 377        }
 378
 379        if (qcrypto_block_decrypt(crypto->block, offset + bytes_done,
 380                                  cipher_data, cur_bytes, NULL) < 0) {
 381            ret = -EIO;
 382            goto cleanup;
 383        }
 384
 385        qemu_iovec_from_buf(qiov, bytes_done, cipher_data, cur_bytes);
 386
 387        bytes -= cur_bytes;
 388        bytes_done += cur_bytes;
 389    }
 390
 391 cleanup:
 392    qemu_iovec_destroy(&hd_qiov);
 393    qemu_vfree(cipher_data);
 394
 395    return ret;
 396}
 397
 398
 399static coroutine_fn int
 400block_crypto_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
 401                        QEMUIOVector *qiov, int flags)
 402{
 403    BlockCrypto *crypto = bs->opaque;
 404    uint64_t cur_bytes; /* number of bytes in current iteration */
 405    uint64_t bytes_done = 0;
 406    uint8_t *cipher_data = NULL;
 407    QEMUIOVector hd_qiov;
 408    int ret = 0;
 409    uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
 410    uint64_t payload_offset = qcrypto_block_get_payload_offset(crypto->block);
 411
 412    assert(!(flags & ~BDRV_REQ_FUA));
 413    assert(payload_offset < INT64_MAX);
 414    assert(QEMU_IS_ALIGNED(offset, sector_size));
 415    assert(QEMU_IS_ALIGNED(bytes, sector_size));
 416
 417    qemu_iovec_init(&hd_qiov, qiov->niov);
 418
 419    /* Bounce buffer because we're not permitted to touch
 420     * contents of qiov - it points to guest memory.
 421     */
 422    cipher_data =
 423        qemu_try_blockalign(bs->file->bs, MIN(BLOCK_CRYPTO_MAX_IO_SIZE,
 424                                              qiov->size));
 425    if (cipher_data == NULL) {
 426        ret = -ENOMEM;
 427        goto cleanup;
 428    }
 429
 430    while (bytes) {
 431        cur_bytes = MIN(bytes, BLOCK_CRYPTO_MAX_IO_SIZE);
 432
 433        qemu_iovec_to_buf(qiov, bytes_done, cipher_data, cur_bytes);
 434
 435        if (qcrypto_block_encrypt(crypto->block, offset + bytes_done,
 436                                  cipher_data, cur_bytes, NULL) < 0) {
 437            ret = -EIO;
 438            goto cleanup;
 439        }
 440
 441        qemu_iovec_reset(&hd_qiov);
 442        qemu_iovec_add(&hd_qiov, cipher_data, cur_bytes);
 443
 444        ret = bdrv_co_pwritev(bs->file, payload_offset + offset + bytes_done,
 445                              cur_bytes, &hd_qiov, flags);
 446        if (ret < 0) {
 447            goto cleanup;
 448        }
 449
 450        bytes -= cur_bytes;
 451        bytes_done += cur_bytes;
 452    }
 453
 454 cleanup:
 455    qemu_iovec_destroy(&hd_qiov);
 456    qemu_vfree(cipher_data);
 457
 458    return ret;
 459}
 460
 461static void block_crypto_refresh_limits(BlockDriverState *bs, Error **errp)
 462{
 463    BlockCrypto *crypto = bs->opaque;
 464    uint64_t sector_size = qcrypto_block_get_sector_size(crypto->block);
 465    bs->bl.request_alignment = sector_size; /* No sub-sector I/O */
 466}
 467
 468
 469static int64_t block_crypto_getlength(BlockDriverState *bs)
 470{
 471    BlockCrypto *crypto = bs->opaque;
 472    int64_t len = bdrv_getlength(bs->file->bs);
 473
 474    uint64_t offset = qcrypto_block_get_payload_offset(crypto->block);
 475    assert(offset < INT64_MAX);
 476
 477    if (offset > len) {
 478        return -EIO;
 479    }
 480
 481    len -= offset;
 482
 483    return len;
 484}
 485
 486
 487static int block_crypto_probe_luks(const uint8_t *buf,
 488                                   int buf_size,
 489                                   const char *filename) {
 490    return block_crypto_probe_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
 491                                      buf, buf_size, filename);
 492}
 493
 494static int block_crypto_open_luks(BlockDriverState *bs,
 495                                  QDict *options,
 496                                  int flags,
 497                                  Error **errp)
 498{
 499    return block_crypto_open_generic(Q_CRYPTO_BLOCK_FORMAT_LUKS,
 500                                     &block_crypto_runtime_opts_luks,
 501                                     bs, options, flags, errp);
 502}
 503
 504static int coroutine_fn
 505block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
 506{
 507    BlockdevCreateOptionsLUKS *luks_opts;
 508    BlockDriverState *bs = NULL;
 509    QCryptoBlockCreateOptions create_opts;
 510    PreallocMode preallocation = PREALLOC_MODE_OFF;
 511    int ret;
 512
 513    assert(create_options->driver == BLOCKDEV_DRIVER_LUKS);
 514    luks_opts = &create_options->u.luks;
 515
 516    bs = bdrv_open_blockdev_ref(luks_opts->file, errp);
 517    if (bs == NULL) {
 518        return -EIO;
 519    }
 520
 521    create_opts = (QCryptoBlockCreateOptions) {
 522        .format = Q_CRYPTO_BLOCK_FORMAT_LUKS,
 523        .u.luks = *qapi_BlockdevCreateOptionsLUKS_base(luks_opts),
 524    };
 525
 526    if (luks_opts->has_preallocation) {
 527        preallocation = luks_opts->preallocation;
 528    }
 529
 530    ret = block_crypto_co_create_generic(bs, luks_opts->size, &create_opts,
 531                                         preallocation, errp);
 532    if (ret < 0) {
 533        goto fail;
 534    }
 535
 536    ret = 0;
 537fail:
 538    bdrv_unref(bs);
 539    return ret;
 540}
 541
 542static int coroutine_fn block_crypto_co_create_opts_luks(const char *filename,
 543                                                         QemuOpts *opts,
 544                                                         Error **errp)
 545{
 546    QCryptoBlockCreateOptions *create_opts = NULL;
 547    BlockDriverState *bs = NULL;
 548    QDict *cryptoopts;
 549    PreallocMode prealloc;
 550    char *buf = NULL;
 551    int64_t size;
 552    int ret;
 553    Error *local_err = NULL;
 554
 555    /* Parse options */
 556    size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
 557
 558    buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
 559    prealloc = qapi_enum_parse(&PreallocMode_lookup, buf,
 560                               PREALLOC_MODE_OFF, &local_err);
 561    g_free(buf);
 562    if (local_err) {
 563        error_propagate(errp, local_err);
 564        return -EINVAL;
 565    }
 566
 567    cryptoopts = qemu_opts_to_qdict_filtered(opts, NULL,
 568                                             &block_crypto_create_opts_luks,
 569                                             true);
 570
 571    qdict_put_str(cryptoopts, "format", "luks");
 572    create_opts = block_crypto_create_opts_init(cryptoopts, errp);
 573    if (!create_opts) {
 574        ret = -EINVAL;
 575        goto fail;
 576    }
 577
 578    /* Create protocol layer */
 579    ret = bdrv_create_file(filename, opts, errp);
 580    if (ret < 0) {
 581        goto fail;
 582    }
 583
 584    bs = bdrv_open(filename, NULL, NULL,
 585                   BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
 586    if (!bs) {
 587        ret = -EINVAL;
 588        goto fail;
 589    }
 590
 591    /* Create format layer */
 592    ret = block_crypto_co_create_generic(bs, size, create_opts, prealloc, errp);
 593    if (ret < 0) {
 594        goto fail;
 595    }
 596
 597    ret = 0;
 598fail:
 599    bdrv_unref(bs);
 600    qapi_free_QCryptoBlockCreateOptions(create_opts);
 601    qobject_unref(cryptoopts);
 602    return ret;
 603}
 604
 605static int block_crypto_get_info_luks(BlockDriverState *bs,
 606                                      BlockDriverInfo *bdi)
 607{
 608    BlockDriverInfo subbdi;
 609    int ret;
 610
 611    ret = bdrv_get_info(bs->file->bs, &subbdi);
 612    if (ret != 0) {
 613        return ret;
 614    }
 615
 616    bdi->unallocated_blocks_are_zero = false;
 617    bdi->cluster_size = subbdi.cluster_size;
 618
 619    return 0;
 620}
 621
 622static ImageInfoSpecific *
 623block_crypto_get_specific_info_luks(BlockDriverState *bs, Error **errp)
 624{
 625    BlockCrypto *crypto = bs->opaque;
 626    ImageInfoSpecific *spec_info;
 627    QCryptoBlockInfo *info;
 628
 629    info = qcrypto_block_get_info(crypto->block, errp);
 630    if (!info) {
 631        return NULL;
 632    }
 633    assert(info->format == Q_CRYPTO_BLOCK_FORMAT_LUKS);
 634
 635    spec_info = g_new(ImageInfoSpecific, 1);
 636    spec_info->type = IMAGE_INFO_SPECIFIC_KIND_LUKS;
 637    spec_info->u.luks.data = g_new(QCryptoBlockInfoLUKS, 1);
 638    *spec_info->u.luks.data = info->u.luks;
 639
 640    /* Blank out pointers we've just stolen to avoid double free */
 641    memset(&info->u.luks, 0, sizeof(info->u.luks));
 642
 643    qapi_free_QCryptoBlockInfo(info);
 644
 645    return spec_info;
 646}
 647
 648static const char *const block_crypto_strong_runtime_opts[] = {
 649    BLOCK_CRYPTO_OPT_LUKS_KEY_SECRET,
 650
 651    NULL
 652};
 653
 654static BlockDriver bdrv_crypto_luks = {
 655    .format_name        = "luks",
 656    .instance_size      = sizeof(BlockCrypto),
 657    .bdrv_probe         = block_crypto_probe_luks,
 658    .bdrv_open          = block_crypto_open_luks,
 659    .bdrv_close         = block_crypto_close,
 660    /* This driver doesn't modify LUKS metadata except when creating image.
 661     * Allow share-rw=on as a special case. */
 662    .bdrv_child_perm    = bdrv_filter_default_perms,
 663    .bdrv_co_create     = block_crypto_co_create_luks,
 664    .bdrv_co_create_opts = block_crypto_co_create_opts_luks,
 665    .bdrv_co_truncate   = block_crypto_co_truncate,
 666    .create_opts        = &block_crypto_create_opts_luks,
 667
 668    .bdrv_reopen_prepare = block_crypto_reopen_prepare,
 669    .bdrv_refresh_limits = block_crypto_refresh_limits,
 670    .bdrv_co_preadv     = block_crypto_co_preadv,
 671    .bdrv_co_pwritev    = block_crypto_co_pwritev,
 672    .bdrv_getlength     = block_crypto_getlength,
 673    .bdrv_get_info      = block_crypto_get_info_luks,
 674    .bdrv_get_specific_info = block_crypto_get_specific_info_luks,
 675
 676    .strong_runtime_opts = block_crypto_strong_runtime_opts,
 677};
 678
 679static void block_crypto_init(void)
 680{
 681    bdrv_register(&bdrv_crypto_luks);
 682}
 683
 684block_init(block_crypto_init);
 685