From 0e9e7d72f3c9eb7ac832746c3034855faaf8d02c Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Tue, 19 Nov 2013 23:26:26 +0200 Subject: GCM: GHASH optimizations * cipher/cipher-gcm.c [GCM_USE_TABLES] (gcmR, ghash): Replace with new. [GCM_USE_TABLES] [GCM_TABLES_USE_U64] (bshift, fillM, do_ghash): New. [GCM_USE_TABLES] [!GCM_TABLES_USE_U64] (bshift, fillM): Replace with new. [GCM_USE_TABLES] [!GCM_TABLES_USE_U64] (do_ghash): New. (_gcry_cipher_gcm_tag): Remove extra memcpy to outbuf and use buf_eq_const for comparing authentication tag. * cipher/cipher-internal.h (gcry_cipher_handle): Different 'gcm_table' for 32-bit and 64-bit platforms. -- Patch improves GHASH speed. Intel Haswell (x86-64): Old: GCM auth | 26.22 ns/B 36.38 MiB/s 83.89 c/B New: GCM auth | 3.18 ns/B 300.0 MiB/s 10.17 c/B Intel Haswell (mingw32): Old: GCM auth | 27.27 ns/B 34.97 MiB/s 87.27 c/B New: GCM auth | 7.58 ns/B 125.7 MiB/s 24.27 c/B Cortex-A8: Old: GCM auth | 231.4 ns/B 4.12 MiB/s 233.3 c/B New: GCM auth | 30.82 ns/B 30.94 MiB/s 31.07 c/B Signed-off-by: Jussi Kivilinna --- cipher/cipher-gcm.c | 333 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 222 insertions(+), 111 deletions(-) (limited to 'cipher/cipher-gcm.c') diff --git a/cipher/cipher-gcm.c b/cipher/cipher-gcm.c index b6c50bf0..d7fc0d85 100644 --- a/cipher/cipher-gcm.c +++ b/cipher/cipher-gcm.c @@ -30,134 +30,251 @@ #include "./cipher-internal.h" #ifdef GCM_USE_TABLES -static const byte gcmR[256][2] = { - {0x00, 0x00,}, {0x01, 0xc2,}, {0x03, 0x84,}, {0x02, 0x46,}, - {0x07, 0x08,}, {0x06, 0xca,}, {0x04, 0x8c,}, {0x05, 0x4e,}, - {0x0e, 0x10,}, {0x0f, 0xd2,}, {0x0d, 0x94,}, {0x0c, 0x56,}, - {0x09, 0x18,}, {0x08, 0xda,}, {0x0a, 0x9c,}, {0x0b, 0x5e,}, - {0x1c, 0x20,}, {0x1d, 0xe2,}, {0x1f, 0xa4,}, {0x1e, 0x66,}, - {0x1b, 0x28,}, {0x1a, 0xea,}, {0x18, 0xac,}, {0x19, 0x6e,}, - {0x12, 0x30,}, {0x13, 0xf2,}, {0x11, 0xb4,}, {0x10, 0x76,}, - {0x15, 0x38,}, {0x14, 0xfa,}, {0x16, 0xbc,}, {0x17, 0x7e,}, - {0x38, 0x40,}, {0x39, 0x82,}, {0x3b, 0xc4,}, {0x3a, 0x06,}, - {0x3f, 0x48,}, {0x3e, 0x8a,}, {0x3c, 0xcc,}, {0x3d, 0x0e,}, - {0x36, 0x50,}, {0x37, 0x92,}, {0x35, 0xd4,}, {0x34, 0x16,}, - {0x31, 0x58,}, {0x30, 0x9a,}, {0x32, 0xdc,}, {0x33, 0x1e,}, - {0x24, 0x60,}, {0x25, 0xa2,}, {0x27, 0xe4,}, {0x26, 0x26,}, - {0x23, 0x68,}, {0x22, 0xaa,}, {0x20, 0xec,}, {0x21, 0x2e,}, - {0x2a, 0x70,}, {0x2b, 0xb2,}, {0x29, 0xf4,}, {0x28, 0x36,}, - {0x2d, 0x78,}, {0x2c, 0xba,}, {0x2e, 0xfc,}, {0x2f, 0x3e,}, - {0x70, 0x80,}, {0x71, 0x42,}, {0x73, 0x04,}, {0x72, 0xc6,}, - {0x77, 0x88,}, {0x76, 0x4a,}, {0x74, 0x0c,}, {0x75, 0xce,}, - {0x7e, 0x90,}, {0x7f, 0x52,}, {0x7d, 0x14,}, {0x7c, 0xd6,}, - {0x79, 0x98,}, {0x78, 0x5a,}, {0x7a, 0x1c,}, {0x7b, 0xde,}, - {0x6c, 0xa0,}, {0x6d, 0x62,}, {0x6f, 0x24,}, {0x6e, 0xe6,}, - {0x6b, 0xa8,}, {0x6a, 0x6a,}, {0x68, 0x2c,}, {0x69, 0xee,}, - {0x62, 0xb0,}, {0x63, 0x72,}, {0x61, 0x34,}, {0x60, 0xf6,}, - {0x65, 0xb8,}, {0x64, 0x7a,}, {0x66, 0x3c,}, {0x67, 0xfe,}, - {0x48, 0xc0,}, {0x49, 0x02,}, {0x4b, 0x44,}, {0x4a, 0x86,}, - {0x4f, 0xc8,}, {0x4e, 0x0a,}, {0x4c, 0x4c,}, {0x4d, 0x8e,}, - {0x46, 0xd0,}, {0x47, 0x12,}, {0x45, 0x54,}, {0x44, 0x96,}, - {0x41, 0xd8,}, {0x40, 0x1a,}, {0x42, 0x5c,}, {0x43, 0x9e,}, - {0x54, 0xe0,}, {0x55, 0x22,}, {0x57, 0x64,}, {0x56, 0xa6,}, - {0x53, 0xe8,}, {0x52, 0x2a,}, {0x50, 0x6c,}, {0x51, 0xae,}, - {0x5a, 0xf0,}, {0x5b, 0x32,}, {0x59, 0x74,}, {0x58, 0xb6,}, - {0x5d, 0xf8,}, {0x5c, 0x3a,}, {0x5e, 0x7c,}, {0x5f, 0xbe,}, - {0xe1, 0x00,}, {0xe0, 0xc2,}, {0xe2, 0x84,}, {0xe3, 0x46,}, - {0xe6, 0x08,}, {0xe7, 0xca,}, {0xe5, 0x8c,}, {0xe4, 0x4e,}, - {0xef, 0x10,}, {0xee, 0xd2,}, {0xec, 0x94,}, {0xed, 0x56,}, - {0xe8, 0x18,}, {0xe9, 0xda,}, {0xeb, 0x9c,}, {0xea, 0x5e,}, - {0xfd, 0x20,}, {0xfc, 0xe2,}, {0xfe, 0xa4,}, {0xff, 0x66,}, - {0xfa, 0x28,}, {0xfb, 0xea,}, {0xf9, 0xac,}, {0xf8, 0x6e,}, - {0xf3, 0x30,}, {0xf2, 0xf2,}, {0xf0, 0xb4,}, {0xf1, 0x76,}, - {0xf4, 0x38,}, {0xf5, 0xfa,}, {0xf7, 0xbc,}, {0xf6, 0x7e,}, - {0xd9, 0x40,}, {0xd8, 0x82,}, {0xda, 0xc4,}, {0xdb, 0x06,}, - {0xde, 0x48,}, {0xdf, 0x8a,}, {0xdd, 0xcc,}, {0xdc, 0x0e,}, - {0xd7, 0x50,}, {0xd6, 0x92,}, {0xd4, 0xd4,}, {0xd5, 0x16,}, - {0xd0, 0x58,}, {0xd1, 0x9a,}, {0xd3, 0xdc,}, {0xd2, 0x1e,}, - {0xc5, 0x60,}, {0xc4, 0xa2,}, {0xc6, 0xe4,}, {0xc7, 0x26,}, - {0xc2, 0x68,}, {0xc3, 0xaa,}, {0xc1, 0xec,}, {0xc0, 0x2e,}, - {0xcb, 0x70,}, {0xca, 0xb2,}, {0xc8, 0xf4,}, {0xc9, 0x36,}, - {0xcc, 0x78,}, {0xcd, 0xba,}, {0xcf, 0xfc,}, {0xce, 0x3e,}, - {0x91, 0x80,}, {0x90, 0x42,}, {0x92, 0x04,}, {0x93, 0xc6,}, - {0x96, 0x88,}, {0x97, 0x4a,}, {0x95, 0x0c,}, {0x94, 0xce,}, - {0x9f, 0x90,}, {0x9e, 0x52,}, {0x9c, 0x14,}, {0x9d, 0xd6,}, - {0x98, 0x98,}, {0x99, 0x5a,}, {0x9b, 0x1c,}, {0x9a, 0xde,}, - {0x8d, 0xa0,}, {0x8c, 0x62,}, {0x8e, 0x24,}, {0x8f, 0xe6,}, - {0x8a, 0xa8,}, {0x8b, 0x6a,}, {0x89, 0x2c,}, {0x88, 0xee,}, - {0x83, 0xb0,}, {0x82, 0x72,}, {0x80, 0x34,}, {0x81, 0xf6,}, - {0x84, 0xb8,}, {0x85, 0x7a,}, {0x87, 0x3c,}, {0x86, 0xfe,}, - {0xa9, 0xc0,}, {0xa8, 0x02,}, {0xaa, 0x44,}, {0xab, 0x86,}, - {0xae, 0xc8,}, {0xaf, 0x0a,}, {0xad, 0x4c,}, {0xac, 0x8e,}, - {0xa7, 0xd0,}, {0xa6, 0x12,}, {0xa4, 0x54,}, {0xa5, 0x96,}, - {0xa0, 0xd8,}, {0xa1, 0x1a,}, {0xa3, 0x5c,}, {0xa2, 0x9e,}, - {0xb5, 0xe0,}, {0xb4, 0x22,}, {0xb6, 0x64,}, {0xb7, 0xa6,}, - {0xb2, 0xe8,}, {0xb3, 0x2a,}, {0xb1, 0x6c,}, {0xb0, 0xae,}, - {0xbb, 0xf0,}, {0xba, 0x32,}, {0xb8, 0x74,}, {0xb9, 0xb6,}, - {0xbc, 0xf8,}, {0xbd, 0x3a,}, {0xbf, 0x7c,}, {0xbe, 0xbe,}, +static const u16 gcmR[256] = { + 0x0000, 0x01c2, 0x0384, 0x0246, 0x0708, 0x06ca, 0x048c, 0x054e, + 0x0e10, 0x0fd2, 0x0d94, 0x0c56, 0x0918, 0x08da, 0x0a9c, 0x0b5e, + 0x1c20, 0x1de2, 0x1fa4, 0x1e66, 0x1b28, 0x1aea, 0x18ac, 0x196e, + 0x1230, 0x13f2, 0x11b4, 0x1076, 0x1538, 0x14fa, 0x16bc, 0x177e, + 0x3840, 0x3982, 0x3bc4, 0x3a06, 0x3f48, 0x3e8a, 0x3ccc, 0x3d0e, + 0x3650, 0x3792, 0x35d4, 0x3416, 0x3158, 0x309a, 0x32dc, 0x331e, + 0x2460, 0x25a2, 0x27e4, 0x2626, 0x2368, 0x22aa, 0x20ec, 0x212e, + 0x2a70, 0x2bb2, 0x29f4, 0x2836, 0x2d78, 0x2cba, 0x2efc, 0x2f3e, + 0x7080, 0x7142, 0x7304, 0x72c6, 0x7788, 0x764a, 0x740c, 0x75ce, + 0x7e90, 0x7f52, 0x7d14, 0x7cd6, 0x7998, 0x785a, 0x7a1c, 0x7bde, + 0x6ca0, 0x6d62, 0x6f24, 0x6ee6, 0x6ba8, 0x6a6a, 0x682c, 0x69ee, + 0x62b0, 0x6372, 0x6134, 0x60f6, 0x65b8, 0x647a, 0x663c, 0x67fe, + 0x48c0, 0x4902, 0x4b44, 0x4a86, 0x4fc8, 0x4e0a, 0x4c4c, 0x4d8e, + 0x46d0, 0x4712, 0x4554, 0x4496, 0x41d8, 0x401a, 0x425c, 0x439e, + 0x54e0, 0x5522, 0x5764, 0x56a6, 0x53e8, 0x522a, 0x506c, 0x51ae, + 0x5af0, 0x5b32, 0x5974, 0x58b6, 0x5df8, 0x5c3a, 0x5e7c, 0x5fbe, + 0xe100, 0xe0c2, 0xe284, 0xe346, 0xe608, 0xe7ca, 0xe58c, 0xe44e, + 0xef10, 0xeed2, 0xec94, 0xed56, 0xe818, 0xe9da, 0xeb9c, 0xea5e, + 0xfd20, 0xfce2, 0xfea4, 0xff66, 0xfa28, 0xfbea, 0xf9ac, 0xf86e, + 0xf330, 0xf2f2, 0xf0b4, 0xf176, 0xf438, 0xf5fa, 0xf7bc, 0xf67e, + 0xd940, 0xd882, 0xdac4, 0xdb06, 0xde48, 0xdf8a, 0xddcc, 0xdc0e, + 0xd750, 0xd692, 0xd4d4, 0xd516, 0xd058, 0xd19a, 0xd3dc, 0xd21e, + 0xc560, 0xc4a2, 0xc6e4, 0xc726, 0xc268, 0xc3aa, 0xc1ec, 0xc02e, + 0xcb70, 0xcab2, 0xc8f4, 0xc936, 0xcc78, 0xcdba, 0xcffc, 0xce3e, + 0x9180, 0x9042, 0x9204, 0x93c6, 0x9688, 0x974a, 0x950c, 0x94ce, + 0x9f90, 0x9e52, 0x9c14, 0x9dd6, 0x9898, 0x995a, 0x9b1c, 0x9ade, + 0x8da0, 0x8c62, 0x8e24, 0x8fe6, 0x8aa8, 0x8b6a, 0x892c, 0x88ee, + 0x83b0, 0x8272, 0x8034, 0x81f6, 0x84b8, 0x857a, 0x873c, 0x86fe, + 0xa9c0, 0xa802, 0xaa44, 0xab86, 0xaec8, 0xaf0a, 0xad4c, 0xac8e, + 0xa7d0, 0xa612, 0xa454, 0xa596, 0xa0d8, 0xa11a, 0xa35c, 0xa29e, + 0xb5e0, 0xb422, 0xb664, 0xb7a6, 0xb2e8, 0xb32a, 0xb16c, 0xb0ae, + 0xbbf0, 0xba32, 0xb874, 0xb9b6, 0xbcf8, 0xbd3a, 0xbf7c, 0xbebe, }; -static unsigned -bshift (unsigned char *b) +#ifdef GCM_TABLES_USE_U64 +static void +bshift (u64 * b0, u64 * b1) +{ + u64 t[2], mask; + + t[0] = *b0; + t[1] = *b1; + mask = t[1] & 1 ? 0xe1 : 0; + mask <<= 56; + + *b1 = (t[1] >> 1) ^ (t[0] << 63); + *b0 = (t[0] >> 1) ^ mask; +} + +static void +fillM (unsigned char *h, u64 * M) +{ + int i, j; + + M[0 + 0] = 0; + M[0 + 16] = 0; + + M[8 + 0] = buf_get_be64 (h + 0); + M[8 + 16] = buf_get_be64 (h + 8); + + for (i = 4; i > 0; i /= 2) + { + M[i + 0] = M[2 * i + 0]; + M[i + 16] = M[2 * i + 16]; + + bshift (&M[i], &M[i + 16]); + } + + for (i = 2; i < 16; i *= 2) + for (j = 1; j < i; j++) + { + M[(i + j) + 0] = M[i + 0] ^ M[j + 0]; + M[(i + j) + 16] = M[i + 16] ^ M[j + 16]; + } +} + +static void +do_ghash (unsigned char *result, const unsigned char *buf, const u64 * gcmM) { - unsigned char c; + u64 V[2]; + u64 tmp[2]; + const u64 *M; + u64 T; + u32 A; int i; - c = b[15] & 1; - for (i = 15; i > 0; i--) + + buf_xor (V, result, buf, 16); + V[0] = be_bswap64 (V[0]); + V[1] = be_bswap64 (V[1]); + + /* First round can be manually tweaked based on fact that 'tmp' is zero. */ + i = 15; + + M = &gcmM[(V[1] & 0xf)]; + V[1] >>= 4; + tmp[0] = (M[0] >> 4) ^ ((u64) gcmR[(M[16] & 0xf) << 4] << 48); + tmp[1] = (M[16] >> 4) ^ (M[0] << 60); + tmp[0] ^= gcmM[(V[1] & 0xf) + 0]; + tmp[1] ^= gcmM[(V[1] & 0xf) + 16]; + V[1] >>= 4; + + --i; + while (1) { - b[i] = (b[i] >> 1) | (b[i - 1] << 7); + M = &gcmM[(V[1] & 0xf)]; + V[1] >>= 4; + + A = tmp[1] & 0xff; + T = tmp[0]; + tmp[0] = (T >> 8) ^ ((u64) gcmR[A] << 48) ^ gcmM[(V[1] & 0xf) + 0]; + tmp[1] = (T << 56) ^ (tmp[1] >> 8) ^ gcmM[(V[1] & 0xf) + 16]; + + tmp[0] ^= (M[0] >> 4) ^ ((u64) gcmR[(M[16] & 0xf) << 4] << 48); + tmp[1] ^= (M[16] >> 4) ^ (M[0] << 60); + + if (i == 0) + break; + else if (i == 8) + V[1] = V[0]; + else + V[1] >>= 4; + --i; } - b[i] >>= 1; - return c; + + buf_put_be64 (result + 0, tmp[0]); + buf_put_be64 (result + 8, tmp[1]); +} + +#else + +static void +bshift (u32 * M, int i) +{ + u32 t[4], mask; + + t[0] = M[i * 4 + 0]; + t[1] = M[i * 4 + 1]; + t[2] = M[i * 4 + 2]; + t[3] = M[i * 4 + 3]; + mask = t[3] & 1 ? 0xe1 : 0; + + M[i * 4 + 3] = (t[3] >> 1) ^ (t[2] << 31); + M[i * 4 + 2] = (t[2] >> 1) ^ (t[1] << 31); + M[i * 4 + 1] = (t[1] >> 1) ^ (t[0] << 31); + M[i * 4 + 0] = (t[0] >> 1) ^ (mask << 24); } static void -fillM (unsigned char *h, unsigned char *M) +fillM (unsigned char *h, u32 * M) { int i, j; - memset (&M[0 * 16], 0, 16); - memcpy (&M[8 * 16], h, 16); + + M[0 * 4 + 0] = 0; + M[0 * 4 + 1] = 0; + M[0 * 4 + 2] = 0; + M[0 * 4 + 3] = 0; + + M[8 * 4 + 0] = buf_get_be32 (h + 0); + M[8 * 4 + 1] = buf_get_be32 (h + 4); + M[8 * 4 + 2] = buf_get_be32 (h + 8); + M[8 * 4 + 3] = buf_get_be32 (h + 12); + for (i = 4; i > 0; i /= 2) { - memcpy (&M[i * 16], &M[2 * i * 16], 16); - if (bshift (&M[i * 16])) - M[i * 16 + 0] ^= 0xe1; + M[i * 4 + 0] = M[2 * i * 4 + 0]; + M[i * 4 + 1] = M[2 * i * 4 + 1]; + M[i * 4 + 2] = M[2 * i * 4 + 2]; + M[i * 4 + 3] = M[2 * i * 4 + 3]; + + bshift (M, i); } + for (i = 2; i < 16; i *= 2) for (j = 1; j < i; j++) - buf_xor (&M[(i + j) * 16], &M[i * 16], &M[j * 16], 16); + { + M[(i + j) * 4 + 0] = M[i * 4 + 0] ^ M[j * 4 + 0]; + M[(i + j) * 4 + 1] = M[i * 4 + 1] ^ M[j * 4 + 1]; + M[(i + j) * 4 + 2] = M[i * 4 + 2] ^ M[j * 4 + 2]; + M[(i + j) * 4 + 3] = M[i * 4 + 3] ^ M[j * 4 + 3]; + } } static void -ghash (unsigned char *result, const unsigned char *buf, - const unsigned char *gcmM) +do_ghash (unsigned char *result, const unsigned char *buf, const u32 * gcmM) { - unsigned char V[16]; + byte V[16]; + u32 tmp[4]; + u32 v; + const u32 *M, *m; + u32 T[3]; int i; - buf_xor (V, result, buf, 16); + buf_xor (V, result, buf, 16); /* V is big-endian */ + + /* First round can be manually tweaked based on fact that 'tmp' is zero. */ + i = 15; - memset (result, 0, 16); + v = V[i]; + M = &gcmM[(v & 0xf) * 4]; + v = (v & 0xf0) >> 4; + m = &gcmM[v * 4]; + v = V[--i]; - for (i = 15; i >= 0; i--) + tmp[0] = (M[0] >> 4) ^ ((u64) gcmR[(M[3] << 4) & 0xf0] << 16) ^ m[0]; + tmp[1] = (M[1] >> 4) ^ (M[0] << 28) ^ m[1]; + tmp[2] = (M[2] >> 4) ^ (M[1] << 28) ^ m[2]; + tmp[3] = (M[3] >> 4) ^ (M[2] << 28) ^ m[3]; + + while (1) { - byte A = result[15]; - byte T[16]; - int j; - const byte *M = &gcmM[(V[i] & 0xf) * 16]; - - memmove (result + 1, result, 15); - result[0] = gcmR[A][0]; - result[1] ^= gcmR[A][1]; - - T[0] = M[0] >> 4; - for (j = 1; j < 16; j++) - T[j] = (M[j] >> 4) | (M[j - 1] << 4); - T[0] ^= gcmR[(M[15] & 0xf) << 4][0]; - T[1] ^= gcmR[(M[15] & 0xf) << 4][1]; - buf_xor (T, T, &gcmM[(V[i] >> 4) * 16], 16); - buf_xor (result, result, T, 16); + M = &gcmM[(v & 0xf) * 4]; + v = (v & 0xf0) >> 4; + m = &gcmM[v * 4]; + + T[0] = tmp[0]; + T[1] = tmp[1]; + T[2] = tmp[2]; + tmp[0] = (T[0] >> 8) ^ ((u32) gcmR[tmp[3] & 0xff] << 16) ^ m[0]; + tmp[1] = (T[0] << 24) ^ (tmp[1] >> 8) ^ m[1]; + tmp[2] = (T[1] << 24) ^ (tmp[2] >> 8) ^ m[2]; + tmp[3] = (T[2] << 24) ^ (tmp[3] >> 8) ^ m[3]; + + tmp[0] ^= (M[0] >> 4) ^ ((u64) gcmR[(M[3] << 4) & 0xf0] << 16); + tmp[1] ^= (M[1] >> 4) ^ (M[0] << 28); + tmp[2] ^= (M[2] >> 4) ^ (M[1] << 28); + tmp[3] ^= (M[3] >> 4) ^ (M[2] << 28); + + if (i == 0) + break; + + v = V[--i]; } + + buf_put_be32 (result + 0, tmp[0]); + buf_put_be32 (result + 4, tmp[1]); + buf_put_be32 (result + 8, tmp[2]); + buf_put_be32 (result + 12, tmp[3]); +} +#endif + +static void +ghash (unsigned char *result, const unsigned char *buf, const void *gcmM) +{ + do_ghash (result, buf, gcmM); } #define GHASH(c, result, buf) ghash (result, buf, c->gcm_table); @@ -447,7 +564,7 @@ _gcry_cipher_gcm_tag (gcry_cipher_hd_t c, buf_xor (c->u_tag.tag, c->lastiv, c->u_tag.tag, 16); c->marks.tag = 1; } - memcpy (outbuf, c->u_tag.tag, 16); + if (!check) { memcpy (outbuf, c->u_tag.tag, outbuflen); @@ -455,13 +572,8 @@ _gcry_cipher_gcm_tag (gcry_cipher_hd_t c, } else { - int diff, i; - - /* Constant-time compare. */ - for (i = 0, diff = 0; i < outbuflen; i++) - diff -= ! !(outbuf[i] - c->u_tag.tag[i]); - - return !diff ? GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; + return buf_eq_const(outbuf, c->u_tag.tag, outbuflen) ? + GPG_ERR_NO_ERROR : GPG_ERR_CHECKSUM; } return 0; @@ -474,7 +586,6 @@ _gcry_cipher_gcm_get_tag (gcry_cipher_hd_t c, unsigned char *outtag, return _gcry_cipher_gcm_tag (c, outtag, taglen, 0); } - gcry_err_code_t _gcry_cipher_gcm_check_tag (gcry_cipher_hd_t c, const unsigned char *intag, size_t taglen) -- cgit v1.2.1