I am trying connect to a SFTP site in my Python script using pysftp
.
Since I don't have the hostkey file, I've created one as suggested here, "hostkey", and I'm trying to load this file, but pysftp
doesn't connect to the sftp site.
The python code is very simple:
cnopts = pysftp.CnOpts()
cnopts.hostkeys.load(pathToTheFile)
with pysftp.Connection(host, username=username, private_key=pathToPKey, cnopts=cnopts) as sftp:
#do things
I first tried adding the following in the hostkey file:
host.com ssh-ed25519 256 AZFsh0........Qy0=
But this results in InvalidHostKey
error with the Incorrect padding
error. I'm guessing it doesn't require 256 for the key. So, I've removed 256.
When I try without 256:
host.com ssh-ed25519 256 AZFsh0........Qy0=
Then it recognizes the key, but the 'utf-8' codec can't decode byte 0x90 in position 11: invalid start byte
error shows up.
So, instead of loading the hostkey file, I've tried adding a hostkey with the following codes as suggested in here:
keydata = b"""AZFsh0........Qy0="""
key1 = paramiko.ed25519key.Ed25519Key(data=keydata)
key2 = paramiko.ed25519key.Ed25519Key(data=base64.b64decode(keydata))
key3 = paramiko.ed25519key.Ed25519Key(data=base64.b64decode(keydata).hex())
key4 = paramiko.ed25519key.Ed25519Key(data=decodebytes(keydata))
key5 = paramiko.ed25519key.Ed25519Key(data=decodebytes(keydata).hex())
cnopts.hostkeys.add("host.com", "ssh-ed25519", key1)
I tried with all the above keys but I still get errors like Incorrect padding
,
I see that someone mentioned that this may be a bug but the post is from 2018. Does anyone know if this is not feasible or I'm missing something?
EDIT (This worked)
The solution posted in Connection to an SFTP server using pysftp and Python 3 with just the server fingerprint, which was linked in the link in Martin Prikryl's response worked.
This what I used (I've cleaned up some to remove unused functions).
import hashlib as hl
#Removed trim_fingerprint() and clean_fingerprint() because it wasn't necessary in my case
class FingerprintKey:
def __init__(self, fingerprint):
self.fingerprint = fingerprint
def compare(self, other):
if callable(getattr(other, "get_fingerprint", None)):
return other.get_fingerprint() == self.fingerprint
elif other == self.get_fingerprint():
return True
elif hl.md5(other).hexdigest() == self.fingerprint:
return True
else:
return False
def __cmp__(self, other):
return self.compare(other)
def __contains__(self, other):
return self.compare(other)
def __eq__(self, other):
return self.compare(other)
def __ne__(self, other):
return not self.compare(other)
def get_fingerprint(self):
return self.fingerprint
def get_name(self):
return u'ssh-ed25519' # Including "256" errors out.
def asbytes(self):
return self
And it was used in this way:
cnopts = pysftp.CnOpts()
cnopts.hostkeys.add('host.com', u'ssh-ed25519 256', FingerprintKey("e2d1............c957")) # Removed ":" from the MD5 value
The main thing I struggled was that I wasn't sure what value should be plugged in for the cnopts.hostkeys.add
, etc, so I'll put those details in case there are people who are new to this.
In my case, I used WinSCP to get the host key fingerprint.
- Open WinSCP
- Enter Host name, User name, and specified the path to the private key to connect
- Click Session
- Click Server/Protocol Information
- Use the value in Algorithm for the second parameter (
keytype
) ofcnopts.hostkeys.add
- Use the value in MD5 for the third parameter (
key
) ofcnopts.hostkeys.add
. The actual value is with colons (e.g. e2:d1:......c9:57), but as the author of Connection to an SFTP server using pysftp and Python 3 with just the server fingerprint mentioned, I had to manually remove the colons as well.