summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--cipher/cipher.c51
-rw-r--r--doc/gcrypt.texi16
-rw-r--r--src/gcrypt.h.in5
-rw-r--r--tests/basic.c95
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);