Question
I am unable to login to my server using key authentication from my Android app. However, I am able to login to the server from my app using password authentication. Additionally, I can login to the server using key authentication from other clients on my network.
Here’s a snippet of my code:
protected String sshConnect() { String stdoutString = null; String alias = "KEYPAIRTEST"; KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); KeyStore.Entry entry = keyStore.getEntry(alias, null); PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey(); PublicKey publicKey = keyStore.getCertificate(alias).getPublicKey(); KeyPair keyPair = new KeyPair(publicKey, privateKey); // create a client instance try (SshClient client = SshClient.setUpDefaultClient()) { client.setServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE); client.start(); // connection and authentication try (ClientSession session = client.connect(username, host, port).verify(TimeUnit.SECONDS.toMillis(defaultTimeoutSeconds)).getSession()) { session.auth().verify(TimeUnit.SECONDS.toMillis(defaultTimeoutSeconds)); // create a channel to communicate ClientChannel channel = session.createExecChannel(this.command); ByteArrayOutputStream stdoutStream = new ByteArrayOutputStream(); channel.setOut(stdoutStream); // open channel channel.open().verify(5, TimeUnit.SECONDS); // close channel channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), TimeUnit.SECONDS.toMillis(5)); // output after converting to string type stdoutString = stdoutStream.toString(); } catch (Exception e) { Log.d(TAG, "sshConnect(): client.connect(): Exception: " + e); } } catch (Exception e) { Log.d(TAG, "sshConnect(): client.start(): Exception: " + e); } return stdoutString; }
I generated and stored the keys in the Android KeyStore using the following code:
KeyPairGenerator kpg = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); kpg.initialize(new KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .setKeySize(2048) .build()); kpg.generateKeyPair();
I extracted the public key and added it to the server’s ~/.ssh/authorized_keys
file. Despite this, the login fails with the following warnings and exception in my client logs:
WARN org.apache.sshd.client.keyverifier.AcceptAllServerKeyVerifier - Server at /192.168.13.4:22 presented unverified EC key: SHA256:nNMe+ZsasdILlkGIZfcLwl41ZvVTzTaEOeA Exception: org.apache.sshd.common.SshException: No more authentication methods available
What am I doing wrong?
Answer
To troubleshoot your issue with SSH key authentication from your Android app, you need to ensure that your key pair generation, public key formatting, and SSH client configuration are all correctly set up. Here’s a comprehensive guide to address these aspects and resolve your problem.
Detailed Description
When attempting to use SSH key authentication from an Android app, several steps must be verified to ensure the process works correctly. This includes generating and storing key pairs, ensuring the public key is correctly formatted and placed, and configuring the SSH client properly. Let’s go through these steps in detail.
Step 1: Key Pair Generation and Storage
Ensure your key generation and storage process is correct. Here’s how you can do it:
KeyPairGenerator kpg = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore"); kpg.initialize(new KeyGenParameterSpec.Builder( alias, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) .setKeySize(2048) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) .build()); kpg.generateKeyPair();
Ensure you include the necessary encryption paddings and key sizes for secure key generation.
Step 2: Public Key Format and Placement
Ensure the public key is correctly formatted and placed in the ~/.ssh/authorized_keys
file on the server. The key should start with ssh-rsa
followed by a space and the base64-encoded key.
Example of correct formatting:
ssh-rsa AAAAB3...base64_encoded_key... rest_of_key== user@host
Also, check the permissions of the ~/.ssh/authorized_keys
file and the ~/.ssh
directory:
chmod 600 ~/.ssh/authorized_keys chmod 700 ~/.ssh
Step 3: SSH Client Configuration and Authentication Process
Ensure your SSH client is correctly configured to use the generated key pair. Here’s a refined version of your sshConnect
method:
protected String sshConnect() { String stdoutString = null; String alias = "KEYPAIRTEST"; try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); KeyStore.Entry entry = keyStore.getEntry(alias, null); PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey(); PublicKey publicKey = keyStore.getCertificate(alias).getPublicKey(); KeyPair keyPair = new KeyPair(publicKey, privateKey); try (SshClient client = SshClient.setUpDefaultClient()) { client.setServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE); client.start(); try (ClientSession session = client.connect(username, host, port).verify(defaultTimeoutSeconds, TimeUnit.SECONDS).getSession()) { session.addPublicKeyIdentity(keyPair); session.auth().verify(defaultTimeoutSeconds, TimeUnit.SECONDS); try (ClientChannel channel = session.createExecChannel(this.command)) { ByteArrayOutputStream stdoutStream = new ByteArrayOutputStream(); channel.setOut(stdoutStream); channel.open().verify(5, TimeUnit.SECONDS); channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), TimeUnit.SECONDS.toMillis(5)); stdoutString = stdoutStream.toString(); } } catch (Exception e) { Log.d(TAG, "sshConnect(): client.connect(): Exception: " + e); } } catch (Exception e) { Log.d(TAG, "sshConnect(): client.start(): Exception: " + e); } } catch (Exception e) { Log.d(TAG, "sshConnect(): KeyStore Exception: " + e); } return stdoutString; }
Additional Checks
- Server Logs: Check the server’s SSH logs (
/var/log/auth.log
or/var/log/secure
) for any relevant error messages when the authentication fails. This can provide clues about why the key authentication is not working. - Key Fingerprint Verification: Ensure the key fingerprint matches on both sides. The warning about the server presenting an unverified EC key may indicate a mismatch or an issue with the server’s host key verification process.
- Network Configuration: Verify that there are no network issues or firewalls blocking the key-based authentication.
Conclusion
By ensuring the correct generation and storage of key pairs, proper formatting and placement of the public key, and verifying the SSH client configuration and server logs, you should be able to diagnose and resolve the key authentication issue from your Android app. If you continue to face problems, detailed logs from both the client and server side will be crucial in further troubleshooting.