From 4d2a7865048489d365d8cb29a548dae206d78668 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Mon, 8 Feb 2016 15:17:50 +0100 Subject: [PATCH] new vault-internal file extensions (no extension at all for files, "_" suffix for directories) --- .../crypto/engine/FilenameCryptor.java | 8 +++++++ .../engine/impl/FilenameCryptorImpl.java | 5 +++++ .../filesystem/crypto/CryptoFile.java | 4 +--- .../filesystem/crypto/CryptoFolder.java | 22 +++++++++++++------ .../crypto/engine/NoFilenameCryptor.java | 5 +++++ .../ShorteningFileSystemFactory.java | 2 +- 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FilenameCryptor.java b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FilenameCryptor.java index f12d04cf7..cb94a12fa 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FilenameCryptor.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/FilenameCryptor.java @@ -21,6 +21,14 @@ public interface FilenameCryptor { */ String hashDirectoryId(String cleartextDirectoryId); + /** + * Tests without an actual decryption attempt, if a name is a well-formed ciphertext. + * + * @param ciphertextName Filename in question + * @return true if the given name is likely to be a valid ciphertext + */ + boolean isEncryptedFilename(String ciphertextName); + /** * @param cleartextName original filename including cleartext file extension * @param associatedData optional associated data, that will not get encrypted but needs to be provided during decryption diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FilenameCryptorImpl.java b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FilenameCryptorImpl.java index 3469ac554..5db611548 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FilenameCryptorImpl.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FilenameCryptorImpl.java @@ -49,6 +49,11 @@ class FilenameCryptorImpl implements FilenameCryptor { return BASE32.encodeAsString(hashedBytes); } + @Override + public boolean isEncryptedFilename(String ciphertextName) { + return BASE32.isInAlphabet(ciphertextName); + } + @Override public String encryptFilename(String cleartextName, byte[]... associatedData) { final byte[] cleartextBytes = cleartextName.getBytes(UTF_8); diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFile.java b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFile.java index fb1cfe803..e8c4aa9b6 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFile.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFile.java @@ -21,8 +21,6 @@ import org.cryptomator.filesystem.WritableFile; public class CryptoFile extends CryptoNode implements File { - static final String FILE_EXT = ".file"; - public CryptoFile(CryptoFolder parent, String name, Cryptor cryptor) { super(parent, name, cryptor); } @@ -30,7 +28,7 @@ public class CryptoFile extends CryptoNode implements File { @Override protected String encryptedName() { final byte[] parentDirId = parent.getDirectoryId().getBytes(UTF_8); - return cryptor.getFilenameCryptor().encryptFilename(name(), parentDirId) + FILE_EXT; + return cryptor.getFilenameCryptor().encryptFilename(name(), parentDirId); } @Override diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java index 151b96195..d67a2ff3a 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java @@ -19,6 +19,7 @@ import java.time.Instant; import java.util.Optional; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; import java.util.stream.Stream; import org.apache.commons.io.IOUtils; @@ -33,7 +34,7 @@ import org.cryptomator.filesystem.WritableFile; class CryptoFolder extends CryptoNode implements Folder { - static final String DIR_EXT = ".dir"; + static final String DIR_SUFFIX = "_"; private final WeakValuedCache folders = WeakValuedCache.usingLoader(this::newFolder); private final WeakValuedCache files = WeakValuedCache.usingLoader(this::newFile); @@ -46,7 +47,7 @@ class CryptoFolder extends CryptoNode implements Folder { @Override protected String encryptedName() { final byte[] parentDirId = parent().map(CryptoFolder::getDirectoryId).map(s -> s.getBytes(UTF_8)).orElse(null); - return cryptor.getFilenameCryptor().encryptFilename(name(), parentDirId) + DIR_EXT; + return cryptor.getFilenameCryptor().encryptFilename(name(), parentDirId) + DIR_SUFFIX; } Folder physicalFolder() { @@ -82,13 +83,16 @@ class CryptoFolder extends CryptoNode implements Folder { @Override public Stream files() { - return physicalFolder().files().map(File::name).filter(s -> s.endsWith(CryptoFile.FILE_EXT)).map(this::decryptChildFileName).map(this::file); + return physicalFolder().files().map(File::name).filter(isEncryptedFileName()).map(this::decryptChildFileName).map(this::file); + } + + private Predicate isEncryptedFileName() { + return (String name) -> cryptor.getFilenameCryptor().isEncryptedFilename(name); } private String decryptChildFileName(String encryptedFileName) { final byte[] dirId = getDirectoryId().getBytes(UTF_8); - final String ciphertext = StringUtils.removeEnd(encryptedFileName, CryptoFile.FILE_EXT); - return cryptor.getFilenameCryptor().decryptFilename(ciphertext, dirId); + return cryptor.getFilenameCryptor().decryptFilename(encryptedFileName, dirId); } @Override @@ -102,12 +106,16 @@ class CryptoFolder extends CryptoNode implements Folder { @Override public Stream folders() { - return physicalFolder().files().map(File::name).filter(s -> s.endsWith(CryptoFolder.DIR_EXT)).map(this::decryptChildFolderName).map(this::folder); + return physicalFolder().files().map(File::name).filter(isEncryptedDirectoryName()).map(this::decryptChildFolderName).map(this::folder); + } + + private Predicate isEncryptedDirectoryName() { + return (String name) -> name.endsWith(DIR_SUFFIX) && isEncryptedFileName().test(StringUtils.removeEnd(name, DIR_SUFFIX)); } private String decryptChildFolderName(String encryptedFolderName) { final byte[] dirId = getDirectoryId().getBytes(UTF_8); - final String ciphertext = StringUtils.removeEnd(encryptedFolderName, CryptoFolder.DIR_EXT); + final String ciphertext = StringUtils.removeEnd(encryptedFolderName, CryptoFolder.DIR_SUFFIX); return cryptor.getFilenameCryptor().decryptFilename(ciphertext, dirId); } diff --git a/main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/NoFilenameCryptor.java b/main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/NoFilenameCryptor.java index 0788643bc..9f3901f7e 100644 --- a/main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/NoFilenameCryptor.java +++ b/main/filesystem-crypto/src/test/java/org/cryptomator/crypto/engine/NoFilenameCryptor.java @@ -28,6 +28,11 @@ class NoFilenameCryptor implements FilenameCryptor { return BASE32.encodeAsString(hashedBytes); } + @Override + public boolean isEncryptedFilename(String ciphertextName) { + return true; + } + @Override public String encryptFilename(String cleartextName, byte[]... associatedData) { return cleartextName; diff --git a/main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/shortening/ShorteningFileSystemFactory.java b/main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/shortening/ShorteningFileSystemFactory.java index 65073e763..4eb83cbc7 100644 --- a/main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/shortening/ShorteningFileSystemFactory.java +++ b/main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/shortening/ShorteningFileSystemFactory.java @@ -19,7 +19,7 @@ import org.cryptomator.filesystem.blacklisting.SamePathPredicate; @Singleton public class ShorteningFileSystemFactory { - private static final int SHORTENING_THRESHOLD = 140; + private static final int SHORTENING_THRESHOLD = 129; // 128 + "_" private static final String METADATA_FOLDER_NAME = "m"; private final BlacklistingFileSystemFactory blacklistingFileSystemFactory;