将RSA公钥转换为具有Bouncy Castle的RFC 4716公钥

我希望将RSA公钥转换为可以用作SSH公钥的东西。

目前我有Bouncy Castle为我提供了一个如下所示的公钥:

-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq1Y5300i8bN+cI2U3wJE Kh3xG/.........jbuz+WB0vvG P25UwCle2k5siVMwbImEYsr+Xt0dsMmGVB3/6MHAqrM3QQdQ8p2E5TyzL+JYa1FT gwIDAQAB -----END PUBLIC KEY----- 

我希望它具有与此类似的RFC 4716格式:

ssh-rsa AAAAB3NzaC1yc2.......G1p2Ag3mZLFsks7RNHVLgMsGIAikQ==

到目前为止,使用Bouncy Castle的我的代码如下所示:

 var r = new Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator(); r.Init(new KeyGenerationParameters(new SecureRandom(), 2048)); var keys = r.GenerateKeyPair(); var stringWriter = new StringWriter(); var pemWriter = new PemWriter(stringWriter); pemWriter.WriteObject(keys.Private); pemWriter.Writer.Flush(); stringWriter.Close(); PrivateKey = stringWriter.ToString(); stringWriter = new StringWriter(); pemWriter = new PemWriter(stringWriter); pemWriter.WriteObject(keys.Public); pemWriter.Writer.Flush(); stringWriter.Close(); PublicKey = stringWriter.ToString(); 

如何重新格式化和编码密钥使其看起来像这样?

有没有人用Bouncy Castle或类似的东西创建SSH公钥?

我发现在BouncyCastle中没有现成的function。 因此,解决方法是使用PemReader ,然后格式化结果。 结果将作为PublicSSH属性提供:

 using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Security; using System; using System.IO; using System.Text; namespace Deploy4Me.Common.Utils { public class RSAKey { public string PublicPEM { get; set; } public string PrivatePEM { get; set; } public string PublicSSH { get; set; } } public static class RSA { public static RSAKey Generate() { try { RSAKey result = new RSAKey(); IAsymmetricCipherKeyPairGenerator gen; KeyGenerationParameters param; gen = new RsaKeyPairGenerator(); param = new RsaKeyGenerationParameters( BigInteger.ValueOf(3L), new SecureRandom(), 2048, 80 ); gen.Init(param); AsymmetricCipherKeyPair pair = gen.GenerateKeyPair(); using(TextWriter textWriter = new StringWriter()) { PemWriter wr = new PemWriter(textWriter); wr.WriteObject(pair.Private); wr.Writer.Flush(); result.PrivatePEM = textWriter.ToString(); } using (TextWriter textWriter = new StringWriter()) { PemWriter wr = new PemWriter(textWriter); wr.WriteObject(pair.Public); wr.Writer.Flush(); result.PublicPEM = textWriter.ToString(); } using (StringReader sr = new StringReader(result.PublicPEM)) { PemReader reader = new PemReader(sr); RsaKeyParameters r = (RsaKeyParameters)reader.ReadObject(); byte[] sshrsa_bytes = Encoding.Default.GetBytes("ssh-rsa"); byte[] n = r.Modulus.ToByteArray(); byte[] e = r.Exponent.ToByteArray(); string buffer64; using(MemoryStream ms = new MemoryStream()){ ms.Write(ToBytes(sshrsa_bytes.Length), 0, 4); ms.Write(sshrsa_bytes, 0, sshrsa_bytes.Length); ms.Write(ToBytes(e.Length), 0, 4); ms.Write(e, 0, e.Length); ms.Write(ToBytes(n.Length), 0, 4); ms.Write(n, 0, n.Length); ms.Flush(); buffer64 = Convert.ToBase64String(ms.ToArray()); } result.PublicSSH = string.Format("ssh-rsa {0} generated-key", buffer64); } return result; } catch (Org.BouncyCastle.Crypto.CryptoException ex) { throw ex; } } private static byte[] ToBytes(int i) { byte[] bts = BitConverter.GetBytes(i); if (BitConverter.IsLittleEndian) { Array.Reverse(bts); } return bts; } } } 

认识到你的post现在已经有几个月了,但是如果你还在寻找下面的代码片段,请启发gotoalberto on 使用来自使用Java安全的authorized_keys的公钥 …

 public static String getPublicOpenSSHKey(String pem, String userComment) throws IOException, EWAException { // Read the PEM supplied using Bouncy Castle's PEMReader ... PEMReader r = new PEMReader(new StringReader(pem)); try { keyPair = (KeyPair) r.readObject(); } catch (IOException ioe) { ioe.printStackTrace(); } finally { try { r.close(); } catch (Throwable ignore) { } } PublicKey publicKey = keyPair.getPublic(); if (publicKey.getAlgorithm().equals("RSA")) { RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; ByteArrayOutputStream byteOs = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(byteOs); dos.writeInt("ssh-rsa".getBytes().length); dos.write("ssh-rsa".getBytes()); dos.writeInt(rsaPublicKey.getPublicExponent().toByteArray().length); dos.write(rsaPublicKey.getPublicExponent().toByteArray()); dos.writeInt(rsaPublicKey.getModulus().toByteArray().length); dos.write(rsaPublicKey.getModulus().toByteArray()); String enc = Base64.encode(byteOs.toByteArray()); return("ssh-rsa " + enc + " " + userComment); } else throw new IllegalArgumentException("Unknown public key encoding: " + publicKey.getAlgorithm()); } 

注意:我在Microsoft工作,但这不是Microsoft的答案,只是个人。

添加到Pavels答案,

我发现由于某种原因,在生成3072位RSA密钥时,PuttyGen会生成与我不同的RSA公钥。

经过研究,我发现它似乎在Putty Gen程序的源代码中它会对字节数组执行.Length + 1,添加前导0。

对于BouncyCastle,您可以更改此行。

  ms.Write(ToBytes(n.Length), 0, 4); ms.Write(n, 0, n.Length); 

  ms.Write(ToBytes(n.Length+1), 0, 4);//Add +1 to Emulate PuttyGen ms.Write(new byte[] { 0 }, 0, 1); //Add a 0 to Emulate PuttyGen ms.Write(n, 0, n.Length); 

对于Microsoft .net RSACryptoServiceProvider,它看起来像这样

  RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(3072); byte[] sshrsa_bytes = Encoding.Default.GetBytes("ssh-rsa"); byte[] n = RSA.ExportParameters(false).Modulus; byte[] e = RSA.ExportParameters(false).Exponent; string buffer64; using (MemoryStream ms = new MemoryStream()) { ms.Write(ToBytes(sshrsa_bytes.Length), 0, 4); ms.Write(sshrsa_bytes, 0, sshrsa_bytes.Length); ms.Write(ToBytes(e.Length), 0, 4); ms.Write(e, 0, e.Length); ms.Write(ToBytes(n.Length+1), 0, 4); //Remove the +1 if not Emulating Putty Gen ms.Write(new byte[] { 0 }, 0, 1); //Add a 0 to Emulate PuttyGen ms.Write(n, 0, n.Length); ms.Flush(); buffer64 = Convert.ToBase64String(ms.ToArray()); } string pubssh = string.Format("ssh-rsa {0} generated-key", buffer64); 

您可以看到我用于测试的私钥和putty gen源代码链接https://www.cameronmoten.com/2017/12/21/rsacryptoserviceprovider-create-a-ssh-rsa-public-key/