diff --git a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java index 290e57b3..a603e2bf 100644 --- a/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java +++ b/src/java/JavaFileStorage/app/src/main/java/keepass2android/javafilestorage/SftpStorage.java @@ -49,14 +49,18 @@ public class SftpStorage extends JavaFileStorageBase { private static final String SFTP_KEYNAME_OPTION_NAME = "key"; private static final String SFTP_KEYPASSPHRASE_OPTION_NAME = "phrase"; + public static final String SSH_CFG_KEX = "kex"; + private static final String[] SSH_CFG_KEYS = new String[] { + SSH_CFG_KEX + }; + private static final ValueResolver cTimeoutResolver = c -> c == null || c == UNSET_SFTP_CONNECT_TIMEOUT ? null : String.valueOf(c); private static final ValueResolver nonBlankStringResolver = s -> s == null || s.isBlank() ? null : s; - - JSch jsch; + private JSch jsch; public class ConnectionInfo { @@ -68,12 +72,14 @@ public class SftpStorage extends JavaFileStorageBase { public String keyPassphrase; public int port; public int connectTimeoutSec = UNSET_SFTP_CONNECT_TIMEOUT; + public final Map configOpts = new HashMap<>(); public String toString() { return "ConnectionInfo{host=" + host + ",port=" + port + ",user=" + username + ",pwd=,localPath=" + localPath + ",key=" + keyName + ",phrase=,connectTimeout=" + connectTimeoutSec + + ",cfgOpts=" + configOpts + "}"; } } @@ -202,7 +208,8 @@ public class SftpStorage extends JavaFileStorageBase { return buildFullPath(cInfo.host, cInfo.port, newPath, cInfo.username, cInfo.password, cInfo.connectTimeoutSec, - cInfo.keyName, cInfo.keyPassphrase); + cInfo.keyName, cInfo.keyPassphrase, + cInfo.configOpts.get(SSH_CFG_KEX)); } catch (Exception e) { throw convertException(e); } @@ -445,6 +452,11 @@ public class SftpStorage extends JavaFileStorageBase { session.setConfig("PreferredAuthentications", "publickey,password"); + for (Map.Entry e : cInfo.configOpts.entrySet()) { + Log.d("KP2AJFS", "Setting SSH config: " + e.getKey() + "=" + e.getValue()); + session.setConfig(e.getKey(), e.getValue()); + } + sessionConnect(session, cInfo); Channel channel = session.openChannel("sftp"); @@ -561,6 +573,14 @@ public class SftpStorage extends JavaFileStorageBase { if (options.containsKey(SFTP_KEYPASSPHRASE_OPTION_NAME)) { ci.keyPassphrase = options.get(SFTP_KEYPASSPHRASE_OPTION_NAME); } + + // TODO: Support for prepending/appending config values (instead of complete replacement)? + for (String cfgKey : SSH_CFG_KEYS) { + if (options.containsKey(cfgKey)) { + ci.configOpts.put(cfgKey, options.get(cfgKey)); + } + } + return ci; } @@ -637,7 +657,8 @@ public class SftpStorage extends JavaFileStorageBase { public String buildFullPath(String host, int port, String localPath, String username, String password, int connectTimeoutSec, - String keyName, String keyPassphrase) + String keyName, String keyPassphrase, + String kexAlgorithms) throws UnsupportedEncodingException { StringBuilder uri = new StringBuilder(getProtocolPrefix()).append(encode(username)); @@ -660,8 +681,13 @@ public class SftpStorage extends JavaFileStorageBase { .addOption(SFTP_CONNECT_TIMEOUT_OPTION_NAME, connectTimeoutSec, cTimeoutResolver) .addOption(SFTP_KEYNAME_OPTION_NAME, keyName, nonBlankStringResolver) .addOption(SFTP_KEYPASSPHRASE_OPTION_NAME, keyPassphrase, nonBlankStringResolver) + .addOption(SSH_CFG_KEX, kexAlgorithms, nonBlankStringResolver) .build()); + // FIXME: Remove this! + Log.d("KP2AJFS", "buildFullPath returns uri: " + uri.toString()); + // FIXME + return uri.toString(); } diff --git a/src/java/JavaFileStorageTest-AS/app/src/main/java/com/crocoapps/javafilestoragetest2/MainActivity.java b/src/java/JavaFileStorageTest-AS/app/src/main/java/com/crocoapps/javafilestoragetest2/MainActivity.java index 2b13fd92..ac2447df 100644 --- a/src/java/JavaFileStorageTest-AS/app/src/main/java/com/crocoapps/javafilestoragetest2/MainActivity.java +++ b/src/java/JavaFileStorageTest-AS/app/src/main/java/com/crocoapps/javafilestoragetest2/MainActivity.java @@ -826,7 +826,7 @@ public class MainActivity extends Activity implements JavaFileStorage.FileStorag onReceivePathForFileSelect(requestCode, sftpStorage1.buildFullPath( host, port, initialDir, user, pwd, connectTimeout, - keyName, keyPassphrase)); + keyName, keyPassphrase, null)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } diff --git a/src/keepass2android/FileSelectHelper.cs b/src/keepass2android/FileSelectHelper.cs index 1d83ee3d..8d7c890e 100644 --- a/src/keepass2android/FileSelectHelper.cs +++ b/src/keepass2android/FileSelectHelper.cs @@ -199,6 +199,11 @@ namespace keepass2android { dlgContents.FindViewById(Resource.Id.sftp_connect_timeout).Text = ci.ConnectTimeoutSec.ToString(); } + + if (ci.ConfigOpts.Contains(SftpStorage.SshCfgKex)) + { + dlgContents.FindViewById(Resource.Id.sftp_kex).Text = ci.ConfigOpts[SftpStorage.SshCfgKex].ToString(); + } if (!string.IsNullOrEmpty(ci.Password)) { @@ -248,9 +253,11 @@ namespace keepass2android { int.TryParse(connectTimeoutText, out connectTimeout); } + string kexAlgorithms = dlgContents.FindViewById(Resource.Id.sftp_kex).Text; string sftpPath = fileStorage.BuildFullPath( - host, port, initialPath, user, password, connectTimeout, keyName, keyPassphrase); + host, port, initialPath, user, password, connectTimeout, keyName, keyPassphrase, + kexAlgorithms); onStartBrowse(sftpPath); }); diff --git a/src/keepass2android/Resources/layout/sftpcredentials.xml b/src/keepass2android/Resources/layout/sftpcredentials.xml index 1bc34cf1..a924638b 100644 --- a/src/keepass2android/Resources/layout/sftpcredentials.xml +++ b/src/keepass2android/Resources/layout/sftpcredentials.xml @@ -165,4 +165,20 @@ android:singleLine="true" android:inputType="number" /> + + + diff --git a/src/keepass2android/Resources/values/strings.xml b/src/keepass2android/Resources/values/strings.xml index b6de5b13..a1572c7b 100644 --- a/src/keepass2android/Resources/values/strings.xml +++ b/src/keepass2android/Resources/values/strings.xml @@ -607,6 +607,8 @@ Selected private key [Add New...] Key passphrase (optional) + Key Exchange (KEX) Algorithm(s) (optional) + "Comma-separated algorithm names Enter FTP login data: