0

I am trying to push a file to an FTP server using the following code from a Python 3 course I am following. I know this question has been asked before, but other questions don't seem to have tried as many attempts as I have.

import pysftp as sftp
import paramiko
from base64 import decodebytes

def get_cnoopts():
    #keydata = b"""2048 SHA256:XpP32aA8DFDaJ46A3V7GEXk+wJldB3K7HHAFlD4pvQ4 root@DevTuts (RSA)"""
    keydata = b"""2048 SHA256:XpP32aA8DFDaJ46A3V7GEXk+wJldB3K7HHAFlD4pvQ4"""
    key = paramiko.RSAKey(data=decodebytes(keydata))
    cnoopts = sftp.CnOpts()
    cnoopts.hostkeys.add("178.62.45.50", "ssh-rsa", key)

def push_file():
    s = sftp.Connection("198.63.45.20", username="root", password="sfewewetw", cnopts=get_cnoopts())
    local_path = "testme.txt"
    remote_path = "/home/testme.txt"

    s.put(local_path, remote_path)
    s.close()

push_file()

I have changed sensitive data above to protect the innocent, so this code will never work for you as is.

I first tried without the cnopts=get_cnoopts() argument, and then I get the very explanatory error:

SSHException: No hostkey for host 178.62.45.50 found.

Then I found the code for get_cnoopts in an answer here on this SO answer, but now I have to find a key that doesn't throw an error on decodebytes.

Finding host keys with ssh-keyscan yields:

# 178.62.45.50:22 SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3
178.62.45.50 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHTaCuJ+5dzrHyHWr7GwD/c2x7cwL2IaEiXpI+ygd4Ma
# 178.62.45.50:22 SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3
178.62.45.50 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGeglgB51BVCuh6wVZFrp2iyBEOFpaLDiSobQT+41Nn39kSGEJXBUPJ+aJfLRZ2e4Eu2o+3DV4gKsG4IEnV10WpBQxAmuq4EQesO/wTQdfgregarteartyertyer5sJwKkyTvLxBLX3AplbS1zBrSTvMWnqqvNV8IaqcR43JOkdt8frtm6dELalNpdTN4Vm/+VdRiFpzUIUj4lyVcnlttXXreE7p8qciRRfCFYA5OhsAvsSDxccv99dvHDYsrdomHZRbpYzel2QNSWLylEsnbRLDABY13n4xtELXC0Us8QyMjhF2x5l7fkm4RYjQmheNdkoN1Ot
# 178.62.45.50:22 SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3
178.62.45.50 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNretryreyrtZE8I2opSVi7R+2nlGMOs05s8j1NZfH3vIB7mL1ehfPbgp8Sjg8daQxQkm0U+NqWjCRE=

I tried all key lines, and the first gives me:

SSHException: No hostkey for host 178.62.45.50 found.

When I say I tried all key lines is that for each potential key given by ssh-keyscan, I have substituted each line in the output for my keydata variable value in my Python script.

Now I have tried using the entire string for keydata, and skipping the words from the beginning of the key string and both give me the same error. Using the second and third key strings I get the same error. The answer I examined also suggests using pysftp.CnOpts(knownhosts='known_hosts') where 'known_hosts' contains a server public key.

Then I tried another approach suggested in the same answer, as an alternative to get_cnoopts:

def get_cnoopts():
    cnoopts = sftp.CnOpts(knownhosts="""178.62.45.50 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGeglgB51BVCuh6wVZFrp2iyBEOFpaLDiSobQT+41Nn39kSGEJXBUPJ+aJfLRZ2e4Eu2o+3DV4gKsG4IEnV10WpBQxAmuq4EQesO/wTQCXuUPw7LknIbIA3pFvJUxOa1K3xRm2TZgs9esJwKkyTvLxBLX3AplbS1zBrSTvMWnqqvNV8IaqcR43JOkdt8frtm6dELalNpdTN4Vm/+VdRiFpzUIUj4lyVcnlttXXreE7p8qciRRfCFYA5OhsAvsSDxccv99dvHDYsrdomHZRbpYzel2QNSWLylEsnbRLDABY13n4xtELXC0Us8QyMjhF2x5l7fkm4RYjQmheNdkoN1Ot""")
    return cnoopts

and I got the same error. Then I tried another suggestion, to use the winSCP->Server and protocol information dialogue, which lists MD5 and SHA-256 keys nice and explicitly. I have tried both key strings, with and without prefixes likessh-ed25519 255`, with the same error.

I suspect either the course's code is out of date, or I'm introducing some sort of encoding problem with copy and pasting between a source and my Python code. What could be wrong here?

ProfK
  • 49,207
  • 121
  • 399
  • 775
  • *"I tried all key lines"* – How example did you try them? Give us more details. – Martin Prikryl Jun 04 '20 at 06:30
  • @MartinPrikryl The output of `ssh-keyscan`, visible in the question, has 6 lines. Three begin with a `#` and are all the same: `# 178.62.45.50:22 SSH-2.0-OpenSSH_7.6p1 Ubuntu-4ubuntu0.3`. The other 3 lines that begin with an IP address are what I called *key lines*, and I have assumed they either contain the key, as the last phrase on the line, or the whole line is a key. I have tried both – ProfK Jun 04 '20 at 08:04
  • **How have you tried them?** Show us the code and/or what file did you modify and how. – Martin Prikryl Jun 04 '20 at 08:05
  • @MartinPrikryl What code or info haven't I displayed or referenced? – ProfK Jun 04 '20 at 18:36
  • You wrote that you *"tried all key lines"*, but you haven't shown us what did you do exactly to try them. – Martin Prikryl Jun 05 '20 at 04:57
  • @MartinPrikryl I have edited the question to describe how I tried all *key lines*. – ProfK Jun 07 '20 at 07:20
  • Sorry, but that's far from "exact" description. Show us your code. We need [mcve]. – Martin Prikryl Jun 08 '20 at 06:44

1 Answers1

1

Your get_cnoopts() doesn't return anything, so cnoopts=get_cnoopts() will be the same as cnoopts=. Try adding return cnoopts to the end of your get_cnoopts() function:

def get_cnoopts():
    keydata = b"""AAAA..."""
    key = paramiko.RSAKey(data=decodebytes(keydata))
    cnoopts = sftp.CnOpts()
    cnoopts.hostkeys.add("178.62.45.50", "ssh-rsa", key)
    return cnoopts

I've been frustrated by pysftp's key handling myself - I only managed to get it to work by manually loading (like you do) the host's RSA key, after copy/pasting from the output of ssh-keyscan. But the key snippets you show in your code look incorrect: an ssh RSA key should always begin with "AAAA" followed by a continuous stream of base64-encoded text (so no spaces, or hyphens). Try making these two changes and report back.

Ola Tuvesson
  • 5,062
  • 2
  • 28
  • 37