On Tue, Jul 14, 2026 at 08:57:24AM +0000, Jamin Lin wrote:
> Hi Daniel
> 
> > Subject: Re: [PATCH v1 09/15] crypto/cipher-gcrypt: Implement AES-GCM
> > 
> > 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 ?
> > 
> 
> Thanks for the review and suggestion.
> 
> The GCM path differs from the common methods in two input checks that GCM 
> legitimately violates:
> 
>   - qcrypto_gcrypt_setiv() rejects niv != blocksize, but GCM uses a
>     96-bit (12-byte) nonce.
>   - qcrypto_gcrypt_encrypt()/decrypt() reject a length that is not a
>     multiple of the block size, but GCM must accept arbitrary lengths
>     (e.g. the 60-byte NIST test vectors).
> 
> So reusing the common methods means relaxing those two checks for GCM,
> e.g.:
>   /* qcrypto_gcrypt_setiv() */
>   if (cipher->mode != QCRYPTO_CIPHER_MODE_GCM && niv != ctx->blocksize) {
>       error_setg(errp, "Expected IV size %zu not %zu", ctx->blocksize, niv);
>       return -1;
>   }
>   /* qcrypto_gcrypt_encrypt() / _decrypt() */
>   if (cipher->mode != QCRYPTO_CIPHER_MODE_GCM &&
>       (len & (ctx->blocksize - 1))) {
>       error_setg(errp, "Length %zu must be a multiple of block size %zu",
>                  len, ctx->blocksize);
>       return -1;
>   }
> 
> I kept them separate to avoid adding GCM special-cases to the shared
> block-cipher path, but I'm happy to switch the GCM driver to the common
> qcrypto_gcrypt_{setiv,encrypt,decrypt} (dropping the GCM-specific ones and
> keeping only the AEAD setaad/gettag hooks)
> 
> If you prefer. I'll make that change in v2 if that's the direction you'd like.

No, leave it as it is.

Reviewed-by: Daniel P. Berrangé <[email protected]>
Acked-by: Daniel P. Berrangé <[email protected]>




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 :|


Reply via email to