crypto/cipher-gcrypt: Implement AES-GCM
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 <jamin_lin@aspeedtech.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Acked-by: Daniel P. Berrangé <berrange@redhat.com> Link: https://lore.kernel.org/qemu-devel/20260811060115.1849266-10-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
Jamin Lin committed
Aug 11, 2026 at 06:01 UTC
1429ef61c89672ef8c8eb3241c22ba46390b9003
1 file changed
+101
crypto/cipher-gcrypt.c.inc
+101
@@ -65,6 +65,8 @@ static int qcrypto_cipher_mode_to_gcry_mode(QCryptoCipherMode mode)
65
return GCRY_CIPHER_MODE_CBC;
66
case QCRYPTO_CIPHER_MODE_CTR:
67
return GCRY_CIPHER_MODE_CTR;
68
+ case QCRYPTO_CIPHER_MODE_GCM:
69
+ return GCRY_CIPHER_MODE_GCM;
70
default:
71
return GCRY_CIPHER_MODE_NONE;
72
}
@@ -104,6 +106,10 @@ bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
106
case QCRYPTO_CIPHER_MODE_XTS:
107
case QCRYPTO_CIPHER_MODE_CTR:
108
return true;
109
+ case QCRYPTO_CIPHER_MODE_GCM:
110
+ /* GCM requires a 128-bit block cipher. */
111
+ return gcry_cipher_get_algo_blklen(
112
+ qcrypto_cipher_alg_to_gcry_alg(alg)) == 16;
113
default:
114
return false;
115
}
@@ -228,6 +234,99 @@ static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
234
.cipher_free = qcrypto_gcrypt_ctx_free,
235
};
236
237
+/*
238
+ * GCM is an AEAD stream mode: the IV/nonce need not match the block size,
239
+ * the message length need not be a multiple of the block size, associated
240
+ * data is fed with gcry_cipher_authenticate() and the authentication tag is
241
+ * read back with gcry_cipher_gettag().
242
+ */
243
+static int qcrypto_gcrypt_gcm_setiv(QCryptoCipher *cipher,
244
+ const uint8_t *iv, size_t niv,
245
+ Error **errp)
246
+{
247
+ QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
248
+ gcry_error_t err;
249
+
250
+ gcry_cipher_reset(ctx->handle);
251
+ err = gcry_cipher_setiv(ctx->handle, iv, niv);
252
+ if (err != 0) {
253
+ error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
254
+ return -1;
255
+ }
256
+
257
+ return 0;
258
+}
259
+
260
+static int qcrypto_gcrypt_gcm_setaad(QCryptoCipher *cipher,
261
+ const uint8_t *aad, size_t len,
262
+ Error **errp)
263
+{
264
+ QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
265
+ gcry_error_t err;
266
+
267
+ err = gcry_cipher_authenticate(ctx->handle, aad, len);
268
+ if (err != 0) {
269
+ error_setg(errp, "Cannot set AAD: %s", gcry_strerror(err));
270
+ return -1;
271
+ }
272
+
273
+ return 0;
274
+}
275
+
276
+static int qcrypto_gcrypt_gcm_encrypt(QCryptoCipher *cipher, const void *in,
277
+ void *out, size_t len, Error **errp)
278
+{
279
+ QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
280
+ gcry_error_t err;
281
+
282
+ err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
283
+ if (err != 0) {
284
+ error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
285
+ return -1;
286
+ }
287
+
288
+ return 0;
289
+}
290
+
291
+static int qcrypto_gcrypt_gcm_decrypt(QCryptoCipher *cipher, const void *in,
292
+ void *out, size_t len, Error **errp)
293
+{
294
+ QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
295
+ gcry_error_t err;
296
+
297
+ err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
298
+ if (err != 0) {
299
+ error_setg(errp, "Cannot decrypt data: %s", gcry_strerror(err));
300
+ return -1;
301
+ }
302
+
303
+ return 0;
304
+}
305
+
306
+static int qcrypto_gcrypt_gcm_gettag(QCryptoCipher *cipher,
307
+ uint8_t *tag, size_t len, Error **errp)
308
+{
309
+ QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
310
+ gcry_error_t err;
311
+
312
+ err = gcry_cipher_gettag(ctx->handle, tag, len);
313
+ if (err != 0) {
314
+ error_setg(errp, "Cannot get tag: %s", gcry_strerror(err));
315
+ return -1;
316
+ }
317
+
318
+ return 0;
319
+}
320
+
321
+static const struct QCryptoCipherDriver qcrypto_gcrypt_gcm_driver = {
322
+ .cipher_encrypt = qcrypto_gcrypt_gcm_encrypt,
323
+ .cipher_decrypt = qcrypto_gcrypt_gcm_decrypt,
324
+ .cipher_setiv = qcrypto_gcrypt_gcm_setiv,
325
+ .cipher_setaad = qcrypto_gcrypt_gcm_setaad,
326
+ .cipher_gettag = qcrypto_gcrypt_gcm_gettag,
327
+ .cipher_free = qcrypto_gcrypt_ctx_free,
328
+};
329
+
330
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
331
QCryptoCipherMode mode,
332
const uint8_t *key,
@@ -259,6 +358,8 @@ static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
358
359
if (mode == QCRYPTO_CIPHER_MODE_CTR) {
360
drv = &qcrypto_gcrypt_ctr_driver;
361
+ } else if (mode == QCRYPTO_CIPHER_MODE_GCM) {
362
+ drv = &qcrypto_gcrypt_gcm_driver;
363
} else {
364
drv = &qcrypto_gcrypt_driver;
365
}