keyPairSupplier;
+
+ @Inject
+ public DeviceKey(KeychainManager keychainManager, Environment env, SecureRandom csprng) {
+ this.keychainManager = keychainManager;
+ this.env = env;
+ this.csprng = csprng;
+ this.keyPairSupplier = Suppliers.memoize(this::loadOrCreate);
+ }
+
+ public P384KeyPair get() throws DeviceKeyRetrievalException {
+ Preconditions.checkState(keychainManager.isSupported());
+ return keyPairSupplier.get();
+ }
+
+ private P384KeyPair loadOrCreate() throws DeviceKeyRetrievalException {
+ char[] passphrase = null;
+ try {
+ passphrase = keychainManager.loadPassphrase(KEYCHAIN_KEY);
+ if (passphrase != null) {
+ return loadExistingKeyPair(passphrase);
+ } else {
+ passphrase = randomPassword();
+ keychainManager.storePassphrase(KEYCHAIN_KEY, CharBuffer.wrap(passphrase));
+ return createAndStoreNewKeyPair(passphrase);
+ }
+ } catch (KeychainAccessException e) {
+ throw new DeviceKeyRetrievalException("Failed to access system keychain", e);
+ } catch (Pkcs12Exception | IOException e) {
+ throw new DeviceKeyRetrievalException("Failed to access .p12 file", e);
+ } finally {
+ if (passphrase != null) {
+ Arrays.fill(passphrase, '\0');
+ }
+ }
+ }
+
+ private P384KeyPair loadExistingKeyPair(char[] passphrase) throws IOException {
+ var p12File = env.getP12Path() //
+ .filter(Files::isRegularFile) //
+ .findFirst() //
+ .orElseThrow(() -> new DeviceKeyRetrievalException("Missing .p12 file"));
+ LOG.debug("Loading existing device key from {}", p12File);
+ return P384KeyPair.load(p12File, passphrase);
+ }
+
+ private P384KeyPair createAndStoreNewKeyPair(char[] passphrase) throws IOException {
+ var p12File = env.getP12Path() //
+ .findFirst() //
+ .orElseThrow(() -> new DeviceKeyRetrievalException("No path for .p12 file configured"));
+ var keyPair = P384KeyPair.generate();
+ LOG.debug("Store new device key to {}", p12File);
+ keyPair.store(p12File, passphrase);
+ return keyPair;
+ }
+
+ private char[] randomPassword() {
+ // this is a fast & easy attempt to create a random string:
+ var uuid = new UUID(csprng.nextLong(), csprng.nextLong());
+ return uuid.toString().toCharArray();
+ }
+
+ public static class DeviceKeyRetrievalException extends RuntimeException {
+ private DeviceKeyRetrievalException(String message) {
+ super(message);
+ }
+ private DeviceKeyRetrievalException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+}
diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
index 627793d6e..578b90969 100644
--- a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
+++ b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
@@ -182,7 +182,7 @@ public class CreateNewVaultPasswordController implements FxController {
// 2. initialize vault:
try {
- MasterkeyLoader loader = ignored -> masterkey.clone();
+ MasterkeyLoader loader = ignored -> masterkey.copy();
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(CryptorProvider.Scheme.SIV_CTRMAC).withKeyLoader(loader).build();
CryptoFileSystemProvider.initialize(path, fsProps, DEFAULT_KEY_ID);
diff --git a/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/src/main/java/org/cryptomator/ui/common/FxmlFile.java
index 84ef8983f..8d96dd216 100644
--- a/src/main/java/org/cryptomator/ui/common/FxmlFile.java
+++ b/src/main/java/org/cryptomator/ui/common/FxmlFile.java
@@ -15,7 +15,6 @@ public enum FxmlFile {
HEALTH_START_FAIL("/fxml/health_start_fail.fxml"), //
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), //
- HUB_P12("/fxml/hub_p12.fxml"), //
HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), //
HUB_REGISTER_DEVICE("/fxml/hub_register_device.fxml"), //
LOCK_FORCED("/fxml/lock_forced.fxml"), //
diff --git a/src/main/java/org/cryptomator/ui/health/CheckExecutor.java b/src/main/java/org/cryptomator/ui/health/CheckExecutor.java
index 5b14bd17c..a9ee9a17f 100644
--- a/src/main/java/org/cryptomator/ui/health/CheckExecutor.java
+++ b/src/main/java/org/cryptomator/ui/health/CheckExecutor.java
@@ -67,7 +67,7 @@ public class CheckExecutor {
@Override
protected Void call() throws Exception {
- try (var masterkeyClone = masterkey.clone(); //
+ try (var masterkeyClone = masterkey.copy(); //
var cryptor = CryptorProvider.forScheme(vaultConfig.getCipherCombo()).provide(masterkeyClone, csprng)) {
c.getHealthCheck().check(vaultPath, vaultConfig, masterkeyClone, cryptor, diagnosis -> {
Platform.runLater(() -> c.getResults().add(Result.create(diagnosis)));
diff --git a/src/main/java/org/cryptomator/ui/health/ResultFixApplier.java b/src/main/java/org/cryptomator/ui/health/ResultFixApplier.java
index 841a8f5c4..3dc91e33b 100644
--- a/src/main/java/org/cryptomator/ui/health/ResultFixApplier.java
+++ b/src/main/java/org/cryptomator/ui/health/ResultFixApplier.java
@@ -50,7 +50,7 @@ class ResultFixApplier {
public void fix(DiagnosticResult diagnosis) {
Preconditions.checkArgument(diagnosis.getSeverity() == DiagnosticResult.Severity.WARN, "Unfixable result");
- try (var masterkeyClone = masterkey.clone(); //
+ try (var masterkeyClone = masterkey.copy(); //
var cryptor = CryptorProvider.forScheme(vaultConfig.getCipherCombo()).provide(masterkeyClone, csprng)) {
diagnosis.fix(vaultPath, vaultConfig, masterkeyClone, cryptor);
} catch (Exception e) {
diff --git a/src/main/java/org/cryptomator/ui/health/StartController.java b/src/main/java/org/cryptomator/ui/health/StartController.java
index ebba001b5..ec980b9f0 100644
--- a/src/main/java/org/cryptomator/ui/health/StartController.java
+++ b/src/main/java/org/cryptomator/ui/health/StartController.java
@@ -84,7 +84,7 @@ public class StartController implements FxController {
try (var masterkey = keyLoadingStrategy.loadKey(unverifiedCfg.getKeyId())) {
var verifiedCfg = unverifiedCfg.verify(masterkey.getEncoded(), unverifiedCfg.allegedVaultVersion());
vaultConfigRef.set(verifiedCfg);
- var old = masterkeyRef.getAndSet(masterkey.clone());
+ var old = masterkeyRef.getAndSet(masterkey.copy());
if (old != null) {
old.destroy();
}
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/EciesHelper.java b/src/main/java/org/cryptomator/ui/keyloading/hub/EciesHelper.java
deleted file mode 100644
index b7dac36ba..000000000
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/EciesHelper.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import com.google.common.base.Preconditions;
-import com.google.common.io.BaseEncoding;
-import org.cryptomator.cryptolib.api.Masterkey;
-import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
-import org.cryptomator.cryptolib.common.CipherSupplier;
-import org.cryptomator.cryptolib.common.DestroyableSecretKey;
-
-import javax.crypto.AEADBadTagException;
-import javax.crypto.BadPaddingException;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.KeyAgreement;
-import javax.crypto.spec.GCMParameterSpec;
-import java.math.BigInteger;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.security.DigestException;
-import java.security.InvalidKeyException;
-import java.security.KeyPair;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.util.Arrays;
-
-class EciesHelper {
-
- private static final int GCM_KEY_SIZE = 32;
- private static final int GCM_TAG_SIZE = 16;
- private static final int GCM_NONCE_SIZE = 12; // 96 bit IVs strongly recommended for GCM
-
- private EciesHelper() {}
-
- public static Masterkey decryptMasterkey(KeyPair deviceKey, EciesParams eciesParams) throws MasterkeyLoadingFailedException {
- var sharedSecret = ecdhAndKdf(deviceKey.getPrivate(), eciesParams.getEphemeralPublicKey(), GCM_KEY_SIZE + GCM_NONCE_SIZE);
- var cleartext = new byte[0];
- try (var kek = new DestroyableSecretKey(sharedSecret, 0, GCM_KEY_SIZE, "AES")) {
- var nonce = Arrays.copyOfRange(sharedSecret, GCM_KEY_SIZE, GCM_KEY_SIZE + GCM_NONCE_SIZE);
- var cipher = CipherSupplier.AES_GCM.forDecryption(kek, new GCMParameterSpec(GCM_TAG_SIZE * Byte.SIZE, nonce));
- cleartext = cipher.doFinal(eciesParams.getCiphertext());
- return new Masterkey(cleartext);
- } catch (AEADBadTagException e) {
- throw new MasterkeyLoadingFailedException("Unsuitable KEK to decrypt encrypted masterkey", e);
- } catch (IllegalBlockSizeException | BadPaddingException e) {
- throw new IllegalStateException("Unexpected exception during GCM decryption.", e);
- } finally {
- Arrays.fill(sharedSecret, (byte) 0x00);
- Arrays.fill(cleartext, (byte) 0x00);
- }
- }
-
- /**
- * Computes a shared secret using ECDH key agreement and derives a key.
- *
- * @param privateKey Recipient's EC private key
- * @param publicKey Sender's EC public key
- * @param numBytes Number of bytes requested form KDF
- * @return A derived secret key
- */
- // visible for testing
- static byte[] ecdhAndKdf(PrivateKey privateKey, PublicKey publicKey, int numBytes) {
- Preconditions.checkArgument(privateKey instanceof ECPrivateKey, "expected ECPrivateKey");
- Preconditions.checkArgument(publicKey instanceof ECPublicKey, "expected ECPublicKey");
- byte[] sharedSecret = new byte[0];
- try {
- var keyAgreement = createKeyAgreement();
- keyAgreement.init(privateKey);
- keyAgreement.doPhase(publicKey, true);
- sharedSecret = keyAgreement.generateSecret();
- return kdf(sharedSecret, new byte[0], numBytes);
- } catch (InvalidKeyException e) {
- throw new IllegalArgumentException("Invalid keys", e);
- } finally {
- Arrays.fill(sharedSecret, (byte) 0x00);
- }
- }
-
- /**
- * Performs ANSI-X9.63-KDF with SHA-256
- * @param sharedSecret A shared secret
- * @param sharedInfo Additional authenticated data
- * @param keyDataLen Desired key length (in bytes)
- * @return key data
- */
- // visible for testing
- static byte[] kdf(byte[] sharedSecret, byte[] sharedInfo, int keyDataLen) {
- MessageDigest digest = sha256(); // max input length is 2^64 - 1, see https://doi.org/10.6028/NIST.SP.800-56Cr2, Table 1
- int hashLen = digest.getDigestLength();
-
- // These two checks must be performed according to spec. However with 32 bit integers, we can't exceed any limits anyway:
- assert BigInteger.valueOf(sharedSecret.length + sharedInfo.length + 4).compareTo(BigInteger.ONE.shiftLeft(64).subtract(BigInteger.ONE)) < 0: "input larger than hashmaxlen";
- assert keyDataLen < (2L << 32 - 1) * hashLen : "keyDataLen larger than hashLen × (2^32 − 1)";
-
- ByteBuffer counter = ByteBuffer.allocate(Integer.BYTES);
- assert ByteOrder.BIG_ENDIAN.equals(counter.order());
- int n = (keyDataLen + hashLen - 1) / hashLen;
- byte[] buffer = new byte[n * hashLen];
- try {
- for (int i = 0; i < n; i++) {
- digest.update(sharedSecret);
- counter.clear();
- counter.putInt(i + 1);
- counter.flip();
- digest.update(counter);
- digest.update(sharedInfo);
- digest.digest(buffer, i * hashLen, hashLen);
- }
- return Arrays.copyOf(buffer, keyDataLen);
- } catch (DigestException e) {
- throw new IllegalStateException("Invalid digest output buffer offset", e);
- } finally {
- Arrays.fill(buffer, (byte) 0x00);
- }
- }
-
- private static MessageDigest sha256() {
- try {
- return MessageDigest.getInstance("SHA-256");
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("Every implementation of the Java platform is required to support SHA-256.");
- }
- }
-
- private static KeyAgreement createKeyAgreement() {
- try {
- return KeyAgreement.getInstance("ECDH");
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("ECDH not supported");
- }
- }
-
-}
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/EciesParams.java b/src/main/java/org/cryptomator/ui/keyloading/hub/EciesParams.java
index 5e25b37f7..8b0519906 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/EciesParams.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/hub/EciesParams.java
@@ -1,43 +1,14 @@
package org.cryptomator.ui.keyloading.hub;
-import com.google.common.io.BaseEncoding;
-
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
-
/**
* ECIES parameters required to decrypt the masterkey:
*
* m Encrypted Masterkey (base64url-encoded ciphertext)
* epk Ephemeral Public Key (base64url-encoded SPKI format)
*
- *
+ *
* No separate tag required, since we use GCM for encryption.
*/
record EciesParams(String m, String epk) {
- public byte[] getCiphertext() {
- return BaseEncoding.base64Url().decode(m());
- }
-
- public ECPublicKey getEphemeralPublicKey() {
- try {
- byte[] keyBytes = BaseEncoding.base64Url().decode(epk());
- PublicKey key = KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(keyBytes));
- if (key instanceof ECPublicKey k) {
- return k;
- } else {
- throw new IllegalArgumentException("Key not an EC public key.");
- }
- } catch (InvalidKeySpecException e) {
- throw new IllegalArgumentException("Invalid license public key", e);
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException(e);
- }
- }
-
}
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java
index ad2c5c02b..f9ade2585 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java
@@ -46,12 +46,6 @@ public abstract class HubKeyLoadingModule {
}
}
- @Provides
- @KeyLoadingScoped
- static AtomicReference provideKeyPair() {
- return new AtomicReference<>();
- }
-
@Provides
@Named("bearerToken")
@KeyLoadingScoped
@@ -83,13 +77,6 @@ public abstract class HubKeyLoadingModule {
@StringKey(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS)
abstract KeyLoadingStrategy bindHubKeyLoadingStrategyToHubHttps(HubKeyLoadingStrategy strategy);
- @Provides
- @FxmlScene(FxmlFile.HUB_P12)
- @KeyLoadingScoped
- static Scene provideHubP12LoadingScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
- return fxmlLoaders.createScene(FxmlFile.HUB_P12);
- }
-
@Provides
@FxmlScene(FxmlFile.HUB_AUTH_FLOW)
@KeyLoadingScoped
@@ -97,7 +84,6 @@ public abstract class HubKeyLoadingModule {
return fxmlLoaders.createScene(FxmlFile.HUB_AUTH_FLOW);
}
-
@Provides
@FxmlScene(FxmlFile.HUB_RECEIVE_KEY)
@KeyLoadingScoped
@@ -112,22 +98,6 @@ public abstract class HubKeyLoadingModule {
return fxmlLoaders.createScene(FxmlFile.HUB_REGISTER_DEVICE);
}
-
- @Binds
- @IntoMap
- @FxControllerKey(P12Controller.class)
- abstract FxController bindP12Controller(P12Controller controller);
-
- @Binds
- @IntoMap
- @FxControllerKey(P12LoadController.class)
- abstract FxController bindP12LoadController(P12LoadController controller);
-
- @Binds
- @IntoMap
- @FxControllerKey(P12CreateController.class)
- abstract FxController bindP12CreateController(P12CreateController controller);
-
@Binds
@IntoMap
@FxControllerKey(AuthFlowController.class)
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java
index b3b213b34..83338ed06 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java
@@ -2,10 +2,12 @@ package org.cryptomator.ui.keyloading.hub;
import com.google.common.base.Preconditions;
import dagger.Lazy;
+import org.cryptomator.common.settings.DeviceKey;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptolib.api.Masterkey;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
import org.cryptomator.cryptolib.common.Destroyables;
+import org.cryptomator.cryptolib.common.MasterkeyHubAccess;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.UserInteractionLock;
@@ -30,17 +32,17 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https";
private final Stage window;
- private final Lazy p12LoadingScene;
+ private final Lazy authFlowScene;
private final UserInteractionLock userInteraction;
- private final AtomicReference keyPairRef;
+ private final DeviceKey deviceKey;
private final AtomicReference eciesParams;
@Inject
- public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_P12) Lazy p12LoadingScene, UserInteractionLock userInteraction, AtomicReference keyPairRef, AtomicReference eciesParams) {
+ public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy authFlowScene, UserInteractionLock userInteraction, DeviceKey deviceKey, AtomicReference eciesParams) {
this.window = window;
- this.p12LoadingScene = p12LoadingScene;
+ this.authFlowScene = authFlowScene;
this.userInteraction = userInteraction;
- this.keyPairRef = keyPairRef;
+ this.deviceKey = deviceKey;
this.eciesParams = eciesParams;
}
@@ -48,28 +50,23 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
public Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException {
Preconditions.checkArgument(keyId.getScheme().startsWith(SCHEME_PREFIX));
try {
+ var keyPair = deviceKey.get();
return switch (auth()) {
- case SUCCESS -> EciesHelper.decryptMasterkey(keyPairRef.get(), eciesParams.get());
+ case SUCCESS -> MasterkeyHubAccess.decryptMasterkey(keyPair.getPrivate(), eciesParams.get().m(), eciesParams.get().epk());
case FAILED -> throw new MasterkeyLoadingFailedException("failed to load keypair");
case CANCELLED -> throw new UnlockCancelledException("User cancelled auth workflow");
};
+ } catch (DeviceKey.DeviceKeyRetrievalException e) {
+ throw new MasterkeyLoadingFailedException("Failed to create or load device key pair", e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new UnlockCancelledException("Loading interrupted", e);
}
}
- @Override
- public void cleanup(boolean unlockedSuccessfully) {
- var keyPair = keyPairRef.getAndSet(null);
- if (keyPair != null) {
- Destroyables.destroySilently(keyPair.getPrivate());
- }
- }
-
private HubKeyLoadingModule.HubLoadingResult auth() throws InterruptedException {
Platform.runLater(() -> {
- window.setScene(p12LoadingScene.get());
+ window.setScene(authFlowScene.get());
window.show();
Window owner = window.getOwner();
if (owner != null) {
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/P12AccessHelper.java b/src/main/java/org/cryptomator/ui/keyloading/hub/P12AccessHelper.java
deleted file mode 100644
index 99bd7d3fe..000000000
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/P12AccessHelper.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import org.cryptomator.cryptolib.api.InvalidPassphraseException;
-import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.nio.file.StandardOpenOption;
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.X509Certificate;
-import java.security.spec.ECGenParameterSpec;
-
-class P12AccessHelper {
-
- private static final String EC_ALG = "EC";
- private static final String EC_CURVE_NAME = "secp384r1";
- private static final String SIGNATURE_ALG = "SHA256withECDSA";
- private static final String KEYSTORE_ALIAS_KEY = "key";
- private static final String KEYSTORE_ALIAS_CERT = "crt";
-
- private P12AccessHelper() {}
-
- /**
- * Creates a new key pair and stores it in PKCS#12 format at the given path.
- *
- * @param p12File The path of the .p12 file
- * @param pw The password to protect the key material
- * @throws IOException In case of I/O errors
- * @throws MasterkeyLoadingFailedException If any cryptographic operation fails
- */
- public static KeyPair createNew(Path p12File, char[] pw) throws IOException, MasterkeyLoadingFailedException {
- try {
- var keyPair = getKeyPairGenerator().generateKeyPair();
- var keyStore = getKeyStore();
- keyStore.load(null, pw);
- var cert = X509Helper.createSelfSignedCert(keyPair, SIGNATURE_ALG);
- var chain = new X509Certificate[]{cert};
- keyStore.setKeyEntry(KEYSTORE_ALIAS_KEY, keyPair.getPrivate(), pw, chain);
- keyStore.setCertificateEntry(KEYSTORE_ALIAS_CERT, cert);
- var tmpFile = p12File.resolveSibling(p12File.getFileName().toString() + ".tmp");
- try (var out = Files.newOutputStream(tmpFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
- keyStore.store(out, pw);
- }
- Files.move(tmpFile, p12File, StandardCopyOption.REPLACE_EXISTING);
- return keyPair;
- } catch (GeneralSecurityException e) {
- throw new MasterkeyLoadingFailedException("Failed to store PKCS12 file.", e);
- }
- }
-
- /**
- * Loads a key pair from a PKCS#12 file located at the given path.
- *
- * @param p12File The path of the .p12 file
- * @param pw The password to protect the key material
- * @throws IOException In case of I/O errors
- * @throws InvalidPassphraseException If the supplied password is incorrect
- * @throws MasterkeyLoadingFailedException If any cryptographic operation fails
- */
- public static KeyPair loadExisting(Path p12File, char[] pw) throws IOException, InvalidPassphraseException, MasterkeyLoadingFailedException {
- try (var in = Files.newInputStream(p12File, StandardOpenOption.READ)) {
- var keyStore = getKeyStore();
- keyStore.load(in, pw);
- var sk = (PrivateKey) keyStore.getKey(KEYSTORE_ALIAS_KEY, pw);
- var pk = keyStore.getCertificate(KEYSTORE_ALIAS_CERT).getPublicKey();
- return new KeyPair(pk, sk);
- } catch (UnrecoverableKeyException e) {
- throw new InvalidPassphraseException();
- } catch (IOException e) {
- if (e.getCause() instanceof UnrecoverableKeyException) {
- throw new InvalidPassphraseException();
- } else {
- throw e;
- }
- } catch (GeneralSecurityException e) {
- throw new MasterkeyLoadingFailedException("Failed to load PKCS12 file.", e);
- }
- }
-
- private static KeyPairGenerator getKeyPairGenerator() {
- try {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance(EC_ALG);
- keyGen.initialize(new ECGenParameterSpec(EC_CURVE_NAME));
- return keyGen;
- } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException e) {
- throw new IllegalStateException(EC_CURVE_NAME + " curve not supported");
- }
- }
-
- private static KeyStore getKeyStore() {
- try {
- return KeyStore.getInstance("PKCS12");
- } catch (KeyStoreException e) {
- throw new IllegalStateException("Every implementation of the Java platform is required to support PKCS12.");
- }
- }
-
-}
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/P12Controller.java b/src/main/java/org/cryptomator/ui/keyloading/hub/P12Controller.java
deleted file mode 100644
index e9a70dc8d..000000000
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/P12Controller.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import org.cryptomator.common.Environment;
-import org.cryptomator.ui.common.FxController;
-import org.cryptomator.ui.common.UserInteractionLock;
-import org.cryptomator.ui.keyloading.KeyLoading;
-import org.cryptomator.ui.keyloading.KeyLoadingScoped;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-import javafx.stage.Stage;
-import javafx.stage.WindowEvent;
-import java.nio.file.Files;
-
-@KeyLoadingScoped
-public class P12Controller implements FxController {
-
- private static final Logger LOG = LoggerFactory.getLogger(P12Controller.class);
-
- private final Stage window;
- private final Environment env;
- private final UserInteractionLock userInteraction;
-
- @Inject
- public P12Controller(@KeyLoading Stage window, Environment env, UserInteractionLock userInteraction) {
- this.window = window;
- this.env = env;
- this.userInteraction = userInteraction;
- this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
- }
-
- private void windowClosed(WindowEvent windowEvent) {
- // if not already interacted, mark this workflow as cancelled:
- if (userInteraction.awaitingInteraction().get()) {
- LOG.debug("P12 loading cancelled by user.");
- userInteraction.interacted(HubKeyLoadingModule.HubLoadingResult.CANCELLED);
- }
- }
-
- /* Getter/Setter */
-
- public boolean isP12Present() {
- return env.getP12Path().anyMatch(Files::isRegularFile);
- }
-
-}
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/P12CreateController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/P12CreateController.java
deleted file mode 100644
index 3f98e62ca..000000000
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/P12CreateController.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import com.google.common.base.Preconditions;
-import dagger.Lazy;
-import org.cryptomator.common.Environment;
-import org.cryptomator.cryptolib.common.Destroyables;
-import org.cryptomator.ui.common.FxController;
-import org.cryptomator.ui.common.FxmlFile;
-import org.cryptomator.ui.common.FxmlScene;
-import org.cryptomator.ui.common.NewPasswordController;
-import org.cryptomator.ui.keyloading.KeyLoading;
-import org.cryptomator.ui.keyloading.KeyLoadingScoped;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-import javafx.beans.binding.Bindings;
-import javafx.beans.binding.BooleanExpression;
-import javafx.beans.binding.ObjectBinding;
-import javafx.beans.binding.ObjectExpression;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.SimpleBooleanProperty;
-import javafx.fxml.FXML;
-import javafx.scene.Scene;
-import javafx.scene.control.ContentDisplay;
-import javafx.stage.Stage;
-import javafx.stage.WindowEvent;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.security.KeyPair;
-import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicReference;
-
-@KeyLoadingScoped
-public class P12CreateController implements FxController {
-
- private static final Logger LOG = LoggerFactory.getLogger(P12LoadController.class);
-
- private final Stage window;
- private final Environment env;
- private final AtomicReference keyPairRef;
- private final Lazy authFlowScene;
-
- private final BooleanProperty userInteractionDisabled = new SimpleBooleanProperty();
- private final ObjectBinding unlockButtonContentDisplay = Bindings.createObjectBinding(this::getUnlockButtonContentDisplay, userInteractionDisabled);
- private final BooleanProperty readyToCreate = new SimpleBooleanProperty();
-
- public NewPasswordController newPasswordController;
-
- @Inject
- public P12CreateController(@KeyLoading Stage window, Environment env, AtomicReference keyPairRef, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy authFlowScene) {
- this.window = window;
- this.env = env;
- this.keyPairRef = keyPairRef;
- this.authFlowScene = authFlowScene;
- this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
- }
-
- @FXML
- public void initialize() {
- readyToCreate.bind(newPasswordController.goodPasswordProperty());
- newPasswordController.passwordField.requestFocus();
- }
-
- @FXML
- public void cancel() {
- window.close();
- }
-
- private void windowClosed(WindowEvent windowEvent) {
- newPasswordController.passwordField.wipe();
- newPasswordController.reenterField.wipe();
- }
-
- @FXML
- public void create() {
- Preconditions.checkState(newPasswordController.goodPasswordProperty().get());
- char[] pw = newPasswordController.passwordField.copyChars();
- try {
- Path p12File = env.getP12Path().findFirst().orElseThrow(IllegalStateException::new);
- var keyPair = P12AccessHelper.createNew(p12File, pw);
- setKeyPair(keyPair);
- LOG.debug("Created .p12 file {}", p12File);
- window.setScene(authFlowScene.get());
- } catch (IOException e) {
- LOG.error("Failed to load .p12 file.", e);
- // TODO
- } finally {
- Arrays.fill(pw, '\0');
- }
- }
-
- private void setKeyPair(KeyPair keyPair) {
- var oldKeyPair = keyPairRef.getAndSet(keyPair);
- if (oldKeyPair != null) {
- Destroyables.destroySilently(oldKeyPair.getPrivate());
- }
- }
- /* Getter/Setter */
-
-
- public BooleanExpression userInteractionDisabledProperty() {
- return userInteractionDisabled;
- }
-
- public boolean isUserInteractionDisabled() {
- return userInteractionDisabled.get();
- }
-
- public ObjectExpression unlockButtonContentDisplayProperty() {
- return unlockButtonContentDisplay;
- }
-
- public ContentDisplay getUnlockButtonContentDisplay() {
- return userInteractionDisabled.get() ? ContentDisplay.LEFT : ContentDisplay.TEXT_ONLY;
- }
-
- public BooleanProperty readyToCreateProperty() {
- return readyToCreate;
- }
-
- public boolean isReadyToCreate() {
- return readyToCreate.get();
- }
-
-}
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/P12LoadController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/P12LoadController.java
deleted file mode 100644
index 24af08384..000000000
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/P12LoadController.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import dagger.Lazy;
-import org.cryptomator.common.Environment;
-import org.cryptomator.cryptolib.api.InvalidPassphraseException;
-import org.cryptomator.cryptolib.common.Destroyables;
-import org.cryptomator.ui.common.Animations;
-import org.cryptomator.ui.common.FxController;
-import org.cryptomator.ui.common.FxmlFile;
-import org.cryptomator.ui.common.FxmlScene;
-import org.cryptomator.ui.controls.NiceSecurePasswordField;
-import org.cryptomator.ui.keyloading.KeyLoading;
-import org.cryptomator.ui.keyloading.KeyLoadingScoped;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-import javafx.beans.binding.Bindings;
-import javafx.beans.binding.BooleanExpression;
-import javafx.beans.binding.ObjectBinding;
-import javafx.beans.binding.ObjectExpression;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.SimpleBooleanProperty;
-import javafx.fxml.FXML;
-import javafx.scene.Scene;
-import javafx.scene.control.ContentDisplay;
-import javafx.stage.Stage;
-import javafx.stage.WindowEvent;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.security.KeyPair;
-import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicReference;
-
-@KeyLoadingScoped
-public class P12LoadController implements FxController {
-
- private static final Logger LOG = LoggerFactory.getLogger(P12LoadController.class);
-
- private final Stage window;
- private final Environment env;
- private final AtomicReference keyPairRef;
- private final Lazy authFlowScene;
- private final BooleanProperty userInteractionDisabled = new SimpleBooleanProperty();
- private final ObjectBinding unlockButtonContentDisplay = Bindings.createObjectBinding(this::getUnlockButtonContentDisplay, userInteractionDisabled);
-
- public NiceSecurePasswordField passwordField;
-
- @Inject
- public P12LoadController(@KeyLoading Stage window, Environment env, AtomicReference keyPairRef, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy authFlowScene) {
- this.window = window;
- this.env = env;
- this.keyPairRef = keyPairRef;
- this.authFlowScene = authFlowScene;
- this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
- }
-
- @FXML
- public void initialize() {
- passwordField.requestFocus();
- }
-
- @FXML
- public void cancel() {
- window.close();
- }
-
- private void windowClosed(WindowEvent windowEvent) {
- passwordField.wipe();
- }
-
- @FXML
- public void load() {
- char[] pw = passwordField.copyChars();
- try {
- Path p12File = env.getP12Path().filter(Files::isRegularFile).findFirst().orElseThrow(IllegalStateException::new);
- var keyPair = P12AccessHelper.loadExisting(p12File, pw);
- setKeyPair(keyPair);
- LOG.debug("Loaded .p12 file {}", p12File);
- window.setScene(authFlowScene.get());
- } catch (InvalidPassphraseException e) {
- LOG.warn("Invalid passphrase entered for .p12 file");
- Animations.createShakeWindowAnimation(window).playFromStart();
- // TODO
- } catch (IOException e) {
- LOG.error("Failed to load .p12 file.", e);
- // TODO
- } finally {
- Arrays.fill(pw, '\0');
- }
- }
-
- private void setKeyPair(KeyPair keyPair) {
- var oldKeyPair = keyPairRef.getAndSet(keyPair);
- if (oldKeyPair != null) {
- Destroyables.destroySilently(oldKeyPair.getPrivate());
- }
- }
-
- /* Getter/Setter */
-
- public BooleanExpression userInteractionDisabledProperty() {
- return userInteractionDisabled;
- }
-
- public boolean isUserInteractionDisabled() {
- return userInteractionDisabled.get();
- }
-
- public ObjectExpression unlockButtonContentDisplayProperty() {
- return unlockButtonContentDisplay;
- }
-
- public ContentDisplay getUnlockButtonContentDisplay() {
- return userInteractionDisabled.get() ? ContentDisplay.LEFT : ContentDisplay.TEXT_ONLY;
- }
-}
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java
index 9707981ec..295aa9244 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java
@@ -59,7 +59,7 @@ public class ReceiveKeyController implements FxController {
private final HttpClient httpClient;
@Inject
- public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, AtomicReference keyPairRef, @Named("bearerToken") AtomicReference tokenRef, AtomicReference eciesParamsRef, UserInteractionLock result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy registerDeviceScene, ErrorComponent.Builder errorComponent) {
+ public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, @Named("bearerToken") AtomicReference tokenRef, AtomicReference eciesParamsRef, UserInteractionLock result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy registerDeviceScene, ErrorComponent.Builder errorComponent) {
this.window = window;
this.bearerToken = Objects.requireNonNull(tokenRef.get());
this.eciesParamsRef = eciesParamsRef;
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java
index 68654a632..ba2c308c7 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterDeviceController.java
@@ -1,6 +1,8 @@
package org.cryptomator.ui.keyloading.hub;
import com.google.common.io.BaseEncoding;
+import org.cryptomator.common.settings.DeviceKey;
+import org.cryptomator.cryptolib.common.P384KeyPair;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.UserInteractionLock;
import org.cryptomator.ui.keyloading.KeyLoading;
@@ -25,16 +27,16 @@ public class RegisterDeviceController implements FxController {
private final Application application;
private final Stage window;
private final HubConfig hubConfig;
- private final KeyPair keyPair;
+ private final P384KeyPair keyPair;
private final UserInteractionLock result;
private final String verificationCode;
@Inject
- public RegisterDeviceController(Application application, SecureRandom csprng, @KeyLoading Stage window, HubConfig hubConfig, AtomicReference keyPairRef, UserInteractionLock result) {
+ public RegisterDeviceController(Application application, SecureRandom csprng, @KeyLoading Stage window, HubConfig hubConfig, DeviceKey deviceKey, UserInteractionLock result) {
this.application = application;
this.window = window;
this.hubConfig = hubConfig;
- this.keyPair = Objects.requireNonNull(keyPairRef.get());
+ this.keyPair = Objects.requireNonNull(deviceKey.get());
this.result = result;
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
this.verificationCode = String.format("%06d", csprng.nextInt(1_000_000));
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/X509Helper.java b/src/main/java/org/cryptomator/ui/keyloading/hub/X509Helper.java
deleted file mode 100644
index d9b7b953a..000000000
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/X509Helper.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.cert.X509v3CertificateBuilder;
-import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
-import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.math.BigInteger;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.sql.Date;
-import java.time.Instant;
-import java.time.temporal.ChronoUnit;
-import java.util.UUID;
-
-class X509Helper {
-
- private static final X500Name ISSUER = new X500Name("CN=Cryptomator");
- private static final X500Name SUBJECT = new X500Name("CN=Self Signed Cert");
- private static final ASN1ObjectIdentifier ASN1_SUBJECT_KEY_ID = new ASN1ObjectIdentifier("2.5.29.14");
-
- private X509Helper() {}
-
- /**
- * Creates a self-signed X509Certificate containing the public key and signed with the private key of a given key pair.
- *
- * @param keyPair A key pair
- * @param signatureAlg A signature algorithm suited for the given key pair (see available algorithms)
- * @return A self-signed X509Certificate
- * @throws CertificateException If certificate generation failed, e.g. because of unsupported algorithms
- */
- public static X509Certificate createSelfSignedCert(KeyPair keyPair, String signatureAlg) throws CertificateException {
- try {
- X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder( //
- ISSUER, //
- randomSerialNo(), //
- Date.from(Instant.now()), //
- Date.from(Instant.now().plus(3650, ChronoUnit.DAYS)), //
- SUBJECT, //
- keyPair.getPublic());
- certificateBuilder.addExtension(ASN1_SUBJECT_KEY_ID, false, getX509ExtensionUtils().createSubjectKeyIdentifier(keyPair.getPublic()));
- var signer = new JcaContentSignerBuilder(signatureAlg).build(keyPair.getPrivate());
- var cert = certificateBuilder.build(signer);
- try (InputStream in = new ByteArrayInputStream(cert.getEncoded())) {
- return (X509Certificate) getCertFactory().generateCertificate(in);
- }
- } catch (IOException | OperatorCreationException e) {
- throw new CertificateException(e);
- }
- }
-
- private static BigInteger randomSerialNo() {
- return BigInteger.valueOf(UUID.randomUUID().getMostSignificantBits());
- }
-
- private static JcaX509ExtensionUtils getX509ExtensionUtils() {
- try {
- return new JcaX509ExtensionUtils();
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("Every implementation of the Java platform is required to support SHA-1.");
- }
- }
-
- private static CertificateFactory getCertFactory() {
- try {
- return CertificateFactory.getInstance("X.509");
- } catch (CertificateException e) {
- throw new IllegalStateException("Every implementation of the Java platform is required to support X.509.");
- }
- }
-
-}
diff --git a/src/main/resources/fxml/hub_p12.fxml b/src/main/resources/fxml/hub_p12.fxml
deleted file mode 100644
index 505e2b8a6..000000000
--- a/src/main/resources/fxml/hub_p12.fxml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/fxml/hub_p12_create.fxml b/src/main/resources/fxml/hub_p12_create.fxml
deleted file mode 100644
index a4897cbc9..000000000
--- a/src/main/resources/fxml/hub_p12_create.fxml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/fxml/hub_p12_load.fxml b/src/main/resources/fxml/hub_p12_load.fxml
deleted file mode 100644
index 98fde1dd0..000000000
--- a/src/main/resources/fxml/hub_p12_load.fxml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/main/resources/license/THIRD-PARTY.txt b/src/main/resources/license/THIRD-PARTY.txt
index 0ed1b3cff..6f06bbb39 100644
--- a/src/main/resources/license/THIRD-PARTY.txt
+++ b/src/main/resources/license/THIRD-PARTY.txt
@@ -11,7 +11,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
-Cryptomator uses 46 third-party dependencies under the following licenses:
+Cryptomator uses 43 third-party dependencies under the following licenses:
Apache License v2.0:
- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
- jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
@@ -44,10 +44,6 @@ Cryptomator uses 46 third-party dependencies under the following licenses:
- asm-commons (org.ow2.asm:asm-commons:7.1 - http://asm.ow2.org/)
- asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
- asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
- Bouncy Castle Licence:
- - Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk15on:1.69 - https://www.bouncycastle.org/java.html)
- - Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15on:1.69 - https://www.bouncycastle.org/java.html)
- - Bouncy Castle ASN.1 Extension and Utility APIs (org.bouncycastle:bcutil-jdk15on:1.69 - https://www.bouncycastle.org/java.html)
Eclipse Public License - Version 1.0:
- Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - https://eclipse.org/jetty/jetty-servlet-api)
Eclipse Public License - Version 2.0:
diff --git a/src/test/java/org/cryptomator/ui/keyloading/hub/EciesHelperTest.java b/src/test/java/org/cryptomator/ui/keyloading/hub/EciesHelperTest.java
deleted file mode 100644
index 0bb432608..000000000
--- a/src/test/java/org/cryptomator/ui/keyloading/hub/EciesHelperTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import com.google.common.io.BaseEncoding;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.extension.ParameterContext;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.converter.ArgumentConversionException;
-import org.junit.jupiter.params.converter.ArgumentConverter;
-import org.junit.jupiter.params.converter.ConvertWith;
-import org.junit.jupiter.params.provider.CsvSource;
-import org.junit.jupiter.params.provider.ValueSource;
-
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-
-public class EciesHelperTest {
-
- @DisplayName("ECDH + KDF")
- @ParameterizedTest
- @ValueSource(ints = {16, 32, 44, 128})
- public void testEcdhAndKdf(int len) throws NoSuchAlgorithmException {
- var alice = KeyPairGenerator.getInstance("EC").generateKeyPair();
- var bob = KeyPairGenerator.getInstance("EC").generateKeyPair();
-
- byte[] result1 = EciesHelper.ecdhAndKdf(alice.getPrivate(), bob.getPublic(), len);
- byte[] result2 = EciesHelper.ecdhAndKdf(bob.getPrivate(), alice.getPublic(), len);
-
- Assertions.assertArrayEquals(result1, result2);
- }
-
- @DisplayName("ANSI-X9.63-KDF")
- @ParameterizedTest
- @CsvSource(value = {
- "96c05619d56c328ab95fe84b18264b08725b85e33fd34f08, , 16, 443024c3dae66b95e6f5670601558f71",
- "96f600b73ad6ac5629577eced51743dd2c24c21b1ac83ee4, , 16, b6295162a7804f5667ba9070f82fa522",
- "22518b10e70f2a3f243810ae3254139efbee04aa57c7af7d, 75eef81aa3041e33b80971203d2c0c52, 128, c498af77161cc59f2962b9a713e2b215152d139766ce34a776df11866a69bf2e52a13d9c7c6fc878c50c5ea0bc7b00e0da2447cfd874f6cf92f30d0097111485500c90c3af8b487872d04685d14c8d1dc8d7fa08beb0ce0ababc11f0bd496269142d43525a78e5bc79a17f59676a5706dc54d54d4d1f0bd7e386128ec26afc21",
- "7e335afa4b31d772c0635c7b0e06f26fcd781df947d2990a, d65a4812733f8cdbcdfb4b2f4c191d87, 128, c0bd9e38a8f9de14c2acd35b2f3410c6988cf02400543631e0d6a4c1d030365acbf398115e51aaddebdc9590664210f9aa9fed770d4c57edeafa0b8c14f93300865251218c262d63dadc47dfa0e0284826793985137e0a544ec80abf2fdf5ab90bdaea66204012efe34971dc431d625cd9a329b8217cc8fd0d9f02b13f2f6b0b",
- })
- // test vectors from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/components/800-135testvectors/ansx963_2001.zip
- public void testKdf(@ConvertWith(HexConverter.class) byte[] sharedSecret, @ConvertWith(HexConverter.class) byte[] sharedInfo, int outLen, @ConvertWith(HexConverter.class) byte[] expectedResult) {
- byte[] result = EciesHelper.kdf(sharedSecret, sharedInfo, outLen);
- Assertions.assertArrayEquals(expectedResult, result);
- }
-
- public static class HexConverter implements ArgumentConverter {
-
- @Override
- public byte[] convert(Object source, ParameterContext context) throws ArgumentConversionException {
- if (source == null) {
- return new byte[0];
- } else if (source instanceof String s) {
- return BaseEncoding.base16().lowerCase().decode(s);
- } else {
- return null;
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/org/cryptomator/ui/keyloading/hub/P12AccessHelperTest.java b/src/test/java/org/cryptomator/ui/keyloading/hub/P12AccessHelperTest.java
deleted file mode 100644
index a92eb40b3..000000000
--- a/src/test/java/org/cryptomator/ui/keyloading/hub/P12AccessHelperTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import org.cryptomator.cryptolib.api.InvalidPassphraseException;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-public class P12AccessHelperTest {
-
- @Test
- public void testCreate(@TempDir Path tmpDir) throws IOException {
- var p12File = tmpDir.resolve("test.p12");
-
- var keyPair = P12AccessHelper.createNew(p12File, "asd".toCharArray());
-
- Assertions.assertNotNull(keyPair);
- Assertions.assertTrue(Files.exists(p12File));
- }
-
- @Nested
- public class ExistingFile {
-
- private Path p12File;
-
- @BeforeEach
- public void setup(@TempDir Path tmpDir) throws IOException {
- p12File = tmpDir.resolve("test.p12");
- P12AccessHelper.createNew(p12File, "foo".toCharArray());
- }
-
- @Test
- public void testLoadWithWrongPassword() {
- Assertions.assertThrows(InvalidPassphraseException.class, () -> {
- P12AccessHelper.loadExisting(p12File, "bar".toCharArray());
- });
- }
-
- @Test
- public void testLoad() throws IOException {
- var keyPair = P12AccessHelper.loadExisting(p12File, "foo".toCharArray());
-
- Assertions.assertNotNull(keyPair);
- }
- }
-
-}
\ No newline at end of file
diff --git a/src/test/java/org/cryptomator/ui/keyloading/hub/X509HelperTest.java b/src/test/java/org/cryptomator/ui/keyloading/hub/X509HelperTest.java
deleted file mode 100644
index 79abc82f4..000000000
--- a/src/test/java/org/cryptomator/ui/keyloading/hub/X509HelperTest.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.cryptomator.ui.keyloading.hub;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-import java.io.IOException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyPairGenerator;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.security.spec.ECGenParameterSpec;
-
-public class X509HelperTest {
-
- @Test
- public void testCreateCert() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException, InvalidAlgorithmParameterException {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
- keyGen.initialize(new ECGenParameterSpec("secp256r1"));
- var keyPair = keyGen.generateKeyPair();
- var cert = X509Helper.createSelfSignedCert(keyPair, "SHA256withECDSA");
- Assertions.assertNotNull(cert);
- }
-
-}
\ No newline at end of file