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 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 27 static 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 33 bool 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 50 QCryptoBlock *qcrypto_block_open(QCryptoBlockOpenOptions *options, 51 const char *optprefix, 52 QCryptoBlockReadFunc readfunc, 53 void *opaque, 54 unsigned int flags, 55 Error **errp) 56 { 57 QCryptoBlock *block = g_new0(QCryptoBlock, 1); 58 59 block->format = options->format; 60 61 if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || 62 !qcrypto_block_drivers[options->format]) { 63 error_setg(errp, "Unsupported block driver %s", 64 QCryptoBlockFormat_str(options->format)); 65 g_free(block); 66 return NULL; 67 } 68 69 block->driver = qcrypto_block_drivers[options->format]; 70 71 if (block->driver->open(block, options, optprefix, 72 readfunc, opaque, flags, errp) < 0) { 73 g_free(block); 74 return NULL; 75 } 76 77 return block; 78 } 79 80 81 QCryptoBlock *qcrypto_block_create(QCryptoBlockCreateOptions *options, 82 const char *optprefix, 83 QCryptoBlockInitFunc initfunc, 84 QCryptoBlockWriteFunc writefunc, 85 void *opaque, 86 Error **errp) 87 { 88 QCryptoBlock *block = g_new0(QCryptoBlock, 1); 89 90 block->format = options->format; 91 92 if (options->format >= G_N_ELEMENTS(qcrypto_block_drivers) || 93 !qcrypto_block_drivers[options->format]) { 94 error_setg(errp, "Unsupported block driver %s", 95 QCryptoBlockFormat_str(options->format)); 96 g_free(block); 97 return NULL; 98 } 99 100 block->driver = qcrypto_block_drivers[options->format]; 101 102 if (block->driver->create(block, options, optprefix, initfunc, 103 writefunc, opaque, errp) < 0) { 104 g_free(block); 105 return NULL; 106 } 107 108 return block; 109 } 110 111 112 QCryptoBlockInfo *qcrypto_block_get_info(QCryptoBlock *block, 113 Error **errp) 114 { 115 QCryptoBlockInfo *info = g_new0(QCryptoBlockInfo, 1); 116 117 info->format = block->format; 118 119 if (block->driver->get_info && 120 block->driver->get_info(block, info, errp) < 0) { 121 g_free(info); 122 return NULL; 123 } 124 125 return info; 126 } 127 128 129 int qcrypto_block_decrypt(QCryptoBlock *block, 130 uint64_t offset, 131 uint8_t *buf, 132 size_t len, 133 Error **errp) 134 { 135 return block->driver->decrypt(block, offset, buf, len, errp); 136 } 137 138 139 int qcrypto_block_encrypt(QCryptoBlock *block, 140 uint64_t offset, 141 uint8_t *buf, 142 size_t len, 143 Error **errp) 144 { 145 return block->driver->encrypt(block, offset, buf, len, errp); 146 } 147 148 149 QCryptoCipher *qcrypto_block_get_cipher(QCryptoBlock *block) 150 { 151 return block->cipher; 152 } 153 154 155 QCryptoIVGen *qcrypto_block_get_ivgen(QCryptoBlock *block) 156 { 157 return block->ivgen; 158 } 159 160 161 QCryptoHashAlgorithm qcrypto_block_get_kdf_hash(QCryptoBlock *block) 162 { 163 return block->kdfhash; 164 } 165 166 167 uint64_t qcrypto_block_get_payload_offset(QCryptoBlock *block) 168 { 169 return block->payload_offset; 170 } 171 172 173 uint64_t qcrypto_block_get_sector_size(QCryptoBlock *block) 174 { 175 return block->sector_size; 176 } 177 178 179 void qcrypto_block_free(QCryptoBlock *block) 180 { 181 if (!block) { 182 return; 183 } 184 185 block->driver->cleanup(block); 186 187 qcrypto_cipher_free(block->cipher); 188 qcrypto_ivgen_free(block->ivgen); 189 g_free(block); 190 } 191 192 193 int qcrypto_block_decrypt_helper(QCryptoCipher *cipher, 194 size_t niv, 195 QCryptoIVGen *ivgen, 196 int sectorsize, 197 uint64_t offset, 198 uint8_t *buf, 199 size_t len, 200 Error **errp) 201 { 202 uint8_t *iv; 203 int ret = -1; 204 uint64_t startsector = offset / sectorsize; 205 206 assert(QEMU_IS_ALIGNED(offset, sectorsize)); 207 assert(QEMU_IS_ALIGNED(len, sectorsize)); 208 209 iv = niv ? g_new0(uint8_t, niv) : NULL; 210 211 while (len > 0) { 212 size_t nbytes; 213 if (niv) { 214 if (qcrypto_ivgen_calculate(ivgen, 215 startsector, 216 iv, niv, 217 errp) < 0) { 218 goto cleanup; 219 } 220 221 if (qcrypto_cipher_setiv(cipher, 222 iv, niv, 223 errp) < 0) { 224 goto cleanup; 225 } 226 } 227 228 nbytes = len > sectorsize ? sectorsize : len; 229 if (qcrypto_cipher_decrypt(cipher, buf, buf, 230 nbytes, errp) < 0) { 231 goto cleanup; 232 } 233 234 startsector++; 235 buf += nbytes; 236 len -= nbytes; 237 } 238 239 ret = 0; 240 cleanup: 241 g_free(iv); 242 return ret; 243 } 244 245 246 int qcrypto_block_encrypt_helper(QCryptoCipher *cipher, 247 size_t niv, 248 QCryptoIVGen *ivgen, 249 int sectorsize, 250 uint64_t offset, 251 uint8_t *buf, 252 size_t len, 253 Error **errp) 254 { 255 uint8_t *iv; 256 int ret = -1; 257 uint64_t startsector = offset / sectorsize; 258 259 assert(QEMU_IS_ALIGNED(offset, sectorsize)); 260 assert(QEMU_IS_ALIGNED(len, sectorsize)); 261 262 iv = niv ? g_new0(uint8_t, niv) : NULL; 263 264 while (len > 0) { 265 size_t nbytes; 266 if (niv) { 267 if (qcrypto_ivgen_calculate(ivgen, 268 startsector, 269 iv, niv, 270 errp) < 0) { 271 goto cleanup; 272 } 273 274 if (qcrypto_cipher_setiv(cipher, 275 iv, niv, 276 errp) < 0) { 277 goto cleanup; 278 } 279 } 280 281 nbytes = len > sectorsize ? sectorsize : len; 282 if (qcrypto_cipher_encrypt(cipher, buf, buf, 283 nbytes, errp) < 0) { 284 goto cleanup; 285 } 286 287 startsector++; 288 buf += nbytes; 289 len -= nbytes; 290 } 291 292 ret = 0; 293 cleanup: 294 g_free(iv); 295 return ret; 296 } 297