summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Makefile.am57
-rw-r--r--src/util/anastasis-config.in12
-rw-r--r--src/util/anastasis_crypto.c637
-rw-r--r--src/util/os_installation.c71
-rw-r--r--src/util/paths.conf29
-rw-r--r--src/util/test_anastasis_crypto.c346
6 files changed, 1152 insertions, 0 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
new file mode 100644
index 0000000..657ec0c
--- /dev/null
+++ b/src/util/Makefile.am
@@ -0,0 +1,57 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include $(LIBGCRYPT_CFLAGS)
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+pkgcfgdir = $(prefix)/share/anastasis/config.d/
+
+pkgcfg_DATA = \
+ paths.conf
+
+EXTRA_DIST = \
+ anastasis-config.in \
+ $(pkgcfg_DATA)
+
+edit_script = $(SED) -e 's,%libdir%,$(libdir),'g $(NULL)
+
+anastasis-config: anastasis-config.in
+ rm -f $@ $@.tmp && \
+ $(edit_script) $< >$@.tmp && \
+ chmod a-w+x $@.tmp && \
+ mv $@.tmp $@
+
+bin_SCRIPTS = \
+ anastasis-config
+
+lib_LTLIBRARIES = \
+ libanastasisutil.la
+
+libanastasisutil_la_SOURCES = \
+ anastasis_crypto.c \
+ os_installation.c
+libanastasisutil_la_LIBADD = \
+ -lgnunetutil \
+ $(LIBGCRYPT_LIBS) \
+ -ljansson \
+ -ltalerutil \
+ $(XLIB)
+libanastasisutil_la_LDFLAGS = \
+ -version-info 0:0:0 \
+ -no-undefined
+
+check_PROGRAMS = \
+ test_anastasis_crypto
+
+TESTS = \
+ $(check_PROGRAMS)
+
+test_anastasis_crypto_SOURCES = \
+ test_anastasis_crypto.c
+test_anastasis_crypto_LDADD = \
+ -lgnunetutil \
+ -ltalerutil \
+ libanastasisutil.la \
+ $(XLIB)
diff --git a/src/util/anastasis-config.in b/src/util/anastasis-config.in
new file mode 100644
index 0000000..0e94921
--- /dev/null
+++ b/src/util/anastasis-config.in
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+set -eu
+
+if ! type gnunet-config >/dev/null; then
+ echo "$0 needs gnunet-config to be installed"
+ exit 1
+fi
+
+GC=`which gnunet-config`
+export LD_PRELOAD=${LD_PRELOAD:-}:%libdir%/libanastasisutil.so
+exec gnunet-config "$@"
diff --git a/src/util/anastasis_crypto.c b/src/util/anastasis_crypto.c
new file mode 100644
index 0000000..ace0162
--- /dev/null
+++ b/src/util/anastasis_crypto.c
@@ -0,0 +1,637 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020 Taler Systems SA
+
+ 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/anastasis_crypto.c
+ * @brief anastasis crypto api
+ * @author Christian Grothoff
+ * @author Dominik Meister
+ * @author Dennis Neufeld
+ */
+
+#include "platform.h"
+#include "anastasis_crypto_lib.h"
+#include <gcrypt.h>
+#include <taler/taler_json_lib.h>
+#include <gnunet/gnunet_util_lib.h>
+#include <string.h>
+
+#if defined(DEBUG) || defined(DEBUG2)
+#define SCRYPT_ITERATION 1
+
+#else
+#define SCRYPT_ITERATION 1000
+#endif
+
+
+void
+ANASTASIS_hash_answer (uint64_t code,
+ struct GNUNET_HashCode *hashed_code)
+{
+ char cbuf[40];
+
+ GNUNET_snprintf (cbuf,
+ sizeof (cbuf),
+ "%llu",
+ (unsigned long long) code);
+ GNUNET_CRYPTO_hash (cbuf,
+ strlen (cbuf),
+ hashed_code);
+}
+
+
+void
+ANASTASIS_CRYPTO_secure_answer_hash (
+ const char *answer,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
+ const struct ANASTASIS_CRYPTO_QuestionSaltP *salt,
+ struct GNUNET_HashCode *result)
+{
+ struct GNUNET_HashCode pow;
+
+ GNUNET_CRYPTO_pow_hash (&salt->pow_salt,
+ answer,
+ strlen (answer),
+ &pow);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (
+ result,
+ sizeof (*result),
+ "Anastasis-secure-question-uuid-salting",
+ strlen ("Anastasis-secure-question-uuid-salting"),
+ &pow,
+ sizeof (pow),
+ uuid,
+ sizeof (*uuid),
+ NULL,
+ 0));
+}
+
+
+/**
+ * Compute @a key and @a iv.
+ *
+ * @param key_material key for calculation
+ * @param key_m_len length of key
+ * @param nonce nonce for calculation
+ * @param salt salt value for calculation
+ * @param[out] key where to write the en-/description key
+ * @param[out] iv where to write the IV
+ */
+static void
+get_iv_key (const void *key_material,
+ size_t key_m_len,
+ const struct ANASTASIS_CRYPTO_NonceP *nonce,
+ const char *salt,
+ const struct ANASTASIS_CRYPTO_SymKeyP *key,
+ struct ANASTASIS_CRYPTO_IvP *iv)
+{
+ char res[sizeof (struct ANASTASIS_CRYPTO_SymKeyP)
+ + sizeof (struct ANASTASIS_CRYPTO_IvP)];
+
+ if (GNUNET_YES !=
+ GNUNET_CRYPTO_hkdf (res,
+ sizeof (res),
+ GCRY_MD_SHA512,
+ GCRY_MD_SHA256,
+ key_material,
+ key_m_len,
+ nonce,
+ sizeof (struct ANASTASIS_CRYPTO_NonceP),
+ salt,
+ strlen (salt),
+ NULL,
+ 0))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ memcpy ((void *) key,
+ res,
+ sizeof (*key));
+ memcpy (iv,
+ &res[sizeof (*key)],
+ sizeof (*iv));
+}
+
+
+/**
+ * Encryption of data like recovery document etc.
+ *
+ * @param nonce value to use for the nonce
+ * @param key key which is used to derive a key/iv pair from
+ * @param key_len length of key
+ * @param data data to encrypt
+ * @param data_size size of the data
+ * @param salt salt value which is used for key derivation
+ * @param res[out] ciphertext output
+ * @param res_size[out] size of the ciphertext
+ */
+static void
+anastasis_encrypt (const struct ANASTASIS_CRYPTO_NonceP *nonce,
+ const void *key,
+ size_t key_len,
+ const void *data,
+ size_t data_size,
+ const char *salt,
+ void **res,
+ size_t *res_size)
+{
+ struct ANASTASIS_CRYPTO_NonceP *nonceptr;
+ gcry_cipher_hd_t cipher;
+ struct ANASTASIS_CRYPTO_SymKeyP sym_key;
+ struct ANASTASIS_CRYPTO_IvP iv;
+ int rc;
+ struct ANASTASIS_CRYPTO_AesTagP *tag;
+ char *ciphertext;
+
+ *res_size = data_size
+ + sizeof (struct ANASTASIS_CRYPTO_NonceP)
+ + sizeof (struct ANASTASIS_CRYPTO_AesTagP);
+ if (*res_size <= data_size)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ *res = GNUNET_malloc (*res_size);
+ if (*res_size != data_size
+ + sizeof (struct ANASTASIS_CRYPTO_NonceP)
+ + sizeof (struct ANASTASIS_CRYPTO_AesTagP))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ nonceptr = (struct ANASTASIS_CRYPTO_NonceP *) *res;
+ tag = (struct ANASTASIS_CRYPTO_AesTagP *) &nonceptr[1];
+ ciphertext = (char *) &tag[1];
+ memcpy (nonceptr,
+ nonce,
+ sizeof (*nonce));
+ get_iv_key (key,
+ key_len,
+ nonce,
+ salt,
+ &sym_key,
+ &iv);
+ GNUNET_assert (0 ==
+ gcry_cipher_open (&cipher,
+ GCRY_CIPHER_AES256,
+ GCRY_CIPHER_MODE_GCM,
+ 0));
+ rc = gcry_cipher_setkey (cipher,
+ &sym_key,
+ sizeof (sym_key));
+ GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
+ rc = gcry_cipher_setiv (cipher,
+ &iv,
+ sizeof (iv));
+ GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
+
+ GNUNET_assert (0 ==
+ gcry_cipher_encrypt (cipher,
+ ciphertext,
+ data_size,
+ data,
+ data_size));
+ GNUNET_assert (0 ==
+ gcry_cipher_gettag (cipher,
+ tag,
+ sizeof (struct ANASTASIS_CRYPTO_AesTagP)));
+ gcry_cipher_close (cipher);
+}
+
+
+/**
+ * Decryption of data like encrypted recovery document etc.
+ *
+ * @param key key which is used to derive a key/iv pair from
+ * @param key_len length of key
+ * @param data data to decrypt
+ * @param data_size size of the data
+ * @param salt salt value which is used for key derivation
+ * @param res[out] plaintext output
+ * @param res_size[out] size of the plaintext
+ */
+static void
+anastasis_decrypt (const void *key,
+ size_t key_len,
+ const void *data,
+ size_t data_size,
+ const char *salt,
+ void **res,
+ size_t *res_size)
+{
+ const struct ANASTASIS_CRYPTO_NonceP *nonce;
+ gcry_cipher_hd_t cipher;
+ const struct ANASTASIS_CRYPTO_SymKeyP sym_key;
+ struct ANASTASIS_CRYPTO_IvP iv;
+ int rc;
+ const struct ANASTASIS_CRYPTO_AesTagP *tag;
+ const char *ciphertext;
+
+ *res_size = data_size
+ - sizeof (struct ANASTASIS_CRYPTO_NonceP)
+ - sizeof (struct ANASTASIS_CRYPTO_AesTagP);
+ if (*res_size >= data_size)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ *res = GNUNET_malloc (*res_size);
+ if (*res_size != data_size
+ - sizeof (struct ANASTASIS_CRYPTO_NonceP)
+ - sizeof (struct ANASTASIS_CRYPTO_AesTagP))
+ {
+ GNUNET_break (0);
+ GNUNET_free (*res);
+ return;
+ }
+
+ nonce = (const struct ANASTASIS_CRYPTO_NonceP *) data;
+ tag = (struct ANASTASIS_CRYPTO_AesTagP *) &nonce[1];
+ ciphertext = (const char *) &tag[1];
+ get_iv_key (key,
+ key_len,
+ nonce,
+ salt,
+ &sym_key,
+ &iv);
+ GNUNET_assert (0 ==
+ gcry_cipher_open (&cipher,
+ GCRY_CIPHER_AES256,
+ GCRY_CIPHER_MODE_GCM,
+ 0));
+ rc = gcry_cipher_setkey (cipher,
+ &sym_key,
+ sizeof (sym_key));
+ GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
+
+ rc = gcry_cipher_setiv (cipher,
+ &iv,
+ sizeof (iv));
+ GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
+
+ GNUNET_assert (0 == gcry_cipher_decrypt (cipher,
+ *res,
+ *res_size,
+ ciphertext,
+ *res_size));
+ if (0 !=
+ gcry_cipher_checktag (cipher,
+ tag,
+ sizeof (struct ANASTASIS_CRYPTO_AesTagP)))
+ {
+ GNUNET_break (0);
+ GNUNET_free (*res);
+ return;
+ }
+ gcry_cipher_close (cipher);
+}
+
+
+void
+ANASTASIS_CRYPTO_user_identifier_derive (
+ const json_t *id_data,
+ const struct ANASTASIS_CRYPTO_ProviderSaltP *server_salt,
+ struct ANASTASIS_CRYPTO_UserIdentifierP *id)
+{
+ char *json_enc;
+ struct GNUNET_HashCode hash;
+
+ json_enc = json_dumps (id_data,
+ JSON_COMPACT | JSON_SORT_KEYS);
+ GNUNET_assert (NULL != json_enc);
+ GNUNET_CRYPTO_pow_hash (&server_salt->salt,
+ json_enc,
+ strlen (json_enc),
+ &hash);
+ id->hash = hash;
+ free (json_enc);
+}
+
+
+void
+ANASTASIS_CRYPTO_account_private_key_derive (
+ const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
+ struct ANASTASIS_CRYPTO_AccountPrivateKeyP *priv_key)
+{
+ /* priv_key = ver_secret */
+ if (GNUNET_YES !=
+ GNUNET_CRYPTO_hkdf (&priv_key->priv,
+ sizeof (priv_key->priv),
+ GCRY_MD_SHA512,
+ GCRY_MD_SHA256,
+ id,
+ sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
+ "ver",
+ strlen ("ver"),
+ NULL,
+ 0))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ /* go from ver_secret to proper private key (eddsa_d_to_a() in spec) */
+ priv_key->priv.d[0] = (priv_key->priv.d[0] & 0x7f) | 0x40;
+ priv_key->priv.d[31] &= 0xf8;
+}
+
+
+void
+ANASTASIS_CRYPTO_account_public_key_derive (
+ const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
+ struct ANASTASIS_CRYPTO_AccountPublicKeyP *pub_key)
+{
+ struct ANASTASIS_CRYPTO_AccountPrivateKeyP priv;
+
+ ANASTASIS_CRYPTO_account_private_key_derive (id,
+ &priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&priv.priv,
+ &pub_key->pub);
+}
+
+
+void
+ANASTASIS_CRYPTO_recovery_document_encrypt (
+ const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
+ const void *rec_doc,
+ size_t rd_size,
+ void **enc_rec_doc,
+ size_t *erd_size)
+{
+ const char *salt = "erd";
+ struct ANASTASIS_CRYPTO_NonceP nonce;
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &nonce,
+ sizeof (nonce));
+ anastasis_encrypt (&nonce,
+ id,
+ sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
+ rec_doc,
+ rd_size,
+ salt,
+ enc_rec_doc,
+ erd_size);
+}
+
+
+void
+ANASTASIS_CRYPTO_recovery_document_decrypt (
+ const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
+ const void *enc_rec_doc,
+ size_t erd_size,
+ void **rec_doc,
+ size_t *rd_size)
+{
+ const char *salt = "erd";
+
+ anastasis_decrypt (id,
+ sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
+ enc_rec_doc,
+ erd_size,
+ salt,
+ rec_doc,
+ rd_size);
+}
+
+
+void
+ANASTASIS_CRYPTO_keyshare_encrypt (
+ const struct ANASTASIS_CRYPTO_KeyShareP *key_share,
+ const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
+ const char *xsalt,
+ struct ANASTASIS_CRYPTO_EncryptedKeyShareP *enc_key_share)
+{
+ const char *salt = "eks";
+ size_t eks_size = 0;
+ void *eks = NULL;
+ struct ANASTASIS_CRYPTO_NonceP nonce;
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &nonce,
+ sizeof (nonce));
+ anastasis_encrypt (&nonce,
+ id,
+ sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
+ key_share,
+ sizeof (struct ANASTASIS_CRYPTO_KeyShareP),
+ (NULL == xsalt) ? salt : xsalt,
+ &eks,
+ &eks_size);
+ GNUNET_assert (eks_size ==
+ sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP));
+ memcpy (enc_key_share,
+ eks,
+ sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP));
+ GNUNET_free (eks);
+}
+
+
+void
+ANASTASIS_CRYPTO_keyshare_decrypt (
+ const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *enc_key_share,
+ const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
+ const char *xsalt,
+ struct ANASTASIS_CRYPTO_KeyShareP *key_share)
+{
+ const char *salt = "eks";
+ size_t ks_size = 0;
+ void *ks = NULL;
+
+ anastasis_decrypt (id,
+ sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
+ enc_key_share,
+ sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP),
+ (NULL == xsalt) ? salt : xsalt,
+ &ks,
+ &ks_size);
+ GNUNET_assert (ks_size ==
+ sizeof (struct ANASTASIS_CRYPTO_KeyShareP));
+ memcpy (key_share,
+ ks,
+ sizeof (struct ANASTASIS_CRYPTO_KeyShareP));
+ GNUNET_free (ks);
+}
+
+
+void
+ANASTASIS_CRYPTO_truth_encrypt (
+ const struct ANASTASIS_CRYPTO_NonceP *nonce,
+ const struct ANASTASIS_CRYPTO_TruthKeyP *truth_enc_key,
+ const void *truth,
+ size_t truth_size,
+ void **enc_truth,
+ size_t *ect_size)
+{
+ const char *salt = "ect";
+
+ anastasis_encrypt (nonce,
+ truth_enc_key,
+ sizeof (struct ANASTASIS_CRYPTO_TruthKeyP),
+ truth,
+ truth_size,
+ salt,
+ enc_truth,
+ ect_size);
+}
+
+
+void
+ANASTASIS_CRYPTO_truth_decrypt (
+ const struct ANASTASIS_CRYPTO_TruthKeyP *truth_enc_key,
+ const void *enc_truth,
+ size_t ect_size,
+ void **truth,
+ size_t *truth_size)
+{
+ const char *salt = "ect";
+
+ anastasis_decrypt (truth_enc_key,
+ sizeof (struct ANASTASIS_CRYPTO_TruthKeyP),
+ enc_truth,
+ ect_size,
+ salt,
+ truth,
+ truth_size);
+}
+
+
+void
+ANASTASIS_CRYPTO_keyshare_create (
+ struct ANASTASIS_CRYPTO_KeyShareP *key_share)
+{
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
+ key_share,
+ sizeof (struct ANASTASIS_CRYPTO_KeyShareP));
+}
+
+
+void
+ANASTASIS_CRYPTO_policy_key_derive (
+ const struct ANASTASIS_CRYPTO_KeyShareP *key_shares,
+ unsigned int keyshare_length,
+ const struct ANASTASIS_CRYPTO_MasterSaltP *salt,
+ struct ANASTASIS_CRYPTO_PolicyKeyP *policy_key)
+{
+ GNUNET_CRYPTO_hkdf (policy_key,
+ sizeof (*policy_key),
+ GCRY_MD_SHA512,
+ GCRY_MD_SHA256,
+ key_shares,
+ keyshare_length * sizeof (*key_shares),
+ salt,
+ sizeof (*salt),
+ NULL, 0);
+}
+
+
+void
+ANASTASIS_CRYPTO_core_secret_encrypt (
+ const struct ANASTASIS_CRYPTO_PolicyKeyP *policy_keys,
+ unsigned int policy_keys_length,
+ const void *core_secret,
+ size_t core_secret_size,
+ void **enc_core_secret,
+ struct ANASTASIS_CRYPTO_EncryptedMasterKeyP *encrypted_master_keys)
+{
+ struct GNUNET_CRYPTO_SymmetricSessionKey sk;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
+ struct GNUNET_HashCode master_key;
+
+ *enc_core_secret = GNUNET_malloc (core_secret_size);
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
+ &master_key,
+ sizeof (struct GNUNET_HashCode));
+ GNUNET_CRYPTO_hash_to_aes_key (&master_key,
+ &sk,
+ &iv);
+ GNUNET_assert (GNUNET_SYSERR !=
+ GNUNET_CRYPTO_symmetric_encrypt (core_secret,
+ core_secret_size,
+ &sk,
+ &iv,
+ *enc_core_secret));
+ for (unsigned int i = 0; i < policy_keys_length; i++)
+ {
+ struct GNUNET_CRYPTO_SymmetricSessionKey i_sk;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector i_iv;
+ struct GNUNET_HashCode key = policy_keys[i].key;
+
+ GNUNET_CRYPTO_hash_to_aes_key (&key,
+ &i_sk,
+ &i_iv);
+ GNUNET_assert (
+ GNUNET_SYSERR !=
+ GNUNET_CRYPTO_symmetric_encrypt (&master_key,
+ sizeof (struct GNUNET_HashCode),
+ &i_sk,
+ &i_iv,
+ &encrypted_master_keys[i]));
+ }
+}
+
+
+void
+ANASTASIS_CRYPTO_core_secret_recover (
+ const struct ANASTASIS_CRYPTO_EncryptedMasterKeyP *encrypted_master_key,
+ const struct ANASTASIS_CRYPTO_PolicyKeyP *policy_key,
+ const void *encrypted_core_secret,
+ size_t encrypted_core_secret_size,
+ void **core_secret,
+ size_t *core_secret_size)
+{
+ struct GNUNET_CRYPTO_SymmetricSessionKey mk_sk;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector mk_iv;
+ struct GNUNET_CRYPTO_SymmetricSessionKey core_sk;
+ struct GNUNET_CRYPTO_SymmetricInitializationVector core_iv;
+ struct GNUNET_HashCode master_key;
+ struct GNUNET_HashCode key = policy_key->key;
+
+ *core_secret = GNUNET_malloc (encrypted_core_secret_size);
+ GNUNET_CRYPTO_hash_to_aes_key (&key,
+ &mk_sk,
+ &mk_iv);
+ GNUNET_assert (
+ GNUNET_SYSERR !=
+ GNUNET_CRYPTO_symmetric_decrypt (
+ encrypted_master_key,
+ sizeof (struct ANASTASIS_CRYPTO_EncryptedMasterKeyP),
+ &mk_sk,
+ &mk_iv,
+ &master_key));
+ GNUNET_CRYPTO_hash_to_aes_key (&master_key,
+ &core_sk,
+ &core_iv);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "At %s:%d encrypted core secret is %s-%llu b\n", __FILE__,
+ __LINE__,
+ TALER_b2s (encrypted_core_secret, encrypted_core_secret_size),
+ (unsigned long long) encrypted_core_secret_size);
+ *core_secret_size = GNUNET_CRYPTO_symmetric_decrypt (encrypted_core_secret,
+ encrypted_core_secret_size,
+ &core_sk,
+ &core_iv,
+ *core_secret);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "At %s:%d decrypted core secret is %s-%llu b\n", __FILE__,
+ __LINE__,
+ TALER_b2s (*core_secret, *core_secret_size),
+ (unsigned long long) *core_secret_size);
+ GNUNET_assert (GNUNET_SYSERR != *core_secret_size);
+}
+
+
+/* end of anastasis_crypto.c */
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
new file mode 100644
index 0000000..d9608d3
--- /dev/null
+++ b/src/util/os_installation.c
@@ -0,0 +1,71 @@
+/*
+ This file is part of GNU Anastasis.
+ Copyright (C) 2019 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify
+ it under the terms of the GNU 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Anastasis; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @file os_installation.c
+ * @brief initialize libgnunet OS subsystem for Anastasis.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+
+
+/**
+ * Default project data used for installation path detection
+ * for GNU Anastasis.
+ */
+static const struct GNUNET_OS_ProjectData anastasis_pd = {
+ .libname = "libanastasisutil",
+ .project_dirname = "anastasis",
+ .binary_name = "anastasis-httpd",
+ .env_varname = "ANASTASIS_PREFIX",
+ .base_config_varname = "ANASTASIS_BASE_CONFIG",
+ .bug_email = "contact@anastasis.lu",
+ .homepage = "https://anastasis.lu/",
+ .config_file = "anastasis.conf",
+ .user_config_file = "~/.config/anastasis.conf",
+ .version = PACKAGE_VERSION,
+ .is_gnu = 0,
+ .gettext_domain = "anastasis",
+ .gettext_path = NULL,
+};
+
+
+/**
+ * Return default project data used by Anastasis.
+ */
+const struct GNUNET_OS_ProjectData *
+ANASTASIS_project_data_default (void)
+{
+ return &anastasis_pd;
+}
+
+
+/**
+ * Initialize libanastasisutil.
+ */
+void __attribute__ ((constructor))
+ANASTASIS_OS_init ()
+{
+ GNUNET_OS_init (&anastasis_pd);
+}
+
+
+/* end of os_installation.c */
diff --git a/src/util/paths.conf b/src/util/paths.conf
new file mode 100644
index 0000000..c62a24a
--- /dev/null
+++ b/src/util/paths.conf
@@ -0,0 +1,29 @@
+# This file is in the public domain.
+#
+[PATHS]
+# The PATHS section is special, as filenames including $-expression are
+# expanded using the values from PATHS or the system environment (PATHS
+# is checked first). Anastasis also supports expanding $-expressions using
+# defaults with the syntax "${VAR:-default}". Here, "default" can again
+# be a $-expression.
+#
+# We usually want $HOME for $ANASTASIS_HOME, but we allow testcases to
+# easily override this by setting $ANASTASIS_TEST_HOME.
+#
+ANASTASIS_HOME = ${ANASTASIS_TEST_HOME:-${HOME:-${USERPROFILE}}}
+
+# see XDG Base Directory Specification at
+# http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+# for how these should be used.
+
+# Persistent data storage
+ANASTASIS_DATA_HOME = ${XDG_DATA_HOME:-$ANASTASIS_HOME/.local/share}/anastasis/
+
+# Configuration files
+ANASTASIS_CONFIG_HOME = ${XDG_CONFIG_HOME:-$ANASTASIS_HOME/.config}/anastasis/
+
+# Cached data, no big deal if lost
+ANASTASIS_CACHE_HOME = ${XDG_CACHE_HOME:-$ANASTASIS_HOME/.cache}/anastasis/
+
+# Runtime data (always lost on system boot)
+ANASTASIS_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/anastasis-system-runtime/
diff --git a/src/util/test_anastasis_crypto.c b/src/util/test_anastasis_crypto.c
new file mode 100644
index 0000000..9a6a98c
--- /dev/null
+++ b/src/util/test_anastasis_crypto.c
@@ -0,0 +1,346 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3, or
+ (at your option) any later version.
+
+ TALER 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file lib/test_anastasis_api.c
+ * @brief testcase to test anastasis' HTTP API interface
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+#include "platform.h"
+#include <taler/taler_util.h>
+#include <gnunet/gnunet_util_lib.h>
+#include "anastasis_crypto_lib.h"
+
+/**
+ * Testing derivation of the user identifier
+ */
+static int
+test_user_identifier_derive (void)
+{
+ json_t *id_data_1;
+ json_t *id_data_2;
+ json_t *id_data_3;
+ struct ANASTASIS_CRYPTO_UserIdentifierP id_1;
+ struct ANASTASIS_CRYPTO_UserIdentifierP id_2;
+ struct ANASTASIS_CRYPTO_UserIdentifierP id_3;
+ struct ANASTASIS_CRYPTO_ProviderSaltP server_salt;
+
+ char *salt_str = "Server-Salt-Test";
+
+ GNUNET_memcpy (&server_salt,
+ salt_str,
+ strlen (salt_str));
+ // sample data 1
+ id_data_1 = json_object ();
+ json_object_set_new (id_data_1, "arg1", json_string ("Hallo"));
+ // sample data 2, equal to sample data 1
+ id_data_2 = json_object ();
+ json_object_set_new (id_data_2, "arg1", json_string ("Hallo"));
+ // sample data 3, differs
+ id_data_3 = json_object ();
+ json_object_set_new (id_data_3, "arg1", json_string ("Hallo2"));
+
+ ANASTASIS_CRYPTO_user_identifier_derive (id_data_1,
+ &server_salt,
+ &id_1);
+ ANASTASIS_CRYPTO_user_identifier_derive (id_data_2,
+ &server_salt,
+ &id_2);
+ ANASTASIS_CRYPTO_user_identifier_derive (id_data_3,
+ &server_salt,
+ &id_3);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "UserIdentifier_1: %s\n",
+ TALER_B2S (&id_1));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "UserIdentifier_2: %s\n",
+ TALER_B2S (&id_2));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "UserIdentifier_3: %s\n",
+ TALER_B2S (&id_3));
+ GNUNET_assert (0 == GNUNET_memcmp (&id_1, &id_2));
+ GNUNET_assert (0 != GNUNET_memcmp (&id_1, &id_3));
+ json_decref (id_data_1);
+ json_decref (id_data_2);
+ json_decref (id_data_3);
+ return 0;
+}
+
+
+/**
+ * Testing the encryption of an recovery document and the
+ * decryption of the encrypted recovery document
+ */
+static int
+test_recovery_document (void)
+{
+ void *ciphertext;
+ size_t size_ciphertext;
+ void *plaintext;
+ size_t size_plaintext;
+ struct ANASTASIS_CRYPTO_UserIdentifierP id;
+ struct ANASTASIS_CRYPTO_ProviderSaltP server_salt;
+ int ret;
+
+ json_t *id_data = json_object ();
+ const char *test = "TEST_ERD";
+ char *salt_str = "Server-Salt-Test";
+
+ GNUNET_memcpy (&server_salt,
+ salt_str,
+ strlen (salt_str));
+ json_object_set_new (id_data, "arg1", json_string ("ID_DATA"));
+ ANASTASIS_CRYPTO_user_identifier_derive (id_data,
+ &server_salt,
+ &id);
+ ANASTASIS_CRYPTO_recovery_document_encrypt (&id,
+ test,
+ strlen (test),
+ &ciphertext,
+ &size_ciphertext);
+
+ ANASTASIS_CRYPTO_recovery_document_decrypt (&id,
+ ciphertext,
+ size_ciphertext,
+ &plaintext,
+ &size_plaintext);
+ GNUNET_assert (strlen (test) == size_plaintext);
+ ret = strncmp (plaintext, test, strlen (test));
+ json_decref (id_data);
+ GNUNET_free (ciphertext);
+ GNUNET_free (plaintext);
+ return ret;
+}
+
+
+static int
+test_key_share (void)
+{
+ struct ANASTASIS_CRYPTO_EncryptedKeyShareP ciphertext;
+ struct ANASTASIS_CRYPTO_KeyShareP plaintext;
+ struct ANASTASIS_CRYPTO_UserIdentifierP id;
+ struct ANASTASIS_CRYPTO_KeyShareP key_share;
+ struct ANASTASIS_CRYPTO_KeyShareP key_share_1;
+ struct ANASTASIS_CRYPTO_KeyShareP key_share_2;
+
+ // testing creation of keyshares
+ ANASTASIS_CRYPTO_keyshare_create (&key_share_1);
+ ANASTASIS_CRYPTO_keyshare_create (&key_share_2);
+ GNUNET_assert (0 !=
+ GNUNET_memcmp (&key_share_1,
+ &key_share_2));
+
+ // testing of enc-/decryption of a keyshare
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &id,
+ sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP));
+ ANASTASIS_CRYPTO_keyshare_create (&key_share);
+ ANASTASIS_CRYPTO_keyshare_encrypt (&key_share,
+ &id,
+ NULL,
+ &ciphertext);
+ ANASTASIS_CRYPTO_keyshare_decrypt (&ciphertext,
+ &id,
+ NULL,
+ &plaintext);
+ return GNUNET_memcmp (&key_share,
+ &plaintext);
+}
+
+
+static int
+test_truth (void)
+{
+ const char *test = "TEST_TRUTH";
+ void *ciphertext;
+ size_t size_ciphertext;
+ void *plaintext;
+ size_t size_plaintext;
+ struct ANASTASIS_CRYPTO_TruthKeyP truth_enc_key;
+ int ret;
+ struct ANASTASIS_CRYPTO_NonceP nonce;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "TRUTH_BEFORE: %s\n",
+ TALER_b2s (test,
+ strlen (test)));
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &truth_enc_key,
+ sizeof (struct ANASTASIS_CRYPTO_TruthKeyP));
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &nonce,
+ sizeof (nonce));
+ ANASTASIS_CRYPTO_truth_encrypt (&nonce,
+ &truth_enc_key,
+ test,
+ strlen (test),
+ &ciphertext,
+ &size_ciphertext);
+
+ ANASTASIS_CRYPTO_truth_decrypt (&truth_enc_key,
+ ciphertext,
+ size_ciphertext,
+ &plaintext,
+ &size_plaintext);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "TRUTH_AFTER: %s\n",
+ TALER_b2s (plaintext, size_plaintext));
+ GNUNET_assert (strlen (test) == size_plaintext);
+ ret = strncmp (plaintext, test, strlen (test));
+ GNUNET_free (ciphertext);
+ GNUNET_free (plaintext);
+ return ret;
+}
+
+
+static int
+test_core_secret (void)
+{
+ const char *test = "TEST_CORE_SECRET";
+ const char *test_wrong = "TEST_CORE_WRONG";
+ void *enc_core_secret;
+ unsigned int policy_keys_length = 5;
+ struct ANASTASIS_CRYPTO_MasterSaltP salt;
+ struct ANASTASIS_CRYPTO_EncryptedMasterKeyP
+ encrypted_master_keys[policy_keys_length];
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &salt,
+ sizeof (salt));
+
+ // construction of PolicyKey-array
+ struct ANASTASIS_CRYPTO_PolicyKeyP policy_keys[policy_keys_length];
+ for (unsigned int i = 0; i < policy_keys_length; i++)
+ {
+ // construction of KeyShare-array
+ unsigned int keyshare_length = 5;
+ struct ANASTASIS_CRYPTO_KeyShareP keyshares[keyshare_length];
+ for (unsigned int j = 0; j < keyshare_length; j++)
+ {
+ ANASTASIS_CRYPTO_keyshare_create (&keyshares[j]);
+ if (j > 0)
+ GNUNET_assert (0 !=
+ GNUNET_memcmp (&keyshares[j - 1], &keyshares[j]));
+ }
+
+ // derive policy-keys
+ ANASTASIS_CRYPTO_policy_key_derive ((struct
+ ANASTASIS_CRYPTO_KeyShareP *)
+ keyshares,
+ keyshare_length,
+ &salt,
+ &policy_keys[i]);
+ if (i > 0)
+ GNUNET_assert (0 !=
+ GNUNET_memcmp (&policy_keys[i - 1], &policy_keys[i]));
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "CORE_SECRET_BEFORE: %s\n",
+ TALER_b2s (test, strlen (test)));
+
+ // test encryption of core_secret
+ ANASTASIS_CRYPTO_core_secret_encrypt (policy_keys,
+ policy_keys_length,
+ test,
+ strlen (test),
+ &enc_core_secret,
+ (struct
+ ANASTASIS_CRYPTO_EncryptedMasterKeyP *)
+ &encrypted_master_keys);
+
+ // test recover of core secret
+ for (unsigned int k = 0; k < policy_keys_length; k++)
+ {
+ void *dec_core_secret;
+ size_t core_secret_size;
+
+ ANASTASIS_CRYPTO_core_secret_recover (&encrypted_master_keys[k],
+ &policy_keys[k],
+ enc_core_secret,
+ strlen (test),
+ &dec_core_secret,
+ &core_secret_size);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "CORE_SECRET_AFTER_%i: %s\n",
+ k,
+ TALER_b2s (dec_core_secret, strlen (test)));
+ GNUNET_assert (strlen (test) == core_secret_size);
+ GNUNET_assert (0 ==
+ strncmp (dec_core_secret, test, strlen (test)));
+ GNUNET_assert (0 !=
+ strncmp (dec_core_secret, test_wrong, strlen (
+ test)));
+ GNUNET_free (dec_core_secret);
+ }
+ GNUNET_free (enc_core_secret);
+ return 0;
+}
+
+
+static int
+test_public_key_derive (void)
+{
+ struct ANASTASIS_CRYPTO_UserIdentifierP id;
+ struct ANASTASIS_CRYPTO_AccountPublicKeyP pub_key;
+ struct ANASTASIS_CRYPTO_ProviderSaltP server_salt;
+ json_t *id_data = json_object ();
+ const char *salt_str = "Server-Salt-Test";
+
+ GNUNET_memcpy (&server_salt,
+ salt_str,
+ strlen (salt_str));
+
+ json_object_set_new (id_data, "arg1", json_string ("ID_DATA"));
+ ANASTASIS_CRYPTO_user_identifier_derive (id_data,
+ &server_salt,
+ &id);
+
+ ANASTASIS_CRYPTO_account_public_key_derive (&id,
+ &pub_key);
+ // FIXME: write a real test, e.g. signing and verification
+ json_decref (id_data);
+ return 0;
+}
+
+
+int
+main (int argc,
+ const char *const argv[])
+{
+ GNUNET_log_setup (argv[0], "DEBUG", NULL);
+ if (0 != test_recovery_document ())
+ return 1;
+ if (0 != test_user_identifier_derive ())
+ return 1;
+ if (0 != test_key_share ())
+ return 1;
+ if (0 != test_truth ())
+ return 1;
+ if (0 != test_core_secret ())
+ return 1;
+ if (0 != test_public_key_derive ())
+ return 1;
+ return 0;
+}
+
+
+/* end of test_anastasis_crypto.c */