anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

anastasis_crypto.c (19061B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2020 Anastasis SARL
      4 
      5   Anastasis is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file util/anastasis_crypto.c
     18  * @brief anastasis crypto api
     19  * @author Christian Grothoff
     20  * @author Dominik Meister
     21  * @author Dennis Neufeld
     22  */
     23 #include "platform.h"
     24 #include "anastasis_crypto_lib.h"
     25 #include <gcrypt.h>
     26 #include <taler/taler_json_lib.h>
     27 #include <gnunet/gnunet_util_lib.h>
     28 #include <string.h>
     29 
     30 
     31 void
     32 ANASTASIS_hash_answer (uint64_t code,
     33                        struct GNUNET_HashCode *hashed_code)
     34 {
     35   char cbuf[40];
     36 
     37   GNUNET_snprintf (cbuf,
     38                    sizeof (cbuf),
     39                    "%llu",
     40                    (unsigned long long) code);
     41   GNUNET_CRYPTO_hash (cbuf,
     42                       strlen (cbuf),
     43                       hashed_code);
     44   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     45               "Hashed answer to %s\n",
     46               GNUNET_h2s (hashed_code));
     47 }
     48 
     49 
     50 void
     51 ANASTASIS_CRYPTO_secure_answer_hash (
     52   const char *answer,
     53   const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid,
     54   const struct ANASTASIS_CRYPTO_QuestionSaltP *salt,
     55   struct GNUNET_HashCode *result)
     56 {
     57   struct GNUNET_HashCode pow;
     58 
     59   GNUNET_CRYPTO_pow_hash (&salt->pow_salt,
     60                           answer,
     61                           strlen (answer),
     62                           &pow);
     63   GNUNET_assert (GNUNET_YES ==
     64                  GNUNET_CRYPTO_hkdf_gnunet (
     65                    result,
     66                    sizeof (*result),
     67                    /* salt / XTS */
     68                    uuid,
     69                    sizeof (*uuid),
     70                    /* skm */
     71                    &pow,
     72                    sizeof (pow),
     73                    GNUNET_CRYPTO_kdf_arg_string (
     74                      "anastasis-secure-question-hashing")));
     75 }
     76 
     77 
     78 /**
     79  * Compute @a key.
     80  *
     81  * @param key_material key for calculation
     82  * @param key_m_len length of key
     83  * @param nonce nonce for calculation
     84  * @param salt salt value for calculation
     85  * @param[out] key where to write the en-/description key
     86  */
     87 static void
     88 derive_key (const void *key_material,
     89             size_t key_m_len,
     90             const struct ANASTASIS_CRYPTO_NonceP *nonce,
     91             const char *salt,
     92             struct ANASTASIS_CRYPTO_SymKeyP *key)
     93 {
     94   GNUNET_assert (GNUNET_YES ==
     95                  GNUNET_CRYPTO_hkdf_gnunet (
     96                    key,
     97                    sizeof (*key),
     98                    /* salt / XTS */
     99                    nonce,
    100                    sizeof (*nonce),
    101                    /* ikm */
    102                    key_material,
    103                    key_m_len,
    104                    /* info chunks */
    105                    /* The "salt" passed here is actually not something random,
    106                       but a protocol-specific identifier string.  Thus
    107                       we pass it as a context info to the HKDF */
    108                    GNUNET_CRYPTO_kdf_arg_string (salt)));
    109 }
    110 
    111 
    112 /**
    113  * Encryption of data like recovery document etc.
    114  *
    115  * @param nonce value to use for the nonce
    116  * @param key key which is used to derive a key/iv pair from
    117  * @param key_len length of key
    118  * @param data data to encrypt
    119  * @param data_size size of the data
    120  * @param salt salt value which is used for key derivation
    121  * @param[out] res ciphertext output
    122  * @param[out] res_size size of the ciphertext
    123  */
    124 static void
    125 anastasis_encrypt (const struct ANASTASIS_CRYPTO_NonceP *nonce,
    126                    const void *key,
    127                    size_t key_len,
    128                    const void *data,
    129                    size_t data_size,
    130                    const char *salt,
    131                    void **res,
    132                    size_t *res_size)
    133 {
    134   size_t ciphertext_size;
    135   struct ANASTASIS_CRYPTO_SymKeyP skey;
    136 
    137   derive_key (key,
    138               key_len,
    139               nonce,
    140               salt,
    141               &skey);
    142   ciphertext_size = crypto_secretbox_NONCEBYTES
    143                     + crypto_secretbox_MACBYTES + data_size;
    144   *res_size = ciphertext_size;
    145   *res = GNUNET_malloc (ciphertext_size);
    146   memcpy (*res, nonce, crypto_secretbox_NONCEBYTES);
    147   GNUNET_assert (0 ==
    148                  crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES,
    149                                         data,
    150                                         data_size,
    151                                         (void *) nonce,
    152                                         (void *) &skey));
    153 }
    154 
    155 
    156 /**
    157  * Decryption of data like encrypted recovery document etc.
    158  *
    159  * @param key key which is used to derive a key/iv pair from
    160  * @param key_len length of key
    161  * @param data data to decrypt
    162  * @param data_size size of the data
    163  * @param salt salt value which is used for key derivation
    164  * @param[out] res plaintext output
    165  * @param[out] res_size size of the plaintext
    166  * @return #GNUNET_OK on success
    167  */
    168 static enum GNUNET_GenericReturnValue
    169 anastasis_decrypt (const void *key,
    170                    size_t key_len,
    171                    const void *data,
    172                    size_t data_size,
    173                    const char *salt,
    174                    void **res,
    175                    size_t *res_size)
    176 {
    177   const struct ANASTASIS_CRYPTO_NonceP *nonce;
    178   struct ANASTASIS_CRYPTO_SymKeyP skey;
    179   size_t plaintext_size;
    180 
    181   if (data_size < crypto_secretbox_NONCEBYTES + crypto_secretbox_MACBYTES)
    182   {
    183     /* short ciphertext is what a hostile provider sends, not a local bug */
    184     GNUNET_break_op (0);
    185     *res = NULL;
    186     *res_size = 0;
    187     return GNUNET_SYSERR;
    188   }
    189   nonce = data;
    190   derive_key (key,
    191               key_len,
    192               nonce,
    193               salt,
    194               &skey);
    195   plaintext_size = data_size - (crypto_secretbox_NONCEBYTES
    196                                 + crypto_secretbox_MACBYTES);
    197   *res = GNUNET_malloc (plaintext_size);
    198   *res_size = plaintext_size;
    199   if (0 != crypto_secretbox_open_easy (*res,
    200                                        data + crypto_secretbox_NONCEBYTES,
    201                                        data_size - crypto_secretbox_NONCEBYTES,
    202                                        (void *) nonce,
    203                                        (void *) &skey))
    204   {
    205     /* likewise: a wrong answer or a hostile provider, not a local bug */
    206     GNUNET_break_op (0);
    207     GNUNET_free (*res);
    208     *res = NULL;
    209     *res_size = 0;
    210     return GNUNET_SYSERR;
    211   }
    212   return GNUNET_OK;
    213 }
    214 
    215 
    216 void
    217 ANASTASIS_CRYPTO_user_identifier_derive (
    218   const json_t *id_data,
    219   const struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt,
    220   struct ANASTASIS_CRYPTO_UserIdentifierP *id)
    221 {
    222   char *json_enc;
    223   struct GNUNET_HashCode hash;
    224 
    225   json_enc = json_dumps (id_data,
    226                          JSON_COMPACT | JSON_SORT_KEYS);
    227   GNUNET_assert (NULL != json_enc);
    228   GNUNET_CRYPTO_pow_hash (&provider_salt->salt,
    229                           json_enc,
    230                           strlen (json_enc),
    231                           &hash);
    232   id->hash = hash;
    233   free (json_enc);
    234 }
    235 
    236 
    237 void
    238 ANASTASIS_CRYPTO_account_private_key_derive (
    239   const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
    240   struct ANASTASIS_CRYPTO_AccountPrivateKeyP *priv_key)
    241 {
    242   /* priv_key = ver_secret */
    243   GNUNET_assert (GNUNET_YES ==
    244                  GNUNET_CRYPTO_hkdf_gnunet (
    245                    &priv_key->priv,
    246                    sizeof (priv_key->priv),
    247                    /* salt / XTS */
    248                    NULL,
    249                    0,
    250                    /* ikm */
    251                    id,
    252                    sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
    253                    /* context chunks */
    254                    GNUNET_CRYPTO_kdf_arg_string ("ver")));
    255 }
    256 
    257 
    258 void
    259 ANASTASIS_CRYPTO_account_public_key_derive (
    260   const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
    261   struct ANASTASIS_CRYPTO_AccountPublicKeyP *pub_key)
    262 {
    263   struct ANASTASIS_CRYPTO_AccountPrivateKeyP priv;
    264 
    265   ANASTASIS_CRYPTO_account_private_key_derive (id,
    266                                                &priv);
    267   GNUNET_CRYPTO_eddsa_key_get_public (&priv.priv,
    268                                       &pub_key->pub);
    269 }
    270 
    271 
    272 void
    273 ANASTASIS_CRYPTO_recovery_document_encrypt (
    274   const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
    275   const void *rec_doc,
    276   size_t rd_size,
    277   void **enc_rec_doc,
    278   size_t *erd_size)
    279 {
    280   const char *salt = "erd";
    281   struct ANASTASIS_CRYPTO_NonceP nonce;
    282 
    283   GNUNET_CRYPTO_random_block (&nonce,
    284                               sizeof (nonce));
    285   anastasis_encrypt (&nonce,
    286                      id,
    287                      sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
    288                      rec_doc,
    289                      rd_size,
    290                      salt,
    291                      enc_rec_doc,
    292                      erd_size);
    293 }
    294 
    295 
    296 enum GNUNET_GenericReturnValue
    297 ANASTASIS_CRYPTO_recovery_document_decrypt (
    298   const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
    299   const void *enc_rec_doc,
    300   size_t erd_size,
    301   void **rec_doc,
    302   size_t *rd_size)
    303 {
    304   const char *salt = "erd";
    305 
    306   return anastasis_decrypt (id,
    307                             sizeof (struct ANASTASIS_CRYPTO_UserIdentifierP),
    308                             enc_rec_doc,
    309                             erd_size,
    310                             salt,
    311                             rec_doc,
    312                             rd_size);
    313 }
    314 
    315 
    316 void
    317 ANASTASIS_CRYPTO_keyshare_encrypt (
    318   const struct ANASTASIS_CRYPTO_KeyShareP *key_share,
    319   const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
    320   const char *xsalt,
    321   struct ANASTASIS_CRYPTO_EncryptedKeyShareP *enc_key_share)
    322 {
    323   const char *salt = "eks";
    324   size_t eks_size = 0;
    325   void *eks = NULL;
    326   struct ANASTASIS_CRYPTO_NonceP nonce;
    327 
    328   GNUNET_CRYPTO_random_block (&nonce,
    329                               sizeof (nonce));
    330   anastasis_encrypt (&nonce,
    331                      id,
    332                      sizeof (*id),
    333                      key_share,
    334                      sizeof (*key_share),
    335                      (NULL == xsalt) ? salt : xsalt,
    336                      &eks,
    337                      &eks_size);
    338   GNUNET_assert (eks_size ==
    339                  sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP));
    340   memcpy (enc_key_share,
    341           eks,
    342           sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP));
    343   GNUNET_free (eks);
    344 }
    345 
    346 
    347 enum GNUNET_GenericReturnValue
    348 ANASTASIS_CRYPTO_keyshare_decrypt (
    349   const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *enc_key_share,
    350   const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
    351   const char *xsalt,
    352   struct ANASTASIS_CRYPTO_KeyShareP *key_share)
    353 {
    354   const char *salt = "eks";
    355   size_t ks_size = 0;
    356   void *ks = NULL;
    357 
    358   if (GNUNET_OK !=
    359       anastasis_decrypt (id,
    360                          sizeof (*id),
    361                          enc_key_share,
    362                          sizeof (*enc_key_share),
    363                          (NULL == xsalt) ? salt : xsalt,
    364                          &ks,
    365                          &ks_size))
    366     return GNUNET_SYSERR;
    367   if (ks_size !=
    368       sizeof (struct ANASTASIS_CRYPTO_KeyShareP))
    369   {
    370     /* the ciphertext came from an untrusted provider, so a wrong
    371        plaintext size must not be an assertion */
    372     GNUNET_break_op (0);
    373     GNUNET_free (ks);
    374     return GNUNET_SYSERR;
    375   }
    376   memcpy (key_share,
    377           ks,
    378           sizeof (struct ANASTASIS_CRYPTO_KeyShareP));
    379   GNUNET_free (ks);
    380   return GNUNET_OK;
    381 }
    382 
    383 
    384 void
    385 ANASTASIS_CRYPTO_truth_encrypt (
    386   const struct ANASTASIS_CRYPTO_NonceP *nonce,
    387   const struct ANASTASIS_CRYPTO_TruthKeyP *truth_enc_key,
    388   const void *truth,
    389   size_t truth_size,
    390   void **enc_truth,
    391   size_t *ect_size)
    392 {
    393   const char *salt = "ect";
    394 
    395   anastasis_encrypt (nonce,
    396                      truth_enc_key,
    397                      sizeof (struct ANASTASIS_CRYPTO_TruthKeyP),
    398                      truth,
    399                      truth_size,
    400                      salt,
    401                      enc_truth,
    402                      ect_size);
    403 }
    404 
    405 
    406 enum GNUNET_GenericReturnValue
    407 ANASTASIS_CRYPTO_truth_decrypt (
    408   const struct ANASTASIS_CRYPTO_TruthKeyP *truth_enc_key,
    409   const void *enc_truth,
    410   size_t ect_size,
    411   void **truth,
    412   size_t *truth_size)
    413 {
    414   const char *salt = "ect";
    415 
    416   return anastasis_decrypt (truth_enc_key,
    417                             sizeof (struct ANASTASIS_CRYPTO_TruthKeyP),
    418                             enc_truth,
    419                             ect_size,
    420                             salt,
    421                             truth,
    422                             truth_size);
    423 }
    424 
    425 
    426 void
    427 ANASTASIS_CRYPTO_keyshare_create (
    428   struct ANASTASIS_CRYPTO_KeyShareP *key_share)
    429 {
    430   GNUNET_CRYPTO_random_block (key_share,
    431                               sizeof (struct ANASTASIS_CRYPTO_KeyShareP));
    432 }
    433 
    434 
    435 void
    436 ANASTASIS_CRYPTO_policy_key_derive (
    437   const struct ANASTASIS_CRYPTO_KeyShareP *key_shares,
    438   unsigned int keyshare_length,
    439   const struct ANASTASIS_CRYPTO_MasterSaltP *salt,
    440   struct ANASTASIS_CRYPTO_PolicyKeyP *policy_key)
    441 {
    442   GNUNET_assert (GNUNET_YES ==
    443                  GNUNET_CRYPTO_hkdf_gnunet (
    444                    policy_key,
    445                    sizeof (*policy_key),
    446                    /* salt / XTS */
    447                    salt,
    448                    sizeof (*salt),
    449                    /* ikm */
    450                    key_shares,
    451                    keyshare_length * sizeof (*key_shares),
    452                    /* info chunks */
    453                    GNUNET_CRYPTO_kdf_arg_string (
    454                      "anastasis-policy-key-derive")));
    455 }
    456 
    457 
    458 struct ANASTASIS_CoreSecretEncryptionResult *
    459 ANASTASIS_CRYPTO_core_secret_encrypt (
    460   const struct ANASTASIS_CRYPTO_PolicyKeyP *policy_keys,
    461   unsigned int policy_keys_length,
    462   const void *core_secret,
    463   size_t core_secret_size)
    464 {
    465   struct GNUNET_HashCode master_key;
    466   struct ANASTASIS_CoreSecretEncryptionResult *cser;
    467   struct ANASTASIS_CRYPTO_NonceP nonce;
    468 
    469   cser = GNUNET_new (struct ANASTASIS_CoreSecretEncryptionResult);
    470 
    471   GNUNET_CRYPTO_random_block (&master_key,
    472                               sizeof (struct GNUNET_HashCode));
    473   GNUNET_CRYPTO_random_block (&nonce,
    474                               sizeof (struct ANASTASIS_CRYPTO_NonceP));
    475 
    476   anastasis_encrypt (&nonce,
    477                      &master_key,
    478                      sizeof (struct GNUNET_HashCode),
    479                      core_secret,
    480                      core_secret_size,
    481                      "cse",
    482                      &cser->enc_core_secret,
    483                      &cser->enc_core_secret_size);
    484 
    485   /* Allocate result arrays with NULL-termination so we don't
    486      need to store the length to free */
    487   cser->enc_master_key_sizes = GNUNET_new_array (policy_keys_length + 1,
    488                                                  size_t);
    489   cser->enc_master_keys = GNUNET_new_array (policy_keys_length + 1,
    490                                             void *);
    491 
    492   for (unsigned int i = 0; i < policy_keys_length; i++)
    493   {
    494     struct ANASTASIS_CRYPTO_NonceP nonce_i;
    495 
    496     GNUNET_CRYPTO_random_block (&nonce_i,
    497                                 sizeof (struct ANASTASIS_CRYPTO_NonceP));
    498 
    499     anastasis_encrypt (&nonce_i,
    500                        &policy_keys[i].key,
    501                        sizeof (struct GNUNET_HashCode),
    502                        &master_key,
    503                        sizeof (struct GNUNET_HashCode),
    504                        "emk",
    505                        &cser->enc_master_keys[i],
    506                        &cser->enc_master_key_sizes[i]);
    507   }
    508   return cser;
    509 }
    510 
    511 
    512 enum GNUNET_GenericReturnValue
    513 ANASTASIS_CRYPTO_core_secret_recover (
    514   const void *encrypted_master_key,
    515   size_t encrypted_master_key_size,
    516   const struct ANASTASIS_CRYPTO_PolicyKeyP *policy_key,
    517   const void *encrypted_core_secret,
    518   size_t encrypted_core_secret_size,
    519   void **core_secret,
    520   size_t *core_secret_size)
    521 {
    522   void *master_key;
    523   size_t master_key_size;
    524 
    525   *core_secret = NULL;
    526   *core_secret_size = 0;
    527   if (GNUNET_OK !=
    528       anastasis_decrypt (&policy_key->key,
    529                          sizeof (struct GNUNET_HashCode),
    530                          encrypted_master_key,
    531                          encrypted_master_key_size,
    532                          "emk",
    533                          &master_key,
    534                          &master_key_size))
    535   {
    536     /* the key shares came from providers we do not trust, so failing to
    537        reassemble the master key is an expected outcome, not a bug */
    538     GNUNET_break_op (0);
    539     return GNUNET_SYSERR;
    540   }
    541   if (GNUNET_OK !=
    542       anastasis_decrypt (master_key,
    543                          master_key_size,
    544                          encrypted_core_secret,
    545                          encrypted_core_secret_size,
    546                          "cse",
    547                          core_secret,
    548                          core_secret_size))
    549   {
    550     GNUNET_break_op (0);
    551     GNUNET_free (master_key);
    552     return GNUNET_SYSERR;
    553   }
    554   GNUNET_free (master_key);
    555   /* Deliberately not logged: TALER_b2s() of the core secret is a ~40 bit
    556      fingerprint of it, which is enough to confirm a guess for anyone who can
    557      read the debug log. */
    558   return GNUNET_OK;
    559 }
    560 
    561 
    562 void
    563 ANASTASIS_CRYPTO_destroy_encrypted_core_secret (
    564   struct ANASTASIS_CoreSecretEncryptionResult *cser)
    565 {
    566   for (unsigned int i = 0; NULL != cser->enc_master_keys[i]; i++)
    567     GNUNET_free (cser->enc_master_keys[i]);
    568   GNUNET_free (cser->enc_master_keys);
    569   GNUNET_free (cser->enc_master_key_sizes);
    570   GNUNET_free (cser->enc_core_secret);
    571   GNUNET_free (cser);
    572 }
    573 
    574 
    575 const char *
    576 ANASTASIS_CRYPTO_uuid2s (const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid)
    577 {
    578   static char uuids[7];
    579   char *tpk;
    580 
    581   tpk = GNUNET_STRINGS_data_to_string_alloc (uuid,
    582                                              sizeof (*uuid));
    583   memcpy (uuids,
    584           tpk,
    585           sizeof (uuids) - 1);
    586   GNUNET_free (tpk);
    587   return uuids;
    588 }
    589 
    590 
    591 void
    592 ANASTASIS_CRYPTO_recovery_metadata_encrypt (
    593   const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
    594   const void *meta_data,
    595   size_t meta_data_size,
    596   void **enc_meta_data,
    597   size_t *enc_meta_data_size)
    598 {
    599   const char *salt = "rmd";
    600   struct ANASTASIS_CRYPTO_NonceP nonce;
    601 
    602   GNUNET_CRYPTO_random_block (&nonce,
    603                               sizeof (nonce));
    604   anastasis_encrypt (&nonce,
    605                      id,
    606                      sizeof (*id),
    607                      meta_data,
    608                      meta_data_size,
    609                      salt,
    610                      enc_meta_data,
    611                      enc_meta_data_size);
    612 }
    613 
    614 
    615 enum GNUNET_GenericReturnValue
    616 ANASTASIS_CRYPTO_recovery_metadata_decrypt (
    617   const struct ANASTASIS_CRYPTO_UserIdentifierP *id,
    618   const void *enc_meta_data,
    619   size_t enc_meta_data_size,
    620   void **meta_data,
    621   size_t *meta_data_size)
    622 {
    623   const char *salt = "rmd";
    624 
    625   return anastasis_decrypt (id,
    626                             sizeof (*id),
    627                             enc_meta_data,
    628                             enc_meta_data_size,
    629                             salt,
    630                             meta_data,
    631                             meta_data_size);
    632 }
    633 
    634 
    635 /* end of anastasis_crypto.c */