Issue
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.
Solution
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.
Answered By - Bruce Chen