无需ssh-keygen,C#应用生成SSH.NET兼容密钥及格式转换方案
C#中生成兼容SSH.NET的ECDSA384密钥对及公钥格式转换
1. 当前实现方式是否合理?
- 整体方向合理:用BouncyCastle在应用内生成ECDSA384密钥对,解决了用户无
ssh-keygen权限的问题,且ECDSA384是SSH.NET明确支持的公钥算法。 - 需注意私钥格式兼容性:SSH.NET对PKCS#8格式的PEM私钥支持更稳定,生成时要确保输出PKCS#8格式(而非传统PKCS#1)。可通过BouncyCastle的
Pkcs8Generator类生成该格式私钥,避免因格式不兼容导致SSH.NET无法加载。 - 额外注意:生成密钥时必须指定标准椭圆曲线
secp384r1(对应nistp384),这是SSH协议中ECDSA384的规范曲线,确保与服务端兼容。
2. 如何将OpenSSL PEM格式公钥转换为OpenSSH格式?
由于无法使用ssh-keygen,可通过手动解析PEM并构造OpenSSH格式公钥,核心实现如下:
核心原理
OpenSSH的ECDSA公钥结构为:
[算法标识长度(4字节大端)][算法标识字符串][公钥数据长度(4字节大端)][公钥数据]
其中:
- 算法标识固定为
ecdsa-sha2-nistp384 - 公钥数据是未压缩EC点:前缀
0x04+ 384位X坐标字节 + 384位Y坐标字节
C#实现代码(基于BouncyCastle)
using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Security; using System; using System.IO; using System.Text; public static string ConvertEcdsaPemToOpenSsh(string pemPublicKey) { // 清理PEM格式的头尾和换行符 var cleanedPem = pemPublicKey .Replace("-----BEGIN PUBLIC KEY-----", "") .Replace("-----END PUBLIC KEY-----", "") .Replace("\r", "") .Replace("\n", ""); // Base64解码得到DER格式字节 var derBytes = Convert.FromBase64String(cleanedPem); // 解析DER格式的EC公钥 var asn1Seq = Asn1Sequence.GetInstance(derBytes); var pubKeyInfo = SubjectPublicKeyInfo.GetInstance(asn1Seq); var ecPubKey = (ECPublicKeyParameters)PublicKeyFactory.CreateKey(pubKeyInfo); // 获取未压缩的公钥点字节(0x04 + X坐标 + Y坐标) var pubKeyBytes = ecPubKey.Q.GetEncoded(false); // 构造OpenSSH公钥的字节流 var algorithmBytes = Encoding.UTF8.GetBytes("ecdsa-sha2-nistp384"); using var ms = new MemoryStream(); // 写入算法标识的长度和内容 WriteBigEndianInt(ms, algorithmBytes.Length); ms.Write(algorithmBytes, 0, algorithmBytes.Length); // 写入公钥数据的长度和内容 WriteBigEndianInt(ms, pubKeyBytes.Length); ms.Write(pubKeyBytes, 0, pubKeyBytes.Length); // 编码为Base64并拼接前缀 var openSshBase64 = Convert.ToBase64String(ms.ToArray()); return $"ecdsa-sha2-nistp384 {openSshBase64}"; // 可追加用户标识,如 " user@example.com" } // 写入大端格式的4字节整数 private static void WriteBigEndianInt(Stream stream, int value) { var bytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) Array.Reverse(bytes); stream.Write(bytes, 0, bytes.Length); }
验证方式
生成的OpenSSH格式公钥可直接添加到SSH服务端的authorized_keys文件中,测试是否能通过SSH.NET使用对应私钥完成认证。
内容的提问来源于stack exchange,提问作者Thomas853
相关产品推荐
相关产品推荐

