Skip to content

Commit

Permalink
MVP for transparent filesystem encryption
Browse files Browse the repository at this point in the history
  • Loading branch information
MarvinKlar committed Jul 6, 2024
1 parent d662eb8 commit 067b6fe
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 35 deletions.
18 changes: 18 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@
<version>1.3.2</version>
</dependency>

<!-- File system encryption for data store -->
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>cryptofs</artifactId>
<version>2.6.9</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>
<!-- Force, to get Java 22 support -->
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>cryptolib</artifactId>
<version>2.2.0</version>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down
140 changes: 105 additions & 35 deletions src/main/java/link/biosmarcel/baka/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,37 @@
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TabPane;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import link.biosmarcel.baka.data.Data;
import link.biosmarcel.baka.view.AccountsView;
import link.biosmarcel.baka.view.EvaluationView;
import link.biosmarcel.baka.view.PaymentsView;
import org.eclipse.store.storage.embedded.configuration.types.EmbeddedStorageConfiguration;
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptolib.api.Masterkey;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.eclipse.store.afs.nio.types.NioFileSystem;
import org.eclipse.store.storage.embedded.types.EmbeddedStorageFoundation;
import org.eclipse.store.storage.types.Storage;
import org.eclipse.store.storage.types.StorageBackupSetup;
import org.eclipse.store.storage.types.StorageChannelCountProvider;
import org.eclipse.store.storage.types.StorageConfiguration;

import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.spec.KeySpec;
import java.util.Objects;

public class Main extends Application {
Expand All @@ -26,48 +46,98 @@ private static Path getDataDir(final String... children) {

@Override
public void start(Stage stage) {
final Data data = new Data();
final var storageManager = EmbeddedStorageConfiguration
.Builder()
.setStorageDirectory(getDataDir("storage").toString())
.setBackupDirectory(getDataDir("backup").toString())
.setChannelCount(1)
.createEmbeddedStorageFoundation()
//.onConnectionFoundation((connection) -> {
// // Log which fields are persisted.
// connection.setFieldEvaluatorPersistable((entityType, field) -> {
// final var result = Persistence.isPersistableField(entityType, field);
// System.out.println("'" + field.getName() + "' " + field.getType() + "=" + result);
// return result;
// });
//})
.setRoot(data)
.start();

ApplicationState state = new ApplicationState(storageManager, storageManager.createEagerStorer(), data);

TabPane tabs = new TabPane(
new PaymentsView(state),
new AccountsView(state),
new EvaluationView(state)
);
tabs.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);

Scene scene = new Scene(tabs, 800, 600);
scene.getStylesheets().add(Objects.requireNonNull(Main.class.getResource("base.css")).toExternalForm());
stage.setTitle("Baka");
stage.getIcons().add(new Image(getClass().getResourceAsStream("icon.png")));
stage.setScene(scene);

// FIXME This seems dumb?
Platform.setImplicitExit(true);
stage.setOnCloseRequest((ae) -> {
Platform.exit();
System.exit(0);
});

final TabPane tabs = new TabPane();
final Scene scene = new Scene(tabs, 800, 600);
scene.getStylesheets().add(Objects.requireNonNull(Main.class.getResource("base.css")).toExternalForm());
stage.setScene(scene);

stage.sizeToScene();
stage.show();

PasswordField passwordField = new PasswordField();
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.initOwner(stage);
alert.getDialogPane().setContent(passwordField);
alert.setTitle(stage.getTitle() + " - Vault Access");
alert.setHeaderText("Please insert your master password to encrypt the data:");
final var choice = alert.showAndWait();

if (!(choice.isPresent() && choice.get().equals(ButtonType.OK))) {
Platform.exit();
return;
}

try {
Files.createDirectories(getDataDir("vault"));

SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(passwordField.getText().toCharArray(),
"2394ec46e279b2a6c9b7a6ec634ed4738866e6f4".getBytes(), 65536, 512);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");

try (
Masterkey masterkey = new Masterkey(key.getEncoded());
) {
MasterkeyLoader loader =
ignoredUri -> masterkey.copy(); //create a copy because the key handed over to init() method will be destroyed
CryptoFileSystemProperties
fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withKeyLoader(loader).build();

if (!Files.exists(getDataDir("vault", "vault.cryptomator"))) {
CryptoFileSystemProvider.initialize(getDataDir("vault"), fsProps, URI.create("baka"));
}

final var data = new Data();
final var cryptoFS = CryptoFileSystemProvider.newFileSystem(getDataDir("vault"), fsProps);
final var nioFS = NioFileSystem.New(cryptoFS);
final var storageManager = EmbeddedStorageFoundation.New()
.setConfiguration(
StorageConfiguration.Builder()
.setStorageFileProvider(
Storage.FileProviderBuilder(nioFS)
.setDirectory(nioFS.ensureDirectoryPath("/storageDir"))
.createFileProvider()
)
.setChannelCountProvider(
StorageChannelCountProvider.New(1)) // Limited to 1 for CryptoFS
.setBackupSetup(StorageBackupSetup.New(
nioFS.ensureDirectoryPath("/backupDir")
))
.createConfiguration()
)
.setRoot(data)
.createEmbeddedStorageManager()
.start();

final ApplicationState state =
new ApplicationState(storageManager, storageManager.createEagerStorer(), data);
tabs.getTabs().addAll(
new PaymentsView(state),
new AccountsView(state),
new EvaluationView(state)
);
tabs.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);

stage.setOnCloseRequest((ae) -> {
try {
cryptoFS.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
Platform.exit();
System.exit(0);
});

}
} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public static void main(String[] __) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
requires org.apache.commons.csv;
requires org.eclipse.store.storage.embedded.configuration;
requires org.jspecify;
requires org.cryptomator.cryptolib;
requires org.cryptomator.cryptofs;
requires jdk.crypto.ec;

exports link.biosmarcel.baka;
exports link.biosmarcel.baka.bankimport;
Expand Down

0 comments on commit 067b6fe

Please sign in to comment.