diff options
Diffstat (limited to 'src/util/anastasis_crypto.c')
-rw-r--r-- | src/util/anastasis_crypto.c | 470 |
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 */ |