Help with Invalid key format in SshPrivateKey

0 votes
asked Sep 8, 2014 by bossvt (160 points)
edited Sep 9, 2014

Hi, I'm evaluating your Rebex Terminal Emulation package to see if we can get it to work with our existing private keys. I believe our keys are RSA, though I am not an expert at it.

I have not been able to get the SshPrivateKey capability to work. The attached image shows the error I am getting. I'm pretty sure I'm passing the correct key in the keyblob variable.

Are you able to see what I am doing wrong?

Thanks

4 Answers

0 votes
answered Sep 8, 2014 by Tomas Knopp (58,890 points)
edited Sep 8, 2014

Hi,

I cannot see the image of the error. Would it be possible to send us the full stack trace of the exception that you get with the following code snippet?

try
{
    // load the private key
    var privateKey = new SshPrivateKey("path", "password");
}
catch(Exception ex)
{
    Console.WriteLine(ex.ToString());
}

For your information the currently supported private key formats include PKCS #8, OpenSSH/OpenSSL and PuTTY .ppk formats. Further info (and format examples) can be found in the Ssh private keys feature page. Please send us the content of ex.ToString and we should be able to help you then.

0 votes
answered Sep 8, 2014 by bossvt (160 points)
edited Sep 9, 2014

Here are the results from the Exception you requested:

System.Security.Cryptography.CryptographicException: Invalid key format.
   at Rebex.Security.Cryptography.Pkcs.PrivateKeyInfo.EJ(Byte[] A, Int32 B, ZE&
C, KeyAlgorithm& D, String& E)
   at Rebex.Security.Cryptography.Pkcs.PrivateKeyInfo.Load(Stream input, String
password)
   at Rebex.Net.SshPrivateKey.N(Stream A, String B)
   at Rebex.Net.SshPrivateKey..ctor(Byte[] data, String password)
   at UnixAlerter.Program.Main(String[] args) in c:\dev\UnixAlerter\RebexAlerter
\Program.cs:line 49

The link to the image should be:


Thank you for your help

0 votes
answered Sep 8, 2014 by Lukas Pokorny (94,670 points)
edited Sep 9, 2014

Thanks for the exception and the image! It looks like your key is in fact a RSA key. However, it's stored in an unsupported format that resembles the format used natively by SSH protocol for transmitting public keys and by PuTTY to store private keys. From the length, it appears the whole private key would actually fit in. Where does the key come from?

I guess we will be able to add support for this format with a bit of your help. I will post some code tomorrow that tries converting this key to something SshPrivateKey object can understand.

commented Sep 8, 2014 by bossvt (160 points)
edited Sep 8, 2014

Lukas, I don't completely understand the legacy SSH code (written in c++) that is generating those keys. It is based on wodSSH, so perhaps wod is generating the keys.

0 votes
answered Sep 9, 2014 by Lukas Pokorny (94,670 points)
edited Sep 9, 2014

The key blob appears to contain both public and private key parameters, which is good. The only problem is that we don't know which is which - we don't know anything about their order in the key blob. These are the parameters that are most likely present:

    //  modulus           INTEGER,  -- n
    //  publicExponent    INTEGER,  -- e
    //  privateExponent   INTEGER,  -- d
    //  prime1            INTEGER,  -- p
    //  prime2            INTEGER,  -- q
    //  exponent1         INTEGER,  -- d mod (p-1)
    //  exponent2         INTEGER,  -- d mod (q-1)
    //  coefficient       INTEGER,  -- (inverse of q) mod p

The following code tries reading the required RSA parameters from the key blob, constructs an SshPrivateKey object based on them, and checks whether it's usable. Please give it a try and let me know whether it works:

    using System.IO;
    using System.Text;
    using System.Security.Cryptography;
    using Rebex.Security.Cryptography;
    using Rebex.Net;
    ....


        // read RSA parameters from the key blob
        var rp = new RSAParameters();
        using (BinaryReader reader = new BinaryReader(new MemoryStream(keyblob)))
        {
            byte[] type = reader.ReadBytes((int)(reader.ReadUInt32() >> 24));
            rp.Modulus = reader.ReadBytes((int)(reader.ReadUInt32() >> 24));
            rp.Exponent = reader.ReadBytes((int)(reader.ReadUInt32() >> 24));
            rp.D = reader.ReadBytes((int)(reader.ReadUInt32() >> 24));

            // if it doesn't work, try uncomenting this line:
            //reader.ReadBytes((int)(reader.ReadUInt32() >> 24));
            // if it still doesn't work, try uncomenting this line as well:
            //reader.ReadBytes((int)(reader.ReadUInt32() >> 24));
            // and one more:
            //reader.ReadBytes((int)(reader.ReadUInt32() >> 24));

            rp.P = reader.ReadBytes((int)(reader.ReadUInt32() >> 24));
            rp.Q = reader.ReadBytes((int)(reader.ReadUInt32() >> 24));
        }

        // use Rebex RSAManaged class to calculate additional helper parameters
        var rsa = new RSAManaged();
        rsa.ImportParameters(rp);
        rp = rsa.ExportParameters(true);

        // create SshPrivateKey using the RSA parameters
        var key = SshPrivateKey.CreateFrom(rp);

        // create a signature and verify it
        byte[] hash = SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes("test data"));
        byte[] signature = key.CreateSignature(hash, SignatureHashAlgorithm.SHA1);
        bool valid = key.VerifySignature(hash, signature, SignatureHashAlgorithm.SHA1);

        // if it is not valid, something is wrong and the key is not usable
        if (!valid)
            throw new Exception("Invalid key.");

If it doesn't work, try uncomening one of the three commented lines and give it a try again. Repeat until all three lines are uncommented. If it still doesn't work, let me know.

commented Sep 9, 2014 by bossvt (160 points)
edited Sep 9, 2014

Hi Lukas, I did try all 4 variations of the code. The first 3 failed at the VerifySignature with a "Object reference not st to an instance of an object.". The last one (with all 3 lines uncommented) failed at the all failed at the CreateSignature with "ModPow not implemented for even modulo." Thank you for going the extra mile to trying to figure that out. I do appreciate the exceptional effort you made. I understand now that these keys all appear to be proprietary formats.

commented Sep 9, 2014 by Lukas Pokorny (94,670 points)
edited Sep 9, 2014

Could you share any of those key blobs with us? It looks like all the parameters are there, we just don't know the correct order, and having access to one would make it possible for us to simply try all possibilities and see which is the correct one. Of course, you should never share your private keys with anyone, but perhaps you have one for test purposes that is not supposed to be kept secret - and it might help us a lot.

...