Paramiko RSAKey "private key file is encrypted" - python

I'm trying to use Paramiko to connect to an SFTP site.
"paramiko": {
"hashes": [
"sha256:6bef55b882c9d130f8015b9a26f4bd93f710e90fe7478b9dcc810304e79b3cd8",
"sha256:fedc9b1dd43bc1d45f67f1ceca10bc336605427a46dcdf8dec6bfea3edf57965"
],
"index": "pypi",
"version": "==3.0.0"
},
I have a .pem file in the form
-----BEGIN OPENSSH PRIVATE KEY-----
data for the key
-----END OPENSSH PRIVATE KEY-----
Worth mentioning that the key is encrypted with a passphrase.
I attempt to load the key file, providing the password and that works fine
# Works great :)
mykey = paramiko.RSAKey.from_private_key_file(key_file_path, password=password)
self.ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# this explodes
self.ssh_client.connect(hostname=settings.ftp_host, username=username, pkey=mykey, port=22)
self.ftp = self.ssh_client.open_sftp()
paramiko.ssh_exception.PasswordRequiredException: private key file is encrypted
If I change the connect to
self.ssh_client.connect(hostname=settings.ftp_host, username=username, pkey=mykey, port=22, passphrase=password)
paramiko.ssh_exception.SSHException: OpenSSH private key file checkints do not match
And if I try to use key_filename instead of pkey
self.ssh_client.connect(hostname=settings.ftp_host, username=username, key_filename=key_file_path, port=22, passphrase=password)
ValueError: q must be exactly 160, 224, or 256 bits long
I am able to successfully connect to the SFTP with this key using FileZilla I'm just not sure what I'm doing wrong in Paramiko.
Thanks!

Figured this out today.
I setup Parmiko's logging and saw that it was defaulting to try to use 'rsa-sha2-512'
2023-02-16 10:01:46 - DEBUG - transport.py:1871 - paramiko.transport - _log() - Our pubkey algorithm list: ['rsa-sha2-512', 'rsa-sha2-256', 'ssh-rsa']
2023-02-16 10:01:46 - DEBUG - transport.py:1871 - paramiko.transport - _log() - Server did not send a server-sig-algs list; defaulting to our first preferred algo ('rsa-sha2-512')
Disabling 'rsa-sha2-512' and 'rsa-sha2-256' so Paramiko was forced to use 'ssh-rsa' fixes the issue.
self.ssh_client.connect(hostname=settings.ftp_host, username=username, pkey=mykey, disabled_algorithms=dict(pubkeys=["rsa-sha2-512", "rsa-sha2-256"]))

Related

Transfer files from local to AWS server using SSH in python [duplicate]

I'm trying to create a single file executable in Python and using Paramiko for my SSH. I need to eliminate external files such as private key files and try to go for embedded strings.
I tried this solution but it's not working for me:
Paramiko: Creating a PKey from a public key string
How do I accomplish this? Thanks.
The solution you mentioned:
key = paramiko.RSAKey(data=base64.b64decode('AAblablabla...'))
works fine however it may be inconvenient to store the key in base64 format.
The following code shows how to use the key stored in "plain-text" format (as key-files in ~/.ssh directory):
import paramiko
import StringIO
my_key = """\
-----BEGIN RSA PRIVATE KEY-----
<your key here>
-----END RSA PRIVATE KEY-----"""
pkey = paramiko.RSAKey.from_private_key(StringIO.StringIO(my_key))
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='host', username='user', pkey=pkey)
...
ssh.close()
In Python 3:
import io
# ...
pkey = paramiko.RSAKey.from_private_key(io.StringIO(my_key))
See StringIO in Python3
I had the same issue where I'm trying to not have private key files using AWS secrets manager, just got it to work with the following. Notice the \n in the privatekey.
import io
privatekey = io.StringIO('-----BEGIN OPENSSH PRIVATE KEY-----\nRestOfTheKey\n-----END OPENSSH PRIVATE KEY-----')
pkey = paramiko.Ed25519Key.from_private_key(privatekey)
Then when you're connecting
aws_ssh = paramiko.SSHClient()
aws_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
aws_ssh.connect(hostname='YOURHOST', username='YOURUSERNAME', pkey=pkey)
Now, however, if you're like me and using this for Lambda+Secrets Manager, and the secrets manager has a key+value and you're pulling the value of this privatekey from there. One thing to note is that secrets manager will escape the \n and turn it into \\n. To fix that, modify the above code to replace the \\n to \n.
awskeytemp = secrets['YOURKEY'].replace('\\n', '\n')
privatekey = io.StringIO(awskeytemp)
pkey = paramiko.Ed25519Key.from_private_key(privatekey)
To add a public key from a string on the ssh client you must set the keyword arg look_for_keys=False then use the MissingHostKeyPolicy classes missing_host_key() method to add the key from your string.
my_pub_key = "xx.xx.xx.xx ecdsa-sha2-nistp256 mlzdHAyNT....."
my_host = my_pub_key.split(' ')[0]
password = 'myFavortitePassword'
username = 'myUsername'
ssh_client=paramiko.SSHClient()
host_key_policy = paramiko.MissingHostKeyPolicy()
host_key_policy.missing_host_key(ssh_client, my_host, my_pub_key)
ssh_client.connect(hostname= my_host
,username=username
,password=password
,port=22
,look_for_keys=False)

Fabric Error: "PasswordRequiredException: Private key file is encrypted"

How to submit the passphrase for a encrypted private key with Fabric?
It seems not to work with the following code as described in the official documentation:
from fabric import Connection
password = '1234'
c = Connection('foo',connect_kwargs={'passphrase': password})
result = c.run('uname -s')
Error Message:
File "/home/user/.miniconda3/envs/test/lib/python3.7/site-
packages/paramiko/ed25519key.py", line 97, in _parse_signing_key_data
"Private key file is encrypted"
PasswordRequiredException: Private key file is encrypted
My ~/.ssh/config file on my linux machine has the following entry:
host foo
hostname localhost
port 12345
user userxxx
ForwardAgent yes
ProxyJump reverse#test.com

How to sftp connect through Paramiko with public key - python [duplicate]

I'm using Paramiko to connect through SSH to a server.
Basic authentication works well, but I can't understand how to connect with public key.
When I connect with PuTTY, the server tell me this:
Using username "root".
Authenticating with public key "rsa-key#ddddd.com"
Passphrase for key "rsa-key#ddddd.com": [i've inserted the passphrase here]
Last login: Mon Dec 5 09:25:18 2011 from ...
I connect to it with this ppk file:
PuTTY-User-Key-File-2: ssh-rsa
Encryption: aes256-cbc
Comment: rsa-key#dddd.com
Public-Lines: 4
[4 lines key]
Private-Lines: 8
[8 lines key]
Private-MAC: [hash]
With basic auth the error I get (from the log) is:
DEB [20111205-09:48:44.328] thr=1 paramiko.transport: userauth is OK
DEB [20111205-09:48:44.927] thr=1 paramiko.transport: Authentication type (password) not permitted.
DEB [20111205-09:48:44.927] thr=1 paramiko.transport: Allowed methods: ['publickey', 'gssapi-with-mic']
I've tried to include that ppk file and set to auth_public_key, but didn't work.
Can you help me?
Ok #Adam and #Kimvais were right, Paramiko cannot parse .ppk files.
So the way to go (thanks to #JimB too) is to convert .ppk file to OpenSSH private key format; this can be achieved using PuTTYgen as described here.
Then it's very simple getting connected with it:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('<hostname>', username='<username>', password='<password>', key_filename='<path/to/openssh-private-key-file>')
stdin, stdout, stderr = ssh.exec_command('ls')
print stdout.readlines()
ssh.close()
For me I doing this:
import paramiko
hostname = 'my hostname or IP'
myuser = 'the user to ssh connect'
mySSHK = '/path/to/sshkey.pub'
sshcon = paramiko.SSHClient() # will create the object
sshcon.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # no known_hosts error
sshcon.connect(hostname, username=myuser, key_filename=mySSHK) # no passwd needed
works for me pretty ok
To create a valid DSA format private key supported by Paramiko in Puttygen.
Click on Conversions then Export OpenSSH Key
#VonC's answer to (deleted) duplicate question:
If, as commented, Paraminko does not support PPK key, the official solution, as seen here, would be to use PuTTYgen.
But you can also use the Python library CkSshKey to make that same conversion directly in your program.
See "Convert PuTTY Private Key (ppk) to OpenSSH (pem)"
import sys
import chilkat
key = chilkat.CkSshKey()
# Load an unencrypted or encrypted PuTTY private key.
# If your PuTTY private key is encrypted, set the Password
# property before calling FromPuttyPrivateKey.
# If your PuTTY private key is not encrypted, it makes no diffference
# if Password is set or not set.
key.put_Password("secret")
# First load the .ppk file into a string:
keyStr = key.loadText("putty_private_key.ppk")
# Import into the SSH key object:
success = key.FromPuttyPrivateKey(keyStr)
if (success != True):
print(key.lastErrorText())
sys.exit()
# Convert to an encrypted or unencrypted OpenSSH key.
# First demonstrate converting to an unencrypted OpenSSH key
bEncrypt = False
unencryptedKeyStr = key.toOpenSshPrivateKey(bEncrypt)
success = key.SaveText(unencryptedKeyStr,"unencrypted_openssh.pem")
if (success != True):
print(key.lastErrorText())
sys.exit()

Embedding key as string in Paramiko application

I'm trying to create a single file executable in Python and using Paramiko for my SSH. I need to eliminate external files such as private key files and try to go for embedded strings.
I tried this solution but it's not working for me:
Paramiko: Creating a PKey from a public key string
How do I accomplish this? Thanks.
The solution you mentioned:
key = paramiko.RSAKey(data=base64.b64decode('AAblablabla...'))
works fine however it may be inconvenient to store the key in base64 format.
The following code shows how to use the key stored in "plain-text" format (as key-files in ~/.ssh directory):
import paramiko
import StringIO
my_key = """\
-----BEGIN RSA PRIVATE KEY-----
<your key here>
-----END RSA PRIVATE KEY-----"""
pkey = paramiko.RSAKey.from_private_key(StringIO.StringIO(my_key))
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='host', username='user', pkey=pkey)
...
ssh.close()
In Python 3:
import io
# ...
pkey = paramiko.RSAKey.from_private_key(io.StringIO(my_key))
See StringIO in Python3
I had the same issue where I'm trying to not have private key files using AWS secrets manager, just got it to work with the following. Notice the \n in the privatekey.
import io
privatekey = io.StringIO('-----BEGIN OPENSSH PRIVATE KEY-----\nRestOfTheKey\n-----END OPENSSH PRIVATE KEY-----')
pkey = paramiko.Ed25519Key.from_private_key(privatekey)
Then when you're connecting
aws_ssh = paramiko.SSHClient()
aws_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
aws_ssh.connect(hostname='YOURHOST', username='YOURUSERNAME', pkey=pkey)
Now, however, if you're like me and using this for Lambda+Secrets Manager, and the secrets manager has a key+value and you're pulling the value of this privatekey from there. One thing to note is that secrets manager will escape the \n and turn it into \\n. To fix that, modify the above code to replace the \\n to \n.
awskeytemp = secrets['YOURKEY'].replace('\\n', '\n')
privatekey = io.StringIO(awskeytemp)
pkey = paramiko.Ed25519Key.from_private_key(privatekey)
To add a public key from a string on the ssh client you must set the keyword arg look_for_keys=False then use the MissingHostKeyPolicy classes missing_host_key() method to add the key from your string.
my_pub_key = "xx.xx.xx.xx ecdsa-sha2-nistp256 mlzdHAyNT....."
my_host = my_pub_key.split(' ')[0]
password = 'myFavortitePassword'
username = 'myUsername'
ssh_client=paramiko.SSHClient()
host_key_policy = paramiko.MissingHostKeyPolicy()
host_key_policy.missing_host_key(ssh_client, my_host, my_pub_key)
ssh_client.connect(hostname= my_host
,username=username
,password=password
,port=22
,look_for_keys=False)

How to connect to SFTP through Paramiko with SSH key - Pageant

I am trying to connect to an SFTP through Paramiko with a passphrase protected SSH key. I have loaded the key into Pageant (which I understand is supported by Paramiko) but I can't get it to decrypt my private key.
I have found this example here that references allow_agent=True but this does not appear to be a parameter that can be used with the SFTPClient.
Can anyone advise if it is possible to work with Paramiko and Pageant in this way?
This is my code at the moment - which raises PasswordRequiredException
privatekeyfile = 'path to key'
mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
transport = paramiko.Transport(('host', 'port'))
transport.connect('username',pkey = mykey)
sftp = paramiko.SFTPClient.from_transport(transport)
You have to provide a passphrase, when loading an encrypted key using the RSAKey.from_private_key_file.
Though note that you do not have to load the key at all, when using the Pageant. That's the point of using an authentication agent. But only the SSHClient class supports the Pageant. The Transport class does not, on its own.
You can follow the code in How to use Pageant with Paramiko on Windows?
Though as the allow_agent is True by default, there is actually nothing special about the code.
Once connected and authenticated, use the SSHClient.open_sftp method to get your instance of the SFTPClient.
ssh = paramiko.SSHClient()
ssh.connect(host, username='user', allow_agent=True)
sftp = ssh.open_sftp()
You will also need to verify the host key:
Paramiko "Unknown Server"
This worked for me
privatekeyfile = 'path to key'
mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
ssh_client = paramiko.SSHClient()
ssh_client.load_system_host_keys()
ssh_client.connect(hostname='host', username='user', allow_agent=True, pkey=mykey)
ftp_client = ssh_client.open_sftp()
print(ftp_client.listdir('/'))

Categories

Resources