SSH/SFTP: Allow kex algorithms to be explicitly set

-kex config overload, set via database connection settings
This commit is contained in:
Rick Brown
2023-07-19 19:38:00 -04:00
parent 006f5497e5
commit 46fdba1bfa
5 changed files with 57 additions and 6 deletions

View File

@@ -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<Integer> cTimeoutResolver = c ->
c == null || c == UNSET_SFTP_CONNECT_TIMEOUT ? null : String.valueOf(c);
private static final ValueResolver<String> 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<String, String> configOpts = new HashMap<>();
public String toString() {
return "ConnectionInfo{host=" + host + ",port=" + port + ",user=" + username +
",pwd=<hidden>,localPath=" + localPath + ",key=" + keyName +
",phrase=<hidden>,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<String, String> 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 <end>
return uri.toString();
}

View File

@@ -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();
}

View File

@@ -199,6 +199,11 @@ namespace keepass2android
{
dlgContents.FindViewById<EditText>(Resource.Id.sftp_connect_timeout).Text = ci.ConnectTimeoutSec.ToString();
}
if (ci.ConfigOpts.Contains(SftpStorage.SshCfgKex))
{
dlgContents.FindViewById<EditText>(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<EditText>(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);
});

View File

@@ -165,4 +165,20 @@
android:singleLine="true"
android:inputType="number" />
<TextView android:id="@+id/sftp_kex_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="4dip"
android:layout_marginTop="4dip"
android:text="@string/sftp_kex_title" />
<EditText
android:id="@+id/sftp_kex"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:hint="@string/hint_sftp_kex"
android:singleLine="true"
android:text=""
/>
</LinearLayout>

View File

@@ -607,6 +607,8 @@
<string name="private_key_select">Selected private key</string>
<string name="private_key_create_new">[Add New...]</string>
<string name="hint_sftp_key_passphrase">Key passphrase (optional)</string>
<string name="sftp_kex_title">Key Exchange (KEX) Algorithm(s) (optional)</string>
<string name="hint_sftp_kex">"Comma-separated algorithm names</string>
<string name="enter_ftp_login_title">Enter FTP login data:</string>