Paramiko SSH客户端无法解压缩ED25519密钥。

6

我正在尝试使用密钥对进行SSH连接到SFTP服务器。

如果我通过 ssh-keygen -t rsa 生成RSA密钥,则可以使用该密钥对进行连接。

当我通过Paramiko连接到服务器时,一切都很顺利:

    private_key = paramiko.RSAKey.from_private_key_file("/path/to/my/private/key")
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    print("Connecting.")
    client.connect(hostname="host.sftp.com", username="user", pkey=private_key)
    print("Connected.")

然而,如果我尝试使用ED25519密钥进行此操作,我会收到以下错误提示:
ssh-keygen -t ed25519

  File "/usr/local/lib/python3.7/site-packages/paramiko/pkey.py", line 235, in from_private_key_file
    key = cls(filename=filename, password=password)
  File "/usr/local/lib/python3.7/site-packages/paramiko/rsakey.py", line 55, in __init__
    self._from_private_key_file(filename, password)
  File "/usr/local/lib/python3.7/site-packages/paramiko/rsakey.py", line 176, in _from_private_key_file
    self._decode_key(data)
  File "/usr/local/lib/python3.7/site-packages/paramiko/rsakey.py", line 192, in _decode_key
    n, e, d, iqmp, q, p = self._uint32_cstruct_unpack(data, "iiiiii")
  File "/usr/local/lib/python3.7/site-packages/paramiko/pkey.py", line 529, in _uint32_cstruct_unpack
    raise SSHException(str(e))
paramiko.ssh_exception.SSHException: unpack requires a buffer of 4 bytes

我有点不知所措,因为围绕这个问题搜索似乎没有相关的解决方案。这是 paramiko 中的一个错误吗?还是我的 SSHClient 初始化方式存在问题?或者实际上这是一个理论问题(即,ED25519 创建密钥的方式,无法通过低级别的 unpack() 调用来读取)?


2
paramiko.RSAKey.from_private_key_file 用于读取 RSA 密钥。要读取 Ed25519 密钥,请使用 paramiko.ed25519key.from_private_key_file。(需要至少 2.2.0 版本。) - dave_thompson_085
面对掌声。哇。我感觉自己像个白痴。请把那写成答案,我会接受的。 - Yu Chen
2个回答

8
这是Dave Thompson对此问题的回答,为了完整性,这里做下解释:
`paramiko.RSAKey.from_private_key_file` 用于读取 RSA 密钥。如果要读取 Ed25519 密钥,请使用 `paramiko.Ed25519Key.from_private_key_file`。(至少需要2.2.0版本)

2
使用 paramiko==2.7.1 似乎无法正常工作:报错 AttributeError: module 'paramiko.ed25519key' has no attribute 'from_private_key_file'。也许这个方法又被移除了? - ShreevatsaR
1
它是 paramiko.Ed25519Key.from_private_key_file - RonanT
@ShreevatsaR 更新了答案以反映RonanT所说的内容。 - Yu Chen

0

我的使用情况是处理未知的密钥类型,这会导致相同的错误。我的私钥是由用户提供的,我事先不知道它的格式。我想发帖是为了让其他人寻找类似的解决方案。此方法使用cryptography库检查密钥类型并返回相应的Paramiko PKey。

from io import StringIO
from paramiko import RSAKey, Ed25519Key, ECDSAKey, DSSKey, PKey
from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import ed25519, dsa, rsa, ec

def from_private_key(file_obj, password=None) -> PKey:
    private_key = None
    file_bytes = bytes(file_obj.read(), "utf-8")
    try:
        key = crypto_serialization.load_ssh_private_key(
            file_bytes,
            password=password,
        )
        file_obj.seek(0)
    except ValueError:
        key = crypto_serialization.load_pem_private_key(
            file_bytes,
            password=password,
        )
        if password:
            encryption_algorithm = crypto_serialization.BestAvailableEncryption(
                password
            )
        else:
            encryption_algorithm = crypto_serialization.NoEncryption()
        file_obj = StringIO(
            key.private_bytes(
                crypto_serialization.Encoding.PEM,
                crypto_serialization.PrivateFormat.OpenSSH,
                encryption_algorithm,
            ).decode("utf-8")
        )
    if isinstance(key, rsa.RSAPrivateKey):
        private_key = RSAKey.from_private_key(file_obj, password)
    elif isinstance(key, ed25519.Ed25519PrivateKey):
        private_key = Ed25519Key.from_private_key(file_obj, password)
    elif isinstance(key, ec.EllipticCurvePrivateKey):
        private_key = ECDSAKey.from_private_key(file_obj, password)
    elif isinstance(key, dsa.DSAPrivateKey):
        private_key = DSSKey.from_private_key(file_obj, password)
    else:
        raise TypeError
    return private_key

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接