SSH RSA privatekeys? with passphrase?

Sep 5, 2012 at 7:50 AM

I want to write a small Windows application in which I need to

use SSH authentication with RSA privatekeys with passphrases.

The Feature-List says: Supports RSA and DSA private key

But the Code says:

// TODO: Implement more private key ciphers //case "AES-128-CBC":
// cipher = new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); }); // break;


So I'm confused about the status of this feature.
Is it working? And if not, is somebody working on this feature?

Thx in advance
Sep 5, 2012 at 8:40 AM
Edited Sep 5, 2012 at 5:18 PM

Ok. I should have read the feature list more carefully.

- Supports DES-EDE3-CBC, DES-EDE3-CFB, DES-CBC algorithms for private key encryption.

Is AES coming? And what can I do to help develop and add this feature?

Sep 8, 2012 at 10:23 AM

Nobody interested in help? :(

Sep 9, 2012 at 1:50 AM

Hello :-)

You are welcome to create a patch, but if you do, also provide unit tests for it, and provide references, like articles you read to understand or figure it out!

Sep 9, 2012 at 10:22 AM
Edited Sep 9, 2012 at 5:12 PM

Hi,

Maybe olegkap can help and explain his code :)

Decryption seems to work. (at least no Exception occurs)

Edit:

Ok. Decryption seems to be the problem.

I just checked what System.Convert.ToBase64String(decryptedData) shows

and what openssl rsa -in rsa-aes-128-cbc shows. They differ :(

Would be awesome if somebody can explain the current status of the AES-Code.


But it fails to set the RsaKey at:

this._key = new RsaKey(decryptedData.ToArray());

And I currently don't understand what DER is and what it should do.

Testname:    Test_Connect_Using_RsaKey_With_PassPhrase_AES_128_CBC
Test FullName:    Renci.SshNet.Tests.ConnectionTest.Test_Connect_Using_RsaKey_With_PassPhrase_AES_128_CBC
Testquelle:    c:\Users\Anonym\Downloads\sshnet-18974\Renci.SshClient\Renci.SshNet.Tests\ConnectionTest.cs Zeile 67
Testergebnis:    Fehler
Testdauer:    0:00:00.065376

Ergebnis Meldung:    Die Renci.SshNet.Tests.ConnectionTest.Test_Connect_Using_RsaKey_With_PassPhrase_AES_128_CBC-Testmethode hat eine Ausnahme ausgelöst: System.InvalidOperationException: DER length is '73' and cannot be more than 4 bytes.

In my Diff

- Added a Test, which loads an RsaKey with AES_128_CBC and Passphrase "tester"

         [TestMethod]
         [TestCategory("Authentication")]
+        public void Test_Connect_Using_RsaKey_With_PassPhrase_AES_128_CBC()
+        {
+            MemoryStream keyFileStream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITH_PASS_AES_128_CBC));
+            using (var client = new SshClient(Resources.HOST, Resources.USERNAME,new PrivateKeyFile(keyFileStream, Resources.PASSWORD)))
+            {
+                client.Connect();
+                client.Disconnect();
+            }
+        }

 

- Added the RsaKey to the resources:


+  <data name="RSA_KEY_WITH_PASS_AES_128_CBC" xml:space="preserve">
+    <value>-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,14E6E28F4EADB6740179BB51685AEFA0
+
+aL3PaH9NWmb+kM7HMUTDRDYU5dRUY+wCGzh/EjSZFavqFWqrS7Z1KN+ur4geI7pw
+V3MnYGjXR+raMdcLxrEnBObJ1VjS0Vx835O5ZAxwFveHlWs83ChSqsvfqQ6tcIK6
+tD0Bcdo31rDTDmoG6saseSXxjNvzrwYRDgjCzRKTVqK2FLQWPgAhqevzojqcV3my
+h714lQqng60tnI+CAqV80W2zCTZZe7cozj+Erx1zQBXmpRjs+R3XY9Jla1yN43pW
+4rBGB/5m8A3nUxV/ZiEfbL17QxuGkLhFIHUjz5zm8+E2+hQv21VTsdIKl1PY5tqr
+0yuCE1RIBZ7e0zzwXeOBaj4UsbbP+Vu0vEQowyQOxkO8O3BnWZFPaOJftEst6adJ
+mPsLF4RCYsYsQcsl5nKcSCastq7SCLLPnT2kwjNDVdrcBc6NeQ9x8IYFflAeFIcY
+SGu77XvNnmjb7taFY63D6tkbZaxZnd8JhyDUc90mzX/Vlneo+cAq9COzxTsRZT0y
+ZU5ccAbpUG+z4HZ6udTjw+TC1nZFCWuFhqMwo49OSQiVVWW4ts2Mz7u4fhJ4ksIe
+q7UleXx3zfQDBIn49pH0c77tb7HtFFyIseXSpfdyo/zdGujyqGLxpNkjFgwoSxrU
+Bpd9YOUzhHT70J2QDQMKSSupSOyT67PGXjlFXP2BGRPyp4dGG87lFRT3Xyo1MGvV
+QfJ+Psvb2O/y7xoUevMqDArsLmrbe/AMcD1QQO+9nZD6+V8rHtBJ2qN7xWmLjj1V
+N52NhagRsSMj3X9uPgtxdgs1lzMo8U5G324OtZKwIg84cWDW8nl6IZbQsSHTsUB5
+s4ChoOx1dMHd9pUu7NSzepGlXyFgKtwLCaoUE6nmMZo5d3HUtq3AU+SOlUF2htok
+L7ZbScpgw8iLt5zjdaa0jXD3wqLxr4qBrlhyeSNZ0O4Fh9wskatidLKtlUJ+dlci
+26TbyJsTrfNhNKO36I9G2lG6XVMaEGpwMS36S90qhbnIUE7ZHxL2qfjd/X6ZX1QW
+Xtz7g0S/mUzo5GtkY3MGNQ+s4DeMLydMF9vUwOf9qM7AMoek4MBZ0VnuyUGF+qOn
+kxDy34sYUU92V3gYigl2a/OkU3c9UlNunL/CZ5DUk2rVUQN6uCs8PpXAdkQuacnJ
+vaS43MEJTB9CLuatbSFo6GWcZp1Ih9BySikJAJ1dX2ndHf5cVA2F+lKvHFk1uSH+
+T8x1z5/S9wSnvyc2E6YiLoVCrqZGIoAcCKHszkE+idjnNrQsta5QpG8ln2gsqhoj
+AvPI3rHKDdn0hs+wRhs5gGqv9VkesLY5zBzdZFwfy69lTy4hg0yXmrZb7samaEZQ
+iBW6YG3QlZ/hY3YTd7wkRm9NVOPNe+yNrRBKJ4sdx2T7Y0QIXBVFSMsiq5PrkBEL
+o5B+dmmr2nff8mM0Am27dM/4mTSYTASC7+3uxaPKwUneMSaBvg5UMSlTRc/LC9es
+qyQIIiFN8yui7YFcDEdkCPgIYQcIJHuXu5YJvHh0rBL14JEl0BVhL8bjH12tqprR
+h9juDxZVaXoIiAKKQJS2l9MZERJ6JEexD4vfw3WsjlTkyg6JDOiHtfpyk4o8fYNk
+-----END RSA PRIVATE KEY-----</value>
+  </data>


- and enabled AES in PrivateKeyFile.cs:

-                    //case "AES-128-CBC":
-                    //    cipher = new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); });
-                    //    break;
-                    //case "AES-192-CBC":
-                    //    cipher = new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); });
-                    //    break;
-                    //case "AES-256-CBC":
-                    //    cipher = new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); });
-                    //    break;
+                    case "AES-128-CBC":
+                        cipher = new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); });
+                        break;
+                    case "AES-192-CBC":
+                        cipher = new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); });
+                        break;
+                    case "AES-256-CBC":
+                        cipher = new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); });
+                        break;

Sep 10, 2012 at 7:24 AM

The DER exception comes from Renci.SshNet\Common\DerData.cs (searched for "DER length" in Entire Solution) and it mentions X690, which wikipedia has an article about X690, where they call it Distinguished Encoding Rules), which then links to ASN.1 (Abstract Syntax Notation).

PS: You can wrap code in <pre></pre> by editing the HTML when clicking on the HTML icon in the toolbar for the post.

Sep 10, 2012 at 7:55 AM
Edited Sep 10, 2012 at 7:55 AM

Hi,

Thanks for the links! DER seems to be OK as far as I can see. The decryption of the key returns something different than openssl rsa -in rsa-aes-128-cbc. So the Exception of DER seems to be the result of wrong decrypted key-data.

Lets see if we can find out why it is wrong :)

Coordinator
Sep 10, 2012 at 1:02 PM

Hi,

 

Unfortunatly, when it comes to private key encryption, I could not find any helpfull documentation.

I used some other source code that encrypts or decrypts private keys to figure out how it works.

For some reason, I could not make it work with AES encryption, even so DES seems to be working just fine.

If anyone can find a documention on how private key encryption should work, then I would defiantly will take a look at it.

I remember I spent some time already to fix it but with no luck, since encryption is also not my strongest side :(.

I tried to implemented DER functionality at first to support multiple situation but at the end, I remeber I think I hardcoded some elements of it so it could work with supported encryption. One guess is may be in case of AES encryption there should be some extra step before encrypting.

 

Sorry couldn't be much more help, also don't really have much time recently to work on it due to few other projects :(

Kenneth, Thanks for trying to help with this and other posts.

 

Thanks,

Oleg

 

Sep 11, 2012 at 7:38 AM
Edited Sep 11, 2012 at 11:37 AM

Hi,

 

OK. I will see what I can find out. Fortunately one of my colleagues at work is Markus Friedl (OpenSSH developer). So I will ask him how decryption of the private keys works.

Sep 12, 2012 at 9:12 AM

Incidentally, if you stumble upon any implementations of DER/BER and related family members, could you let me know?

Sep 15, 2012 at 9:30 AM

Here is my diff which encrypts AES128:
diff --git a/Renci.SshNet/PrivateKeyFile.cs b/Renci.SshNet/PrivateKeyFile.cs
index 1caf89a..c3bb040 100644
--- a/Renci.SshNet/PrivateKeyFile.cs
+++ b/Renci.SshNet/PrivateKeyFile.cs
@@ -121,7 +121,7 @@ namespace Renci.SshNet
 
             var binaryData = System.Convert.FromBase64String(data);
 
-            byte[] decryptedData;
+            byte[] decryptedData = null;
 
             if (!string.IsNullOrEmpty(cipherName) && !string.IsNullOrEmpty(salt))
             {
@@ -145,9 +145,36 @@ namespace Renci.SshNet
                         cipher = new CipherInfo(64, (key, iv) => { return new DesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); });
                         break;
                     //  TODO:   Implement more private key ciphers
-                    //case "AES-128-CBC":
+                    case "AES-128-CBC":
                     //    cipher = new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); });
-                    //    break;
+                        MD5 md5 = MD5.Create();
+
+                        byte[] password = Encoding.UTF8.GetBytes(passPhrase);
+
+                        byte[] mysalt = new byte[8];
+                        Buffer.BlockCopy(binarySalt, 0, mysalt, 0, 8);
+
+                        int preKeyLength = password.Length + mysalt.Length;
+                        byte[] preKey = new byte[preKeyLength];
+                        Buffer.BlockCopy(password, 0, preKey, 0, password.Length);
+                        Buffer.BlockCopy(mysalt, 0, preKey, password.Length, 8); // get first 8 bytes of iv
+                        byte[] mykey = md5.ComputeHash(preKey);
+
+                        md5.Clear();
+                        md5 = null;
+
+                        RijndaelManaged aes128 = new RijndaelManaged();
+                        aes128.Mode = System.Security.Cryptography.CipherMode.CBC;
+                        aes128.Padding = PaddingMode.PKCS7;
+                        aes128.KeySize = 128;
+                        aes128.BlockSize = 128;
+                        aes128.Key = mykey;
+                        aes128.IV = binarySalt;
+
+                        ICryptoTransform rijndaelDecryptor = aes128.CreateDecryptor();
+
+                        decryptedData = rijndaelDecryptor.TransformFinalBlock(binaryData, 0, binaryData.Length);
+                        break;
                     //case "AES-192-CBC":
                     //    cipher = new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS5Padding()); });
                     //    break;
@@ -157,8 +184,10 @@ namespace Renci.SshNet
                     default:
                         throw new SshException(string.Format(CultureInfo.CurrentCulture, "Private key cipher \"{0}\" is not supported.", cipherName));
                 }
-
-                decryptedData = DecryptKey(cipher, binaryData, passPhrase, binarySalt);
+                if (decryptedData == null)
+                {
+                    decryptedData = DecryptKey(cipher, binaryData, passPhrase, binarySalt);
+                }
             }
             else
             {

Since I'm no crypto-guru I use the System-Crypto libs.

Sep 15, 2012 at 9:38 AM

Commit on github is here:

https://github.com/darinkes/Renci.SshClient/commit/d1299020b8398866baa504dcd191e83d7edc7490

Oct 20, 2012 at 12:32 AM

Any chance of this being committed to the main code repo any time soon?

Coordinator
Dec 19, 2012 at 2:58 PM

Hi,

 

Sorry for delay in my responses, was very busy with other project and only now have some down time to look and fix some issues as I can.

 

I just added suport for all AES key encryption, please take a look and let me know if it works for you.

 

Thanks,

Oleg

Dec 19, 2012 at 5:35 PM

Awesome! Thanks! :)

Will test it ASAP

Aug 28, 2014 at 6:48 PM
Edited Aug 28, 2014 at 7:45 PM
Hello,

I am still getting similar error "DER length is '43' and cannot be more than 4 bytes." using the latest release 2014.4.6-beta1 . Is there a fix for this or is AES still not supported?


----------------------------UPDATE------------------------------
In case anyone ever comes across this in the future, my issue turned out to be an invalid passPhrase.