Skip to content

Commit fc05637

Browse files
committed
Extract filename cryptor and provider.
1 parent 4c6cbb1 commit fc05637

File tree

6 files changed

+201
-156
lines changed

6 files changed

+201
-156
lines changed

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

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -342,29 +342,20 @@ protected CryptoFilename createFilenameProvider(final VaultConfig vaultConfig) {
342342
}
343343
}
344344

345-
protected CryptoDirectory createDirectoryProvider(final VaultConfig vaultConfig) {
345+
protected CryptoDirectory createDirectoryProvider(final VaultConfig vaultConfig, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) {
346346
switch(vaultConfig.version) {
347347
case VAULT_VERSION_DEPRECATED:
348-
return new CryptoDirectoryV6Provider(vault, this);
348+
return new CryptoDirectoryV6Provider(vault, filenameProvider, filenameCryptor);
349349
default:
350-
return new CryptoDirectoryV7Provider(vault, this);
350+
return new CryptoDirectoryV7Provider(vault, filenameProvider, filenameCryptor);
351351
}
352352
}
353353

354-
// UVF: extract to v6/v7/uvf imple, VaultConfig only for v6/v7
355-
// pro memoria:
356-
// create -> open
357-
// unlock -> open
358-
protected void open(final VaultConfig vaultConfig, final CharSequence passphrase) throws BackgroundException {
359-
this.open(vaultConfig, passphrase, this.createFilenameProvider(vaultConfig), this.createDirectoryProvider(vaultConfig));
360-
}
361-
362354
// UVF: extract to v6/v7/uvf, at this point we know which version
363-
protected void open(final VaultConfig vaultConfig, final CharSequence passphrase,
364-
final CryptoFilename filenameProvider, final CryptoDirectory directoryProvider) throws BackgroundException {
355+
protected void open(final VaultConfig vaultConfig, final CharSequence passphrase) throws BackgroundException {
365356
try {
366357
final PerpetualMasterkey masterKey = this.getMasterKey(vaultConfig.getMkfile(), passphrase);
367-
this.open(vaultConfig, masterKey, filenameProvider, directoryProvider);
358+
this.open(vaultConfig, masterKey);
368359
}
369360
catch(IllegalArgumentException | IOException e) {
370361
throw new VaultException("Failure reading key file", e);
@@ -376,20 +367,14 @@ protected void open(final VaultConfig vaultConfig, final CharSequence passphrase
376367

377368
// UVF: unused?!
378369
protected void open(final VaultConfig vaultConfig, final PerpetualMasterkey masterKey) throws BackgroundException {
379-
this.open(vaultConfig, masterKey, this.createFilenameProvider(vaultConfig), this.createDirectoryProvider(vaultConfig));
380-
}
381-
382-
// UVF: extract to v6/v7 imple, can we use the new MasterKey interface from https://github.com/cryptomator/cryptolib/pull/51/files?
383-
protected void open(final VaultConfig vaultConfig, final PerpetualMasterkey masterKey,
384-
final CryptoFilename filenameProvider, final CryptoDirectory directoryProvider) throws BackgroundException {
385370
this.vaultVersion = vaultConfig.version;
386371
final CryptorProvider provider = CryptorProvider.forScheme(vaultConfig.getCipherCombo());
387372
log.debug("Initialized crypto provider {}", provider);
388373
vaultConfig.verify(masterKey.getEncoded(), VAULT_VERSION);
389374
this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide());
390375
this.fileNameCryptor = new CryptorCache(cryptor.fileNameCryptor());
391-
this.filenameProvider = filenameProvider;
392-
this.directoryProvider = directoryProvider;
376+
this.filenameProvider = this.createFilenameProvider(vaultConfig);
377+
this.directoryProvider = this.createDirectoryProvider(vaultConfig, this.filenameProvider, this.fileNameCryptor);
393378
this.nonceSize = vaultConfig.getNonceSize();
394379
}
395380

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package ch.cyberduck.core.cryptomator;
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.PasswordCallback;
19+
import ch.cyberduck.core.Path;
20+
import ch.cyberduck.core.PathAttributes;
21+
import ch.cyberduck.core.Session;
22+
import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV7Provider;
23+
import ch.cyberduck.core.cryptomator.impl.CryptoFilenameV7Provider;
24+
import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider;
25+
import ch.cyberduck.core.exception.BackgroundException;
26+
import ch.cyberduck.core.features.Vault;
27+
import ch.cyberduck.core.vault.VaultCredentials;
28+
29+
import org.apache.logging.log4j.LogManager;
30+
import org.apache.logging.log4j.Logger;
31+
import org.cryptomator.cryptolib.api.Cryptor;
32+
import org.cryptomator.cryptolib.api.CryptorProvider;
33+
import org.cryptomator.cryptolib.api.UVFMasterkey;
34+
35+
import java.util.EnumSet;
36+
37+
public class UVFVault implements Vault {
38+
39+
private static final Logger log = LogManager.getLogger(UVFVault.class);
40+
41+
/**
42+
* Root of vault directory
43+
*/
44+
private final Path home;
45+
private final Path vault;
46+
47+
private final String decrypted;
48+
private Cryptor cryptor;
49+
private CryptorCache fileNameCryptor;
50+
private CryptoFilename filenameProvider;
51+
private CryptoDirectory directoryProvider;
52+
53+
public UVFVault(final Path home, final String decryptedPayload) {
54+
this.home = home;
55+
this.decrypted = decryptedPayload;
56+
// New vault home with vault flag set for internal use
57+
final EnumSet<Path.Type> type = EnumSet.copyOf(home.getType());
58+
type.add(Path.Type.vault);
59+
if(home.isRoot()) {
60+
this.vault = new Path(home.getAbsolute(), type, new PathAttributes(home.attributes()));
61+
}
62+
else {
63+
this.vault = new Path(home.getParent(), home.getName(), type, new PathAttributes(home.attributes()));
64+
}
65+
}
66+
67+
@Override
68+
public Path create(final Session<?> session, final String region, final VaultCredentials credentials) throws BackgroundException {
69+
return null;
70+
}
71+
72+
// load -> unlock -> open
73+
@Override
74+
public UVFVault load(final Session<?> session, final PasswordCallback prompt) throws BackgroundException {
75+
UVFMasterkey masterKey = UVFMasterkey.fromDecryptedPayload(this.decrypted);
76+
77+
final CryptorProvider provider = CryptorProvider.forScheme(CryptorProvider.Scheme.UVF_DRAFT);
78+
log.debug("Initialized crypto provider {}", provider);
79+
this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide());
80+
this.fileNameCryptor = new CryptorCache(cryptor.fileNameCryptor());
81+
this.filenameProvider = new CryptoFilenameV7Provider(/* TODO threshold was previously defined in vault.config - default now? */);
82+
this.directoryProvider = new CryptoDirectoryV7Provider(vault, filenameProvider, fileNameCryptor);
83+
//TODO where? this.nonceSize = vaultConfig.getNonceSize();
84+
return this;
85+
}
86+
87+
@Override
88+
public void close() {
89+
90+
}
91+
92+
@Override
93+
public boolean contains(final Path file) {
94+
return false;
95+
}
96+
97+
@Override
98+
public Path encrypt(final Session<?> session, final Path file) throws BackgroundException {
99+
return null;
100+
}
101+
102+
@Override
103+
public Path encrypt(final Session<?> session, final Path file, final boolean metadata) throws BackgroundException {
104+
return null;
105+
}
106+
107+
@Override
108+
public Path decrypt(final Session<?> session, final Path file) throws BackgroundException {
109+
return null;
110+
}
111+
112+
@Override
113+
public long toCiphertextSize(final long cleartextFileOffset, final long cleartextFileSize) {
114+
return 0;
115+
}
116+
117+
@Override
118+
public long toCleartextSize(final long cleartextFileOffset, final long ciphertextFileSize) throws BackgroundException {
119+
return 0;
120+
}
121+
122+
@Override
123+
public <T> T getFeature(final Session<?> session, final Class<T> type, final T delegate) {
124+
return null;
125+
}
126+
127+
@Override
128+
public State getState() {
129+
return null;
130+
}
131+
132+
@Override
133+
public Path getHome() {
134+
return null;
135+
}
136+
}

cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6Provider.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import ch.cyberduck.core.cache.LRUCache;
2626
import ch.cyberduck.core.cryptomator.ContentReader;
2727
import ch.cyberduck.core.cryptomator.CryptoDirectory;
28+
import ch.cyberduck.core.cryptomator.CryptoFilename;
2829
import ch.cyberduck.core.cryptomator.CryptoVault;
2930
import ch.cyberduck.core.cryptomator.CryptorCache;
3031
import ch.cyberduck.core.exception.BackgroundException;
@@ -48,28 +49,30 @@ public class CryptoDirectoryV6Provider implements CryptoDirectory {
4849

4950
private final Path dataRoot;
5051
private final Path home;
51-
private final CryptoVault cryptomator;
52+
private final CryptoFilename filenameProvider;
53+
private final CryptorCache filenameCryptor;
5254

5355
private final RandomStringService random
54-
= new UUIDRandomStringService();
56+
= new UUIDRandomStringService();
5557

5658
private final Lock lock = new ReentrantLock();
5759

5860
private final LRUCache<CacheReference<Path>, String> cache = LRUCache.build(
59-
PreferencesFactory.get().getInteger("cryptomator.cache.size"));
61+
PreferencesFactory.get().getInteger("cryptomator.cache.size"));
6062

61-
public CryptoDirectoryV6Provider(final Path vault, final CryptoVault cryptomator) {
63+
public CryptoDirectoryV6Provider(final Path vault, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) {
6264
this.home = vault;
6365
this.dataRoot = new Path(vault, DATA_DIR_NAME, vault.getType());
64-
this.cryptomator = cryptomator;
66+
this.filenameProvider = filenameProvider;
67+
this.filenameCryptor = filenameCryptor;
6568
}
6669

6770
@Override
6871
public String toEncrypted(final Session<?> session, final String directoryId, final String filename, final EnumSet<Path.Type> type) throws BackgroundException {
6972
final String prefix = type.contains(Path.Type.directory) ? CryptoVault.DIR_PREFIX : "";
70-
final String ciphertextName = prefix + cryptomator.getFileNameCryptor().encryptFilename(CryptorCache.BASE32, filename, directoryId.getBytes(StandardCharsets.UTF_8));
73+
final String ciphertextName = prefix + filenameCryptor.encryptFilename(CryptorCache.BASE32, filename, directoryId.getBytes(StandardCharsets.UTF_8));
7174
log.debug("Encrypted filename {} to {}", filename, ciphertextName);
72-
return cryptomator.getFilenameProvider().deflate(session, ciphertextName);
75+
return filenameProvider.deflate(session, ciphertextName);
7376
}
7477

7578
@Override
@@ -87,7 +90,7 @@ public Path toEncrypted(final Session<?> session, final String directoryId, fina
8790
log.debug("Use directory ID '{}' for folder {}", id, directory);
8891
attributes.setDirectoryId(id);
8992
attributes.setDecrypted(directory);
90-
final String directoryIdHash = cryptomator.getFileNameCryptor().hashDirectoryId(id);
93+
final String directoryIdHash = filenameCryptor.hashDirectoryId(id);
9194
// Intermediate directory
9295
final Path intermediate = new Path(dataRoot, directoryIdHash.substring(0, 2), dataRoot.getType());
9396
// Add encrypted type

cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
import ch.cyberduck.core.Session;
2121
import ch.cyberduck.core.UUIDRandomStringService;
2222
import ch.cyberduck.core.cryptomator.ContentReader;
23-
import ch.cyberduck.core.cryptomator.CryptoVault;
23+
import ch.cyberduck.core.cryptomator.CryptoFilename;
24+
import ch.cyberduck.core.cryptomator.CryptorCache;
2425
import ch.cyberduck.core.exception.BackgroundException;
2526
import ch.cyberduck.core.exception.NotfoundException;
2627

@@ -41,22 +42,24 @@ public class CryptoDirectoryV7Provider extends CryptoDirectoryV6Provider {
4142
public static final String BACKUP_FILENAME_DIRECTORYID = "dirid";
4243
public static final String BACKUP_DIRECTORY_METADATAFILE = String.format("%s%s", BACKUP_FILENAME_DIRECTORYID, EXTENSION_REGULAR);
4344

44-
private final CryptoVault cryptomator;
45+
private final CryptoFilename filenameProvider;
46+
private final CryptorCache filenameCryptor;
4547

4648
private final RandomStringService random
47-
= new UUIDRandomStringService();
49+
= new UUIDRandomStringService();
4850

49-
public CryptoDirectoryV7Provider(final Path vault, final CryptoVault cryptomator) {
50-
super(vault, cryptomator);
51-
this.cryptomator = cryptomator;
51+
public CryptoDirectoryV7Provider(final Path vault, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) {
52+
super(vault, filenameProvider, filenameCryptor);
53+
this.filenameProvider = filenameProvider;
54+
this.filenameCryptor = filenameCryptor;
5255
}
5356

5457
@Override
5558
public String toEncrypted(final Session<?> session, final String directoryId, final String filename, final EnumSet<Path.Type> type) throws BackgroundException {
56-
final String ciphertextName = cryptomator.getFileNameCryptor().encryptFilename(BaseEncoding.base64Url(),
57-
filename, directoryId.getBytes(StandardCharsets.UTF_8)) + EXTENSION_REGULAR;
59+
final String ciphertextName = filenameCryptor.encryptFilename(BaseEncoding.base64Url(),
60+
filename, directoryId.getBytes(StandardCharsets.UTF_8)) + EXTENSION_REGULAR;
5861
log.debug("Encrypted filename {} to {}", filename, ciphertextName);
59-
return cryptomator.getFilenameProvider().deflate(session, ciphertextName);
62+
return filenameProvider.deflate(session, ciphertextName);
6063
}
6164

6265
protected String load(final Session<?> session, final Path directory) throws BackgroundException {

0 commit comments

Comments
 (0)