2013-03-17 73 views
3

我期待将RSA公钥转换为我可以用作SSH公钥的东西。将RSA公钥转换为RFC 4716公钥和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公钥?

回答

8

我发现没有现成的使用功能为此在BouncyCastle。所以,解决方法是使用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; 
     } 
    } 
} 
+0

谢谢 - 这工作完美! – Doug 2015-12-19 07:08:50

+0

同意道格 - 非常好,并允许我生成与SFTP一起使用的密钥。 – 2017-05-05 06:40:35

0

实现,现在您的文章是几个月大,但如果你还在寻找试试下面的代码片段,由gotoalberto上Using public key from authorized_keys with Java security启发...

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()); 
} 
+1

这只是在.net中不起作用,并且似乎只是使用完全不同的对象名称。 – Doug 2013-12-11 14:01:54

0

注:我在微软工作,但是这不是微软回答,只是个人。

添加到Pavels答案,

我发现,由于某些原因产生3072位RSA密钥时,会的puttygen产生比我不同的RSA公钥。

经过研究,我发现,它似乎在腻子创程序的源代码,它会做。长度+ 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); 

你可以看到我的我用于测试&腻子创源代码私钥链接https://www.cameronmoten.com/2017/12/21/rsacryptoserviceprovider-create-a-ssh-rsa-public-key/