1*7d969014SDaniel P. Berrange /* 2*7d969014SDaniel P. Berrange * QEMU Crypto block device encryption 3*7d969014SDaniel P. Berrange * 4*7d969014SDaniel P. Berrange * Copyright (c) 2015-2016 Red Hat, Inc. 5*7d969014SDaniel P. Berrange * 6*7d969014SDaniel P. Berrange * This library is free software; you can redistribute it and/or 7*7d969014SDaniel P. Berrange * modify it under the terms of the GNU Lesser General Public 8*7d969014SDaniel P. Berrange * License as published by the Free Software Foundation; either 9*7d969014SDaniel P. Berrange * version 2 of the License, or (at your option) any later version. 10*7d969014SDaniel P. Berrange * 11*7d969014SDaniel P. Berrange * This library is distributed in the hope that it will be useful, 12*7d969014SDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*7d969014SDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*7d969014SDaniel P. Berrange * Lesser General Public License for more details. 15*7d969014SDaniel P. Berrange * 16*7d969014SDaniel P. Berrange * You should have received a copy of the GNU Lesser General Public 17*7d969014SDaniel P. Berrange * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18*7d969014SDaniel P. Berrange * 19*7d969014SDaniel P. Berrange */ 20*7d969014SDaniel P. Berrange 21*7d969014SDaniel P. Berrange #include "qemu/osdep.h" 22*7d969014SDaniel P. Berrange #include "crypto/blockpriv.h" 23*7d969014SDaniel P. Berrange #include "crypto/block-qcow.h" 24*7d969014SDaniel P. Berrange 25*7d969014SDaniel P. Berrange static const QCryptoBlockDriver *qcrypto_block_drivers[] = { 26*7d969014SDaniel P. Berrange [Q_CRYPTO_BLOCK_FORMAT_QCOW] = &qcrypto_block_driver_qcow, 27*7d969014SDaniel P. Berrange }; 28*7d969014SDaniel P. Berrange 29*7d969014SDaniel P. Berrange 30*7d969014SDaniel P. Berrange bool qcrypto_block_has_format(QCryptoBlockFormat format, 31*7d969014SDaniel P. Berrange const uint8_t *buf, 32*7d969014SDaniel P. Berrange size_t len) 33*7d969014SDaniel P. Berrange { 34*7d969014SDaniel P. Berrange const QCryptoBlockDriver *driver; 35*7d969014SDaniel P. Berrange 36*7d969014SDaniel P. Berrange if (format >= G_N_ELEMENTS(qcrypto_block_drivers) || 37*7d969014SDaniel P. Berrange !qcrypto_block_drivers[format]) { 38*7d969014SDaniel P. Berrange return false; 39*7d969014SDaniel P. Berrange } 40*7d969014SDaniel P. Berrange 41*7d969014SDaniel P. Berrange driver = qcrypto_block_drivers[format]; 42*7d969014SDaniel P. Berrange 43*7d969014SDaniel P. Berrange return driver->has_format(buf, len); 44*7d969014SDaniel P. Berrange } 45*7d969014SDaniel P. Berrange 46*7d969014SDaniel P. Berrange 47*7d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, 48*7d969014SDaniel P. Berrange QCryptoBlockReadFunc readfunc, 49*7d969014SDaniel P. Berrange void *opaque, 50*7d969014SDaniel P. Berrange unsigned int flags, 51*7d969014SDaniel P. Berrange Error **errp) 52*7d969014SDaniel P. Berrange { 53*7d969014SDaniel P. Berrange QCryptoBlock *block = g_new0(QCryptoBlock, 1); 54*7d969014SDaniel P. Berrange 55*7d969014SDaniel P. Berrange block->format = options->format; 56*7d969014SDaniel P. Berrange 57*7d969014SDaniel P. Berrange if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || 58*7d969014SDaniel P. Berrange !qcrypto_block_drivers[options->format]) { 59*7d969014SDaniel P. Berrange error_setg(errp, "Unsupported block driver %d", options->format); 60*7d969014SDaniel P. Berrange g_free(block); 61*7d969014SDaniel P. Berrange return NULL; 62*7d969014SDaniel P. Berrange } 63*7d969014SDaniel P. Berrange 64*7d969014SDaniel P. Berrange block->driver = qcrypto_block_drivers[options->format]; 65*7d969014SDaniel P. Berrange 66*7d969014SDaniel P. Berrange if (block->driver->open(block, options, 67*7d969014SDaniel P. Berrange readfunc, opaque, flags, errp) < 0) { 68*7d969014SDaniel P. Berrange g_free(block); 69*7d969014SDaniel P. Berrange return NULL; 70*7d969014SDaniel P. Berrange } 71*7d969014SDaniel P. Berrange 72*7d969014SDaniel P. Berrange return block; 73*7d969014SDaniel P. Berrange } 74*7d969014SDaniel P. Berrange 75*7d969014SDaniel P. Berrange 76*7d969014SDaniel P. Berrange QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, 77*7d969014SDaniel P. Berrange QCryptoBlockInitFunc initfunc, 78*7d969014SDaniel P. Berrange QCryptoBlockWriteFunc writefunc, 79*7d969014SDaniel P. Berrange void *opaque, 80*7d969014SDaniel P. Berrange Error **errp) 81*7d969014SDaniel P. Berrange { 82*7d969014SDaniel P. Berrange QCryptoBlock *block = g_new0(QCryptoBlock, 1); 83*7d969014SDaniel P. Berrange 84*7d969014SDaniel P. Berrange block->format = options->format; 85*7d969014SDaniel P. Berrange 86*7d969014SDaniel P. Berrange if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || 87*7d969014SDaniel P. Berrange !qcrypto_block_drivers[options->format]) { 88*7d969014SDaniel P. Berrange error_setg(errp, "Unsupported block driver %d", options->format); 89*7d969014SDaniel P. Berrange g_free(block); 90*7d969014SDaniel P. Berrange return NULL; 91*7d969014SDaniel P. Berrange } 92*7d969014SDaniel P. Berrange 93*7d969014SDaniel P. Berrange block->driver = qcrypto_block_drivers[options->format]; 94*7d969014SDaniel P. Berrange 95*7d969014SDaniel P. Berrange if (block->driver->create(block, options, initfunc, 96*7d969014SDaniel P. Berrange writefunc, opaque, errp) < 0) { 97*7d969014SDaniel P. Berrange g_free(block); 98*7d969014SDaniel P. Berrange return NULL; 99*7d969014SDaniel P. Berrange } 100*7d969014SDaniel P. Berrange 101*7d969014SDaniel P. Berrange return block; 102*7d969014SDaniel P. Berrange } 103*7d969014SDaniel P. Berrange 104*7d969014SDaniel P. Berrange 105*7d969014SDaniel P. Berrange int qcrypto_block_decrypt(QCryptoBlock *block, 106*7d969014SDaniel P. Berrange uint64_t startsector, 107*7d969014SDaniel P. Berrange uint8_t *buf, 108*7d969014SDaniel P. Berrange size_t len, 109*7d969014SDaniel P. Berrange Error **errp) 110*7d969014SDaniel P. Berrange { 111*7d969014SDaniel P. Berrange return block->driver->decrypt(block, startsector, buf, len, errp); 112*7d969014SDaniel P. Berrange } 113*7d969014SDaniel P. Berrange 114*7d969014SDaniel P. Berrange 115*7d969014SDaniel P. Berrange int qcrypto_block_encrypt(QCryptoBlock *block, 116*7d969014SDaniel P. Berrange uint64_t startsector, 117*7d969014SDaniel P. Berrange uint8_t *buf, 118*7d969014SDaniel P. Berrange size_t len, 119*7d969014SDaniel P. Berrange Error **errp) 120*7d969014SDaniel P. Berrange { 121*7d969014SDaniel P. Berrange return block->driver->encrypt(block, startsector, buf, len, errp); 122*7d969014SDaniel P. Berrange } 123*7d969014SDaniel P. Berrange 124*7d969014SDaniel P. Berrange 125*7d969014SDaniel P. Berrange QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block) 126*7d969014SDaniel P. Berrange { 127*7d969014SDaniel P. Berrange return block->cipher; 128*7d969014SDaniel P. Berrange } 129*7d969014SDaniel P. Berrange 130*7d969014SDaniel P. Berrange 131*7d969014SDaniel P. Berrange QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block) 132*7d969014SDaniel P. Berrange { 133*7d969014SDaniel P. Berrange return block->ivgen; 134*7d969014SDaniel P. Berrange } 135*7d969014SDaniel P. Berrange 136*7d969014SDaniel P. Berrange 137*7d969014SDaniel P. Berrange QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block) 138*7d969014SDaniel P. Berrange { 139*7d969014SDaniel P. Berrange return block->kdfhash; 140*7d969014SDaniel P. Berrange } 141*7d969014SDaniel P. Berrange 142*7d969014SDaniel P. Berrange 143*7d969014SDaniel P. Berrange uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block) 144*7d969014SDaniel P. Berrange { 145*7d969014SDaniel P. Berrange return block->payload_offset; 146*7d969014SDaniel P. Berrange } 147*7d969014SDaniel P. Berrange 148*7d969014SDaniel P. Berrange 149*7d969014SDaniel P. Berrange void qcrypto_block_free(QCryptoBlock *block) 150*7d969014SDaniel P. Berrange { 151*7d969014SDaniel P. Berrange if (!block) { 152*7d969014SDaniel P. Berrange return; 153*7d969014SDaniel P. Berrange } 154*7d969014SDaniel P. Berrange 155*7d969014SDaniel P. Berrange block->driver->cleanup(block); 156*7d969014SDaniel P. Berrange 157*7d969014SDaniel P. Berrange qcrypto_cipher_free(block->cipher); 158*7d969014SDaniel P. Berrange qcrypto_ivgen_free(block->ivgen); 159*7d969014SDaniel P. Berrange g_free(block); 160*7d969014SDaniel P. Berrange } 161*7d969014SDaniel P. Berrange 162*7d969014SDaniel P. Berrange 163*7d969014SDaniel P. Berrange int qcrypto_block_decrypt_helper(QCryptoCipher *cipher, 164*7d969014SDaniel P. Berrange size_t niv, 165*7d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 166*7d969014SDaniel P. Berrange int sectorsize, 167*7d969014SDaniel P. Berrange uint64_t startsector, 168*7d969014SDaniel P. Berrange uint8_t *buf, 169*7d969014SDaniel P. Berrange size_t len, 170*7d969014SDaniel P. Berrange Error **errp) 171*7d969014SDaniel P. Berrange { 172*7d969014SDaniel P. Berrange uint8_t *iv; 173*7d969014SDaniel P. Berrange int ret = -1; 174*7d969014SDaniel P. Berrange 175*7d969014SDaniel P. Berrange iv = niv ? g_new0(uint8_t, niv) : NULL; 176*7d969014SDaniel P. Berrange 177*7d969014SDaniel P. Berrange while (len > 0) { 178*7d969014SDaniel P. Berrange size_t nbytes; 179*7d969014SDaniel P. Berrange if (niv) { 180*7d969014SDaniel P. Berrange if (qcrypto_ivgen_calculate(ivgen, 181*7d969014SDaniel P. Berrange startsector, 182*7d969014SDaniel P. Berrange iv, niv, 183*7d969014SDaniel P. Berrange errp) < 0) { 184*7d969014SDaniel P. Berrange goto cleanup; 185*7d969014SDaniel P. Berrange } 186*7d969014SDaniel P. Berrange 187*7d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 188*7d969014SDaniel P. Berrange iv, niv, 189*7d969014SDaniel P. Berrange errp) < 0) { 190*7d969014SDaniel P. Berrange goto cleanup; 191*7d969014SDaniel P. Berrange } 192*7d969014SDaniel P. Berrange } 193*7d969014SDaniel P. Berrange 194*7d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 195*7d969014SDaniel P. Berrange if (qcrypto_cipher_decrypt(cipher, buf, buf, 196*7d969014SDaniel P. Berrange nbytes, errp) < 0) { 197*7d969014SDaniel P. Berrange goto cleanup; 198*7d969014SDaniel P. Berrange } 199*7d969014SDaniel P. Berrange 200*7d969014SDaniel P. Berrange startsector++; 201*7d969014SDaniel P. Berrange buf += nbytes; 202*7d969014SDaniel P. Berrange len -= nbytes; 203*7d969014SDaniel P. Berrange } 204*7d969014SDaniel P. Berrange 205*7d969014SDaniel P. Berrange ret = 0; 206*7d969014SDaniel P. Berrange cleanup: 207*7d969014SDaniel P. Berrange g_free(iv); 208*7d969014SDaniel P. Berrange return ret; 209*7d969014SDaniel P. Berrange } 210*7d969014SDaniel P. Berrange 211*7d969014SDaniel P. Berrange 212*7d969014SDaniel P. Berrange int qcrypto_block_encrypt_helper(QCryptoCipher *cipher, 213*7d969014SDaniel P. Berrange size_t niv, 214*7d969014SDaniel P. Berrange QCryptoIVGen *ivgen, 215*7d969014SDaniel P. Berrange int sectorsize, 216*7d969014SDaniel P. Berrange uint64_t startsector, 217*7d969014SDaniel P. Berrange uint8_t *buf, 218*7d969014SDaniel P. Berrange size_t len, 219*7d969014SDaniel P. Berrange Error **errp) 220*7d969014SDaniel P. Berrange { 221*7d969014SDaniel P. Berrange uint8_t *iv; 222*7d969014SDaniel P. Berrange int ret = -1; 223*7d969014SDaniel P. Berrange 224*7d969014SDaniel P. Berrange iv = niv ? g_new0(uint8_t, niv) : NULL; 225*7d969014SDaniel P. Berrange 226*7d969014SDaniel P. Berrange while (len > 0) { 227*7d969014SDaniel P. Berrange size_t nbytes; 228*7d969014SDaniel P. Berrange if (niv) { 229*7d969014SDaniel P. Berrange if (qcrypto_ivgen_calculate(ivgen, 230*7d969014SDaniel P. Berrange startsector, 231*7d969014SDaniel P. Berrange iv, niv, 232*7d969014SDaniel P. Berrange errp) < 0) { 233*7d969014SDaniel P. Berrange goto cleanup; 234*7d969014SDaniel P. Berrange } 235*7d969014SDaniel P. Berrange 236*7d969014SDaniel P. Berrange if (qcrypto_cipher_setiv(cipher, 237*7d969014SDaniel P. Berrange iv, niv, 238*7d969014SDaniel P. Berrange errp) < 0) { 239*7d969014SDaniel P. Berrange goto cleanup; 240*7d969014SDaniel P. Berrange } 241*7d969014SDaniel P. Berrange } 242*7d969014SDaniel P. Berrange 243*7d969014SDaniel P. Berrange nbytes = len > sectorsize ? sectorsize : len; 244*7d969014SDaniel P. Berrange if (qcrypto_cipher_encrypt(cipher, buf, buf, 245*7d969014SDaniel P. Berrange nbytes, errp) < 0) { 246*7d969014SDaniel P. Berrange goto cleanup; 247*7d969014SDaniel P. Berrange } 248*7d969014SDaniel P. Berrange 249*7d969014SDaniel P. Berrange startsector++; 250*7d969014SDaniel P. Berrange buf += nbytes; 251*7d969014SDaniel P. Berrange len -= nbytes; 252*7d969014SDaniel P. Berrange } 253*7d969014SDaniel P. Berrange 254*7d969014SDaniel P. Berrange ret = 0; 255*7d969014SDaniel P. Berrange cleanup: 256*7d969014SDaniel P. Berrange g_free(iv); 257*7d969014SDaniel P. Berrange return ret; 258*7d969014SDaniel P. Berrange } 259