diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml
new file mode 100644
index 000000000..4fab0ebc6
--- /dev/null
+++ b/main/keychain/pom.xml
@@ -0,0 +1,39 @@
+
+ 4.0.0
+
+ org.cryptomator
+ main
+ 1.2.0-SNAPSHOT
+
+ keychain
+ System Keychain Access
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ org.bouncycastle
+ bcprov-jdk15on
+ 1.54
+
+
+
+
+ com.google.dagger
+ dagger
+
+
+ com.google.dagger
+ dagger-compiler
+ provided
+
+
+
+
+ org.cryptomator
+ commons-test
+
+
+
\ No newline at end of file
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java
new file mode 100644
index 000000000..af2152ce6
--- /dev/null
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java
@@ -0,0 +1,19 @@
+package org.cryptomator.keychain;
+
+public interface KeychainAccess {
+
+ /**
+ * Associates a passphrase with a given key.
+ *
+ * @param key Key used to retrieve the passphrase via {@link #loadPassphrase(String)}.
+ * @param passphrase The secret to store in this keychain.
+ */
+ void storePassphrase(String key, CharSequence passphrase);
+
+ /**
+ * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}.
+ * @return The stored passphrase for the given key or null if no value for the given key could be found.
+ */
+ CharSequence loadPassphrase(String key);
+
+}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java
new file mode 100644
index 000000000..b304d6edf
--- /dev/null
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java
@@ -0,0 +1,10 @@
+package org.cryptomator.keychain;
+
+interface KeychainAccessStrategy extends KeychainAccess {
+
+ /**
+ * @return true if this KeychainAccessStrategy works on the current machine.
+ */
+ boolean isSupported();
+
+}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainComponent.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainComponent.java
new file mode 100644
index 000000000..0264aa3fc
--- /dev/null
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainComponent.java
@@ -0,0 +1,15 @@
+package org.cryptomator.keychain;
+
+import java.util.Optional;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+
+@Singleton
+@Component(modules = KeychainModule.class)
+public interface KeychainComponent {
+
+ Optional keychainAccess();
+
+}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java
new file mode 100644
index 000000000..ab593f674
--- /dev/null
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java
@@ -0,0 +1,26 @@
+package org.cryptomator.keychain;
+
+import java.util.Optional;
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.ElementsIntoSet;
+
+@Module
+public class KeychainModule {
+
+ @Provides
+ @ElementsIntoSet
+ Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsSystemKeychainAccess winKeychain) {
+ return Sets.newHashSet(macKeychain, winKeychain);
+ }
+
+ @Provides
+ public Optional provideSupportedKeychain(Set keychainAccessStrategies) {
+ return keychainAccessStrategies.stream().filter(KeychainAccessStrategy::isSupported).map(KeychainAccess.class::cast).findFirst();
+ }
+
+}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java
new file mode 100644
index 000000000..55a5e6ce9
--- /dev/null
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java
@@ -0,0 +1,45 @@
+package org.cryptomator.keychain;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.commons.lang3.SystemUtils;
+
+@Singleton
+class MacSystemKeychainAccess implements KeychainAccessStrategy {
+
+ private final KeyStore keyStore;
+
+ @Inject
+ public MacSystemKeychainAccess() {
+ KeyStore ks;
+ try {
+ ks = KeyStore.getInstance("KeychainStore", "Apple");
+ ks.load(null);
+ } catch (GeneralSecurityException | IOException e) {
+ ks = null;
+ }
+ this.keyStore = ks;
+ }
+
+ @Override
+ public void storePassphrase(String key, CharSequence passphrase) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public CharSequence loadPassphrase(String key) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return SystemUtils.IS_OS_MAC_OSX && keyStore != null;
+ }
+
+}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsSystemKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsSystemKeychainAccess.java
new file mode 100644
index 000000000..61aed5af9
--- /dev/null
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsSystemKeychainAccess.java
@@ -0,0 +1,45 @@
+package org.cryptomator.keychain;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.apache.commons.lang3.SystemUtils;
+
+@Singleton
+class WindowsSystemKeychainAccess implements KeychainAccessStrategy {
+
+ private final KeyStore keyStore;
+
+ @Inject
+ public WindowsSystemKeychainAccess() {
+ KeyStore ks;
+ try {
+ ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
+ ks.load(null);
+ } catch (GeneralSecurityException | IOException e) {
+ ks = null;
+ }
+ this.keyStore = ks;
+ }
+
+ @Override
+ public void storePassphrase(String key, CharSequence passphrase) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public CharSequence loadPassphrase(String key) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return SystemUtils.IS_OS_WINDOWS && keyStore != null;
+ }
+
+}
diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/KeychainModuleTest.java b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainModuleTest.java
new file mode 100644
index 000000000..c15c8c1f1
--- /dev/null
+++ b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainModuleTest.java
@@ -0,0 +1,17 @@
+package org.cryptomator.keychain;
+
+import java.util.Optional;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class KeychainModuleTest {
+
+ @Test
+ public void testGetKeychain() {
+ Optional keychainAccess = DaggerKeychainComponent.builder().keychainModule(new KeychainTestModule()).build().keychainAccess();
+ Assert.assertTrue(keychainAccess.isPresent());
+ Assert.assertTrue(keychainAccess.get() instanceof MapKeychainAccess);
+ }
+
+}
diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/KeychainTestModule.java b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainTestModule.java
new file mode 100644
index 000000000..e2636981b
--- /dev/null
+++ b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainTestModule.java
@@ -0,0 +1,14 @@
+package org.cryptomator.keychain;
+
+import java.util.Set;
+
+import com.google.common.collect.Sets;
+
+public class KeychainTestModule extends KeychainModule {
+
+ @Override
+ Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsSystemKeychainAccess winKeychain) {
+ return Sets.newHashSet(new MapKeychainAccess());
+ }
+
+}
diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java b/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java
new file mode 100644
index 000000000..0af7f0a51
--- /dev/null
+++ b/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java
@@ -0,0 +1,25 @@
+package org.cryptomator.keychain;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class MapKeychainAccess implements KeychainAccessStrategy {
+
+ private final Map map = new HashMap<>();
+
+ @Override
+ public void storePassphrase(String key, CharSequence passphrase) {
+ map.put(key, passphrase);
+ }
+
+ @Override
+ public CharSequence loadPassphrase(String key) {
+ return map.get(key);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+}
diff --git a/main/pom.xml b/main/pom.xml
index 6640becc7..ef7cf60fb 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -273,6 +273,7 @@
frontend-webdav
ui
filesystem-charsets
+ keychain