gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-anastasis] branch master updated: test vector generation WIP


From: gnunet
Subject: [taler-anastasis] branch master updated: test vector generation WIP
Date: Wed, 06 Oct 2021 16:50:19 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository anastasis.

The following commit(s) were added to refs/heads/master by this push:
     new 9328a55  test vector generation WIP
9328a55 is described below

commit 9328a55a72c4a61d62f7e052854ea8ba52801879
Author: Florian Dold <florian@dold.me>
AuthorDate: Wed Oct 6 16:50:02 2021 +0200

    test vector generation WIP
---
 .gitignore                      |   1 +
 src/util/.gitignore             |   1 +
 src/util/Makefile.am            |  14 +
 src/util/anastasis-crypto-tvg.c | 618 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 634 insertions(+)

diff --git a/.gitignore b/.gitignore
index dd37851..beacf7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -126,3 +126,4 @@ src/include/anastasis_error_codes.h
 src/lib/test_anastasis_api_home/
 doc/anastasis.info
 src/cli/test_reducer.err
+.vscode
diff --git a/src/util/.gitignore b/src/util/.gitignore
new file mode 100644
index 0000000..80af6f7
--- /dev/null
+++ b/src/util/.gitignore
@@ -0,0 +1 @@
+anastasis-crypto-tvg
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 657ec0c..5f3b3d5 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -6,6 +6,9 @@ if USE_COVERAGE
   XLIB = -lgcov
 endif
 
+bin_PROGRAMS = \
+  anastasis-crypto-tvg
+
 pkgcfgdir = $(prefix)/share/anastasis/config.d/
 
 pkgcfg_DATA = \
@@ -55,3 +58,14 @@ test_anastasis_crypto_LDADD = \
   -ltalerutil \
   libanastasisutil.la \
   $(XLIB)
+
+anastasis_crypto_tvg_SOURCES = \
+  anastasis-crypto-tvg.c
+anastasis_crypto_tvg_LDADD = \
+  $(top_builddir)/src/util/libanastasisutil.la \
+  -ltalerjson \
+  -ltalerutil \
+  -lgnunetjson \
+  -lgnunetutil \
+  -ljansson \
+  $(XLIB)
diff --git a/src/util/anastasis-crypto-tvg.c b/src/util/anastasis-crypto-tvg.c
new file mode 100644
index 0000000..ee3df2e
--- /dev/null
+++ b/src/util/anastasis-crypto-tvg.c
@@ -0,0 +1,618 @@
+/*
+  This file is part of Anastasis
+  Copyright (C) 2020,2021 Anastasis SARL
+
+  Anastasis is free software; you can redistribute it and/or modify it under 
the
+  terms of the GNU Lesser General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  Anastasis; see the file COPYING.GPL.  If not, see 
<http://www.gnu.org/licenses/>
+*/
+
+
+/**
+ * @file util/anastasis-crypto-tgv.c
+ * @brief Generate test vectors for cryptographic operations.
+ * @author Florian Dold
+ *
+ *
+ * Test vectors have the following format (TypeScript pseudo code):
+ *
+ * interface TestVectorFile {
+ *   encoding: "base32crockford";
+ *   producer?: string;
+ *   vectors: TestVector[];
+ * }
+ *
+ * enum Operation {
+ *  Hash("hash"),
+ *  ...
+ * }
+ *
+ * interface TestVector {
+ *   operation: Operation;
+ *   // Inputs for the operation
+ *   [ k: string]: string | number;
+ * };
+ *
+ *
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_signatures.h>
+#include <gnunet/gnunet_testing_lib.h>
+#include <jansson.h>
+#include <gcrypt.h>
+#include "anastasis_crypto_lib.h"
+
+
+/**
+ * Should we verify or output test vectors?
+ */
+static int verify_flag = GNUNET_NO;
+
+
+/**
+ * Global exit code.
+ */
+static int global_ret = 0;
+
+
+/**
+ * Create a fresh test vector for a given operation label.
+ *
+ * @param vecs array of vectors to append the new vector to
+ * @param vecname label for the operation of the vector
+ * @returns the fresh test vector
+ */
+static json_t *
+vec_for (json_t *vecs, const char *vecname)
+{
+  json_t *t = json_object ();
+
+  json_object_set_new (t,
+                       "operation",
+                       json_string (vecname));
+  json_array_append_new (vecs, t);
+  return t;
+}
+
+
+/**
+ * Add a base32crockford encoded value
+ * to a test vector.
+ *
+ * @param vec test vector to add to
+ * @param label label for the value
+ * @param data data to add
+ * @param size size of data
+ */
+static void
+d2j (json_t *vec,
+     const char *label,
+     const void *data,
+     size_t size)
+{
+  char *buf;
+  json_t *json;
+
+  buf = GNUNET_STRINGS_data_to_string_alloc (data, size);
+  json = json_string (buf);
+  GNUNET_free (buf);
+  GNUNET_break (NULL != json);
+
+  json_object_set_new (vec, label, json);
+}
+
+
+static void
+d2j_append (json_t *arr,
+            const void *data,
+            size_t size)
+{
+  char *buf;
+  json_t *json;
+
+  buf = GNUNET_STRINGS_data_to_string_alloc (data, size);
+  json = json_string (buf);
+  GNUNET_free (buf);
+  GNUNET_break (NULL != json);
+
+  json_array_append_new (arr,
+                         json);
+}
+
+
+#define d2j_auto(vec, label, d) d2j (vec, label, d, sizeof (*d))
+#define d2j_append_auto(arr,  d) d2j_append (arr, d, sizeof (*d))
+#define random_auto(d) GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 
\
+                                                   d, \
+                                                   sizeof (*d));
+
+/**
+ * Add a number to a test vector.
+ *
+ * @param vec test vector to add to
+ * @param label label for the value
+ * @param data data to add
+ * @param size size of data
+ */
+static void
+uint2j (json_t *vec,
+        const char *label,
+        unsigned int num)
+{
+  json_t *json = json_integer (num);
+
+  json_object_set_new (vec, label, json);
+}
+
+
+static int
+expect_data_fixed (json_t *vec,
+                   const char *name,
+                   void *data,
+                   size_t expect_len)
+{
+  const char *s = json_string_value (json_object_get (vec, name));
+
+  if (NULL == s)
+    return GNUNET_NO;
+
+  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s,
+                                                  strlen (s),
+                                                  data,
+                                                  expect_len))
+    return GNUNET_NO;
+  return GNUNET_OK;
+}
+
+
+static int
+expect_data_dynamic (json_t *vec,
+                     const char *name,
+                     void **data,
+                     size_t *ret_len)
+{
+  const char *s = json_string_value (json_object_get (vec, name));
+  char *tmp;
+  size_t len;
+
+  if (NULL == s)
+    return GNUNET_NO;
+
+  len = (strlen (s) * 5) / 8;
+  if (NULL != ret_len)
+    *ret_len = len;
+  tmp = GNUNET_malloc (len);
+
+  if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, strlen (s), tmp, len))
+  {
+    GNUNET_free (tmp);
+    return GNUNET_NO;
+  }
+  *data = tmp;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Check a single vector.
+ *
+ * @param operation operator of the vector
+ * @param vec the vector, a JSON object.
+ *
+ * @returns GNUNET_OK if the vector is okay
+ */
+static int
+checkvec (const char *operation,
+          json_t *vec)
+{
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "checking %s\n", operation);
+
+  if (0 == strcmp (operation, "hash"))
+  {
+    void *data;
+    size_t data_len;
+    struct GNUNET_HashCode hash_out;
+    struct GNUNET_HashCode hc;
+
+    if (GNUNET_OK != expect_data_dynamic (vec,
+                                          "input",
+                                          &data,
+                                          &data_len))
+    {
+      GNUNET_break (0);
+      return GNUNET_SYSERR;
+    }
+    if (GNUNET_OK != expect_data_fixed (vec,
+                                        "output",
+                                        &hash_out,
+                                        sizeof (hash_out)))
+    {
+      GNUNET_free (data);
+      GNUNET_break (0);
+      return GNUNET_NO;
+    }
+
+    GNUNET_CRYPTO_hash (data, data_len, &hc);
+
+    if (0 != GNUNET_memcmp (&hc, &hash_out))
+    {
+      GNUNET_free (data);
+      GNUNET_break (0);
+      return GNUNET_NO;
+    }
+    GNUNET_free (data);
+  }
+
+  return GNUNET_OK;
+}
+
+
+/**
+ * Check test vectors from stdin.
+ *
+ * @returns global exit code
+ */
+static int
+check_vectors ()
+{
+  json_error_t err;
+  json_t *vecfile = json_loadf (stdin, 0, &err);
+  const char *encoding;
+  json_t *vectors;
+
+  if (NULL == vecfile)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unable to parse JSON\n");
+    return 1;
+  }
+  encoding = json_string_value (json_object_get (vecfile,
+                                                 "encoding"));
+  if ( (NULL == encoding) || (0 != strcmp (encoding, "base32crockford")) )
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unsupported or missing encoding\n");
+    json_decref (vecfile);
+    return 1;
+  }
+  vectors = json_object_get (vecfile, "vectors");
+  if (! json_is_array (vectors))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bad vectors\n");
+    json_decref (vecfile);
+    return 1;
+  }
+  {
+    /* array is a JSON array */
+    size_t index;
+    json_t *value;
+    int ret;
+
+    json_array_foreach (vectors, index, value) {
+      const char *op = json_string_value (json_object_get (value,
+                                                           "operation"));
+
+      if (NULL == op)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "missing operation\n");
+        ret = GNUNET_SYSERR;
+        break;
+      }
+      ret = checkvec (op, value);
+      if (GNUNET_OK != ret)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                    "bad vector %u\n",
+                    (unsigned int) index);
+        break;
+      }
+    }
+    return (ret == GNUNET_OK) ? 0 : 1;
+  }
+}
+
+
+/**
+ * Output test vectors.
+ *
+ * @returns global exit code
+ */
+static int
+output_vectors ()
+{
+  json_t *vecfile = json_object ();
+  json_t *vecs = json_array ();
+
+  json_object_set_new (vecfile,
+                       "encoding",
+                       json_string ("base32crockford"));
+  json_object_set_new (vecfile,
+                       "producer",
+                       json_string (
+                         "GNU Anastasis (C implementation) " PACKAGE_VERSION " 
"
+                         VCS_VERSION));
+  json_object_set_new (vecfile,
+                       "vectors",
+                       vecs);
+
+  {
+    json_t *vec = vec_for (vecs, "hash");
+    struct GNUNET_HashCode hc;
+    char *str = "Hello, GNUnet";
+
+    GNUNET_CRYPTO_hash (str, strlen (str), &hc);
+
+    d2j (vec, "input", str, strlen (str));
+    d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode));
+  }
+
+  {
+    json_t *vec = vec_for (vecs, "user_identifier_derive");
+    struct ANASTASIS_CRYPTO_ProviderSaltP server_salt;
+    struct ANASTASIS_CRYPTO_UserIdentifierP id;
+    json_t *id_data = json_pack ("{s:s, s:s}",
+                                 "name",
+                                 "Fleabag",
+                                 "ssn",
+                                 "AB123");
+    GNUNET_assert (NULL != id_data);
+    random_auto (&server_salt);
+
+    ANASTASIS_CRYPTO_user_identifier_derive (id_data,
+                                             &server_salt,
+                                             &id);
+    json_object_set_new (vec, "input_id_data", id_data);
+    d2j_auto (vec, "input_server_salt", &server_salt);
+    d2j_auto (vec, "output_id", &id);
+  }
+
+  {
+    json_t *vec = vec_for (vecs, "account_keypair_derive");
+    struct ANASTASIS_CRYPTO_UserIdentifierP id;
+    struct ANASTASIS_CRYPTO_AccountPrivateKeyP priv_key;
+    struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key;
+
+    random_auto (&id);
+    ANASTASIS_CRYPTO_account_public_key_derive (&id, &pub_key);
+    ANASTASIS_CRYPTO_account_private_key_derive (&id, &priv_key);
+
+    d2j_auto (vec, "input_id", &id);
+    d2j_auto (vec, "output_priv_key", &priv_key);
+    d2j_auto (vec, "output_pub_key", &pub_key);
+
+  }
+
+  {
+    json_t *vec = vec_for (vecs, "secure_answer_hash");
+    const char *answer = "Blah";
+    struct ANASTASIS_CRYPTO_TruthUUIDP uuid;
+    struct ANASTASIS_CRYPTO_QuestionSaltP salt;
+    struct GNUNET_HashCode result;
+
+    random_auto (&uuid);
+    random_auto (&salt);
+    ANASTASIS_CRYPTO_secure_answer_hash (answer, &uuid, &salt, &result);
+    json_object_set_new (vec, "input_answer", json_string (answer));
+    d2j_auto (vec, "input_uuid", &uuid);
+    d2j_auto (vec, "input_salt", &salt);
+    d2j_auto (vec, "output_hash", &result);
+  }
+
+  {
+    json_t *vec = vec_for (vecs, "recovery_document_encryption");
+    struct ANASTASIS_CRYPTO_UserIdentifierP id;
+    void *rec_doc = "my recovery doc";
+    size_t rd_size = strlen (rec_doc) + 1;
+    void *enc_rec_doc;
+    size_t erd_size;
+
+    random_auto (&id);
+
+    ANASTASIS_CRYPTO_recovery_document_encrypt (&id,
+                                                rec_doc,
+                                                rd_size,
+                                                &enc_rec_doc,
+                                                &erd_size);
+    d2j_auto (vec, "input_user_id", &id);
+    d2j (vec, "input_recovery_document", rec_doc, rd_size);
+    d2j (vec, "output_encrypted_recovery_document", &enc_rec_doc, erd_size);
+  }
+
+  {
+    /* With extra salt */
+    json_t *vec = vec_for (vecs, "keyshare_encryption");
+    struct ANASTASIS_CRYPTO_KeyShareP key_share;
+    struct ANASTASIS_CRYPTO_UserIdentifierP id;
+    char *xsalt = "myanswer";
+    struct ANASTASIS_CRYPTO_EncryptedKeyShareP enc_key_share;
+
+    random_auto (&key_share);
+    random_auto (&id);
+
+    ANASTASIS_CRYPTO_keyshare_encrypt (&key_share,
+                                       &id,
+                                       xsalt,
+                                       &enc_key_share);
+    d2j_auto (vec, "input_key_share", &key_share);
+    d2j_auto (vec, "input_user_id", &id);
+    json_object_set_new (vec, "input_xsalt", json_string (xsalt));
+    d2j_auto (vec, "output_enc_key_share", &enc_key_share);
+  }
+
+  {
+    /* Without extra salt */
+    json_t *vec = vec_for (vecs, "keyshare_encryption");
+    struct ANASTASIS_CRYPTO_KeyShareP key_share;
+    struct ANASTASIS_CRYPTO_UserIdentifierP id;
+    char *xsalt = NULL;
+    struct ANASTASIS_CRYPTO_EncryptedKeyShareP enc_key_share;
+
+    random_auto (&key_share);
+    random_auto (&id);
+
+    ANASTASIS_CRYPTO_keyshare_encrypt (&key_share,
+                                       &id,
+                                       xsalt,
+                                       &enc_key_share);
+    d2j_auto (vec, "input_key_share", &key_share);
+    d2j_auto (vec, "input_user_id", &id);
+    json_object_set_new (vec, "input_xsalt", json_null ());
+    d2j_auto (vec, "output_enc_key_share", &enc_key_share);
+  }
+
+  {
+    json_t *vec = vec_for (vecs, "truth_encryption");
+
+    struct ANASTASIS_CRYPTO_NonceP nonce;
+    struct ANASTASIS_CRYPTO_TruthKeyP truth_enc_key;
+    char truth[256];
+    size_t truth_size = 256;
+    void *enc_truth;
+    size_t ect_size;
+
+    random_auto (&nonce);
+    random_auto (&truth);
+    random_auto (&truth_enc_key);
+
+    ANASTASIS_CRYPTO_truth_encrypt (&nonce,
+                                    &truth_enc_key,
+                                    &truth, truth_size,
+                                    &enc_truth,
+                                    &ect_size);
+
+    d2j_auto (vec, "input_nonce", &nonce);
+    d2j_auto (vec, "input_truth_enc_key", &truth_enc_key);
+    d2j (vec, "input_truth", &truth, truth_size);
+    d2j (vec, "output_encrypted_truth", &enc_truth, ect_size);
+  }
+
+  {
+    json_t *vec = vec_for (vecs, "policy_key_derive");
+
+    struct ANASTASIS_CRYPTO_KeyShareP key_shares[2];
+    unsigned int keyshare_length = 2;
+    struct ANASTASIS_CRYPTO_MasterSaltP salt;
+    struct ANASTASIS_CRYPTO_PolicyKeyP policy_key;
+    json_t *key_shares_json = json_array ();
+
+    random_auto (&key_shares[0]);
+    random_auto (&key_shares[1]);
+    random_auto (&salt);
+
+    ANASTASIS_CRYPTO_policy_key_derive (key_shares,
+                                        keyshare_length,
+                                        &salt,
+                                        &policy_key);
+
+    d2j_append_auto (key_shares_json, &key_shares[0]);
+    d2j_append_auto (key_shares_json, &key_shares[1]);
+    json_object_set_new (vec, "input_key_shares", key_shares_json);
+    d2j_auto (vec, "input_salt", &salt);
+    d2j_auto (vec, "output_policy_key", &policy_key);
+  }
+
+  {
+    // json_t *vec = vec_for (vecs, "core_secret_encryption");
+    // struct ANASTASIS_CRYPTO_PolicyKeyP policy_keys[2];
+    // unsigned int policy_keys_length = 2;
+    // char core_secret[256];
+    // size_t core_secret_size = 256;
+    // void *enc_core_secret;
+    // struct ANASTASIS_CRYPTO_EncryptedMasterKeyP encrypted_master_keys[2];
+    // json_t *policy_keys_json = json_array ();
+    // json_t *encrypted_master_keys_json = json_array ();
+
+    // random_auto (&policy_keys[0]);
+    // random_auto (&policy_keys[1]);
+    // random_auto (&core_secret);
+
+    // ANASTASIS_CRYPTO_core_secret_encrypt (policy_keys, policy_keys_length,
+    //                                       core_secret, core_secret_size,
+    //                                       &enc_core_secret,
+    //                                       encrypted_master_keys);
+
+    // d2j_append_auto (policy_keys_json, &policy_keys_json[0]);
+    // d2j_append_auto (policy_keys_json, &policy_keys_json[1]);
+    // d2j_append_auto (encrypted_master_keys_json, &encrypted_master_keys[0]);
+    // d2j_append_auto (encrypted_master_keys_json, &encrypted_master_keys[1]);
+
+    // d2j_auto (vec, "input_core_secret", &core_secret);
+    // json_object_set_new (vec, "input_policy_keys", policy_keys_json);
+    // json_object_set_new (vec, "output_encrypted_core_secret", 
encrypted_master_keys_json);
+    // json_object_set_new (vec, "output_encrypted_master_keys", 
encrypted_master_keys_json);
+  }
+
+
+  json_dumpf (vecfile, stdout, JSON_INDENT (2));
+  json_decref (vecfile);
+  printf ("\n");
+
+  return 0;
+}
+
+
+/**
+ * Main function that will be run.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be 
NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
+     const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  if (GNUNET_YES == verify_flag)
+    global_ret = check_vectors ();
+  else
+    global_ret = output_vectors ();
+}
+
+
+/**
+ * The main function of the test vector generation tool.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc,
+      char *const *argv)
+{
+  const struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_option_flag ('V',
+                               "verify",
+                               gettext_noop (
+                                 "verify a test vector from stdin"),
+                               &verify_flag),
+    GNUNET_GETOPT_OPTION_END
+  };
+
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_log_setup ("anastasis-crypto-tvg",
+                                   "INFO",
+                                   NULL));
+  if (GNUNET_OK !=
+      GNUNET_PROGRAM_run (argc, argv,
+                          "anastasis-crypto-tvg",
+                          "Generate test vectors for cryptographic operations",
+                          options,
+                          &run, NULL))
+    return 1;
+  return global_ret;
+}
+
+
+/* end of anastasis-crypto-tvg.c */

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]