mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-20 03:31:27 +00:00
check vault version before unlocking
This commit is contained in:
@@ -21,7 +21,7 @@ public interface Cryptor extends Destroyable {
|
||||
|
||||
void randomizeMasterkey();
|
||||
|
||||
void readKeysFromMasterkeyFile(byte[] masterkeyFileContents, CharSequence passphrase) throws InvalidPassphraseException;
|
||||
void readKeysFromMasterkeyFile(byte[] masterkeyFileContents, CharSequence passphrase) throws InvalidPassphraseException, UnsupportedVaultFormatException;
|
||||
|
||||
byte[] writeKeysToMasterkeyFile(CharSequence passphrase);
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016 Sebastian Stenzel and others.
|
||||
* This file is licensed under the terms of the MIT license.
|
||||
* See the LICENSE.txt file for more info.
|
||||
*
|
||||
* Contributors:
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.crypto.engine;
|
||||
|
||||
public class UnsupportedVaultFormatException extends CryptoException {
|
||||
|
||||
private final Integer detectedVersion;
|
||||
private final Integer supportedVersion;
|
||||
|
||||
public UnsupportedVaultFormatException(Integer detectedVersion, Integer supportedVersion) {
|
||||
super("Tried to open vault of version " + detectedVersion + ", but can only handle version " + supportedVersion);
|
||||
this.detectedVersion = detectedVersion;
|
||||
this.supportedVersion = supportedVersion;
|
||||
}
|
||||
|
||||
public Integer getDetectedVersion() {
|
||||
return detectedVersion;
|
||||
}
|
||||
|
||||
public Integer getSupportedVersion() {
|
||||
return supportedVersion;
|
||||
}
|
||||
|
||||
public boolean isVaultOlderThanSoftware() {
|
||||
return detectedVersion == null || detectedVersion < supportedVersion;
|
||||
}
|
||||
|
||||
public boolean isSoftwareOlderThanVault() {
|
||||
return detectedVersion > supportedVersion;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,8 @@ public final class Constants {
|
||||
private Constants() {
|
||||
}
|
||||
|
||||
static final Integer CURRENT_VAULT_VERSION = 3;
|
||||
|
||||
public static final int PAYLOAD_SIZE = 32 * 1024;
|
||||
public static final int NONCE_SIZE = 16;
|
||||
public static final int MAC_SIZE = 32;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.crypto.engine.impl;
|
||||
|
||||
import static org.cryptomator.crypto.engine.impl.Constants.CURRENT_VAULT_VERSION;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -25,6 +27,7 @@ import org.cryptomator.crypto.engine.Cryptor;
|
||||
import org.cryptomator.crypto.engine.FileContentCryptor;
|
||||
import org.cryptomator.crypto.engine.FilenameCryptor;
|
||||
import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.crypto.engine.UnsupportedVaultFormatException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -97,10 +100,8 @@ class CryptorImpl implements Cryptor {
|
||||
}
|
||||
|
||||
// check version
|
||||
if (keyFile.getVersion() != KeyFile.CURRENT_VERSION) {
|
||||
// TODO
|
||||
// throw new UnsupportedVaultException(keyfile.getVersion(), KeyFile.CURRENT_VERSION);
|
||||
throw new IllegalArgumentException("Unsupported key (expected version: " + KeyFile.CURRENT_VERSION + ", actual version: " + keyFile.getVersion() + ")");
|
||||
if (keyFile.getVersion() != CURRENT_VAULT_VERSION) {
|
||||
throw new UnsupportedVaultFormatException(keyFile.getVersion(), CURRENT_VAULT_VERSION);
|
||||
}
|
||||
|
||||
final byte[] kekBytes = Scrypt.scrypt(passphrase, keyFile.getScryptSalt(), keyFile.getScryptCostParam(), keyFile.getScryptBlockSize(), KEYLENGTH_IN_BYTES);
|
||||
@@ -134,7 +135,7 @@ class CryptorImpl implements Cryptor {
|
||||
}
|
||||
|
||||
final KeyFile keyfile = new KeyFile();
|
||||
keyfile.setVersion(KeyFile.CURRENT_VERSION);
|
||||
keyfile.setVersion(CURRENT_VAULT_VERSION);
|
||||
keyfile.setScryptSalt(scryptSalt);
|
||||
keyfile.setScryptCostParam(SCRYPT_COST_PARAM);
|
||||
keyfile.setScryptBlockSize(SCRYPT_BLOCK_SIZE);
|
||||
|
||||
@@ -10,13 +10,14 @@ package org.cryptomator.crypto.engine.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonPropertyOrder(value = {"version", "scryptSalt", "scryptCostParam", "scryptBlockSize", "primaryMasterKey", "hmacMasterKey"})
|
||||
class KeyFile implements Serializable {
|
||||
|
||||
static final Integer CURRENT_VERSION = 3;
|
||||
private static final long serialVersionUID = 8578363158959619885L;
|
||||
|
||||
@JsonProperty("version")
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.cryptomator.filesystem.crypto;
|
||||
|
||||
public final class Constants {
|
||||
|
||||
private Constants() {
|
||||
}
|
||||
|
||||
static final String DATA_ROOT_DIR = "d";
|
||||
static final String ROOT_DIRECOTRY_ID = "";
|
||||
|
||||
static final String MASTERKEY_FILENAME = "masterkey.cryptomator";
|
||||
static final String MASTERKEY_BACKUP_FILENAME = "masterkey.cryptomator.bkup";
|
||||
|
||||
static final String DIR_SUFFIX = "_";
|
||||
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.filesystem.crypto;
|
||||
|
||||
import static org.cryptomator.filesystem.crypto.Constants.DATA_ROOT_DIR;
|
||||
import static org.cryptomator.filesystem.crypto.Constants.ROOT_DIRECOTRY_ID;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
@@ -20,9 +23,6 @@ import org.cryptomator.filesystem.Folder;
|
||||
|
||||
class CryptoFileSystem extends CryptoFolder implements FileSystem {
|
||||
|
||||
private static final String DATA_ROOT_DIR = "d";
|
||||
private static final String ROOT_DIRECOTRY_ID = "";
|
||||
|
||||
private final Folder physicalRoot;
|
||||
private final CryptoFileSystemDelegate delegate;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
package org.cryptomator.filesystem.crypto;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.cryptomator.filesystem.crypto.Constants.DIR_SUFFIX;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.UncheckedIOException;
|
||||
@@ -31,8 +32,6 @@ import org.cryptomator.io.FileContents;
|
||||
|
||||
class CryptoFolder extends CryptoNode implements Folder {
|
||||
|
||||
static final String DIR_SUFFIX = "_";
|
||||
|
||||
private final WeakValuedCache<String, CryptoFolder> folders = WeakValuedCache.usingLoader(this::newFolder);
|
||||
private final WeakValuedCache<String, CryptoFile> files = WeakValuedCache.usingLoader(this::newFile);
|
||||
private final AtomicReference<String> directoryId = new AtomicReference<>();
|
||||
@@ -114,7 +113,7 @@ class CryptoFolder extends CryptoNode implements Folder {
|
||||
|
||||
private String decryptChildFolderName(String encryptedFolderName) {
|
||||
final byte[] dirId = getDirectoryId().get().getBytes(UTF_8);
|
||||
final String ciphertext = StringUtils.removeEnd(encryptedFolderName, CryptoFolder.DIR_SUFFIX);
|
||||
final String ciphertext = StringUtils.removeEnd(encryptedFolderName, DIR_SUFFIX);
|
||||
return cryptor.getFilenameCryptor().decryptFilename(ciphertext, dirId);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.filesystem.crypto;
|
||||
|
||||
import static org.cryptomator.filesystem.crypto.Constants.MASTERKEY_BACKUP_FILENAME;
|
||||
import static org.cryptomator.filesystem.crypto.Constants.MASTERKEY_FILENAME;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
@@ -28,9 +31,6 @@ import org.cryptomator.filesystem.WritableFile;
|
||||
@Singleton
|
||||
class Masterkeys {
|
||||
|
||||
private static final String MASTERKEY_FILENAME = "masterkey.cryptomator";
|
||||
private static final String MASTERKEY_BACKUP_FILENAME = "masterkey.cryptomator.bkup";
|
||||
|
||||
private final Provider<Cryptor> cryptorProvider;
|
||||
|
||||
@Inject
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.io.IOException;
|
||||
|
||||
import org.cryptomator.crypto.engine.Cryptor;
|
||||
import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.crypto.engine.UnsupportedVaultFormatException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -35,6 +36,15 @@ public class CryptorImplTest {
|
||||
cryptor.readKeysFromMasterkeyFile(testMasterKey.getBytes(), "qwe");
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedVaultFormatException.class)
|
||||
public void testMasterkeyDecryptionWithWrongVaultFormat() throws IOException {
|
||||
final String testMasterKey = "{\"version\":-1,\"scryptSalt\":\"AAAAAAAAAAA=\",\"scryptCostParam\":2,\"scryptBlockSize\":8," //
|
||||
+ "\"primaryMasterKey\":\"mM+qoQ+o0qvPTiDAZYt+flaC3WbpNAx1sTXaUzxwpy0M9Ctj6Tih/Q==\"," //
|
||||
+ "\"hmacMasterKey\":\"mM+qoQ+o0qvPTiDAZYt+flaC3WbpNAx1sTXaUzxwpy0M9Ctj6Tih/Q==\"}";
|
||||
final Cryptor cryptor = TestCryptorImplFactory.insecureCryptorImpl();
|
||||
cryptor.readKeysFromMasterkeyFile(testMasterKey.getBytes(), "qwe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMasterkeyEncryption() throws IOException {
|
||||
final String expectedMasterKey = "{\"version\":3,\"scryptSalt\":\"AAAAAAAAAAA=\",\"scryptCostParam\":16384,\"scryptBlockSize\":8," //
|
||||
|
||||
@@ -20,6 +20,7 @@ import javax.inject.Inject;
|
||||
import org.apache.commons.lang3.CharUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.crypto.engine.UnsupportedVaultFormatException;
|
||||
import org.cryptomator.frontend.CommandFailedException;
|
||||
import org.cryptomator.frontend.FrontendCreationFailedException;
|
||||
import org.cryptomator.frontend.webdav.mount.WindowsDriveLetters;
|
||||
@@ -261,20 +262,21 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
progressIndicator.setVisible(false);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.wrongPassword"));
|
||||
Platform.runLater(passwordField::requestFocus);
|
||||
} catch (UnsupportedVaultFormatException e) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
downloadsPageLink.setVisible(true);
|
||||
LOG.warn("Unable to unlock vault: " + e.getMessage());
|
||||
if (e.isVaultOlderThanSoftware()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
} else if (e.isSoftwareOlderThanVault()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
}
|
||||
} catch (FrontendCreationFailedException ex) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.decryptionFailed"));
|
||||
LOG.error("Decryption failed for technical reasons.", ex);
|
||||
// } catch (UnsupportedVaultException e) {
|
||||
// setControlsDisabled(false);
|
||||
// progressIndicator.setVisible(false);
|
||||
// downloadsPageLink.setVisible(true);
|
||||
// if (e.isVaultOlderThanSoftware()) {
|
||||
// messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
// } else if (e.isSoftwareOlderThanVault()) {
|
||||
// messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
// }
|
||||
} finally {
|
||||
passwordField.swipe();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user