我已經寫了一個簡單的程序,它可以成功連接到主機的SFTP站點並可以檢索文件。如何使用Python將主機的公鑰文件(.pub)添加到SFTP連接?
import pysftp
cnopts = pysftp.CnOpts()
cnopts.hostkeys = None
srv = pysftp.Connection(host=FTP_SITE, username=DOWNLOAD['USERNAME'],
password=DOWNLOAD['PASSWORD'], cnopts=cnopts)
data = srv.listdir()
file_get = srv.get(get_file, localpath='C:/Users/Me/Desktop/test.csv')
雖然我還沒有能夠將主機的公鑰添加到SFTP連接。我有這種格式的主機公鑰文件:
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "Created by Ipswitch WS_FTP Pro"
AAAAB3NzaC1kc3MAAACBAMtINmL43m2CttyjDfHDWNJT9C+ik1OTgJSB5WRpw0G
i0HdYSrJqjUvDQhwCzbt7JRX2V9yCO9xlieUzbkDLSJ7Y8a5g5G4A1FsFEXS1kf
yZuOLBSXxs3+ibTXTMmkAyXq0FzapW6Oka6OvZW1aGfHeBbUADueJnXhyyw1+UL
1uVAAAAFQClKT+RhjhgDGbbLxl1cROQRTaoJwAAAIEAqiAV9hTPrcH6lXBb2GVz
R8TLIchLSOweOme+RK5WqN9sEPgxoo7s3xoXDzv3KJtuPAx7XRvJ/4jdcgbpQLe
1scm9LtczccG/lC583pa7WD9SUbx6mDVe8BbtHfFrp24JIkqaD47iZDYxozi8Ob
As+vny9AcfKgBbjqyTcOYVKkMAAACBALBk3DPcUCxzGXqhgi4fwyv+ze8beyGxv
2uXM1LgLjwdIRcojqZhyziDcUaRXeIlUYVFC/nC+mTItpuveZMj4xZSPyTlfxjl
E36zkbdbSGvNbvO+jP1qupp2fRDWiRSrMr0MBUzFltIocVlcXMXEl/NfEm5h6vu
BWyWQVKtaEPV0
---- END SSH2 PUBLIC KEY ----
有沒有人知道添加主機公鑰的正確方法?我已經檢查了pysftp https://pysftp.readthedocs.io/en/release_0.2.9/和其他教程http://www.pythonforbeginners.com/modules-in-python/python-secure-ftp-module的文檔,但沒有運氣。
編輯:我試過了Martin Prikryl的建議。我第一次格式化密鑰文件的格式
sftp.hostsite.com ssh-rsa AAAAB3NzaC1k...m5h6vuBWyWAAAAB3Nz
然後我試着修改代碼來:
key_file = 'host_site_key.pub'
cnopts = pysftp.CnOpts()
cnopts.hostkeys.load(path_to_key_file + key_file)
srv = pysftp.Connection(host=SFTP_SITE, username=DOWNLOAD['USERNAME'],
password=DOWNLOAD['PASSWORD'], cnopts=cnopts)
不過,我得到以下堆棧跟蹤
SSHException Traceback (most recent call last)
<ipython-input-8-52797202ff65> in <module>()
3
4 srv = pysftp.Connection(host=SFTP_SITE, username=DOWNLOAD['USERNAME'],
----> 5 password=DOWNLOAD['PASSWORD'], cnopts=cnopts)
6 data = srv.listdir()
C:\Users\Alex\Anaconda2\lib\site-packages\pysftp\__init__.pyc in __init__(self, host, username, private_key, password, port, private_key_pass, ciphers, log, cnopts, default_path)
130 # check that we have a hostkey to verify
131 if self._cnopts.hostkeys is not None:
--> 132 self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
133
134 self._sftp_live = False
C:\Users\Alex\Anaconda2\lib\site-packages\pysftp\__init__.pyc in get_hostkey(self, host)
69 kval = self.hostkeys.lookup(host) # None|{keytype: PKey}
70 if kval is None:
---> 71 raise SSHException("No hostkey for host %s found." % host)
72 # return the pkey from the dict
73 return list(kval.values())[0]
SSHException: No hostkey for host sftp.hostsite.com found.
我也嘗試了第二個建議,在這裏我將密鑰硬編碼爲一個字節字符串,然後將其加載爲RSAkey
但是stil我沒有運氣。
key_hardcode_rsa = b'AAAAB3NzaC1k...AAB3Nz'
key = paramiko.RSAKey(data=bytes.decode(key_hardcode_rsa))
SSHException Traceback (most recent call last)
<ipython-input-29-f3a4ae42127d> in <module>()
----> 1 key = paramiko.RSAKey(data=bytes.decode(key_hardcode_rsa))
C:\Users\Alex\Anaconda2\lib\site-packages\paramiko\rsakey.pyc in __init__(self, msg, data, filename, password, key, file_obj)
54 raise SSHException('Key object may not be empty')
55 if msg.get_text() != 'ssh-rsa':
---> 56 raise SSHException('Invalid key')
57 self.key = rsa.RSAPublicNumbers(
58 e=msg.get_mpint(), n=msg.get_mpint()
SSHException: Invalid key
我去的paramiko的源代碼在這裏https://github.com/enjrolas/lumenToy/tree/master/env/lib/python2.7/site-packages/paramiko。
def __init__(self, msg=None, data=None, filename=None, password=None, vals=None, file_obj=None):
self.n = None
self.e = None
self.d = None
self.p = None
self.q = None
if file_obj is not None:
self._from_private_key(file_obj, password)
return
if filename is not None:
self._from_private_key_file(filename, password)
return
if (msg is None) and (data is not None):
msg = Message(data)
if vals is not None:
self.e, self.n = vals
else:
if msg is None:
raise SSHException('Key object may not be empty')
if msg.get_text() != 'ssh-rsa':
raise SSHException('Invalid key')
self.e = msg.get_mpint()
self.n = msg.get_mpint()
self.size = util.bit_length(self.n)
def get_text(self):
"""
Fetch a string from the stream. This could be a byte string and may
contain unprintable characters. (It's not unheard of for a string to
contain another byte-stream Message.)
@return: a string.
@rtype: string
"""
return u(self.get_bytes(self.get_int()))
def get_bytes(self, n):
"""
Return the next ``n`` bytes of the message (as a `str`), without
decomposing into an int, decoded string, etc. Just the raw bytes are
returned. Returns a string of ``n`` zero bytes if there weren't ``n``
bytes remaining in the message.
"""
b = self.packet.read(n)
max_pad_size = 1 << 20 # Limit padding to 1 MB
if len(b) < n < max_pad_size:
return b + zero_byte * (n - len(b))
return b
def get_int(self):
"""
Fetch an int from the stream.
@return: a 32-bit unsigned integer.
@rtype: int
"""
return struct.unpack('>I', self.get_bytes(4))[0]
所以,源代碼顯示msg
從data
參數創建一個對象,它是傳遞如何格式化我的鑰匙,因此paramiko.message.get_text
函數將返回'ssh-rsa'
RSA密鑰字節串?
[尋找與pysftp主機密鑰]的可能的複製(http://stackoverflow.com/q/38939454/850848#43389508) –
pysftp /的paramiko不支持你擁有的公鑰格式。你必須先將它轉換爲'known_hosts'格式(請參閱我的答案)。 –
@MartinPrikryl我嘗試了你的建議,並將修改發佈到我上面的帖子中。 –