summaryrefslogtreecommitdiff
path: root/src/util/crypto.c
blob: b4a4a718b3ecd831c939c31e23ea4a121736aa60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
  This file is part of TALER
  (C) 2014 Christian Grothoff (and other contributing authors)

  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, If not, see <http://www.gnu.org/licenses/>
*/

/**
 * @file crypto.c
 * @brief Cryptographic utility functions
 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
 * @author Florian Dold
 * @author Benedikt Mueller
 */

#include "platform.h"
#include "taler_util.h"
#include <gnunet/gnunet_common.h>
#include <gnunet/gnunet_util_lib.h>
#include <gcrypt.h>

#define CURVE "Ed25519"


static void
fatal_error_handler (void *cls, int wtf, const char *msg)
{
  LOG_ERROR("Fatal error in Gcrypt: %s\n", msg);
  abort();
}


/**
 * Initialize Gcrypt library.
 */
void
TALER_gcrypt_init()
{
  gcry_set_fatalerror_handler (&fatal_error_handler, NULL);
  TALER_assert_as(gcry_check_version(NEED_LIBGCRYPT_VERSION),
                  "libgcrypt version mismatch");
  /* Disable secure memory.  */
  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
}


/**
 * Derive symmetric key material for refresh operations from
 * a given shared secret.
 *
 * @param secret the shared secret
 * @param[out] iv set to initialization vector
 * @param[out] skey set to session key
 */
static void
derive_refresh_key (const struct GNUNET_HashCode *secret,
                    struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
                    struct GNUNET_CRYPTO_SymmetricSessionKey *skey)
{
  static const char ctx_key[] = "taler-key-skey";
  static const char ctx_iv[] = "taler-key-iv";

  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
                                    ctx_key, strlen (ctx_key),
                                    secret, sizeof (struct GNUNET_HashCode),
                                    NULL, 0));
  GNUNET_assert (GNUNET_YES ==
                 GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
                                    ctx_iv, strlen (ctx_iv),
                                    secret, sizeof (struct GNUNET_HashCode),
                                    NULL, 0));
}


/**
 * Decrypt refresh link information.
 *
 * @param input encrypted refresh link data
 * @param secret shared secret to use for decryption
 * @return NULL on error
 */
struct TALER_RefreshLinkDecrypted *
TALER_refresh_decrypt (const struct TALER_RefreshLinkEncrypted *input,
                       const struct GNUNET_HashCode *secret)
{
  struct TALER_RefreshLinkDecrypted *ret;
  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  struct GNUNET_CRYPTO_SymmetricSessionKey skey;
  size_t buf_size = input->blinding_key_enc_size
    + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
  char buf[buf_size];

  GNUNET_assert (input->blinding_key_enc == (const char *) &input[1]);
  derive_refresh_key (secret, &iv, &skey);
  if (GNUNET_OK !=
      GNUNET_CRYPTO_symmetric_decrypt (input->coin_priv_enc,
                                       buf_size,
                                       &skey,
                                       &iv,
                                       buf))
    return NULL;
  ret = GNUNET_new (struct TALER_RefreshLinkDecrypted);
  memcpy (&ret->coin_priv,
          buf,
          sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
  ret->blinding_key
    = GNUNET_CRYPTO_rsa_blinding_key_decode (&buf[sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)],
                                             input->blinding_key_enc_size);
  if (NULL == ret->blinding_key)
  {
    GNUNET_free (ret);
    return NULL;
  }
  return ret;
}


/**
 * Encrypt refresh link information.
 *
 * @param input plaintext refresh link data
 * @param secret shared secret to use for encryption
 * @return NULL on error (should never happen)
 */
struct TALER_RefreshLinkEncrypted *
TALER_refresh_encrypt (const struct TALER_RefreshLinkDecrypted *input,
                       const struct GNUNET_HashCode *secret)
{
  char *b_buf;
  size_t b_buf_size;
  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  struct GNUNET_CRYPTO_SymmetricSessionKey skey;
  struct TALER_RefreshLinkEncrypted *ret;

  derive_refresh_key (secret, &iv, &skey);
  b_buf_size = GNUNET_CRYPTO_rsa_blinding_key_encode (input->blinding_key,
                                                      &b_buf);
  ret = GNUNET_malloc (sizeof (struct TALER_RefreshLinkEncrypted) +
                       b_buf_size);
  ret->blinding_key_enc = (const char *) &ret[1];
  ret->blinding_key_enc_size = b_buf_size;
  {
    size_t buf_size = b_buf_size + sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey);
    char buf[buf_size];

    memcpy (buf,
            &input->coin_priv,
            sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
    memcpy (&buf[sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)],
            b_buf,
            b_buf_size);

    if (GNUNET_OK !=
        GNUNET_CRYPTO_symmetric_encrypt (buf,
                                         buf_size,
                                         &skey,
                                         &iv,
                                         ret->coin_priv_enc))
    {
      GNUNET_free (ret);
      return NULL;
    }
  }
  return ret;
}


/* end of crypto.c */