1 /* 2 * QEMU Crypto block encryption 3 * 4 * Copyright (c) 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 "crypto/init.h" 24 #include "crypto/block.h" 25 #include "qemu/buffer.h" 26 #include "qemu/module.h" 27 #include "crypto/secret.h" 28 #ifndef _WIN32 29 #include <sys/resource.h> 30 #endif 31 32 #if (defined(_WIN32) || defined RUSAGE_THREAD) && \ 33 (defined(CONFIG_NETTLE) || defined(CONFIG_GCRYPT)) 34 #define TEST_LUKS 35 #else 36 #undef TEST_LUKS 37 #endif 38 39 static QCryptoBlockCreateOptions qcow_create_opts = { 40 .format = Q_CRYPTO_BLOCK_FORMAT_QCOW, 41 .u.qcow = { 42 .has_key_secret = true, 43 .key_secret = (char *)"sec0", 44 }, 45 }; 46 47 static QCryptoBlockOpenOptions qcow_open_opts = { 48 .format = Q_CRYPTO_BLOCK_FORMAT_QCOW, 49 .u.qcow = { 50 .has_key_secret = true, 51 .key_secret = (char *)"sec0", 52 }, 53 }; 54 55 56 #ifdef TEST_LUKS 57 static QCryptoBlockOpenOptions luks_open_opts = { 58 .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, 59 .u.luks = { 60 .has_key_secret = true, 61 .key_secret = (char *)"sec0", 62 }, 63 }; 64 65 66 /* Creation with all default values */ 67 static QCryptoBlockCreateOptions luks_create_opts_default = { 68 .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, 69 .u.luks = { 70 .has_key_secret = true, 71 .key_secret = (char *)"sec0", 72 }, 73 }; 74 75 76 /* ...and with explicit values */ 77 static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_plain64 = { 78 .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, 79 .u.luks = { 80 .has_key_secret = true, 81 .key_secret = (char *)"sec0", 82 .has_cipher_alg = true, 83 .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, 84 .has_cipher_mode = true, 85 .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, 86 .has_ivgen_alg = true, 87 .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64, 88 }, 89 }; 90 91 92 static QCryptoBlockCreateOptions luks_create_opts_aes256_cbc_essiv = { 93 .format = Q_CRYPTO_BLOCK_FORMAT_LUKS, 94 .u.luks = { 95 .has_key_secret = true, 96 .key_secret = (char *)"sec0", 97 .has_cipher_alg = true, 98 .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, 99 .has_cipher_mode = true, 100 .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, 101 .has_ivgen_alg = true, 102 .ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV, 103 .has_ivgen_hash_alg = true, 104 .ivgen_hash_alg = QCRYPTO_HASH_ALG_SHA256, 105 .has_hash_alg = true, 106 .hash_alg = QCRYPTO_HASH_ALG_SHA1, 107 }, 108 }; 109 #endif /* TEST_LUKS */ 110 111 112 static struct QCryptoBlockTestData { 113 const char *path; 114 QCryptoBlockCreateOptions *create_opts; 115 QCryptoBlockOpenOptions *open_opts; 116 117 bool expect_header; 118 119 QCryptoCipherAlgorithm cipher_alg; 120 QCryptoCipherMode cipher_mode; 121 QCryptoHashAlgorithm hash_alg; 122 123 QCryptoIVGenAlgorithm ivgen_alg; 124 QCryptoHashAlgorithm ivgen_hash; 125 126 bool slow; 127 } test_data[] = { 128 { 129 .path = "/crypto/block/qcow", 130 .create_opts = &qcow_create_opts, 131 .open_opts = &qcow_open_opts, 132 133 .expect_header = false, 134 135 .cipher_alg = QCRYPTO_CIPHER_ALG_AES_128, 136 .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, 137 138 .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64, 139 }, 140 #ifdef TEST_LUKS 141 { 142 .path = "/crypto/block/luks/default", 143 .create_opts = &luks_create_opts_default, 144 .open_opts = &luks_open_opts, 145 146 .expect_header = true, 147 148 .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, 149 .cipher_mode = QCRYPTO_CIPHER_MODE_XTS, 150 .hash_alg = QCRYPTO_HASH_ALG_SHA256, 151 152 .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64, 153 154 .slow = true, 155 }, 156 { 157 .path = "/crypto/block/luks/aes-256-cbc-plain64", 158 .create_opts = &luks_create_opts_aes256_cbc_plain64, 159 .open_opts = &luks_open_opts, 160 161 .expect_header = true, 162 163 .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, 164 .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, 165 .hash_alg = QCRYPTO_HASH_ALG_SHA256, 166 167 .ivgen_alg = QCRYPTO_IVGEN_ALG_PLAIN64, 168 169 .slow = true, 170 }, 171 { 172 .path = "/crypto/block/luks/aes-256-cbc-essiv", 173 .create_opts = &luks_create_opts_aes256_cbc_essiv, 174 .open_opts = &luks_open_opts, 175 176 .expect_header = true, 177 178 .cipher_alg = QCRYPTO_CIPHER_ALG_AES_256, 179 .cipher_mode = QCRYPTO_CIPHER_MODE_CBC, 180 .hash_alg = QCRYPTO_HASH_ALG_SHA1, 181 182 .ivgen_alg = QCRYPTO_IVGEN_ALG_ESSIV, 183 .ivgen_hash = QCRYPTO_HASH_ALG_SHA256, 184 185 .slow = true, 186 }, 187 #endif 188 }; 189 190 191 static int test_block_read_func(QCryptoBlock *block, 192 size_t offset, 193 uint8_t *buf, 194 size_t buflen, 195 void *opaque, 196 Error **errp) 197 { 198 Buffer *header = opaque; 199 200 g_assert_cmpint(offset + buflen, <=, header->capacity); 201 202 memcpy(buf, header->buffer + offset, buflen); 203 204 return 0; 205 } 206 207 208 static int test_block_init_func(QCryptoBlock *block, 209 size_t headerlen, 210 void *opaque, 211 Error **errp) 212 { 213 Buffer *header = opaque; 214 215 g_assert_cmpint(header->capacity, ==, 0); 216 217 buffer_reserve(header, headerlen); 218 219 return 0; 220 } 221 222 223 static int test_block_write_func(QCryptoBlock *block, 224 size_t offset, 225 const uint8_t *buf, 226 size_t buflen, 227 void *opaque, 228 Error **errp) 229 { 230 Buffer *header = opaque; 231 232 g_assert_cmpint(buflen + offset, <=, header->capacity); 233 234 memcpy(header->buffer + offset, buf, buflen); 235 header->offset = offset + buflen; 236 237 return 0; 238 } 239 240 241 static Object *test_block_secret(void) 242 { 243 return object_new_with_props( 244 TYPE_QCRYPTO_SECRET, 245 object_get_objects_root(), 246 "sec0", 247 &error_abort, 248 "data", "123456", 249 NULL); 250 } 251 252 static void test_block_assert_setup(const struct QCryptoBlockTestData *data, 253 QCryptoBlock *blk) 254 { 255 QCryptoIVGen *ivgen; 256 QCryptoCipher *cipher; 257 258 ivgen = qcrypto_block_get_ivgen(blk); 259 cipher = qcrypto_block_get_cipher(blk); 260 261 g_assert(ivgen); 262 g_assert(cipher); 263 264 g_assert_cmpint(data->cipher_alg, ==, cipher->alg); 265 g_assert_cmpint(data->cipher_mode, ==, cipher->mode); 266 g_assert_cmpint(data->hash_alg, ==, 267 qcrypto_block_get_kdf_hash(blk)); 268 269 g_assert_cmpint(data->ivgen_alg, ==, 270 qcrypto_ivgen_get_algorithm(ivgen)); 271 g_assert_cmpint(data->ivgen_hash, ==, 272 qcrypto_ivgen_get_hash(ivgen)); 273 } 274 275 276 static void test_block(gconstpointer opaque) 277 { 278 const struct QCryptoBlockTestData *data = opaque; 279 QCryptoBlock *blk; 280 Buffer header; 281 Object *sec = test_block_secret(); 282 283 memset(&header, 0, sizeof(header)); 284 buffer_init(&header, "header"); 285 286 blk = qcrypto_block_create(data->create_opts, NULL, 287 test_block_init_func, 288 test_block_write_func, 289 &header, 290 &error_abort); 291 g_assert(blk); 292 293 if (data->expect_header) { 294 g_assert_cmpint(header.capacity, >, 0); 295 } else { 296 g_assert_cmpint(header.capacity, ==, 0); 297 } 298 299 test_block_assert_setup(data, blk); 300 301 qcrypto_block_free(blk); 302 object_unparent(sec); 303 304 /* Ensure we can't open without the secret */ 305 blk = qcrypto_block_open(data->open_opts, NULL, 306 test_block_read_func, 307 &header, 308 0, 309 1, 310 NULL); 311 g_assert(blk == NULL); 312 313 /* Ensure we can't open without the secret, unless NO_IO */ 314 blk = qcrypto_block_open(data->open_opts, NULL, 315 test_block_read_func, 316 &header, 317 QCRYPTO_BLOCK_OPEN_NO_IO, 318 1, 319 &error_abort); 320 321 g_assert(qcrypto_block_get_cipher(blk) == NULL); 322 g_assert(qcrypto_block_get_ivgen(blk) == NULL); 323 324 qcrypto_block_free(blk); 325 326 327 /* Now open for real with secret */ 328 sec = test_block_secret(); 329 blk = qcrypto_block_open(data->open_opts, NULL, 330 test_block_read_func, 331 &header, 332 0, 333 1, 334 &error_abort); 335 g_assert(blk); 336 337 test_block_assert_setup(data, blk); 338 339 qcrypto_block_free(blk); 340 341 object_unparent(sec); 342 343 buffer_free(&header); 344 } 345 346 347 int main(int argc, char **argv) 348 { 349 gsize i; 350 351 module_call_init(MODULE_INIT_QOM); 352 g_test_init(&argc, &argv, NULL); 353 354 g_assert(qcrypto_init(NULL) == 0); 355 356 for (i = 0; i < G_N_ELEMENTS(test_data); i++) { 357 if (test_data[i].open_opts->format == Q_CRYPTO_BLOCK_FORMAT_LUKS && 358 !qcrypto_hash_supports(test_data[i].hash_alg)) { 359 continue; 360 } 361 if (!test_data[i].slow || 362 g_test_slow()) { 363 g_test_add_data_func(test_data[i].path, &test_data[i], test_block); 364 } 365 } 366 367 return g_test_run(); 368 } 369