Skip to content

Commit 5dc0d63

Browse files
committed
Add JWKCallback to decrypt keys.
1 parent f304bd3 commit 5dc0d63

File tree

13 files changed

+125
-16
lines changed

13 files changed

+125
-16
lines changed

core/src/main/java/ch/cyberduck/core/features/Vault.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public interface Vault {
4747
* @throws BackgroundException Failure reading master key from server
4848
* @throws NotfoundException No master key file in home
4949
*/
50-
Vault load(Session<?> session, PasswordCallback prompt) throws BackgroundException;
50+
Vault load(Session<?> session, PasswordCallback prompt, VaultMetadataProvider provider) throws BackgroundException;
5151

5252
/**
5353
* Close vault

core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public Vault create(final Session<?> session, final String region, final VaultMe
4242
}
4343

4444
@Override
45-
public Vault load(final Session<?> session, final PasswordCallback prompt) {
45+
public Vault load(final Session<?> session, final PasswordCallback prompt, final VaultMetadataProvider provider) {
4646
return this;
4747
}
4848

core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ public Vault load(final Session session, final VaultMetadata metadata) throws Va
4343
log.info("Loading vault for session {}", session);
4444
final Vault vault = VaultProviderFactory.get(session).provide(session, metadata);
4545
try {
46-
registry.add(vault.load(session, prompt));
46+
// TODO provide correct metadata provider
47+
registry.add(vault.load(session, prompt, new VaultMetadataProvider() {
48+
}));
4749
return vault;
4850
}
4951
catch(BackgroundException e) {

cryptomator/pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
<properties>
2828
<cryptolib.version>2.3.0.uvfdraft-SNAPSHOT</cryptolib.version>
29+
<nimbus-jose.version>10.5</nimbus-jose.version>
2930
</properties>
3031

3132
<dependencies>
@@ -46,6 +47,11 @@
4647
<artifactId>cryptolib</artifactId>
4748
<version>${cryptolib.version}</version>
4849
</dependency>
50+
<dependency>
51+
<groupId>com.nimbusds</groupId>
52+
<artifactId>nimbus-jose-jwt</artifactId>
53+
<version>${nimbus-jose.version}</version>
54+
</dependency>
4955
<dependency>
5056
<groupId>com.auth0</groupId>
5157
<artifactId>java-jwt</artifactId>

cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
* GNU General Public License for more details.
1616
*/
1717

18-
import ch.cyberduck.core.LocaleFactory;
1918
import ch.cyberduck.core.LoginOptions;
2019
import ch.cyberduck.core.PasswordCallback;
2120
import ch.cyberduck.core.Path;
@@ -38,9 +37,11 @@
3837
import ch.cyberduck.core.features.Write;
3938
import ch.cyberduck.core.preferences.PreferencesFactory;
4039
import ch.cyberduck.core.transfer.TransferStatus;
40+
import ch.cyberduck.core.vault.VaultException;
4141
import ch.cyberduck.core.vault.VaultMetadata;
4242
import ch.cyberduck.core.vault.VaultMetadataProvider;
4343

44+
import org.apache.commons.lang3.StringUtils;
4445
import org.apache.logging.log4j.LogManager;
4546
import org.apache.logging.log4j.Logger;
4647
import org.cryptomator.cryptolib.api.Cryptor;
@@ -51,12 +52,16 @@
5152
import org.cryptomator.cryptolib.api.RevolvingMasterkey;
5253
import org.cryptomator.cryptolib.api.UVFMasterkey;
5354

54-
import java.text.MessageFormat;
55+
import java.nio.charset.StandardCharsets;
56+
import java.text.ParseException;
5557
import java.util.EnumSet;
5658
import java.util.Objects;
5759
import java.util.regex.Pattern;
5860

5961
import com.google.auto.service.AutoService;
62+
import com.nimbusds.jose.JOSEException;
63+
import com.nimbusds.jose.JWEObjectJSON;
64+
import com.nimbusds.jose.crypto.MultiDecrypter;
6065

6166
@AutoService(Vault.class)
6267
public class CryptoVault extends AbstractVault {
@@ -123,16 +128,18 @@ public AbstractVault create(final Session<?> session, final String region, final
123128

124129
// load -> unlock -> open
125130
@Override
126-
public CryptoVault load(final Session<?> session, final PasswordCallback prompt) throws BackgroundException {
127-
masterKey = UVFMasterkey.fromDecryptedPayload(prompt.prompt(session.getHost(),
128-
LocaleFactory.localizedString("Unlock Vault", "Cryptomator"),
129-
MessageFormat.format(LocaleFactory.localizedString("Provide your passphrase to unlock the Cryptomator Vault {0}", "Cryptomator"), home.getName()),
130-
new LoginOptions()
131-
.save(false)
132-
.user(false)
133-
.anonymous(false)
134-
.icon("cryptomator.tiff")
135-
.passwordPlaceholder(LocaleFactory.localizedString("Passphrase", "Cryptomator"))).getPassword());
131+
public CryptoVault load(final Session<?> session, final PasswordCallback callback, final VaultMetadataProvider metadata) throws BackgroundException {
132+
final JWKCallback jwk = JWKCallback.cast(callback);
133+
final VaultMetadataUVFProvider metadataProvider = VaultMetadataUVFProvider.cast(metadata);
134+
final JWEObjectJSON jweObject;
135+
try {
136+
jweObject = JWEObjectJSON.parse(new String(metadataProvider.getMetadata(), StandardCharsets.US_ASCII));
137+
jweObject.decrypt(new MultiDecrypter(jwk.prompt(session.getHost(), StringUtils.EMPTY, StringUtils.EMPTY, new LoginOptions()).getKeyset()));
138+
}
139+
catch(ParseException | JOSEException e) {
140+
throw new VaultException("Failure retrieving key material", e);
141+
}
142+
masterKey = UVFMasterkey.fromDecryptedPayload(jweObject.getPayload().toString());
136143
final CryptorProvider provider = CryptorProvider.forScheme(CryptorProvider.Scheme.UVF_DRAFT);
137144
log.debug("Initialized crypto provider {}", provider);
138145
this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide());
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package ch.cyberduck.core.cryptomator.impl.uvf;
2+
3+
/*
4+
* Copyright (c) 2002-2025 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.Host;
19+
import ch.cyberduck.core.LoginOptions;
20+
import ch.cyberduck.core.PasswordCallback;
21+
import ch.cyberduck.core.exception.LoginCanceledException;
22+
23+
public class JWKCallback implements PasswordCallback {
24+
25+
@Override
26+
public void close(final String input) {
27+
28+
}
29+
30+
@Override
31+
public JWKCredentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) throws LoginCanceledException {
32+
return null;
33+
}
34+
35+
static JWKCallback cast(PasswordCallback callback) {
36+
if(callback instanceof JWKCallback) {
37+
return (JWKCallback) callback;
38+
}
39+
else {
40+
throw new IllegalArgumentException("Unsupported metadata type " + callback.getClass());
41+
}
42+
}
43+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ch.cyberduck.core.cryptomator.impl.uvf;
2+
3+
/*
4+
* Copyright (c) 2002-2025 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.vault.VaultCredentials;
19+
20+
import com.nimbusds.jose.jwk.JWK;
21+
22+
public class JWKCredentials extends VaultCredentials {
23+
24+
private final JWK keyset;
25+
26+
public JWKCredentials(final JWK keyset) {
27+
super(null);
28+
this.keyset = keyset;
29+
}
30+
31+
public JWK getKeyset() {
32+
return keyset;
33+
}
34+
}

cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ private static VaultConfig parseVaultConfigFromMasterKey(final MasterkeyFile mas
279279
}
280280

281281
@Override
282-
public Vault load(final Session<?> session, final PasswordCallback prompt) throws BackgroundException {
282+
public Vault load(final Session<?> session, final PasswordCallback prompt, final VaultMetadataProvider provider) throws BackgroundException {
283283
final Host bookmark = session.getHost();
284284
String passphrase = keychain.getPassword(String.format("Cryptomator Passphrase (%s)", bookmark.getCredentials().getUsername()),
285285
new DefaultUrlProvider(bookmark).toUrl(masterkeyPath, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl());

cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import ch.cyberduck.core.features.Read;
3030
import ch.cyberduck.core.transfer.TransferStatus;
3131
import ch.cyberduck.core.vault.VaultCredentials;
32+
import ch.cyberduck.core.vault.VaultMetadataProvider;
3233

3334
import org.apache.commons.io.IOUtils;
3435
import org.cryptomator.cryptolib.api.CryptorProvider;
@@ -87,6 +88,7 @@ public Credentials prompt(final Host bookmark, final String title, final String
8788
final LoginOptions options) {
8889
return new VaultCredentials("vault");
8990
}
91+
}, new VaultMetadataProvider() {
9092
}).
9193

9294
getHome());
@@ -162,6 +164,7 @@ public boolean offset(final Path file) {
162164
public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) {
163165
return new VaultCredentials("vault");
164166
}
167+
}, new VaultMetadataProvider() {
165168
}).getHome());
166169
CryptoReadFeature read = new CryptoReadFeature(null, null, vault);
167170
{

cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import ch.cyberduck.core.features.Read;
3232
import ch.cyberduck.core.transfer.TransferStatus;
3333
import ch.cyberduck.core.vault.VaultCredentials;
34+
import ch.cyberduck.core.vault.VaultMetadataProvider;
3435

3536
import org.apache.commons.io.IOUtils;
3637
import org.cryptomator.cryptolib.api.CryptorProvider;
@@ -111,6 +112,7 @@ public boolean offset(final Path file) {
111112
public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) {
112113
return new VaultCredentials("vault123");
113114
}
115+
}, new VaultMetadataProvider() {
114116
});
115117
final CryptoDirectory provider = new CryptoDirectoryV8Provider(vault, new CryptoFilenameV7Provider());
116118
assertNotNull(provider.toEncrypted(session, home));

0 commit comments

Comments
 (0)