tests: Add option to time the S2K function.
[libgcrypt.git] / tests / t-kdf.c
index 06c0026..18c8357 100644 (file)
@@ -27,7 +27,9 @@
 #include <stdarg.h>
 #include <assert.h>
 
-#include "../src/gcrypt.h"
+#include "../src/gcrypt-int.h"
+#include "stopwatch.h"
+
 
 #ifndef DIM
 # define DIM(v)                     (sizeof(v)/sizeof((v)[0]))
@@ -35,6 +37,7 @@
 
 /* Program option flags.  */
 static int verbose;
+static int debug;
 static int error_count;
 
 static void
@@ -61,6 +64,58 @@ die (const char *format, ...)
 
 
 static void
+dummy_consumer (volatile char *buffer, size_t buflen)
+{
+  (void)buffer;
+  (void)buflen;
+}
+
+
+static void
+bench_s2k (unsigned long s2kcount)
+{
+  gpg_error_t err;
+  const char passphrase[] = "123456789abcdef0";
+  char keybuf[128/8];
+  unsigned int repetitions = 10;
+  unsigned int count;
+  const char *elapsed;
+  int pass = 0;
+
+ again:
+  start_timer ();
+  for (count = 0; count < repetitions; count++)
+    {
+      err = gcry_kdf_derive (passphrase, strlen (passphrase),
+                             GCRY_KDF_ITERSALTED_S2K,
+                             GCRY_MD_SHA1, "saltsalt", 8, s2kcount,
+                             sizeof keybuf, keybuf);
+      if (err)
+        die ("gcry_kdf_derive failed: %s\n", gpg_strerror (err));
+      dummy_consumer (keybuf, sizeof keybuf);
+    }
+  stop_timer ();
+
+  elapsed = elapsed_time (repetitions);
+  if (!pass++)
+    {
+      if (!atoi (elapsed))
+        {
+          repetitions = 10000;
+          goto again;
+        }
+      else if (atoi (elapsed) < 10)
+        {
+          repetitions = 100;
+          goto again;
+        }
+    }
+
+  printf ("%s\n", elapsed);
+}
+
+
+static void
 check_openpgp (void)
 {
   /* Test vectors manually created with gpg 1.4 derived code: In
@@ -863,6 +918,7 @@ check_pbkdf2 (void)
     size_t plen;     /* Length of P. */
     const char *salt;
     size_t saltlen;
+    int hashalgo;
     unsigned long c; /* Iterations.  */
     int dklen;       /* Requested key length.  */
     const char *dk;  /* Derived key.  */
@@ -871,6 +927,7 @@ check_pbkdf2 (void)
     {
       "password", 8,
       "salt", 4,
+      GCRY_MD_SHA1,
       1,
       20,
       "\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9"
@@ -879,6 +936,7 @@ check_pbkdf2 (void)
     {
       "password", 8,
       "salt", 4,
+      GCRY_MD_SHA1,
       2,
       20,
       "\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e"
@@ -887,6 +945,7 @@ check_pbkdf2 (void)
     {
       "password", 8,
       "salt", 4,
+      GCRY_MD_SHA1,
       4096,
       20,
       "\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad"
@@ -895,6 +954,7 @@ check_pbkdf2 (void)
     {
       "password", 8,
       "salt", 4,
+      GCRY_MD_SHA1,
       16777216,
       20,
       "\xee\xfe\x3d\x61\xcd\x4d\xa4\xe4\xe9\x94"
@@ -904,6 +964,7 @@ check_pbkdf2 (void)
     {
       "passwordPASSWORDpassword", 24,
       "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
+      GCRY_MD_SHA1,
       4096,
       25,
       "\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8"
@@ -913,6 +974,7 @@ check_pbkdf2 (void)
     {
       "pass\0word", 9,
       "sa\0lt", 5,
+      GCRY_MD_SHA1,
       4096,
       16,
       "\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37"
@@ -921,15 +983,71 @@ check_pbkdf2 (void)
     { /* empty password test, not in RFC-6070 */
       "", 0,
       "salt", 4,
+      GCRY_MD_SHA1,
       2,
       20,
       "\x13\x3a\x4c\xe8\x37\xb4\xd2\x52\x1e\xe2"
       "\xbf\x03\xe1\x1c\x71\xca\x79\x4e\x07\x97"
     },
+    {
+      "password", 8,
+      "salt", 4,
+      GCRY_MD_GOSTR3411_CP,
+      1,
+      32,
+      "\x73\x14\xe7\xc0\x4f\xb2\xe6\x62\xc5\x43\x67\x42\x53\xf6\x8b\xd0"
+      "\xb7\x34\x45\xd0\x7f\x24\x1b\xed\x87\x28\x82\xda\x21\x66\x2d\x58"
+    },
+    {
+      "password", 8,
+      "salt", 4,
+      GCRY_MD_GOSTR3411_CP,
+      2,
+      32,
+      "\x99\x0d\xfa\x2b\xd9\x65\x63\x9b\xa4\x8b\x07\xb7\x92\x77\x5d\xf7"
+      "\x9f\x2d\xb3\x4f\xef\x25\xf2\x74\x37\x88\x72\xfe\xd7\xed\x1b\xb3"
+    },
+    {
+      "password", 8,
+      "salt", 4,
+      GCRY_MD_GOSTR3411_CP,
+      4096,
+      32,
+      "\x1f\x18\x29\xa9\x4b\xdf\xf5\xbe\x10\xd0\xae\xb3\x6a\xf4\x98\xe7"
+      "\xa9\x74\x67\xf3\xb3\x11\x16\xa5\xa7\xc1\xaf\xff\x9d\xea\xda\xfe"
+    },
+    /* { -- takes too long (4-5 min) to calculate
+      "password", 8,
+      "salt", 4,
+      GCRY_MD_GOSTR3411_CP,
+      16777216,
+      32,
+      "\xa5\x7a\xe5\xa6\x08\x83\x96\xd1\x20\x85\x0c\x5c\x09\xde\x0a\x52"
+      "\x51\x00\x93\x8a\x59\xb1\xb5\xc3\xf7\x81\x09\x10\xd0\x5f\xcd\x97"
+    }, */
+    {
+      "passwordPASSWORDpassword", 24,
+      "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36,
+      GCRY_MD_GOSTR3411_CP,
+      4096,
+      40,
+      "\x78\x83\x58\xc6\x9c\xb2\xdb\xe2\x51\xa7\xbb\x17\xd5\xf4\x24\x1f"
+      "\x26\x5a\x79\x2a\x35\xbe\xcd\xe8\xd5\x6f\x32\x6b\x49\xc8\x50\x47"
+      "\xb7\x63\x8a\xcb\x47\x64\xb1\xfd"
+    },
+    {
+      "pass\0word", 9,
+      "sa\0lt", 5,
+      GCRY_MD_GOSTR3411_CP,
+      4096,
+      20,
+      "\x43\xe0\x6c\x55\x90\xb0\x8c\x02\x25\x24"
+      "\x23\x73\x12\x7e\xdf\x9c\x8e\x9c\x32\x91"
+    }
   };
   int tvidx;
   gpg_error_t err;
-  unsigned char outbuf[32];
+  unsigned char outbuf[40];
   int i;
 
   for (tvidx=0; tvidx < DIM(tv); tvidx++)
@@ -937,10 +1055,11 @@ check_pbkdf2 (void)
       if (tv[tvidx].disabled)
         continue;
       if (verbose)
-        fprintf (stderr, "checking PBKDF2 test vector %d\n", tvidx);
+        fprintf (stderr, "checking PBKDF2 test vector %d algo %d\n", tvidx,
+                 tv[tvidx].hashalgo);
       assert (tv[tvidx].dklen <= sizeof outbuf);
       err = gcry_kdf_derive (tv[tvidx].p, tv[tvidx].plen,
-                             GCRY_KDF_PBKDF2, GCRY_MD_SHA1,
+                             GCRY_KDF_PBKDF2, tv[tvidx].hashalgo,
                              tv[tvidx].salt, tv[tvidx].saltlen,
                              tv[tvidx].c, tv[tvidx].dklen, outbuf);
       if (err)
@@ -957,15 +1076,158 @@ check_pbkdf2 (void)
 }
 
 
+static void
+check_scrypt (void)
+{
+  /* Test vectors are from draft-josefsson-scrypt-kdf-01.  */
+  static struct {
+    const char *p;        /* Passphrase.  */
+    size_t plen;          /* Length of P. */
+    const char *salt;
+    size_t saltlen;
+    int parm_n;           /* CPU/memory cost.  */
+    int parm_r;           /* blocksize */
+    unsigned long parm_p; /* parallelization. */
+    int dklen;            /* Requested key length.  */
+    const char *dk;       /* Derived key.  */
+    int disabled;
+  } tv[] = {
+    {
+      "", 0,
+      "", 0,
+      16,
+      1,
+      1,
+      64,
+      "\x77\xd6\x57\x62\x38\x65\x7b\x20\x3b\x19\xca\x42\xc1\x8a\x04\x97"
+      "\xf1\x6b\x48\x44\xe3\x07\x4a\xe8\xdf\xdf\xfa\x3f\xed\xe2\x14\x42"
+      "\xfc\xd0\x06\x9d\xed\x09\x48\xf8\x32\x6a\x75\x3a\x0f\xc8\x1f\x17"
+      "\xe8\xd3\xe0\xfb\x2e\x0d\x36\x28\xcf\x35\xe2\x0c\x38\xd1\x89\x06"
+    },
+    {
+      "password", 8,
+      "NaCl", 4,
+      1024,
+      8,
+      16,
+      64,
+      "\xfd\xba\xbe\x1c\x9d\x34\x72\x00\x78\x56\xe7\x19\x0d\x01\xe9\xfe"
+      "\x7c\x6a\xd7\xcb\xc8\x23\x78\x30\xe7\x73\x76\x63\x4b\x37\x31\x62"
+      "\x2e\xaf\x30\xd9\x2e\x22\xa3\x88\x6f\xf1\x09\x27\x9d\x98\x30\xda"
+      "\xc7\x27\xaf\xb9\x4a\x83\xee\x6d\x83\x60\xcb\xdf\xa2\xcc\x06\x40"
+    },
+    {
+      "pleaseletmein", 13,
+      "SodiumChloride", 14,
+      16384,
+      8,
+      1,
+      64,
+      "\x70\x23\xbd\xcb\x3a\xfd\x73\x48\x46\x1c\x06\xcd\x81\xfd\x38\xeb"
+      "\xfd\xa8\xfb\xba\x90\x4f\x8e\x3e\xa9\xb5\x43\xf6\x54\x5d\xa1\xf2"
+      "\xd5\x43\x29\x55\x61\x3f\x0f\xcf\x62\xd4\x97\x05\x24\x2a\x9a\xf9"
+      "\xe6\x1e\x85\xdc\x0d\x65\x1e\x40\xdf\xcf\x01\x7b\x45\x57\x58\x87"
+    },
+    {
+      "pleaseletmein", 13,
+      "SodiumChloride", 14,
+      1048576,
+      8,
+      1,
+      64,
+      "\x21\x01\xcb\x9b\x6a\x51\x1a\xae\xad\xdb\xbe\x09\xcf\x70\xf8\x81"
+      "\xec\x56\x8d\x57\x4a\x2f\xfd\x4d\xab\xe5\xee\x98\x20\xad\xaa\x47"
+      "\x8e\x56\xfd\x8f\x4b\xa5\xd0\x9f\xfa\x1c\x6d\x92\x7c\x40\xf4\xc3"
+      "\x37\x30\x40\x49\xe8\xa9\x52\xfb\xcb\xf4\x5c\x6f\xa7\x7a\x41\xa4",
+      2 /* Only in debug mode.  */
+    }
+  };
+  int tvidx;
+  gpg_error_t err;
+  unsigned char outbuf[64];
+  int i;
+
+  for (tvidx=0; tvidx < DIM(tv); tvidx++)
+    {
+      if (tv[tvidx].disabled && !(tv[tvidx].disabled == 2 && debug))
+        continue;
+      if (verbose)
+        fprintf (stderr, "checking SCRYPT test vector %d\n", tvidx);
+      assert (tv[tvidx].dklen <= sizeof outbuf);
+      err = gcry_kdf_derive (tv[tvidx].p, tv[tvidx].plen,
+                             tv[tvidx].parm_r == 1 ? 41 : GCRY_KDF_SCRYPT,
+                             tv[tvidx].parm_n,
+                             tv[tvidx].salt, tv[tvidx].saltlen,
+                             tv[tvidx].parm_p, tv[tvidx].dklen, outbuf);
+      if (err)
+        fail ("scrypt test %d failed: %s\n", tvidx, gpg_strerror (err));
+      else if (memcmp (outbuf, tv[tvidx].dk, tv[tvidx].dklen))
+        {
+          fail ("scrypt test %d failed: mismatch\n", tvidx);
+          fputs ("got:", stderr);
+          for (i=0; i < tv[tvidx].dklen; i++)
+            fprintf (stderr, " %02x", outbuf[i]);
+          putc ('\n', stderr);
+        }
+    }
+}
+
+
 int
 main (int argc, char **argv)
 {
-  int debug = 0;
+  int last_argc = -1;
+  unsigned long s2kcount = 0;
 
-  if (argc > 1 && !strcmp (argv[1], "--verbose"))
-    verbose = 1;
-  else if (argc > 1 && !strcmp (argv[1], "--debug"))
-    verbose = debug = 1;
+  if (argc)
+    { argc--; argv++; }
+
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--help"))
+        {
+          fputs ("usage: t-kdf [options]"
+                 "Options:\n"
+                 " --verbose    print timinigs etc.\n"
+                 " --debug      flyswatter\n"
+                 " --s2k        print the time needed for S2K\n",
+                 stdout);
+          exit (0);
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--s2k"))
+        {
+          s2kcount = 1;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        die ("unknown option '%s'\n", *argv);
+    }
+
+  if (s2kcount)
+    {
+      if (argc != 1)
+        die ("usage: t-kdf --s2k S2KCOUNT\n", stderr );
+      s2kcount = strtoul (*argv, NULL, 10);
+      if (!s2kcount)
+        die ("t-kdf: S2KCOUNT must be positive\n", stderr );
+    }
 
   if (!gcry_check_version (GCRYPT_VERSION))
     die ("version mismatch\n");
@@ -975,8 +1237,14 @@ main (int argc, char **argv)
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
 
-  check_openpgp ();
-  check_pbkdf2 ();
+  if (s2kcount)
+    bench_s2k (s2kcount);
+  else
+    {
+      check_openpgp ();
+      check_pbkdf2 ();
+      check_scrypt ();
+    }
 
   return error_count ? 1 : 0;
 }