From nobody Thu Feb 12 18:28:05 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1770906114; cv=none; d=zohomail.com; s=zohoarc; b=VsGDQIpvRk4zdBq8NffBsqRnGMwtfdhBMx3OceKu72w8+JvKVRuwFBM2MoNpQCNp3GEJr3CXlQA+0qgTxCrwaN25CAaZTRxXbml5IUP4Hkj+kv/+Z/6Nld7lB2YiXjaTQ8B/tt0gZlt274BmSLtvdNydexX5kwnJmV5eSocrsow= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1770906114; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id; bh=8lx+wkL/wAUZywaI7GnDV5LAlwXs2qP3PnHSvN/W8wc=; b=co7muJhk3QGTNe1k63g/70u9/yIC4N562MbxUnCsAS0pNETyQ8VK1T5a6/7lTS2m4e6GzqO1bfZAN5vsrtZtiYYJkXde2Dfy2JFWeDkb0QPLZcWoK8XbWHyg9D9/1mNyaWESNNv+9/Gco8hnOK9Q2bTPegNEsGNjVaSNF67lL0M= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1770906114344195.39548244679827; Thu, 12 Feb 2026 06:21:54 -0800 (PST) Received: by lists.libvirt.org (Postfix, from userid 993) id 10B604415A; Thu, 12 Feb 2026 09:21:53 -0500 (EST) Received: from [172.19.199.6] (lists.libvirt.org [8.43.85.245]) by lists.libvirt.org (Postfix) with ESMTP id E455544FED; Thu, 12 Feb 2026 07:53:18 -0500 (EST) Received: by lists.libvirt.org (Postfix, from userid 993) id 0B62D4555E; Thu, 12 Feb 2026 07:51:35 -0500 (EST) Received: from mx1.osci.io (unknown [8.43.85.229]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id F057D46300 for ; Thu, 12 Feb 2026 07:40:11 -0500 (EST) Received: by mx1.osci.io (Postfix, from userid 995) id 05EC328C7D; Tue, 10 Feb 2026 12:56:54 -0500 (EST) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-256) server-digest SHA256) (No client certificate requested) by mx1.osci.io (Postfix) with ESMTPS id 2AF8B28C7B for ; Tue, 10 Feb 2026 12:56:53 -0500 (EST) Received: from mail-pf1-f200.google.com (mail-pf1-f200.google.com [209.85.210.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-410-pmwheDxdNoO2LlbSzEjcvQ-1; Tue, 10 Feb 2026 12:56:51 -0500 Received: by mail-pf1-f200.google.com with SMTP id d2e1a72fcca58-81f3c36dd2cso1178456b3a.2 for ; Tue, 10 Feb 2026 09:56:51 -0800 (PST) Received: from armenon-kvm.armenon-thinkpadp16vgen1.bengluru.csb ([49.36.106.234]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-824418a70fesm13782658b3a.45.2026.02.10.09.56.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 09:56:49 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,SPF_PASS autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770746212; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8lx+wkL/wAUZywaI7GnDV5LAlwXs2qP3PnHSvN/W8wc=; b=bpyw51b1usoC3J1Z4zN6wnPmEe1+3gRtCeKi8O+C+6yafQz1vS2C2GMJ8glUg++S6XbCqS EqLGeVPbU96G1OsHRedBMsb4wDX+rBfjogyl8JZYAdm4vRopRfwW+E0pDVrjPoqTbhcZze GXg552WCNTdVgEseSmaxufGd43Tkniw= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1770746212; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8lx+wkL/wAUZywaI7GnDV5LAlwXs2qP3PnHSvN/W8wc=; b=bpyw51b1usoC3J1Z4zN6wnPmEe1+3gRtCeKi8O+C+6yafQz1vS2C2GMJ8glUg++S6XbCqS EqLGeVPbU96G1OsHRedBMsb4wDX+rBfjogyl8JZYAdm4vRopRfwW+E0pDVrjPoqTbhcZze GXg552WCNTdVgEseSmaxufGd43Tkniw= X-MC-Unique: pmwheDxdNoO2LlbSzEjcvQ-1 X-Mimecast-MFC-AGG-ID: pmwheDxdNoO2LlbSzEjcvQ_1770746210 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770746210; x=1771351010; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8lx+wkL/wAUZywaI7GnDV5LAlwXs2qP3PnHSvN/W8wc=; b=rzmP3l5G/oBS6W87ZjnWYlIMeUn/MuJkOVf99vVPwoJsqjcOYidKyn5yybwqZx6+wi B994vaxQ5PiwaGUh/Z1s1o75Xt8Ok2KxO3XLsUIfyoK4QEkkHtmU2g+awcw+1isMAFm1 PvrvBQOKezYMR6nJelKBJRmUqZwpar0458OB8EYfKWPz7XY7M2/xy7g5hITtUaSesMjX whTXdmdsqNsgZ941Edt3kkDRPxmoGsFHAm0ERqbKj92nTsWy/GmztH0UWl4k/AvV2HsH +QJrgmEImyQqFvVlIC7fE4JZF5U2oJOR8/3quo123Gz/c1pFpFCICy0lsKb2OIRSV+O0 1Zhg== X-Gm-Message-State: AOJu0Yz+Dais5itcYinJFjK6HY+5B6qktv39AtxAfABuBvQ9Lz+O/7yn VxSUc21eru6P1awZW/gOlKquks3K1INkRO5QljTEucF/ISfAHdWTqbL/TMmrwprS4s0bHdz3vRt Y3iSXM1EdujywQPOW04jNJif876jI+JbtwHTJnYatl6cseG6s+YUoHqz+xaF7SnOvK8OHPoYADJ s/YAdSOFIoKeQq3wnQ1zki7utFJEltv9xr3Jlru6MqIA== X-Gm-Gg: AZuq6aJG+dbsN/DQuZZ8GO7rjz2tVRck2ecfR7TWP793AhSf/wwBalyRPKP7+NQAaDL JKstfzUUhGjzBbfebPf1p5yq374zl8xjAjxkjOq3O6mk++cR/WgheMwBoGnR4Mm6v4SjMhpijdr uu01NveMgG7X9oLqMu5Aym0qWVCiOYFGkXVmpH2B8OdACxIUWB6iAZHgnw04Ez4OWQlAv2bM55Y rjE53D4KcWQ1qw0AH+g1SfU0VxueyNAXsSIHFJ+yaMa9KD8tHJEClgjIICdfEu3Xhb/ytfhBsHu oMlMtiupPMLriq4Dzmx5xt7yWxv8IE1ZHCkQTcmVXtijDtYHy9st9uBvjL2nijp7h5afXmObaRM mJ/55rWPF5S8AJwycIISZJ9fZKfu0KQs6fsS1s+uHBo+grAHam4+Kwr1j/+OK40616hxwDQ== X-Received: by 2002:a05:6a00:ab86:b0:81f:9c54:65df with SMTP id d2e1a72fcca58-82441754f9bmr12479548b3a.50.1770746209960; Tue, 10 Feb 2026 09:56:49 -0800 (PST) X-Received: by 2002:a05:6a00:ab86:b0:81f:9c54:65df with SMTP id d2e1a72fcca58-82441754f9bmr12479534b3a.50.1770746209367; Tue, 10 Feb 2026 09:56:49 -0800 (PST) To: devel@lists.libvirt.org Subject: [PATCH v6 1/6] util: Add support for GnuTLS decryption Date: Tue, 10 Feb 2026 23:26:38 +0530 Message-ID: <20260210175643.23351-2-armenon@redhat.com> X-Mailer: git-send-email 2.51.1 In-Reply-To: <20260210175643.23351-1-armenon@redhat.com> References: <20260210175643.23351-1-armenon@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: kTk_Ho-R3ZbEf4ZRm4QHZAuvMgYp1R2iH2UkD0HjKLY_1770746210 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: FVE4XUGZAVX53EERNAZL43MTB7IHDWWN X-Message-ID-Hash: FVE4XUGZAVX53EERNAZL43MTB7IHDWWN X-MailFrom: armenon@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Arun Menon X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Arun Menon via Devel Reply-To: Arun Menon X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1770906124896158500 Content-Type: text/plain; charset="utf-8"; x-default="true" From: Arun Menon Adds `virCryptoDecryptDataAESgnutls` and `virCryptoDecryptData` as wrapper functions for GnuTLS decryption. These functions are the inverse of the existing GnuTLS encryption wrappers. This commit also includes a corresponding test case to validate data decryp= tion. Signed-off-by: Arun Menon Reviewed-by: Peter Krempa --- src/libvirt_private.syms | 1 + src/util/vircrypto.c | 126 ++++++++++++++++++++++++++++++++++++++- src/util/vircrypto.h | 8 +++ tests/vircryptotest.c | 65 ++++++++++++++++++++ 4 files changed, 199 insertions(+), 1 deletion(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d81b30f0b6..40af831070 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2248,6 +2248,7 @@ virConfWriteMem; =20 =20 # util/vircrypto.h +virCryptoDecryptData; virCryptoEncryptData; virCryptoHashBuf; virCryptoHashString; diff --git a/src/util/vircrypto.c b/src/util/vircrypto.c index 3ce23264ca..00f723bb75 100644 --- a/src/util/vircrypto.c +++ b/src/util/vircrypto.c @@ -98,7 +98,7 @@ virCryptoHashString(virCryptoHash hash, } =20 =20 -/* virCryptoEncryptDataAESgntuls: +/* virCryptoEncryptDataAESgnutls: * * Performs the AES gnutls encryption * @@ -233,3 +233,127 @@ virCryptoEncryptData(virCryptoCipher algorithm, _("algorithm=3D%1$d is not supported"), algorithm); return -1; } + +/* virCryptoDecryptDataAESgnutls: + * + * Performs the AES gnutls decryption + * + * Same input as virCryptoDecryptData, except the algorithm is replaced + * by the specific gnutls algorithm. + * + * Decrypts the @data buffer using the @deckey and if available the @iv + * + * Returns 0 on success with the plaintext being filled. It is the + * caller's responsibility to clear and free it. Returns -1 on failure + * w/ error set. + */ +static int +virCryptoDecryptDataAESgnutls(gnutls_cipher_algorithm_t gnutls_dec_alg, + uint8_t *deckey, + size_t deckeylen, + uint8_t *iv, + size_t ivlen, + uint8_t *data, + size_t datalen, + uint8_t **plaintextret, + size_t *plaintextlenret) +{ + int rc; + uint8_t padding_length; + gnutls_cipher_hd_t handle =3D NULL; + gnutls_datum_t dec_key =3D { .data =3D deckey, .size =3D deckeylen }; + gnutls_datum_t iv_buf =3D { .data =3D iv, .size =3D ivlen }; + g_autofree uint8_t *plaintext =3D NULL; + size_t plaintextlen; + + if ((rc =3D gnutls_cipher_init(&handle, gnutls_dec_alg, + &dec_key, &iv_buf)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to initialize cipher: '%1$s'"), + gnutls_strerror(rc)); + return -1; + } + + plaintext =3D g_memdup2(data, datalen); + plaintextlen =3D datalen; + if (plaintextlen =3D=3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("decrypted data has zero length")); + goto error; + } + rc =3D gnutls_cipher_decrypt(handle, plaintext, plaintextlen); + gnutls_cipher_deinit(handle); + if (rc < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to decrypt the data: '%1$s'"), + gnutls_strerror(rc)); + goto error; + } + /* Before encryption, padding is added to the data. + * The last byte indicates the padding length, because in PKCS#7, all + * padding bytes are set to the padding length value. + */ + padding_length =3D plaintext[plaintextlen - 1]; + if (padding_length > plaintextlen) { + virReportError(VIR_ERR_INVALID_SECRET, "%s", + _("decrypted data has invalid padding")); + goto error; + } + *plaintextlenret =3D plaintextlen - padding_length; + *plaintextret =3D g_steal_pointer(&plaintext); + return 0; + error: + virSecureErase(plaintext, plaintextlen); + return -1; +} + +/* virCryptoDecryptData: + * @algorithm: algorithm desired for decryption + * @deckey: decryption key + * @deckeylen: decryption key length + * @iv: initialization vector + * @ivlen: length of initialization vector + * @data: data to decrypt + * @datalen: length of data + * @plaintext: stream of bytes allocated to store plaintext + * @plaintextlen: size of the stream of bytes + * Returns 0 on success, -1 on failure with error set + */ +int +virCryptoDecryptData(virCryptoCipher algorithm, + uint8_t *deckey, + size_t deckeylen, + uint8_t *iv, + size_t ivlen, + uint8_t *data, + size_t datalen, + uint8_t **plaintext, + size_t *plaintextlen) +{ + switch (algorithm) { + case VIR_CRYPTO_CIPHER_AES256CBC: + if (deckeylen !=3D 32) { + virReportError(VIR_ERR_INVALID_ARG, + _("AES256CBC decryption invalid keylen=3D%1$zu= "), + deckeylen); + return -1; + } + if (ivlen !=3D 16) { + virReportError(VIR_ERR_INVALID_ARG, + _("AES256CBC initialization vector invalid len= =3D%1$zu"), + ivlen); + return -1; + } + return virCryptoDecryptDataAESgnutls(GNUTLS_CIPHER_AES_256_CBC, + deckey, deckeylen, iv, ivlen, + data, datalen, + plaintext, plaintextlen); + case VIR_CRYPTO_CIPHER_NONE: + case VIR_CRYPTO_CIPHER_LAST: + break; + } + + virReportError(VIR_ERR_INVALID_ARG, + _("algorithm=3D%1$d is not supported"), algorithm); + return -1; +} diff --git a/src/util/vircrypto.h b/src/util/vircrypto.h index 5f079ac335..2e8557839d 100644 --- a/src/util/vircrypto.h +++ b/src/util/vircrypto.h @@ -61,3 +61,11 @@ int virCryptoEncryptData(virCryptoCipher algorithm, uint8_t **ciphertext, size_t *ciphertextlen) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6) ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(9) G_GNUC_WARN_UNUSED_RESULT; + +int virCryptoDecryptData(virCryptoCipher algorithm, + uint8_t *deckey, size_t deckeylen, + uint8_t *iv, size_t ivlen, + uint8_t *data, size_t datalen, + uint8_t **plaintext, size_t *plaintextlen) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(6) + ATTRIBUTE_NONNULL(8) ATTRIBUTE_NONNULL(9) G_GNUC_WARN_UNUSED_RESULT; diff --git a/tests/vircryptotest.c b/tests/vircryptotest.c index 9ffe70756e..864fa8838d 100644 --- a/tests/vircryptotest.c +++ b/tests/vircryptotest.c @@ -62,6 +62,14 @@ struct testCryptoEncryptData { size_t ciphertextlen; }; =20 +struct testCryptoDecryptData { + virCryptoCipher algorithm; + uint8_t *input; + size_t inputlen; + uint8_t *plaintext; + size_t plaintextlen; +}; + static int testCryptoEncrypt(const void *opaque) { @@ -101,6 +109,44 @@ testCryptoEncrypt(const void *opaque) return 0; } =20 +static int +testCryptoDecrypt(const void *opaque) +{ + const struct testCryptoDecryptData *data =3D opaque; + g_autofree uint8_t *deckey =3D NULL; + size_t deckeylen =3D 32; + g_autofree uint8_t *iv =3D NULL; + size_t ivlen =3D 16; + g_autofree uint8_t *plaintext =3D NULL; + size_t plaintextlen =3D 0; + + deckey =3D g_new0(uint8_t, deckeylen); + iv =3D g_new0(uint8_t, ivlen); + + if (virRandomBytes(deckey, deckeylen) < 0 || + virRandomBytes(iv, ivlen) < 0) { + fprintf(stderr, "Failed to generate random bytes\n"); + return -1; + } + + if (virCryptoDecryptData(data->algorithm, deckey, deckeylen, iv, ivlen, + data->input, data->inputlen, + &plaintext, &plaintextlen) < 0) + return -1; + + if (data->plaintextlen !=3D plaintextlen) { + fprintf(stderr, "Expected plaintexlen(%zu) doesn't match (%zu)\n", + data->plaintextlen, plaintextlen); + return -1; + } + + if (memcmp(data->plaintext, plaintext, plaintextlen)) { + fprintf(stderr, "Expected plaintext doesn't match\n"); + return -1; + } + + return 0; +} =20 static int mymain(void) @@ -155,7 +201,26 @@ mymain(void) =20 #undef VIR_CRYPTO_ENCRYPT =20 +#define VIR_CRYPTO_DECRYPT(a, n, i, il, c, cl) \ + do { \ + struct testCryptoDecryptData data =3D { \ + .algorithm =3D a, \ + .input =3D i, \ + .inputlen =3D il, \ + .plaintext =3D c, \ + .plaintextlen =3D cl, \ + }; \ + if (virTestRun("Decrypt " n, testCryptoDecrypt, &data) < 0) \ + ret =3D -1; \ + } while (0) + + VIR_CRYPTO_DECRYPT(VIR_CRYPTO_CIPHER_AES256CBC, "aes256cbc", + expected_ciphertext, 16, secretdata, 7); + +#undef VIR_CRYPTO_DECRYPT + return ret =3D=3D 0 ? EXIT_SUCCESS : EXIT_FAILURE; + } =20 /* Forces usage of not so random virRandomBytes */ --=20 2.51.1