Set SFTP server host public key in Paramiko with non-default port

Question:

I am trying to set a known host public key before establishing the connection. I have tried using the public key file the partner shared with me, but I wasn’t able to connect, so now I am trying to add the key which is returned by the server. This are the steps I am performing:

1. Retrieve key from host

from io import StringIO

import paramiko
paramiko.util.log_to_file('paramiko.log')

private_key_data = '...'
private_key = paramiko.RSAKey.from_private_key(StringIO(private_key_data))

ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh_client.connect('my-host', port='5022', username='my-username', pkey=private_key)

public_key = ssh_client.get_transport().get_remote_server_key()
print(public_key.get_name())
print(public_key.get_base64())

With this I can retrieve the host information, which is:

ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAACAQCe+JHg9baP3+RiUfURnMx+KUWV+BU2KxPItLzY7b2bxQYirzOhvrgEyLNQxD/DFPlPX+BZVbu1DnLjclmvRx9mpY2ksMH75S/xCoqTleOk1Xyaq001SjjcjVFfkgpBdxDx6amWighSqyzYHMS0NLE+0w2i3TTtAw8AfqtPBloXC+dAXOuBS97uKLm6RDmFq6gx0NAn7WoGM1Tpbb8WFsNbLqlRriqMwCd8WRvAFEsvUbbnq7XboCH0nWLJ85//k6UX7Oz9Xbv7YEq4O6BpYr86iUoCaJ6+XVJ1Gs1LG4ALyBeD78lLQUHiXuXcAuIoIF7UHPhAF3mL2iPrl30xZ+WId3LvtGJukWYNE7kdkxwspQi42K8OFdRPTa8Ana7a1e6iP8/MTfrddBBb7W1jHrTWgQCDEerv3nc7sUWHmbdePoSySuzon+4v/zNppUwyYVrscDT6alKrGGHt3cnoEuln584i0z4fEWyY6Y0MO5DXCqGJEJaUDIkZZYsHvD0EkiKe0dAeQ28jsVBqHIvGVSKtUxL9Vh4uG0Px6LMlToCsknrz0/Ur+V1HkZTRzd9A8MDCjK083GElto+9neVIuDTglIp3EJHwW/vw/z9XX2qVGRUODp/G/sD73vhQeVT0WNp5LviZa59ReNcw2p2djQpn/LlvwAU4kjywTpbSX/PHww==

The connection is established successfully, as the logs show:

DEB [20220923-13:50:09.046] thr=1   paramiko.transport: starting thread (client mode): 0x341f6040
DEB [20220923-13:50:09.047] thr=1   paramiko.transport: Local version/idstring: SSH-2.0-paramiko_2.11.0
DEB [20220923-13:50:09.113] thr=1   paramiko.transport: Remote version/idstring: SSH-2.0-SSHD
INF [20220923-13:50:09.114] thr=1   paramiko.transport: Connected (version 2.0, client SSHD)
DEB [20220923-13:50:09.117] thr=1   paramiko.transport: === Key exchange possibilities ===
DEB [20220923-13:50:09.118] thr=1   paramiko.transport: kex algos: diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha256, diffie-hellman-group-exchange-sha1
DEB [20220923-13:50:09.119] thr=1   paramiko.transport: server key: ssh-rsa
DEB [20220923-13:50:09.121] thr=1   paramiko.transport: client encrypt: aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, aes256-ctr, aes192-ctr, blowfish-cbc, 3des-cbc
DEB [20220923-13:50:09.122] thr=1   paramiko.transport: server encrypt: aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, aes256-ctr, aes192-ctr, blowfish-cbc, 3des-cbc
DEB [20220923-13:50:09.122] thr=1   paramiko.transport: client mac: hmac-sha1, hmac-md5, hmac-sha1-96, hmac-md5-96, hmac-sha256, [email protected]
DEB [20220923-13:50:09.122] thr=1   paramiko.transport: server mac: hmac-sha256, hmac-sha1, hmac-md5, hmac-sha1-96, hmac-md5-96, [email protected]
DEB [20220923-13:50:09.123] thr=1   paramiko.transport: client compress: none, zlib
DEB [20220923-13:50:09.123] thr=1   paramiko.transport: server compress: none, zlib
DEB [20220923-13:50:09.123] thr=1   paramiko.transport: client lang: <none>
DEB [20220923-13:50:09.124] thr=1   paramiko.transport: server lang: <none>
DEB [20220923-13:50:09.124] thr=1   paramiko.transport: kex follows: False
DEB [20220923-13:50:09.124] thr=1   paramiko.transport: === Key exchange agreements ===
DEB [20220923-13:50:09.124] thr=1   paramiko.transport: Kex: diffie-hellman-group-exchange-sha256
DEB [20220923-13:50:09.125] thr=1   paramiko.transport: HostKey: ssh-rsa
DEB [20220923-13:50:09.125] thr=1   paramiko.transport: Cipher: aes128-ctr
DEB [20220923-13:50:09.125] thr=1   paramiko.transport: MAC: hmac-sha1
DEB [20220923-13:50:09.125] thr=1   paramiko.transport: Compression: none
DEB [20220923-13:50:09.125] thr=1   paramiko.transport: === End of kex handshake ===
DEB [20220923-13:50:09.278] thr=1   paramiko.transport: Got server p (2048 bits)
DEB [20220923-13:50:09.382] thr=1   paramiko.transport: kex engine KexGexSHA256 specified hash_algo <built-in function openssl_sha256>
DEB [20220923-13:50:09.383] thr=1   paramiko.transport: Switch to new keys ...
DEB [20220923-13:50:09.384] thr=2   paramiko.transport: Adding ssh-rsa host key for [my-host]:5022: b'466adf2cd4948be2edf7f8d3336aa337'
DEB [20220923-13:50:09.385] thr=2   paramiko.transport: Trying SSH key b'3954a61f2e2692563090acefd187b519'
DEB [20220923-13:50:09.518] thr=1   paramiko.transport: userauth is OK
DEB [20220923-13:50:09.519] thr=1   paramiko.transport: Finalizing pubkey algorithm for key of type 'ssh-rsa'
DEB [20220923-13:50:09.520] thr=1   paramiko.transport: Our pubkey algorithm list: ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa']
DEB [20220923-13:50:09.520] thr=1   paramiko.transport: Server did not send a server-sig-algs list; defaulting to our first preferred algo ('rsa-sha2-512')
DEB [20220923-13:50:09.521] thr=1   paramiko.transport: NOTE: you may use the 'disabled_algorithms' SSHClient/Transport init kwarg to disable that or other algorithms if your server does not support them!
INF [20220923-13:50:09.804] thr=1   paramiko.transport: Authentication (publickey) successful!

2. Set expected host public key

Now, I want to manually set the public key I inspected:

from io import StringIO
from base64 import decodebytes

import paramiko
paramiko.util.log_to_file('paramiko.log')

public_key_data = b'AAAAB3NzaC1yc2EAAAADAQABAAACAQCe+JHg9baP3+RiUfURnMx+KUWV+BU2KxPItLzY7b2bxQYirzOhvrgEyLNQxD/DFPlPX+BZVbu1DnLjclmvRx9mpY2ksMH75S/xCoqTleOk1Xyaq001SjjcjVFfkgpBdxDx6amWighSqyzYHMS0NLE+0w2i3TTtAw8AfqtPBloXC+dAXOuBS97uKLm6RDmFq6gx0NAn7WoGM1Tpbb8WFsNbLqlRriqMwCd8WRvAFEsvUbbnq7XboCH0nWLJ85//k6UX7Oz9Xbv7YEq4O6BpYr86iUoCaJ6+XVJ1Gs1LG4ALyBeD78lLQUHiXuXcAuIoIF7UHPhAF3mL2iPrl30xZ+WId3LvtGJukWYNE7kdkxwspQi42K8OFdRPTa8Ana7a1e6iP8/MTfrddBBb7W1jHrTWgQCDEerv3nc7sUWHmbdePoSySuzon+4v/zNppUwyYVrscDT6alKrGGHt3cnoEuln584i0z4fEWyY6Y0MO5DXCqGJEJaUDIkZZYsHvD0EkiKe0dAeQ28jsVBqHIvGVSKtUxL9Vh4uG0Px6LMlToCsknrz0/Ur+V1HkZTRzd9A8MDCjK083GElto+9neVIuDTglIp3EJHwW/vw/z9XX2qVGRUODp/G/sD73vhQeVT0WNp5LviZa59ReNcw2p2djQpn/LlvwAU4kjywTpbSX/PHww=='
public_key = paramiko.RSAKey(data=decodebytes(public_key_data))
private_key_data = '...'
private_key = paramiko.RSAKey.from_private_key(StringIO(private_key_data))

ssh_client = paramiko.SSHClient()
ssh_client.get_host_keys().add('my-host', 'ssh-rsa', public_key)
ssh_client.connect('my-host', port='5022', username='my-username', pkey=private_key)

However, the connection throws an error, which can be inspected in the logs:

DEB [20220923-14:00:18.113] thr=4   paramiko.transport: starting thread (client mode): 0x34153ee0
DEB [20220923-14:00:18.115] thr=4   paramiko.transport: Local version/idstring: SSH-2.0-paramiko_2.11.0
DEB [20220923-14:00:18.163] thr=4   paramiko.transport: Remote version/idstring: SSH-2.0-SSHD
INF [20220923-14:00:18.165] thr=4   paramiko.transport: Connected (version 2.0, client SSHD)
DEB [20220923-14:00:18.169] thr=4   paramiko.transport: === Key exchange possibilities ===
DEB [20220923-14:00:18.170] thr=4   paramiko.transport: kex algos: diffie-hellman-group1-sha1, diffie-hellman-group14-sha1, diffie-hellman-group-exchange-sha256, diffie-hellman-group-exchange-sha1
DEB [20220923-14:00:18.170] thr=4   paramiko.transport: server key: ssh-rsa
DEB [20220923-14:00:18.171] thr=4   paramiko.transport: client encrypt: aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, aes256-ctr, aes192-ctr, blowfish-cbc, 3des-cbc
DEB [20220923-14:00:18.171] thr=4   paramiko.transport: server encrypt: aes128-ctr, aes256-cbc, aes192-cbc, aes128-cbc, aes256-ctr, aes192-ctr, blowfish-cbc, 3des-cbc
DEB [20220923-14:00:18.172] thr=4   paramiko.transport: client mac: hmac-sha1, hmac-md5, hmac-sha1-96, hmac-md5-96, hmac-sha256, [email protected]
DEB [20220923-14:00:18.172] thr=4   paramiko.transport: server mac: hmac-sha256, hmac-sha1, hmac-md5, hmac-sha1-96, hmac-md5-96, [email protected]
DEB [20220923-14:00:18.173] thr=4   paramiko.transport: client compress: none, zlib
DEB [20220923-14:00:18.173] thr=4   paramiko.transport: server compress: none, zlib
DEB [20220923-14:00:18.173] thr=4   paramiko.transport: client lang: <none>
DEB [20220923-14:00:18.173] thr=4   paramiko.transport: server lang: <none>
DEB [20220923-14:00:18.173] thr=4   paramiko.transport: kex follows: False
DEB [20220923-14:00:18.174] thr=4   paramiko.transport: === Key exchange agreements ===
DEB [20220923-14:00:18.174] thr=4   paramiko.transport: Kex: diffie-hellman-group-exchange-sha256
DEB [20220923-14:00:18.174] thr=4   paramiko.transport: HostKey: ssh-rsa
DEB [20220923-14:00:18.174] thr=4   paramiko.transport: Cipher: aes128-ctr
DEB [20220923-14:00:18.174] thr=4   paramiko.transport: MAC: hmac-sha1
DEB [20220923-14:00:18.174] thr=4   paramiko.transport: Compression: none
DEB [20220923-14:00:18.174] thr=4   paramiko.transport: === End of kex handshake ===
DEB [20220923-14:00:18.316] thr=4   paramiko.transport: Got server p (2048 bits)
DEB [20220923-14:00:18.422] thr=4   paramiko.transport: kex engine KexGexSHA256 specified hash_algo <built-in function openssl_sha256>
DEB [20220923-14:00:18.423] thr=4   paramiko.transport: Switch to new keys ...
DEB [20220923-14:00:18.424] thr=2   paramiko.transport: Rejecting ssh-rsa host key for [my-host]:5022: b'466adf2cd4948be2edf7f8d3336aa337'

The connection seems to be rejecting the ssh-rsa host key I set. Any idea why is this happening?

Asked By: Luiscri

||

Answers:

When you use non-standard port number (not 22), the key to the hostkey repository is [host]:port, not just host.

ssh_client.get_host_keys().add('[my-host]:5022', 'ssh-rsa', public_key)
Answered By: Martin Prikryl
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.