Skip to content

Conversation

@overheadhunter
Copy link
Member

@overheadhunter overheadhunter commented May 10, 2024

This PR adds fundamental support for UVF-based vaults. During vault creation either format is selected. There is no migration of format 8 based vaults planned. Vault access tokens either contain a format 8 Masterkey OR a UVF member key (which is an A256KW key for the vault.uvf file).

Notable changes:

  1. split up crypto implementation into uvf.ts and vaultv8.ts, leaving common crypto in crypto.ts
  2. make jwe.ts capable of handling compact as well as json serialization with support for ECDH-ES (legacy, decrypt only), ECDH-ES+A256KW, PBES2+A256KW and A256KW, allowing encryption for multiple recipients
  3. add new vault fields to database and DTOs to allow storing a vault.uvf file as well as the public part of a recovery key pair
  4. instead of serializing the masterkey, the recovery key consists of a serialized private key

TODO

  • bump API level

overheadhunter and others added 30 commits March 2, 2024 12:10
# Conflicts:
#	backend/src/test/java/org/cryptomator/hub/api/VaultResourceTest.java
# Conflicts:
#	backend/src/main/java/org/cryptomator/hub/api/VaultResource.java
#	backend/src/main/java/org/cryptomator/hub/entities/Vault.java
#	backend/src/test/java/org/cryptomator/hub/api/VaultResourceIT.java
#	frontend/src/components/VaultDetails.vue
[ci skip]
# Conflicts:
#	frontend/package-lock.json
#	frontend/src/components/CreateVault.vue
#	frontend/src/components/VaultDetails.vue
# Conflicts:
#	backend/src/main/resources/org/cryptomator/hub/flyway/ERM.png
#	frontend/src/common/userdata.ts
#	frontend/src/components/InitialSetup.vue
#	frontend/src/components/RegenerateSetupCodeDialog.vue
#	frontend/src/components/VaultDetails.vue
#	frontend/src/i18n/de-DE.json
# Conflicts:
#	backend/src/test/java/org/cryptomator/hub/api/VaultResourceIT.java
[ci skip]
cty: 'json',
crit: ['uvf.spec.version'],
'uvf.spec.version': 1,
'cloud.katta.origin': `${apiURL}/vaults/${vault.id}/uvf/vault.uvf`, // single source of truth for this vault
Copy link
Contributor

@chenkins chenkins Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@overheadhunter is this katta only? Does not make sense upstream?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, should be org.cryptomator here...

name: 'test',
archived: false,
creationTime: new Date(),
uvfMetadataFile: '{"protected":"eyJvcmlnaW4iOiJodHRwcy4vL2V4YW1wbGUuY29tL2FwaS8vdmF1bHRzLzEyMy91dmYvdmF1bHQudXZmIiwiamt1Ijoiandrcy5qc29uIiwiZW5jIjoiQTI1NkdDTSJ9","recipients":[{"header":{"kid":"org.cryptomator.hub.memberkey","alg":"A256KW"},"encrypted_key":"vJ16vGF2Z3NcA7nXPnVrgDLzgxZ8RFtySgf0FsckcrTBfKDg4hAK0w"},{"header":{"kid":"org.cryptomator.hub.recoverykey.J7-F_hjMaygRKdqIoZrbxSqVSRFJ5aF8BXuOCoBBGjw","alg":"ECDH-ES+A256KW","epk":{"key_ops":[],"ext":true,"kty":"EC","x":"oQZ8e-e9UIOtbN50ySx5Xwik9ET3uu38Bzl6HdDR8uipOzdXIO8OUhVQMJWqEHjs","y":"cTP6OI_YfdCVPVWpGOA1SjQ6-4vUpE4a6QJx3JSw29DkOL70Rjl4GAcDc4Iw-VHY","crv":"P-384"},"apu":"","apv":""},"encrypted_key":"m_tSjpBcNQK42pgqLA9YDZYa3WQwJZ94HhGIpwOcKDoJQ8lP8IKbFw"}],"iv":"XPY9W-TE__Hu2m53","ciphertext":"uoukmSAuFTq-20gD9Ayum8iH6ERrld6cNV_ZTyfHBcWeIIZKOdp3RWWEtzNagVnRy5ix0yAafJIa14aSLnsxFv-NhzW1BirU5YypIkvFIO4cPnjI54vzd8nEtPdpp6z2JOqKUvZQYN89Y2EGoXb33FmQAwVMNJt_xDn2Bcb1dvI0q0uKLUidsvFL87NHSA8KUVWjXmmFdjibfqhWuO9YtFVoYD2Oqso9TzQIRMnDt3aIcVAouTTE7bR9O8kj5nseNID2gQ2osKlJVVcUn-4Cn0bI2w_-SeAfAvnePWLmolF8q79_aOsMkow3zMGsQHFoVU3PWCHR374Z02Lnt0Mj5_aUu_k8R5L11xNZQ0EYY7XWWGoUjRif7HmRfTZoHbJwvnHWk5q6IuEEjd_zSa4_im7PpoEofZR2EcH7Zz_Llq00wPWT05ZD82aRo3VCRNs6A2s6Jd8hspnaYA","tag":"j-xKxc2aZ2EDHDm8CzNf8Tj4QIkruZauF0LeUwrhq6c"}',
Copy link
Contributor

@chenkins chenkins Nov 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update with all protected headers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decided against it as the header doesn't affect the purpose or outcome of the test and didn't have much time

});

it('recover()', async () => {
const vaultUvfFileContents = '{"protected":"eyJvcmlnaW4iOiJodHRwcy4vL2V4YW1wbGUuY29tL2FwaS8vdmF1bHRzLzEyMy91dmYvdmF1bHQudXZmIiwiamt1Ijoiandrcy5qc29uIiwiZW5jIjoiQTI1NkdDTSJ9","recipients":[{"header":{"kid":"org.cryptomator.hub.memberkey","alg":"A256KW"},"encrypted_key":"J3Gd7wZzsy-ykWPboW9CqK6DzoDGwRiZCJ3d6fNYkpt0klqDRmYR0g"},{"header":{"kid":"org.cryptomator.hub.recoverykey.DGbyooUW5QlVWzTaF102-f59uRTX1kdqkQb_CMDq9gM","alg":"ECDH-ES+A256KW","epk":{"key_ops":[],"ext":true,"kty":"EC","x":"q4p-3TTjHZxAkf6Fa3rknf_oqBGRiAkXB78_UxElbv6DN0Ufc_2RSX2pYKb8gaAU","y":"czJGKQe_q12AMYROZfEUBbP6zMo0DjgjK_346_BjS9RQ531jf32Ryht4xIBP50ef","crv":"P-384"},"apu":"","apv":""},"encrypted_key":"7D-irqonnK01xQiTNGmsgSRPBzLdKdGTtq2XGS6BONkHWFgESpOYeg"}],"iv":"FNxcOvj_BgQ4vRVN","ciphertext":"qyORqJsK_3aec14d6gnIuNrLmnhFggY0MBWkjqOUXsOhSgOKcamtLbLGhk1gqWfc_dcshzWnBxx7TB2K_TwfSKnF0mumPldFMQ6u_HQM-jemBDCsStBSdOQoYqYcwbLyEfvH39XO4Oremppsj1a-8bOIbga0gnbQQmuNXraQtZLtyut82Q7P521Ab_leIUo_laKHPk610SW3DyJySoroxFH40qEb0GfsUAdcHMwCNA2dhQCCOW4zFZsmV_PxnVaNOhUV8aVz-lmwW8PnNCLxMdveQDegnbSvban6O0Qjl1MRnf1_pnBEM2meWk6CTnuJYwWaKHgbG69geGliOB_wKRTAapw8gOyQ-gPZya2hMvK2gAJLPWXAAc6mDo_MfzHa7PbLQ70J1r_tsJLKLmTrvU683Let70KG1_UyHFi6m9aFfXgA5PfmfGFKeDZ3e_bqNzFJbf-ytZJq9A","tag":"FpTkkwkTujb3OosDC-ck97W4awBStimQ95NfTe0TRxQ"}';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update with all protected headers?

Comment on lines +329 to +330
'cloud.katta.origin': `${apiURL}/vaults/${vault.id}/uvf/vault.uvf`, // single source of truth for this vault
jku: 'jwks.json', // URL relative to cloud.katta.origin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@overheadhunter Also: the spec says:

As the current version of this specification only allows for predefined parameter values, nothing but the parameter order may change. The base64url-encoded version of the protected header for spec version 1 should therefore always be this:

echo eyJlbmMiOiJBMjU2R0NNIiwiY3R5IjoianNvbiIsImNyaXQiOlsidXZmLnNwZWMudmVyc2lvbiJdLCJ1dmYuc3BlYy52ZXJzaW9uIjoxfQ | jq -R '@base64d | fromjson'
{
  "enc": "A256GCM",
  "cty": "json",
  "crit": [
    "uvf.spec.version"
  ],
  "uvf.spec.version": 1
}

Do I misread the spec or ar origin and jku not allowed?

*/
public static async decryptWithMemberKey(uvfMetadataFile: string, memberKey: MemberKey): Promise<VaultMetadata> {
const json: JsonJWE = JSON.parse(uvfMetadataFile);
const payload: MetadataPayload = await JWE.parseJson(json).decrypt(Recipient.a256kw('org.cryptomator.hub.memberkey', memberKey.key));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@overheadhunter Check uvf.spec.version as discussed here

}
const recoveryKeyID = `org.cryptomator.hub.recoverykey.${await getJwkThumbprintStr(recoveryKey.publicKey)}`;
const json: JsonJWE = JSON.parse(uvfMetadataFile);
const payload: MetadataPayload = await JWE.parseJson(json).decrypt(Recipient.ecdhEs(recoveryKeyID, recoveryKey.privateKey));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@overheadhunter Check uvf.spec.version as discussed here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants