On Tue, Jul 14, 2026 at 07:29:14AM +0000, Jamin Lin wrote:
> Map QCRYPTO_CIPHER_MODE_GCM to GCRY_CIPHER_MODE_GCM and advertise it in
> qcrypto_cipher_supports() for 128-bit block ciphers. Add a GCM driver
> whose setiv accepts the (typically 96-bit) nonce, whose encrypt/decrypt
> do not require block-aligned lengths, and which implements setaad via
> gcry_cipher_authenticate() and gettag via gcry_cipher_gettag().
>
> Signed-off-by: Jamin Lin <[email protected]>
> ---
> crypto/cipher-gcrypt.c.inc | 101 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 101 insertions(+)
>
> diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc
> index 12eb9ddb5a..fce09a3c77 100644
> --- a/crypto/cipher-gcrypt.c.inc
> +++ b/crypto/cipher-gcrypt.c.inc
> @@ -65,6 +65,8 @@ static int
> qcrypto_cipher_mode_to_gcry_mode(QCryptoCipherMode mode)
> return GCRY_CIPHER_MODE_CBC;
> case QCRYPTO_CIPHER_MODE_CTR:
> return GCRY_CIPHER_MODE_CTR;
> + case QCRYPTO_CIPHER_MODE_GCM:
> + return GCRY_CIPHER_MODE_GCM;
> default:
> return GCRY_CIPHER_MODE_NONE;
> }
> @@ -104,6 +106,10 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
> case QCRYPTO_CIPHER_MODE_XTS:
> case QCRYPTO_CIPHER_MODE_CTR:
> return true;
> + case QCRYPTO_CIPHER_MODE_GCM:
> + /* GCM requires a 128-bit block cipher. */
> + return gcry_cipher_get_algo_blklen(
> + qcrypto_cipher_alg_to_gcry_alg(alg)) == 16;
> default:
> return false;
> }
> @@ -228,6 +234,99 @@ static const struct QCryptoCipherDriver
> qcrypto_gcrypt_ctr_driver = {
> .cipher_free = qcrypto_gcrypt_ctx_free,
> };
>
> +/*
> + * GCM is an AEAD stream mode: the IV/nonce need not match the block size,
> + * the message length need not be a multiple of the block size, associated
> + * data is fed with gcry_cipher_authenticate() and the authentication tag is
> + * read back with gcry_cipher_gettag().
> + */
> +static int qcrypto_gcrypt_gcm_setiv(QCryptoCipher *cipher,
> + const uint8_t *iv, size_t niv,
> + Error **errp)
> +{
> + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt,
> base);
> + gcry_error_t err;
> +
> + gcry_cipher_reset(ctx->handle);
> + err = gcry_cipher_setiv(ctx->handle, iv, niv);
> + if (err != 0) {
> + error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
> + return -1;
> + }
> +
> + return 0;
> +}
>
> +static int qcrypto_gcrypt_gcm_encrypt(QCryptoCipher *cipher, const void *in,
> + void *out, size_t len, Error **errp)
> +{
> + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt,
> base);
> + gcry_error_t err;
> +
> + err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
> + if (err != 0) {
> + error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int qcrypto_gcrypt_gcm_decrypt(QCryptoCipher *cipher, const void *in,
> + void *out, size_t len, Error **errp)
> +{
> + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt,
> base);
> + gcry_error_t err;
> +
> + err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
> + if (err != 0) {
> + error_setg(errp, "Cannot decrypt data: %s", gcry_strerror(err));
> + return -1;
> + }
> +
> + return 0;
> +}
Is there a reason you can't use the common qcrypto_gcrypt_setiv,
qcrypto_gcrypt_decrypt and qcrypto_gcrypt_encrypt methods ?
> +
> +static int qcrypto_gcrypt_gcm_gettag(QCryptoCipher *cipher,
> + uint8_t *tag, size_t len, Error **errp)
> +{
> + QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt,
> base);
> + gcry_error_t err;
> +
> + err = gcry_cipher_gettag(ctx->handle, tag, len);
> + if (err != 0) {
> + error_setg(errp, "Cannot get tag: %s", gcry_strerror(err));
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static const struct QCryptoCipherDriver qcrypto_gcrypt_gcm_driver = {
> + .cipher_encrypt = qcrypto_gcrypt_gcm_encrypt,
> + .cipher_decrypt = qcrypto_gcrypt_gcm_decrypt,
> + .cipher_setiv = qcrypto_gcrypt_gcm_setiv,
> + .cipher_setaad = qcrypto_gcrypt_gcm_setaad,
> + .cipher_gettag = qcrypto_gcrypt_gcm_gettag,
> + .cipher_free = qcrypto_gcrypt_ctx_free,
> +};
> +
> static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
> QCryptoCipherMode mode,
> const uint8_t *key,
> @@ -259,6 +358,8 @@ static QCryptoCipher
> *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
>
> if (mode == QCRYPTO_CIPHER_MODE_CTR) {
> drv = &qcrypto_gcrypt_ctr_driver;
> + } else if (mode == QCRYPTO_CIPHER_MODE_GCM) {
> + drv = &qcrypto_gcrypt_gcm_driver;
> } else {
> drv = &qcrypto_gcrypt_driver;
> }
> --
> 2.43.0
>
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|