From b20150456ec9643e7eeb4a1f824959e3be576bb7 Mon Sep 17 00:00:00 2001 From: olegkap_cp Date: Thu, 11 Aug 2011 02:01:18 +0000 Subject: [PATCH] Refactor and reorganize cipher encryption (more need to be done) Add padding for private key DES-EDE3-CBC, DES-EDE3-CFB and others encryption/decryption Add internally implemented DSA digital signature Change encruption and hash algorithm definition in ConnectionInfo from Type to Lambda expression --- .../Renci.SshNet.Tests/Security/TestCipher.cs | 20 +- .../Renci.SshNet.Tests/Security/TestHMac.cs | 5 +- Renci.SshClient/Renci.SshNet.sln | 44 +- Renci.SshClient/Renci.SshNet.vsmdi | 44 - Renci.SshClient/Renci.SshNet/CipherInfo.cs | 38 + .../Renci.SshNet/Common/DerData.cs | 216 +++ .../Renci.SshNet/ConnectionInfo.cs | 64 +- .../ChannelRequest/EndOfWriteRequestInfo.cs | 3 + .../Renci.SshNet/PrivateKeyFile.cs | 29 +- .../Renci.SshNet/Renci.SshNet.csproj | 93 +- .../Security/CryptoPrivateKeyDss.cs | 36 +- .../Security/CryptoPrivateKeyRsa.cs | 3 +- .../Security/CryptoPublicKeyDss.cs | 70 +- .../Security/CryptoPublicKeyRsa.cs | 5 +- .../Security/Cryptography/AsymmetricCipher.cs | 18 +- .../Security/Cryptography/BlockCipher.cs | 129 ++ .../Security/Cryptography/Cipher.cs | 239 +++ .../Cryptography/CipherDigitalSignature.cs | 124 ++ .../Cryptography/Ciphers/AesCipher.cs | 366 ++--- .../Cryptography/Ciphers/Arc4Cipher.cs | 87 ++ .../Cryptography/Ciphers/BlowfishCipher.cs | 372 +++-- .../Cryptography/Ciphers/CastCipher.cs | 313 ++-- .../Cryptography/Ciphers/CipherMode.cs | 68 + .../Cryptography/Ciphers/CipherPadding.cs | 21 + .../Cryptography/Ciphers/DesCipher.cs | 100 +- .../Modes/CbcCipherMode.cs} | 71 +- .../Modes/CfbCipherMode.cs} | 71 +- .../Modes/CtrCipherMode.cs} | 72 +- .../Modes/OfbCipherMode.cs} | 72 +- .../Ciphers/Paddings/PKCS7Padding.cs | 33 + .../Cryptography/Ciphers/RsaCipher.cs | 140 ++ .../Cryptography/Ciphers/SerpentCipher.cs | 1290 +++++++++-------- .../Cryptography/Ciphers/TripleDesCipher.cs | 30 +- .../Cryptography/Ciphers/TwofishCipher.cs | 68 +- .../Cryptography/DsaDigitalSignature.cs | 145 ++ .../Security/Cryptography/HMAC.cs | 4 +- .../Security/Cryptography/Hashes/MD5Hash.cs | 383 +++++ .../Security/Cryptography/Hashes/SHA1Hash.cs | 382 +++++ .../Cryptography/Hashes/SHA256Hash.cs | 389 +++++ .../Cryptography/Modes/CipherModeEx.cs | 70 - .../Security/Cryptography/Modes/ModeBase.cs | 28 - .../Cryptography/RsaDigitalSignature.cs | 42 + .../Security/Cryptography/StreamCipher.cs | 22 + .../Security/Cryptography/SymmetricCipher.cs | 72 + .../Renci.SshNet/Security/KeyExchange.cs | 58 +- Renci.SshClient/Renci.SshNet/Session.cs | 10 +- 46 files changed, 4227 insertions(+), 1732 deletions(-) delete mode 100644 Renci.SshClient/Renci.SshNet.vsmdi create mode 100644 Renci.SshClient/Renci.SshNet/CipherInfo.cs create mode 100644 Renci.SshClient/Renci.SshNet/Common/DerData.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/BlockCipher.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Cipher.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/CipherMode.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/CipherPadding.cs rename Renci.SshClient/Renci.SshNet/Security/Cryptography/{Modes/CbcMode.cs => Ciphers/Modes/CbcCipherMode.cs} (55%) rename Renci.SshClient/Renci.SshNet/Security/Cryptography/{Modes/OfbMode.cs => Ciphers/Modes/CfbCipherMode.cs} (56%) rename Renci.SshClient/Renci.SshNet/Security/Cryptography/{Modes/CfbMode.cs => Ciphers/Modes/CtrCipherMode.cs} (55%) rename Renci.SshClient/Renci.SshNet/Security/Cryptography/{Modes/CtrMode.cs => Ciphers/Modes/OfbCipherMode.cs} (59%) create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/MD5Hash.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA1Hash.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Hashes/SHA256Hash.cs delete mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Modes/CipherModeEx.cs delete mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/Modes/ModeBase.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/StreamCipher.cs create mode 100644 Renci.SshClient/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs diff --git a/Renci.SshClient/Renci.SshNet.Tests/Security/TestCipher.cs b/Renci.SshClient/Renci.SshNet.Tests/Security/TestCipher.cs index 3c0fd055..abd804d8 100644 --- a/Renci.SshClient/Renci.SshNet.Tests/Security/TestCipher.cs +++ b/Renci.SshClient/Renci.SshNet.Tests/Security/TestCipher.cs @@ -5,6 +5,8 @@ using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Security; using Renci.SshNet.Tests.Properties; +using Renci.SshNet.Security.Cryptography.Ciphers; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; namespace Renci.SshNet.Tests.Security { @@ -16,7 +18,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("3des-cbc", typeof(CipherTripleDes192Cbc)); + connectionInfo.Encryptions.Add("3des-cbc", new CipherInfo(192, (key, iv) => { return new TripleDesCipher(key, new CbcCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { @@ -30,7 +32,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes128-cbc", typeof(CipherAes128Cbc)); + connectionInfo.Encryptions.Add("aes128-cbc", new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { @@ -44,7 +46,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes192-cbc", typeof(CipherAes192Cbc)); + connectionInfo.Encryptions.Add("aes192-cbc", new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { @@ -58,7 +60,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes256-cbc", typeof(CipherAes256Cbc)); + connectionInfo.Encryptions.Add("aes256-cbc", new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { @@ -72,7 +74,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes128-ctr", typeof(CipherAes128Ctr)); + connectionInfo.Encryptions.Add("aes128-ctr", new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { @@ -86,7 +88,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes192-ctr", typeof(CipherAes192Ctr)); + connectionInfo.Encryptions.Add("aes192-ctr", new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { @@ -100,7 +102,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes256-ctr", typeof(CipherAes256Ctr)); + connectionInfo.Encryptions.Add("aes256-ctr", new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { @@ -114,7 +116,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("blowfish-cbc", typeof(CipherBlowfish)); + connectionInfo.Encryptions.Add("blowfish-cbc", new CipherInfo(128, (key, iv) => { return new BlowfishCipher(key, new CbcCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { @@ -128,7 +130,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("cast128-cbc", typeof(CipherCast128Cbc)); + connectionInfo.Encryptions.Add("cast128-cbc", new CipherInfo(128, (key, iv) => { return new CastCipher(key, new CbcCipherMode(iv), null); })); using (var client = new SshClient(connectionInfo)) { diff --git a/Renci.SshClient/Renci.SshNet.Tests/Security/TestHMac.cs b/Renci.SshClient/Renci.SshNet.Tests/Security/TestHMac.cs index f063e4d1..4c772967 100644 --- a/Renci.SshClient/Renci.SshNet.Tests/Security/TestHMac.cs +++ b/Renci.SshClient/Renci.SshNet.Tests/Security/TestHMac.cs @@ -5,6 +5,7 @@ using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Security; using Renci.SshNet.Tests.Properties; +using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet.Tests.Security { @@ -16,7 +17,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-md5", typeof(HMacMD5)); + connectionInfo.HmacAlgorithms.Add("hmac-md5", (key) => { return new HMac(key.Take(16).ToArray());}); using (var client = new SshClient(connectionInfo)) { @@ -30,7 +31,7 @@ namespace Renci.SshNet.Tests.Security { var connectionInfo = new PasswordConnectionInfo(Resources.HOST, 22, Resources.USERNAME, Resources.PASSWORD); connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-sha1", typeof(HMacSha1)); + connectionInfo.HmacAlgorithms.Add("hmac-sha1", (key) => { return new HMac(key.Take(20).ToArray()); }); using (var client = new SshClient(connectionInfo)) { diff --git a/Renci.SshClient/Renci.SshNet.sln b/Renci.SshClient/Renci.SshNet.sln index d5c64581..7b0902c0 100644 --- a/Renci.SshClient/Renci.SshNet.sln +++ b/Renci.SshClient/Renci.SshNet.sln @@ -4,15 +4,18 @@ Microsoft Visual Studio Solution File, Format Version 11.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet", "Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A3063E62-89D5-43FF-AB1A-FFBECB4A1850}" - ProjectSection(SolutionItems) = preProject - Renci.SshNet.vsmdi = Renci.SshNet.vsmdi - EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Tests", "Renci.SshNet.Tests\Renci.SshNet.Tests.csproj", "{C45379B9-17B1-4E89-BC2E-6D41726413E8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{EFAF2072-A01F-4970-878A-AAD40326AFD2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Silverlight", "Renci.SshNet.Silverlight\Renci.SshNet.Silverlight.csproj", "{77C294BB-1DC2-49DC-BE16-963F8F22794D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.Web", "Test.Web\Test.Web.csproj", "{1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}" +EndProject Global GlobalSection(TeamFoundationVersionControl) = preSolution - SccNumberOfProjects = 3 + SccNumberOfProjects = 4 SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs11 SccLocalPath0 = . @@ -22,6 +25,9 @@ Global SccProjectUniqueName2 = Renci.SshNet.Tests\\Renci.SshNet.Tests.csproj SccProjectName2 = Renci.SshNet.Tests SccLocalPath2 = Renci.SshNet.Tests + SccProjectUniqueName3 = Renci.SshNet.Silverlight\\Renci.SshNet.Silverlight.csproj + SccProjectName3 = Renci.SshNet.Silverlight + SccLocalPath3 = Renci.SshNet.Silverlight EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = Renci.SshNet.vsmdi @@ -55,6 +61,36 @@ Global {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Debug|Any CPU.ActiveCfg = Debug|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Debug|x86.ActiveCfg = Debug|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Debug|x86.Build.0 = Debug|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Release|Any CPU.ActiveCfg = Release|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Release|Mixed Platforms.Build.0 = Release|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Release|x86.ActiveCfg = Release|x86 + {EFAF2072-A01F-4970-878A-AAD40326AFD2}.Release|x86.Build.0 = Release|x86 + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|x86.ActiveCfg = Debug|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Any CPU.Build.0 = Release|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|x86.ActiveCfg = Release|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Debug|x86.ActiveCfg = Debug|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Release|Any CPU.Build.0 = Release|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {1A1BAB9E-0DAD-4171-A979-6F2F221E3C28}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Renci.SshClient/Renci.SshNet.vsmdi b/Renci.SshClient/Renci.SshNet.vsmdi deleted file mode 100644 index 366af5eb..00000000 --- a/Renci.SshClient/Renci.SshNet.vsmdi +++ /dev/null @@ -1,44 +0,0 @@ - - - - Tests that affect SftpClient. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Renci.SshClient/Renci.SshNet/CipherInfo.cs b/Renci.SshClient/Renci.SshNet/CipherInfo.cs new file mode 100644 index 00000000..2d00348f --- /dev/null +++ b/Renci.SshClient/Renci.SshNet/CipherInfo.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Renci.SshNet.Security.Cryptography; + +namespace Renci.SshNet +{ + /// + /// Holds information about key size and cipher to use + /// + public class CipherInfo + { + /// + /// Gets the size of the key. + /// + /// + /// The size of the key. + /// + public int KeySize { get; private set; } + + /// + /// Gets the cipher. + /// + public Func Cipher { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// Size of the key. + /// The cipher. + public CipherInfo(int keySize, Func cipher) + { + this.KeySize = keySize; + this.Cipher = (key, iv) => (cipher(key.Take(this.KeySize / 8).ToArray(), iv)); + } + } +} diff --git a/Renci.SshClient/Renci.SshNet/Common/DerData.cs b/Renci.SshClient/Renci.SshNet/Common/DerData.cs new file mode 100644 index 00000000..7f2392ab --- /dev/null +++ b/Renci.SshClient/Renci.SshNet/Common/DerData.cs @@ -0,0 +1,216 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Renci.SshNet.Common +{ + /// + /// Base class for DER encoded data. + /// + public abstract class DerData + { + private const byte CONSTRUCTED = 0x20; + + private const byte BOOLEAN = 0x01; + private const byte INTEGER = 0x02; + private const byte BITSTRING = 0x03; + private const byte OCTETSTRING = 0x04; + private const byte NULL = 0x05; + private const byte OBJECTIDENTIFIER = 0x06; + private const byte EXTERNAL = 0x08; + private const byte ENUMERATED = 0x0a; + private const byte SEQUENCE = 0x10; + private const byte SEQUENCEOF = 0x10; // for completeness + private const byte SET = 0x11; + private const byte SETOF = 0x11; // for completeness + + private const byte NUMERICSTRING = 0x12; + private const byte PRINTABLESTRING = 0x13; + private const byte T61STRING = 0x14; + private const byte VIDEOTEXSTRING = 0x15; + private const byte IA5STRING = 0x16; + private const byte UTCTIME = 0x17; + private const byte GENERALIZEDTIME = 0x18; + private const byte GRAPHICSTRING = 0x19; + private const byte VISIBLESTRING = 0x1a; + private const byte GENERALSTRING = 0x1b; + private const byte UNIVERSALSTRING = 0x1c; + private const byte BMPSTRING = 0x1e; + private const byte UTF8STRING = 0x0c; + private const byte APPLICATION = 0x40; + private const byte TAGGED = 0x80; + + private List _data; + + private int _readerIndex = 0; + + public byte[] Encode() + { + this._data = new List(); + + this.SaveData(); + + var length = this._data.Count(); + var lengthBytes = this.GetLength(length); + + this._data.InsertRange(0, lengthBytes); + this._data.Insert(0, CONSTRUCTED | SEQUENCE); + + return this._data.ToArray(); + } + + public void Decode(byte[] data) + { + this._data = new List(data); + this._readerIndex = 0; + var dataType = this.ReadByte(); + var length = this.ReadLength(); + + this.LoadData(); + } + + /// + /// Called when type specific data need to be loaded. + /// + protected abstract void LoadData(); + + /// + /// Called when type specific data need to be saved. + /// + protected abstract void SaveData(); + + /// + /// Reads next mpint data type from internal buffer. + /// + /// mpint read. + protected BigInteger ReadBigInt() + { + var type = this.ReadByte(); + if (type != INTEGER) + throw new InvalidOperationException("Invalid data type, INTEGER(02) is expected."); + + var length = this.ReadLength(); + + var data = this.ReadBytes(length); + + return new BigInteger(data.Reverse().ToArray()); + } + + /// + /// Writes uint32 data into internal buffer. + /// + /// uint32 data to write. + protected void Write(UInt32 data) + { + var bytes = data.GetBytes(); + this._data.Add(INTEGER); + var length = this.GetLength(bytes.Length); + this.WriteBytes(length); + this.WriteBytes(bytes); + } + + protected void Write(BigInteger data) + { + var bytes = data.ToByteArray().Reverse().ToList(); + this._data.Add(INTEGER); + var length = this.GetLength(bytes.Count); + this.WriteBytes(length); + this.WriteBytes(bytes); + } + + protected void Write(DerData data) + { + throw new NotImplementedException(); + } + + private byte[] GetLength(int length) + { + if (length > 127) + { + int size = 1; + int val = length; + + while ((val >>= 8) != 0) + size++; + + var data = new byte[size]; + data[0] = (byte)(size | 0x80); + + for (int i = (size - 1) * 8, j = 1; i >= 0; i -= 8, j++) + { + data[j] = (byte)(length >> i); + } + + return data; + } + else + { + return new byte[] { (byte)length }; + } + } + + private int ReadLength() + { + int length = this.ReadByte(); + + if (length == 0x80) + { + throw new NotSupportedException("Indefinite-length encoding is not supported."); + } + + if (length > 127) + { + int size = length & 0x7f; + + // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here + if (size > 4) + throw new InvalidOperationException(string.Format("DER length is '{0}' and cannot be more than 4 bytes.", size)); + + length = 0; + for (int i = 0; i < size; i++) + { + int next = this.ReadByte(); + + length = (length << 8) + next; + } + + if (length < 0) + throw new InvalidOperationException("Corrupted data - negative length found"); + + //if (length >= limit) // after all we must have read at least 1 byte + // throw new IOException("Corrupted stream - out of bounds length found"); + } + + return length; + } + + private void WriteBytes(IEnumerable data) + { + this._data.AddRange(data); + } + + private byte ReadByte() + { + if (this._readerIndex > this._data.Count) + throw new InvalidOperationException("Read out of boundaries."); + + return this._data[this._readerIndex++]; + } + + private byte[] ReadBytes(int length) + { + if (this._readerIndex + length > this._data.Count) + throw new InvalidOperationException("Read out of boundaries."); + + var result = new byte[length]; + this._data.CopyTo(this._readerIndex, result, 0, length); + this._readerIndex += length; + return result; + } + + + + + } +} diff --git a/Renci.SshClient/Renci.SshNet/ConnectionInfo.cs b/Renci.SshClient/Renci.SshNet/ConnectionInfo.cs index 61caefdb..017c2274 100644 --- a/Renci.SshClient/Renci.SshNet/ConnectionInfo.cs +++ b/Renci.SshClient/Renci.SshNet/ConnectionInfo.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Renci.SshNet.Security; @@ -9,10 +10,14 @@ using Renci.SshNet.Common; using System.Threading; using System.Net; using Renci.SshNet.Messages.Connection; +using Renci.SshNet.Security.Cryptography.Ciphers; +using System.Security.Cryptography; +using Renci.SshNet.Security.Cryptography; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; namespace Renci.SshNet { /// - /// Represents remote connection infroamtion base class. + /// Represents remote connection information base class. /// public abstract class ConnectionInfo { @@ -47,12 +52,12 @@ namespace Renci.SshNet /// /// Gets supported encryptions for this connection. /// - public IDictionary Encryptions { get; private set; } + public IDictionary Encryptions { get; private set; } /// /// Gets supported hash algorithms for this connection. /// - public IDictionary HmacAlgorithms { get; private set; } + public IDictionary> HmacAlgorithms { get; private set; } /// /// Gets supported host key algorithms for this connection. @@ -136,35 +141,35 @@ namespace Renci.SshNet {"diffie-hellman-group1-sha1", typeof(KeyExchangeDiffieHellmanGroup1Sha1)}, }; - this.Encryptions = new Dictionary() + this.Encryptions = new Dictionary() { - {"3des-cbc", typeof(CipherTripleDes192Cbc)}, - {"aes128-cbc", typeof(CipherAes128Cbc)}, - {"aes192-cbc", typeof(CipherAes192Cbc)}, - {"aes256-cbc", typeof(CipherAes256Cbc)}, - {"blowfish-cbc", typeof(CipherBlowfish)}, - //{"twofish-cbc", typeof(...)}, - //{"twofish192-cbc", typeof(...)}, - //{"twofish128-cbc", typeof(...)}, - //{"twofish256-cbc", typeof(...)}, - //{"serpent256-cbc", typeof(CipherSerpent256CBC)}, - //{"serpent192-cbc", typeof(...)}, - //{"serpent128-cbc", typeof(...)}, - //{"arcfour128", typeof(...)}, - //{"arcfour256", typeof(...)}, - //{"arcfour", typeof(...)}, - //{"idea-cbc", typeof(...)}, - {"cast128-cbc", typeof(CipherCast128Cbc)}, - //{"rijndael-cbc@lysator.liu.se", typeof(...)}, - {"aes128-ctr", typeof(CipherAes128Ctr)}, - {"aes192-ctr", typeof(CipherAes192Ctr)}, - {"aes256-ctr", typeof(CipherAes256Ctr)}, + {"3des-cbc", new CipherInfo(192, (key, iv)=>{ return new TripleDesCipher(key, new CbcCipherMode(iv), null); }) }, + {"aes128-cbc", new CipherInfo(128, (key, iv)=>{ return new AesCipher(key, new CbcCipherMode(iv), null); }) }, + {"aes192-cbc", new CipherInfo(192, (key, iv)=>{ return new AesCipher(key, new CbcCipherMode(iv), null); }) }, + {"aes256-cbc", new CipherInfo(256, (key, iv)=>{ return new AesCipher(key, new CbcCipherMode(iv), null); }) }, + {"blowfish-cbc", new CipherInfo(128, (key, iv)=>{ return new BlowfishCipher(key, new CbcCipherMode(iv), null); }) }, + ////{"twofish-cbc", typeof(...)}, + ////{"twofish192-cbc", typeof(...)}, + ////{"twofish128-cbc", typeof(...)}, + ////{"twofish256-cbc", typeof(...)}, + ////{"serpent256-cbc", typeof(CipherSerpent256CBC)}, + ////{"serpent192-cbc", typeof(...)}, + ////{"serpent128-cbc", typeof(...)}, + ////{"arcfour128", typeof(...)}, + ////{"arcfour256", typeof(...)}, + ////{"arcfour", typeof(...)}, + ////{"idea-cbc", typeof(...)}, + {"cast128-cbc", new CipherInfo(128, (key, iv)=>{ return new CastCipher(key, new CbcCipherMode(iv), null); }) }, + ////{"rijndael-cbc@lysator.liu.se", typeof(...)}, + {"aes128-ctr", new CipherInfo(128, (key, iv)=>{ return new AesCipher(key, new CtrCipherMode(iv), null); }) }, + {"aes192-ctr", new CipherInfo(192, (key, iv)=>{ return new AesCipher(key, new CtrCipherMode(iv), null); }) }, + {"aes256-ctr", new CipherInfo(256, (key, iv)=>{ return new AesCipher(key, new CtrCipherMode(iv), null); }) }, }; - this.HmacAlgorithms = new Dictionary() + this.HmacAlgorithms = new Dictionary>() { - {"hmac-md5", typeof(HMacMD5)}, - {"hmac-sha1", typeof(HMacSha1)}, + {"hmac-md5", (key) => { return new HMac(key.Take(16).ToArray());}}, + {"hmac-sha1", (key) => { return new HMac(key.Take(20).ToArray());}}, //{"umac-64@openssh.com", typeof(HMacSha1)}, //{"hmac-ripemd160", typeof(HMacSha1)}, //{"hmac-ripemd160@openssh.com", typeof(HMacSha1)}, @@ -176,10 +181,7 @@ namespace Renci.SshNet this.HostKeyAlgorithms = new Dictionary() { {"ssh-rsa", typeof(CryptoPublicKeyRsa)}, -#if SILVERLIGHT -#else {"ssh-dss", typeof(CryptoPublicKeyDss)}, -#endif }; this.AuthenticationMethods = new Dictionary() diff --git a/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs b/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs index 5ef73c00..c40d9301 100644 --- a/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs +++ b/Renci.SshClient/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs @@ -5,6 +5,9 @@ using System.Text; namespace Renci.SshNet.Messages.Connection { + /// + /// Represents "eow@openssh.com" type channel request information + /// public class EndOfWriteRequestInfo : RequestInfo { /// diff --git a/Renci.SshClient/Renci.SshNet/PrivateKeyFile.cs b/Renci.SshClient/Renci.SshNet/PrivateKeyFile.cs index 6ecbee6c..9c271272 100644 --- a/Renci.SshClient/Renci.SshNet/PrivateKeyFile.cs +++ b/Renci.SshClient/Renci.SshNet/PrivateKeyFile.cs @@ -10,6 +10,9 @@ using System.Security; using Renci.SshNet.Common; using System.Globalization; using Renci.SshNet.Security.Cryptography; +using Renci.SshNet.Security.Cryptography.Ciphers; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; +using Renci.SshNet.Security.Cryptography.Ciphers.Paddings; namespace Renci.SshNet { @@ -152,27 +155,30 @@ namespace Renci.SshNet for (int i = 0; i < binarySalt.Length; i++) binarySalt[i] = Convert.ToByte(salt.Substring(i * 2, 2), 16); - Cipher cipher = null; + CipherInfo cipher = null; switch (cipherName) { case "DES-EDE3-CBC": - cipher = new CipherTripleDes192Cbc(); + cipher = new CipherInfo(192, (key, iv) => { return new TripleDesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); }); + break; + case "DES-EDE3-CFB": + cipher = new CipherInfo(192, (key, iv) => { return new TripleDesCipher(key, new CfbCipherMode(iv), new PKCS7Padding()); }); break; case "DES-CBC": // TODO: Not tested - cipher = new CipherDes64Cbc(); + cipher = new CipherInfo(64, (key, iv) => { return new DesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); }); break; case "AES-128-CBC": // TODO: Not tested - cipher = new CipherAes128Cbc(); + cipher = new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); }); break; case "AES-192-CBC": // TODO: Not tested - cipher = new CipherAes192Cbc(); + cipher = new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); }); break; case "AES-256-CBC": // TODO: Not tested - cipher = new CipherAes256Cbc(); + cipher = new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); }); break; default: throw new SshException(string.Format(CultureInfo.CurrentCulture, "Unknown private key cipher \"{0}\".", cipherName)); @@ -190,12 +196,9 @@ namespace Renci.SshNet case "RSA": this._key = new CryptoPrivateKeyRsa(); break; -#if SILVERLIGHT -#else case "DSA": this._key = new CryptoPrivateKeyDss(); break; -#endif default: throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Key '{0}' is not supported.", keyName)); } @@ -206,12 +209,12 @@ namespace Renci.SshNet /// /// Decrypts encrypted private key file data. /// - /// Encryption cipher. + /// The cipher info. /// Encrypted data. /// Decryption pass phrase. /// Decryption binary salt. /// - public static IEnumerable DecryptKey(Cipher cipher, byte[] cipherData, string passPhrase, byte[] binarySalt) + public static IEnumerable DecryptKey(CipherInfo cipherInfo, byte[] cipherData, string passPhrase, byte[] binarySalt) { List cipherKey = new List(); @@ -225,7 +228,7 @@ namespace Renci.SshNet cipherKey.AddRange(hash); - while (cipherKey.Count < cipher.KeySize / 8) + while (cipherKey.Count < cipherInfo.KeySize / 8) { hash = hash.Concat(initVector); @@ -235,7 +238,7 @@ namespace Renci.SshNet } } - cipher.Init(cipherKey, binarySalt); + var cipher = cipherInfo.Cipher(cipherKey.ToArray(), binarySalt); return cipher.Decrypt(cipherData); } diff --git a/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj b/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj index ee69304e..8dffb084 100644 --- a/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj +++ b/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj @@ -64,6 +64,7 @@ + Code @@ -81,6 +82,7 @@ + Code @@ -108,58 +110,45 @@ Code - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - + + + + + + + + + + + + + + + + + + + + + + + Code - + Code - + Code - + Code - + Code - - Code - - - Code - - - Code - - + Code @@ -183,13 +172,6 @@ Code - - Code - - - Code - - Code @@ -238,20 +220,6 @@ - - - - - - - - - - - - - - Code @@ -411,6 +379,7 @@ +