From fea5971488e049f902d7912df22a945bc755ad6d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 23 Mar 2016 15:24:40 +0100 Subject: Add new control GCRYCTL_GET_TAGLEN for use with gcry_cipher_info. * src/gcrypt.h.in (GCRYCTL_GET_TAGLEN): New. * cipher/cipher.c (_gcry_cipher_info): Add GCRYCTL_GET_TAGLEN feature. * tests/basic.c (_check_gcm_cipher): Check that new feature. (_check_poly1305_cipher): Ditto. (check_ccm_cipher): Ditto. (do_check_ocb_cipher): Ditto. (check_ctr_cipher): Add negative test for new feature. -- Signed-off-by: Werner Koch --- NEWS | 1 + cipher/cipher.c | 51 +++++++++++++++++++++++++------ doc/gcrypt.texi | 16 ++++++++-- src/gcrypt.h.in | 5 +-- tests/basic.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 151 insertions(+), 17 deletions(-) diff --git a/NEWS b/NEWS index 0064bbee..9cb5e36d 100644 --- a/NEWS +++ b/NEWS @@ -69,6 +69,7 @@ Noteworthy changes in version 1.7.0 (unreleased) GCRY_CIPHER_MODE_POLY1305 NEW. GCRY_CIPHER_MODE_OCB NEW. GCRYCTL_SET_TAGLEN NEW. + GCRYCTL_GET_TAGLEN NEW. gcry_cipher_final NEW macro. GCRY_PK_EDDSA NEW constant. diff --git a/cipher/cipher.c b/cipher/cipher.c index 3a8597f5..bdcbfbd7 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -1361,24 +1361,55 @@ _gcry_cipher_ctl (gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen) /* Return information about the cipher handle H. CMD is the kind of - information requested. BUFFER and NBYTES are reserved for now. - - There are no values for CMD yet defined. - - The function always returns GPG_ERR_INV_OP. - + * information requested. + * + * CMD may be one of: + * + * GCRYCTL_GET_TAGLEN: + * Return the length of the tag for an AE algorithm mode. An + * error is returned for modes which do not support a tag. + * BUFFER must be given as NULL. On success the result is stored + * at NBYTES. The taglen is returned in bytes. + * + * The function returns 0 on success or an error code. */ gcry_err_code_t _gcry_cipher_info (gcry_cipher_hd_t h, int cmd, void *buffer, size_t *nbytes) { gcry_err_code_t rc = 0; - (void)h; - (void)buffer; - (void)nbytes; - switch (cmd) { + case GCRYCTL_GET_TAGLEN: + if (!h || buffer || !nbytes) + rc = GPG_ERR_INV_ARG; + else + { + switch (h->mode) + { + case GCRY_CIPHER_MODE_OCB: + *nbytes = h->u_mode.ocb.taglen; + break; + + case GCRY_CIPHER_MODE_CCM: + *nbytes = h->u_mode.ccm.authlen; + break; + + case GCRY_CIPHER_MODE_GCM: + *nbytes = GCRY_GCM_BLOCK_LEN; + break; + + case GCRY_CIPHER_MODE_POLY1305: + *nbytes = POLY1305_TAGLEN; + break; + + default: + rc = GPG_ERR_INV_CIPHER_MODE; + break; + } + } + break; + default: rc = GPG_ERR_INV_OP; } diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 3265a706..84516279 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -1900,12 +1900,24 @@ handle @var{h}. Please see the comments in the source code (@code{src/global.c}) for details. @end deftypefun -@deftypefun gcry_error_t gcry_cipher_info (gcry_cipher_hd_t @var{h}, int @var{what}, void *@var{buffer}, size_t *@var{nbytes}) +@deftypefun gcry_error_t gcry_cipher_info (gcry_cipher_hd_t @var{h}, @ + int @var{what}, void *@var{buffer}, size_t *@var{nbytes}) @code{gcry_cipher_info} is used to retrieve various information about a cipher context or the cipher module in general. -Currently no information is available. +@c begin constants for gcry_cipher_info +@table @code + +@item GCRYCTL_GET_TAGLEN: +Return the length of the tag for an AE algorithm mode. An error is +returned for modes which do not support a tag. @var{buffer} must be +given as NULL. On success the result is stored @var{nbytes}. The +taglen is returned in bytes. + +@end table +@c end constants for gcry_cipher_info + @end deftypefun @node General cipher functions diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in index 797da2e2..c2696212 100644 --- a/src/gcrypt.h.in +++ b/src/gcrypt.h.in @@ -332,7 +332,8 @@ enum gcry_ctl_cmds GCRYCTL_REACTIVATE_FIPS_FLAG = 72, GCRYCTL_SET_SBOX = 73, GCRYCTL_DRBG_REINIT = 74, - GCRYCTL_SET_TAGLEN = 75 + GCRYCTL_SET_TAGLEN = 75, + GCRYCTL_GET_TAGLEN = 76 }; /* Perform various operations defined by CMD. */ @@ -986,7 +987,7 @@ enum gcry_cipher_flags gcry_error_t gcry_cipher_open (gcry_cipher_hd_t *handle, int algo, int mode, unsigned int flags); -/* Close the cioher handle H and release all resource. */ +/* Close the cipher handle H and release all resource. */ void gcry_cipher_close (gcry_cipher_hd_t h); /* Perform various operations on the cipher object H. */ diff --git a/tests/basic.c b/tests/basic.c index c633ae96..36a83d07 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -690,6 +690,7 @@ check_ctr_cipher (void) unsigned char out[MAX_DATA_LEN]; int i, j, keylen, blklen; gcry_error_t err = 0; + size_t taglen2; if (verbose) fprintf (stderr, " Starting CTR cipher checks.\n"); @@ -753,6 +754,17 @@ check_ctr_cipher (void) return; } + + err = gcry_cipher_info (hde, GCRYCTL_GET_TAGLEN, NULL, &taglen2); + if (gpg_err_code (err) != GPG_ERR_INV_CIPHER_MODE) + { + fail ("aes-ctr, gcryctl_get_taglen failed to fail (tv %d): %s\n", + i, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + if (verbose) fprintf (stderr, " checking CTR mode for %s [%i]\n", gcry_cipher_algo_name (tv[i].algo), @@ -1418,7 +1430,7 @@ _check_gcm_cipher (unsigned int step) unsigned char tag[GCRY_GCM_BLOCK_LEN]; int i, keylen; gcry_error_t err = 0; - size_t pos, poslen; + size_t pos, poslen, taglen2; int byteNum; if (verbose) @@ -1478,6 +1490,25 @@ _check_gcm_cipher (unsigned int step) return; } + err = gcry_cipher_info (hde, GCRYCTL_GET_TAGLEN, NULL, &taglen2); + if (err) + { + fail ("cipher-gcm, gcryctl_get_taglen failed (tv %d): %s\n", + i, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + if (taglen2 != GCRY_GCM_BLOCK_LEN) + { + fail ("cipher-gcm, gcryctl_get_taglen returned bad length" + " (tv %d): got=%zu want=%d\n", + i, taglen2, GCRY_GCM_BLOCK_LEN); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + for (pos = 0; pos < tv[i].aadlen; pos += step) { poslen = (pos + step < tv[i].aadlen) ? step : tv[i].aadlen - pos; @@ -1772,7 +1803,7 @@ _check_poly1305_cipher (unsigned int step) unsigned char tag[16]; int i, keylen; gcry_error_t err = 0; - size_t pos, poslen; + size_t pos, poslen, taglen2; int byteNum; if (verbose) @@ -1824,6 +1855,25 @@ _check_poly1305_cipher (unsigned int step) return; } + err = gcry_cipher_info (hde, GCRYCTL_GET_TAGLEN, NULL, &taglen2); + if (err) + { + fail ("cipher-poly1305, gcryctl_get_taglen failed (tv %d): %s\n", + i, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + if (taglen2 != 16) + { + fail ("cipher-poly1305, gcryctl_get_taglen returned bad length" + " (tv %d): got=%zu want=%d\n", + i, taglen2, 16); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + for (pos = 0; pos < tv[i].aadlen; pos += step) { poslen = (pos + step < tv[i].aadlen) ? step : tv[i].aadlen - pos; @@ -2446,7 +2496,7 @@ check_ccm_cipher (void) unsigned char out[MAX_DATA_LEN]; u64 ctl_params[3]; int split, aadsplit; - size_t j, i, keylen, blklen, authlen; + size_t j, i, keylen, blklen, authlen, taglen2; gcry_error_t err = 0; if (verbose) @@ -2539,6 +2589,25 @@ check_ccm_cipher (void) return; } + err = gcry_cipher_info (hde, GCRYCTL_GET_TAGLEN, NULL, &taglen2); + if (err) + { + fail ("cipher-ccm, gcryctl_get_taglen failed (tv %d): %s\n", + i, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + if (taglen2 != authlen) + { + fail ("cipher-ccm, gcryctl_get_taglen returned bad length" + " (tv %d): got=%zu want=%zu\n", + i, taglen2, authlen); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + aadsplit = split > tv[i].aadlen ? 0 : split; err = gcry_cipher_authenticate (hde, tv[i].aad, @@ -2973,6 +3042,7 @@ do_check_ocb_cipher (int inplace) char *key, *nonce, *aad, *ciph, *plain; size_t keylen, noncelen, aadlen, ciphlen, plainlen; int taglen; + size_t taglen2; if (verbose) fprintf (stderr, " checking OCB mode for %s [%i] (tv %d)\n", @@ -3030,6 +3100,25 @@ do_check_ocb_cipher (int inplace) return; } + err = gcry_cipher_info (hde, GCRYCTL_GET_TAGLEN, NULL, &taglen2); + if (err) + { + fail ("cipher-ocb, gcryctl_get_taglen failed (tv %d): %s\n", + tidx, gpg_strerror (err)); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + if (taglen2 != tv[tidx].taglen) + { + fail ("cipher-ocb, gcryctl_get_taglen returned bad length (tv %d): " + "got=%zu want=%d\n", + tidx, taglen2, tv[tidx].taglen); + gcry_cipher_close (hde); + gcry_cipher_close (hdd); + return; + } + err = gcry_cipher_setkey (hde, key, keylen); if (!err) err = gcry_cipher_setkey (hdd, key, keylen); -- cgit v1.2.1