From 8c8db84a4ae09868e61add287d59526cbda962ef Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 23 Aug 2016 21:15:40 +0200 Subject: [PATCH] refactored migration (using cryptolib) --- main/pom.xml | 8 ++++ main/ui/pom.xml | 6 +++ .../cryptomator/ui/model/UpgradeStrategy.java | 48 +++++++++++++------ .../UpgradeVersion3DropBundleExtension.java | 47 +++--------------- .../ui/model/UpgradeVersion3to4.java | 36 +++----------- 5 files changed, 62 insertions(+), 83 deletions(-) diff --git a/main/pom.xml b/main/pom.xml index cfb5ace1a..757794d7d 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -28,6 +28,7 @@ UTF-8 + 1.0.0-SNAPSHOT 2.1 1.7.7 4.12 @@ -123,6 +124,13 @@ ui ${project.version} + + + + org.cryptomator + cryptolib + ${cryptolib.version} + diff --git a/main/ui/pom.xml b/main/ui/pom.xml index 2c261d3ad..5515e6d26 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -55,6 +55,12 @@ frontend-webdav + + + org.cryptomator + cryptolib + + org.fxmisc.easybind diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java index 6f7f147ce..9d77b93d4 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java @@ -6,11 +6,11 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; -import javax.inject.Provider; - -import org.cryptomator.crypto.engine.Cryptor; -import org.cryptomator.crypto.engine.InvalidPassphraseException; -import org.cryptomator.crypto.engine.UnsupportedVaultFormatException; +import org.cryptomator.cryptolib.api.Cryptor; +import org.cryptomator.cryptolib.api.CryptorProvider; +import org.cryptomator.cryptolib.api.InvalidPassphraseException; +import org.cryptomator.cryptolib.api.KeyFile; +import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException; import org.cryptomator.filesystem.crypto.Constants; import org.cryptomator.ui.settings.Localization; import org.slf4j.Logger; @@ -20,12 +20,16 @@ public abstract class UpgradeStrategy { private static final Logger LOG = LoggerFactory.getLogger(UpgradeStrategy.class); - protected final Provider cryptorProvider; + protected final CryptorProvider cryptorProvider; protected final Localization localization; + protected final int vaultVersionBeforeUpgrade; + protected final int vaultVersionAfterUpgrade; - UpgradeStrategy(Provider cryptorProvider, Localization localization) { + UpgradeStrategy(CryptorProvider cryptorProvider, Localization localization, int vaultVersionBeforeUpgrade, int vaultVersionAfterUpgrade) { this.cryptorProvider = cryptorProvider; this.localization = localization; + this.vaultVersionBeforeUpgrade = vaultVersionBeforeUpgrade; + this.vaultVersionAfterUpgrade = vaultVersionAfterUpgrade; } /** @@ -37,27 +41,29 @@ public abstract class UpgradeStrategy { * Upgrades a vault. Might take a moment, should be run in a background thread. */ public void upgrade(Vault vault, CharSequence passphrase) throws UpgradeFailedException { - final Cryptor cryptor = cryptorProvider.get(); + Cryptor cryptor = null; try { final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); final byte[] masterkeyFileContents = Files.readAllBytes(masterkeyFile); - cryptor.readKeysFromMasterkeyFile(masterkeyFileContents, passphrase); + cryptor = cryptorProvider.createFromKeyFile(KeyFile.parse(masterkeyFileContents), passphrase, vaultVersionBeforeUpgrade); // create backup, as soon as we know the password was correct: final Path masterkeyBackupFile = vault.path().getValue().resolve(Constants.MASTERKEY_BACKUP_FILENAME); Files.copy(masterkeyFile, masterkeyBackupFile, StandardCopyOption.REPLACE_EXISTING); // do stuff: upgrade(vault, cryptor); // write updated masterkey file: - final byte[] upgradedMasterkeyFileContents = cryptor.writeKeysToMasterkeyFile(passphrase); - final Path masterkeyFileAfterUpgrading = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); // path may have changed - Files.write(masterkeyFileAfterUpgrading, upgradedMasterkeyFileContents, StandardOpenOption.TRUNCATE_EXISTING); + final byte[] upgradedMasterkeyFileContents = cryptor.writeKeysToMasterkeyFile(passphrase, vaultVersionAfterUpgrade).serialize(); + final Path masterkeyFileAfterUpgrade = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); // path may have changed + Files.write(masterkeyFileAfterUpgrade, upgradedMasterkeyFileContents, StandardOpenOption.TRUNCATE_EXISTING); } catch (InvalidPassphraseException e) { throw new UpgradeFailedException(localization.getString("unlock.errorMessage.wrongPassword")); } catch (IOException | UnsupportedVaultFormatException e) { LOG.warn("Upgrade failed.", e); throw new UpgradeFailedException("Upgrade failed. Details in log message."); } finally { - cryptor.destroy(); + if (cryptor != null) { + cryptor.destroy(); + } } } @@ -68,7 +74,21 @@ public abstract class UpgradeStrategy { * * @return true if and only if the vault can be migrated to a newer version without the risk of data losses. */ - public abstract boolean isApplicable(Vault vault); + public boolean isApplicable(Vault vault) { + final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); + try { + if (Files.isRegularFile(masterkeyFile)) { + byte[] masterkeyFileContents = Files.readAllBytes(masterkeyFile); + return KeyFile.parse(masterkeyFileContents).getVersion() == vaultVersionBeforeUpgrade; + } else { + LOG.warn("Not a file: {}", masterkeyFile); + return false; + } + } catch (IOException e) { + LOG.warn("Could not determine, whether upgrade is applicable.", e); + return false; + } + } /** * Thrown when data migration failed. diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3DropBundleExtension.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3DropBundleExtension.java index 04fa63f30..a0462cd65 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3DropBundleExtension.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3DropBundleExtension.java @@ -1,19 +1,16 @@ package org.cryptomator.ui.model; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.security.SecureRandom; import javax.inject.Inject; -import javax.inject.Provider; import javax.inject.Singleton; import org.apache.commons.lang3.StringUtils; -import org.cryptomator.crypto.engine.Cryptor; -import org.cryptomator.crypto.engine.InvalidPassphraseException; -import org.cryptomator.crypto.engine.UnsupportedVaultFormatException; -import org.cryptomator.filesystem.crypto.Constants; +import org.cryptomator.cryptolib.Cryptors; +import org.cryptomator.cryptolib.api.Cryptor; import org.cryptomator.ui.settings.Localization; import org.cryptomator.ui.settings.Settings; import org.slf4j.Logger; @@ -28,8 +25,8 @@ class UpgradeVersion3DropBundleExtension extends UpgradeStrategy { private final Settings settings; @Inject - public UpgradeVersion3DropBundleExtension(Provider cryptorProvider, Localization localization, Settings settings) { - super(cryptorProvider, localization); + public UpgradeVersion3DropBundleExtension(SecureRandom secureRandom, Localization localization, Settings settings) { + super(Cryptors.version1(secureRandom), localization, 3, 3); this.settings = settings; } @@ -42,25 +39,6 @@ class UpgradeVersion3DropBundleExtension extends UpgradeStrategy { return String.format(fmt, oldVaultName, newVaultName); } - @Override - public void upgrade(Vault vault, CharSequence passphrase) throws UpgradeFailedException { - final Cryptor cryptor = cryptorProvider.get(); - try { - final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); - final byte[] masterkeyFileContents = Files.readAllBytes(masterkeyFile); - cryptor.readKeysFromMasterkeyFile(masterkeyFileContents, passphrase); - upgrade(vault, cryptor); - // don't write new masterkey. this is a special case, as we were stupid and didn't increase the vault version with this upgrade... - } catch (InvalidPassphraseException e) { - throw new UpgradeFailedException(localization.getString("unlock.errorMessage.wrongPassword")); - } catch (IOException | UnsupportedVaultFormatException e) { - LOG.warn("Upgrade failed.", e); - throw new UpgradeFailedException("Upgrade failed. Details in log message."); - } finally { - cryptor.destroy(); - } - } - @Override protected void upgrade(Vault vault, Cryptor cryptor) throws UpgradeFailedException { Path path = vault.path().getValue(); @@ -73,6 +51,7 @@ class UpgradeVersion3DropBundleExtension extends UpgradeStrategy { throw new UpgradeFailedException(msg); } else { try { + LOG.info("Renaming {} to {}", path, newPath.getFileName()); Files.move(path, path.resolveSibling(newVaultName)); Platform.runLater(() -> { vault.setPath(newPath); @@ -89,19 +68,7 @@ class UpgradeVersion3DropBundleExtension extends UpgradeStrategy { public boolean isApplicable(Vault vault) { Path vaultPath = vault.path().getValue(); if (vaultPath.toString().endsWith(Vault.VAULT_FILE_EXTENSION)) { - final Path masterkeyFile = vaultPath.resolve(Constants.MASTERKEY_FILENAME); - try { - if (Files.isRegularFile(masterkeyFile)) { - final String keyContents = new String(Files.readAllBytes(masterkeyFile), StandardCharsets.UTF_8); - return keyContents.contains("\"version\":3") || keyContents.contains("\"version\": 3"); - } else { - LOG.warn("Not a file: {}", masterkeyFile); - return false; - } - } catch (IOException e) { - LOG.warn("Could not determine, whether upgrade is applicable.", e); - return false; - } + return super.isApplicable(vault); } else { return false; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java index 51a75b263..17bbcaac1 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java @@ -9,19 +9,19 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.inject.Inject; -import javax.inject.Provider; import javax.inject.Singleton; import org.apache.commons.codec.binary.Base32; import org.apache.commons.codec.binary.BaseNCodec; import org.apache.commons.lang3.StringUtils; -import org.cryptomator.crypto.engine.Cryptor; -import org.cryptomator.filesystem.crypto.Constants; +import org.cryptomator.cryptolib.Cryptors; +import org.cryptomator.cryptolib.api.Cryptor; +import org.cryptomator.cryptolib.common.MessageDigestSupplier; import org.cryptomator.ui.settings.Localization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,17 +40,12 @@ class UpgradeVersion3to4 extends UpgradeStrategy { private static final String OLD_FOLDER_SUFFIX = "_"; private static final String NEW_FOLDER_PREFIX = "0"; - private final MessageDigest sha1; + private final MessageDigest sha1 = MessageDigestSupplier.SHA1.get(); private final BaseNCodec base32 = new Base32(); @Inject - public UpgradeVersion3to4(Provider cryptorProvider, Localization localization) { - super(cryptorProvider, localization); - try { - sha1 = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError("SHA-1 exists in every JVM"); - } + public UpgradeVersion3to4(SecureRandom secureRandom, Localization localization) { + super(Cryptors.version1(secureRandom), localization, 3, 4); } @Override @@ -144,21 +139,4 @@ class UpgradeVersion3to4 extends UpgradeStrategy { } } - @Override - public boolean isApplicable(Vault vault) { - final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); - try { - if (Files.isRegularFile(masterkeyFile)) { - final String keyContents = new String(Files.readAllBytes(masterkeyFile), UTF_8); - return keyContents.contains("\"version\":3") || keyContents.contains("\"version\": 3"); - } else { - LOG.warn("Not a file: {}", masterkeyFile); - return false; - } - } catch (IOException e) { - LOG.warn("Could not determine, whether upgrade is applicable.", e); - return false; - } - } - }