From nobody Mon Feb 9 10:30:04 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1565814534; cv=none; d=zoho.com; s=zohoarc; b=L/kOdWREtz3zYcT7CSpfvHXphT1nFPDrpHLgQrUkUvzHFJis8QITcw9/RJoFogUqQKVmzABAb5Sg8lFbzT16G/pvZj5w1MRY3Ui7ejJBSQjkjQVzEIiWx//b+Sw39HfCsG6JtUFKnjKmu/L+V9R42dRMih9vc5zwEOlWdsN/gfs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1565814534; h=Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=CxBqneTrBGfDvqlexU4WDW8dtSpLY0Nr5Q/MM4awhdQ=; b=OUSR3pMRjgmlohEjgVvAKoCZRiI2hAb2VE/+n1VkGd1WwSntm1+iGbMh3e4707sTPy934luuYFn1AfTJH6PNJ+T21LKZTu4qpruJz0uipzCKONsNAbQv+GKWAerP22HltcvboNdVXCztLGLD9ojWuYf18IhAsq/q0MttneClsww= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1565814534102870.8460594681414; Wed, 14 Aug 2019 13:28:54 -0700 (PDT) Received: from localhost ([::1]:35728 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1hxzt6-0001Fd-8b for importer@patchew.org; Wed, 14 Aug 2019 16:28:52 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:33126) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1hxznE-00041S-2U for qemu-devel@nongnu.org; Wed, 14 Aug 2019 16:22:50 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hxznA-0003vq-9n for qemu-devel@nongnu.org; Wed, 14 Aug 2019 16:22:47 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58558) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hxzn0-0003oj-P0; Wed, 14 Aug 2019 16:22:35 -0400 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D2FD330A7B8F; Wed, 14 Aug 2019 20:22:33 +0000 (UTC) Received: from maximlenovopc.usersys.redhat.com (unknown [10.35.206.39]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3E74410016EB; Wed, 14 Aug 2019 20:22:31 +0000 (UTC) From: Maxim Levitsky To: qemu-devel@nongnu.org Date: Wed, 14 Aug 2019 23:22:08 +0300 Message-Id: <20190814202219.1870-3-mlevitsk@redhat.com> In-Reply-To: <20190814202219.1870-1-mlevitsk@redhat.com> References: <20190814202219.1870-1-mlevitsk@redhat.com> X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.47]); Wed, 14 Aug 2019 20:22:33 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH 02/13] qcrypto-luks: misc refactoring X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , Fam Zheng , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , qemu-block@nongnu.org, Markus Armbruster , Max Reitz , Stefan Hajnoczi , Maxim Levitsky Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This is also a preparation for key read/write/erase functions * use master key len from the header * prefer to use crypto params in the QCryptoBlockLUKS over passing them as function arguments * define QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME * Add comments to various crypto parameters in the QCryptoBlockLUKS Signed-off-by: Maxim Levitsky --- crypto/block-luks.c | 213 ++++++++++++++++++++++---------------------- 1 file changed, 105 insertions(+), 108 deletions(-) diff --git a/crypto/block-luks.c b/crypto/block-luks.c index 409ab50f20..48213abde7 100644 --- a/crypto/block-luks.c +++ b/crypto/block-luks.c @@ -70,6 +70,8 @@ typedef struct QCryptoBlockLUKSKeySlot QCryptoBlockLUKSKe= ySlot; =20 #define QCRYPTO_BLOCK_LUKS_SECTOR_SIZE 512LL =20 +#define QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME 2000 + static const char qcrypto_block_luks_magic[QCRYPTO_BLOCK_LUKS_MAGIC_LEN] = =3D { 'L', 'U', 'K', 'S', 0xBA, 0xBE }; @@ -199,13 +201,25 @@ QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSHeade= r) !=3D 592); struct QCryptoBlockLUKS { QCryptoBlockLUKSHeader header; =20 - /* Cache parsed versions of what's in header fields, - * as we can't rely on QCryptoBlock.cipher being - * non-NULL */ + /* Main encryption algorithm used for encryption*/ QCryptoCipherAlgorithm cipher_alg; + + /* Mode of encryption for the selected encryption algorithm */ QCryptoCipherMode cipher_mode; + + /* Initialization vector generation algorithm */ QCryptoIVGenAlgorithm ivgen_alg; + + /* Hash algorithm used for IV generation*/ QCryptoHashAlgorithm ivgen_hash_alg; + + /* + * Encryption algorithm used for IV generation. + * Usually the same as main encryption algorithm + */ + QCryptoCipherAlgorithm ivgen_cipher_alg; + + /* Hash algorithm used in pbkdf2 function */ QCryptoHashAlgorithm hash_alg; }; =20 @@ -397,6 +411,12 @@ qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorithm= cipher, } } =20 +static int masterkeylen(QCryptoBlockLUKS *luks) +{ + return luks->header.key_bytes; +} + + /* * Given a key slot, and user password, this will attempt to unlock * the master encryption key from the key slot. @@ -410,21 +430,15 @@ qcrypto_block_luks_essiv_cipher(QCryptoCipherAlgorith= m cipher, */ static int qcrypto_block_luks_load_key(QCryptoBlock *block, - QCryptoBlockLUKSKeySlot *slot, + uint slot_idx, const char *password, - QCryptoCipherAlgorithm cipheralg, - QCryptoCipherMode ciphermode, - QCryptoHashAlgorithm hash, - QCryptoIVGenAlgorithm ivalg, - QCryptoCipherAlgorithm ivcipheralg, - QCryptoHashAlgorithm ivhash, uint8_t *masterkey, - size_t masterkeylen, QCryptoBlockReadFunc readfunc, void *opaque, Error **errp) { QCryptoBlockLUKS *luks =3D block->opaque; + QCryptoBlockLUKSKeySlot *slot =3D &luks->header.key_slots[slot_idx]; uint8_t *splitkey; size_t splitkeylen; uint8_t *possiblekey; @@ -439,9 +453,9 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, return 0; } =20 - splitkeylen =3D masterkeylen * slot->stripes; + splitkeylen =3D masterkeylen(luks) * slot->stripes; splitkey =3D g_new0(uint8_t, splitkeylen); - possiblekey =3D g_new0(uint8_t, masterkeylen); + possiblekey =3D g_new0(uint8_t, masterkeylen(luks)); =20 /* * The user password is used to generate a (possible) @@ -450,11 +464,11 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, * the key is correct and validate the results of * decryption later. */ - if (qcrypto_pbkdf2(hash, + if (qcrypto_pbkdf2(luks->hash_alg, (const uint8_t *)password, strlen(password), slot->salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, slot->iterations, - possiblekey, masterkeylen, + possiblekey, masterkeylen(luks), errp) < 0) { goto cleanup; } @@ -478,19 +492,19 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, =20 /* Setup the cipher/ivgen that we'll use to try to decrypt * the split master key material */ - cipher =3D qcrypto_cipher_new(cipheralg, ciphermode, - possiblekey, masterkeylen, + cipher =3D qcrypto_cipher_new(luks->cipher_alg, luks->cipher_mode, + possiblekey, masterkeylen(luks), errp); if (!cipher) { goto cleanup; } =20 - niv =3D qcrypto_cipher_get_iv_len(cipheralg, - ciphermode); - ivgen =3D qcrypto_ivgen_new(ivalg, - ivcipheralg, - ivhash, - possiblekey, masterkeylen, + niv =3D qcrypto_cipher_get_iv_len(luks->cipher_alg, + luks->cipher_mode); + ivgen =3D qcrypto_ivgen_new(luks->ivgen_alg, + luks->ivgen_cipher_alg, + luks->ivgen_hash_alg, + possiblekey, masterkeylen(luks), errp); if (!ivgen) { goto cleanup; @@ -519,8 +533,8 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, * Now we've decrypted the split master key, join * it back together to get the actual master key. */ - if (qcrypto_afsplit_decode(hash, - masterkeylen, + if (qcrypto_afsplit_decode(luks->hash_alg, + masterkeylen(luks), slot->stripes, splitkey, masterkey, @@ -537,8 +551,8 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, * then comparing that to the hash stored in the key slot * header */ - if (qcrypto_pbkdf2(hash, - masterkey, masterkeylen, + if (qcrypto_pbkdf2(luks->hash_alg, + masterkey, masterkeylen(luks), luks->header.master_key_salt, QCRYPTO_BLOCK_LUKS_SALT_LEN, luks->header.master_key_iterations, @@ -577,37 +591,19 @@ qcrypto_block_luks_load_key(QCryptoBlock *block, static int qcrypto_block_luks_find_key(QCryptoBlock *block, const char *password, - QCryptoCipherAlgorithm cipheralg, - QCryptoCipherMode ciphermode, - QCryptoHashAlgorithm hash, - QCryptoIVGenAlgorithm ivalg, - QCryptoCipherAlgorithm ivcipheralg, - QCryptoHashAlgorithm ivhash, - uint8_t **masterkey, - size_t *masterkeylen, + uint8_t *masterkey, QCryptoBlockReadFunc readfunc, void *opaque, Error **errp) { - QCryptoBlockLUKS *luks =3D block->opaque; size_t i; int rv; =20 - *masterkey =3D g_new0(uint8_t, luks->header.key_bytes); - *masterkeylen =3D luks->header.key_bytes; - for (i =3D 0; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS; i++) { rv =3D qcrypto_block_luks_load_key(block, - &luks->header.key_slots[i], + i, password, - cipheralg, - ciphermode, - hash, - ivalg, - ivcipheralg, - ivhash, - *masterkey, - *masterkeylen, + masterkey, readfunc, opaque, errp); @@ -620,11 +616,7 @@ qcrypto_block_luks_find_key(QCryptoBlock *block, } =20 error_setg(errp, "Invalid password, cannot unlock any keyslot"); - error: - g_free(*masterkey); - *masterkey =3D NULL; - *masterkeylen =3D 0; return -1; } =20 @@ -639,21 +631,15 @@ qcrypto_block_luks_open(QCryptoBlock *block, size_t n_threads, Error **errp) { - QCryptoBlockLUKS *luks; + QCryptoBlockLUKS *luks =3D NULL; Error *local_err =3D NULL; int ret =3D 0; size_t i; ssize_t rv; uint8_t *masterkey =3D NULL; - size_t masterkeylen; char *ivgen_name, *ivhash_name; - QCryptoCipherMode ciphermode; - QCryptoCipherAlgorithm cipheralg; - QCryptoIVGenAlgorithm ivalg; - QCryptoCipherAlgorithm ivcipheralg; - QCryptoHashAlgorithm hash; - QCryptoHashAlgorithm ivhash; char *password =3D NULL; + char *cipher_mode =3D NULL; =20 if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { if (!options->u.luks.key_secret) { @@ -710,6 +696,8 @@ qcrypto_block_luks_open(QCryptoBlock *block, goto fail; } =20 + cipher_mode =3D g_strdup(luks->header.cipher_mode); + /* * The cipher_mode header contains a string that we have * to further parse, of the format @@ -718,7 +706,7 @@ qcrypto_block_luks_open(QCryptoBlock *block, * * eg cbc-essiv:sha256, cbc-plain64 */ - ivgen_name =3D strchr(luks->header.cipher_mode, '-'); + ivgen_name =3D strchr(cipher_mode, '-'); if (!ivgen_name) { ret =3D -EINVAL; error_setg(errp, "Unexpected cipher mode string format %s", @@ -730,13 +718,13 @@ qcrypto_block_luks_open(QCryptoBlock *block, =20 ivhash_name =3D strchr(ivgen_name, ':'); if (!ivhash_name) { - ivhash =3D 0; + luks->ivgen_hash_alg =3D 0; } else { *ivhash_name =3D '\0'; ivhash_name++; =20 - ivhash =3D qcrypto_block_luks_hash_name_lookup(ivhash_name, - &local_err); + luks->ivgen_hash_alg =3D qcrypto_block_luks_hash_name_lookup(ivhas= h_name, + &local_= err); if (local_err) { ret =3D -ENOTSUP; error_propagate(errp, local_err); @@ -744,25 +732,27 @@ qcrypto_block_luks_open(QCryptoBlock *block, } } =20 - ciphermode =3D qcrypto_block_luks_cipher_mode_lookup(luks->header.ciph= er_mode, - &local_err); + luks->cipher_mode =3D qcrypto_block_luks_cipher_mode_lookup(cipher_mod= e, + &local_err); if (local_err) { ret =3D -ENOTSUP; error_propagate(errp, local_err); goto fail; } =20 - cipheralg =3D qcrypto_block_luks_cipher_name_lookup(luks->header.ciphe= r_name, - ciphermode, - luks->header.key_byt= es, - &local_err); + luks->cipher_alg =3D + qcrypto_block_luks_cipher_name_lookup(luks->header.cipher_name, + luks->cipher_mode, + luks->header.key_bytes, + &local_err); if (local_err) { ret =3D -ENOTSUP; error_propagate(errp, local_err); goto fail; } =20 - hash =3D qcrypto_block_luks_hash_name_lookup(luks->header.hash_spec, + luks->hash_alg =3D + qcrypto_block_luks_hash_name_lookup(luks->header.hash_spec, &local_err); if (local_err) { ret =3D -ENOTSUP; @@ -770,23 +760,24 @@ qcrypto_block_luks_open(QCryptoBlock *block, goto fail; } =20 - ivalg =3D qcrypto_block_luks_ivgen_name_lookup(ivgen_name, - &local_err); + luks->ivgen_alg =3D qcrypto_block_luks_ivgen_name_lookup(ivgen_name, + &local_err); if (local_err) { ret =3D -ENOTSUP; error_propagate(errp, local_err); goto fail; } =20 - if (ivalg =3D=3D QCRYPTO_IVGEN_ALG_ESSIV) { + if (luks->ivgen_alg =3D=3D QCRYPTO_IVGEN_ALG_ESSIV) { if (!ivhash_name) { ret =3D -EINVAL; error_setg(errp, "Missing IV generator hash specification"); goto fail; } - ivcipheralg =3D qcrypto_block_luks_essiv_cipher(cipheralg, - ivhash, - &local_err); + luks->ivgen_cipher_alg =3D + qcrypto_block_luks_essiv_cipher(luks->cipher_alg, + luks->ivgen_hash_alg, + &local_err); if (local_err) { ret =3D -ENOTSUP; error_propagate(errp, local_err); @@ -800,21 +791,25 @@ qcrypto_block_luks_open(QCryptoBlock *block, * ignore hash names with these ivgens rather than report * an error about the invalid usage */ - ivcipheralg =3D cipheralg; + luks->ivgen_cipher_alg =3D luks->cipher_alg; } =20 + + g_free(cipher_mode); + cipher_mode =3D NULL; + ivgen_name =3D NULL; + ivhash_name =3D NULL; + if (!(flags & QCRYPTO_BLOCK_OPEN_NO_IO)) { /* Try to find which key slot our password is valid for * and unlock the master key from that slot. */ + + masterkey =3D g_new0(uint8_t, masterkeylen(luks)); + if (qcrypto_block_luks_find_key(block, password, - cipheralg, ciphermode, - hash, - ivalg, - ivcipheralg, - ivhash, - &masterkey, &masterkeylen, + masterkey, readfunc, opaque, errp) < 0) { ret =3D -EACCES; @@ -824,21 +819,24 @@ qcrypto_block_luks_open(QCryptoBlock *block, /* We have a valid master key now, so can setup the * block device payload decryption objects */ - block->kdfhash =3D hash; - block->niv =3D qcrypto_cipher_get_iv_len(cipheralg, - ciphermode); - block->ivgen =3D qcrypto_ivgen_new(ivalg, - ivcipheralg, - ivhash, - masterkey, masterkeylen, + block->kdfhash =3D luks->hash_alg; + block->niv =3D qcrypto_cipher_get_iv_len(luks->cipher_alg, + luks->cipher_mode); + + block->ivgen =3D qcrypto_ivgen_new(luks->ivgen_alg, + luks->ivgen_cipher_alg, + luks->ivgen_hash_alg, + masterkey, masterkeylen(luks), errp); if (!block->ivgen) { ret =3D -ENOTSUP; goto fail; } =20 - ret =3D qcrypto_block_init_cipher(block, cipheralg, ciphermode, - masterkey, masterkeylen, n_threads, + ret =3D qcrypto_block_init_cipher(block, luks->cipher_alg, + luks->cipher_mode, + masterkey, masterkeylen(luks), + n_threads, errp); if (ret < 0) { ret =3D -ENOTSUP; @@ -850,12 +848,6 @@ qcrypto_block_luks_open(QCryptoBlock *block, block->payload_offset =3D luks->header.payload_offset * block->sector_size; =20 - luks->cipher_alg =3D cipheralg; - luks->cipher_mode =3D ciphermode; - luks->ivgen_alg =3D ivalg; - luks->ivgen_hash_alg =3D ivhash; - luks->hash_alg =3D hash; - g_free(masterkey); g_free(password); =20 @@ -910,7 +902,7 @@ qcrypto_block_luks_create(QCryptoBlock *block, =20 memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts)); if (!luks_opts.has_iter_time) { - luks_opts.iter_time =3D 2000; + luks_opts.iter_time =3D QCRYPTO_BLOCK_LUKS_DEFAULT_ITER_TIME; } if (!luks_opts.has_cipher_alg) { luks_opts.cipher_alg =3D QCRYPTO_CIPHER_ALG_AES_256; @@ -930,6 +922,17 @@ qcrypto_block_luks_create(QCryptoBlock *block, luks_opts.has_ivgen_hash_alg =3D true; } } + + luks =3D g_new0(QCryptoBlockLUKS, 1); + block->opaque =3D luks; + + luks->cipher_alg =3D luks_opts.cipher_alg; + luks->cipher_mode =3D luks_opts.cipher_mode; + luks->ivgen_alg =3D luks_opts.ivgen_alg; + luks->ivgen_hash_alg =3D luks_opts.ivgen_hash_alg; + luks->hash_alg =3D luks_opts.hash_alg; + + /* Note we're allowing ivgen_hash_alg to be set even for * non-essiv iv generators that don't need a hash. It will * be silently ignored, for compatibility with dm-crypt */ @@ -944,8 +947,6 @@ qcrypto_block_luks_create(QCryptoBlock *block, return -1; } =20 - luks =3D g_new0(QCryptoBlockLUKS, 1); - block->opaque =3D luks; =20 memcpy(luks->header.magic, qcrypto_block_luks_magic, QCRYPTO_BLOCK_LUKS_MAGIC_LEN); @@ -1003,6 +1004,8 @@ qcrypto_block_luks_create(QCryptoBlock *block, ivcipheralg =3D luks_opts.cipher_alg; } =20 + luks->ivgen_cipher_alg =3D ivcipheralg; + strcpy(luks->header.cipher_name, cipher_alg); strcpy(luks->header.cipher_mode, cipher_mode_spec); strcpy(luks->header.hash_spec, hash_alg); @@ -1304,12 +1307,6 @@ qcrypto_block_luks_create(QCryptoBlock *block, goto error; } =20 - luks->cipher_alg =3D luks_opts.cipher_alg; - luks->cipher_mode =3D luks_opts.cipher_mode; - luks->ivgen_alg =3D luks_opts.ivgen_alg; - luks->ivgen_hash_alg =3D luks_opts.ivgen_hash_alg; - luks->hash_alg =3D luks_opts.hash_alg; - memset(masterkey, 0, luks->header.key_bytes); g_free(masterkey); memset(slotkey, 0, luks->header.key_bytes); --=20 2.17.2