Skip to content

Commit 84cccd4

Browse files
ylangiscdkocher
authored andcommitted
Add JWKCallback to decrypt keys.
1 parent 22535e6 commit 84cccd4

File tree

14 files changed

+121
-20
lines changed

14 files changed

+121
-20
lines changed

core/pom.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
<artifactId>core</artifactId>
2424
<packaging>jar</packaging>
2525

26+
<properties>
27+
<nimbus-jose.version>10.5</nimbus-jose.version>
28+
</properties>
29+
2630
<build>
2731
<plugins>
2832
<plugin>
@@ -144,6 +148,11 @@
144148
<artifactId>auto-service-annotations</artifactId>
145149
<version>1.1.1</version>
146150
</dependency>
151+
<dependency>
152+
<groupId>com.nimbusds</groupId>
153+
<artifactId>nimbus-jose-jwt</artifactId>
154+
<version>${nimbus-jose.version}</version>
155+
</dependency>
147156
<dependency>
148157
<groupId>junit</groupId>
149158
<artifactId>junit</artifactId>

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package ch.cyberduck.core.vault;
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 interface JWKCallback extends PasswordCallback {
24+
25+
@Override
26+
JWKCredentials prompt(Host bookmark, String title, String reason, LoginOptions options) throws LoginCanceledException;
27+
28+
static JWKCallback cast(PasswordCallback callback) {
29+
if(callback instanceof JWKCallback) {
30+
return (JWKCallback) callback;
31+
}
32+
else {
33+
throw new IllegalArgumentException("Unsupported metadata type " + callback.getClass());
34+
}
35+
}
36+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package ch.cyberduck.core.vault;
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 com.nimbusds.jose.jwk.JWK;
19+
20+
public class JWKCredentials extends VaultCredentials {
21+
22+
private final JWK key;
23+
24+
public JWKCredentials(final JWK key) {
25+
super(null);
26+
this.key = key;
27+
}
28+
29+
public JWK getKey() {
30+
return key;
31+
}
32+
}

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) {

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,5 @@
1616
*/
1717

1818
public interface VaultMetadataProvider {
19-
20-
//Map<Path, byte[]> metadataFiles() throws BackgroundException;
21-
22-
//String dirPath();
19+
// Marker interface
2320
}

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

Lines changed: 20 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,12 @@
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.JWKCallback;
41+
import ch.cyberduck.core.vault.VaultException;
4142
import ch.cyberduck.core.vault.VaultMetadata;
4243
import ch.cyberduck.core.vault.VaultMetadataProvider;
4344

45+
import org.apache.commons.lang3.StringUtils;
4446
import org.apache.logging.log4j.LogManager;
4547
import org.apache.logging.log4j.Logger;
4648
import org.cryptomator.cryptolib.api.Cryptor;
@@ -51,12 +53,16 @@
5153
import org.cryptomator.cryptolib.api.RevolvingMasterkey;
5254
import org.cryptomator.cryptolib.api.UVFMasterkey;
5355

54-
import java.text.MessageFormat;
56+
import java.nio.charset.StandardCharsets;
57+
import java.text.ParseException;
5558
import java.util.EnumSet;
5659
import java.util.Objects;
5760
import java.util.regex.Pattern;
5861

5962
import com.google.auto.service.AutoService;
63+
import com.nimbusds.jose.JOSEException;
64+
import com.nimbusds.jose.JWEObjectJSON;
65+
import com.nimbusds.jose.crypto.MultiDecrypter;
6066

6167
@AutoService(Vault.class)
6268
public class CryptoVault extends AbstractVault {
@@ -123,16 +129,18 @@ public AbstractVault create(final Session<?> session, final String region, final
123129

124130
// load -> unlock -> open
125131
@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());
132+
public CryptoVault load(final Session<?> session, final PasswordCallback callback, final VaultMetadataProvider metadata) throws BackgroundException {
133+
final JWKCallback jwk = JWKCallback.cast(callback);
134+
final VaultMetadataUVFProvider metadataProvider = VaultMetadataUVFProvider.cast(metadata);
135+
final JWEObjectJSON jweObject;
136+
try {
137+
jweObject = JWEObjectJSON.parse(new String(metadataProvider.getMetadata(), StandardCharsets.US_ASCII));
138+
jweObject.decrypt(new MultiDecrypter(jwk.prompt(session.getHost(), StringUtils.EMPTY, StringUtils.EMPTY, new LoginOptions()).getKey()));
139+
}
140+
catch(ParseException | JOSEException e) {
141+
throw new VaultException("Failure retrieving key material", e);
142+
}
143+
masterKey = UVFMasterkey.fromDecryptedPayload(jweObject.getPayload().toString());
136144
final CryptorProvider provider = CryptorProvider.forScheme(CryptorProvider.Scheme.UVF_DRAFT);
137145
log.debug("Initialized crypto provider {}", provider);
138146
this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide());

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
{

0 commit comments

Comments
 (0)