summaryrefslogtreecommitdiff
path: root/doc/sphinx/cryptography.rst
blob: 6e8c29b4bb43c21f0deb7e0a36af6fb3a1648fa9 (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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
..
  This file is part of Anastasis
  Copyright (C) 2019-2021 Anastasis SARL

  Anastasis is free software; you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free Software
  Foundation; either version 2.1, 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.

  You should have received a copy of the GNU Affero General Public License along with
  Anastasis; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>

  @author Christian Grothoff
  @author Dominik Meister
  @author Dennis Neufeld

------------
Cryptography
------------

When a user needs to interact with Anastasis, the system first derives some key
material, but not the master secret, from the user's **identifier** using
different HKDFs.  These HKDFs are salted using the respective escrow
provider's **server salt**, which ensures that the accounts for the same user
cannot be easily correlated across the various Anastasis servers.

Each Anastasis server uses an EdDSA **account key** to identify the account of
the user.  The account private key is derived from the user's **identifier** using
a computationally expensive cryptographic hash function.  Using an
expensive hash algorithm is assumed to make it infeasible for a weak adversary to
determine account keys by brute force (without knowing the user's identifier).
However, it is assumed that a strong adversary performing a targeted attack can
compute the account key pair.

The public account key is Crockford base32-encoded in the URI to identify the
account, and used to sign requests.  These signatures are also provided in
base32-encoding and transmitted using the HTTP header
``Anastasis-Account-Signature``.

When confidential data is uploaded to an Anastasis server, the respective
payload is encrypted using AES-GCM with a symmetric key and initialization
vector derived from the **identifier** and a high-entropy **nonce**.  The
nonce and the GCM tag are prepended to the ciphertext before being uploaded to
the Anastasis server.  This is done whenever confidential data is stored with
the server.

The **core secret** of the user is (AES) encrypted using a symmetric **master
key**.  Recovering this master key requires the user to satisfy a particular
**policy**.  Policies specify a set of **escrow methods**, each of which leads
the user to a **key share**. Combining those key shares (by hashing) allows
the user to obtain a **policy key**, which can be used to decrypt the **master
key**.  There can be many policies, satisfying any of these will allow the
user to recover the master key.  A **recovery document** contains the
encrypted **core secret**, a set of escrow methods and a set of policies.




Key derivations
^^^^^^^^^^^^^^^

EdDSA and ECDHE public keys are always points on Curve25519 and represented
using the standard 256 bit Ed25519 compact format.  The binary representation
is converted to Crockford Base32 when transmitted inside JSON or as part of
URLs.

To start, a user provides their private, unique and unforgettable
**identifier** as a seed to identify their account.  For example, this could
be a social security number together with their full name.  Specifics may
depend on the cultural context, in this document we will simply refer to this
information as the **identifier**.

This identifier will be first hashed with Argon2, to provide a **kdf_id**
which will be used to derive other keys later. The Hash must also include the
respective **server_salt**. This also ensures that the **kdf_id** is different
on each server. The use of Argon2 and the respective **server_salt** is intended
to make it difficult to brute-force **kdf_id** values and help protect the user's
privacy. Also this ensures that the **kdf_id**\ s on every server differs. However,
we do not assume that the **identifier** or the **kdf_id** cannot be
determined by an adversary performing a targeted attack, as a user's
**identifier** is likely to always be known to state actors and may
likely also be available to other actors.


.. code-block:: none

    kdf_id := Argon2( identifier, server_salt, keysize )

**identifier**: The secret defined from the user beforehand.

**server_salt**: The salt from the Server.

**keysize**: The desired output size of the KDF, here 32 bytes.


Verification
------------

For users to authorize "policy" operations we need an EdDSA key pair.  As we
cannot assure that the corresponding private key is truly secret, such policy
operations must never be destructive: Should an adversary learn the private
key, they could access (and with the **kdf_id**, decrypt) the user's policy (but
not the core secret), or upload a new version of the
**encrypted recovery document** (but not delete an existing version).

For the generation of the private key we use the **kdf_id** as the entropy source,
hash it to derive a base secret which will then be processed to fit the
requirements for EdDSA private keys.  From the private key we can then
generate the corresponding public key.  Here, "ver" is used as a salt for the
HKDF to ensure that the result differs from other cases where we hash
**kdf_id**.

.. code-block:: none

    ver_secret := HKDF(kdf_id, "ver", keysize)
    eddsa_priv := eddsa_d_to_a(ver_secret)
    eddsa_pub := get_EdDSA_Pub(eddsa_priv)


**HKDF()**: The HKDF-function uses two phases: First we use HMAC-SHA512 for the extraction phase, then HMAC-SHA256 is used for expansion phase.

**kdf_id**: Hashed identifier.

**key_size**: Size of the output, here 32 bytes.

**ver_secret**: Derived key from the ``kdf_id``, serves as intermediate step for the generation of the private key.

**eddsa_d_to_a()**: Function which converts the ver_key to a valid EdDSA private key. Specifically, assuming the value ``eddsa_priv`` is in a 32-byte array "digest", the function clears and sets certain bits as follows:

.. code-block:: c

   digest[0] = (digest[0] & 0x7f) | 0x40;
   digest[31] &= 0xf8;

**eddsa_priv**: The generated EdDSA private key.

**eddsa_pub**: The generated EdDSA public key.


Encryption
----------

For symmetric encryption of data we use AES256-GCM. For this we need a
symmetric key and an initialization vector (IV).  To ensure that the
symmetric key changes for each encryption operation, we compute the
key material using an HKDF over a ``nonce`` and the ``kdf_id``.

.. code-block:: none

    (iv,key) := HKDF(kdf_id, nonce, keysize + ivsize)

**HKDF()**: The HKDF-function uses two phases: First we use HMAC-SHA512 for the extraction phase, then HMAC-SHA256 is used for expansion phase.

**kdf_id**: Hashed identifier.

**keysize**: Size of the AES symmetric key, here 32 bytes.

**ivsize**: Size of the AES GCM IV, here 12 bytes.

**prekey**: Original key material.

**nonce**: 32-byte nonce, must never match "ver" (which it cannot as the length is different). Of course, we must
avoid key reuse. So, we have to use different nonces to get different keys and IVs (see below).

**key**: Symmetric key which is later used to encrypt the documents with AES256-GCM.

**iv**: IV which will be used for AES-GCM.



Key Usage
^^^^^^^^^

The keys we have generated are then used to encrypt the **recovery document** and
the **key_share** of the user.


Encryption
----------

Before every encryption a 32-byte nonce is generated.
From this the symmetric key is computed as described above.
We use AES256-GCM for the encryption of the **recovery document** and
the **key_share**.  To ensure that the key derivation for the encryption
of the **recovery document** differs fundamentally from that of an
individual **key share**, we use different salts ("erd" and "eks", respectively).

.. code-block:: none

    (iv0, key0) := HKDF(key_id, nonce0, "erd", keysize + ivsize)
    (encrypted_recovery_document, aes_gcm_tag) := AES256_GCM(recovery_document, key0, iv0)
    (iv_i, key_i) := HKDF(key_id, nonce_i, "eks", [optional data], keysize + ivsize)
    (encrypted_key_share_i, aes_gcm_tag_i) := AES256_GCM(key_share_i, key_i, iv_i)

**encrypted_recovery_document**: The encrypted **recovery document** which contains the escrow methods, policies
and the encrypted **core secret**.

**nonce0**: Nonce which is used to generate *key0* and *iv0* which are used for the encryption of the *recovery document*.
Nonce must contain the string "ERD".

**optional data**: Key material that optionally is contributed from the authentication method to further obfuscate the key share from the escrow provider.

**encrypted_key_share_i**: The encrypted **key_share** which the escrow provider must release upon successful authentication.
Here, **i** must be a positive number used to iterate over the various **key shares** used for the various **escrow methods**
at the various providers.

**nonce_i**: Nonce which is used to generate *key_i* and *iv_i* which are used for the encryption of the **key share**. **i** must be
the same number as specified above for *encrypted_key_share_i*. Nonce must contain the string "EKS" plus the according *i*.

As a special rule, when a **security question** is used to authorize access to an
**encrypted_key_share_i**, then the salt "eks" is replaced with an (expensive) hash
of the answer to the security question as an additional way to make the key share
inaccessible to those who do not have the answer:

.. code-block:: none

   powh := POW_HASH (qsalt, answer)
   ekss := HKDF("Anastasis-secure-question-uuid-salting",
                powh,
                uuid);
   (iv_i, key_i) := HKDF(key_id, nonce_i, ekss, [optional data], keysize + ivsize)


**qsalt**: Salt value used to hash answer to satisfy the challenge to prevent the provider from determining the answer via guessing.

**answer**: Answer to the security question, in UTF-8, as entered by the user.

**powh**: Result of the (expensive, proof-of-work) hash algorithm.

**uuid**: UUID of the challenge associated with the security question and the encrypted key share.

**ekss**: Replacement salt to be used instead of "eks" when deriving the key to encrypt/decrypt the key share.


Signatures
----------

The EdDSA keys are used to sign the data sent from the client to the
server. Everything the client sends to server is signed. The following
algorithm is equivalent for **Anastasis-Policy-Signature**.

.. code-block:: none

    (anastasis-account-signature) := eddsa_sign(h_body, eddsa_priv)
    ver_res := eddsa_verifiy(h_body, anastasis-account-signature, eddsa_pub)

**anastasis-account-signature**: Signature over the SHA-512 hash of the body using the purpose code ``TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD`` (1400) (see GNUnet EdDSA signature API for the use of purpose).

**h_body**: The hashed body.

**ver_res**: A boolean value. True: Signature verification passed, False: Signature verification failed.


When requesting policy downloads, the client must also provide a signature:

.. code-block:: none

    (anastasis-account-signature) := eddsa_sign(version, eddsa_priv)
    ver_res := eddsa_verifiy(version, anastasis-account-signature, eddsa_pub)

**anastasis-account-signature**: Signature over the SHA-512 hash of the body using the purpose code ``TALER_SIGNATURE_ANASTASIS_POLICY_DOWNLOAD`` (1401) (see GNUnet EdDSA signature API for the use of purpose).

**version**: The version requested as a 64-bit integer, 2^64-1 for the "latest version".

**ver_res**: A boolean value. True: Signature verification passed, False: Signature verification failed.



Availability Considerations
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Anastasis considers two main threats against availability. First, the
Anastasis server operators must be protected against denial-of-service attacks
where an adversary attempts to exhaust the operator's resources.  The API protects
against these attacks by allowing operators to set fees for all
operations. Furthermore, all data stored comes with an expiration logic, so an
attacker cannot force servers to store data indefinitely.

A second availability issue arises from strong adversaries that may be able to
compute the account keys of some user.  While we assume that such an adversary
cannot successfully authenticate against the truth, the account key does
inherently enable these adversaries to upload a new policy for the account.
This cannot be prevented, as the legitimate user must be able to set or change
a policy using only the account key.  To ensure that an adversary cannot
exploit this, policy uploads first of all never delete existing policies, but
merely create another version.  This way, even if an adversary uploads a
malicious policy, a user can still retrieve an older version of the policy to
recover access to their data.  This append-only storage for policies still
leaves a strong adversary with the option of uploading many policies to
exhaust the Anastasis server's capacity.  We limit this attack by requiring a
policy upload to include a reference to a **payment identifier** from a payment
made by the user.  Thus, a policy upload requires both knowledge of the
**identity** and making a payment.  This effectively prevents an adversary
from using the append-only policy storage from exhausting Anastasis server
capacity.