在C#中使用字符串形式的"OPENSSH"私钥文件与SSH.NET一起失败,显示"无效的私钥文件"错误。

17

我对SFTP或OpenSSH经验不足。我试图连接到客户的SFTP以上传文件。

我正在使用SSH.NET库 - https://github.com/sshnet/SSH.NET

在我的C#代码中,我将私钥存储在一个字符串变量中:

var key = @"-----BEGIN OPENSSH PRIVATE KEY-----
// snipped
-----END OPENSSH PRIVATE KEY-----
";

MemoryStream keyStream = new MemoryStream(Encoding.UTF32.GetBytes(key));

Renci.SshNet.ConnectionInfo conn = new Renci.SshNet.ConnectionInfo(
    host, 
    port,
    username, 
    new AuthenticationMethod[]
    {
         new PrivateKeyAuthenticationMethod(username, new PrivateKeyFile[]
         {
            new PrivateKeyFile(keyStream, ""), 
         }), 
    });

但是我遇到了一个错误:

无效的私钥文件。

我的问题是,我看到其他密钥以BEGIN RSA开头,但我的密钥以BEGIN OPENSSH开头 - 这是问题吗?


是的,最佳做法是将密钥存储在Azure应用程序设置中,但更好的方法是使用KeyVault以获得更高的安全性!然后,您还可以使用某些证书或身份验证进一步验证KV,以确保没有未经授权的访问。我会把它放在KeyVault中。 - Ahmed ilyas
4个回答

34

你的代码有两个问题:

  • PrivateKeyFile类使用StreamReader读取密钥,默认为UTF8,而不是UTF16。这就是为什么会出现模糊的

    invalid private key file.

  • 即使您将Encoding.UTF32更正为Encoding.UTF8,它仍然会失败。正如您所猜测的那样,SSH.NET不支持OPENSSH格式。

    最新的SSH.NET 2020.0.1仅支持ssh-ed25519密钥的OPENSSH格式。它会说:

    openssh key type: ssh-rsa is not supported

    旧版本根本不支持此格式,它们会说:

    Key 'OPENSSH' is not supported

    这些OPENSSH密钥由较新版本的OpenSSH(7.8及更高版本)生成。

    您可以使用ssh-keygen将密钥转换为经典OpenSSH格式:

    ssh-keygen -p -f file -m pem -P passphrase -N passphrase
    

    (如果密钥未加密,请使用""代替passphrase

    对于Windows用户:请注意,ssh-keygen.exe现在内置于Windows 10和11中。并且可以从Microsoft Win32-OpenSSH项目下载以供旧版本的Windows使用。


    在Windows上,您还可以使用PuTTYgen(来自PuTTY软件包):

    • 启动PuTTYgen
    • 加载密钥
    • 转到Conversions > Export OpenSSH key
      对于RSA密钥,它将使用经典格式。

    如果您正在使用ssh-keygen创建新密钥,请添加-m PEM以在经典格式中生成新密钥:

    ssh-keygen -m PEM
    

这个可以运行:

var key = @"-----BEGIN RSA PRIVATE KEY-----
MIIEoQIBAAKCAQEAjQtUVe5ewYro8utRXqftODAg9zpqkP3+kmpVoIIXe27ga3jy
rUzJtCItx1jqjdZypcPrxB+8j2nUJj108Bw5y088OquGz/GhBk0uTN+/kQ7K4vnE
y7X4VuKDOloAAXRcyUZ621RWzM/Xp5M/lU6kuR+TtlMd1lpWmeKSNXhfP4gYaPMT
p/4+u247ng+HIwW9CLl5PGIO/AXImt/XyVMKMqw8IgGRKaYBBL2R9wLPBAYVzgHe
svfSDYdeNyh3XG+gbLgq2lmCYcq3wF//Ms3G/cTIm1ipeaeL89bTR9fYhLwQFdlp
UPy8wii/7jlfY/V+8EHQENNGZc3w0wPzP7EdkwIBJQKCAQBIbZoCnQA534xhEQ4b
2bEqsO5VcQZKdJd7nmNSbFE/YnM+G4OJbJ7tzFyyecSOBlaMeV1ktlnox6RK/Pbc
KiuEE+5+/iKiIiJBgZRQ/UayRd3OgEJ2cjNq4wUd9t1oh9yetX1b3zN97jB4pY9a
glSWailB81SC1HGo986KKQ5RDcA9cNa19uBEkUcTdcaph8wLcUDkT2PsavJt1wUF
0d8E3mKejDFMJJBt+642PdnrSK2N+3TtkEx2DxMAoQ5gPfaDWeN4QwbxDeNllfFM
BHj7ezL2N+U037fp/jAMyWVDaqN2leAakXkqQ73pdnvIsYHlxIvNTq0rFD64ELkT
ABq9AoGBAPG63tfV7Bzkd/iX5uIrjJY1UtbxhWMaoaF6tEJ+wZyEpcVEYWcFu0v2
20aFsdFWYFTe2vqkVcJpm3QjUJqBg6D7LWUBmy46VFlXhpvkp9g7I4xeRLT9xWVY
iwCgofyKw3Wa+aZWyBxt3DR2e+WKU5y4/dqAoprgGy3ChgSjM4DLAoGBAJVe2i3o
+3qUzeEIrxSf3H6HOT7fGaXsk+M8zDqrBjSki0sHMNedHMQ3tM/EUc6SnvWyPTZA
AlJSOllIg0eYxCzdiuJ1SUai4g9fp+u6HTkOzETJY7zfBhFM45AHkrh2r6z/u+Yk
yH57QeO+k2BgSDYZgdfX9cYW3C365BpqBCVZAoGBAOSp2bdpfnwyEJ8MO0SlvFa8
0dI+aWuVu30TNOT0cfTsLht4CRxDsSwus79AMpWW5YC3IitdLod4p865n0YLz4px
D0Pe7L0Gvn4Gr8PmIjs+3HAGJVFDFKv5z5jPTR9S1JHXyY+ChfFhALwBYHFZVgL0
LmboYnbT/gixFv13yO9zAoGAcQmCg5uN4DlB2rp2p9LsDLlbwOAvFcfJ3GVcSBK4
lopbkrlVZOWZOosFXvVuVyLZKKKPL/kWg3x/Ls8XPRmpNrV9285g9y8nnO5xPMQx
ylBjOvlEju32wPvqetVMb+sdKPjhOIqJ4yzX6p4OqcxSUnQq6IfA6O60ddKex+GG
mM0CgYAqm3oISjWhyq+4iN4C2eQXtAdAjkA7c0ZaHRFFapOI+ZqPXEi+oyhuPj4Z
ZeUcZkS9cYKkgRGDG33p1ZiR+iY7I6Qv8Seyu/oh75/lL0imiq7yKTmizL2WIow7
lT1yYNZJI/YNEdWPKOZl6kYsHliW8TaUk0yvDC/LPADabjvjzg==
-----END RSA PRIVATE KEY-----
";

MemoryStream keyStream = new MemoryStream(Encoding.UTF8.GetBytes(key));
new PrivateKeyFile(keyStream);

一个相关的问题:当使用SSH.NET从配置字符串加载SSH私钥时,“Renci.SshNet.Common.SshException:Invalid private key file”

2
感谢马丁的帮助。 - andrewb
如果你在Windows上进行这个操作,请确保密钥文件使用的是Unix文件结尾符(\n),而不是Windows的结尾符(\r\n),否则ssh-keygen会报错。 - ElGringo

-1

我想实现一个使用基于密钥的身份验证的Posh SSH会话,并遇到了相同的消息“openssh key type: ssh-rsa不受支持”,我正在连接到一个RHEL 8服务器。根据这篇文章,我在RHEL盒子上重新生成了私钥:

ssh-keygen -p -f id_rsa -m pem

结果id_rsa文件被重写。然后我将这个私钥传输到我的Windows电脑上,并成功地使用重新生成的文件进行了身份验证。


目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - MD. RAKIB HASAN

-1

很抱歉要说,我在这个OpenSSH问题上花了几个小时...最终通过将我的ssh.net库从2016年升级到2020年来解决它...是我的错误之前没有尝试过。


我的回答已经说得很清楚了。 - Martin Prikryl

-1

我也遇到了这个问题。

请确保使用seek方法或设置position = 0将流设置为位置0。

查看SSH.Net代码。当我不设置位置时,它会读取流并生成一个空字符串——这是一个无效的密钥。更好的错误提示会更好……


你期望什么样的更好的错误? - Martin Prikryl
这并没有回答问题。一旦您拥有足够的声望,您将能够评论任何帖子;相反,提供不需要询问者澄清的答案。- 来自审核 - user16217248

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