Page MenuHome GnuPG

libgcrypt: New functions to support waiting time
Open, WishlistPublic

Description

Let me add utility functions to wait, so that those can be used in an application which wants to hide timing information.

Event Timeline

gniibe triaged this task as Wishlist priority.Apr 12 2024, 5:04 AM
gniibe created this task.

I mean, something like this (for GNU/Linux):

diff --git a/src/misc.c b/src/misc.c
index 4db2d9a4..74864334 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -577,3 +577,80 @@ _gcry_divide_by_zero (void)
     gpg_err_set_errno (EDOM);
     _gcry_fatal_error (gpg_err_code_from_errno (errno), "divide by zero");
 }
+
+#ifdef HAVE_CLOCK_GETTIME
+#include <time.h>
+# if defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCK_TAI)
+struct gcry_timedwait
+{
+  struct timespec ts;
+};
+
+typedef struct gcry_timedwait *gcry_timedwait_t;
+
+gcry_err_code_t
+_gcry_timedwait_new (gcry_timedwait_t *r_tw, unsigned int flags)
+{
+  gcry_err_code_t err;
+  gcry_timedwait_t tw;
+
+  *r_tw = NULL;
+
+  /* Possibly, it would be good to be able to select the wall clock.
+   * For now, it's CPU time by the thread.  */
+  if (flags != 0)
+    return GPG_ERR_INV_ARG;
+
+  tw = xtrymalloc (sizeof (gcry_timedwait_t));
+  if (!tw)
+    return gpg_err_code_from_syserror ();
+
+  if (clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tw->ts) < 0)
+    {
+      err = gpg_err_code_from_syserror ();
+      xfree (tw);
+      return err;
+    }
+
+  *r_tw = tw;
+  return 0;
+}
+
+gcry_err_code_t
+_gcry_timedwait_release (gcry_timedwait_t tw, struct timespec ts_r)
+{
+  gcry_err_code_t err;
+  struct timespec ts;
+  u32 negative;
+
+  if (clock_gettime (CLOCK_THREAD_CPUTIME_ID, &ts) < 0)
+    {
+      err = gpg_err_code_from_syserror ();
+      xfree (tw);
+      return err;
+    }
+
+  ts.tv_sec -= tw->ts.tv_sec;
+  ts.tv_nsec -= tw->ts.tv_nsec;
+  negative = ((u32)ts.tv_nsec) >> 31;
+  ts.tv_sec -= negative;
+  ts.tv_nsec += (1000000000 * negative);
+
+  xfree (tw);
+
+  ts_r.tv_sec -= ts.tv_sec;
+  ts_r.tv_nsec -= ts.tv_nsec;
+  negative = ((u32)ts_r.tv_nsec) >> 31;
+  ts_r.tv_sec -= negative;
+  ts_r.tv_nsec += (1000000000 * negative);
+
+  if (ts_r.tv_sec < 0)
+    return GPG_ERR_TIME_CONFLICT;
+
+  if (clock_nanosleep (CLOCK_TAI, 0, &ts_r, &ts_r))
+    return gpg_err_code_from_syserror ();
+
+  return 0;
+}
+# endif
+#endif

Intended scenario is:

  • gcry_timedwait_new
  • some non-constant time computation
  • gcry_timedwait_release specifying relative timespec

API which does not require allocation internally would be better. In this case, it is allocated on stack by the caller.

Here is current version:

diff --git a/src/misc.c b/src/misc.c
index 4db2d9a4..bf50b00b 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -577,3 +577,61 @@ _gcry_divide_by_zero (void)
     gpg_err_set_errno (EDOM);
     _gcry_fatal_error (gpg_err_code_from_errno (errno), "divide by zero");
 }
+
+#ifdef HAVE_CLOCK_GETTIME
+#include <time.h>
+# if defined(CLOCK_THREAD_CPUTIME_ID) && defined(CLOCK_TAI)
+struct gcry_timedwait
+{
+  clockid_t id;
+  struct timespec ts;
+};
+
+typedef struct gcry_timedwait *gcry_timedwait_t;
+
+gcry_err_code_t
+_gcry_timedwait_init (gcry_timedwait_t tw, unsigned int flags)
+{
+  /* Possibly, it would be good to be able to select the wall clock.
+   * For now, it's CPU time by the thread.  */
+  if (flags != 0)
+    return GPG_ERR_INV_ARG;
+
+  tw->id = CLOCK_THREAD_CPUTIME_ID;
+  if (clock_gettime (tw->id, &tw->ts) < 0)
+    return gpg_err_code_from_syserror ();
+
+  return 0;
+}
+
+gcry_err_code_t
+_gcry_timedwait_finish (gcry_timedwait_t tw, struct timespec ts_r)
+{
+  struct timespec ts;
+  u32 negative;
+
+  if (clock_gettime (tw->id, &ts) < 0)
+    return gpg_err_code_from_syserror ();
+
+  ts.tv_sec -= tw->ts.tv_sec;
+  ts.tv_nsec -= tw->ts.tv_nsec;
+  negative = ((u32)ts.tv_nsec) >> 31;
+  ts.tv_sec -= negative;
+  ts.tv_nsec += (1000000000 * negative);
+
+  ts_r.tv_sec -= ts.tv_sec;
+  ts_r.tv_nsec -= ts.tv_nsec;
+  negative = ((u32)ts_r.tv_nsec) >> 31;
+  ts_r.tv_sec -= negative;
+  ts_r.tv_nsec += (1000000000 * negative);
+
+  if (ts_r.tv_sec < 0)
+    return GPG_ERR_TIME_CONFLICT;
+
+  if (clock_nanosleep (CLOCK_TAI, 0, &ts_r, &ts_r))
+    return gpg_err_code_from_syserror ();
+
+  return 0;
+}
+# endif
+#endif