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
This commit is contained in:
olegkap_cp
2011-08-11 02:01:18 +00:00
parent 033218647f
commit b20150456e
46 changed files with 4227 additions and 1732 deletions
@@ -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))
{
@@ -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<MD5Hash>(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<SHA1Hash>(key.Take(20).ToArray()); });
using (var client = new SshClient(connectionInfo))
{
+40 -4
View File
@@ -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
-44
View File
@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<TestList name="SftpClient" id="1405242d-fd39-46f3-88aa-a561b16d9136" parentListId="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<Description>Tests that affect SftpClient.</Description>
<TestLinks>
<TestLink id="cea8b905-fcf5-11e0-972a-3b87e3b06d10" name="Test_Sftp_DeleteDirectory_Without_Connecting" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="86b4e210-a8c7-86d0-9b57-acd5d0060acb" name="Test_Sftp_CreateDirectory_Without_Connecting" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="aa7f3916-bb55-a71b-d160-15c09fd64091" name="Test_Sftp_BeginDownloadFile_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="7c8b8c07-1c12-c2f3-fa49-520c689784e8" name="Test_Sftp_ListDirectory_Current" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="d8cbe94f-d682-20ba-659f-a9c8986ae22d" name="Test_Sftp_ListDirectory_Permission_Denied" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="8887787c-1395-1d98-842b-4a8c85efd0fa" name="Test_Sftp_ChangeDirectory_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="ce1e9ed2-2cf4-e43a-54e0-54c6eda70e9b" name="Test_Sftp_DeleteDirectory_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="5a37e1ff-2ba3-e44c-6850-b939ace9d25a" name="Test_Sftp_RenameFile_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="ff23463d-d5d3-46bd-c184-e53689e9ef5d" name="Test_Sftp_DeleteDirectory" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="293683f6-5b0a-9c36-3360-95836ac13e3e" name="Test_Sftp_Rename_File" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="af3b3194-bfb2-9b70-efa0-27c4a025dd31" name="Test_Sftp_ListDirectory_Not_Exists" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="73191d59-b774-74ef-7cdd-feab7acd6ed5" name="Test_Sftp_CreateDirectory_Already_Exists" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="e449ea7e-c991-cced-0a0e-dbb7043b0555" name="Test_Sftp_CreateDirectory_In_Current_Location" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="dde422f9-1b3b-0885-224c-b2c1a67b82dc" name="Test_Sftp_Upload_Forbidden" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="1bd90317-f6bc-efef-7d89-bec673a74c2e" name="Test_Sftp_CreateDirectory_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="7ff3a089-3ed8-8531-8278-6044b9992b80" name="Test_Sftp_Download_Forbidden" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="842c8c3f-9ebf-2949-64e4-e118d925d64e" name="Test_Get_Root_Directory" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="d0f2ec5e-3aa1-2c25-4bcb-b7378f0d0283" name="Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="5e6b8258-8ab1-4d79-15bf-b5267cbb85ac" name="Test_Sftp_ListDirectory_Empty" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="ae8ea5fd-f0ba-9da5-2cdc-e0f47f3d5409" name="Test_Sftp_ListDirectory_HugeDirectory" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="aeeee14f-a9f7-aaeb-dca0-0f71f5d24bc1" name="Test_Sftp_Upload_And_Download_1MB_File" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="7ee25cf7-b1fe-f444-6d0f-7e9cd472fcae" name="Test_Sftp_ListDirectory_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="767acb2f-2b0c-2227-05ef-22178c779a33" name="Test_Sftp_Change_Directory" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="d8eea890-99df-9b9f-7083-3a306dd65565" name="Test_Sftp_CreateDirectory_Invalid_Path" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="1f0eddc0-c2b2-0aba-21ca-313cf8f09aa1" name="Test_Get_File" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="ef88ac59-64c7-8ccf-47bd-f882f19c0194" name="Test_Sftp_DeleteFile_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="1cf918a2-a03b-1756-2aa5-bed3122b6f2c" name="Test_Sftp_BeginUploadFile_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="8595c9d0-7153-2141-b96d-b19c6e959b33" name="Test_Sftp_CreateDirectory_In_Forbidden_Directory" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="a2a0b9e4-ae8f-562d-9a9e-e8b999ce0e72" name="Test_Sftp_Ensure_Async_Delegates_Called_For_BeginFileUpload_BeginFileDownload_BeginListDirectory" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="3305f837-8225-85c8-f1e9-c36ad7e38db9" name="Test_Get_Invalid_Directory" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="1cae396c-6e6f-66d2-9f2b-2d35cfb6d8c5" name="Test_Sftp_Download_File_Not_Exists" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="566be3e3-7344-2506-a01e-b2858b86453f" name="Test_Sftp_DeleteDirectory_Which_No_Permissions" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="a3afb0a2-ca8b-d745-4584-8564f70689eb" name="Test_Sftp_DeleteDirectory_Which_Doesnt_Exists" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="69e19f40-2e27-b25b-db00-4f960242a34b" name="Test_Sftp_ListDirectory_Without_Connecting" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<TestLink id="abe06631-df5e-2d93-a0a9-f8e7f62a52b6" name="Test_Get_File_Null" storage="renci.sshnet.tests\bin\debug\renci.sshnet.tests.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</TestLinks>
</TestList>
<TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6" />
</TestLists>
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Renci.SshNet.Security.Cryptography;
namespace Renci.SshNet
{
/// <summary>
/// Holds information about key size and cipher to use
/// </summary>
public class CipherInfo
{
/// <summary>
/// Gets the size of the key.
/// </summary>
/// <value>
/// The size of the key.
/// </value>
public int KeySize { get; private set; }
/// <summary>
/// Gets the cipher.
/// </summary>
public Func<byte[], byte[], BlockCipher> Cipher { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="CipherInfo"/> class.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <param name="cipher">The cipher.</param>
public CipherInfo(int keySize, Func<byte[], byte[], BlockCipher> cipher)
{
this.KeySize = keySize;
this.Cipher = (key, iv) => (cipher(key.Take(this.KeySize / 8).ToArray(), iv));
}
}
}
@@ -0,0 +1,216 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Common
{
/// <summary>
/// Base class for DER encoded data.
/// </summary>
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<byte> _data;
private int _readerIndex = 0;
public byte[] Encode()
{
this._data = new List<byte>();
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<byte>(data);
this._readerIndex = 0;
var dataType = this.ReadByte();
var length = this.ReadLength();
this.LoadData();
}
/// <summary>
/// Called when type specific data need to be loaded.
/// </summary>
protected abstract void LoadData();
/// <summary>
/// Called when type specific data need to be saved.
/// </summary>
protected abstract void SaveData();
/// <summary>
/// Reads next mpint data type from internal buffer.
/// </summary>
/// <returns>mpint read.</returns>
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());
}
/// <summary>
/// Writes uint32 data into internal buffer.
/// </summary>
/// <param name="data">uint32 data to write.</param>
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<byte> 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;
}
}
}
+33 -31
View File
@@ -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
{
/// <summary>
/// Represents remote connection infroamtion base class.
/// Represents remote connection information base class.
/// </summary>
public abstract class ConnectionInfo
{
@@ -47,12 +52,12 @@ namespace Renci.SshNet
/// <summary>
/// Gets supported encryptions for this connection.
/// </summary>
public IDictionary<string, Type> Encryptions { get; private set; }
public IDictionary<string, CipherInfo> Encryptions { get; private set; }
/// <summary>
/// Gets supported hash algorithms for this connection.
/// </summary>
public IDictionary<string, Type> HmacAlgorithms { get; private set; }
public IDictionary<string, Func<byte[], HashAlgorithm>> HmacAlgorithms { get; private set; }
/// <summary>
/// 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<string, Type>()
this.Encryptions = new Dictionary<string, CipherInfo>()
{
{"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<string, Type>()
this.HmacAlgorithms = new Dictionary<string, Func<byte[], HashAlgorithm>>()
{
{"hmac-md5", typeof(HMacMD5)},
{"hmac-sha1", typeof(HMacSha1)},
{"hmac-md5", (key) => { return new HMac<MD5Hash>(key.Take(16).ToArray());}},
{"hmac-sha1", (key) => { return new HMac<SHA1Hash>(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<string, Type>()
{
{"ssh-rsa", typeof(CryptoPublicKeyRsa)},
#if SILVERLIGHT
#else
{"ssh-dss", typeof(CryptoPublicKeyDss)},
#endif
};
this.AuthenticationMethods = new Dictionary<string, Type>()
@@ -5,6 +5,9 @@ using System.Text;
namespace Renci.SshNet.Messages.Connection
{
/// <summary>
/// Represents "eow@openssh.com" type channel request information
/// </summary>
public class EndOfWriteRequestInfo : RequestInfo
{
/// <summary>
+16 -13
View File
@@ -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
/// <summary>
/// Decrypts encrypted private key file data.
/// </summary>
/// <param name="cipher">Encryption cipher.</param>
/// <param name="cipherInfo">The cipher info.</param>
/// <param name="cipherData">Encrypted data.</param>
/// <param name="passPhrase">Decryption pass phrase.</param>
/// <param name="binarySalt">Decryption binary salt.</param>
/// <returns></returns>
public static IEnumerable<byte> DecryptKey(Cipher cipher, byte[] cipherData, string passPhrase, byte[] binarySalt)
public static IEnumerable<byte> DecryptKey(CipherInfo cipherInfo, byte[] cipherData, string passPhrase, byte[] binarySalt)
{
List<byte> cipherKey = new List<byte>();
@@ -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);
}
@@ -64,6 +64,7 @@
<ItemGroup>
<Compile Include="Channels\ChannelDirectTcpip.NET40.cs" />
<Compile Include="Channels\ChannelForwardedTcpip.NET40.cs" />
<Compile Include="CipherInfo.cs" />
<Compile Include="Common\ASCIIEncoding.cs" />
<Compile Include="Common\ASCIIEncoding.NET40.cs">
<SubType>Code</SubType>
@@ -81,6 +82,7 @@
<Compile Include="Common\ChannelEventArgs.cs" />
<Compile Include="Common\ChannelOpenFailedEventArgs.cs" />
<Compile Include="Common\ChannelRequestEventArgs.cs" />
<Compile Include="Common\DerData.cs" />
<Compile Include="Common\SemaphoreLight.cs">
<SubType>Code</SubType>
</Compile>
@@ -108,58 +110,45 @@
<Compile Include="Security\Algorithm.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cipher.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\CipherAesCbc.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\CipherAesCtr.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\CipherBlowfish.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\CipherCastCbc.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\CipherDesCbc.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\CipherSerpent.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\CipherTripleDesCbc.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\AsymmetricCipher.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\CipherDigitalSignature.cs" />
<Compile Include="Security\Cryptography\Ciphers\AesCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\Arc4Cipher.cs" />
<Compile Include="Security\Cryptography\AsymmetricCipher.cs" />
<Compile Include="Security\Cryptography\BlockCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\BlowfishCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\CastCipher.cs" />
<Compile Include="Security\Cryptography\Cipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\CipherMode.cs" />
<Compile Include="Security\Cryptography\Ciphers\CipherPadding.cs" />
<Compile Include="Security\Cryptography\Ciphers\DesCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\Modes\CbcCipherMode.cs" />
<Compile Include="Security\Cryptography\Ciphers\Modes\CfbCipherMode.cs" />
<Compile Include="Security\Cryptography\Ciphers\Modes\CtrCipherMode.cs" />
<Compile Include="Security\Cryptography\Ciphers\Modes\OfbCipherMode.cs" />
<Compile Include="Security\Cryptography\Ciphers\Paddings\PKCS7Padding.cs" />
<Compile Include="Security\Cryptography\Ciphers\RsaCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\SerpentCipher.cs" />
<Compile Include="Security\Cryptography\DsaDigitalSignature.cs" />
<Compile Include="Security\Cryptography\StreamCipher.cs" />
<Compile Include="Security\Cryptography\SymmetricCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\TripleDesCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\TwofishCipher.cs" />
<Compile Include="Security\Cryptography\DigitalSignature.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\HMAC.cs">
<Compile Include="Security\Cryptography\HMac.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\MD5Hash.cs">
<Compile Include="Security\Cryptography\Hashes\MD5Hash.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\RSACipher.cs">
<Compile Include="Security\Cryptography\RsaDigitalSignature.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\RSADigitalSignature.cs">
<Compile Include="Security\Cryptography\Hashes\SHA1Hash.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\RSAPrivateKey.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\RSAPublicKey.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\SHA1Hash.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\Cryptography\SHA256Hash.cs">
<Compile Include="Security\Cryptography\Hashes\SHA256Hash.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\CryptoKey.cs">
@@ -183,13 +172,6 @@
<Compile Include="Security\CryptoPublicKeyRsa.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\HMac.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\HMacMD5.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Security\HMacSha1.cs" />
<Compile Include="Security\KeyExchange.cs">
<SubType>Code</SubType>
</Compile>
@@ -238,20 +220,6 @@
<Compile Include="Messages\Connection\ChannelRequest\XonXoffRequestInfo.cs" />
<Compile Include="Messages\MessageAttribute.cs" />
<Compile Include="NoneConnectionInfo.cs" />
<Compile Include="Security\Cryptography\Ciphers\AesCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\BlowfishCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\CastCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\SerpentCipher.cs" />
<Compile Include="Security\Cryptography\Ciphers\TwofishCipher.cs" />
<Compile Include="Security\Cryptography\Modes\CfbMode.cs" />
<Compile Include="Security\Cryptography\Modes\CipherModeEx.cs" />
<Compile Include="Security\Cryptography\Modes\ModeBase.cs" />
<Compile Include="Security\Cryptography\Modes\CbcMode.cs" />
<Compile Include="Security\Cryptography\Ciphers\CipherBase.cs" />
<Compile Include="Security\Cryptography\Ciphers\TripleDesCipher.cs" />
<Compile Include="Security\Cryptography\Modes\CtrMode.cs" />
<Compile Include="Security\Cryptography\Modes\OfbMode.cs" />
<Compile Include="Security\Cryptography\Ciphers\DesCipher.cs" />
<Compile Include="Sftp\Flags.cs" />
<Compile Include="Sftp\SftpDataMessage.cs">
<SubType>Code</SubType>
@@ -411,6 +379,7 @@
<ItemGroup>
<Content Include="Documentation\SshClient.shfbproj" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
@@ -102,37 +102,13 @@ namespace Renci.SshNet.Security
/// <returns></returns>
public override byte[] GetSignature(IEnumerable<byte> key)
{
var data = key.ToArray();
//using (var sha1 = new Renci.SshNet.Security.Cryptography.SHA1Hash())
using (var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider())
var ss1 = new DsaDigitalSignature(this._p, this._q, this._g, this._privateKey, null);
var signature = ss1.CreateSignature(key.ToArray());
return new SignatureKeyData
{
using (var cs = new System.Security.Cryptography.CryptoStream(System.IO.Stream.Null, sha1, System.Security.Cryptography.CryptoStreamMode.Write))
{
cs.Write(data, 0, data.Length);
}
var dsaKeyInfo = new System.Security.Cryptography.DSAParameters();
dsaKeyInfo.X = this._privateKey.TrimLeadingZero().ToArray();
dsaKeyInfo.P = this._p.TrimLeadingZero().ToArray();
dsaKeyInfo.Q = this._q.TrimLeadingZero().ToArray();
dsaKeyInfo.G = this._g.TrimLeadingZero().ToArray();
using (var DSA = new System.Security.Cryptography.DSACryptoServiceProvider())
{
DSA.ImportParameters(dsaKeyInfo);
var DSAFormatter = new DSASignatureFormatter(DSA);
DSAFormatter.SetHashAlgorithm("SHA1");
var signature = DSAFormatter.CreateSignature(sha1);
return new SignatureKeyData
{
AlgorithmName = this.Name,
Signature = signature,
}.GetBytes().ToArray();
}
}
AlgorithmName = this.Name,
Signature = signature,
}.GetBytes().ToArray();
}
/// <summary>
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
using Renci.SshNet.Security.Cryptography.Ciphers;
namespace Renci.SshNet.Security
{
@@ -113,7 +114,7 @@ namespace Renci.SshNet.Security
/// <returns></returns>
public override byte[] GetSignature(IEnumerable<byte> key)
{
var signature = new RSADigitalSignature(new RSAPrivateKey(this._exponent, this._modulus, this._dValue, this._dpValue, this._qValue, this._dqValue, this._pValue, this._inverseQ));
var signature = new RsaDigitalSignature(this._exponent, this._modulus, this._dValue, this._dpValue, this._dqValue, this._inverseQ, this._pValue, this._qValue);
return new SignatureKeyData
{
@@ -4,13 +4,14 @@ using System.IO;
using System.Linq;
using System.Security.Cryptography;
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
namespace Renci.SshNet.Security
{
/// <summary>
/// Represents DSS public key
/// </summary>
internal class CryptoPublicKeyDss : CryptoPublicKey
public class CryptoPublicKeyDss : CryptoPublicKey
{
private byte[] _p;
private byte[] _q;
@@ -98,55 +99,34 @@ namespace Renci.SshNet.Security
/// </returns>
public override bool VerifySignature(IEnumerable<byte> hash, IEnumerable<byte> signature)
{
using (var sha1 = new SHA1CryptoServiceProvider())
long i = 0;
long j = 0;
byte[] tmp;
var sig = signature.ToArray();
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0)
{
using (var cs = new CryptoStream(System.IO.Stream.Null, sha1, CryptoStreamMode.Write))
{
var data = hash.ToArray();
cs.Write(data, 0, data.Length);
}
long i1 = (sig[i++] << 24) & 0xff000000;
long i2 = (sig[i++] << 16) & 0x00ff0000;
long i3 = (sig[i++] << 8) & 0x0000ff00;
long i4 = (sig[i++]) & 0x000000ff;
j = i1 | i2 | i3 | i4;
using (var dsa = new DSACryptoServiceProvider())
{
dsa.ImportParameters(new DSAParameters
{
Y = _publicKey.TrimLeadingZero().ToArray(),
P = _p.TrimLeadingZero().ToArray(),
Q = _q.TrimLeadingZero().ToArray(),
G = _g.TrimLeadingZero().ToArray(),
});
var dsaDeformatter = new DSASignatureDeformatter(dsa);
dsaDeformatter.SetHashAlgorithm("SHA1");
i += j;
long i = 0;
long j = 0;
byte[] tmp;
i1 = (sig[i++] << 24) & 0xff000000;
i2 = (sig[i++] << 16) & 0x00ff0000;
i3 = (sig[i++] << 8) & 0x0000ff00;
i4 = (sig[i++]) & 0x000000ff;
j = i1 | i2 | i3 | i4;
var sig = signature.ToArray();
if (sig[0] == 0 && sig[1] == 0 && sig[2] == 0)
{
long i1 = (sig[i++] << 24) & 0xff000000;
long i2 = (sig[i++] << 16) & 0x00ff0000;
long i3 = (sig[i++] << 8) & 0x0000ff00;
long i4 = (sig[i++]) & 0x000000ff;
j = i1 | i2 | i3 | i4;
i += j;
i1 = (sig[i++] << 24) & 0xff000000;
i2 = (sig[i++] << 16) & 0x00ff0000;
i3 = (sig[i++] << 8) & 0x0000ff00;
i4 = (sig[i++]) & 0x000000ff;
j = i1 | i2 | i3 | i4;
tmp = new byte[j];
Array.Copy(sig, (int)i, tmp, 0, (int)j);
sig = tmp;
}
return dsaDeformatter.VerifySignature(sha1, sig);
}
tmp = new byte[j];
Array.Copy(sig, (int)i, tmp, 0, (int)j);
sig = tmp;
}
var sig1 = new DsaDigitalSignature(_p, _q, _g, null, _publicKey);
return sig1.VerifySignature(hash.ToArray(), sig);
}
/// <summary>
@@ -5,13 +5,14 @@ using System.Linq;
using System.Security.Cryptography;
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography;
using Renci.SshNet.Security.Cryptography.Ciphers;
namespace Renci.SshNet.Security
{
/// <summary>
/// Represents RSA public key
/// </summary>
internal class CryptoPublicKeyRsa : CryptoPublicKey
public class CryptoPublicKeyRsa : CryptoPublicKey
{
private byte[] _modulus;
@@ -111,7 +112,7 @@ namespace Renci.SshNet.Security
sig = tmp;
}
var sig1 = new RSADigitalSignature(new RSAPublicKey(this._exponent, this._modulus));
var sig1 = new RsaDigitalSignature(this._exponent, this._modulus);
return sig1.VerifySignature(hash.ToArray(), sig);
@@ -2,27 +2,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Renci.SshNet.Common;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Base class for asymmetric cipher implementation
/// Base class for asymmetric cipher implementations.
/// </summary>
public abstract class AsymmetricCipher
public abstract class AsymmetricCipher : Cipher
{
/// <summary>
/// Transforms the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
public abstract byte[] Transform(byte[] input);
/// <summary>
/// Transforms the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
public abstract BigInteger Transform(BigInteger input);
}
}
@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Renci.SshNet.Security.Cryptography.Ciphers;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Base class for block cipher implementations.
/// </summary>
public abstract class BlockCipher : SymmetricCipher
{
private CipherMode _mode;
private CipherPadding _padding;
/// <summary>
/// Gets the size of the block in bytes.
/// </summary>
/// <value>
/// The size of the block in bytes.
/// </value>
public abstract int BlockSize { get; }
/// <summary>
/// Initializes a new instance of the <see cref="BlockCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="mode">Cipher mode.</param>
/// <param name="padding">Cipher padding.</param>
protected BlockCipher(byte[] key, CipherMode mode, CipherPadding padding)
: base(key)
{
this._mode = mode;
this._padding = padding;
this._mode.Init(this);
}
/// <summary>
/// Encrypts the specified data.
/// </summary>
/// <param name="data">The data.</param>
/// <returns>Encrypted data</returns>
public override byte[] Encrypt(byte[] data)
{
var output = new byte[data.Length];
if (data.Length % this.BlockSize > 0)
{
if (this._padding == null)
{
throw new ArgumentException("data");
}
else
{
data = this._padding.Pad(this.BlockSize, data);
}
}
var writtenBytes = 0;
for (int i = 0; i < data.Length / this.BlockSize; i++)
{
if (this._mode == null)
{
writtenBytes += this.EncryptBlock(data, i * this.BlockSize, this.BlockSize, output, i * this.BlockSize);
}
else
{
writtenBytes += this._mode.EncryptBlock(data, i * this.BlockSize, this.BlockSize, output, i * this.BlockSize);
}
}
if (writtenBytes < data.Length)
{
throw new InvalidOperationException("Encryption error.");
}
return output;
}
/// <summary>
/// Decrypts the specified data.
/// </summary>
/// <param name="data">The data.</param>
/// <returns>Decrypted data</returns>
public override byte[] Decrypt(byte[] data)
{
if (data.Length % this.BlockSize > 0)
{
{
if (this._padding == null)
{
throw new ArgumentException("data");
}
else
{
data = this._padding.Pad(this.BlockSize, data);
}
}
}
var output = new byte[data.Length];
var writtenBytes = 0;
for (int i = 0; i < data.Length / this.BlockSize; i++)
{
if (this._mode == null)
{
writtenBytes += this.DecryptBlock(data, i * this.BlockSize, this.BlockSize, output, i * this.BlockSize);
}
else
{
writtenBytes += this._mode.DecryptBlock(data, i * this.BlockSize, this.BlockSize, output, i * this.BlockSize);
}
}
if (writtenBytes < data.Length)
{
throw new InvalidOperationException("Encryption error.");
}
return output;
}
}
}
@@ -0,0 +1,239 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Base class for cipher implementation.
/// </summary>
public abstract class Cipher
{
/// <summary>
/// Encrypts the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
public abstract byte[] Encrypt(byte[] input);
/// <summary>
/// Decrypts the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
public abstract byte[] Decrypt(byte[] input);
#region Packing functions
/// <summary>
/// Populates buffer with big endian number representation.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <param name="buffer">The buffer.</param>
protected static void UInt32ToBigEndian(uint number, byte[] buffer)
{
buffer[0] = (byte)(number >> 24);
buffer[1] = (byte)(number >> 16);
buffer[2] = (byte)(number >> 8);
buffer[3] = (byte)(number);
}
/// <summary>
/// Populates buffer with big endian number representation.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
protected static void UInt32ToBigEndian(uint number, byte[] buffer, int offset)
{
buffer[offset] = (byte)(number >> 24);
buffer[++offset] = (byte)(number >> 16);
buffer[++offset] = (byte)(number >> 8);
buffer[++offset] = (byte)(number);
}
/// <summary>
/// Converts big endian bytes into number.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
protected static uint BigEndianToUInt32(byte[] buffer)
{
uint n = (uint)buffer[0] << 24;
n |= (uint)buffer[1] << 16;
n |= (uint)buffer[2] << 8;
n |= (uint)buffer[3];
return n;
}
/// <summary>
/// Converts big endian bytes into number.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
/// <returns></returns>
protected static uint BigEndianToUInt32(byte[] buffer, int offset)
{
uint n = (uint)buffer[offset] << 24;
n |= (uint)buffer[++offset] << 16;
n |= (uint)buffer[++offset] << 8;
n |= (uint)buffer[++offset];
return n;
}
/// <summary>
/// Converts big endian bytes into number.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
protected static ulong BigEndianToUInt64(byte[] buffer)
{
uint hi = BigEndianToUInt32(buffer);
uint lo = BigEndianToUInt32(buffer, 4);
return ((ulong)hi << 32) | (ulong)lo;
}
/// <summary>
/// Converts big endian bytes into number.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
/// <returns></returns>
protected static ulong BigEndianToUInt64(byte[] buffer, int offset)
{
uint hi = BigEndianToUInt32(buffer, offset);
uint lo = BigEndianToUInt32(buffer, offset + 4);
return ((ulong)hi << 32) | (ulong)lo;
}
/// <summary>
/// Populates buffer with big endian number representation.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <param name="buffer">The buffer.</param>
protected static void UInt64ToBigEndian(ulong number, byte[] buffer)
{
UInt32ToBigEndian((uint)(number >> 32), buffer);
UInt32ToBigEndian((uint)(number), buffer, 4);
}
/// <summary>
/// Populates buffer with big endian number representation.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
protected static void UInt64ToBigEndian(ulong number, byte[] buffer, int offset)
{
UInt32ToBigEndian((uint)(number >> 32), buffer, offset);
UInt32ToBigEndian((uint)(number), buffer, offset + 4);
}
/// <summary>
/// Populates buffer with little endian number representation.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <param name="buffer">The buffer.</param>
protected static void UInt32ToLittleEndian(uint number, byte[] buffer)
{
buffer[0] = (byte)(number);
buffer[1] = (byte)(number >> 8);
buffer[2] = (byte)(number >> 16);
buffer[3] = (byte)(number >> 24);
}
/// <summary>
/// Populates buffer with little endian number representation.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
protected static void UInt32ToLittleEndian(uint number, byte[] buffer, int offset)
{
buffer[offset] = (byte)(number);
buffer[++offset] = (byte)(number >> 8);
buffer[++offset] = (byte)(number >> 16);
buffer[++offset] = (byte)(number >> 24);
}
/// <summary>
/// Converts little endian bytes into number.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
protected static uint LittleEndianToUInt32(byte[] buffer)
{
uint n = (uint)buffer[0];
n |= (uint)buffer[1] << 8;
n |= (uint)buffer[2] << 16;
n |= (uint)buffer[3] << 24;
return n;
}
/// <summary>
/// Converts little endian bytes into number.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
/// <returns></returns>
protected static uint LittleEndianToUInt32(byte[] buffer, int offset)
{
uint n = (uint)buffer[offset];
n |= (uint)buffer[++offset] << 8;
n |= (uint)buffer[++offset] << 16;
n |= (uint)buffer[++offset] << 24;
return n;
}
/// <summary>
/// Converts little endian bytes into number.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <returns></returns>
protected static ulong LittleEndianToUInt64(byte[] buffer)
{
uint lo = LittleEndianToUInt32(buffer);
uint hi = LittleEndianToUInt32(buffer, 4);
return ((ulong)hi << 32) | (ulong)lo;
}
/// <summary>
/// Converts little endian bytes into number.
/// </summary>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
/// <returns></returns>
protected static ulong LittleEndianToUInt64(byte[] buffer, int offset)
{
uint lo = LittleEndianToUInt32(buffer, offset);
uint hi = LittleEndianToUInt32(buffer, offset + 4);
return ((ulong)hi << 32) | (ulong)lo;
}
/// <summary>
/// Populates buffer with little endian number representation.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <param name="buffer">The buffer.</param>
protected static void UInt64ToLittleEndian(ulong number, byte[] buffer)
{
UInt32ToLittleEndian((uint)(number), buffer);
UInt32ToLittleEndian((uint)(number >> 32), buffer, 4);
}
/// <summary>
/// Populates buffer with little endian number representation.
/// </summary>
/// <param name="number">The number to convert.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The buffer offset.</param>
protected static void UInt64ToLittleEndian(ulong number, byte[] buffer, int offset)
{
UInt32ToLittleEndian((uint)(number), buffer, offset);
UInt32ToLittleEndian((uint)(number >> 32), buffer, offset + 4);
}
#endregion
}
}
@@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Implements digital signature where where asymmetric cipher is used,
/// </summary>
public class CipherDigitalSignature : DigitalSignature
{
private HashAlgorithm _hash;
private AsymmetricCipher _cipher;
/// <summary>
/// Initializes a new instance of the <see cref="CipherDigitalSignature"/> class.
/// </summary>
/// <param name="hash">The hash.</param>
/// <param name="cipher">The cipher.</param>
public CipherDigitalSignature(HashAlgorithm hash, AsymmetricCipher cipher)
{
this._hash = hash;
this._cipher = cipher;
}
/// <summary>
/// Verifies the signature.
/// </summary>
/// <param name="input">The input.</param>
/// <param name="signature">The signature.</param>
/// <returns></returns>
public override bool VerifySignature(byte[] input, byte[] signature)
{
var sig = this._cipher.Decrypt(signature);
// TODO: Ensure that only 1 or 2 types are supported
var position = 1;
while (position < sig.Length && sig[position] != 0)
position++;
position++;
var sig1 = new byte[sig.Length - position];
Array.Copy(sig, position, sig1, 0, sig1.Length);
var hashData = this.Hash(input);
var expected = DerEncode(hashData);
if (expected.Count != sig1.Length)
return false;
for (int i = 0; i < expected.Count; i++)
{
if (expected[i] != sig1[i])
return false;
}
return true;
}
/// <summary>
/// Creates the signature.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
public override byte[] CreateSignature(byte[] input)
{
// Calculate hash value
var hashData = this.Hash(input);
// Calculate DER string
// Resolve algorithm identifier
var dd = DerEncode(hashData);
// Calculate signature
var rsaInputBlockSize = new byte[255];
rsaInputBlockSize[0] = 0x01;
for (int i = 1; i < rsaInputBlockSize.Length - dd.Count - 1; i++)
{
rsaInputBlockSize[i] = 0xFF;
}
Array.Copy(dd.ToArray(), 0, rsaInputBlockSize, rsaInputBlockSize.Length - dd.Count, dd.Count);
return this._cipher.Encrypt(rsaInputBlockSize).TrimLeadingZero().ToArray();
}
/// <summary>
/// Hashes the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
protected byte[] Hash(byte[] input)
{
return this._hash.ComputeHash(input);
}
protected static List<byte> DerEncode(byte[] hashData)
{
// TODO: Replace with algorithm code
var algorithm = new byte[] { 6, 5, 43, 14, 3, 2, 26 };
var algorithmParams = new byte[] { 5, 0 };
var dd = new List<byte>(algorithm);
dd.AddRange(algorithmParams);
dd.Insert(0, (byte)dd.Count);
dd.Insert(0, 48);
dd.Add(4);
dd.Add((byte)hashData.Length);
dd.AddRange(hashData);
dd.Insert(0, (byte)dd.Count);
dd.Insert(0, 48);
return dd;
}
}
}
@@ -3,115 +3,26 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
internal class AesCipher : CipherBase
/// <summary>
///
/// </summary>
public class AesCipher : BlockCipher
{
private int ROUNDS;
private byte[] _key;
private uint[,] _encryptionKey;
private uint[,] EncryptionKey
{
get
{
if (this._encryptionKey == null)
{
this._encryptionKey = this.GenerateWorkingKey(true, this._key);
}
return this._encryptionKey;
}
}
private uint[,] _decryptionKey;
private uint[,] DecryptionKey
{
get
{
if (this._decryptionKey == null)
{
this._decryptionKey = this.GenerateWorkingKey(false, this._key);
}
return this._decryptionKey;
}
}
private uint C0, C1, C2, C3;
/// <summary>
/// Gets the size of the block.
/// </summary>
/// <value>
/// The size of the block.
/// </value>
public override int BlockSize { get { return 16; } } // 128 bit block size
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
private const uint m1 = 0x80808080;
private const uint m2 = 0x7f7f7f7f;
private const uint m3 = 0x0000001b;
private int _rounds;
public AesCipher(byte[] key, byte[] iv)
: base(key, iv)
{
this._key = key;
}
private uint[,] _encryptionKey;
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (this.EncryptionKey == null)
{
throw new InvalidOperationException("AES engine not initialized");
}
private uint[,] _decryptionKey;
if ((inputOffset + (32 / 2)) > inputBuffer.Length)
{
throw new IndexOutOfRangeException("input buffer too short");
}
if ((outputOffset + (32 / 2)) > outputBuffer.Length)
{
throw new IndexOutOfRangeException("output buffer too short");
}
this.UnPackBlock(inputBuffer, inputOffset);
this.EncryptBlock(this.EncryptionKey);
this.PackBlock(outputBuffer, outputOffset);
return this.BlockSize;
}
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (this.DecryptionKey == null)
{
throw new InvalidOperationException("AES engine not initialized");
}
if ((inputOffset + (32 / 2)) > inputBuffer.Length)
{
throw new IndexOutOfRangeException("input buffer too short");
}
if ((outputOffset + (32 / 2)) > outputBuffer.Length)
{
throw new IndexOutOfRangeException("output buffer too short");
}
this.UnPackBlock(inputBuffer, inputOffset);
this.DecryptBlock(this.DecryptionKey);
this.PackBlock(outputBuffer, outputOffset);
return this.BlockSize;
}
private uint C0, C1, C2, C3;
#region Static Definition Tables
@@ -646,6 +557,167 @@ namespace Renci.SshNet.Security.Cryptography
#endregion
/// <summary>
/// Gets the size of the block in bytes.
/// </summary>
/// <value>
/// The size of the block in bytes.
/// </value>
public override int BlockSize
{
get { return 16; }
}
/// <summary>
/// Initializes a new instance of the <see cref="AesCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="mode">The mode.</param>
/// <param name="padding">The padding.</param>
public AesCipher(byte[] key, CipherMode mode, CipherPadding padding)
: base(key, mode, padding)
{
this._encryptionKey = this.GenerateWorkingKey(true, key);
this._decryptionKey = this.GenerateWorkingKey(false, key);
}
/// <summary>
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to encrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes encrypted.
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if ((inputOffset + (32 / 2)) > inputBuffer.Length)
{
throw new IndexOutOfRangeException("input buffer too short");
}
if ((outputOffset + (32 / 2)) > outputBuffer.Length)
{
throw new IndexOutOfRangeException("output buffer too short");
}
this.UnPackBlock(inputBuffer, inputOffset);
this.EncryptBlock(this._encryptionKey);
this.PackBlock(outputBuffer, outputOffset);
return this.BlockSize;
}
/// <summary>
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to decrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes decrypted.
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if ((inputOffset + (32 / 2)) > inputBuffer.Length)
{
throw new IndexOutOfRangeException("input buffer too short");
}
if ((outputOffset + (32 / 2)) > outputBuffer.Length)
{
throw new IndexOutOfRangeException("output buffer too short");
}
this.UnPackBlock(inputBuffer, inputOffset);
this.DecryptBlock(this._decryptionKey);
this.PackBlock(outputBuffer, outputOffset);
return this.BlockSize;
}
/// <summary>
/// Validates the size of the key.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <returns>
/// true if keySize is valid; otherwise false
/// </returns>
protected override bool ValidateKeySize(int keySize)
{
if (keySize == 256 ||
keySize == 192 ||
keySize == 128)
return true;
else
return false;
}
private uint[,] GenerateWorkingKey(bool isEncryption, byte[] key)
{
int KC = key.Length / 4; // key length in words
if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length))
throw new ArgumentException("Key length not 128/192/256 bits.");
_rounds = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
uint[,] W = new uint[_rounds + 1, 4]; // 4 words in a block
//
// copy the key into the round key array
//
int t = 0;
for (int i = 0; i < key.Length; t++)
{
W[t >> 2, t & 3] = LittleEndianToUInt32(key, i);
i += 4;
}
//
// while not enough round key material calculated
// calculate new values
//
int k = (_rounds + 1) << 2;
for (int i = KC; (i < k); i++)
{
uint temp = W[(i - 1) >> 2, (i - 1) & 3];
if ((i % KC) == 0)
{
temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC) - 1];
}
else if ((KC > 6) && ((i % KC) == 4))
{
temp = SubWord(temp);
}
W[i >> 2, i & 3] = W[(i - KC) >> 2, (i - KC) & 3] ^ temp;
}
if (!isEncryption)
{
for (int j = 1; j < _rounds; j++)
{
for (int i = 0; i < 4; i++)
{
W[j, i] = InvMcol(W[j, i]);
}
}
}
return W;
}
private uint Shift(uint r, int shift)
{
return (r >> shift) | (r << (32 - shift));
@@ -684,87 +756,20 @@ namespace Renci.SshNet.Security.Cryptography
| (((uint)S[(x >> 24) & 255]) << 24);
}
/**
* Calculate the necessary round keys
* The number of calculations depends on key size and block size
* AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
* This code is written assuming those are the only possible values
*/
private uint[,] GenerateWorkingKey(bool isEncryption, byte[] key)
{
int KC = key.Length / 4; // key length in words
if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length))
throw new ArgumentException("Key length not 128/192/256 bits.");
ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes
uint[,] W = new uint[ROUNDS + 1, 4]; // 4 words in a block
//
// copy the key into the round key array
//
int t = 0;
for (int i = 0; i < key.Length; t++)
{
W[t >> 2, t & 3] = CipherBase.LittleEndianToUInt32(key, i);
i += 4;
}
//
// while not enough round key material calculated
// calculate new values
//
int k = (ROUNDS + 1) << 2;
for (int i = KC; (i < k); i++)
{
uint temp = W[(i - 1) >> 2, (i - 1) & 3];
if ((i % KC) == 0)
{
temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC) - 1];
}
else if ((KC > 6) && ((i % KC) == 4))
{
temp = SubWord(temp);
}
W[i >> 2, i & 3] = W[(i - KC) >> 2, (i - KC) & 3] ^ temp;
}
if (!isEncryption)
{
for (int j = 1; j < ROUNDS; j++)
{
for (int i = 0; i < 4; i++)
{
W[j, i] = InvMcol(W[j, i]);
}
}
}
return W;
}
private bool IsPartialBlockOkay
{
get { return false; }
}
private void UnPackBlock(byte[] bytes, int off)
{
C0 = CipherBase.LittleEndianToUInt32(bytes, off);
C1 = CipherBase.LittleEndianToUInt32(bytes, off + 4);
C2 = CipherBase.LittleEndianToUInt32(bytes, off + 8);
C3 = CipherBase.LittleEndianToUInt32(bytes, off + 12);
C0 = LittleEndianToUInt32(bytes, off);
C1 = LittleEndianToUInt32(bytes, off + 4);
C2 = LittleEndianToUInt32(bytes, off + 8);
C3 = LittleEndianToUInt32(bytes, off + 12);
}
private void PackBlock(byte[] bytes, int off)
{
CipherBase.UInt32ToLittleEndian(C0, bytes, off);
CipherBase.UInt32ToLittleEndian(C1, bytes, off + 4);
CipherBase.UInt32ToLittleEndian(C2, bytes, off + 8);
CipherBase.UInt32ToLittleEndian(C3, bytes, off + 12);
UInt32ToLittleEndian(C0, bytes, off);
UInt32ToLittleEndian(C1, bytes, off + 4);
UInt32ToLittleEndian(C2, bytes, off + 8);
UInt32ToLittleEndian(C3, bytes, off + 12);
}
private void EncryptBlock(uint[,] KW)
@@ -777,7 +782,7 @@ namespace Renci.SshNet.Security.Cryptography
C2 ^= KW[0, 2];
C3 ^= KW[0, 3];
for (r = 1; r < ROUNDS - 1; )
for (r = 1; r < _rounds - 1; )
{
r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ KW[r, 0];
r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ KW[r, 1];
@@ -807,12 +812,12 @@ namespace Renci.SshNet.Security.Cryptography
int r;
uint r0, r1, r2, r3;
C0 ^= KW[ROUNDS, 0];
C1 ^= KW[ROUNDS, 1];
C2 ^= KW[ROUNDS, 2];
C3 ^= KW[ROUNDS, 3];
C0 ^= KW[_rounds, 0];
C1 ^= KW[_rounds, 1];
C2 ^= KW[_rounds, 2];
C3 ^= KW[_rounds, 3];
for (r = ROUNDS - 1; r > 1; )
for (r = _rounds - 1; r > 1; )
{
r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ KW[r, 0];
r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ KW[r, 1];
@@ -836,5 +841,6 @@ namespace Renci.SshNet.Security.Cryptography
C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ KW[0, 2];
C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ KW[0, 3];
}
}
}
@@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
/// <summary>
/// Implements ARCH4 cipher algorithm
/// </summary>
public class Arc4Cipher : StreamCipher
{
/// <summary>
/// Initializes a new instance of the <see cref="Arc4Cipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
public Arc4Cipher(byte[] key)
: base(key)
{
}
/// <summary>
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to encrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes encrypted.
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
throw new NotImplementedException();
}
/// <summary>
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to decrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes decrypted.
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
throw new NotImplementedException();
}
/// <summary>
/// Encrypts the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
public override byte[] Encrypt(byte[] input)
{
throw new NotImplementedException();
}
/// <summary>
/// Decrypts the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
public override byte[] Decrypt(byte[] input)
{
throw new NotImplementedException();
}
/// <summary>
/// Validates the size of the key.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <returns>
/// true if keySize is valid; otherwise false
/// </returns>
protected override bool ValidateKeySize(int keySize)
{
throw new NotImplementedException();
}
}
}
@@ -3,13 +3,16 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
internal class BlowfishCipher : CipherBase
{
#region Static reference tables
/// <summary>
///
/// </summary>
public class BlowfishCipher : BlockCipher
{
#region Static reference tables
private readonly static uint[] KP =
private readonly static uint[] KP =
{
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
@@ -17,7 +20,7 @@ namespace Renci.SshNet.Security.Cryptography
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
0x9216D5D9, 0x8979FB1B
},
KS0 =
KS0 =
{
0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
@@ -84,7 +87,7 @@ namespace Renci.SshNet.Security.Cryptography
0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
},
KS1 =
KS1 =
{
0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
@@ -151,7 +154,7 @@ namespace Renci.SshNet.Security.Cryptography
0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
},
KS2 =
KS2 =
{
0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
@@ -218,7 +221,7 @@ namespace Renci.SshNet.Security.Cryptography
0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
},
KS3 =
KS3 =
{
0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
@@ -286,188 +289,239 @@ namespace Renci.SshNet.Security.Cryptography
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
};
#endregion
#endregion
private static readonly int ROUNDS = 16;
private static readonly int SBOX_SK = 256;
private static readonly int P_SZ = ROUNDS + 2;
private static readonly int ROUNDS = 16;
private static readonly int SBOX_SK = 256;
private static readonly int P_SZ = ROUNDS + 2;
private readonly uint[] S0, S1, S2, S3; // the s-boxes
private readonly uint[] P; // the p-array
private readonly uint[] S0, S1, S2, S3; // the s-boxes
private readonly uint[] P; // the p-array
public BlowfishCipher(byte[] key, byte[] iv)
: base(key, iv)
{
S0 = new uint[SBOX_SK];
S1 = new uint[SBOX_SK];
S2 = new uint[SBOX_SK];
S3 = new uint[SBOX_SK];
P = new uint[P_SZ];
/// <summary>
/// Gets the size of the block in bytes.
/// </summary>
/// <value>
/// The size of the block in bytes.
/// </value>
public override int BlockSize
{
get { return 8; }
}
this.SetKey(key);
}
/// <summary>
/// Initializes a new instance of the <see cref="BlowfishCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="mode">The mode.</param>
/// <param name="padding">The padding.</param>
public BlowfishCipher(byte[] key, CipherMode mode, CipherPadding padding)
: base(key, mode, padding)
{
// TODO: Refactor this algorithm
public override int BlockSize
{
get { return 8; }
}
S0 = new uint[SBOX_SK];
S1 = new uint[SBOX_SK];
S2 = new uint[SBOX_SK];
S3 = new uint[SBOX_SK];
P = new uint[P_SZ];
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputCount != this.BlockSize)
throw new ArgumentException("inputCount");
this.SetKey(key);
}
uint xl = CipherBase.BigEndianToUInt32(inputBuffer, inputOffset);
uint xr = CipherBase.BigEndianToUInt32(inputBuffer, inputOffset + 4);
/// <summary>
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to encrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes encrypted.
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputCount != this.BlockSize)
throw new ArgumentException("inputCount");
xl ^= P[0];
uint xl = BigEndianToUInt32(inputBuffer, inputOffset);
uint xr = BigEndianToUInt32(inputBuffer, inputOffset + 4);
for (int i = 1; i < ROUNDS; i += 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
xl ^= P[0];
xr ^= P[ROUNDS + 1];
for (int i = 1; i < ROUNDS; i += 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
CipherBase.UInt32ToBigEndian(xr, outputBuffer, outputOffset);
CipherBase.UInt32ToBigEndian(xl, outputBuffer, outputOffset + 4);
return this.BlockSize;
}
xr ^= P[ROUNDS + 1];
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputCount != this.BlockSize)
throw new ArgumentException("inputCount");
UInt32ToBigEndian(xr, outputBuffer, outputOffset);
UInt32ToBigEndian(xl, outputBuffer, outputOffset + 4);
uint xl = CipherBase.BigEndianToUInt32(inputBuffer, inputOffset);
uint xr = CipherBase.BigEndianToUInt32(inputBuffer, inputOffset + 4);
return this.BlockSize;
}
xl ^= P[ROUNDS + 1];
/// <summary>
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to decrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes decrypted.
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputCount != this.BlockSize)
throw new ArgumentException("inputCount");
for (int i = ROUNDS; i > 0; i -= 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i - 1];
}
uint xl = BigEndianToUInt32(inputBuffer, inputOffset);
uint xr = BigEndianToUInt32(inputBuffer, inputOffset + 4);
xr ^= P[0];
xl ^= P[ROUNDS + 1];
CipherBase.UInt32ToBigEndian(xr, outputBuffer, outputOffset);
CipherBase.UInt32ToBigEndian(xl, outputBuffer, outputOffset + 4);
for (int i = ROUNDS; i > 0; i -= 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i - 1];
}
return this.BlockSize;
}
xr ^= P[0];
private uint F(uint x)
{
return (((S0[x >> 24] + S1[(x >> 16) & 0xff]) ^ S2[(x >> 8) & 0xff]) + S3[x & 0xff]);
}
UInt32ToBigEndian(xr, outputBuffer, outputOffset);
UInt32ToBigEndian(xl, outputBuffer, outputOffset + 4);
return this.BlockSize;
}
/// <summary>
/// apply the encryption cycle to each value pair in the table.
/// Validates the size of the key.
/// </summary>
/// <param name="xl">The xl.</param>
/// <param name="xr">The xr.</param>
/// <param name="table">The table.</param>
private void ProcessTable(uint xl, uint xr, uint[] table)
{
int size = table.Length;
/// <param name="keySize">Size of the key.</param>
/// <returns>
/// true if keySize is valid; otherwise false
/// </returns>
protected override bool ValidateKeySize(int keySize)
{
if (keySize >= 1 && keySize <= 448)
return true;
else
return false;
}
for (int s = 0; s < size; s += 2)
{
xl ^= P[0];
private uint F(uint x)
{
return (((S0[x >> 24] + S1[(x >> 16) & 0xff]) ^ S2[(x >> 8) & 0xff]) + S3[x & 0xff]);
}
for (int i = 1; i < ROUNDS; i += 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
/// <summary>
/// apply the encryption cycle to each value pair in the table.
/// </summary>
/// <param name="xl">The xl.</param>
/// <param name="xr">The xr.</param>
/// <param name="table">The table.</param>
private void ProcessTable(uint xl, uint xr, uint[] table)
{
int size = table.Length;
xr ^= P[ROUNDS + 1];
for (int s = 0; s < size; s += 2)
{
xl ^= P[0];
table[s] = xr;
table[s + 1] = xl;
for (int i = 1; i < ROUNDS; i += 2)
{
xr ^= F(xl) ^ P[i];
xl ^= F(xr) ^ P[i + 1];
}
xr = xl; // end of cycle swap
xl = table[s];
}
}
xr ^= P[ROUNDS + 1];
private void SetKey(byte[] key)
{
/*
* - comments are from _Applied Crypto_, Schneier, p338
* please be careful comparing the two, AC numbers the
* arrays from 1, the enclosed code from 0.
*
* (1)
* Initialise the S-boxes and the P-array, with a fixed string
* This string contains the hexadecimal digits of pi (3.141...)
*/
Array.Copy(KS0, 0, S0, 0, SBOX_SK);
Array.Copy(KS1, 0, S1, 0, SBOX_SK);
Array.Copy(KS2, 0, S2, 0, SBOX_SK);
Array.Copy(KS3, 0, S3, 0, SBOX_SK);
table[s] = xr;
table[s + 1] = xl;
Array.Copy(KP, 0, P, 0, P_SZ);
xr = xl; // end of cycle swap
xl = table[s];
}
}
/*
* (2)
* Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the
* second 32-bits of the key, and so on for all bits of the key
* (up to P[17]). Repeatedly cycle through the key bits until the
* entire P-array has been XOR-ed with the key bits
*/
int keyLength = key.Length;
int keyIndex = 0;
private void SetKey(byte[] key)
{
/*
* - comments are from _Applied Crypto_, Schneier, p338
* please be careful comparing the two, AC numbers the
* arrays from 1, the enclosed code from 0.
*
* (1)
* Initialise the S-boxes and the P-array, with a fixed string
* This string contains the hexadecimal digits of pi (3.141...)
*/
Array.Copy(KS0, 0, S0, 0, SBOX_SK);
Array.Copy(KS1, 0, S1, 0, SBOX_SK);
Array.Copy(KS2, 0, S2, 0, SBOX_SK);
Array.Copy(KS3, 0, S3, 0, SBOX_SK);
for (int i = 0; i < P_SZ; i++)
{
// Get the 32 bits of the key, in 4 * 8 bit chunks
uint data = 0x0000000;
for (int j = 0; j < 4; j++)
{
// create a 32 bit block
data = (data << 8) | (uint)key[keyIndex++];
Array.Copy(KP, 0, P, 0, P_SZ);
// wrap when we get to the end of the key
if (keyIndex >= keyLength)
{
keyIndex = 0;
}
}
// XOR the newly created 32 bit chunk onto the P-array
P[i] ^= data;
}
/*
* (2)
* Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the
* second 32-bits of the key, and so on for all bits of the key
* (up to P[17]). Repeatedly cycle through the key bits until the
* entire P-array has been XOR-ed with the key bits
*/
int keyLength = key.Length;
int keyIndex = 0;
/*
* (3)
* Encrypt the all-zero string with the Blowfish algorithm, using
* the subkeys described in (1) and (2)
*
* (4)
* Replace P1 and P2 with the output of step (3)
*
* (5)
* Encrypt the output of step(3) using the Blowfish algorithm,
* with the modified subkeys.
*
* (6)
* Replace P3 and P4 with the output of step (5)
*
* (7)
* Continue the process, replacing all elements of the P-array
* and then all four S-boxes in order, with the output of the
* continuously changing Blowfish algorithm
*/
for (int i = 0; i < P_SZ; i++)
{
// Get the 32 bits of the key, in 4 * 8 bit chunks
uint data = 0x0000000;
for (int j = 0; j < 4; j++)
{
// create a 32 bit block
data = (data << 8) | (uint)key[keyIndex++];
ProcessTable(0, 0, P);
ProcessTable(P[P_SZ - 2], P[P_SZ - 1], S0);
ProcessTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
ProcessTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
ProcessTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
}
}
// wrap when we get to the end of the key
if (keyIndex >= keyLength)
{
keyIndex = 0;
}
}
// XOR the newly created 32 bit chunk onto the P-array
P[i] ^= data;
}
/*
* (3)
* Encrypt the all-zero string with the Blowfish algorithm, using
* the subkeys described in (1) and (2)
*
* (4)
* Replace P1 and P2 with the output of step (3)
*
* (5)
* Encrypt the output of step(3) using the Blowfish algorithm,
* with the modified subkeys.
*
* (6)
* Replace P3 and P4 with the output of step (5)
*
* (7)
* Continue the process, replacing all elements of the P-array
* and then all four S-boxes in order, with the output of the
* continuously changing Blowfish algorithm
*/
ProcessTable(0, 0, P);
ProcessTable(P[P_SZ - 2], P[P_SZ - 1], S0);
ProcessTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
ProcessTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
ProcessTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
}
}
}
@@ -3,11 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
internal class CastCipher : CipherBase
/// <summary>
/// Implements CAST cipher algorithm
/// </summary>
public class CastCipher : BlockCipher
{
internal static readonly int MAX_ROUNDS = 16;
internal static readonly int RED_ROUNDS = 12;
@@ -16,54 +18,104 @@ namespace Renci.SshNet.Security.Cryptography
private int _rounds = MAX_ROUNDS;
/// <summary>
/// Gets the size of the block in bytes.
/// </summary>
/// <value>
/// The size of the block in bytes.
/// </value>
public override int BlockSize
{
get { return 8; }
}
public CastCipher(byte[] key, byte[] iv)
: base(key, iv)
{
/// <summary>
/// Initializes a new instance of the <see cref="CastCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="mode">The mode.</param>
/// <param name="padding">The padding.</param>
public CastCipher(byte[] key, CipherMode mode, CipherPadding padding)
: base(key, mode, padding)
{
// TODO: Refactor this algorithm
this.SetKey(key);
}
/// <summary>
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to encrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes encrypted.
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
// process the input block
// batch the units up into a 32 bit chunk and go for it
// the array is in bytes, the increment is 8x8 bits = 64
uint L0 = CipherBase.BigEndianToUInt32(inputBuffer, inputOffset);
uint R0 = CipherBase.BigEndianToUInt32(inputBuffer, inputOffset + 4);
uint L0 = BigEndianToUInt32(inputBuffer, inputOffset);
uint R0 = BigEndianToUInt32(inputBuffer, inputOffset + 4);
uint[] result = new uint[2];
CAST_Encipher(L0, R0, result);
CastEncipher(L0, R0, result);
// now stuff them into the destination block
CipherBase.UInt32ToBigEndian(result[0], outputBuffer, outputOffset);
CipherBase.UInt32ToBigEndian(result[1], outputBuffer, outputOffset + 4);
UInt32ToBigEndian(result[0], outputBuffer, outputOffset);
UInt32ToBigEndian(result[1], outputBuffer, outputOffset + 4);
return this.BlockSize;
}
/// <summary>
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to decrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes decrypted.
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
// process the input block
// batch the units up into a 32 bit chunk and go for it
// the array is in bytes, the increment is 8x8 bits = 64
uint L16 = CipherBase.BigEndianToUInt32(inputBuffer, inputOffset);
uint R16 = CipherBase.BigEndianToUInt32(inputBuffer, inputOffset + 4);
uint L16 = BigEndianToUInt32(inputBuffer, inputOffset);
uint R16 = BigEndianToUInt32(inputBuffer, inputOffset + 4);
uint[] result = new uint[2];
CAST_Decipher(L16, R16, result);
CastDecipher(L16, R16, result);
// now stuff them into the destination block
CipherBase.UInt32ToBigEndian(result[0], outputBuffer, outputOffset);
CipherBase.UInt32ToBigEndian(result[1], outputBuffer, outputOffset + 4);
UInt32ToBigEndian(result[0], outputBuffer, outputOffset);
UInt32ToBigEndian(result[1], outputBuffer, outputOffset + 4);
return this.BlockSize;
}
/// <summary>
/// Validates the size of the key.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <returns>
/// true if keySize is valid; otherwise false
/// </returns>
protected override bool ValidateKeySize(int keySize)
{
if (keySize >= 40 && keySize <= 128 && keySize % 8 == 0)
return true;
else
return false;
}
#region Static Definition Tables
internal static readonly uint[] S1 =
@@ -101,7 +153,7 @@ namespace Renci.SshNet.Security.Cryptography
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
},
S2 =
S2 =
{
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
@@ -136,7 +188,7 @@ namespace Renci.SshNet.Security.Cryptography
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
},
S3 =
S3 =
{
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
@@ -171,7 +223,7 @@ namespace Renci.SshNet.Security.Cryptography
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
},
S4 =
S4 =
{
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
@@ -206,7 +258,7 @@ namespace Renci.SshNet.Security.Cryptography
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
},
S5 =
S5 =
{
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
@@ -241,7 +293,7 @@ namespace Renci.SshNet.Security.Cryptography
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
},
S6 =
S6 =
{
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
@@ -276,7 +328,7 @@ namespace Renci.SshNet.Security.Cryptography
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
},
S7 =
S7 =
{
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
@@ -311,7 +363,7 @@ namespace Renci.SshNet.Security.Cryptography
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
},
S8 =
S8 =
{
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
@@ -371,14 +423,14 @@ namespace Renci.SshNet.Security.Cryptography
_rounds = RED_ROUNDS;
}
int [] z = new int[16];
int [] x = new int[16];
int[] z = new int[16];
int[] x = new int[16];
uint z03, z47, z8B, zCF;
uint x03, x47, x8B, xCF;
/* copy the key into x */
for (int i=0; i< key.Length; i++)
for (int i = 0; i < key.Length; i++)
{
x[i] = (int)(key[i] & 0xff);
}
@@ -393,138 +445,138 @@ namespace Renci.SshNet.Security.Cryptography
x8B = IntsTo32bits(x, 0x8);
xCF = IntsTo32bits(x, 0xC);
z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
z03 = x03 ^ S5[x[0xD]] ^ S6[x[0xF]] ^ S7[x[0xC]] ^ S8[x[0xE]] ^ S7[x[0x8]];
Bits32ToInts(z03, z, 0x0);
z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
z47 = x8B ^ S5[z[0x0]] ^ S6[z[0x2]] ^ S7[z[0x1]] ^ S8[z[0x3]] ^ S8[x[0xA]];
Bits32ToInts(z47, z, 0x4);
z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
z8B = xCF ^ S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S5[x[0x9]];
Bits32ToInts(z8B, z, 0x8);
zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
zCF = x47 ^ S5[z[0xA]] ^ S6[z[0x9]] ^ S7[z[0xB]] ^ S8[z[0x8]] ^ S6[x[0xB]];
Bits32ToInts(zCF, z, 0xC);
_Km[ 1]= S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]];
_Km[ 2]= S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]];
_Km[ 3]= S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]];
_Km[ 4]= S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]];
_Km[1] = S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]];
_Km[2] = S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]];
_Km[3] = S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]];
_Km[4] = S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]];
z03 = IntsTo32bits(z, 0x0);
z47 = IntsTo32bits(z, 0x4);
z8B = IntsTo32bits(z, 0x8);
zCF = IntsTo32bits(z, 0xC);
x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
x03 = z8B ^ S5[z[0x5]] ^ S6[z[0x7]] ^ S7[z[0x4]] ^ S8[z[0x6]] ^ S7[z[0x0]];
Bits32ToInts(x03, x, 0x0);
x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
x47 = z03 ^ S5[x[0x0]] ^ S6[x[0x2]] ^ S7[x[0x1]] ^ S8[x[0x3]] ^ S8[z[0x2]];
Bits32ToInts(x47, x, 0x4);
x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
x8B = z47 ^ S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S5[z[0x1]];
Bits32ToInts(x8B, x, 0x8);
xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
xCF = zCF ^ S5[x[0xA]] ^ S6[x[0x9]] ^ S7[x[0xB]] ^ S8[x[0x8]] ^ S6[z[0x3]];
Bits32ToInts(xCF, x, 0xC);
_Km[ 5]= S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]];
_Km[ 6]= S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]];
_Km[ 7]= S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]];
_Km[ 8]= S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]];
_Km[5] = S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]];
_Km[6] = S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]];
_Km[7] = S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]];
_Km[8] = S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]];
x03 = IntsTo32bits(x, 0x0);
x47 = IntsTo32bits(x, 0x4);
x8B = IntsTo32bits(x, 0x8);
xCF = IntsTo32bits(x, 0xC);
z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
z03 = x03 ^ S5[x[0xD]] ^ S6[x[0xF]] ^ S7[x[0xC]] ^ S8[x[0xE]] ^ S7[x[0x8]];
Bits32ToInts(z03, z, 0x0);
z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
z47 = x8B ^ S5[z[0x0]] ^ S6[z[0x2]] ^ S7[z[0x1]] ^ S8[z[0x3]] ^ S8[x[0xA]];
Bits32ToInts(z47, z, 0x4);
z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
z8B = xCF ^ S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S5[x[0x9]];
Bits32ToInts(z8B, z, 0x8);
zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
zCF = x47 ^ S5[z[0xA]] ^ S6[z[0x9]] ^ S7[z[0xB]] ^ S8[z[0x8]] ^ S6[x[0xB]];
Bits32ToInts(zCF, z, 0xC);
_Km[ 9]= S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]];
_Km[10]= S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]];
_Km[11]= S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]];
_Km[12]= S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]];
_Km[9] = S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]];
_Km[10] = S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]];
_Km[11] = S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]];
_Km[12] = S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]];
z03 = IntsTo32bits(z, 0x0);
z47 = IntsTo32bits(z, 0x4);
z8B = IntsTo32bits(z, 0x8);
zCF = IntsTo32bits(z, 0xC);
x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
x03 = z8B ^ S5[z[0x5]] ^ S6[z[0x7]] ^ S7[z[0x4]] ^ S8[z[0x6]] ^ S7[z[0x0]];
Bits32ToInts(x03, x, 0x0);
x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
x47 = z03 ^ S5[x[0x0]] ^ S6[x[0x2]] ^ S7[x[0x1]] ^ S8[x[0x3]] ^ S8[z[0x2]];
Bits32ToInts(x47, x, 0x4);
x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
x8B = z47 ^ S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S5[z[0x1]];
Bits32ToInts(x8B, x, 0x8);
xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
xCF = zCF ^ S5[x[0xA]] ^ S6[x[0x9]] ^ S7[x[0xB]] ^ S8[x[0x8]] ^ S6[z[0x3]];
Bits32ToInts(xCF, x, 0xC);
_Km[13]= S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]];
_Km[14]= S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]];
_Km[15]= S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]];
_Km[16]= S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]];
_Km[13] = S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]];
_Km[14] = S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]];
_Km[15] = S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]];
_Km[16] = S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]];
x03 = IntsTo32bits(x, 0x0);
x47 = IntsTo32bits(x, 0x4);
x8B = IntsTo32bits(x, 0x8);
xCF = IntsTo32bits(x, 0xC);
z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
z03 = x03 ^ S5[x[0xD]] ^ S6[x[0xF]] ^ S7[x[0xC]] ^ S8[x[0xE]] ^ S7[x[0x8]];
Bits32ToInts(z03, z, 0x0);
z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
z47 = x8B ^ S5[z[0x0]] ^ S6[z[0x2]] ^ S7[z[0x1]] ^ S8[z[0x3]] ^ S8[x[0xA]];
Bits32ToInts(z47, z, 0x4);
z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
z8B = xCF ^ S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S5[x[0x9]];
Bits32ToInts(z8B, z, 0x8);
zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
zCF = x47 ^ S5[z[0xA]] ^ S6[z[0x9]] ^ S7[z[0xB]] ^ S8[z[0x8]] ^ S6[x[0xB]];
Bits32ToInts(zCF, z, 0xC);
_Kr[ 1]=(int)((S5[z[0x8]]^S6[z[0x9]]^S7[z[0x7]]^S8[z[0x6]] ^ S5[z[0x2]])&0x1f);
_Kr[ 2]=(int)((S5[z[0xA]]^S6[z[0xB]]^S7[z[0x5]]^S8[z[0x4]] ^ S6[z[0x6]])&0x1f);
_Kr[ 3]=(int)((S5[z[0xC]]^S6[z[0xD]]^S7[z[0x3]]^S8[z[0x2]] ^ S7[z[0x9]])&0x1f);
_Kr[ 4]=(int)((S5[z[0xE]]^S6[z[0xF]]^S7[z[0x1]]^S8[z[0x0]] ^ S8[z[0xC]])&0x1f);
_Kr[1] = (int)((S5[z[0x8]] ^ S6[z[0x9]] ^ S7[z[0x7]] ^ S8[z[0x6]] ^ S5[z[0x2]]) & 0x1f);
_Kr[2] = (int)((S5[z[0xA]] ^ S6[z[0xB]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S6[z[0x6]]) & 0x1f);
_Kr[3] = (int)((S5[z[0xC]] ^ S6[z[0xD]] ^ S7[z[0x3]] ^ S8[z[0x2]] ^ S7[z[0x9]]) & 0x1f);
_Kr[4] = (int)((S5[z[0xE]] ^ S6[z[0xF]] ^ S7[z[0x1]] ^ S8[z[0x0]] ^ S8[z[0xC]]) & 0x1f);
z03 = IntsTo32bits(z, 0x0);
z47 = IntsTo32bits(z, 0x4);
z8B = IntsTo32bits(z, 0x8);
zCF = IntsTo32bits(z, 0xC);
x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
x03 = z8B ^ S5[z[0x5]] ^ S6[z[0x7]] ^ S7[z[0x4]] ^ S8[z[0x6]] ^ S7[z[0x0]];
Bits32ToInts(x03, x, 0x0);
x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
x47 = z03 ^ S5[x[0x0]] ^ S6[x[0x2]] ^ S7[x[0x1]] ^ S8[x[0x3]] ^ S8[z[0x2]];
Bits32ToInts(x47, x, 0x4);
x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
x8B = z47 ^ S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S5[z[0x1]];
Bits32ToInts(x8B, x, 0x8);
xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
xCF = zCF ^ S5[x[0xA]] ^ S6[x[0x9]] ^ S7[x[0xB]] ^ S8[x[0x8]] ^ S6[z[0x3]];
Bits32ToInts(xCF, x, 0xC);
_Kr[ 5]=(int)((S5[x[0x3]]^S6[x[0x2]]^S7[x[0xC]]^S8[x[0xD]]^S5[x[0x8]])&0x1f);
_Kr[ 6]=(int)((S5[x[0x1]]^S6[x[0x0]]^S7[x[0xE]]^S8[x[0xF]]^S6[x[0xD]])&0x1f);
_Kr[ 7]=(int)((S5[x[0x7]]^S6[x[0x6]]^S7[x[0x8]]^S8[x[0x9]]^S7[x[0x3]])&0x1f);
_Kr[ 8]=(int)((S5[x[0x5]]^S6[x[0x4]]^S7[x[0xA]]^S8[x[0xB]]^S8[x[0x7]])&0x1f);
_Kr[5] = (int)((S5[x[0x3]] ^ S6[x[0x2]] ^ S7[x[0xC]] ^ S8[x[0xD]] ^ S5[x[0x8]]) & 0x1f);
_Kr[6] = (int)((S5[x[0x1]] ^ S6[x[0x0]] ^ S7[x[0xE]] ^ S8[x[0xF]] ^ S6[x[0xD]]) & 0x1f);
_Kr[7] = (int)((S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x8]] ^ S8[x[0x9]] ^ S7[x[0x3]]) & 0x1f);
_Kr[8] = (int)((S5[x[0x5]] ^ S6[x[0x4]] ^ S7[x[0xA]] ^ S8[x[0xB]] ^ S8[x[0x7]]) & 0x1f);
x03 = IntsTo32bits(x, 0x0);
x47 = IntsTo32bits(x, 0x4);
x8B = IntsTo32bits(x, 0x8);
xCF = IntsTo32bits(x, 0xC);
z03 = x03 ^S5[x[0xD]] ^S6[x[0xF]] ^S7[x[0xC]] ^S8[x[0xE]] ^S7[x[0x8]];
z03 = x03 ^ S5[x[0xD]] ^ S6[x[0xF]] ^ S7[x[0xC]] ^ S8[x[0xE]] ^ S7[x[0x8]];
Bits32ToInts(z03, z, 0x0);
z47 = x8B ^S5[z[0x0]] ^S6[z[0x2]] ^S7[z[0x1]] ^S8[z[0x3]] ^S8[x[0xA]];
z47 = x8B ^ S5[z[0x0]] ^ S6[z[0x2]] ^ S7[z[0x1]] ^ S8[z[0x3]] ^ S8[x[0xA]];
Bits32ToInts(z47, z, 0x4);
z8B = xCF ^S5[z[0x7]] ^S6[z[0x6]] ^S7[z[0x5]] ^S8[z[0x4]] ^S5[x[0x9]];
z8B = xCF ^ S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S5[x[0x9]];
Bits32ToInts(z8B, z, 0x8);
zCF = x47 ^S5[z[0xA]] ^S6[z[0x9]] ^S7[z[0xB]] ^S8[z[0x8]] ^S6[x[0xB]];
zCF = x47 ^ S5[z[0xA]] ^ S6[z[0x9]] ^ S7[z[0xB]] ^ S8[z[0x8]] ^ S6[x[0xB]];
Bits32ToInts(zCF, z, 0xC);
_Kr[ 9]=(int)((S5[z[0x3]]^S6[z[0x2]]^S7[z[0xC]]^S8[z[0xD]]^S5[z[0x9]])&0x1f);
_Kr[10]=(int)((S5[z[0x1]]^S6[z[0x0]]^S7[z[0xE]]^S8[z[0xF]]^S6[z[0xc]])&0x1f);
_Kr[11]=(int)((S5[z[0x7]]^S6[z[0x6]]^S7[z[0x8]]^S8[z[0x9]]^S7[z[0x2]])&0x1f);
_Kr[12]=(int)((S5[z[0x5]]^S6[z[0x4]]^S7[z[0xA]]^S8[z[0xB]]^S8[z[0x6]])&0x1f);
_Kr[9] = (int)((S5[z[0x3]] ^ S6[z[0x2]] ^ S7[z[0xC]] ^ S8[z[0xD]] ^ S5[z[0x9]]) & 0x1f);
_Kr[10] = (int)((S5[z[0x1]] ^ S6[z[0x0]] ^ S7[z[0xE]] ^ S8[z[0xF]] ^ S6[z[0xc]]) & 0x1f);
_Kr[11] = (int)((S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x8]] ^ S8[z[0x9]] ^ S7[z[0x2]]) & 0x1f);
_Kr[12] = (int)((S5[z[0x5]] ^ S6[z[0x4]] ^ S7[z[0xA]] ^ S8[z[0xB]] ^ S8[z[0x6]]) & 0x1f);
z03 = IntsTo32bits(z, 0x0);
z47 = IntsTo32bits(z, 0x4);
z8B = IntsTo32bits(z, 0x8);
zCF = IntsTo32bits(z, 0xC);
x03 = z8B ^S5[z[0x5]] ^S6[z[0x7]] ^S7[z[0x4]] ^S8[z[0x6]] ^S7[z[0x0]];
x03 = z8B ^ S5[z[0x5]] ^ S6[z[0x7]] ^ S7[z[0x4]] ^ S8[z[0x6]] ^ S7[z[0x0]];
Bits32ToInts(x03, x, 0x0);
x47 = z03 ^S5[x[0x0]] ^S6[x[0x2]] ^S7[x[0x1]] ^S8[x[0x3]] ^S8[z[0x2]];
x47 = z03 ^ S5[x[0x0]] ^ S6[x[0x2]] ^ S7[x[0x1]] ^ S8[x[0x3]] ^ S8[z[0x2]];
Bits32ToInts(x47, x, 0x4);
x8B = z47 ^S5[x[0x7]] ^S6[x[0x6]] ^S7[x[0x5]] ^S8[x[0x4]] ^S5[z[0x1]];
x8B = z47 ^ S5[x[0x7]] ^ S6[x[0x6]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S5[z[0x1]];
Bits32ToInts(x8B, x, 0x8);
xCF = zCF ^S5[x[0xA]] ^S6[x[0x9]] ^S7[x[0xB]] ^S8[x[0x8]] ^S6[z[0x3]];
xCF = zCF ^ S5[x[0xA]] ^ S6[x[0x9]] ^ S7[x[0xB]] ^ S8[x[0x8]] ^ S6[z[0x3]];
Bits32ToInts(xCF, x, 0xC);
_Kr[13]=(int)((S5[x[0x8]]^S6[x[0x9]]^S7[x[0x7]]^S8[x[0x6]]^S5[x[0x3]])&0x1f);
_Kr[14]=(int)((S5[x[0xA]]^S6[x[0xB]]^S7[x[0x5]]^S8[x[0x4]]^S6[x[0x7]])&0x1f);
_Kr[15]=(int)((S5[x[0xC]]^S6[x[0xD]]^S7[x[0x3]]^S8[x[0x2]]^S7[x[0x8]])&0x1f);
_Kr[16]=(int)((S5[x[0xE]]^S6[x[0xF]]^S7[x[0x1]]^S8[x[0x0]]^S8[x[0xD]])&0x1f);
_Kr[13] = (int)((S5[x[0x8]] ^ S6[x[0x9]] ^ S7[x[0x7]] ^ S8[x[0x6]] ^ S5[x[0x3]]) & 0x1f);
_Kr[14] = (int)((S5[x[0xA]] ^ S6[x[0xB]] ^ S7[x[0x5]] ^ S8[x[0x4]] ^ S6[x[0x7]]) & 0x1f);
_Kr[15] = (int)((S5[x[0xC]] ^ S6[x[0xD]] ^ S7[x[0x3]] ^ S8[x[0x2]] ^ S7[x[0x8]]) & 0x1f);
_Kr[16] = (int)((S5[x[0xE]] ^ S6[x[0xF]] ^ S7[x[0x1]] ^ S8[x[0x0]] ^ S8[x[0xD]]) & 0x1f);
}
/**
@@ -536,11 +588,11 @@ namespace Renci.SshNet.Security.Cryptography
* @param Kri the rotation value to be used
*
*/
internal static uint F1(uint D, uint Kmi, int Kri)
private static uint F1(uint D, uint Kmi, int Kri)
{
uint I = Kmi + D;
I = I << Kri | (I >> (32-Kri));
return ((S1[(I>>24)&0xff]^S2[(I>>16)&0xff])-S3[(I>>8)&0xff])+S4[I&0xff];
I = I << Kri | (I >> (32 - Kri));
return ((S1[(I >> 24) & 0xff] ^ S2[(I >> 16) & 0xff]) - S3[(I >> 8) & 0xff]) + S4[I & 0xff];
}
/**
@@ -552,11 +604,11 @@ namespace Renci.SshNet.Security.Cryptography
* @param Kri the rotation value to be used
*
*/
internal static uint F2(uint D, uint Kmi, int Kri)
private static uint F2(uint D, uint Kmi, int Kri)
{
uint I = Kmi ^ D;
I = I << Kri | (I >> (32-Kri));
return ((S1[(I>>24)&0xff]-S2[(I>>16)&0xff])+S3[(I>>8)&0xff])^S4[I&0xff];
I = I << Kri | (I >> (32 - Kri));
return ((S1[(I >> 24) & 0xff] - S2[(I >> 16) & 0xff]) + S3[(I >> 8) & 0xff]) ^ S4[I & 0xff];
}
/**
@@ -568,11 +620,11 @@ namespace Renci.SshNet.Security.Cryptography
* @param Kri the rotation value to be used
*
*/
internal static uint F3(uint D, uint Kmi, int Kri)
private static uint F3(uint D, uint Kmi, int Kri)
{
uint I = Kmi - D;
I = I << Kri | (I >> (32-Kri));
return ((S1[(I>>24)&0xff]+S2[(I>>16)&0xff])^S3[(I>>8)&0xff])-S4[I&0xff];
I = I << Kri | (I >> (32 - Kri));
return ((S1[(I >> 24) & 0xff] + S2[(I >> 16) & 0xff]) ^ S3[(I >> 8) & 0xff]) - S4[I & 0xff];
}
/**
@@ -581,7 +633,7 @@ namespace Renci.SshNet.Security.Cryptography
* @param L0 the LH-32bits of the plaintext block
* @param R0 the RH-32bits of the plaintext block
*/
internal void CAST_Encipher(uint L0, uint R0, uint[] result)
private void CastEncipher(uint L0, uint R0, uint[] result)
{
uint Lp = L0; // the previous value, equiv to L[i-1]
uint Rp = R0; // equivalent to R[i-1]
@@ -592,7 +644,7 @@ namespace Renci.SshNet.Security.Cryptography
*/
uint Li = L0, Ri = R0;
for (int i = 1; i<=_rounds ; i++)
for (int i = 1; i <= _rounds; i++)
{
Lp = Li;
Rp = Ri;
@@ -600,24 +652,24 @@ namespace Renci.SshNet.Security.Cryptography
Li = Rp;
switch (i)
{
case 1:
case 4:
case 7:
case 1:
case 4:
case 7:
case 10:
case 13:
case 16:
Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
break;
case 2:
case 5:
case 8:
case 2:
case 5:
case 8:
case 11:
case 14:
Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
break;
case 3:
case 6:
case 9:
case 3:
case 6:
case 9:
case 12:
case 15:
Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
@@ -631,7 +683,7 @@ namespace Renci.SshNet.Security.Cryptography
return;
}
internal void CAST_Decipher(uint L16, uint R16, uint[] result)
private void CastDecipher(uint L16, uint R16, uint[] result)
{
uint Lp = L16; // the previous value, equiv to L[i-1]
uint Rp = R16; // equivalent to R[i-1]
@@ -650,24 +702,24 @@ namespace Renci.SshNet.Security.Cryptography
Li = Rp;
switch (i)
{
case 1:
case 4:
case 7:
case 1:
case 4:
case 7:
case 10:
case 13:
case 16:
Ri = Lp ^ F1(Rp, _Km[i], _Kr[i]);
break;
case 2:
case 5:
case 8:
case 2:
case 5:
case 8:
case 11:
case 14:
Ri = Lp ^ F2(Rp, _Km[i], _Kr[i]);
break;
case 3:
case 6:
case 9:
case 3:
case 6:
case 9:
case 12:
case 15:
Ri = Lp ^ F3(Rp, _Km[i], _Kr[i]);
@@ -681,20 +733,21 @@ namespace Renci.SshNet.Security.Cryptography
return;
}
internal static void Bits32ToInts(uint inData, int[] b, int offset)
private static void Bits32ToInts(uint inData, int[] b, int offset)
{
b[offset + 3] = (int) (inData & 0xff);
b[offset + 2] = (int) ((inData >> 8) & 0xff);
b[offset + 1] = (int) ((inData >> 16) & 0xff);
b[offset] = (int) ((inData >> 24) & 0xff);
b[offset + 3] = (int)(inData & 0xff);
b[offset + 2] = (int)((inData >> 8) & 0xff);
b[offset + 1] = (int)((inData >> 16) & 0xff);
b[offset] = (int)((inData >> 24) & 0xff);
}
internal static uint IntsTo32bits(int[] b, int i)
private static uint IntsTo32bits(int[] b, int i)
{
return (uint)(((b[i] & 0xff) << 24) |
((b[i+1] & 0xff) << 16) |
((b[i+2] & 0xff) << 8) |
((b[i+3] & 0xff)));
return (uint)(((b[i] & 0xff) << 24) |
((b[i + 1] & 0xff) << 16) |
((b[i + 2] & 0xff) << 8) |
((b[i + 3] & 0xff)));
}
}
}
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
/// <summary>
/// Base class for cipher mode implementations
/// </summary>
public abstract class CipherMode
{
/// <summary>
/// Gets the cipher.
/// </summary>
protected BlockCipher Cipher { get; private set; }
/// <summary>
/// Gets the IV vector.
/// </summary>
protected byte[] IV { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="CipherMode"/> class.
/// </summary>
/// <param name="iv">The iv.</param>
protected CipherMode(byte[] iv)
{
this.IV = iv;
}
/// <summary>
/// Inits the specified cipher.
/// </summary>
/// <param name="cipher">The cipher.</param>
internal void Init(BlockCipher cipher)
{
this.Cipher = cipher;
this.IV = this.IV.Take(cipher.BlockSize).ToArray();
}
/// <summary>
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to encrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes encrypted.
/// </returns>
public abstract int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
/// <summary>
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to decrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes decrypted.
/// </returns>
public abstract int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
/// <summary>
/// Base class for cipher padding implementations
/// </summary>
public abstract class CipherPadding
{
/// <summary>
/// Pads specified input to match block size.
/// </summary>
/// <param name="blockSize">Size of the block.</param>
/// <param name="input">The input.</param>
/// <returns></returns>
public abstract byte[] Pad(int blockSize, byte[] input);
}
}
@@ -2,47 +2,27 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
/// <summary>
/// Represents the class for the DES algorithm.
/// </summary>
public class DesCipher : CipherBase
/// <summary>
/// Implements DES cipher algorithm.
/// </summary>
public class DesCipher : BlockCipher
{
private int[] _encryptionKey;
private readonly int[] _encryptionKey;
private readonly int[] _decryptionKey;
/// <summary>
/// Gets the encryption key.
/// Gets the size of the block in bytes.
/// </summary>
protected int[] EncryptionKey
/// <value>
/// The size of the block in bytes.
/// </value>
public override int BlockSize
{
get
{
if (this._encryptionKey == null)
{
this._encryptionKey = DesCipher.GenerateWorkingKey(true, this.Key);
}
return this._encryptionKey;
}
}
private int[] _decryptionKey;
/// <summary>
/// Gets the decryption key.
/// </summary>
protected int[] DecryptionKey
{
get
{
if (this._decryptionKey == null)
{
this._decryptionKey = DesCipher.GenerateWorkingKey(true, this.Key);
}
return this._decryptionKey;
}
get { return 8; }
}
#region Static tables
@@ -249,25 +229,17 @@ namespace Renci.SshNet.Security.Cryptography
#endregion
/// <summary>
/// Gets the size of the block.
/// </summary>
/// <value>
/// The size of the block.
/// </value>
public override int BlockSize
{
get { return 8; }
}
/// <summary>
/// Initializes a new instance of the <see cref="DesCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="iv">The iv.</param>
public DesCipher(byte[] key, byte[] iv)
: base(key, iv)
/// <param name="mode">The mode.</param>
/// <param name="padding">The padding.</param>
public DesCipher(byte[] key, CipherMode mode, CipherPadding padding)
: base(key, mode, padding)
{
this._encryptionKey = GenerateWorkingKey(true, key);
this._decryptionKey = GenerateWorkingKey(false, key);
}
/// <summary>
@@ -289,7 +261,7 @@ namespace Renci.SshNet.Security.Cryptography
if ((outputOffset + this.BlockSize) > outputBuffer.Length)
throw new IndexOutOfRangeException("output buffer too short");
DesCipher.DesFunc(this.EncryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
DesCipher.DesFunc(this._encryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
return this.BlockSize;
}
@@ -313,9 +285,25 @@ namespace Renci.SshNet.Security.Cryptography
if ((outputOffset + this.BlockSize) > outputBuffer.Length)
throw new IndexOutOfRangeException("output buffer too short");
DesCipher.DesFunc(this.DecryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
DesCipher.DesFunc(this._decryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset);
return this.BlockSize;
throw new NotImplementedException();
}
/// <summary>
/// Validates the size of the key.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <returns>
/// true if keySize is valid; otherwise false
/// </returns>
protected override bool ValidateKeySize(int keySize)
{
if (keySize == 56)
return true;
else
return false;
}
/// <summary>
@@ -427,8 +415,8 @@ namespace Renci.SshNet.Security.Cryptography
/// <param name="outOff">The out off.</param>
protected static void DesFunc(int[] wKey, byte[] input, int inOff, byte[] outBytes, int outOff)
{
uint left = CipherBase.BigEndianToUInt32(input, inOff);
uint right = CipherBase.BigEndianToUInt32(input, inOff + 4);
uint left = BigEndianToUInt32(input, inOff);
uint right = BigEndianToUInt32(input, inOff + 4);
uint work;
work = ((left >> 4) ^ right) & 0x0f0f0f0f;
@@ -497,10 +485,8 @@ namespace Renci.SshNet.Security.Cryptography
left ^= work;
right ^= (work << 4);
CipherBase.UInt32ToBigEndian(right, outBytes, outOff);
CipherBase.UInt32ToBigEndian(left, outBytes, outOff + 4);
UInt32ToBigEndian(right, outBytes, outOff);
UInt32ToBigEndian(left, outBytes, outOff + 4);
}
}
}
@@ -4,40 +4,20 @@ using System.Linq;
using System.Text;
using System.Globalization;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes
{
/// <summary>
/// Represents the class for the CBC Block Cipher.
/// Implements CBC cipher mode
/// </summary>
public class CbcMode : ModeBase
public class CbcCipherMode : CipherMode
{
private byte[] _iv;
private byte[] _nextIV;
private int _blockSize;
/// <summary>
/// Gets the size of the block.
/// Initializes a new instance of the <see cref="CbcCipherMode"/> class.
/// </summary>
/// <value>
/// The size of the block.
/// </value>
public override int BlockSize
/// <param name="iv">The iv.</param>
public CbcCipherMode(byte[] iv)
: base(iv)
{
get { return this._blockSize; }
}
/// <summary>
/// Initializes a new instance of the <see cref="CbcMode"/> class.
/// </summary>
/// <param name="cipher">The cipher.</param>
public CbcMode(CipherBase cipher)
: base(cipher)
{
this._blockSize = cipher.BlockSize;
this._iv = cipher.IV.Take(this._blockSize).ToArray();
this._nextIV = new byte[this._iv.Length];
}
/// <summary>
@@ -53,25 +33,25 @@ namespace Renci.SshNet.Security.Cryptography
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer.Length - inputOffset < this._blockSize)
if (inputBuffer.Length - inputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid input buffer");
if (outputBuffer.Length - outputOffset < this._blockSize)
if (outputBuffer.Length - outputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid output buffer");
if (inputCount != this._blockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this._blockSize));
if (inputCount != this.Cipher.BlockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this.Cipher.BlockSize));
for (int i = 0; i < this._blockSize; i++)
for (int i = 0; i < this.Cipher.BlockSize; i++)
{
this._iv[i] ^= inputBuffer[inputOffset + i];
this.IV[i] ^= inputBuffer[inputOffset + i];
}
this.Cipher.EncryptBlock(this._iv, 0, inputCount, outputBuffer, outputOffset);
this.Cipher.EncryptBlock(this.IV, 0, inputCount, outputBuffer, outputOffset);
Array.Copy(outputBuffer, outputOffset, this._iv, 0, this._iv.Length);
Array.Copy(outputBuffer, outputOffset, this.IV, 0, this.IV.Length);
return this._blockSize;
return this.Cipher.BlockSize;
}
/// <summary>
@@ -87,28 +67,25 @@ namespace Renci.SshNet.Security.Cryptography
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer.Length - inputOffset < this._blockSize)
if (inputBuffer.Length - inputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid input buffer");
if (outputBuffer.Length - outputOffset < this._blockSize)
if (outputBuffer.Length - outputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid output buffer");
if (inputCount != this._blockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this._blockSize));
Array.Copy(inputBuffer, inputOffset, this._nextIV, 0, this._nextIV.Length);
if (inputCount != this.Cipher.BlockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this.Cipher.BlockSize));
this.Cipher.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
for (int i = 0; i < this._blockSize; i++)
for (int i = 0; i < this.Cipher.BlockSize; i++)
{
outputBuffer[outputOffset + i] ^= this._iv[i];
outputBuffer[outputOffset + i] ^= this.IV[i];
}
Array.Copy(this._nextIV, 0, this._iv, 0, this._nextIV.Length);
Array.Copy(inputBuffer, inputOffset, this.IV, 0, this.IV.Length);
return this._blockSize;
return this.Cipher.BlockSize;
}
}
}
@@ -4,40 +4,23 @@ using System.Linq;
using System.Text;
using System.Globalization;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes
{
/// <summary>
/// Represents the class for the OFB Block Cipher.
/// Implements CFB cipher mode
/// </summary>
public class OfbMode : ModeBase
public class CfbCipherMode : CipherMode
{
private readonly byte[] _iv;
private readonly byte[] _ivOutput;
private int _blockSize;
/// <summary>
/// Gets the size of the block.
/// Initializes a new instance of the <see cref="CfbCipherMode"/> class.
/// </summary>
/// <value>
/// The size of the block.
/// </value>
public override int BlockSize
/// <param name="iv">The iv.</param>
public CfbCipherMode(byte[] iv)
: base(iv)
{
get { return this._blockSize; }
}
/// <summary>
/// Initializes a new instance of the <see cref="OfbMode"/> class.
/// </summary>
/// <param name="cipher">The cipher.</param>
public OfbMode(CipherBase cipher)
: base(cipher)
{
this._blockSize = cipher.BlockSize;
this._iv = cipher.IV.ToArray();
this._ivOutput = new byte[this._iv.Length];
this._ivOutput = new byte[iv.Length];
}
/// <summary>
@@ -53,26 +36,26 @@ namespace Renci.SshNet.Security.Cryptography
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer.Length - inputOffset < this._blockSize)
if (inputBuffer.Length - inputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid input buffer");
if (outputBuffer.Length - outputOffset < this._blockSize)
if (outputBuffer.Length - outputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid output buffer");
if (inputCount != this._blockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this._blockSize));
if (inputCount != this.Cipher.BlockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this.Cipher.BlockSize));
this.Cipher.EncryptBlock(this._iv, 0, this._iv.Length, this._ivOutput, 0);
this.Cipher.EncryptBlock(this.IV, 0, this.IV.Length, this._ivOutput, 0);
for (int i = 0; i < this._blockSize; i++)
for (int i = 0; i < this.Cipher.BlockSize; i++)
{
outputBuffer[outputOffset + i] = (byte)(this._ivOutput[i] ^ inputBuffer[inputOffset + i]);
}
Array.Copy(this._iv, this._blockSize, this._iv, 0, this._iv.Length - this._blockSize);
Array.Copy(outputBuffer, outputOffset, this._iv, this._iv.Length - this._blockSize, this._blockSize);
Array.Copy(this.IV, this.Cipher.BlockSize, this.IV, 0, this.IV.Length - this.Cipher.BlockSize);
Array.Copy(outputBuffer, outputOffset, this.IV, this.IV.Length - this.Cipher.BlockSize, this.Cipher.BlockSize);
return this._blockSize;
return this.Cipher.BlockSize;
}
/// <summary>
@@ -88,26 +71,26 @@ namespace Renci.SshNet.Security.Cryptography
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer.Length - inputOffset < this._blockSize)
if (inputBuffer.Length - inputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid input buffer");
if (outputBuffer.Length - outputOffset < this._blockSize)
if (outputBuffer.Length - outputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid output buffer");
if (inputCount != this._blockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this._blockSize));
if (inputCount != this.Cipher.BlockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this.Cipher.BlockSize));
this.Cipher.EncryptBlock(this._iv, 0, this._iv.Length, this._ivOutput, 0);
this.Cipher.EncryptBlock(this.IV, 0, this.IV.Length, this._ivOutput, 0);
for (int i = 0; i < this._blockSize; i++)
Array.Copy(this.IV, this.Cipher.BlockSize, this.IV, 0, this.IV.Length - this.Cipher.BlockSize);
Array.Copy(inputBuffer, inputOffset, this.IV, this.IV.Length - this.Cipher.BlockSize, this.Cipher.BlockSize);
for (int i = 0; i < this.Cipher.BlockSize; i++)
{
outputBuffer[outputOffset + i] = (byte)(this._ivOutput[i] ^ inputBuffer[inputOffset + i]);
}
Array.Copy(this._iv, this._blockSize, this._iv, 0, this._iv.Length - this._blockSize);
Array.Copy(outputBuffer, outputOffset, this._iv, this._iv.Length - this._blockSize, this._blockSize);
return this._blockSize;
return this.Cipher.BlockSize;
}
}
}
@@ -2,43 +2,25 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Globalization;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes
{
/// <summary>
/// Represents the class for the CFB Block Cipher.
/// Implements CTR cipher mode
/// </summary>
public class CfbMode : ModeBase
public class CtrCipherMode : CipherMode
{
private readonly byte[] _iv;
private readonly byte[] _ivOutput;
private int _blockSize;
/// <summary>
/// Gets the size of the block.
/// Initializes a new instance of the <see cref="CtrCipherMode"/> class.
/// </summary>
/// <value>
/// The size of the block.
/// </value>
public override int BlockSize
/// <param name="iv">The iv.</param>
public CtrCipherMode(byte[] iv)
: base(iv)
{
get { return this._blockSize; }
}
/// <summary>
/// Initializes a new instance of the <see cref="CfbMode"/> class.
/// </summary>
/// <param name="cipher">The cipher.</param>
public CfbMode(CipherBase cipher)
: base(cipher)
{
this._blockSize = cipher.BlockSize;
this._iv = cipher.IV.ToArray();
this._ivOutput = new byte[this._iv.Length];
this._ivOutput = new byte[iv.Length];
}
/// <summary>
@@ -54,26 +36,26 @@ namespace Renci.SshNet.Security.Cryptography
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer.Length - inputOffset < this._blockSize)
if (inputBuffer.Length - inputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid input buffer");
if (outputBuffer.Length - outputOffset < this._blockSize)
if (outputBuffer.Length - outputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid output buffer");
if (inputCount != this._blockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this._blockSize));
if (inputCount != this.Cipher.BlockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this.Cipher.BlockSize));
this.Cipher.EncryptBlock(this._iv, 0, this._iv.Length, this._ivOutput, 0);
this.Cipher.EncryptBlock(this.IV, 0, this.IV.Length, this._ivOutput, 0);
for (int i = 0; i < this._blockSize; i++)
for (int i = 0; i < this.Cipher.BlockSize; i++)
{
outputBuffer[outputOffset + i] = (byte)(this._ivOutput[i] ^ inputBuffer[inputOffset + i]);
}
Array.Copy(this._iv, this._blockSize, this._iv, 0, this._iv.Length - this._blockSize);
Array.Copy(outputBuffer, outputOffset, this._iv, this._iv.Length - this._blockSize, this._blockSize);
int j = this.IV.Length;
while (--j >= 0 && ++this.IV[j] == 0) ;
return this._blockSize;
return this.Cipher.BlockSize;
}
/// <summary>
@@ -89,26 +71,26 @@ namespace Renci.SshNet.Security.Cryptography
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer.Length - inputOffset < this._blockSize)
if (inputBuffer.Length - inputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid input buffer");
if (outputBuffer.Length - outputOffset < this._blockSize)
if (outputBuffer.Length - outputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid output buffer");
if (inputCount != this._blockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this._blockSize));
if (inputCount != this.Cipher.BlockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this.Cipher.BlockSize));
this.Cipher.EncryptBlock(this._iv, 0, this._iv.Length, this._ivOutput, 0);
this.Cipher.EncryptBlock(this.IV, 0, this.IV.Length, this._ivOutput, 0);
Array.Copy(this._iv, this._blockSize, this._iv, 0, this._iv.Length - this._blockSize);
Array.Copy(inputBuffer, inputOffset, this._iv, this._iv.Length - this._blockSize, this._blockSize);
for (int i = 0; i < this._blockSize; i++)
for (int i = 0; i < this.Cipher.BlockSize; i++)
{
outputBuffer[outputOffset + i] = (byte)(this._ivOutput[i] ^ inputBuffer[inputOffset + i]);
}
return this._blockSize;
int j = this.IV.Length;
while (--j >= 0 && ++this.IV[j] == 0) ;
return this.Cipher.BlockSize;
}
}
}
@@ -2,42 +2,26 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Renci.SshNet.Security.Cryptography.Ciphers;
using System.Globalization;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes
{
/// <summary>
/// Represents the class for the CTR Block Cipher.
/// Implements OFB cipher mode
/// </summary>
public class CtrMode : ModeBase
public class OfbCipherMode : CipherMode
{
private readonly byte[] _iv;
private readonly byte[] _ivOutput;
private int _blockSize;
/// <summary>
/// Gets the size of the block.
/// Initializes a new instance of the <see cref="OfbCipherMode"/> class.
/// </summary>
/// <value>
/// The size of the block.
/// </value>
public override int BlockSize
/// <param name="iv">The iv.</param>
public OfbCipherMode(byte[] iv)
: base(iv)
{
get { return this._blockSize; }
}
/// <summary>
/// Initializes a new instance of the <see cref="CtrMode"/> class.
/// </summary>
/// <param name="cipher">The cipher.</param>
public CtrMode(CipherBase cipher)
: base(cipher)
{
this._blockSize = cipher.BlockSize;
this._iv = cipher.IV.ToArray();
this._ivOutput = new byte[this._iv.Length];
this._ivOutput = new byte[iv.Length];
}
/// <summary>
@@ -53,26 +37,26 @@ namespace Renci.SshNet.Security.Cryptography
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer.Length - inputOffset < this._blockSize)
if (inputBuffer.Length - inputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid input buffer");
if (outputBuffer.Length - outputOffset < this._blockSize)
if (outputBuffer.Length - outputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid output buffer");
if (inputCount != this._blockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this._blockSize));
if (inputCount != this.Cipher.BlockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this.Cipher.BlockSize));
this.Cipher.EncryptBlock(this._iv, 0, this._iv.Length, this._ivOutput, 0);
this.Cipher.EncryptBlock(this.IV, 0, this.IV.Length, this._ivOutput, 0);
for (int i = 0; i < this._blockSize; i++)
for (int i = 0; i < this.Cipher.BlockSize; i++)
{
outputBuffer[outputOffset + i] = (byte)(this._ivOutput[i] ^ inputBuffer[inputOffset + i]);
}
int j = this._iv.Length;
while (--j >= 0 && ++this._iv[j] == 0) ;
Array.Copy(this.IV, this.Cipher.BlockSize, this.IV, 0, this.IV.Length - this.Cipher.BlockSize);
Array.Copy(outputBuffer, outputOffset, this.IV, this.IV.Length - this.Cipher.BlockSize, this.Cipher.BlockSize);
return this._blockSize;
return this.Cipher.BlockSize;
}
/// <summary>
@@ -88,26 +72,28 @@ namespace Renci.SshNet.Security.Cryptography
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
if (inputBuffer.Length - inputOffset < this._blockSize)
if (inputBuffer.Length - inputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid input buffer");
if (outputBuffer.Length - outputOffset < this._blockSize)
if (outputBuffer.Length - outputOffset < this.Cipher.BlockSize)
throw new ArgumentException("Invalid output buffer");
if (inputCount != this._blockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this._blockSize));
if (inputCount != this.Cipher.BlockSize)
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", this.Cipher.BlockSize));
this.Cipher.EncryptBlock(this._iv, 0, this._iv.Length, this._ivOutput, 0);
this.Cipher.EncryptBlock(this.IV, 0, this.IV.Length, this._ivOutput, 0);
for (int i = 0; i < this._blockSize; i++)
for (int i = 0; i < this.Cipher.BlockSize; i++)
{
outputBuffer[outputOffset + i] = (byte)(this._ivOutput[i] ^ inputBuffer[inputOffset + i]);
}
int j = this._iv.Length;
while (--j >= 0 && ++this._iv[j] == 0) ;
Array.Copy(this.IV, this.Cipher.BlockSize, this.IV, 0, this.IV.Length - this.Cipher.BlockSize);
Array.Copy(outputBuffer, outputOffset, this.IV, this.IV.Length - this.Cipher.BlockSize, this.Cipher.BlockSize);
return this._blockSize;
return this.Cipher.BlockSize;
}
}
}
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography.Ciphers.Paddings
{
/// <summary>
/// Implements PKCS7 cipher padding
/// </summary>
public class PKCS7Padding : CipherPadding
{
/// <summary>
/// Transforms the specified input.
/// </summary>
/// <param name="blockSize"></param>
/// <param name="input">The input.</param>
/// <returns></returns>
public override byte[] Pad(int blockSize, byte[] input)
{
var numOfPaddedBytes = blockSize - (input.Length % blockSize);
var output = new byte[input.Length + numOfPaddedBytes];
Array.Copy(input, output, input.Length);
for (int i = 0; i < numOfPaddedBytes; i++)
{
output[input.Length + i] = output[input.Length - 1];
}
return output;
}
}
}
@@ -0,0 +1,140 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using Renci.SshNet.Common;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
/// <summary>
/// Implements RSA cipher algorithm.
/// </summary>
public class RsaCipher : AsymmetricCipher
{
private static RNGCryptoServiceProvider _randomizer = new System.Security.Cryptography.RNGCryptoServiceProvider();
private bool _isPrivate;
private BigInteger _exponent;
private BigInteger _modulus;
private BigInteger _d;
private BigInteger _dp;
private BigInteger _dq;
private BigInteger _inverseQ;
private BigInteger _p;
private BigInteger _q;
/// <summary>
/// Initializes a new instance of the <see cref="RsaCipher"/> class.
/// </summary>
/// <param name="exponent">The exponent.</param>
/// <param name="modulus">The modulus.</param>
public RsaCipher(BigInteger exponent, BigInteger modulus)
{
//if (key == null)
// throw new ArgumentNullException("key");
//this._publicKey = key;
this._exponent = exponent;
this._modulus = modulus;
this._isPrivate = false;
}
/// <summary>
/// Initializes a new instance of the <see cref="RsaCipher"/> class.
/// </summary>
/// <param name="exponent">The exponent.</param>
/// <param name="modulus">The modulus.</param>
/// <param name="d">The d.</param>
/// <param name="dp">The dp.</param>
/// <param name="dq">The dq.</param>
/// <param name="inverseQ">The inverse Q.</param>
/// <param name="p">The p.</param>
/// <param name="q">The q.</param>
public RsaCipher(BigInteger exponent, BigInteger modulus, BigInteger d, BigInteger dp, BigInteger dq, BigInteger inverseQ, BigInteger p, BigInteger q)
{
//if (key == null)
// throw new ArgumentNullException("key");
//this._privateKey = key;
this._exponent = exponent;
this._modulus = modulus;
this._d = d;
this._dp = dp;
this._dq = dq;
this._inverseQ = inverseQ;
this._p = p;
this._q = q;
this._isPrivate = true;
}
/// <summary>
/// Encrypts the specified data.
/// </summary>
/// <param name="data">The data.</param>
/// <returns></returns>
public override byte[] Encrypt(byte[] data)
{
return this.Transform(data);
}
/// <summary>
/// Decrypts the specified data.
/// </summary>
/// <param name="data">The data.</param>
/// <returns></returns>
public override byte[] Decrypt(byte[] data)
{
return this.Transform(data);
}
private byte[] Transform(byte[] data)
{
var bytes = new List<byte>(data.Reverse());
bytes.Add(0);
var input = new BigInteger(bytes.ToArray());
BigInteger result;
if (this._isPrivate)
{
BigInteger random = BigInteger.One;
var max = this._modulus - 1;
while (random <= BigInteger.One || random >= max)
{
var bytesArray = new byte[256];
_randomizer.GetBytes(bytesArray);
bytesArray[bytesArray.Length - 1] = (byte)(bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value
random = new BigInteger(bytesArray.Reverse().ToArray());
}
BigInteger blindedInput = BigInteger.PositiveMod((BigInteger.ModPow(random, this._exponent, this._modulus) * input), this._modulus);
// mP = ((input Mod p) ^ dP)) Mod p
var mP = BigInteger.ModPow((blindedInput % this._p), this._dp, this._p);
// mQ = ((input Mod q) ^ dQ)) Mod q
var mQ = BigInteger.ModPow((blindedInput % this._q), this._dq, this._q);
var h = BigInteger.PositiveMod(((mP - mQ) * this._inverseQ), this._p);
var m = h * this._q + mQ;
BigInteger rInv = BigInteger.ModInverse(random, this._modulus);
result = BigInteger.PositiveMod((m * rInv), this._modulus);
}
else
{
result = BigInteger.ModPow(input, this._exponent, this._modulus);
}
return result.ToByteArray().Reverse().ToArray();
}
}
}
File diff suppressed because it is too large Load Diff
@@ -2,12 +2,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace Renci.SshNet.Security.Cryptography
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
/// <summary>
/// Represents the class for the 3DES algorithm.
/// Implements 3DES cipher algorithm.
/// </summary>
public class TripleDesCipher : DesCipher
{
@@ -23,9 +22,10 @@ namespace Renci.SshNet.Security.Cryptography
/// Initializes a new instance of the <see cref="TripleDesCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="iv">The iv.</param>
public TripleDesCipher(byte[] key, byte[] iv)
: base(key, iv)
/// <param name="mode">The mode.</param>
/// <param name="padding">The padding.</param>
public TripleDesCipher(byte[] key, CipherMode mode, CipherPadding padding)
: base(key, mode, padding)
{
var part1 = new byte[8];
var part2 = new byte[8];
@@ -39,7 +39,7 @@ namespace Renci.SshNet.Security.Cryptography
this._encryptionKey2 = GenerateWorkingKey(false, part2);
this._decryptionKey2 = GenerateWorkingKey(true, part2);
if (this.Key.Length == 24)
if (key.Length == 24)
{
var part3 = new byte[8];
Array.Copy(key, 16, part3, 0, 8);
@@ -52,6 +52,7 @@ namespace Renci.SshNet.Security.Cryptography
this._encryptionKey3 = this._encryptionKey1;
this._decryptionKey3 = this._decryptionKey1;
}
}
/// <summary>
@@ -109,5 +110,20 @@ namespace Renci.SshNet.Security.Cryptography
return this.BlockSize;
}
/// <summary>
/// Validates the size of the key.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <returns>
/// true if keySize is valid; otherwise false
/// </returns>
protected override bool ValidateKeySize(int keySize)
{
if (keySize == 128 || keySize == 128 + 64)
return true;
else
return false;
}
}
}
@@ -5,16 +5,33 @@ using System.Text;
namespace Renci.SshNet.Security.Cryptography.Ciphers
{
internal class TwofishCipher : CipherBase
{
/// <summary>
/// Implements Twofish cipher algorithm
/// </summary>
public class TwofishCipher : BlockCipher
{
/// <summary>
/// Gets the size of the block in bytes.
/// </summary>
/// <value>
/// The size of the block in bytes.
/// </value>
public override int BlockSize
{
get { return 16; }
}
public TwofishCipher(byte[] key, byte[] iv)
: base(key, iv)
{
/// <summary>
/// Initializes a new instance of the <see cref="TwofishCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="mode">The mode.</param>
/// <param name="padding">The padding.</param>
public TwofishCipher(byte[] key, CipherMode mode, CipherPadding padding)
: base(key, mode, padding)
{
// TODO: Refactor this algorithm
// calculate the MDS matrix
int[] m1 = new int[2];
int[] mX = new int[2];
@@ -48,9 +65,19 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
this.k64Cnt = (key.Length / 8); // pre-padded ?
this.SetKey(key);
}
}
/// <summary>
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to encrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes encrypted.
/// </returns>
public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
int x0 = BytesTo32Bits(inputBuffer, inputOffset) ^ gSubKeys[INPUT_WHITEN];
@@ -83,6 +110,17 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
return this.BlockSize;
}
/// <summary>
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to decrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes decrypted.
/// </returns>
public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
int x2 = BytesTo32Bits(inputBuffer, inputOffset) ^ gSubKeys[OUTPUT_WHITEN];
@@ -115,6 +153,21 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
return this.BlockSize;
}
/// <summary>
/// Validates the size of the key.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <returns>
/// true if keySize is valid; otherwise false
/// </returns>
protected override bool ValidateKeySize(int keySize)
{
if (keySize == 128 || keySize == 192 || keySize == 256)
return true;
else
return false;
}
#region Static Definition Tables
private static readonly byte[,] P = {
@@ -580,6 +633,5 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers
b[offset + 2] = (byte)(inData >> 16);
b[offset + 3] = (byte)(inData >> 24);
}
}
}
@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using Renci.SshNet.Common;
using System.Globalization;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Implements DSA digital signature algorithm.
/// </summary>
public class DsaDigitalSignature : DigitalSignature
{
private BigInteger _p;
private BigInteger _q;
private BigInteger _g;
private BigInteger _privateKey;
private BigInteger _publicKey;
private HashAlgorithm _hash;
/// <summary>
/// Initializes a new instance of the <see cref="DsaDigitalSignature"/> class.
/// </summary>
/// <param name="p">The p.</param>
/// <param name="q">The q.</param>
/// <param name="g">The g.</param>
/// <param name="privateKey">The private key.</param>
/// <param name="publicKey">The public key.</param>
public DsaDigitalSignature(byte[] p, byte[] q, byte[] g, byte[] privateKey, byte[] publicKey)
{
this._p = new BigInteger(p.Reverse().ToArray());
this._q = new BigInteger(q.Reverse().ToArray());
this._g = new BigInteger(g.Reverse().ToArray());
if (privateKey != null)
this._privateKey = new BigInteger(privateKey.Reverse().ToArray());
if (publicKey != null)
this._publicKey = new BigInteger(publicKey.Reverse().ToArray());
this._hash = new SHA1Hash();
}
/// <summary>
/// Verifies the signature.
/// </summary>
/// <param name="input">The input.</param>
/// <param name="signature">The signature.</param>
/// <returns></returns>
public override bool VerifySignature(byte[] input, byte[] signature)
{
var hashInput = this._hash.ComputeHash(input);
BigInteger hm = new BigInteger(hashInput.Reverse().Concat(new byte[] { 0 }).ToArray());
if (signature.Length != 40)
throw new InvalidOperationException("Invalid signature.");
// Extract r and s numbers from the signature
var rBytes = new byte[21];
var sBytes = new byte[21];
for (int i = 0, j = 20; i < 20; i++, j--)
{
rBytes[i] = signature[j - 1];
sBytes[i] = signature[j + 20 - 1];
}
BigInteger r = new BigInteger(rBytes);
BigInteger s = new BigInteger(sBytes);
// Reject the signature if 0 < r < q or 0 < s < q is not satisfied.
if (r <= 0 || r >= this._q)
return false;
if (s <= 0 || s >= this._q)
return false;
// Calculate w = s1 mod q
BigInteger w = BigInteger.ModInverse(s, this._q);
// Calculate u1 = H(m)·w mod q
BigInteger u1 = hm * w % this._q;
// Calculate u2 = r * w mod q
BigInteger u2 = r * w % this._q;
u1 = BigInteger.ModPow(this._g, u1, this._p);
u2 = BigInteger.ModPow(this._publicKey, u2, this._p);
// Calculate v = ((g pow u1 * y pow u2) mod p) mod q
BigInteger v = ((u1 * u2) % this._p) % this._q;
// The signature is valid if v = r
return v == r;
}
/// <summary>
/// Creates the signature.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
public override byte[] CreateSignature(byte[] input)
{
var hashInput = this._hash.ComputeHash(input);
BigInteger m = new BigInteger(hashInput.Reverse().Concat(new byte[] { 0 }).ToArray());
BigInteger s = BigInteger.Zero;
BigInteger r = BigInteger.Zero;
do
{
BigInteger k;
do
{
// TODO: Take random function to base class
// Generate a random per-message value k where 0 < k < q
do
{
//k = new BigInteger(q.BitLength, random);
k = BigInteger.Parse("980263959677973875983479554308083464979482795347", System.Globalization.NumberStyles.None, CultureInfo.InvariantCulture);
}
while (k <= 0 || k >= this._q);
// Calculate r = ((g pow k) mod p) mod q
r = BigInteger.ModPow(this._g, k, this._p) % this._q;
// In the unlikely case that r = 0, start again with a different random k
} while (r.IsZero);
// Calculate s = ((k pow 1)(H(m) + x*r)) mod q
k = (BigInteger.ModInverse(k, this._q) * (m + this._privateKey * r));
s = k % this._q;
// In the unlikely case that s = 0, start again with a different random k
} while (s.IsZero);
// The signature is (r, s)
return r.ToByteArray().Reverse().TrimLeadingZero().Concat(s.ToByteArray().Reverse().TrimLeadingZero()).ToArray();
}
}
}
@@ -10,7 +10,7 @@ namespace Renci.SshNet.Security.Cryptography
/// Provides HMAC algorithm implementation.
/// </summary>
/// <typeparam name="T"></typeparam>
public class HMAC<T> : KeyedHashAlgorithm where T : HashAlgorithm, new()
public class HMac<T> : KeyedHashAlgorithm where T : HashAlgorithm, new()
{
private HashAlgorithm _hash;
private bool _isHashing;
@@ -35,7 +35,7 @@ namespace Renci.SshNet.Security.Cryptography
/// Rfc 2104.
/// </summary>
/// <param name="key">The key.</param>
public HMAC(byte[] key)
public HMac(byte[] key)
{
// Create the hash algorithms.
this._hash = new T();
@@ -0,0 +1,383 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// MD5 algorithm implementation
/// </summary>
public class MD5Hash : HashAlgorithm
{
private byte[] _buffer = new byte[4];
private int _bufferOffset;
private long _byteCount;
private int H1, H2, H3, H4; // IV's
private int[] _hashValue = new int[16];
private int _offset;
/// <summary>
/// Gets the size, in bits, of the computed hash code.
/// </summary>
/// <returns>The size, in bits, of the computed hash code.</returns>
public override int HashSize
{
get
{
return 128;
}
}
/// <summary>
/// Gets the input block size.
/// </summary>
/// <returns>The input block size.</returns>
public override int InputBlockSize
{
get
{
return 64;
}
}
/// <summary>
/// Gets the output block size.
/// </summary>
/// <returns>The output block size.</returns>
public override int OutputBlockSize
{
get
{
return 64;
}
}
/// <summary>
/// Gets a value indicating whether the current transform can be reused.
/// </summary>
/// <returns>Always true.</returns>
public override bool CanReuseTransform
{
get
{
return true;
}
}
/// <summary>
/// Gets a value indicating whether multiple blocks can be transformed.
/// </summary>
/// <returns>true if multiple blocks can be transformed; otherwise, false.</returns>
public override bool CanTransformMultipleBlocks
{
get
{
return true;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="MD5Hash"/> class.
/// </summary>
public MD5Hash()
{
this.Initialize();
}
/// <summary>
/// Routes data written to the object into the hash algorithm for computing the hash.
/// </summary>
/// <param name="array">The input to compute the hash code for.</param>
/// <param name="ibStart">The offset into the byte array from which to begin using data.</param>
/// <param name="cbSize">The number of bytes in the byte array to use as data.</param>
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
// Fill the current word
while ((this._bufferOffset != 0) && (cbSize > 0))
{
this.Update(array[ibStart]);
ibStart++;
cbSize--;
}
// Process whole words.
while (cbSize > this._buffer.Length)
{
this.ProcessWord(array, ibStart);
ibStart += this._buffer.Length;
cbSize -= this._buffer.Length;
this._byteCount += this._buffer.Length;
}
// Load in the remainder.
while (cbSize > 0)
{
this.Update(array[ibStart]);
ibStart++;
cbSize--;
}
}
/// <summary>
/// Finalizes the hash computation after the last data is processed by the cryptographic stream object.
/// </summary>
/// <returns>
/// The computed hash code.
/// </returns>
protected override byte[] HashFinal()
{
long bitLength = (this._byteCount << 3);
// Add the pad bytes.
this.Update((byte)128);
while (this._bufferOffset != 0)
this.Update((byte)0);
if (this._offset > 14)
{
this.ProcessBlock();
}
this._hashValue[14] = (int)(bitLength & 0xffffffff);
this._hashValue[15] = (int)((ulong)bitLength >> 32);
this.ProcessBlock();
var output = new byte[16];
this.UnpackWord(H1, output, 0);
this.UnpackWord(H2, output, 0 + 4);
this.UnpackWord(H3, output, 0 + 8);
this.UnpackWord(H4, output, 0 + 12);
this.Initialize();
return output;
}
/// <summary>
/// Initializes an implementation of the <see cref="T:System.Security.Cryptography.HashAlgorithm"/> class.
/// </summary>
public override void Initialize()
{
this._byteCount = 0;
this._bufferOffset = 0;
Array.Clear(this._buffer, 0, this._buffer.Length);
H1 = unchecked((int)0x67452301);
H2 = unchecked((int)0xefcdab89);
H3 = unchecked((int)0x98badcfe);
H4 = unchecked((int)0x10325476);
this._offset = 0;
for (int i = 0; i != this._hashValue.Length; i++)
{
this._hashValue[i] = 0;
}
}
private void Update(byte input)
{
this._buffer[this._bufferOffset++] = input;
if (this._bufferOffset == this._buffer.Length)
{
this.ProcessWord(this._buffer, 0);
this._bufferOffset = 0;
}
this._byteCount++;
}
private void ProcessWord(byte[] input, int inOff)
{
this._hashValue[this._offset++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
| ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
if (this._offset == 16)
{
ProcessBlock();
}
}
private void UnpackWord(int word, byte[] outBytes, int outOff)
{
outBytes[outOff] = (byte)word;
outBytes[outOff + 1] = (byte)((uint)word >> 8);
outBytes[outOff + 2] = (byte)((uint)word >> 16);
outBytes[outOff + 3] = (byte)((uint)word >> 24);
}
//
// round 1 left rotates
//
private static readonly int S11 = 7;
private static readonly int S12 = 12;
private static readonly int S13 = 17;
private static readonly int S14 = 22;
//
// round 2 left rotates
//
private static readonly int S21 = 5;
private static readonly int S22 = 9;
private static readonly int S23 = 14;
private static readonly int S24 = 20;
//
// round 3 left rotates
//
private static readonly int S31 = 4;
private static readonly int S32 = 11;
private static readonly int S33 = 16;
private static readonly int S34 = 23;
//
// round 4 left rotates
//
private static readonly int S41 = 6;
private static readonly int S42 = 10;
private static readonly int S43 = 15;
private static readonly int S44 = 21;
/*
* rotate int x left n bits.
*/
private int RotateLeft(int x, int n)
{
return (x << n) | (int)((uint)x >> (32 - n));
}
/*
* F, G, H and I are the basic MD5 functions.
*/
private int F(int u, int v, int w)
{
return (u & v) | (~u & w);
}
private int G(int u, int v, int w)
{
return (u & w) | (v & ~w);
}
private int H(int u, int v, int w)
{
return u ^ v ^ w;
}
private int K(int u, int v, int w)
{
return v ^ (u | ~w);
}
private void ProcessBlock()
{
int a = H1;
int b = H2;
int c = H3;
int d = H4;
//
// Round 1 - F cycle, 16 times.
//
a = RotateLeft((a + F(b, c, d) + this._hashValue[0] + unchecked((int)0xd76aa478)), S11) + b;
d = RotateLeft((d + F(a, b, c) + this._hashValue[1] + unchecked((int)0xe8c7b756)), S12) + a;
c = RotateLeft((c + F(d, a, b) + this._hashValue[2] + unchecked((int)0x242070db)), S13) + d;
b = RotateLeft((b + F(c, d, a) + this._hashValue[3] + unchecked((int)0xc1bdceee)), S14) + c;
a = RotateLeft((a + F(b, c, d) + this._hashValue[4] + unchecked((int)0xf57c0faf)), S11) + b;
d = RotateLeft((d + F(a, b, c) + this._hashValue[5] + unchecked((int)0x4787c62a)), S12) + a;
c = RotateLeft((c + F(d, a, b) + this._hashValue[6] + unchecked((int)0xa8304613)), S13) + d;
b = RotateLeft((b + F(c, d, a) + this._hashValue[7] + unchecked((int)0xfd469501)), S14) + c;
a = RotateLeft((a + F(b, c, d) + this._hashValue[8] + unchecked((int)0x698098d8)), S11) + b;
d = RotateLeft((d + F(a, b, c) + this._hashValue[9] + unchecked((int)0x8b44f7af)), S12) + a;
c = RotateLeft((c + F(d, a, b) + this._hashValue[10] + unchecked((int)0xffff5bb1)), S13) + d;
b = RotateLeft((b + F(c, d, a) + this._hashValue[11] + unchecked((int)0x895cd7be)), S14) + c;
a = RotateLeft((a + F(b, c, d) + this._hashValue[12] + unchecked((int)0x6b901122)), S11) + b;
d = RotateLeft((d + F(a, b, c) + this._hashValue[13] + unchecked((int)0xfd987193)), S12) + a;
c = RotateLeft((c + F(d, a, b) + this._hashValue[14] + unchecked((int)0xa679438e)), S13) + d;
b = RotateLeft((b + F(c, d, a) + this._hashValue[15] + unchecked((int)0x49b40821)), S14) + c;
//
// Round 2 - G cycle, 16 times.
//
a = RotateLeft((a + G(b, c, d) + this._hashValue[1] + unchecked((int)0xf61e2562)), S21) + b;
d = RotateLeft((d + G(a, b, c) + this._hashValue[6] + unchecked((int)0xc040b340)), S22) + a;
c = RotateLeft((c + G(d, a, b) + this._hashValue[11] + unchecked((int)0x265e5a51)), S23) + d;
b = RotateLeft((b + G(c, d, a) + this._hashValue[0] + unchecked((int)0xe9b6c7aa)), S24) + c;
a = RotateLeft((a + G(b, c, d) + this._hashValue[5] + unchecked((int)0xd62f105d)), S21) + b;
d = RotateLeft((d + G(a, b, c) + this._hashValue[10] + unchecked((int)0x02441453)), S22) + a;
c = RotateLeft((c + G(d, a, b) + this._hashValue[15] + unchecked((int)0xd8a1e681)), S23) + d;
b = RotateLeft((b + G(c, d, a) + this._hashValue[4] + unchecked((int)0xe7d3fbc8)), S24) + c;
a = RotateLeft((a + G(b, c, d) + this._hashValue[9] + unchecked((int)0x21e1cde6)), S21) + b;
d = RotateLeft((d + G(a, b, c) + this._hashValue[14] + unchecked((int)0xc33707d6)), S22) + a;
c = RotateLeft((c + G(d, a, b) + this._hashValue[3] + unchecked((int)0xf4d50d87)), S23) + d;
b = RotateLeft((b + G(c, d, a) + this._hashValue[8] + unchecked((int)0x455a14ed)), S24) + c;
a = RotateLeft((a + G(b, c, d) + this._hashValue[13] + unchecked((int)0xa9e3e905)), S21) + b;
d = RotateLeft((d + G(a, b, c) + this._hashValue[2] + unchecked((int)0xfcefa3f8)), S22) + a;
c = RotateLeft((c + G(d, a, b) + this._hashValue[7] + unchecked((int)0x676f02d9)), S23) + d;
b = RotateLeft((b + G(c, d, a) + this._hashValue[12] + unchecked((int)0x8d2a4c8a)), S24) + c;
//
// Round 3 - H cycle, 16 times.
//
a = RotateLeft((a + H(b, c, d) + this._hashValue[5] + unchecked((int)0xfffa3942)), S31) + b;
d = RotateLeft((d + H(a, b, c) + this._hashValue[8] + unchecked((int)0x8771f681)), S32) + a;
c = RotateLeft((c + H(d, a, b) + this._hashValue[11] + unchecked((int)0x6d9d6122)), S33) + d;
b = RotateLeft((b + H(c, d, a) + this._hashValue[14] + unchecked((int)0xfde5380c)), S34) + c;
a = RotateLeft((a + H(b, c, d) + this._hashValue[1] + unchecked((int)0xa4beea44)), S31) + b;
d = RotateLeft((d + H(a, b, c) + this._hashValue[4] + unchecked((int)0x4bdecfa9)), S32) + a;
c = RotateLeft((c + H(d, a, b) + this._hashValue[7] + unchecked((int)0xf6bb4b60)), S33) + d;
b = RotateLeft((b + H(c, d, a) + this._hashValue[10] + unchecked((int)0xbebfbc70)), S34) + c;
a = RotateLeft((a + H(b, c, d) + this._hashValue[13] + unchecked((int)0x289b7ec6)), S31) + b;
d = RotateLeft((d + H(a, b, c) + this._hashValue[0] + unchecked((int)0xeaa127fa)), S32) + a;
c = RotateLeft((c + H(d, a, b) + this._hashValue[3] + unchecked((int)0xd4ef3085)), S33) + d;
b = RotateLeft((b + H(c, d, a) + this._hashValue[6] + unchecked((int)0x04881d05)), S34) + c;
a = RotateLeft((a + H(b, c, d) + this._hashValue[9] + unchecked((int)0xd9d4d039)), S31) + b;
d = RotateLeft((d + H(a, b, c) + this._hashValue[12] + unchecked((int)0xe6db99e5)), S32) + a;
c = RotateLeft((c + H(d, a, b) + this._hashValue[15] + unchecked((int)0x1fa27cf8)), S33) + d;
b = RotateLeft((b + H(c, d, a) + this._hashValue[2] + unchecked((int)0xc4ac5665)), S34) + c;
//
// Round 4 - K cycle, 16 times.
//
a = RotateLeft((a + K(b, c, d) + this._hashValue[0] + unchecked((int)0xf4292244)), S41) + b;
d = RotateLeft((d + K(a, b, c) + this._hashValue[7] + unchecked((int)0x432aff97)), S42) + a;
c = RotateLeft((c + K(d, a, b) + this._hashValue[14] + unchecked((int)0xab9423a7)), S43) + d;
b = RotateLeft((b + K(c, d, a) + this._hashValue[5] + unchecked((int)0xfc93a039)), S44) + c;
a = RotateLeft((a + K(b, c, d) + this._hashValue[12] + unchecked((int)0x655b59c3)), S41) + b;
d = RotateLeft((d + K(a, b, c) + this._hashValue[3] + unchecked((int)0x8f0ccc92)), S42) + a;
c = RotateLeft((c + K(d, a, b) + this._hashValue[10] + unchecked((int)0xffeff47d)), S43) + d;
b = RotateLeft((b + K(c, d, a) + this._hashValue[1] + unchecked((int)0x85845dd1)), S44) + c;
a = RotateLeft((a + K(b, c, d) + this._hashValue[8] + unchecked((int)0x6fa87e4f)), S41) + b;
d = RotateLeft((d + K(a, b, c) + this._hashValue[15] + unchecked((int)0xfe2ce6e0)), S42) + a;
c = RotateLeft((c + K(d, a, b) + this._hashValue[6] + unchecked((int)0xa3014314)), S43) + d;
b = RotateLeft((b + K(c, d, a) + this._hashValue[13] + unchecked((int)0x4e0811a1)), S44) + c;
a = RotateLeft((a + K(b, c, d) + this._hashValue[4] + unchecked((int)0xf7537e82)), S41) + b;
d = RotateLeft((d + K(a, b, c) + this._hashValue[11] + unchecked((int)0xbd3af235)), S42) + a;
c = RotateLeft((c + K(d, a, b) + this._hashValue[2] + unchecked((int)0x2ad7d2bb)), S43) + d;
b = RotateLeft((b + K(c, d, a) + this._hashValue[9] + unchecked((int)0xeb86d391)), S44) + c;
H1 += a;
H2 += b;
H3 += c;
H4 += d;
//
// reset the offset and clean out the word buffer.
//
this._offset = 0;
for (int i = 0; i != this._hashValue.Length; i++)
{
this._hashValue[i] = 0;
}
}
}
}
@@ -0,0 +1,382 @@
using System.Security.Cryptography;
using System;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// SHA1 algorithm implementation
/// </summary>
public class SHA1Hash : HashAlgorithm
{
private const int DIGEST_SIZE = 20;
private const uint Y1 = 0x5a827999;
private const uint Y2 = 0x6ed9eba1;
private const uint Y3 = 0x8f1bbcdc;
private const uint Y4 = 0xca62c1d6;
private uint H1, H2, H3, H4, H5;
private uint[] _hashValue = new uint[80];
private int _offset;
private byte[] _buffer;
private int _bufferOffset;
private long _byteCount;
/// <summary>
/// Gets the size, in bits, of the computed hash code.
/// </summary>
/// <returns>The size, in bits, of the computed hash code.</returns>
public override int HashSize
{
get
{
return DIGEST_SIZE * 8;
}
}
/// <summary>
/// Gets the input block size.
/// </summary>
/// <returns>The input block size.</returns>
public override int InputBlockSize
{
get
{
return 64;
}
}
/// <summary>
/// Gets the output block size.
/// </summary>
/// <returns>The output block size.</returns>
public override int OutputBlockSize
{
get
{
return 64;
}
}
/// <summary>
/// Gets a value indicating whether the current transform can be reused.
/// </summary>
/// <returns>Always true.</returns>
public override bool CanReuseTransform
{
get
{
return true;
}
}
/// <summary>
/// Gets a value indicating whether multiple blocks can be transformed.
/// </summary>
/// <returns>true if multiple blocks can be transformed; otherwise, false.</returns>
public override bool CanTransformMultipleBlocks
{
get
{
return true;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SHA1Hash"/> class.
/// </summary>
public SHA1Hash()
{
this._buffer = new byte[4];
this.Initialize();
}
/// <summary>
/// Routes data written to the object into the hash algorithm for computing the hash.
/// </summary>
/// <param name="array">The input to compute the hash code for.</param>
/// <param name="ibStart">The offset into the byte array from which to begin using data.</param>
/// <param name="cbSize">The number of bytes in the byte array to use as data.</param>
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
// Fill the current word
while ((this._bufferOffset != 0) && (cbSize > 0))
{
this.Update(array[ibStart]);
ibStart++;
cbSize--;
}
// Process whole words.
while (cbSize > this._buffer.Length)
{
this.ProcessWord(array, ibStart);
ibStart += this._buffer.Length;
cbSize -= this._buffer.Length;
this._byteCount += this._buffer.Length;
}
// Load in the remainder.
while (cbSize > 0)
{
this.Update(array[ibStart]);
ibStart++;
cbSize--;
}
}
/// <summary>
/// Finalizes the hash computation after the last data is processed by the cryptographic stream object.
/// </summary>
/// <returns>
/// The computed hash code.
/// </returns>
protected override byte[] HashFinal()
{
var output = new byte[DIGEST_SIZE];
long bitLength = (this._byteCount << 3);
//
// add the pad bytes.
//
this.Update((byte)128);
while (this._bufferOffset != 0)
this.Update((byte)0);
if (this._offset > 14)
{
this.ProcessBlock();
}
_hashValue[14] = (uint)((ulong)bitLength >> 32);
_hashValue[15] = (uint)((ulong)bitLength);
this.ProcessBlock();
UInt32_To__BE(H1, output, 0);
UInt32_To__BE(H2, output, 0 + 4);
UInt32_To__BE(H3, output, 0 + 8);
UInt32_To__BE(H4, output, 0 + 12);
UInt32_To__BE(H5, output, 0 + 16);
this.Initialize();
return output;
}
/// <summary>
/// Initializes an implementation of the <see cref="T:System.Security.Cryptography.HashAlgorithm"/> class.
/// </summary>
public override void Initialize()
{
this._byteCount = 0;
this._bufferOffset = 0;
Array.Clear(this._buffer, 0, this._buffer.Length);
H1 = 0x67452301;
H2 = 0xefcdab89;
H3 = 0x98badcfe;
H4 = 0x10325476;
H5 = 0xc3d2e1f0;
this._offset = 0;
Array.Clear(_hashValue, 0, _hashValue.Length);
}
private void Update(byte input)
{
this._buffer[this._bufferOffset++] = input;
if (this._bufferOffset == this._buffer.Length)
{
this.ProcessWord(this._buffer, 0);
this._bufferOffset = 0;
}
this._byteCount++;
}
private void ProcessWord(byte[] input, int inOff)
{
_hashValue[this._offset] = BE_To__UInt32(input, inOff);
if (++this._offset == 16)
{
this.ProcessBlock();
}
}
private static uint F(uint u, uint v, uint w)
{
return (u & v) | (~u & w);
}
private static uint H(uint u, uint v, uint w)
{
return u ^ v ^ w;
}
private static uint G(uint u, uint v, uint w)
{
return (u & v) | (u & w) | (v & w);
}
private void ProcessBlock()
{
//
// expand 16 word block into 80 word block.
//
for (int i = 16; i < 80; i++)
{
uint t = _hashValue[i - 3] ^ _hashValue[i - 8] ^ _hashValue[i - 14] ^ _hashValue[i - 16];
_hashValue[i] = t << 1 | t >> 31;
}
//
// set up working variables.
//
uint A = H1;
uint B = H2;
uint C = H3;
uint D = H4;
uint E = H5;
//
// round 1
//
int idx = 0;
for (int j = 0; j < 4; j++)
{
// E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1
// B = rotateLeft(B, 30)
E += (A << 5 | (A >> 27)) + F(B, C, D) + _hashValue[idx++] + Y1;
B = B << 30 | (B >> 2);
D += (E << 5 | (E >> 27)) + F(A, B, C) + _hashValue[idx++] + Y1;
A = A << 30 | (A >> 2);
C += (D << 5 | (D >> 27)) + F(E, A, B) + _hashValue[idx++] + Y1;
E = E << 30 | (E >> 2);
B += (C << 5 | (C >> 27)) + F(D, E, A) + _hashValue[idx++] + Y1;
D = D << 30 | (D >> 2);
A += (B << 5 | (B >> 27)) + F(C, D, E) + _hashValue[idx++] + Y1;
C = C << 30 | (C >> 2);
}
//
// round 2
//
for (int j = 0; j < 4; j++)
{
// E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2
// B = rotateLeft(B, 30)
E += (A << 5 | (A >> 27)) + H(B, C, D) + _hashValue[idx++] + Y2;
B = B << 30 | (B >> 2);
D += (E << 5 | (E >> 27)) + H(A, B, C) + _hashValue[idx++] + Y2;
A = A << 30 | (A >> 2);
C += (D << 5 | (D >> 27)) + H(E, A, B) + _hashValue[idx++] + Y2;
E = E << 30 | (E >> 2);
B += (C << 5 | (C >> 27)) + H(D, E, A) + _hashValue[idx++] + Y2;
D = D << 30 | (D >> 2);
A += (B << 5 | (B >> 27)) + H(C, D, E) + _hashValue[idx++] + Y2;
C = C << 30 | (C >> 2);
}
//
// round 3
//
for (int j = 0; j < 4; j++)
{
// E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3
// B = rotateLeft(B, 30)
E += (A << 5 | (A >> 27)) + G(B, C, D) + _hashValue[idx++] + Y3;
B = B << 30 | (B >> 2);
D += (E << 5 | (E >> 27)) + G(A, B, C) + _hashValue[idx++] + Y3;
A = A << 30 | (A >> 2);
C += (D << 5 | (D >> 27)) + G(E, A, B) + _hashValue[idx++] + Y3;
E = E << 30 | (E >> 2);
B += (C << 5 | (C >> 27)) + G(D, E, A) + _hashValue[idx++] + Y3;
D = D << 30 | (D >> 2);
A += (B << 5 | (B >> 27)) + G(C, D, E) + _hashValue[idx++] + Y3;
C = C << 30 | (C >> 2);
}
//
// round 4
//
for (int j = 0; j < 4; j++)
{
// E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y4
// B = rotateLeft(B, 30)
E += (A << 5 | (A >> 27)) + H(B, C, D) + _hashValue[idx++] + Y4;
B = B << 30 | (B >> 2);
D += (E << 5 | (E >> 27)) + H(A, B, C) + _hashValue[idx++] + Y4;
A = A << 30 | (A >> 2);
C += (D << 5 | (D >> 27)) + H(E, A, B) + _hashValue[idx++] + Y4;
E = E << 30 | (E >> 2);
B += (C << 5 | (C >> 27)) + H(D, E, A) + _hashValue[idx++] + Y4;
D = D << 30 | (D >> 2);
A += (B << 5 | (B >> 27)) + H(C, D, E) + _hashValue[idx++] + Y4;
C = C << 30 | (C >> 2);
}
H1 += A;
H2 += B;
H3 += C;
H4 += D;
H5 += E;
//
// reset start of the buffer.
//
this._offset = 0;
Array.Clear(_hashValue, 0, 16);
}
private static uint BE_To__UInt32(byte[] bs, int off)
{
uint n = (uint)bs[off] << 24;
n |= (uint)bs[++off] << 16;
n |= (uint)bs[++off] << 8;
n |= (uint)bs[++off];
return n;
}
private static void UInt32_To__BE
(uint n, byte[] bs, int off)
{
bs[off] = (byte)(n >> 24);
bs[++off] = (byte)(n >> 16);
bs[++off] = (byte)(n >> 8);
bs[++off] = (byte)(n);
}
}
}
@@ -0,0 +1,389 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// SHA256 algorithm implementation.
/// </summary>
public class SHA256Hash : HashAlgorithm
{
private const int DIGEST_SIZE = 32;
private uint H1, H2, H3, H4, H5, H6, H7, H8;
private uint[] X = new uint[64];
private int _offset;
private byte[] _buffer;
private int _bufferOffset;
private long _byteCount;
/// <summary>
/// Gets the size, in bits, of the computed hash code.
/// </summary>
/// <returns>The size, in bits, of the computed hash code.</returns>
public override int HashSize
{
get
{
return DIGEST_SIZE * 8;
}
}
/// <summary>
/// Gets the input block size.
/// </summary>
/// <returns>The input block size.</returns>
public override int InputBlockSize
{
get
{
return 64;
}
}
/// <summary>
/// Gets the output block size.
/// </summary>
/// <returns>The output block size.</returns>
public override int OutputBlockSize
{
get
{
return 64;
}
}
/// <summary>
/// Gets a value indicating whether the current transform can be reused.
/// </summary>
/// <returns>Always true.</returns>
public override bool CanReuseTransform
{
get
{
return true;
}
}
/// <summary>
/// Gets a value indicating whether multiple blocks can be transformed.
/// </summary>
/// <returns>true if multiple blocks can be transformed; otherwise, false.</returns>
public override bool CanTransformMultipleBlocks
{
get
{
return true;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="SHA1"/> class.
/// </summary>
public SHA256Hash()
{
this._buffer = new byte[4];
this.Initialize();
}
/// <summary>
/// Routes data written to the object into the hash algorithm for computing the hash.
/// </summary>
/// <param name="array">The input to compute the hash code for.</param>
/// <param name="ibStart">The offset into the byte array from which to begin using data.</param>
/// <param name="cbSize">The number of bytes in the byte array to use as data.</param>
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
// Fill the current word
while ((this._bufferOffset != 0) && (cbSize > 0))
{
this.Update(array[ibStart]);
ibStart++;
cbSize--;
}
// Process whole words.
while (cbSize > this._buffer.Length)
{
this.ProcessWord(array, ibStart);
ibStart += this._buffer.Length;
cbSize -= this._buffer.Length;
this._byteCount += this._buffer.Length;
}
// Load in the remainder.
while (cbSize > 0)
{
this.Update(array[ibStart]);
ibStart++;
cbSize--;
}
}
/// <summary>
/// Finalizes the hash computation after the last data is processed by the cryptographic stream object.
/// </summary>
/// <returns>
/// The computed hash code.
/// </returns>
protected override byte[] HashFinal()
{
var output = new byte[DIGEST_SIZE];
long bitLength = (this._byteCount << 3);
//
// add the pad bytes.
//
this.Update((byte)128);
while (this._bufferOffset != 0)
this.Update((byte)0);
if (this._offset > 14)
{
this.ProcessBlock();
}
X[14] = (uint)((ulong)bitLength >> 32);
X[15] = (uint)((ulong)bitLength);
this.ProcessBlock();
UInt32_To_BE((uint)H1, output, 0);
UInt32_To_BE((uint)H2, output, 0 + 4);
UInt32_To_BE((uint)H3, output, 0 + 8);
UInt32_To_BE((uint)H4, output, 0 + 12);
UInt32_To_BE((uint)H5, output, 0 + 16);
UInt32_To_BE((uint)H6, output, 0 + 20);
UInt32_To_BE((uint)H7, output, 0 + 24);
UInt32_To_BE((uint)H8, output, 0 + 28);
this.Initialize();
return output;
}
/// <summary>
/// Initializes an implementation of the <see cref="T:System.Security.Cryptography.HashAlgorithm"/> class.
/// </summary>
public override void Initialize()
{
//this.Reset();
this._byteCount = 0;
this._bufferOffset = 0;
Array.Clear(this._buffer, 0, this._buffer.Length);
H1 = 0x6a09e667;
H2 = 0xbb67ae85;
H3 = 0x3c6ef372;
H4 = 0xa54ff53a;
H5 = 0x510e527f;
H6 = 0x9b05688c;
H7 = 0x1f83d9ab;
H8 = 0x5be0cd19;
this._offset = 0;
Array.Clear(X, 0, X.Length);
}
private void Update(byte input)
{
this._buffer[this._bufferOffset++] = input;
if (this._bufferOffset == this._buffer.Length)
{
this.ProcessWord(this._buffer, 0);
this._bufferOffset = 0;
}
this._byteCount++;
}
private static uint BE_To_UInt32(byte[] bs, int off)
{
uint n = (uint)bs[off] << 24;
n |= (uint)bs[++off] << 16;
n |= (uint)bs[++off] << 8;
n |= (uint)bs[++off];
return n;
}
private static void UInt32_To_BE(uint n, byte[] bs, int off)
{
bs[off] = (byte)(n >> 24);
bs[++off] = (byte)(n >> 16);
bs[++off] = (byte)(n >> 8);
bs[++off] = (byte)(n);
}
private void ProcessWord(byte[] input, int inOff)
{
X[this._offset] = BE_To_UInt32(input, inOff);
if (++this._offset == 16)
{
ProcessBlock();
}
}
private void ProcessLength(long bitLength)
{
if (this._offset > 14)
{
ProcessBlock();
}
X[14] = (uint)((ulong)bitLength >> 32);
X[15] = (uint)((ulong)bitLength);
}
private void ProcessBlock()
{
//
// expand 16 word block into 64 word blocks.
//
for (int ti = 16; ti <= 63; ti++)
{
X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16];
}
//
// set up working variables.
//
uint a = H1;
uint b = H2;
uint c = H3;
uint d = H4;
uint e = H5;
uint f = H6;
uint g = H7;
uint h = H8;
int t = 0;
for (int i = 0; i < 8; ++i)
{
// t = 8 * i
h += Sum1Ch(e, f, g) + K[t] + X[t];
d += h;
h += Sum0Maj(a, b, c);
++t;
// t = 8 * i + 1
g += Sum1Ch(d, e, f) + K[t] + X[t];
c += g;
g += Sum0Maj(h, a, b);
++t;
// t = 8 * i + 2
f += Sum1Ch(c, d, e) + K[t] + X[t];
b += f;
f += Sum0Maj(g, h, a);
++t;
// t = 8 * i + 3
e += Sum1Ch(b, c, d) + K[t] + X[t];
a += e;
e += Sum0Maj(f, g, h);
++t;
// t = 8 * i + 4
d += Sum1Ch(a, b, c) + K[t] + X[t];
h += d;
d += Sum0Maj(e, f, g);
++t;
// t = 8 * i + 5
c += Sum1Ch(h, a, b) + K[t] + X[t];
g += c;
c += Sum0Maj(d, e, f);
++t;
// t = 8 * i + 6
b += Sum1Ch(g, h, a) + K[t] + X[t];
f += b;
b += Sum0Maj(c, d, e);
++t;
// t = 8 * i + 7
a += Sum1Ch(f, g, h) + K[t] + X[t];
e += a;
a += Sum0Maj(b, c, d);
++t;
}
H1 += a;
H2 += b;
H3 += c;
H4 += d;
H5 += e;
H6 += f;
H7 += g;
H8 += h;
//
// reset the offset and clean out the word buffer.
//
this._offset = 0;
Array.Clear(X, 0, 16);
}
private static uint Sum1Ch(uint x, uint y, uint z)
{
// return Sum1(x) + Ch(x, y, z);
return (((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)))
+ ((x & y) ^ ((~x) & z));
}
private static uint Sum0Maj(uint x, uint y, uint z)
{
// return Sum0(x) + Maj(x, y, z);
return (((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)))
+ ((x & y) ^ (x & z) ^ (y & z));
}
private static uint Theta0(uint x)
{
return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3);
}
private static uint Theta1(uint x)
{
return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10);
}
/* SHA-256 Constants
* (represent the first 32 bits of the fractional parts of the
* cube roots of the first sixty-four prime numbers)
*/
private static readonly uint[] K = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
}
}
@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Provides additional cipher modes
/// </summary>
public enum CipherModeEx
{
/// <summary>
/// The Cipher Block Chaining (CBC) mode introduces feedback. Before each plain
/// text block is encrypted, it is combined with the cipher text of the previous
/// block by a bitwise exclusive OR operation. This ensures that even if the
/// plain text contains many identical blocks, they will each encrypt to a different
/// cipher text block. The initialization vector is combined with the first plain
/// text block by a bitwise exclusive OR operation before the block is encrypted.
/// If a single bit of the cipher text block is mangled, the corresponding plain
/// text block will also be mangled. In addition, a bit in the subsequent block,
/// in the same position as the original mangled bit, will be mangled.
/// </summary>
CBC = 1,
/// <summary>
/// The Electronic Codebook (ECB) mode encrypts each block individually. This
/// means that any blocks of plain text that are identical and are in the same
/// message, or in a different message encrypted with the same key, will be transformed
/// into identical cipher text blocks. If the plain text to be encrypted contains
/// substantial repetition, it is feasible for the cipher text to be broken one
/// block at a time. Also, it is possible for an active adversary to substitute
/// and exchange individual blocks without detection. If a single bit of the
/// cipher text block is mangled, the entire corresponding plain text block will
/// also be mangled.
/// </summary>
ECB = 2,
/// <summary>
/// The Output Feedback (OFB) mode processes small increments of plain text into
/// cipher text instead of processing an entire block at a time. This mode is
/// similar to CFB; the only difference between the two modes is the way that
/// the shift register is filled. If a bit in the cipher text is mangled, the
/// corresponding bit of plain text will be mangled. However, if there are extra
/// or missing bits from the cipher text, the plain text will be mangled from
/// that point on.
/// </summary>
OFB = 3,
/// <summary>
/// The Cipher Feedback (CFB) mode processes small increments of plain text into
/// cipher text, instead of processing an entire block at a time. This mode uses
/// a shift register that is one block in length and is divided into sections.
/// For example, if the block size is eight bytes, with one byte processed at
/// a time, the shift register is divided into eight sections. If a bit in the
/// cipher text is mangled, one plain text bit is mangled and the shift register
/// is corrupted. This results in the next several plain text increments being
/// mangled until the bad bit is shifted out of the shift register.
/// </summary>
CFB = 4,
/// <summary>
/// The Cipher Text Stealing (CTS) mode handles any length of plain text and
/// produces cipher text whose length matches the plain text length. This mode
/// behaves like the CBC mode for all but the last two blocks of the plain text.
/// </summary>
CTS = 5,
/// <summary>
/// Counter Block Cipher mode
/// </summary>
CTR = 10,
}
}
@@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
///
/// </summary>
public abstract class ModeBase : CipherBase
{
/// <summary>
/// Gets the cipher.
/// </summary>
public CipherBase Cipher { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="ModeBase"/> class.
/// </summary>
/// <param name="cipher">The cipher.</param>
public ModeBase(CipherBase cipher)
: base(cipher.Key, cipher.IV)
{
this.Cipher = cipher;
}
}
}
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using Renci.SshNet.Common;
using Renci.SshNet.Security.Cryptography.Ciphers;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Implements RSA digital signature algorithm.
/// </summary>
public class RsaDigitalSignature : CipherDigitalSignature
{
/// <summary>
/// Initializes a new instance of the <see cref="RsaDigitalSignature"/> class.
/// </summary>
/// <param name="exponent">The exponent.</param>
/// <param name="modulus">The modulus.</param>
/// <param name="d">The D value.</param>
/// <param name="dp">The DP value.</param>
/// <param name="dq">The DQ value.</param>
/// <param name="inverseQ">The InverseQ value.</param>
/// <param name="p">The P value.</param>
/// <param name="q">The Q value.</param>
public RsaDigitalSignature(byte[] exponent, byte[] modulus, byte[] d, byte[] dp, byte[] dq, byte[] inverseQ, byte[] p, byte[] q)
: base(new SHA1Hash(), new RsaCipher(new BigInteger(exponent.Reverse().ToArray()), new BigInteger(modulus.Reverse().ToArray()), new BigInteger(d.Reverse().ToArray()), new BigInteger(dp.Reverse().ToArray()), new BigInteger(dq.Reverse().ToArray()), new BigInteger(inverseQ.Reverse().ToArray()), new BigInteger(p.Reverse().ToArray()), new BigInteger(q.Reverse().ToArray())))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RsaDigitalSignature"/> class.
/// </summary>
/// <param name="exponent">The exponent.</param>
/// <param name="modulus">The modulus.</param>
public RsaDigitalSignature(byte[] exponent, byte[] modulus)
: base(new SHA1Hash(), new RsaCipher(new BigInteger(exponent.Reverse().ToArray()), new BigInteger(modulus.Reverse().ToArray())))
{
}
}
}
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
///
/// </summary>
public abstract class StreamCipher : SymmetricCipher
{
/// <summary>
/// Initializes a new instance of the <see cref="StreamCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
protected StreamCipher(byte[] key)
: base(key)
{
}
}
}
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Renci.SshNet.Security.Cryptography
{
/// <summary>
/// Base class for symmetric cipher implementations.
/// </summary>
public abstract class SymmetricCipher : Cipher
{
/// <summary>
/// Gets the size of the key in bits.
/// </summary>
/// <value>
/// The size of the key in bits.
/// </value>
public int KeySize { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="SymmetricCipher"/> class.
/// </summary>
/// <param name="key">The key.</param>
protected SymmetricCipher(byte[] key)
{
var keySize = key.Length * 8;
if (this.ValidateKeySize(keySize))
{
this.KeySize = keySize;
}
else
{
throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize));
}
}
/// <summary>
/// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to encrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write encrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes encrypted.
/// </returns>
public abstract int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
/// <summary>
/// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array.
/// </summary>
/// <param name="inputBuffer">The input data to decrypt.</param>
/// <param name="inputOffset">The offset into the input byte array from which to begin using data.</param>
/// <param name="inputCount">The number of bytes in the input byte array to use as data.</param>
/// <param name="outputBuffer">The output to which to write decrypted data.</param>
/// <param name="outputOffset">The offset into the output byte array from which to begin writing data.</param>
/// <returns>
/// The number of bytes decrypted.
/// </returns>
public abstract int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset);
/// <summary>
/// Validates the size of the key.
/// </summary>
/// <param name="keySize">Size of the key.</param>
/// <returns>true if keySize is valid; otherwise false</returns>
protected abstract bool ValidateKeySize(int keySize);
}
}
@@ -6,6 +6,8 @@ using Renci.SshNet.Common;
using Renci.SshNet.Compression;
using Renci.SshNet.Messages;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Security.Cryptography.Ciphers;
using Renci.SshNet.Security.Cryptography;
namespace Renci.SshNet.Security
{
@@ -14,13 +16,13 @@ namespace Renci.SshNet.Security
/// </summary>
public abstract class KeyExchange : Algorithm, IDisposable
{
private Type _clientCipherType;
private CipherInfo _clientCipherInfo;
private Type _serverCipherType;
private CipherInfo _serverCipherInfo;
private Type _cientHmacAlgorithmType;
private Func<byte[], HashAlgorithm> _cientHmacAlgorithmType;
private Type _serverHmacAlgorithmType;
private Func<byte[], HashAlgorithm> _serverHmacAlgorithmType;
private Type _compressionType;
@@ -131,8 +133,8 @@ namespace Renci.SshNet.Security
throw new SshConnectionException("Decompression algorithm not found", DisconnectReason.KeyExchangeFailed);
}
this._clientCipherType = session.ConnectionInfo.Encryptions[clientEncryptionAlgorithmName];
this._serverCipherType = session.ConnectionInfo.Encryptions[clientEncryptionAlgorithmName];
this._clientCipherInfo = session.ConnectionInfo.Encryptions[clientEncryptionAlgorithmName];
this._serverCipherInfo = session.ConnectionInfo.Encryptions[clientEncryptionAlgorithmName];
this._cientHmacAlgorithmType = session.ConnectionInfo.HmacAlgorithms[clientHmacAlgorithmName];
this._serverHmacAlgorithmType = session.ConnectionInfo.HmacAlgorithms[serverHmacAlgorithmName];
this._compressionType = session.ConnectionInfo.CompressionAlgorithms[compressionAlgorithmName];
@@ -159,84 +161,78 @@ namespace Renci.SshNet.Security
/// Creates the server side cipher to use.
/// </summary>
/// <returns></returns>
public Cipher CreateServerCipher()
public BlockCipher CreateServerCipher()
{
// Resolve Session ID
var sessionId = this.Session.SessionId ?? this.ExchangeHash;
// Create server cipher
var serverCipher = this._serverCipherType.CreateInstance<Cipher>();
// Calculate server to client initial IV
var serverVector = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'B', sessionId));
// Calculate server to client encryption
var serverKey = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'D', sessionId));
serverKey = this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, serverKey, serverCipher.KeySize / 8);
serverCipher.Init(serverKey, serverVector);
return serverCipher;
serverKey = this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, serverKey, this._serverCipherInfo.KeySize / 8);
// Create server cipher
return this._serverCipherInfo.Cipher(serverKey, serverVector);
}
/// <summary>
/// Creates the client side cipher to use.
/// </summary>
/// <returns></returns>
public Cipher CreateClientCipher()
public BlockCipher CreateClientCipher()
{
// Resolve Session ID
var sessionId = this.Session.SessionId ?? this.ExchangeHash;
// Create client cipher
var clientCipher = this._clientCipherType.CreateInstance<Cipher>();
// Calculate client to server initial IV
var clientVector = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'A', sessionId));
// Calculate client to server encryption
var clientKey = this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'C', sessionId));
clientKey = this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, clientKey, clientCipher.KeySize / 8);
clientKey = this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, clientKey, this._clientCipherInfo.KeySize / 8);
clientCipher.Init(clientKey, clientVector);
return clientCipher;
// Create client cipher
return this._clientCipherInfo.Cipher(clientKey, clientVector);
}
/// <summary>
/// Creates the server side hash algorithm to use.
/// </summary>
/// <returns></returns>
public HMac CreateServerHash()
public HashAlgorithm CreateServerHash()
{
// Resolve Session ID
var sessionId = this.Session.SessionId ?? this.ExchangeHash;
// Create server HMac
var serverHMac = this._serverHmacAlgorithmType.CreateInstance<HMac>();
//var serverHMac = this._serverHmacAlgorithmType.CreateInstance<HMac>();
serverHMac.Init(this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'F', sessionId)));
//serverHMac.Init(this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'F', sessionId)));
return serverHMac;
//return serverHMac;
return this._serverHmacAlgorithmType(this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'F', sessionId)));
}
/// <summary>
/// Creates the client side hash algorithm to use.
/// </summary>
/// <returns></returns>
public HMac CreateClientHash()
public HashAlgorithm CreateClientHash()
{
// Resolve Session ID
var sessionId = this.Session.SessionId ?? this.ExchangeHash;
// Create client HMac
var clientHMac = this._cientHmacAlgorithmType.CreateInstance<HMac>();
//var clientHMac = this._cientHmacAlgorithmType.CreateInstance<HMac>();
clientHMac.Init(this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'E', sessionId)));
//clientHMac.Init(this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'E', sessionId)));
return clientHMac;
//return clientHMac;
return this._cientHmacAlgorithmType(this.Hash(this.GenerateSessionKey(this.SharedKey, this.ExchangeHash, 'E', sessionId)));
}
/// <summary>
+6 -4
View File
@@ -17,6 +17,8 @@ using Renci.SshNet.Messages.Connection;
using Renci.SshNet.Messages.Transport;
using Renci.SshNet.Security;
using System.Globalization;
using Renci.SshNet.Security.Cryptography.Ciphers;
using Renci.SshNet.Security.Cryptography;
namespace Renci.SshNet
{
@@ -108,13 +110,13 @@ namespace Renci.SshNet
private KeyExchange _keyExchange;
private HMac _serverMac;
private HashAlgorithm _serverMac;
private HMac _clientMac;
private HashAlgorithm _clientMac;
private Cipher _clientCipher;
private BlockCipher _clientCipher;
private Cipher _serverCipher;
private BlockCipher _serverCipher;
private Compressor _serverDecompression;