Przeglądaj źródła

refactored migration (using cryptolib)

Sebastian Stenzel 8 lat temu
rodzic
commit
8c8db84a4a

+ 8 - 0
main/pom.xml

@@ -28,6 +28,7 @@
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 
 		<!-- dependency versions -->
+		<cryptolib.version>1.0.0-SNAPSHOT</cryptolib.version>
 		<log4j.version>2.1</log4j.version>
 		<slf4j.version>1.7.7</slf4j.version>
 		<junit.version>4.12</junit.version>
@@ -123,6 +124,13 @@
 				<artifactId>ui</artifactId>
 				<version>${project.version}</version>
 			</dependency>
+			
+			<!-- Libs -->
+			<dependency>
+				<groupId>org.cryptomator</groupId>
+				<artifactId>cryptolib</artifactId>
+				<version>${cryptolib.version}</version>
+			</dependency>
 
 			<!-- Logging -->
 			<dependency>

+ 6 - 0
main/ui/pom.xml

@@ -55,6 +55,12 @@
 			<artifactId>frontend-webdav</artifactId>
 		</dependency>
 		
+		<!-- CryptoLib -->
+		<dependency>
+			<groupId>org.cryptomator</groupId>
+			<artifactId>cryptolib</artifactId>
+		</dependency>
+		
 		<!-- EasyBind -->
 		<dependency>
 			<groupId>org.fxmisc.easybind</groupId>

+ 34 - 14
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<Cryptor> cryptorProvider;
+	protected final CryptorProvider cryptorProvider;
 	protected final Localization localization;
+	protected final int vaultVersionBeforeUpgrade;
+	protected final int vaultVersionAfterUpgrade;
 
-	UpgradeStrategy(Provider<Cryptor> 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 <code>true</code> 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.

+ 7 - 40
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<Cryptor> 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;
 		}

+ 7 - 29
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<Cryptor> 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;
-		}
-	}
-
 }