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 "crypto/blockpriv.h" 24 #include "crypto/block-qcow.h" 25 #include "crypto/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_lookup[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_lookup[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 startsector, 131 uint8_t *buf, 132 size_t len, 133 Error **errp) 134 { 135 return block->driver->decrypt(block, startsector, buf, len, errp); 136 } 137 138 139 int qcrypto_block_encrypt(QCryptoBlock *block, 140 uint64_t startsector, 141 uint8_t *buf, 142 size_t len, 143 Error **errp) 144 { 145 return block->driver->encrypt(block, startsector, 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 void qcrypto_block_free(QCryptoBlock *block) 174 { 175 if (!block) { 176 return; 177 } 178 179 block->driver->cleanup(block); 180 181 qcrypto_cipher_free(block->cipher); 182 qcrypto_ivgen_free(block->ivgen); 183 g_free(block); 184 } 185 186 187 int qcrypto_block_decrypt_helper(QCryptoCipher *cipher, 188 size_t niv, 189 QCryptoIVGen *ivgen, 190 int sectorsize, 191 uint64_t startsector, 192 uint8_t *buf, 193 size_t len, 194 Error **errp) 195 { 196 uint8_t *iv; 197 int ret = -1; 198 199 iv = niv ? g_new0(uint8_t, niv) : NULL; 200 201 while (len > 0) { 202 size_t nbytes; 203 if (niv) { 204 if (qcrypto_ivgen_calculate(ivgen, 205 startsector, 206 iv, niv, 207 errp) < 0) { 208 goto cleanup; 209 } 210 211 if (qcrypto_cipher_setiv(cipher, 212 iv, niv, 213 errp) < 0) { 214 goto cleanup; 215 } 216 } 217 218 nbytes = len > sectorsize ? sectorsize : len; 219 if (qcrypto_cipher_decrypt(cipher, buf, buf, 220 nbytes, errp) < 0) { 221 goto cleanup; 222 } 223 224 startsector++; 225 buf += nbytes; 226 len -= nbytes; 227 } 228 229 ret = 0; 230 cleanup: 231 g_free(iv); 232 return ret; 233 } 234 235 236 int qcrypto_block_encrypt_helper(QCryptoCipher *cipher, 237 size_t niv, 238 QCryptoIVGen *ivgen, 239 int sectorsize, 240 uint64_t startsector, 241 uint8_t *buf, 242 size_t len, 243 Error **errp) 244 { 245 uint8_t *iv; 246 int ret = -1; 247 248 iv = niv ? g_new0(uint8_t, niv) : NULL; 249 250 while (len > 0) { 251 size_t nbytes; 252 if (niv) { 253 if (qcrypto_ivgen_calculate(ivgen, 254 startsector, 255 iv, niv, 256 errp) < 0) { 257 goto cleanup; 258 } 259 260 if (qcrypto_cipher_setiv(cipher, 261 iv, niv, 262 errp) < 0) { 263 goto cleanup; 264 } 265 } 266 267 nbytes = len > sectorsize ? sectorsize : len; 268 if (qcrypto_cipher_encrypt(cipher, buf, buf, 269 nbytes, errp) < 0) { 270 goto cleanup; 271 } 272 273 startsector++; 274 buf += nbytes; 275 len -= nbytes; 276 } 277 278 ret = 0; 279 cleanup: 280 g_free(iv); 281 return ret; 282 } 283