2013-03-17 169 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/