Add new control GCRYCTL_GET_TAGLEN for use with gcry_cipher_info.
authorWerner Koch <wk@gnupg.org>
Wed, 23 Mar 2016 14:24:40 +0000 (15:24 +0100)
committerWerner Koch <wk@gnupg.org>
Wed, 23 Mar 2016 14:24:40 +0000 (15:24 +0100)
* 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 <wk@gnupg.org>
NEWS
cipher/cipher.c
doc/gcrypt.texi
src/gcrypt.h.in
tests/basic.c

diff --git a/NEWS b/NEWS
index 0064bbe..9cb5e36 100644 (file)
--- 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.
 
index 3a8597f..bdcbfbd 100644 (file)
@@ -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;
     }
index 3265a70..8451627 100644 (file)
@@ -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
index 797da2e..c269621 100644 (file)
@@ -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. */
index c633ae9..36a83d0 100644 (file)
@@ -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);