-
Notifications
You must be signed in to change notification settings - Fork 41
Initial version key uvf documentation. #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
chenkins
wants to merge
14
commits into
cryptomator:main
Choose a base branch
from
chenkins:feature/uvf
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 6 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
dcece52
Initial version key uvf documentation.
chenkins 4530bc6
Add diagrams and describe key rotation steps.
chenkins 00f1747
Update source/security/uvf.rst
chenkins a533c8d
Update source/security/uvf.rst
chenkins 6d24faf
Update source/security/uvf.rst
chenkins c96a339
Update source/security/uvf.rst
chenkins 06d6b25
Update source/security/uvf.rst
chenkins 64fd5c7
Update source/security/uvf.rst
chenkins dbf6c1c
Apply suggestions from code review
chenkins c97196e
Update source/security/architecture.rst
chenkins e30010a
Update source/security/architecture.rst
chenkins ea058ff
Update source/security/uvf.rst
chenkins 0052574
Fix broken sentence.
chenkins cdfb79f
Merge branch 'main' into feature/uvf
overheadhunter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -160,4 +160,53 @@ When unlocking a vault the KEK is used to unwrap (i.e. decrypt) the stored maste | |
.. image:: ../img/security/[email protected] | ||
:alt: Masterkey Decryption | ||
:width: 440px | ||
:align: center | ||
:align: center | ||
|
||
|
||
Key Rotation: Multiple Masterkey Generations using Cryptomator Hub with Universal Vault Format | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
`Unified Vault Format (uvf) <https://github.com/encryption-alliance/unified-vault-format>`_ | ||
defines a common vendor-independent standard based on `Vault Format 8 <https://docs.cryptomator.org/en/latest/misc/vault-format-history/>`_. | ||
|
||
The uvf metadata file ``vault.uvf`` replaces the ``vault.cryptomator`` file. | ||
It is both stored in the vault as file and uploaded to hub. | ||
chenkins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
It can contain many key generations - only the latest generation is used for data encryption. | ||
The older generations are used to read the older data encrypted with previous generation keys. | ||
See :ref:`Key Rotation <security/uvf/key-rotation>` for more details. | ||
|
||
Cryptomator hub `1.3.0 <https://github.com/cryptomator/hub/releases/tag/1.3.0>`_) introduced user-specific vault access token JWE containing the vault masterkey for data encryption. | ||
In the uvf setting, the uvf metadata (with the current and older (master)key generations. | ||
chenkins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Instead, it will contain a Vault Member key, which allows to decrypt the ``vault.uvf`` metadata. | ||
Specifically, a Vault Owner will have an access token under ``/access-token`` sub-resource of the form | ||
|
||
.. code-block:: json | ||
|
||
{ | ||
"key": "{memberkey}", | ||
"recoveryKey": "{recovery key}", | ||
} | ||
|
||
Non-owner Vault Members will not have the ``recoveryKey`` shared with them, the JWE will only contain the ``key`` element. | ||
Vault members can decrypt their access token using their private user key. | ||
See :ref:`User Key Pair <security/hub/keys/user-keys>`. | ||
|
||
Upon Vault creation, a new memberkey and an asymmetric recovery key pair are generated. The public recovery key and the ``vault.uvf`` JWE are uploaded to Cryptomator hub. | ||
|
||
.. image:: ../img/security/uvf_vault_creation.drawio.png | ||
:alt: uvf Vault Creation | ||
:width: 700px | ||
:align: center | ||
|
||
See :ref:`Key Rotation <security/uvf/key-rotation>` for more details on key rotation and ``vault.uvf``. | ||
|
||
Vault sharing is the same as with access tokens introduced in Cryptomator hub `1.3.0 <https://github.com/cryptomator/hub/releases/tag/1.3.0>`_. | ||
|
||
Only the payload's ``key`` field contains the latest member key (instead of the masterkey) and the ``recoverKey`` (Vault Owners only). | ||
|
||
.. image:: ../img/security/uvf_vault_sharing.drawio.png | ||
:alt: uvf Vault Sharing | ||
:width: 550px | ||
:align: center | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
Vault Cryptography with Universal Vault Format | ||
============================================== | ||
|
||
In the mid-term, we want to support Key Rotation. | ||
After Key Rotation, new data will be encrypted with new keys. | ||
This will allow to retract access from vault members, | ||
cryptographically ensuring they can never decrypt new data. | ||
|
||
`Unified Vault Format (uvf) <https://github.com/encryption-alliance/unified-vault-format>`_ | ||
defines a common vendor-independent standard. It is close to `Vault Format 8 <https://docs.cryptomator.org/en/latest/misc/vault-format-history/>`_, | ||
and will allow to support key rotation in the future. | ||
Key rotation is not implemented yet, though. | ||
Users will need to decide at vault creation time whether to use the new format. | ||
|
||
.. warning:: | ||
New vaults will be created in the new uvf format. | ||
There is no automatic migration plan for Vault Format 8 and below as data needs to be re-encrypted. | ||
Users will need to create a new vault (in the new uvf format) and to upload the data again. | ||
Clients and hub will be backwards-compatible. | ||
|
||
|
||
.. _security/uvf/key-rotation: | ||
|
||
Key Rotation | ||
------------ | ||
If a member (assume it's Bob) is removed from a vault, we need to replace the existing keys. | ||
Theoretically, we could re-encrypt the whole data. However, this is time- and resource-consuming (I/O). And Bob may have made a backup copy of the data anyway. | ||
Therefore, key rotation aims at enrypting new data - Bob must not be able to decrypt the new data with his old key, even if he still has access to the new ciphertext. | ||
|
||
The uvf metadata file replaces the masterkey file (or the user-specific JWE containing the masterkey introduced in Cryptomator hub `1.3.0 <https://github.com/cryptomator/hub/releases/tag/1.3.0>`_). | ||
It can contain many key generations - only the latest generation is used for data encryption. | ||
The older generations are used to read the older data encrypted with previous generation keys. | ||
|
||
Here's an example of the uvf metadata payload with different key generations in the ``seeds`` field and the ``latestFileKey`` pointing to the current key: | ||
|
||
.. code-block:: json | ||
|
||
{ | ||
"fileFormat": "AES-256-GCM-32k", | ||
"nameFormat": "AES-256-SIV", | ||
"seeds": { | ||
"HDm38i": "ypeBEsobvcr6wjGzmiPcTaeG7/gUfE5yuYB3ha/uSLs=", | ||
"gBryKw": "PiPoFgA5WUoziU9lZOGxNIu9egCI1CxKy3PurtWcAJ0=", | ||
"QBsJFo": "Ln0sA6lQeuJl7PW1NWiFpTOTogKdJBOUmXJloaJa78Y=" | ||
}, | ||
"latestFileKey": "QBsJFo", | ||
"nameKey": "HDm38i", | ||
"kdf": "HKDF-SHA512", | ||
"kdfSalt": "NIlr89R7FhochyP4yuXZmDqCnQ0dBB3UZ2D+6oiIjr8=", | ||
"org.example.customfield": 42 | ||
} | ||
|
||
|
||
When a new generation of keys is added to the metadata file, it must be re-encrypted as well - Bob, with his old key, must not be able to decrypt data encrypted later. | ||
|
||
Furthermore, for technical reasons (which will become clear below), the above payload needs to be shared with several ``recipients``. | ||
More precisely, we use different Key Encapsulation methods to encrypt the payload for multiple recipients (a ``recipient`` being identified by their key ID ``kid``). | ||
This is done in two steps: | ||
|
||
- The payload is encrypted only once with the same (shared) Content Encryption Key (CEK). The encrypted payload is stored in the ``ciphertext`` field of the encrypted metadata file. | ||
- The CEK is then encrypted specifically for each recipient with their key and method, and the resulting encrypted key is stored in the ``encrypted_key`` field of the encrypted metadata file. | ||
|
||
Here's an example of an (encrypted) metadata file (JWE in JSON serialization, see `RFC 7516 <https://www.rfc-editor.org/rfc/rfc7516.html>`_) with two recipients (``org.cryptomator.hub.memberkey`` and ``org.cryptomator.hub.recoverykey``): | ||
|
||
.. code-block:: json | ||
|
||
{ | ||
"protected": "eyJlbmMiOiJBMjU2R0NNIiwiamt1IjogImZvby9iYXIva2V5cy5qd2tzIn0", | ||
"recipients": [ | ||
{ | ||
"header": { | ||
"alg": "A256KW", | ||
"kid": "org.cryptomator.hub.memberkey" | ||
}, | ||
"encrypted_key": "6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ" | ||
}, | ||
{ | ||
"header": { | ||
"alg": "ECDH-ES+A256KW", | ||
"kid": "org.cryptomator.hub.recoverykey.{keyhash}", | ||
"epk": { | ||
"kty": "EC", | ||
"crv": "P-384", | ||
"x": "z7S-cEoCC0J0H42jocPnEgMr8pr0wyIZgaMvzu4We8B_nQkF1zpYSGZRcD9wI3hA", | ||
"y": "PlaiCkoGadNfVFi2ju-Dr19CewL-kjvXI8ibFOWaKizPh5gWjm9BFvx9Ox41Ka8x" | ||
} | ||
}, | ||
"encrypted_key": "6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ" | ||
} | ||
], | ||
"iv": "48V1_ALb6US04U3b", | ||
"ciphertext": "5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A", | ||
"tag": "XFBoMYUZodetZdvTiFvSkQ" | ||
} | ||
|
||
The `tag` field contains the `MAC <https://en.wikipedia.org/wiki/Message_authentication_code>`_ which allows to verify message authentication and integrigy checking, i.e. | ||
verify that the message can only come from someone having access to the CEK and not being tampered with. | ||
chenkins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Note that the recipient headers are authenticated as well. | ||
|
||
.. image:: ../img/security/uvf_key_rotation.drawio.png | ||
:alt: uvf Key Rotation | ||
:width: 700px | ||
:align: center | ||
|
||
|
||
|
||
Vault Members | ||
------------- | ||
All vault members share the same vault member key to access the vault metadata. | ||
|
||
The shared vault member key is a 256 bit AES Key. It is used for AES Key Wrap (``"alg": "A256KW"``) to enrypt/decrypt the metadata CEK. | ||
The wrapped CEK is stored as ``encrypted_key`` for the ``org.cryptomator.hub.memberkey`` recipient. | ||
|
||
The vault member key in turn is stored for each user separately in the hub in the form of a JWE encrypted with user's public user key. | ||
chenkins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Upon key rotation, the JWE for each user needs to be updated by using the public user key of each vault member. | ||
|
||
|
||
|
||
|
||
Recovery Key | ||
------------ | ||
Recovery keys are supposed to be long-living (print out human-readable and store offline) and should not be known by every vault member (only members with access to the private recovery key). | ||
|
||
In the key rotation setting, symmetric keys cannot be used for recovery key encryption. | ||
Not only vault members with access to the recovery key, but any vault member must be able to carry out key rotation. | ||
However, in symmetric cryptography, the same key is used for encryption and decryption. | ||
Key rotation mast be carried out by a vault member as only vault members must know the metadata containing the CEK generations so far. | ||
|
||
Vault members may also be notified by an external event (e.g. person leaving an organisation), share the new metadata after key rotation with a restricted member set only. | ||
|
||
|
||
Therefore, we use an ECDH key pair for each ``org.cryptomator.hub.recoverykey.{keyhash}`` recipient. Here's an example of such a key pair: | ||
|
||
.. code-block:: json | ||
|
||
{ | ||
"kty": "EC", | ||
"crv": "P-384", | ||
"d": "cMyQpw7YIGjop48z1fh9fekbjwVvCThhC0Owumzv_hTHkljBAG8bnMUSbts55Vy6", | ||
"x": "BzMNrgLiKSi9-gJ944_u7YgdXk5UfzGzSFlbDmuQS49LgVc8JpMAm1rAYhrLV9zi", | ||
"y": "X9rATILnkQNx33tIjVwkgVZj1E7r69ZN1K4QHvhjO3tgoBGiIbvf2D14CaFPnvM9" | ||
} | ||
|
||
The private key is the part that can be printed out at vault creation time. | ||
That's the ``d`` parameter above, which is a short bit of information that can be easily encoded in a human-readable way. | ||
All the other parts form the public key. | ||
During key rotation, only the public key needs to be known. | ||
The public key is used to encrypt the new CEK, and the recipient in the metadata is updated with the new ``encrypted_key``. | ||
The public key can be retrieved from the hub for key rotation with the vault's ID. | ||
|
||
The API returns a JWK Set, containing the public key for the vault recovery key ``org.cryptomator.hub.recoverykey.{keyhash}`` | ||
(currently, the JWK set will only contain the vault recovery key, but could be used for further keys in the future): | ||
|
||
.. code-block:: json | ||
|
||
{ | ||
"keys": [ | ||
{ | ||
"kid": "org.cryptomator.hub.recoverykey.{keyhash}", | ||
"kty": "EC", | ||
"crv": "P-384", | ||
"x": "BzMNrgLiKSi9-gJ944_u7YgdXk5UfzGzSFlbDmuQS49LgVc8JpMAm1rAYhrLV9zi", | ||
"y": "X9rATILnkQNx33tIjVwkgVZj1E7r69ZN1K4QHvhjO3tgoBGiIbvf2D14CaFPnvM9", | ||
"use": "enc", | ||
"key_ops": ["deriveKey"] | ||
} | ||
] | ||
} | ||
|
||
The following rules need to be respected upon encrypting the CEK for vault recovery key: | ||
|
||
.. csv-table:: Recovery Key JWE verification | ||
:header: "verify", "protection against" | ||
|
||
|
||
"relative URL", "implantation of untrusted URLs " | ||
"JWE signature", "JWE manipulation" | ||
"public key hash", "implantation of new public key at server side" | ||
|
||
Only URLs relative to the trusted hub must be followed, absolute URLs must not be followed in order for not retrieve the public recovery key from an untrusted source. | ||
chenkins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
JWE signature verification makes sure the JWE comes from someone having access to the CEK, i.e. from a vault member (having access to CEK via memberkey or recoverykey). | ||
A technical admin of the managed server cannot implant public keys at the server side unnoticed without being a vault member, as the keyhash is authenticated by the `tag` as well. | ||
|
||
|
||
.. warning:: | ||
Vault owners must be careful not to share vaults with technical hub admins. | ||
Only a technical hub admin who is also a Vault Member, could sneak in a new recovery key pair (and thereby gain access to future data). | ||
A technical hub admin of the managed server who is not Vault Member cannot perform this forgery. | ||
This ensures Zero Knowledge for Managed Servers. | ||
|
||
.. warning:: | ||
A malicious technical hub admin could still do some sort of "phishing" attack by "emptying" the vault, i.e. uploading a new memberkey (or also recoverykey). | ||
Vault members not paying attention could upload files and the malicious technical hub admin would then have access to the new data. | ||
This kind of attack would be noticed only if there is data in the storage for which the seeds have been removed from the metadata file or | ||
if a vault owner cannot use their locally stored recovery key any more. | ||
|
||
|
||
Look Ahead: Key Rotation | ||
------------------------ | ||
Although actual rotation of keys is not implemented yet, we give a sketch of the future implementation. | ||
To ensure Zero Knowledge, key rotation is not performed in the server, but on a vault member's machine in the client code. | ||
Only the encrypted data is then uploaded to the hub. | ||
Even a technical admin with access to the DB cannot gain access to the key material and, therefore, not decrypt the data even with access to the cloud storage. | ||
|
||
Key rotation will comprise the following steps: | ||
|
||
- get mutex for vault key rotation from hub (avoid concurrent key rotation for the same vault, lock at server) | ||
- generate new memberkey | ||
- encrypt new memberkey for all members with their public user key and update their vault access token | ||
- generate new CEK | ||
- generate new seed for data encryption and add to `seeds` of new metadata payload | ||
- encrypt payload with CEK for `ciphertext` of new metadata JWE | ||
- encrypt CEK with new memberkey and public recovery key into corresponding `encrypted_key` new metadata JWE | ||
chenkins marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- upload new metadata JWE | ||
- return mutex for vault key rotation to hub | ||
|
||
|
||
File Header Encryption | ||
---------------------- | ||
.. warning:: | ||
TODO: Differences to Vault8? | ||
|
||
File Content Encryption | ||
----------------------- | ||
.. warning:: | ||
TODO: Differences to Vault8? | ||
|
||
Directory Ids | ||
------------- | ||
.. warning:: | ||
TODO: Differences to Vault8? | ||
|
||
Filename Encryption | ||
------------------- | ||
.. warning:: | ||
TODO: Differences to Vault8? | ||
|
||
Name Shortening | ||
--------------- | ||
.. warning:: | ||
TODO: Differences to Vault8? | ||
|
||
Backup Directory Ids | ||
-------------------- | ||
.. warning:: | ||
TODO: Differences to Vault8? |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.