refactored key validation

This commit is contained in:
Jan-Peter Klein
2025-03-21 11:03:24 +01:00
parent 6bb8c0d4e7
commit 1ae951126a
2 changed files with 49 additions and 42 deletions

View File

@@ -16,6 +16,7 @@ import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
import static org.cryptomator.common.Constants.DEFAULT_KEY_ID;
@@ -56,19 +57,32 @@ public class RecoverUtil {
public static CryptorProvider.Scheme detectCipherCombo(byte[] masterkey, Path pathToVault) {
try (Stream<Path> paths = Files.walk(pathToVault.resolve(DATA_DIR_NAME))) {
return paths.filter(path -> path.toString().endsWith(".c9r")).findFirst().map(c9rFile -> determineScheme(c9rFile, masterkey)).orElseThrow(() -> new IllegalStateException("No .c9r file found."));
Path c9rFile = paths.filter(path -> path.toString().endsWith(".c9r"))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No .c9r file found. The vault might not exist or the provided masterkey does not match."));
CryptorProvider.Scheme scheme = determineScheme(c9rFile, masterkey);
if (scheme == null) {
throw new IllegalArgumentException("Invalid masterkey: Decryption failed.");
}
return scheme;
} catch (IOException e) {
throw new IllegalStateException("Failed to detect cipher combo.", e);
throw new IllegalStateException("Failed to detect cipher combo.");
}
}
private static CryptorProvider.Scheme determineScheme(Path c9rFile, byte[] masterkey) {
try {
ByteBuffer header = ByteBuffer.wrap(Files.readAllBytes(c9rFile));
return tryDecrypt(header, new Masterkey(masterkey), SIV_GCM) ? SIV_GCM : tryDecrypt(header, new Masterkey(masterkey), SIV_CTRMAC) ? SIV_CTRMAC : null;
if (tryDecrypt(header, new Masterkey(masterkey), SIV_GCM)) {
return SIV_GCM;
}
if (tryDecrypt(header, new Masterkey(masterkey), SIV_CTRMAC)) {
return SIV_CTRMAC;
}
} catch (IOException e) {
return null;
throw new IllegalStateException("Failed to read .c9r file.", e);
}
return null;
}
private static boolean tryDecrypt(ByteBuffer header, Masterkey masterkey, CryptorProvider.Scheme scheme) {
@@ -129,35 +143,35 @@ public class RecoverUtil {
try {
return Optional.of(RecoverUtil.detectCipherCombo(masterkey.getEncoded(), vaultPath));
} catch (Exception e) {
LOG.warn("Failed to detect cipher combo", e);
LOG.info("Failed to detect cipher combo.");
return Optional.empty();
}
}
public static Optional<CryptorProvider.Scheme> validateRecoveryKeyAndGetCombo(RecoveryKeyFactory recoveryKeyFactory, Vault vault, StringProperty recoveryKey, MasterkeyFileAccess masterkeyFileAccess) {
Path tempRecoveryPath = null;
CharSequence tmpPass = "asdasdasd";
public static Optional<CryptorProvider.Scheme> validateRecoveryKeyAndGetCombo(RecoveryKeyFactory recoveryKeyFactory, Vault vault, StringProperty recoveryKey, MasterkeyFileAccess masterkeyFileAccess, AtomicBoolean illegalArgumentExceptionOccurred) {
var tmpPass = "asdasdasd";
try {
tempRecoveryPath = createRecoveryDirectory(vault.getPath());
createNewMasterkeyFile(recoveryKeyFactory, tempRecoveryPath, recoveryKey.get(), tmpPass);
Path masterkeyFilePath = tempRecoveryPath.resolve(MASTERKEY_FILENAME);
var tempRecoveryPath = createRecoveryDirectory(vault.getPath());
try {
createNewMasterkeyFile(recoveryKeyFactory, tempRecoveryPath, recoveryKey.get(), tmpPass);
var masterkeyFilePath = tempRecoveryPath.resolve(MASTERKEY_FILENAME);
try (Masterkey masterkey = loadMasterkey(masterkeyFileAccess, masterkeyFilePath, tmpPass)) {
return getCipherCombo(vault.getPath(), masterkey);
}
} catch (IOException | CryptoException e) {
LOG.warn("Recovery key validation failed", e);
return Optional.empty();
} finally {
if (tempRecoveryPath != null) {
try (var masterkey = loadMasterkey(masterkeyFileAccess, masterkeyFilePath, tmpPass)) {
return getCipherCombo(vault.getPath(), masterkey);
}
} finally {
deleteRecoveryDirectory(tempRecoveryPath);
}
} catch (IOException | CryptoException e) {
LOG.info("Recovery key validation failed");
} catch (IllegalArgumentException e) {
LOG.info("Recovery key has an illegal argument");
illegalArgumentExceptionOccurred.set(true);
}
return Optional.empty();
}
public static void moveRecoveredFiles(Path recoveryPath, Path vaultPath) throws IOException {
Files.move(recoveryPath.resolve(MASTERKEY_FILENAME), vaultPath.resolve(MASTERKEY_FILENAME), StandardCopyOption.REPLACE_EXISTING);
Files.move(recoveryPath.resolve(VAULTCONFIG_FILENAME), vaultPath.resolve(VAULTCONFIG_FILENAME));

View File

@@ -26,6 +26,7 @@ import javafx.scene.control.TextArea;
import javafx.scene.control.TextFormatter;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import java.util.concurrent.atomic.AtomicBoolean;
public class RecoveryKeyValidateController implements FxController {
@@ -133,34 +134,26 @@ public class RecoveryKeyValidateController implements FxController {
}
private void validateRecoveryKey() {
isWrongKey = false;
var valid = false;
switch (recoverType.get()) {
AtomicBoolean illegalArgumentExceptionOccurred = new AtomicBoolean(false);
boolean valid = switch (recoverType.get()) {
case RESTORE_VAULT_CONFIG -> {
try {
var combo = RecoverUtil.validateRecoveryKeyAndGetCombo(recoveryKeyFactory, vault, recoveryKey, masterkeyFileAccess);
valid = combo.isPresent();
combo.ifPresent(cipherCombo::set);
} catch (IllegalStateException e) {
isWrongKey = true;
} catch (IllegalArgumentException e) {
isWrongKey = false;
}
var combo = RecoverUtil.validateRecoveryKeyAndGetCombo(
recoveryKeyFactory, vault, recoveryKey, masterkeyFileAccess, illegalArgumentExceptionOccurred);
combo.ifPresent(cipherCombo::set);
yield combo.isPresent();
}
case RESTORE_MASTERKEY, RESET_PASSWORD, SHOW_KEY, CONVERT_VAULT -> {
valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null);
}
}
case RESTORE_MASTERKEY, RESET_PASSWORD, SHOW_KEY, CONVERT_VAULT ->
recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(),
unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null);
};
if (valid) {
recoveryKeyState.set(RecoveryKeyState.CORRECT);
} else if (isWrongKey) { //set via side effect in checkKeyAgainstVaultConfig()
recoveryKeyState.set(RecoveryKeyState.WRONG);
} else {
recoveryKeyState.set(RecoveryKeyState.INVALID);
return;
}
recoveryKeyState.set(illegalArgumentExceptionOccurred.get() ? RecoveryKeyState.INVALID : RecoveryKeyState.WRONG);
}
/* Getter/Setter */
public Vault getVault() {