简体   繁体   中英

C# create ssh-rsa public key from existing private key string

I wish to create an ssh-rsa public key from an existing private key string

for example:

for the following private rsa key string:

    -----BEGIN RSA PRIVATE KEY-----     MIIEogIBAAKCAQEAvyN0aQKoYl/LAZ/1dQt0rWuSNyOty88k3439HT3rcT/vhaSk     d5lbnNKiYTzdDEkAxAnx4rxw6bEdD/8A9ISs0jy3pFRORFdbgBVFjIPR2NKbwVbs     9fcQNOQHcNslAyHA/yy57ktw+/6VyHYnHfXFlhkt1Jx4A1ubFIGzXttnXkwuNhdn     2JLJ5+JA3zRDJNBZR7p7NHVu9cRBwADm/WSzPqI6Sgs8kkU0eBcfy7qJRao3cmR5     95lLxkhFARufSW8lD/tCs2k99T2ZwZpKJpliA5VGjIC3iHhck3tpXs5w9sQ5Axhv     n1kTq5GKNi48r132KgRNJO+jIY0QSI60A6akbwIDAQABAoIBACCB3SiG5TBl7lbG     Z66SVjOwWdu627IP9st2kJfKkiJep1PpXndgw632PNugyE9wkwrETjkrp2B3WOQB     kJ4Feob/AJSYKf+Bg/RSqdNuD+B6YTcOm5pxfHYiWgmdm7ven75GUxDuD7cr4zmG     rrxvsj0G5z6Dpf2cNNHWBTWaxwfITaC8yXp6dx8o8V86/T0qrsEl+S0YJ5VQWt6L     I5GzipFNhhjcaemkOxDJg2T/g0FbpBEuj3RnwWNfRiiTCt+AuROg6/4M2oyLBE9W     e8n8KAUhZvRJA2dFwzZY38U9MfX9k9zIkJXtpkeghGx3M2zG3cQcFOaly6aFNHjr     QuEd6kECgYEA7NQgfqxuJ34kMnmtZeYccFGI6WUosuXUlgMhqU8CUnjIaRX8u8Ho     UjvjbezHNsI8tyH3vopgHNqTkcuElyuxKZQBTtUOFGG4a1HUS5tlo913DcnuSVIa     qL8kn3XVDHvuTr8tJbsb4KXrEMFfGoJBemU4ixSDiYWk/FdXvyyEEbECgYEAzpx6     JPOktmdaLf8U7snvlRY9daBqKfPqtKDxYgsC3xOp90Z3FMWQi5OyPmBsLGmjHxhe     YrPYQ3lbRh2JuRgZ7rTAxXN9dnDNgrh4tFjEEqQiFBCGlhP6syNM9Kx0YYNAoJN4     U29Tv71rxHJiFaLiRTh3Nopdn5ir4Raoj2fQgB8CgYBxCCFmNAfzA2plSNuwia5D     ETcmJejR0Y2v91imhRYXpJwKQ7s3JaorLXgzq9G82eG+ihDDOSn8O3o5GIh02h6Z     OJGTPW6V3bn2RrzrRQSyu+2pgBohlnUw2uGw1b1UUwX/QZFbs7zvcGELwy8P6OE1     eIAPKUBKb6W55jnz/VwfUQKBgGPTpQyPkAj1vNO2iLWrag/dtApOXJ0yljd5/8cA     TP3dsWShbk3h+yoFTbznt7xpuf//NTN5c8d+LkSdZvrAk18LhIyidX8xl4pOeTui     G/JpzXFmXrDKrHm7V6ZsYLrwwNwVBLFDe/KLojNDlPKhRbRuSONYTU4cZQeXfA/1     9/6/AoGAarF4JSdpzMzfacpLy2nsOM6XmL76B218uKANSHQy9k1X/Hp1u1StY8tQ     H4+DSrRUQBb4sdxkCRXVvMH3zttDGoIrSUvDqN3k4opcP8nmzMc/EDwD3xFgri/p     yBXBhE99r1B0p7fneXt58tTqtcevk5dQPzyF9SdsfUxD5PrnZRI=     -----END RSA PRIVATE KEY-----

I wish to get the following output:

   ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/I3RpAqhiX8sBn/V1C3Sta5I3I63LzyTfjf0dPetxP++FpKR3mVuc0qJhPN0MSQDECfHivHDpsR0P/wD0hKzSPLekVE5EV1uAFUWMg9HY0pvBVuz19xA05Adw2yUDIcD/LLnuS3D7/pXIdicd9cWWGS3UnHgDW5sUgbNe22deTC42F2fYksnn4kDfNEMk0FlHuns0dW71xEHAAOb9ZLM+ojpKCzySRTR4Fx/LuolFqjdyZHn3mUvGSEUBG59JbyUP+0KzaT31PZnBmkommWIDlUaMgLeIeFyTe2leznD2xDkDGG+fWROrkYo2LjyvXfYqBE0k76MhjRBIjrQDpqRv administrator@LovelyTrust

I tried few ways but unfortunately nothing gave me the desired output, for example, I was able to generate RSA object from my private key using:

    public static string ExtractPublicKeyFromPrivate(string privateKey)
    {
        var rsa = RSA.Create();
        rsa.ImportFromPem(privateKey.ToCharArray());
        return ""
    }

but both

rsa.ExportRSAPublicKey()
rsa.ExportSubjectPublicKeyInfo()

didn't give me the desired output, any ideas?

SSH key format is a bit complex. Moreover, .NET doesn't have a method to directly get the key in this format. However, something like this will work (I tried in a .NET 6 console application, and got the public key exactly how you want it.):

// See https://aka.ms/new-console-template for more information
using System.Security.Cryptography;
using System.Text;

static byte[] ToBytes(int i)
{
    byte[] bytes = BitConverter.GetBytes(i);

    if (BitConverter.IsLittleEndian)
    {
        Array.Reverse(bytes);
    }

    return bytes;
}

string privateKey = "-----BEGIN RSA PRIVATE KEY-----     MIIEogIBAAKCAQEAvyN0aQKoYl/LAZ/1dQt0rWuSNyOty88k3439HT3rcT/vhaSk     d5lbnNKiYTzdDEkAxAnx4rxw6bEdD/8A9ISs0jy3pFRORFdbgBVFjIPR2NKbwVbs     9fcQNOQHcNslAyHA/yy57ktw+/6VyHYnHfXFlhkt1Jx4A1ubFIGzXttnXkwuNhdn     2JLJ5+JA3zRDJNBZR7p7NHVu9cRBwADm/WSzPqI6Sgs8kkU0eBcfy7qJRao3cmR5     95lLxkhFARufSW8lD/tCs2k99T2ZwZpKJpliA5VGjIC3iHhck3tpXs5w9sQ5Axhv     n1kTq5GKNi48r132KgRNJO+jIY0QSI60A6akbwIDAQABAoIBACCB3SiG5TBl7lbG     Z66SVjOwWdu627IP9st2kJfKkiJep1PpXndgw632PNugyE9wkwrETjkrp2B3WOQB     kJ4Feob/AJSYKf+Bg/RSqdNuD+B6YTcOm5pxfHYiWgmdm7ven75GUxDuD7cr4zmG     rrxvsj0G5z6Dpf2cNNHWBTWaxwfITaC8yXp6dx8o8V86/T0qrsEl+S0YJ5VQWt6L     I5GzipFNhhjcaemkOxDJg2T/g0FbpBEuj3RnwWNfRiiTCt+AuROg6/4M2oyLBE9W     e8n8KAUhZvRJA2dFwzZY38U9MfX9k9zIkJXtpkeghGx3M2zG3cQcFOaly6aFNHjr     QuEd6kECgYEA7NQgfqxuJ34kMnmtZeYccFGI6WUosuXUlgMhqU8CUnjIaRX8u8Ho     UjvjbezHNsI8tyH3vopgHNqTkcuElyuxKZQBTtUOFGG4a1HUS5tlo913DcnuSVIa     qL8kn3XVDHvuTr8tJbsb4KXrEMFfGoJBemU4ixSDiYWk/FdXvyyEEbECgYEAzpx6     JPOktmdaLf8U7snvlRY9daBqKfPqtKDxYgsC3xOp90Z3FMWQi5OyPmBsLGmjHxhe     YrPYQ3lbRh2JuRgZ7rTAxXN9dnDNgrh4tFjEEqQiFBCGlhP6syNM9Kx0YYNAoJN4     U29Tv71rxHJiFaLiRTh3Nopdn5ir4Raoj2fQgB8CgYBxCCFmNAfzA2plSNuwia5D     ETcmJejR0Y2v91imhRYXpJwKQ7s3JaorLXgzq9G82eG+ihDDOSn8O3o5GIh02h6Z     OJGTPW6V3bn2RrzrRQSyu+2pgBohlnUw2uGw1b1UUwX/QZFbs7zvcGELwy8P6OE1     eIAPKUBKb6W55jnz/VwfUQKBgGPTpQyPkAj1vNO2iLWrag/dtApOXJ0yljd5/8cA     TP3dsWShbk3h+yoFTbznt7xpuf//NTN5c8d+LkSdZvrAk18LhIyidX8xl4pOeTui     G/JpzXFmXrDKrHm7V6ZsYLrwwNwVBLFDe/KLojNDlPKhRbRuSONYTU4cZQeXfA/1     9/6/AoGAarF4JSdpzMzfacpLy2nsOM6XmL76B218uKANSHQy9k1X/Hp1u1StY8tQ     H4+DSrRUQBb4sdxkCRXVvMH3zttDGoIrSUvDqN3k4opcP8nmzMc/EDwD3xFgri/p     yBXBhE99r1B0p7fneXt58tTqtcevk5dQPzyF9SdsfUxD5PrnZRI=     -----END RSA PRIVATE KEY-----";

var rsa = RSA.Create();
rsa.ImportFromPem(privateKey.ToCharArray());

byte[] sshrsaBytes = Encoding.Default.GetBytes("ssh-rsa");
byte[] n = rsa.ExportParameters(false).Modulus;
byte[] e = rsa.ExportParameters(false).Exponent;
string buffer64;

using (var ms = new MemoryStream())
{
    ms.Write(ToBytes(sshrsaBytes.Length), 0, 4);
    ms.Write(sshrsaBytes, 0, sshrsaBytes.Length);
    ms.Write(ToBytes(e.Length), 0, 4);
    ms.Write(e, 0, e.Length);
    ms.Write(ToBytes(n.Length + 1), 0, 4);
    ms.Write(new byte[] { 0 }, 0, 1);
    ms.Write(n, 0, n.Length);
    ms.Flush();
    buffer64 = Convert.ToBase64String(ms.ToArray());
}

string comment = "administrator@LovelyTrust";
string publicKey = $"ssh-rsa {buffer64} {comment}";
Console.WriteLine(publicKey);

ToBytes method is simply checks your machine's endianness and converts bytes into correct order if necessary.

We first create an RSA object and import the private key, just like you did. After that, the complex part I mentioned starts, and continues until the end of the using block. Finally, we concatenate that value with ssh-rsa word from the left and the comment (this is the value entered in Key comment text field if you use PuTTY Key Generator) from the right.

This code is heavily inspired from the code of SshKeyGenerator library. Unfortunately, the library itself does not support key import. On the other hand, if you want randomly generated SSH private and public key pairs, using directly the library will be probably easier and more convenient.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM