2017-04-25 131 views
1

我已經寫了一個簡單的程序,它可以成功連接到主機的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] 

所以,源代碼顯示msgdata參數創建一個對象,它是傳遞如何格式化我的鑰匙,因此paramiko.message.get_text函數將返回'ssh-rsa' RSA密鑰字節串?

+0

[尋找與pysftp主機密鑰]的可能的複製(http://stackoverflow.com/q/38939454/850848#43389508) –

+0

pysftp /的paramiko不支持你擁有的公鑰格式。你必須先將它轉換爲'known_hosts'格式(請參閱我的答案)。 –

+0

@MartinPrikryl我嘗試了你的建議,並將修改發佈到我上面的帖子中。 –

回答

1

Verify host key with pysftp


除了從上述問題我的答案,你需要知道你的關鍵是ssh-dssDSSKey),不ssh-rsaRSAKey)。

我也想不明白,你來自哪裏得到了...m5h6vuBWyWAAAAB3Nz.pub文件中沒有這樣的序列。

您的條目應該是這樣的:

sftp.hostsite.com ssh-dss AAAAB3NzaC1kc3MAAACBAMtINmL43m2CttyjDfHDWNJT9C+ik1OTgJSB5WRpw0Gi0HdYSrJqjUvDQhwCzbt7JRX2V9yCO9xlieUzbkDLSJ7Y8a5g5G4A1FsFEXS1kfyZuOLBSXxs3+ibTXTMmkAyXq0FzapW6Oka6OvZW1aGfHeBbUADueJnXhyyw1+UL1uVAAAAFQClKT+RhjhgDGbbLxl1cROQRTaoJwAAAIEAqiAV9hTPrcH6lXBb2GVzR8TLIchLSOweOme+RK5WqN9sEPgxoo7s3xoXDzv3KJtuPAx7XRvJ/4jdcgbpQLe1scm9LtczccG/lC583pa7WD9SUbx6mDVe8BbtHfFrp24JIkqaD47iZDYxozi8ObAs+vny9AcfKgBbjqyTcOYVKkMAAACBALBk3DPcUCxzGXqhgi4fwyv+ze8beyGxv2uXM1LgLjwdIRcojqZhyziDcUaRXeIlUYVFC/nC+mTItpuveZMj4xZSPyTlfxjlE36zkbdbSGvNbvO+jP1qupp2fRDWiRSrMr0MBUzFltIocVlcXMXEl/NfEm5h6vuBWyWQVKtaEPV0 
+0

這樣一個簡單的解決方案。非常感謝你。 –

相關問題