简体   繁体   中英

Issue with streaming private key using SSH.NET

I'm using Renci.SshNet library and have it working with using a username and private key. I can get the private key to open fine when it is read from a file or file stream, but it fails during a memory stream.

This works:

var pk = new PrivateKeyFile(@"C:\myfile.ppk");

This works:

var f = new FileStream(@"C:\myfile.ppk", FileMode.Open, FileAccess.Read);
var pk = new PrivateKeyFile(f);

These fail with "Invalid Private Key".

var s = new MemoryStream(Encoding.UTF8.GetBytes(variablename));
//No carriage returns
var s = new MemoryStream(Encoding.UTF8.GetBytes(@"-----BEGIN RSA PRIVATE KEY----- <snip>"));
//Include carriage returns
var s = new MemoryStream(Encoding.UTF8.GetBytes(@"-----BEGIN RSA PRIVATE KEY----- <snip>"));

I even tried the stream position as found on SO:

private Stream GenerateStreamFromString(string s)
{
    MemoryStream stream = new MemoryStream();
    StreamWriter writer = new StreamWriter(stream);
    writer.Write(s);
    writer.Flush();
    stream.Position = 0;
    return stream;
}

I was at first thinking the Renci library had a bug with the Stream , but obviously the file stream works. I plan on hosting the key in string format in an azure storage table, but am open to other ideas.

According to your description, I generated my private key file with SSH by using PuTTYgen and converted my key to OpenSSH format by referring to this tutorial . Based on the code you provided about using MemoryStream , I could make it work as expected on my side, you could refer to it:

var f = new MemoryStream(Encoding.UTF8.GetBytes(@"-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----");
var pk = new PrivateKeyFile(f, "{password}");

Note: I assumed that the string content of your private key which passed to Encoding.UTF8.GetBytes is in the incorrect format. To isolate this cause, you could try to save your loaded MemoryStream to a file as following code and compare it with C:\\myfile.ppk .

memoryStream.CopyTo(fileStream);

I plan on hosting the key in string format in an azure storage table, but am open to other ideas

As I known, for web applications hosted on Azure Web App, you could leverage app settings to store the key-value pairs which could be automatically loaded and overridden the existing appsettings within your web.config file at run-time.

Also, you could leverage Azure Blob storage to store your private key file in private and retrieve it as follows:

using(var ms=new MemoryStream())
{
   cloudBlockBlob.DownloadToStream(ms);
   var pk = new PrivateKeyFile(ms, "{password}"); 
}

Note: You could follow the "Encrypting blob data" section in this tutorial to encrypt your blob data both on client and server side.

Additionally, you could leverage Azure Key Vault to store your private key. More details, you could refer to this official document for getting started with Azure Key Vault.

The above answer helped me. I had the exact same problem where reading directly from a file worked but could not get a memorystream to work. It would give the error "invalid private key" every time.

The way I was reading the file into the memory steam was like this:

byte[] bytes = ReadSSHKeyFromDatabase();
MemoryStream ms = new MemoryStream();
ms.Read(bytes, 0, bytes.Length);
Renci.SshNet.PrivateKeyFile pkf = new Renci.SshNet.PrivateKeyFile(ms, Password);

However I got it to work by changing it to this:

byte[] bytes = ReadSSHKeyFromDatabase();
MemoryStream ms = new MemoryStream(bytes);
Renci.SshNet.PrivateKeyFile pkf = new Renci.SshNet.PrivateKeyFile(ms, Password);

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