summaryrefslogtreecommitdiff
path: root/src/util/anastasis_crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/anastasis_crypto.c')
-rw-r--r--src/util/anastasis_crypto.c470
1 files changed, 236 insertions, 234 deletions
diff --git a/src/util/anastasis_crypto.c b/src/util/anastasis_crypto.c
index bed0a94..579f097 100644
--- a/src/util/anastasis_crypto.c
+++ b/src/util/anastasis_crypto.c
@@ -3,14 +3,14 @@
Copyright (C) 2020 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
+ 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 Affero General Public License for more details.
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- You should have received a copy of the GNU Affero General Public License along with
+ 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/>
*/
/**
@@ -41,6 +41,10 @@ ANASTASIS_hash_answer (uint64_t code,
GNUNET_CRYPTO_hash (cbuf,
strlen (cbuf),
hashed_code);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Hashed answer %llu to %s\n",
+ (unsigned long long) code,
+ GNUNET_h2s (hashed_code));
}
@@ -61,61 +65,53 @@ ANASTASIS_CRYPTO_secure_answer_hash (
GNUNET_CRYPTO_kdf (
result,
sizeof (*result),
- "Anastasis-secure-question-uuid-salting",
- strlen ("Anastasis-secure-question-uuid-salting"),
- &pow,
- sizeof (pow),
+ /* salt / XTS */
uuid,
sizeof (*uuid),
+ /* skm */
+ &pow,
+ sizeof (pow),
+ /* info chunks */
+ "anastasis-secure-question-hashing",
+ strlen ("anastasis-secure-question-hashing"),
NULL,
0));
}
/**
- * Compute @a key and @a iv.
+ * Compute @a key.
*
* @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,
+derive_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)
+ struct ANASTASIS_CRYPTO_SymKeyP *key)
{
- 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));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (key,
+ sizeof (*key),
+ /* salt / XTS */
+ nonce,
+ sizeof (*nonce),
+ /* ikm */
+ key_material,
+ key_m_len,
+ /* info chunks */
+ /* The "salt" passed here is actually not something random,
+ but a protocol-specific identifier string. Thus
+ we pass it as a context info to the HKDF */
+ salt,
+ strlen (salt),
+ NULL,
+ 0));
}
@@ -141,67 +137,25 @@ anastasis_encrypt (const struct ANASTASIS_CRYPTO_NonceP *nonce,
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,
+ size_t ciphertext_size;
+ struct ANASTASIS_CRYPTO_SymKeyP skey;
+
+ derive_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));
-
+ &skey);
+ ciphertext_size = crypto_secretbox_NONCEBYTES
+ + crypto_secretbox_MACBYTES + data_size;
+ *res_size = ciphertext_size;
+ *res = GNUNET_malloc (ciphertext_size);
+ memcpy (*res, nonce, crypto_secretbox_NONCEBYTES);
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);
+ crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES,
+ data,
+ data_size,
+ (void *) nonce,
+ (void *) &skey));
}
@@ -215,8 +169,9 @@ anastasis_encrypt (const struct ANASTASIS_CRYPTO_NonceP *nonce,
* @param salt salt value which is used for key derivation
* @param[out] res plaintext output
* @param[out] res_size size of the plaintext
+ * @return #GNUNET_OK on success
*/
-static void
+static enum GNUNET_GenericReturnValue
anastasis_decrypt (const void *key,
size_t key_len,
const void *data,
@@ -226,77 +181,42 @@ anastasis_decrypt (const void *key,
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))
+ struct ANASTASIS_CRYPTO_SymKeyP skey;
+ size_t plaintext_size;
+
+ if (data_size < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES)
{
GNUNET_break (0);
- GNUNET_free (*res);
- return;
+ return GNUNET_SYSERR;
}
-
- nonce = (const struct ANASTASIS_CRYPTO_NonceP *) data;
- tag = (struct ANASTASIS_CRYPTO_AesTagP *) &nonce[1];
- ciphertext = (const char *) &tag[1];
- get_iv_key (key,
+ nonce = data;
+ derive_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)))
+ &skey);
+ plaintext_size = data_size - (crypto_secretbox_NONCEBYTES
+ + crypto_secretbox_MACBYTES);
+ *res = GNUNET_malloc (plaintext_size);
+ *res_size = plaintext_size;
+ if (0 != crypto_secretbox_open_easy (*res,
+ data + crypto_secretbox_NONCEBYTES,
+ data_size - crypto_secretbox_NONCEBYTES,
+ (void *) nonce,
+ (void *) &skey))
{
GNUNET_break (0);
GNUNET_free (*res);
- return;
+ return GNUNET_SYSERR;
}
- gcry_cipher_close (cipher);
+ return GNUNET_OK;
}
void
ANASTASIS_CRYPTO_user_identifier_derive (
const json_t *id_data,
- const struct ANASTASIS_CRYPTO_ProviderSaltP *server_salt,
+ const struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt,
struct ANASTASIS_CRYPTO_UserIdentifierP *id)
{
char *json_enc;
@@ -305,7 +225,7 @@ ANASTASIS_CRYPTO_user_identifier_derive (
json_enc = json_dumps (id_data,
JSON_COMPACT | JSON_SORT_KEYS);
GNUNET_assert (NULL != json_enc);
- GNUNET_CRYPTO_pow_hash (&server_salt->salt,
+ GNUNET_CRYPTO_pow_hash (&provider_salt->salt,
json_enc,
strlen (json_enc),
&hash);
@@ -321,23 +241,23 @@ ANASTASIS_CRYPTO_account_private_key_derive (
{
/* 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_CRYPTO_kdf (&priv_key->priv,
+ sizeof (priv_key->priv),
+ /* salt / XTS */
+ NULL,
+ 0,
+ /* ikm */
+ id,
+ sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
+ /* context chunks */
+ "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;
}
@@ -417,9 +337,9 @@ ANASTASIS_CRYPTO_keyshare_encrypt (
sizeof (nonce));
anastasis_encrypt (&nonce,
id,
- sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
+ sizeof (*id),
key_share,
- sizeof (struct ANASTASIS_CRYPTO_KeyShareP),
+ sizeof (*key_share),
(NULL == xsalt) ? salt : xsalt,
&eks,
&eks_size);
@@ -444,9 +364,9 @@ ANASTASIS_CRYPTO_keyshare_decrypt (
void *ks = NULL;
anastasis_decrypt (id,
- sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
+ sizeof (*id),
enc_key_share,
- sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP),
+ sizeof (*enc_key_share),
(NULL == xsalt) ? salt : xsalt,
&ks,
&ks_size);
@@ -518,105 +438,113 @@ ANASTASIS_CRYPTO_policy_key_derive (
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);
+ GNUNET_CRYPTO_kdf (policy_key,
+ sizeof (*policy_key),
+ /* salt / XTS */
+ salt,
+ sizeof (*salt),
+ /* ikm */
+ key_shares,
+ keyshare_length * sizeof (*key_shares),
+ /* info chunks */
+ "anastasis-policy-key-derive",
+ strlen ("anastasis-policy-key-derive"),
+ NULL, 0);
}
-void
+struct ANASTASIS_CoreSecretEncryptionResult *
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)
+ size_t core_secret_size)
{
- struct GNUNET_CRYPTO_SymmetricSessionKey sk;
- struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
struct GNUNET_HashCode master_key;
+ struct ANASTASIS_CoreSecretEncryptionResult *cser;
+ struct ANASTASIS_CRYPTO_NonceP nonce;
+
+ cser = GNUNET_new (struct ANASTASIS_CoreSecretEncryptionResult);
- *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));
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
+ &nonce,
+ sizeof (struct ANASTASIS_CRYPTO_NonceP));
+
+ anastasis_encrypt (&nonce,
+ &master_key,
+ sizeof (struct GNUNET_HashCode),
+ core_secret,
+ core_secret_size,
+ "cse",
+ &cser->enc_core_secret,
+ &cser->enc_core_secret_size);
+
+ /* Allocate result arrays with NULL-termination so we don't
+ need to store the length to free */
+ cser->enc_master_key_sizes = GNUNET_new_array (policy_keys_length + 1,
+ size_t);
+ cser->enc_master_keys = GNUNET_new_array (policy_keys_length + 1,
+ void *);
+
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]));
+ struct ANASTASIS_CRYPTO_NonceP nonce_i;
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
+ &nonce_i,
+ sizeof (struct ANASTASIS_CRYPTO_NonceP));
+
+ anastasis_encrypt (&nonce_i,
+ &policy_keys[i].key,
+ sizeof (struct GNUNET_HashCode),
+ &master_key,
+ sizeof (struct GNUNET_HashCode),
+ "emk",
+ &cser->enc_master_keys[i],
+ &cser->enc_master_key_sizes[i]);
}
+ return cser;
}
void
ANASTASIS_CRYPTO_core_secret_recover (
- const struct ANASTASIS_CRYPTO_EncryptedMasterKeyP *encrypted_master_key,
+ const void *encrypted_master_key,
+ size_t encrypted_master_key_size,
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;
+ void *master_key;
+ size_t master_key_size;
*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);
+ anastasis_decrypt (&policy_key->key,
+ sizeof (struct GNUNET_HashCode),
+ encrypted_master_key,
+ encrypted_master_key_size,
+ "emk",
+ &master_key,
+ &master_key_size);
+ GNUNET_break (NULL != master_key);
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);
+ anastasis_decrypt (master_key,
+ master_key_size,
+ encrypted_core_secret,
+ encrypted_core_secret_size,
+ "cse",
+ core_secret,
+ core_secret_size);
+ GNUNET_break (NULL != *core_secret);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"At %s:%d decrypted core secret is %s-%llu b\n", __FILE__,
__LINE__,
@@ -626,4 +554,78 @@ ANASTASIS_CRYPTO_core_secret_recover (
}
+void
+ANASTASIS_CRYPTO_destroy_encrypted_core_secret (
+ struct ANASTASIS_CoreSecretEncryptionResult *cser)
+{
+ for (unsigned int i = 0; NULL != cser->enc_master_keys[i]; i++)
+ GNUNET_free (cser->enc_master_keys[i]);
+ GNUNET_free (cser->enc_master_keys);
+ GNUNET_free (cser->enc_master_key_sizes);
+ GNUNET_free (cser->enc_core_secret);
+ GNUNET_free (cser);
+}
+
+
+const char *
+ANASTASIS_CRYPTO_uuid2s (const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid)
+{
+ static char uuids[7];
+ char *tpk;
+
+ tpk = GNUNET_STRINGS_data_to_string_alloc (uuid,
+ sizeof (*uuid));
+ memcpy (uuids,
+ tpk,
+ sizeof (uuids) - 1);
+ GNUNET_free (tpk);
+ return uuids;
+}
+
+
+void
+ANASTASIS_CRYPTO_recovery_metadata_encrypt (
+ const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
+ const void *meta_data,
+ size_t meta_data_size,
+ void **enc_meta_data,
+ size_t *enc_meta_data_size)
+{
+ const char *salt = "rmd";
+ struct ANASTASIS_CRYPTO_NonceP nonce;
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &nonce,
+ sizeof (nonce));
+ anastasis_encrypt (&nonce,
+ id,
+ sizeof (*id),
+ meta_data,
+ meta_data_size,
+ salt,
+ enc_meta_data,
+ enc_meta_data_size);
+}
+
+
+enum GNUNET_GenericReturnValue
+ANASTASIS_CRYPTO_recovery_metadata_decrypt (
+ const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
+ const void *enc_meta_data,
+ size_t enc_meta_data_size,
+ void **meta_data,
+ size_t *meta_data_size)
+{
+ const char *salt = "rmd";
+
+ return anastasis_decrypt (id,
+ sizeof (*id),
+ enc_meta_data,
+ enc_meta_data_size,
+ salt,
+ meta_data,
+ meta_data_size);
+}
+
+
/* end of anastasis_crypto.c */