diff --git a/README.md b/README.md index f58d2e7e..2eacd873 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,29 @@ -SSH.NET +SSH.NET ======= SSH.NET is a Secure Shell (SSH-2) library for .NET, optimized for parallelism. [![Version](https://img.shields.io/nuget/vpre/SSH.NET.svg)](https://www.nuget.org/packages/SSH.NET) +[![NuGet download count](https://img.shields.io/nuget/dt/SSH.NET.svg)](https://www.nuget.org/packages/SSH.NET) [![Build status](https://ci.appveyor.com/api/projects/status/ih77qu6tap3o92gu/branch/develop?svg=true)](https://ci.appveyor.com/api/projects/status/ih77qu6tap3o92gu/branch/develop) ## Introduction -This project was inspired by **Sharp.SSH** library which was ported from java and it seems like was not supported for quite some time. This library is a complete rewrite, without any third party dependencies, using parallelism to achieve the best performance possible. +This project was inspired by **Sharp.SSH** library which was ported from java and it seems like was not supported +for quite some time. This library is a complete rewrite, without any third party dependencies, using parallelism +to achieve the best performance possible. + +## Documentation +There is MSDN-style class documentation in a .chm file for each release, which you can find in the Assets section +of the [latest release](https://github.com/sshnet/SSH.NET/releases/latest) page. Please note that you will need +to [right-click and "unblock"](https://support.microsoft.com/en-us/help/2021383/some-chm-files-may-not-render-properly-on-windows-vista-and-windows-7) +the CHM file after you download it. + +Currently (4/18/2020), the documentation is very sparse. Fortunately, there are a large number of tests in +[Renci.SshNet.Tests](https://github.com/sshnet/SSH.NET/tree/develop/src/Renci.SshNet.Tests) that demonstrate +usage with working code. + +If the test for the functionality you would like to see documented is not complete, then you are cordially +invited to read the source, Luke, and highly encouraged to generate a pull request for the implementation of +the missing test once you figure things out. 🤓 ## Features * Execution of SSH command using both synchronous and asynchronous methods @@ -17,22 +34,72 @@ This project was inspired by **Sharp.SSH** library which was ported from java an * Remote, dynamic and local port forwarding * Shell/Terminal implementation * Specify key file pass phrase -* Use multiple key files to authenticate -* Supports 3des-cbc, aes128-cbc, aes192-cbc, aes256-cbc, aes128-ctr, aes192-ctr, aes256-ctr, blowfish-cbc, cast128-cbc, arcfour and twofish encryptions +* Use multiple key files to authenticate * Supports publickey, password and keyboard-interactive authentication methods -* Supports RSA and DSA private key -* Supports DES-EDE3-CBC, DES-EDE3-CFB, DES-CBC, AES-128-CBC, AES-192-CBC and AES-256-CBC algorithms for private key encryption * Supports two-factor or higher authentication * Supports SOCKS4, SOCKS5 and HTTP Proxy +## Encryption Method + +**SSH.NET** supports the following encryption methods: +* aes256-ctr +* 3des-cbc +* aes128-cbc +* aes192-cbc +* aes256-cbc +* blowfish-cbc +* twofish-cbc +* twofish192-cbc +* twofish128-cbc +* twofish256-cbc +* arcfour +* arcfour128 +* arcfour256 +* cast128-cbc +* aes128-ctr +* aes192-ctr + ## Key Exchange Method **SSH.NET** supports the following key exchange methods: +* curve25519-sha256 +* curve25519-sha256@libssh.org +* ecdh-sha2-nistp256 +* ecdh-sha2-nistp384 +* ecdh-sha2-nistp521 * diffie-hellman-group-exchange-sha256 * diffie-hellman-group-exchange-sha1 +* diffie-hellman-group16-sha512 +* diffie-hellman-group14-sha256 * diffie-hellman-group14-sha1 * diffie-hellman-group1-sha1 +## Public Key Authentication + +**SSH.NET** supports the following private key formats: +* RSA in OpenSSL PEM and ssh.com format +* DSA in OpenSSL PEM and ssh.com format +* ECDSA 256/384/521 in OpenSSL PEM format +* ED25519 in OpenSSH key format + +Private keys can be encrypted using one of the following cipher methods: +* DES-EDE3-CBC +* DES-EDE3-CFB +* DES-CBC +* AES-128-CBC +* AES-192-CBC +* AES-256-CBC + +## Host Key Algorithms + +**SSH.NET** supports the following host key algorithms: +* ssh-ed25519 +* ecdsa-sha2-nistp256 +* ecdsa-sha2-nistp384 +* ecdsa-sha2-nistp521 +* ssh-rsa +* ssh-dss + ## Message Authentication Code **SSH.NET** supports the following MAC algorithms: @@ -45,7 +112,7 @@ This project was inspired by **Sharp.SSH** library which was ported from java an * hmac-sha2-512 * hmac-sha2-512-96 * hmac-ripemd160 -* hmac-ripemd160@openssh.com +* hmac-ripemd160@openssh.com ## Framework Support **SSH.NET** supports the following target frameworks: diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT new file mode 100644 index 00000000..1cacf79e --- /dev/null +++ b/THIRD-PARTY-NOTICES.TXT @@ -0,0 +1,73 @@ +SSH.NET uses third-party libraries or other resources that may be +distributed under licenses different than the SSH.NET software. + +License notice for BouncyCastle +------------------------------- + +http://bouncycastle.org/csharp + +Copyright (c) 2000 - 2018 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for Chaos.NaCl +------------------------------- + +https://github.com/CodesInChaos/Chaos.NaCl + +Public domain + +C# port + code by Christian Winnerlein (CodesInChaos) + +Poly1305 in c + written by Andrew M. (floodyberry) + original license: MIT or PUBLIC DOMAIN + https://github.com/floodyberry/poly1305-donna/blob/master/poly1305-donna-unrolled.c + +Curve25519 and Ed25519 in c + written by Dan Bernstein (djb) + public domain + from Ref10 in SUPERCOP http://bench.cr.yp.to/supercop.html + +(H)Salsa20 in c + written by Dan Bernstein (djb) + public domain + from SUPERCOP http://bench.cr.yp.to/supercop.html + +SHA512 + written by Christian Winnerlein (CodesInChaos) + public domain + directly from the specification + +License notice for BCrypt +------------------------- + +Copyright (c) 2006 Damien Miller +Copyright (c) 2010 Ryan D. Emerle + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/appveyor.yml b/appveyor.yml index ab8e88d5..c5bb4a18 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,14 +1,14 @@ -os: Visual Studio 2015 +os: Visual Studio 2019 before_build: - - nuget restore src\Renci.SshNet.VS2015.sln + - nuget restore src\Renci.SshNet.VS2019.sln build: - project: src\Renci.SshNet.VS2015.sln + project: src\Renci.SshNet.VS2019.sln verbosity: minimal test_script: - cmd: >- - vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" + vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net40\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" - vstest.console /logger:Appveyor src\Renci.SshNet.Tests.NET35\bin\Debug\Renci.SshNet.Tests.NET35.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" \ No newline at end of file + vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net35\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" \ No newline at end of file diff --git a/build/build.cmd b/build/build.cmd deleted file mode 100644 index 146c26fb..00000000 --- a/build/build.cmd +++ /dev/null @@ -1,12 +0,0 @@ -@echo off - -set MSBUILD14_EXE=%ProgramFiles(x86)%\MSBuild\14.0\Bin\MSBuild.exe -set MSBUILD15_EXE=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\\MSBuild\15.0\bin\MSBuild.exe - -call "%MSBUILD14_EXE%" build.proj /t:Clean -call "%MSBUILD15_EXE%" build.proj /t:Clean - -call "%MSBUILD14_EXE%" build.proj /t:Build -call "%MSBUILD15_EXE%" build.proj /t:Build - -call "%MSBUILD15_EXE%" build.proj /t:Package /p:ReleaseVersion=%1 \ No newline at end of file diff --git a/build/build.proj b/build/build.proj index 96708a6c..fd5a96ed 100644 --- a/build/build.proj +++ b/build/build.proj @@ -1,5 +1,5 @@ - + Release @@ -8,128 +8,214 @@ MSBuildTasks 1.5.0.214 + - + $(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2012.sln - 14.0 - true - - + 14.0 + 14.0 + + $(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2015.sln - 14.0 - true - - - $(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2017.sln - 15.0 - + 14.0 + 14.0 + + - - Renci.SshNet.NET35\bin\$(Configuration) - net35 - - - Renci.SshNet\bin\$(Configuration) - net40 - - - Renci.SshNet.NETCore\bin\$(Configuration)\netstandard1.3 - netstandard1.3 - - + + $(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2019.sln + 16.0 + + + + + Renci.SshNet.WindowsPhone\bin\$(Configuration) wp71 - - + + Renci.SshNet.WindowsPhone8\bin\$(Configuration) wp8 - - + + Renci.SshNet.Silverlight\bin\$(Configuration) sl4 - - + + Renci.SshNet.Silverlight5\bin\$(Configuration) sl5 - - + + Renci.SshNet.UAP10\bin\$(Configuration) uap10 - + - + + + + Renci.SshNet\bin\$(Configuration)\net35 + net35 + + + Renci.SshNet\bin\$(Configuration)\net40 + net40 + + + Renci.SshNet\bin\$(Configuration)\netstandard1.3 + netstandard1.3 + + + Renci.SshNet\bin\$(Configuration)\netstandard2.0 + netstandard2.0 + + + + + + + + + + + - - Configuration=Release + + Configuration=Release;VisualStudioVersion=%(VisualStudioVersionClassic.VisualStudioVersion) - + + + + + + + Configuration=Release;VisualStudioVersion=%(VisualStudioVersionModern.VisualStudioVersion) + + + + + + + + + + + + + + + + + + + + Configuration=Release;VisualStudioVersion=%(VisualStudioVersionClassic.VisualStudioVersion) + + + + + + + + + + Configuration=Release;VisualStudioVersion=%(VisualStudioVersionModern.VisualStudioVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - Configuration=Release - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + $(MSBuildThisFileDirectory)target\nuget-$(ReleaseVersion) + + + + + + $(MSBuildThisFileDirectory)target\bin-$(ReleaseVersion) + + +
diff --git a/build/nuget/SSH.NET.nuspec b/build/nuget/SSH.NET.nuspec index 12bffe81..03830583 100644 --- a/build/nuget/SSH.NET.nuspec +++ b/build/nuget/SSH.NET.nuspec @@ -2,7 +2,7 @@ SSH.NET - 2016.1.0 + $version$ SSH.NET Renci olegkap,drieseng @@ -10,53 +10,43 @@ https://github.com/sshnet/SSH.NET/ false SSH.NET is a Secure Shell (SSH) library for .NET, optimized for parallelism and with broad framework support. - https://github.com/sshnet/SSH.NET/releases/tag/2016.1.0 + https://github.com/sshnet/SSH.NET/releases/tag/$version$ A Secure Shell (SSH) library for .NET, optimized for parallelism. - 2012-2017, RENCI + $copyright$ en-US ssh scp sftp - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - + - + - + - + - - + + diff --git a/build/sandcastle/SSH.NET.shfbproj b/build/sandcastle/SSH.NET.shfbproj index dbd43088..50141f16 100644 --- a/build/sandcastle/SSH.NET.shfbproj +++ b/build/sandcastle/SSH.NET.shfbproj @@ -41,8 +41,8 @@ - - + + Summary, Parameter, Returns, AutoDocumentCtors, TypeParameter, AutoDocumentDispose OnlyWarningsAndErrors diff --git a/runtest.cmd b/runtest.cmd new file mode 100644 index 00000000..ad4c0f5a --- /dev/null +++ b/runtest.cmd @@ -0,0 +1,3 @@ +rem vstest.console src\Renci.SshNet.Tests\bin\Debug\net40\Renci.SshNet.Tests.dll "/TestCaseFilter:TestCategory=Gert + +vstest.console src\Renci.SshNet.Tests\bin\Debug\net40\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" \ No newline at end of file diff --git a/src/References/How the SCP protocol works.pdf b/src/References/How the SCP protocol works.pdf new file mode 100644 index 00000000..74728daa Binary files /dev/null and b/src/References/How the SCP protocol works.pdf differ diff --git a/src/Renci.SshNet.NET35/Common/Extensions.NET35.cs b/src/Renci.SshNet.NET35/Common/Extensions.NET35.cs deleted file mode 100644 index ed198c00..00000000 --- a/src/Renci.SshNet.NET35/Common/Extensions.NET35.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Diagnostics; -using System.Security.Cryptography; -using System.Text; - -namespace Renci.SshNet.Common -{ - /// - /// Collection of different extension method specific for .NET 3.5 - /// - internal static partial class Extensions - { - /// - /// Disposes the specified algorithm. - /// - /// The algorithm. - [DebuggerNonUserCode] - internal static void Dispose(this HashAlgorithm algorithm) - { - if (algorithm == null) - throw new NullReferenceException(); - - algorithm.Clear(); - } - - /// - /// Clears the contents of the string builder. - /// - /// - /// The to clear. - /// - public static void Clear(this StringBuilder value) - { - value.Length = 0; - value.Capacity = 16; - } - } -} diff --git a/src/Renci.SshNet.NET35/Properties/AssemblyInfo.cs b/src/Renci.SshNet.NET35/Properties/AssemblyInfo.cs deleted file mode 100644 index 9b3fcd24..00000000 --- a/src/Renci.SshNet.NET35/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("SSH.NET .NET 3.5")] -[assembly: Guid("a9698831-4993-469b-81f1-aed4e5379252")] -[assembly: InternalsVisibleTo("Renci.SshNet.Tests.NET35, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] \ No newline at end of file diff --git a/src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj b/src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj deleted file mode 100644 index a6878d18..00000000 --- a/src/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj +++ /dev/null @@ -1,984 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A} - Library - Properties - Renci.SshNet - Renci.SshNet - v3.5 - 512 - - - true - full - false - bin\Debug\ - TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII - prompt - 4 - true - bin\Debug\Renci.SshNet.xml - 5 - - - none - true - bin\Release\ - TRACE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII - prompt - 4 - bin\Release\Renci.SshNet.xml - - - true - 5 - - - true - - - ..\Renci.SshNet.snk - - - - - - - - - Abstractions\CryptoAbstraction.cs - - - Abstractions\DiagnosticAbstraction.cs - - - Abstractions\DnsAbstraction.cs - - - Abstractions\FileSystemAbstraction.cs - - - Abstractions\ReflectionAbstraction.cs - - - Abstractions\SocketAbstraction.cs - - - Abstractions\ThreadAbstraction.cs - - - AuthenticationMethod.cs - - - AuthenticationResult.cs - - - BaseClient.cs - - - Channels\Channel.cs - - - Channels\ChannelDirectTcpip.cs - - - Channels\ChannelForwardedTcpip.cs - - - Channels\ChannelSession.cs - - - Channels\ChannelTypes.cs - - - Channels\ClientChannel.cs - - - Channels\IChannel.cs - - - Channels\IChannelDirectTcpip.cs - - - Channels\IChannelForwardedTcpip.cs - - - Channels\IChannelSession.cs - - - Channels\ServerChannel.cs - - - CipherInfo.cs - - - ClientAuthentication.cs - - - CommandAsyncResult.cs - - - Common\Array.cs - - - Common\ASCIIEncoding.cs - - - Common\AsyncResult.cs - - - Common\AuthenticationBannerEventArgs.cs - - - Common\AuthenticationEventArgs.cs - - - Common\AuthenticationPasswordChangeEventArgs.cs - - - Common\AuthenticationPrompt.cs - - - Common\AuthenticationPromptEventArgs.cs - - - Common\BigInteger.cs - - - Common\ChannelDataEventArgs.cs - - - Common\ChannelEventArgs.cs - - - Common\ChannelExtendedDataEventArgs.cs - - - Common\ChannelOpenConfirmedEventArgs.cs - - - Common\ChannelOpenFailedEventArgs.cs - - - Common\ChannelRequestEventArgs.cs - - - Common\CountdownEvent.cs - - - Common\DerData.cs - - - Common\ExceptionEventArgs.cs - - - Common\Extensions.cs - - - Common\HostKeyEventArgs.cs - - - Common\NetConfServerException.cs - - - Common\ObjectIdentifier.cs - - - Common\Pack.cs - - - Common\PipeStream.cs - - - Common\PortForwardEventArgs.cs - - - Common\PosixPath.cs - - - Common\ProxyException.cs - - - Common\ScpDownloadEventArgs.cs - - - Common\ScpException.cs - - - Common\ScpUploadEventArgs.cs - - - Common\SemaphoreLight.cs - - - Common\SftpPathNotFoundException.cs - - - Common\SftpPermissionDeniedException.cs - - - Common\ShellDataEventArgs.cs - - - Common\SshAuthenticationException.cs - - - Common\SshConnectionException.cs - - - Common\SshData.cs - - - Common\SshDataStream.cs - - - Common\SshException.cs - - - Common\SshOperationTimeoutException.cs - - - Common\SshPassPhraseNullOrEmptyException.cs - - - Common\TerminalModes.cs - - - Compression\CompressionMode.cs - - - Compression\Compressor.cs - - - Compression\Zlib.cs - - - Compression\ZlibOpenSsh.cs - - - Compression\ZlibStream.cs - - - ConnectionInfo.cs - - - ExpectAction.cs - - - ExpectAsyncResult.cs - - - ForwardedPort.cs - - - ForwardedPortDynamic.cs - - - ForwardedPortDynamic.NET.cs - - - ForwardedPortLocal.cs - - - ForwardedPortLocal.NET.cs - - - ForwardedPortRemote.cs - - - ForwardedPortStatus.cs - - - HashInfo.cs - - - IAuthenticationMethod.cs - - - IClientAuthentication.cs - - - IConnectionInfo.cs - - - IForwardedPort.cs - - - IRemotePathTransformation.cs - - - IServiceFactory.cs - - - IServiceFactory.NET.cs - - - ISession.cs - - - ISubsystemSession.cs - - - KeyboardInteractiveAuthenticationMethod.cs - - - KeyboardInteractiveConnectionInfo.cs - - - MessageEventArgs.cs - - - Messages\Authentication\BannerMessage.cs - - - Messages\Authentication\FailureMessage.cs - - - Messages\Authentication\InformationRequestMessage.cs - - - Messages\Authentication\InformationResponseMessage.cs - - - Messages\Authentication\PasswordChangeRequiredMessage.cs - - - Messages\Authentication\PublicKeyMessage.cs - - - Messages\Authentication\RequestMessage.cs - - - Messages\Authentication\RequestMessageHost.cs - - - Messages\Authentication\RequestMessageKeyboardInteractive.cs - - - Messages\Authentication\RequestMessageNone.cs - - - Messages\Authentication\RequestMessagePassword.cs - - - Messages\Authentication\RequestMessagePublicKey.cs - - - Messages\Authentication\SuccessMessage.cs - - - Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs - - - Messages\Connection\ChannelCloseMessage.cs - - - Messages\Connection\ChannelDataMessage.cs - - - Messages\Connection\ChannelEofMessage.cs - - - Messages\Connection\ChannelExtendedDataMessage.cs - - - Messages\Connection\ChannelFailureMessage.cs - - - Messages\Connection\ChannelMessage.cs - - - Messages\Connection\ChannelOpenConfirmationMessage.cs - - - Messages\Connection\ChannelOpenFailureMessage.cs - - - Messages\Connection\ChannelOpenFailureReasons.cs - - - Messages\Connection\ChannelOpen\ChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\ChannelOpenMessage.cs - - - Messages\Connection\ChannelOpen\DirectTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\ForwardedTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\SessionChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\X11ChannelOpenInfo.cs - - - Messages\Connection\ChannelRequest\BreakRequestInfo.cs - - - Messages\Connection\ChannelRequest\ChannelRequestMessage.cs - - - Messages\Connection\ChannelRequest\EndOfWriteRequestInfo.cs - - - Messages\Connection\ChannelRequest\EnvironmentVariableRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExecRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitSignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitStatusRequestInfo.cs - - - Messages\Connection\ChannelRequest\KeepAliveRequestInfo.cs - - - Messages\Connection\ChannelRequest\PseudoTerminalInfo.cs - - - Messages\Connection\ChannelRequest\RequestInfo.cs - - - Messages\Connection\ChannelRequest\ShellRequestInfo.cs - - - Messages\Connection\ChannelRequest\SignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\SubsystemRequestInfo.cs - - - Messages\Connection\ChannelRequest\WindowChangeRequestInfo.cs - - - Messages\Connection\ChannelRequest\X11ForwardingRequestInfo.cs - - - Messages\Connection\ChannelRequest\XonXoffRequestInfo.cs - - - Messages\Connection\ChannelSuccessMessage.cs - - - Messages\Connection\ChannelWindowAdjustMessage.cs - - - Messages\Connection\GlobalRequestMessage.cs - - - Messages\Connection\GlobalRequestName.cs - - - Messages\Connection\RequestFailureMessage.cs - - - Messages\Connection\RequestSuccessMessage.cs - - - Messages\Connection\TcpIpForwardGlobalRequestMessage.cs - - - Messages\Message.cs - - - Messages\MessageAttribute.cs - - - Messages\ServiceName.cs - - - Messages\Transport\DebugMessage.cs - - - Messages\Transport\DisconnectMessage.cs - - - Messages\Transport\DisconnectReason.cs - - - Messages\Transport\IgnoreMessage.cs - - - Messages\Transport\IKeyExchangedAllowed.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeGroup.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeInit.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeReply.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeRequest.cs - - - Messages\Transport\KeyExchangeDhInitMessage.cs - - - Messages\Transport\KeyExchangeDhReplyMessage.cs - - - Messages\Transport\KeyExchangeEcdhInitMessage.cs - - - Messages\Transport\KeyExchangeEcdhReplyMessage.cs - - - Messages\Transport\KeyExchangeInitMessage.cs - - - Messages\Transport\NewKeysMessage.cs - - - Messages\Transport\ServiceAcceptMessage.cs - - - Messages\Transport\ServiceRequestMessage.cs - - - Messages\Transport\UnimplementedMessage.cs - - - NetConfClient.cs - - - Netconf\INetConfSession.cs - - - Netconf\NetConfSession.cs - - - NoneAuthenticationMethod.cs - - - PasswordAuthenticationMethod.cs - - - PasswordConnectionInfo.cs - - - PrivateKeyAuthenticationMethod.cs - - - PrivateKeyConnectionInfo.cs - - - PrivateKeyFile.cs - - - ProxyTypes.cs - - - RemotePathDoubleQuoteTransformation.cs - - - RemotePathNoneTransformation.cs - - - RemotePathShellQuoteTransformation.cs - - - RemotePathTransformation.cs - - - ScpClient.cs - - - ScpClient.NET.cs - - - Security\Algorithm.cs - - - Security\CertificateHostAlgorithm.cs - - - Security\Cryptography\AsymmetricCipher.cs - - - Security\Cryptography\BlockCipher.cs - - - Security\Cryptography\Cipher.cs - - - Security\Cryptography\CipherDigitalSignature.cs - - - Security\Cryptography\Ciphers\AesCipher.cs - - - Security\Cryptography\Ciphers\Arc4Cipher.cs - - - Security\Cryptography\Ciphers\BlowfishCipher.cs - - - Security\Cryptography\Ciphers\CastCipher.cs - - - Security\Cryptography\Ciphers\CipherMode.cs - - - Security\Cryptography\Ciphers\CipherPadding.cs - - - Security\Cryptography\Ciphers\DesCipher.cs - - - Security\Cryptography\Ciphers\Modes\CbcCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CfbCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CtrCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\OfbCipherMode.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS5Padding.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS7Padding.cs - - - Security\Cryptography\Ciphers\RsaCipher.cs - - - Security\Cryptography\Ciphers\SerpentCipher.cs - - - Security\Cryptography\Ciphers\TripleDesCipher.cs - - - Security\Cryptography\Ciphers\TwofishCipher.cs - - - Security\Cryptography\DigitalSignature.cs - - - Security\Cryptography\DsaDigitalSignature.cs - - - Security\Cryptography\DsaKey.cs - - - Security\Cryptography\HMACMD5.cs - - - Security\Cryptography\HMACSHA1.cs - - - Security\Cryptography\HMACSHA256.cs - - - Security\Cryptography\HMACSHA384.cs - - - Security\Cryptography\HMACSHA512.cs - - - Security\Cryptography\Key.cs - - - Security\Cryptography\RsaDigitalSignature.cs - - - Security\Cryptography\RsaKey.cs - - - Security\Cryptography\StreamCipher.cs - - - Security\Cryptography\SymmetricCipher.cs - - - Security\GroupExchangeHashData.cs - - - Security\HostAlgorithm.cs - - - Security\IKeyExchange.cs - - - Security\KeyExchange.cs - - - Security\KeyExchangeDiffieHellman.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroup1Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs - - - Security\KeyExchangeDiffieHellmanGroupSha1.cs - - - Security\KeyHostAlgorithm.cs - - - ServiceFactory.cs - - - ServiceFactory.NET.cs - - - Session.cs - - - SftpClient.cs - - - Sftp\Flags.cs - - - Sftp\ISftpFileReader.cs - - - Sftp\ISftpResponseFactory.cs - - - Sftp\ISftpSession.cs - - - Sftp\Requests\ExtendedRequests\FStatVfsRequest.cs - - - Sftp\Requests\ExtendedRequests\HardLinkRequest.cs - - - Sftp\Requests\ExtendedRequests\PosixRenameRequest.cs - - - Sftp\Requests\ExtendedRequests\StatVfsRequest.cs - - - Sftp\Requests\SftpBlockRequest.cs - - - Sftp\Requests\SftpCloseRequest.cs - - - Sftp\Requests\SftpExtendedRequest.cs - - - Sftp\Requests\SftpFSetStatRequest.cs - - - Sftp\Requests\SftpFStatRequest.cs - - - Sftp\Requests\SftpInitRequest.cs - - - Sftp\Requests\SftpLinkRequest.cs - - - Sftp\Requests\SftpLStatRequest.cs - - - Sftp\Requests\SftpMkDirRequest.cs - - - Sftp\Requests\SftpOpenDirRequest.cs - - - Sftp\Requests\SftpOpenRequest.cs - - - Sftp\Requests\SftpReadDirRequest.cs - - - Sftp\Requests\SftpReadLinkRequest.cs - - - Sftp\Requests\SftpReadRequest.cs - - - Sftp\Requests\SftpRealPathRequest.cs - - - Sftp\Requests\SftpRemoveRequest.cs - - - Sftp\Requests\SftpRenameRequest.cs - - - Sftp\Requests\SftpRequest.cs - - - Sftp\Requests\SftpRmDirRequest.cs - - - Sftp\Requests\SftpSetStatRequest.cs - - - Sftp\Requests\SftpStatRequest.cs - - - Sftp\Requests\SftpSymLinkRequest.cs - - - Sftp\Requests\SftpUnblockRequest.cs - - - Sftp\Requests\SftpWriteRequest.cs - - - Sftp\Responses\ExtendedReplies\ExtendedReplyInfo.cs - - - Sftp\Responses\ExtendedReplies\StatVfsReplyInfo.cs - - - Sftp\Responses\SftpAttrsResponse.cs - - - Sftp\Responses\SftpDataResponse.cs - - - Sftp\Responses\SftpExtendedReplyResponse.cs - - - Sftp\Responses\SftpHandleResponse.cs - - - Sftp\Responses\SftpNameResponse.cs - - - Sftp\Responses\SftpResponse.cs - - - Sftp\Responses\SftpStatusResponse.cs - - - Sftp\Responses\SftpVersionResponse.cs - - - Sftp\SftpCloseAsyncResult.cs - - - Sftp\SftpDownloadAsyncResult.cs - - - Sftp\SftpFile.cs - - - Sftp\SftpFileAttributes.cs - - - Sftp\SftpFileReader.cs - - - Sftp\SftpFileStream.cs - - - Sftp\SftpFileSystemInformation.cs - - - Sftp\SftpListDirectoryAsyncResult.cs - - - Sftp\SftpMessage.cs - - - Sftp\SftpMessageTypes.cs - - - Sftp\SftpOpenAsyncResult.cs - - - Sftp\SftpReadAsyncResult.cs - - - Sftp\SftpRealPathAsyncResult.cs - - - Sftp\SftpResponseFactory.cs - - - Sftp\SftpSession.cs - - - Sftp\SFtpStatAsyncResult.cs - - - Sftp\SftpSynchronizeDirectoriesAsyncResult.cs - - - Sftp\SftpUploadAsyncResult.cs - - - Sftp\StatusCodes.cs - - - Shell.cs - - - ShellStream.cs - - - SshClient.cs - - - SshCommand.cs - - - SshMessageFactory.cs - - - SubsystemSession.cs - - - - - Properties\CommonAssemblyInfo.cs - - - - - - Renci.SshNet.snk - - - - - - - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.NETCore/Properties/AssemblyInfo.cs b/src/Renci.SshNet.NETCore/Properties/AssemblyInfo.cs deleted file mode 100644 index d5769ab9..00000000 --- a/src/Renci.SshNet.NETCore/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("SSH.NET")] diff --git a/src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.csproj b/src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.csproj deleted file mode 100644 index d913f3d2..00000000 --- a/src/Renci.SshNet.NETCore/Renci.SshNet.NETCore.csproj +++ /dev/null @@ -1,113 +0,0 @@ - - - SSH.NET - netstandard1.3 - true - true - Renci.SshNet - ../Renci.SshNet.snk - 5 - true - true - false - false - false - false - false - false - false - false - false - - - - %(RecursiveDir)%(Filename)%(Extension) - - - - - 1.6.0 - - - - - 4.0.1 - - - [1.2.0] - - - 4.0.11 - - - 4.0.1 - - - 4.0.0 - - - 4.0.11 - - - 4.1.0 - - - 4.0.1 - - - 4.0.1 - - - 4.1.0 - - - 4.0.0 - - - 4.1.0 - - - 4.0.1 - - - 4.1.0 - - - 4.2.0 - - - 4.1.0 - - - 4.0.11 - - - 4.0.0 - - - 4.0.10 - - - 4.0.1 - - - 4.0.1 - - - 4.0.1 - - - - - - - - FEATURE_ENCODING_ASCII;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_RNG_CREATE;FEATURE_SOCKET_TAP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_DNS_TAP;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512 - - - portable - - - none - - \ No newline at end of file diff --git a/src/Renci.SshNet.Silverlight/Common/Extensions.SilverlightShared.cs b/src/Renci.SshNet.Silverlight/Common/Extensions.SilverlightShared.cs deleted file mode 100644 index c69e7c4f..00000000 --- a/src/Renci.SshNet.Silverlight/Common/Extensions.SilverlightShared.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Net.Sockets; -using System.Threading; -using System.Security.Cryptography; -using System.Diagnostics; - -namespace Renci.SshNet.Common -{ - /// - /// Collection of different extension method specific for Silverlight - /// - internal static partial class Extensions - { - /// - /// Disposes the specified socket. - /// - /// The socket. - [DebuggerNonUserCode] - internal static void Dispose(this Socket socket) - { - if (socket == null) - throw new NullReferenceException(); - - socket.Close(); - } - - /// - /// Disposes the specified handle. - /// - /// The handle. - [DebuggerNonUserCode] - internal static void Dispose(this WaitHandle handle) - { - if (handle == null) - throw new NullReferenceException(); - - handle.Close(); - } - - /// - /// Disposes the specified algorithm. - /// - /// The algorithm. - [DebuggerNonUserCode] - internal static void Dispose(this HashAlgorithm algorithm) - { - if (algorithm == null) - throw new NullReferenceException(); - - algorithm.Clear(); - } - } -} diff --git a/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj b/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj index 16c95635..8e579ab1 100644 --- a/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj +++ b/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj @@ -593,12 +593,411 @@ Security\Algorithm.cs + + Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs + + + Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs + + + Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\util\Pack.cs + + + Security\Cryptography\BouncyCastle\math\BigInteger.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\LongArray.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs + + + Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\PrimeField.cs + + + Security\Cryptography\BouncyCastle\math\raw\Mod.cs + + + Security\Cryptography\BouncyCastle\math\raw\Nat.cs + + + Security\Cryptography\BouncyCastle\security\DigestUtilities.cs + + + Security\Cryptography\BouncyCastle\security\SecureRandom.cs + + + Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs + + + Security\Cryptography\BouncyCastle\util\Arrays.cs + + + Security\Cryptography\BouncyCastle\util\BigIntegers.cs + + + Security\Cryptography\BouncyCastle\util\encoders\Hex.cs + + + Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs + + + Security\Cryptography\BouncyCastle\util\IMemoable.cs + + + Security\Cryptography\BouncyCastle\util\Integers.cs + + + Security\Cryptography\BouncyCastle\util\MemoableResetException.cs + + + Security\Cryptography\BouncyCastle\util\Times.cs + Security\CertificateHostAlgorithm.cs + + Security\Cryptography\Chaos.NaCl\CryptoBytes.cs + + + Security\Cryptography\Chaos.NaCl\Ed25519.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array16.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array8.cs + + + Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs + + + Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs + + + Security\Cryptography\Chaos.NaCl\Sha512.cs + Security\Cryptography\AsymmetricCipher.cs + + Security\Cryptography\Bcrypt.cs + Security\Cryptography\BlockCipher.cs @@ -668,6 +1067,12 @@ Security\Cryptography\DsaKey.cs + + Security\Cryptography\ED25519DigitalSignature.cs + + + Security\Cryptography\ED25519Key.cs + Security\Cryptography\HMACMD5.cs @@ -731,6 +1136,24 @@ Security\KeyExchangeDiffieHellmanGroupSha1.cs + + Security\KeyExchangeEC.cs + + + Security\KeyExchangeECCurve25519.cs + + + Security\KeyExchangeECDH.cs + + + Security\KeyExchangeECDH256.cs + + + Security\KeyExchangeECDH384.cs + + + Security\KeyExchangeECDH521.cs + Security\KeyHostAlgorithm.cs @@ -944,7 +1367,6 @@ SubsystemSession.cs - Properties\CommonAssemblyInfo.cs diff --git a/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj b/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj index 910eb770..30e4f2b8 100644 --- a/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj +++ b/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj @@ -29,7 +29,7 @@ full false Bin\Debug - TRACE;DEBUG;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 + TRACE;DEBUG;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 true true prompt @@ -42,7 +42,7 @@ none true Bin\Release - TRACE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 + TRACE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 true true prompt @@ -200,9 +200,6 @@ Common\Extensions.cs - - Common\Extensions.SilverlightShared.cs - Common\HostKeyEventArgs.cs @@ -602,12 +599,411 @@ Security\Algorithm.cs + + Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs + + + Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs + + + Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\util\Pack.cs + + + Security\Cryptography\BouncyCastle\math\BigInteger.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\LongArray.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs + + + Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\PrimeField.cs + + + Security\Cryptography\BouncyCastle\math\raw\Mod.cs + + + Security\Cryptography\BouncyCastle\math\raw\Nat.cs + + + Security\Cryptography\BouncyCastle\security\DigestUtilities.cs + + + Security\Cryptography\BouncyCastle\security\SecureRandom.cs + + + Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs + + + Security\Cryptography\BouncyCastle\util\Arrays.cs + + + Security\Cryptography\BouncyCastle\util\BigIntegers.cs + + + Security\Cryptography\BouncyCastle\util\encoders\Hex.cs + + + Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs + + + Security\Cryptography\BouncyCastle\util\IMemoable.cs + + + Security\Cryptography\BouncyCastle\util\Integers.cs + + + Security\Cryptography\BouncyCastle\util\MemoableResetException.cs + + + Security\Cryptography\BouncyCastle\util\Times.cs + Security\CertificateHostAlgorithm.cs + + Security\Cryptography\Chaos.NaCl\CryptoBytes.cs + + + Security\Cryptography\Chaos.NaCl\Ed25519.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array16.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array8.cs + + + Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs + + + Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs + + + Security\Cryptography\Chaos.NaCl\Sha512.cs + Security\Cryptography\AsymmetricCipher.cs + + Security\Cryptography\Bcrypt.cs + Security\Cryptography\BlockCipher.cs @@ -677,6 +1073,12 @@ Security\Cryptography\DsaKey.cs + + Security\Cryptography\ED25519DigitalSignature.cs + + + Security\Cryptography\ED25519Key.cs + Security\Cryptography\HMACMD5.cs @@ -740,6 +1142,24 @@ Security\KeyExchangeDiffieHellmanGroupSha1.cs + + Security\KeyExchangeEC.cs + + + Security\KeyExchangeECCurve25519.cs + + + Security\KeyExchangeECDH.cs + + + Security\KeyExchangeECDH256.cs + + + Security\KeyExchangeECDH384.cs + + + Security\KeyExchangeECDH521.cs + Security\KeyHostAlgorithm.cs diff --git a/src/Renci.SshNet.Tests.NET35/Classes/ForwardedPortLocal.NET35.cs b/src/Renci.SshNet.Tests.NET35/Classes/ForwardedPortLocal.NET35.cs deleted file mode 100644 index 2eec0336..00000000 --- a/src/Renci.SshNet.Tests.NET35/Classes/ForwardedPortLocal.NET35.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.SshClientTests -{ - public partial class ForwardedPortLocalTest : TestBase - { - } -} diff --git a/src/Renci.SshNet.Tests.NET35/Classes/ForwardedPortRemote.NET35.cs b/src/Renci.SshNet.Tests.NET35/Classes/ForwardedPortRemote.NET35.cs deleted file mode 100644 index 5b057ba1..00000000 --- a/src/Renci.SshNet.Tests.NET35/Classes/ForwardedPortRemote.NET35.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.SshClientTests -{ - public partial class ForwardedPortRemoteTest : TestBase - { - } -} diff --git a/src/Renci.SshNet.Tests.NET35/Classes/SshCommandTest.NET35.cs b/src/Renci.SshNet.Tests.NET35/Classes/SshCommandTest.NET35.cs deleted file mode 100644 index 8f95bf3f..00000000 --- a/src/Renci.SshNet.Tests.NET35/Classes/SshCommandTest.NET35.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.SshClientTests -{ - public partial class SshCommandTest : TestBase - { - } -} diff --git a/src/Renci.SshNet.Tests.NET35/Properties/AssemblyInfo.cs b/src/Renci.SshNet.Tests.NET35/Properties/AssemblyInfo.cs deleted file mode 100644 index 01506232..00000000 --- a/src/Renci.SshNet.Tests.NET35/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("SSH.NET Tests .NET 3.5")] -[assembly: Guid("7c827904-40c1-4fe3-8ed1-8a729b8417a9")] \ No newline at end of file diff --git a/src/Renci.SshNet.Tests.NET35/Properties/Resources.Designer.cs b/src/Renci.SshNet.Tests.NET35/Properties/Resources.Designer.cs deleted file mode 100644 index 54bef950..00000000 --- a/src/Renci.SshNet.Tests.NET35/Properties/Resources.Designer.cs +++ /dev/null @@ -1,206 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.18010 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Renci.SshNet.Tests.Properties { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Renci.SshNet.Tests.Properties.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to -----BEGIN DSA PRIVATE KEY----- - ///Proc-Type: 4,ENCRYPTED - ///DEK-Info: DES-EDE3-CBC,053105DCFC6132E7 - /// - ///nVjIhJr3Eeqk0aBfyYK38B6cF0g35U2acgq5t3zG8fCM5JLSnFcmkkYvohbmCLva - ///swNHMfmwumoX8Ga94cxGu6vW1qf+IMvgEU4U53DtJqRoeICMwIre1yUq2cCrV+gI - ///qQ6MAVMDgfMs7HrPs5999m+KoDh7oYsA1l5q+axU/rqM4g3lySr/1oT6oAQx5Qp2 - ///2DYkZEwnX5+NTw6aoMXl2qgIHBVxa7wZRMp9L0yAlEFk8T7fMuPrLSAEUBghcIaP - ///iBY1OY+M9MgDTTU56ZjLl+DfT3XfKzsZ3fmn1+bLqTRreiuS4/WF6xIa/DQu1sQd - ///nnjYgnKYcTWSvWWK9AcIVSpoiW2y6FcPkMAIw54ABrzBp4Rz0//Ykwv2Ga7AZxxm - ///P+lkxKf2RWnh406F [rest of string was truncated]";. - /// - internal static string DSA_KEY_WITH_PASS { - get { - return ResourceManager.GetString("DSA_KEY_WITH_PASS", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to -----BEGIN DSA PRIVATE KEY----- - ///MIIBvAIBAAKBgQDdQrrwGvknwD+pb9Gpv/vDxj8yqFUg0cUuC/tkjm3u+lQj86Rw - ///fA8RJOV+OP4Gtvs9zOSsxiuginoB/uEiT+6jbHvyvJeJp2fsDWLx/tVRXxpi8Nwe - ///bfb455R0wVVZdqnFKsAZLrQAT589EUtLgyVAFQbUP5Fz6px8H8AG0qlybQIVALn7 - ///UOxnbFR7fDfZkq2Pc7ZCVegpAoGBANRKf9vezuz1aGUnUGWILHO09SibHK255fkr - ///u4//zvCbdawWSZOoU+vMnplLUhNaVMoSyYE/TYOZvvbG9UtPvr8wZGdNPipvIXIB - ///xlpr+FH0mnSx0qlaRy3PEoDRAmw6msRCzVYV3vZ8ZTEUdt+phuru+pn0W9EugzCM - ///HikVVhJMAoGASHB5nNlWhpqvungn+otYyGKoVoATkRdRfSiUo3fb0mJLTmxrEhEH - ///4UOFA/UFdQ0TYXXW0 [rest of string was truncated]";. - /// - internal static string DSA_KEY_WITHOUT_PASS { - get { - return ResourceManager.GetString("DSA_KEY_WITHOUT_PASS", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to oleg-centos.edc.renci.org. - /// - internal static string HOST { - get { - return ResourceManager.GetString("HOST", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to -----BEGIN DSA PRIVATE KEY----- - ///MIIBugIBAAKBgQCG3ij/JvdNp+1VUsK2zmLM5QWNN4MRRm/FCOHDknDJrWdSKheO - ///h6BbCgyFOw+k5qYtwXQnt3DpQfxPi7PIjr3tQJ9gB8LzqH2DwT2hMXm9VV2ImX2P - ///12aj8hZVM99WOp/ma6+ivLSFHnwET19eaqS9SRb0ftIqZXpWGE3ddW07qQIVAOfT - ///1OPSsvAnOsSrYc5HG5K3xIWlAoGAAzhTmi29+v0YTIsW2W1FihsexeAnpPPjYgRO - ///eT6HreyTvh20UASxDP+IJ2Ba+41G6MU0isuAijp8Z4CCC4RpoS46Ksc3JtPsZiRy - ///wAjwlb7JKGRBoY8V3aT47Xyx+iTSclZfzTmv0Z0bb56NZ6KEU8WRnks2d7tsb0fq - ///JTAgLkkCgYBvt5EoxhlCwEUgm8j3nD4TLSRYt1lt6LVulBYA9qlV4F68b2cJUuOi - ///YTV9H2SWRF6UF+GiR [rest of string was truncated]";. - /// - internal static string INVALID_KEY { - get { - return ResourceManager.GetString("INVALID_KEY", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to tester. - /// - internal static string PASSWORD { - get { - return ResourceManager.GetString("PASSWORD", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to 22. - /// - internal static string PORT { - get { - return ResourceManager.GetString("PORT", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to proxy.oleg-centos.edc.renci.org. - /// - internal static string PROXY_HOST { - get { - return ResourceManager.GetString("PROXY_HOST", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to 8123. - /// - internal static string PROXY_PORT { - get { - return ResourceManager.GetString("PROXY_PORT", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to -----BEGIN RSA PRIVATE KEY----- - ///Proc-Type: 4,ENCRYPTED - ///DEK-Info: DES-EDE3-CBC,B3475536EDD1B442 - /// - ///Xa6Y7FYTfz19CMzPcVbCpBHEh8x3tnA9PutKEDNMwKbR+NVUvBx5fN1QjrLpltCr - ///uX7yD3vLCeyihg4oaK3nTBZBcsB/1TZx+MlLgpvMfV1JKmbKCmebBZ3lUpsypHlG - ///FpCY41miFwdHmBe6tuwL9XA3vz26eJwSgJGMkVN9EBvNbiOHinEPhSW0whzBfbv+ - ///OfseG73gvHc4jZS6Sw8h5VDBAmlldJEfkP/s/1/iTbCXFQ22xRb4Z6NilEyKiWpB - ///nQviXmaucTWCEuNF5QDA7oV7Ugwm5cAXuBqFIs9ZGaKV4/XpfX1tClOLfB3Lguh+ - ///bbkwjPb0ztlhKa4gkwXiMs0S/lhoueXBae4QStM0qJBXHtFhhRYIn4JeIZ8CJ0k6 - ///SMP7QVfPf5aJIaa8 [rest of string was truncated]";. - /// - internal static string RSA_KEY_WITH_PASS { - get { - return ResourceManager.GetString("RSA_KEY_WITH_PASS", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to -----BEGIN RSA PRIVATE KEY----- - ///MIIEogIBAAKCAQEA8ZsD8jgH7ySXnd4dprEFFkJ+zs1ne81E8febjR8hekiKrc+D - ///9GjeEykchy0PsrsBrf2F8J3GtLNISVerkl+EnVh1E0pi9Vllc1vcpQHvBeNPG/jl - ///9Dnum/DcaaMKLot+ARXjBuMX/xJVfnlgkvfpBvoq4QzQ6E27rOMbcPlvrN7KeYba - ///orsTpDMUraHX5u99P1evvw7sOuNl3lc9YpIgmjHT6dWUGTqBx9T2SEKXBRVk2NNb - ///d2UctQkr5BJn1gGehA+1KYS30FMiCSN8F8ZOlpYj1+K6xzs0srq1z30LailIyy7Q - ///mYp739BJlOF3cVywdcFXGre35H2cJylcNV2e+QIBIwKCAQAbnK/+bM207j02nQqz - ///9vlEX17zECkVdouJXiBn5kz4CEpdAcXwC/wfcmmpDHbSmQeBmVEi0DP3ZPJRhlzA - ///RW493jlECIBWjd+1a [rest of string was truncated]";. - /// - internal static string RSA_KEY_WITHOUT_PASS { - get { - return ResourceManager.GetString("RSA_KEY_WITHOUT_PASS", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to tester. - /// - internal static string USERNAME { - get { - return ResourceManager.GetString("USERNAME", resourceCulture); - } - } - } -} diff --git a/src/Renci.SshNet.Tests.NET35/Properties/Resources.resx b/src/Renci.SshNet.Tests.NET35/Properties/Resources.resx deleted file mode 100644 index b1605aba..00000000 --- a/src/Renci.SshNet.Tests.NET35/Properties/Resources.resx +++ /dev/null @@ -1,244 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - -----BEGIN DSA PRIVATE KEY----- -MIIBvAIBAAKBgQDdQrrwGvknwD+pb9Gpv/vDxj8yqFUg0cUuC/tkjm3u+lQj86Rw -fA8RJOV+OP4Gtvs9zOSsxiuginoB/uEiT+6jbHvyvJeJp2fsDWLx/tVRXxpi8Nwe -bfb455R0wVVZdqnFKsAZLrQAT589EUtLgyVAFQbUP5Fz6px8H8AG0qlybQIVALn7 -UOxnbFR7fDfZkq2Pc7ZCVegpAoGBANRKf9vezuz1aGUnUGWILHO09SibHK255fkr -u4//zvCbdawWSZOoU+vMnplLUhNaVMoSyYE/TYOZvvbG9UtPvr8wZGdNPipvIXIB -xlpr+FH0mnSx0qlaRy3PEoDRAmw6msRCzVYV3vZ8ZTEUdt+phuru+pn0W9EugzCM -HikVVhJMAoGASHB5nNlWhpqvungn+otYyGKoVoATkRdRfSiUo3fb0mJLTmxrEhEH -4UOFA/UFdQ0TYXXW0wRX/amynT4iTEXAx0FjxUNK5ryxloeoXiXEH4FK7D8RtJO1 -1UsaRrN+nqWiSTVAehl6tzoMCPargGcWeFlAZZnPGN76OD9J1GiKZj8CFQCl8SkF -GWfS+mH8xhLsxh1nI7rfJw== ------END DSA PRIVATE KEY----- - - - -----BEGIN DSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,053105DCFC6132E7 - -nVjIhJr3Eeqk0aBfyYK38B6cF0g35U2acgq5t3zG8fCM5JLSnFcmkkYvohbmCLva -swNHMfmwumoX8Ga94cxGu6vW1qf+IMvgEU4U53DtJqRoeICMwIre1yUq2cCrV+gI -qQ6MAVMDgfMs7HrPs5999m+KoDh7oYsA1l5q+axU/rqM4g3lySr/1oT6oAQx5Qp2 -2DYkZEwnX5+NTw6aoMXl2qgIHBVxa7wZRMp9L0yAlEFk8T7fMuPrLSAEUBghcIaP -iBY1OY+M9MgDTTU56ZjLl+DfT3XfKzsZ3fmn1+bLqTRreiuS4/WF6xIa/DQu1sQd -nnjYgnKYcTWSvWWK9AcIVSpoiW2y6FcPkMAIw54ABrzBp4Rz0//Ykwv2Ga7AZxxm -P+lkxKf2RWnh406FxBvBZzwB3rQeeM7QTg2IcFqGnlf005FIikp6SlyhZ/3M/Nl3 -FW235vuO37jLCL8qosGt4NOWAstXaxDujfIb/Q+IYxUpWZrdiH5tM/mUXARK0Sjf -D8DHbFwAT2mUv1QxRXYJO1y4pENboEzT6LUqxJgE+ae/F/29g2RD9DhtwqKqWjhM -7jB0kNVZrz3qUKnoJHIozA== ------END DSA PRIVATE KEY----- - - - oleg-centos.edc.renci.org - - - -----BEGIN DSA PRIVATE KEY----- -MIIBugIBAAKBgQCG3ij/JvdNp+1VUsK2zmLM5QWNN4MRRm/FCOHDknDJrWdSKheO -h6BbCgyFOw+k5qYtwXQnt3DpQfxPi7PIjr3tQJ9gB8LzqH2DwT2hMXm9VV2ImX2P -12aj8hZVM99WOp/ma6+ivLSFHnwET19eaqS9SRb0ftIqZXpWGE3ddW07qQIVAOfT -1OPSsvAnOsSrYc5HG5K3xIWlAoGAAzhTmi29+v0YTIsW2W1FihsexeAnpPPjYgRO -eT6HreyTvh20UASxDP+IJ2Ba+41G6MU0isuAijp8Z4CCC4RpoS46Ksc3JtPsZiRy -wAjwlb7JKGRBoY8V3aT47Xyx+iTSclZfzTmv0Z0bb56NZ6KEU8WRnks2d7tsb0fq -JTAgLkkCgYBvt5EoxhlCwEUgm8j3nD4TLSRYt1lt6LVulBYA9qlV4F68b2cJUuOi -YTV9H2SWRF6UF+GiR5SajChveS106T9O+tepip+7V5YgFfW+ALOxwar+6V8VoUF4 -xNvNTWtaw+wK8xsgxhhYDaWVhVLVhR40QmeQhx/BQm+EYkSSa9kkCQIURGd0R+Zj -tM7dZpB+reWl9L5e2L8= ------END DSA PRIVATE KEY----- - - - tester - - - 22 - - - proxy.oleg-centos.edc.renci.org - - - 8123 - - - -----BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEA8ZsD8jgH7ySXnd4dprEFFkJ+zs1ne81E8febjR8hekiKrc+D -9GjeEykchy0PsrsBrf2F8J3GtLNISVerkl+EnVh1E0pi9Vllc1vcpQHvBeNPG/jl -9Dnum/DcaaMKLot+ARXjBuMX/xJVfnlgkvfpBvoq4QzQ6E27rOMbcPlvrN7KeYba -orsTpDMUraHX5u99P1evvw7sOuNl3lc9YpIgmjHT6dWUGTqBx9T2SEKXBRVk2NNb -d2UctQkr5BJn1gGehA+1KYS30FMiCSN8F8ZOlpYj1+K6xzs0srq1z30LailIyy7Q -mYp739BJlOF3cVywdcFXGre35H2cJylcNV2e+QIBIwKCAQAbnK/+bM207j02nQqz -9vlEX17zECkVdouJXiBn5kz4CEpdAcXwC/wfcmmpDHbSmQeBmVEi0DP3ZPJRhlzA -RW493jlECIBWjd+1aZWPM2vGKJtTp2q802u6DOX9cbgFUcVB899ugFqDjREVxLqU -dBqhtjDJQ0sTPBVy2CBkrsrvLy7AZd4LlaqxpdTdpkD/auUxg4zdThHT/XeQ0V0G -3BS5vGehfqgkDOQpQSm7HexM+9GDJnnzMdNXjmWBPxZU49QAlxujZeZ1M2IgKwMq -eNkWAOnZJidfsfwYluSCi8OHPN2i1s/b7pgn6ffb50S/k2mmhTHxNChDdGTlW91G -6CFLAoGBAPlGA4qzZCG4SLBQicGhhXZlwaKKfTvWNi4xNPZeoJezC0G+yZZT7IIV -zCj83t3dteaRRw15e+7NuIXZx3zl2hANfEpBZwnS4sOekvbS9/S7cEVzOEk53jRU -TOtHRsvNxS2xK3RywqoaqzcPaK2Df917yzbqvEajMRudRPrsTvYdAoGBAPggB/kJ -+VxZf13JqV2KgrFoVvykJpRlw2F5+lkH69ON9gdl976J3TNJDqAmHeWFxBUL+6Lt -9TSpMq3fYueJXg9xaTkSYg177sPRGCmRLO5aneA4nJkIB6KHRXsR71C9D4fJK8Fi -YB5n5dnBUTBhkvaI6KsxcxDzEg2zAJEcn4WNAoGBAOsHf66pI+VHWnpakINdxvqa -dL3TCFz9K8UnFK3G7y/x9Kuz4qOuNsPLaLjua7s+wXL+ASn2MwW6pqoWekKPkxZz -HWqVb8dvEFIKipDyzIepadsU3UxbIfbTI/PG3FnCAw3S7nUbvtrl8eN07arpsxKn -63zr81iLPO4mkX7ezhs/AoGADi23UA8y0hO+Ip3PKeqoYei0g3cYJbysFDLbGwfE -VTtP4ypl7aF6WrO3sWFDiXVbqW5mJpFBNjWN3gzD0rdkdek5NnYUO0jpEoD6EQD7 -QNH6ZJWFSpK+m5Kzg2AcTcGpHbO5W4H23SqCKbNGd8sPtlD3Wj1XCEhnbn9B3GgJ -HZMCgYEAjn9BH4fcobMaM15AV0s6sCEyr/vzn3QBfoIBqqqlipMqOtPDv8oyvGO4 -5tSpMrTKf4e3YAMPA4TXRAiVLjeRYlhdj3He0LkAuZZabrHeRmWqjDruMWd1TcKZ -3o8DLgYbSH7eGXUJ+euM4spKr5OLkBEkmH7Of6Qxss2njvjVNTE= ------END RSA PRIVATE KEY----- - - - -----BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,B3475536EDD1B442 - -Xa6Y7FYTfz19CMzPcVbCpBHEh8x3tnA9PutKEDNMwKbR+NVUvBx5fN1QjrLpltCr -uX7yD3vLCeyihg4oaK3nTBZBcsB/1TZx+MlLgpvMfV1JKmbKCmebBZ3lUpsypHlG -FpCY41miFwdHmBe6tuwL9XA3vz26eJwSgJGMkVN9EBvNbiOHinEPhSW0whzBfbv+ -OfseG73gvHc4jZS6Sw8h5VDBAmlldJEfkP/s/1/iTbCXFQ22xRb4Z6NilEyKiWpB -nQviXmaucTWCEuNF5QDA7oV7Ugwm5cAXuBqFIs9ZGaKV4/XpfX1tClOLfB3Lguh+ -bbkwjPb0ztlhKa4gkwXiMs0S/lhoueXBae4QStM0qJBXHtFhhRYIn4JeIZ8CJ0k6 -SMP7QVfPf5aJIaa8t+SlpvtIFTIkEhTViOCl+udT04670DGwmJUgrJAV0r+/Ytf7 -Mi+m3DagN7gGmCvYo+7r7EBl1G6e3hCSYm0rFxGOBesmCWriRoeRpxirWnkrns57 -D57pEC1hg90IdycCGpiwqubGDKFljuMLiVd2w0onVhudShPszP+nJAaq18wUB+rE -mtBv+GlpqCITREB4lG2noP4r9P9lgrOTqmKvWjvUTQjfS3u0XO/1aQllKlwe97C7 -mfOxcZQWy5F7+9CiWpDpomW7Eso89ja6uyupw4Q4gsm7EUacqOOaVxHrm3MVhYjE -Bfk9I5agKFqeHdjBUUP0DQ6X7JUEtb/Ri8ZrFnyT8sBG7JYnMTXfjPQqdR493cp2 -hWI5reZLi4CCUqt4Pcmhm2vtwJz5HXChARPYq2C3DhdJHcdhxUr97rfTGE1w8mPY -JcwSFnNN47UBcDg6nvSfY3SJKV0gmmqz9fEw1pBoCrudJKw9U0vQrNoCEJOpEETG -4XojbAMsTr0Ps5fI2X1VbVYWtU1uyZxqF8KaTCTN1Paapmqaq4N+qIFrrXA+PTH+ -dyaMLmYJ263Gy5eNkCZMeWLDFZ9WHX/Zx2ERMXfI6fyGImXkb6E0Dia+bB087BZP -9C5gHAvZIjv+FosZrViFqDfrV5hDXL6bO3+V3zieemRxRCTvMtk+RXUJDd50qIOW -gKNcSbevLPOyQH7eQbR+fU4KtJDUigbTFunSn2MZkDl2GDDlKI35wUAVr5yGsJbE -yiIQe5DgLGZcMiEpqbhuqSfuOw0cUlFVyKeNZ/Hr701HWngLt677IY8ExyuNbBfT -PRaes+hcjJ1QmJoRHZx9rQ3w0IpezCpRkRLRKJzzuQZOuwd95whKFXroFsdeaHxO -hS4PqlLbuSMLiSIaPSZM6Huc4kb5lqCaxg/SBlXTCX17Z/8TFoqV/wCJz17XnkH6 -9WtKAC2TwKxiLZ2Qzwr2XV48lASugIOZkSW2qxM9ui+b1T9ICFKRGLn/UB//pOiG -270hNJDLB/BKRExjS+RXeOpdAIJB5XsAEp8h56ub9emhhf9tCEXOn7PN7HbMCnQh -7k8EpAG0h5StLUhY1HHvynVz2/qyMvZa/bIaaudL2565Z6nDU+iBxed7O1qrbRAH -Vakr7Sa3K5niCyH5kxdyO1t29l1ksBqpDUrj+vViFuLkd3XIiui8IA== ------END RSA PRIVATE KEY----- - - - tester - - \ No newline at end of file diff --git a/src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj b/src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj deleted file mode 100644 index 33c9b1c2..00000000 --- a/src/Renci.SshNet.Tests.NET35/Renci.SshNet.Tests.NET35.csproj +++ /dev/null @@ -1,1705 +0,0 @@ - - - - Debug - AnyCPU - - - 2.0 - {007CE8B3-7827-4AD0-AACD-860505638ABE} - Library - Properties - Renci.SshNet.Tests - Renci.SshNet.Tests.NET35 - v3.5 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - true - full - false - bin\Debug\ - TRACE;DEBUG - prompt - 4 - 5 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 0 - - - true - - - ..\Renci.SshNet.snk - - - - - ..\..\packages\Moq.4.2.1409.1722\lib\net35\Moq.dll - - - - 3.5 - - - - - - - False - - - - - Classes\Abstraction\CryptoAbstraction_GenerateRandom.cs - - - Classes\Abstraction\DnsAbstraction_GetHostAddresses.cs - - - Classes\Abstraction\ThreadAbstraction_ExecuteThread.cs - - - Classes\ForwardedPortStatusTest_Started.cs - - - Classes\ForwardedPortStatusTest_Starting.cs - - - Classes\ForwardedPortStatusTest_Stopped.cs - - - Classes\ForwardedPortStatusTest_Stopping.cs - - - Classes\BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs - - - Classes\Channels\ChannelDirectTcpipTest.cs - - - Classes\Channels\ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs - - - Classes\Channels\ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs - - - Classes\Channels\ChannelSessionTest_Disposed_Closed.cs - - - Classes\Channels\ChannelSessionTest_Dispose_Disposed.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs - - - Classes\Channels\ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs - - - Classes\Channels\ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs - - - Classes\Channels\ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs - - - Classes\Channels\ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs - - - Classes\Channels\ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs - - - Classes\Channels\ChannelStub.cs - - - Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs - - - Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs - - - Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs - - - Classes\Channels\ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs - - - Classes\Channels\ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs - - - Classes\Channels\ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs - - - Classes\Channels\ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs - - - Classes\Channels\ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs - - - Classes\Channels\ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs - - - Classes\Channels\ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs - - - Classes\Channels\ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs - - - Classes\Channels\ClientChannelStub.cs - - - Classes\Channels\ClientChannelTest_OnSessionChannelOpenConfirmationReceived_OnOpenConfirmation_Exception.cs - - - Classes\Channels\ClientChannelTest_OnSessionChannelOpenFailureReceived_OnOpenFailure_Exception.cs - - - Classes\CipherInfoTest.cs - - - Classes\ClientAuthenticationTest.cs - - - Classes\ClientAuthenticationTestBase.cs - - - Classes\ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit.cs - - - Classes\ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodFailed.cs - - - Classes\ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodNotConfigured.cs - - - Classes\ClientAuthenticationTest_Success_MultiList_DifferentAllowedAuthenticationsAfterPartialSuccess.cs - - - Classes\ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch.cs - - - Classes\ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch2.cs - - - Classes\ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInSameBranch.cs - - - Classes\ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs - - - Classes\ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInSameBranch.cs - - - Classes\ClientAuthenticationTest_Success_MultiList_SameAllowedAuthenticationsAfterPartialSuccess.cs - - - Classes\ClientAuthenticationTest_Success_MultiList_SkipFailedAuthenticationMethod.cs - - - Classes\ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess.cs - - - Classes\ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess_PartialSuccessLimitReached.cs - - - Classes\CommandAsyncResultTest.cs - - - Classes\Common\ASCIIEncodingTest.cs - - - Classes\Common\AsyncResultTest.cs - - - Classes\Common\AuthenticationBannerEventArgsTest.cs - - - Classes\Common\AuthenticationPasswordChangeEventArgsTest.cs - - - Classes\Common\AuthenticationPromptEventArgsTest.cs - - - Classes\Common\AuthenticationPromptTest.cs - - - Classes\Common\BigIntegerTest.cs - - - Classes\Common\ChannelDataEventArgsTest.cs - - - Classes\Common\ChannelEventArgsTest.cs - - - Classes\Common\ChannelOpenFailedEventArgsTest.cs - - - Classes\Common\ChannelRequestEventArgsTest.cs - - - Classes\Common\CountdownEventTest.cs - - - Classes\Common\CountdownEventTest_Dispose_NotSet.cs - - - Classes\Common\CountdownEventTest_Dispose_Set.cs - - - Classes\Common\DerDataTest.cs - - - Classes\Common\ExceptionEventArgsTest.cs - - - Classes\Common\ExtensionsTest_Concat.cs - - - Classes\Common\ExtensionsTest_IsEqualTo_ByteArray.cs - - - Classes\Common\ExtensionsTest_Reverse.cs - - - Classes\Common\ExtensionsTest_Take_Count.cs - - - Classes\Common\ExtensionsTest_Take_OffsetAndCount.cs - - - Classes\Common\ExtensionsTest_TrimLeadingZeros.cs - - - Classes\Common\HostKeyEventArgsTest.cs - - - Classes\Common\NetConfServerExceptionTest.cs - - - Classes\Common\ObjectIdentifierTest.cs - - - Classes\Common\PipeStreamTest.cs - - - Classes\Common\PipeStream_Close_BlockingRead.cs - - - Classes\Common\PipeStream_Close_BlockingWrite.cs - - - Classes\Common\PipeStream_Flush_BytesRemainingAfterRead.cs - - - Classes\Common\PipeStream_Flush_NoBytesRemainingAfterRead.cs - - - Classes\Common\PortForwardEventArgsTest.cs - - - Classes\Common\PosixPathTest_GetFileName.cs - - - Classes\Common\ProxyExceptionTest.cs - - - Classes\Common\ScpDownloadEventArgsTest.cs - - - Classes\Common\ScpExceptionTest.cs - - - Classes\Common\ScpUploadEventArgsTest.cs - - - Classes\Common\SemaphoreLightTest.cs - - - Classes\Common\SftpPathNotFoundExceptionTest.cs - - - Classes\Common\SftpPermissionDeniedExceptionTest.cs - - - Classes\Common\ShellDataEventArgsTest.cs - - - Classes\Common\SshAuthenticationExceptionTest.cs - - - Classes\Common\SshConnectionExceptionTest.cs - - - Classes\Common\SshDataTest.cs - - - Classes\Common\SshExceptionTest.cs - - - Classes\Common\SshOperationTimeoutExceptionTest.cs - - - Classes\Common\SshPassPhraseNullOrEmptyExceptionTest.cs - - - Classes\Compression\CompressorTest.cs - - - Classes\Compression\ZlibOpenSshTest.cs - - - Classes\Compression\ZlibStreamTest.cs - - - Classes\Compression\ZlibTest.cs - - - Classes\ConnectionInfoTest.cs - - - Classes\ExpectActionTest.cs - - - Classes\ForwardedPortDynamicTest.cs - - - Classes\ForwardedPortDynamicTest_Dispose_PortDisposed.cs - - - Classes\ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs - - - Classes\ForwardedPortDynamicTest_Dispose_PortStarted_ChannelBound.cs - - - Classes\ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs - - - Classes\ForwardedPortDynamicTest_Dispose_PortStopped.cs - - - Classes\ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs - - - Classes\ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs - - - Classes\ForwardedPortDynamicTest_Start_PortDisposed.cs - - - Classes\ForwardedPortDynamicTest_Start_PortNeverStarted.cs - - - Classes\ForwardedPortDynamicTest_Start_PortStarted.cs - - - Classes\ForwardedPortDynamicTest_Start_PortStopped.cs - - - Classes\ForwardedPortDynamicTest_Start_SessionNotConnected.cs - - - Classes\ForwardedPortDynamicTest_Start_SessionNull.cs - - - Classes\ForwardedPortDynamicTest_Stop_PortDisposed.cs - - - Classes\ForwardedPortDynamicTest_Stop_PortNeverStarted.cs - - - Classes\ForwardedPortDynamicTest_Stop_PortStarted_ChannelBound.cs - - - Classes\ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs - - - Classes\ForwardedPortDynamicTest_Stop_PortStopped.cs - - - Classes\ForwardedPortLocalTest.cs - - - Classes\ForwardedPortLocalTest_Dispose_PortDisposed.cs - - - Classes\ForwardedPortLocalTest_Dispose_PortDisposed_NeverStarted.cs - - - Classes\ForwardedPortLocalTest_Dispose_PortNeverStarted.cs - - - Classes\ForwardedPortLocalTest_Dispose_PortStarted_ChannelBound.cs - - - Classes\ForwardedPortLocalTest_Dispose_PortStarted_ChannelNotBound.cs - - - Classes\ForwardedPortLocalTest_Dispose_PortStopped.cs - - - Classes\ForwardedPortLocalTest_Start_PortDisposed.cs - - - Classes\ForwardedPortLocalTest_Start_PortNeverStarted.cs - - - Classes\ForwardedPortLocalTest_Start_PortStarted.cs - - - Classes\ForwardedPortLocalTest_Start_PortStopped.cs - - - Classes\ForwardedPortLocalTest_Start_SessionNotConnected.cs - - - Classes\ForwardedPortLocalTest_Start_SessionNull.cs - - - Classes\ForwardedPortLocalTest_Stop_PortDisposed.cs - - - Classes\ForwardedPortLocalTest_Stop_PortNeverStarted.cs - - - Classes\ForwardedPortLocalTest_Stop_PortStarted_ChannelBound.cs - - - Classes\ForwardedPortLocalTest_Stop_PortStarted_ChannelNotBound.cs - - - Classes\ForwardedPortLocalTest_Stop_PortStopped.cs - - - Classes\ForwardedPortRemoteTest.cs - - - Classes\ForwardedPortRemoteTest_Dispose_PortDisposed.cs - - - Classes\ForwardedPortRemoteTest_Dispose_PortNeverStarted.cs - - - Classes\ForwardedPortRemoteTest_Dispose_PortStarted_ChannelBound.cs - - - Classes\ForwardedPortRemoteTest_Dispose_PortStopped.cs - - - Classes\ForwardedPortRemoteTest_Started.cs - - - Classes\ForwardedPortRemoteTest_Start_PortDisposed.cs - - - Classes\ForwardedPortRemoteTest_Start_PortNeverStarted.cs - - - Classes\ForwardedPortRemoteTest_Start_PortStarted.cs - - - Classes\ForwardedPortRemoteTest_Start_PortStopped.cs - - - Classes\ForwardedPortRemoteTest_Start_SessionNotConnected.cs - - - Classes\ForwardedPortRemoteTest_Start_SessionNull.cs - - - Classes\ForwardedPortRemoteTest_Stop_PortDisposed.cs - - - Classes\ForwardedPortRemoteTest_Stop_PortNeverStarted.cs - - - Classes\ForwardedPortRemoteTest_Stop_PortStarted_ChannelBound.cs - - - Classes\ForwardedPortRemoteTest_Stop_PortStopped.cs - - - Classes\KeyboardInteractiveAuthenticationMethodTest.cs - - - Classes\KeyboardInteractiveConnectionInfoTest.cs - - - Classes\MessageEventArgsTest.cs - - - Classes\Messages\Authentication\BannerMessageTest.cs - - - Classes\Messages\Authentication\FailureMessageTest.cs - - - Classes\Messages\Authentication\InformationRequestMessageTest.cs - - - Classes\Messages\Authentication\InformationResponseMessageTest.cs - - - Classes\Messages\Authentication\PasswordChangeRequiredMessageTest.cs - - - Classes\Messages\Authentication\PublicKeyMessageTest.cs - - - Classes\Messages\Authentication\RequestMessageHostTest.cs - - - Classes\Messages\Authentication\RequestMessageKeyboardInteractiveTest.cs - - - Classes\Messages\Authentication\RequestMessageNoneTest.cs - - - Classes\Messages\Authentication\RequestMessagePasswordTest.cs - - - Classes\Messages\Authentication\RequestMessagePublicKeyTest.cs - - - Classes\Messages\Authentication\SuccessMessageTest.cs - - - Classes\Messages\Connection\ChannelCloseMessageTest.cs - - - Classes\Messages\Connection\ChannelDataMessageTest.cs - - - Classes\Messages\Connection\ChannelEofMessageTest.cs - - - Classes\Messages\Connection\ChannelExtendedDataMessageTest.cs - - - Classes\Messages\Connection\ChannelFailureMessageTest.cs - - - Classes\Messages\Connection\ChannelMessageTest.cs - - - Classes\Messages\Connection\ChannelOpenConfirmationMessageTest.cs - - - Classes\Messages\Connection\ChannelOpenFailureMessageTest.cs - - - Classes\Messages\Connection\ChannelOpenInfoTest.cs - - - Classes\Messages\Connection\ChannelOpen\ChannelOpenMessageTest.cs - - - Classes\Messages\Connection\ChannelOpen\DirectTcpipChannelInfoTest.cs - - - Classes\Messages\Connection\ChannelOpen\ForwardedTcpipChannelInfoTest.cs - - - Classes\Messages\Connection\ChannelOpen\SessionChannelOpenInfoTest.cs - - - Classes\Messages\Connection\ChannelOpen\X11ChannelOpenInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\BreakRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\ChannelRequestMessageTest.cs - - - Classes\Messages\Connection\ChannelRequest\EndOfWriteRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\EnvironmentVariableRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\ExecRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\ExitSignalRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\ExitStatusRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\KeepAliveRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\PseudoTerminalInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\ShellRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\SignalRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\SubsystemRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\WindowChangeRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\X11ForwardingRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelRequest\XonXoffRequestInfoTest.cs - - - Classes\Messages\Connection\ChannelSuccessMessageTest.cs - - - Classes\Messages\Connection\ChannelWindowAdjustMessageTest.cs - - - Classes\Messages\Connection\GlobalRequestMessageTest.cs - - - Classes\Messages\Connection\RequestFailureMessageTest.cs - - - Classes\Messages\Connection\RequestInfoTest.cs - - - Classes\Messages\Connection\RequestSuccessMessageTest.cs - - - Classes\Messages\MessageAttributeTest.cs - - - Classes\Messages\MessageTest.cs - - - Classes\Messages\Transport\DebugMessageTest.cs - - - Classes\Messages\Transport\DisconnectMessageTest.cs - - - Classes\Messages\Transport\IgnoreMessageTest.cs - - - Classes\Messages\Transport\KeyExchangeDhGroupExchangeGroupTest.cs - - - Classes\Messages\Transport\KeyExchangeDhGroupExchangeInitTest.cs - - - Classes\Messages\Transport\KeyExchangeDhGroupExchangeReplyTest.cs - - - Classes\Messages\Transport\KeyExchangeDhGroupExchangeRequestTest.cs - - - Classes\Messages\Transport\KeyExchangeDhInitMessageTest.cs - - - Classes\Messages\Transport\KeyExchangeDhReplyMessageTest.cs - - - Classes\Messages\Transport\KeyExchangeInitMessageTest.cs - - - Classes\Messages\Transport\NewKeysMessageTest.cs - - - Classes\Messages\Transport\ServiceAcceptMessageTest.cs - - - Classes\Messages\Transport\ServiceRequestMessageTest.cs - - - Classes\Messages\Transport\UnimplementedMessageTest.cs - - - Classes\NetConfClientTest.cs - - - Classes\NoneAuthenticationMethodTest.cs - - - Classes\PasswordAuthenticationMethodTest.cs - - - Classes\PasswordConnectionInfoTest.cs - - - Classes\PrivateKeyAuthenticationMethodTest.cs - - - Classes\PrivateKeyConnectionInfoTest.cs - - - Classes\PrivateKeyFileTest.cs - - - Classes\RemotePathDoubleQuoteTransformationTest.cs - - - Classes\RemotePathShellQuoteTransformationTest.cs - - - Classes\ScpClientTest.cs - - - Classes\ScpClientTestBase.cs - - - Classes\ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs - - - Classes\ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs - - - Classes\ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs - - - Classes\ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs - - - Classes\ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs - - - Classes\ScpClientTest_Upload_FileInfoAndPath_Success.cs - - - Classes\ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs - - - Classes\Security\CertificateHostAlgorithmTest.cs - - - Classes\Security\Cryptography\Ciphers\AesCipherTest.cs - - - Classes\Security\Cryptography\Ciphers\Arc4CipherTest.cs - - - Classes\Security\Cryptography\Ciphers\BlowfishCipherTest.cs - - - Classes\Security\Cryptography\Ciphers\CastCipherTest.cs - - - Classes\Security\Cryptography\Ciphers\CipherModeTest.cs - - - Classes\Security\Cryptography\Ciphers\CipherPaddingTest.cs - - - Classes\Security\Cryptography\Ciphers\DesCipherTest.cs - - - Classes\Security\Cryptography\Ciphers\Modes\CbcCipherModeTest.cs - - - Classes\Security\Cryptography\Ciphers\Modes\CfbCipherModeTest.cs - - - Classes\Security\Cryptography\Ciphers\Modes\CtrCipherModeTest.cs - - - Classes\Security\Cryptography\Ciphers\Modes\OfbCipherModeTest.cs - - - Classes\Security\Cryptography\Ciphers\Paddings\PKCS5PaddingTest.cs - - - Classes\Security\Cryptography\Ciphers\Paddings\PKCS7PaddingTest.cs - - - Classes\Security\Cryptography\Ciphers\RsaCipherTest.cs - - - Classes\Security\Cryptography\Ciphers\SerpentCipherTest.cs - - - Classes\Security\Cryptography\Ciphers\TripleDesCipherTest.cs - - - Classes\Security\Cryptography\Ciphers\TwofishCipherTest.cs - - - Classes\Security\Cryptography\DsaDigitalSignatureTest.cs - - - Classes\Security\Cryptography\DsaKeyTest.cs - - - Classes\Security\Cryptography\HMacTest.cs - - - Classes\Security\Cryptography\RsaDigitalSignatureTest.cs - - - Classes\Security\Cryptography\RsaKeyTest.cs - - - Classes\Security\KeyExchangeDiffieHellmanGroup14Sha1Test.cs - - - Classes\Security\KeyExchangeDiffieHellmanGroup1Sha1Test.cs - - - Classes\Security\KeyExchangeDiffieHellmanGroupExchangeSha1Test.cs - - - Classes\Security\KeyExchangeDiffieHellmanGroupExchangeSha256Test.cs - - - Classes\Security\KeyHostAlgorithmTest.cs - - - Classes\ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs - - - Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs - - - Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs - - - Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs - - - Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs - - - Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs - - - Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs - - - Classes\ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs - - - Classes\ServiceFactoryTest_CreateShellStream.cs - - - Classes\SessionTest.cs - - - Classes\SessionTest.HttpProxy.cs - - - Classes\SessionTest_Connected.cs - - - Classes\SessionTest_ConnectedBase.cs - - - Classes\SessionTest_Connected_ConnectionReset.cs - - - Classes\SessionTest_Connected_Disconnect.cs - - - Classes\SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs - - - Classes\SessionTest_Connected_ServerAndClientDisconnectRace.cs - - - Classes\SessionTest_Connected_ServerSendsBadPacket.cs - - - Classes\SessionTest_Connected_ServerSendsDisconnectMessage.cs - - - Classes\SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs - - - Classes\SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs - - - Classes\SessionTest_Connected_ServerShutsDownSocket.cs - - - Classes\SessionTest_NotConnected.cs - - - Classes\SessionTest_SocketConnected_BadPacketAndDispose.cs - - - Classes\SftpClientTest.ChangeDirectory.cs - - - Classes\SftpClientTest.Connect.cs - - - Classes\SftpClientTest.CreateDirectory.cs - - - Classes\SftpClientTest.cs - - - Classes\SftpClientTest.DeleteDirectory.cs - - - Classes\SftpClientTest.DeleteFile.cs - - - Classes\SftpClientTest.Download.cs - - - Classes\SftpClientTest.ListDirectory.cs - - - Classes\SftpClientTest.RenameFile.cs - - - Classes\SftpClientTest.SynchronizeDirectories.cs - - - Classes\SftpClientTest.Upload.cs - - - Classes\Sftp\Requests\ExtendedRequests\FStatVfsRequestTest.cs - - - Classes\Sftp\Requests\ExtendedRequests\HardLinkRequestTest.cs - - - Classes\Sftp\Requests\ExtendedRequests\PosixRenameRequestTest.cs - - - Classes\Sftp\Requests\ExtendedRequests\StatVfsRequestTest.cs - - - Classes\Sftp\Requests\SftpBlockRequestTest.cs - - - Classes\Sftp\Requests\SftpCloseRequestTest.cs - - - Classes\Sftp\Requests\SftpFSetStatRequestTest.cs - - - Classes\Sftp\Requests\SftpFStatRequestTest.cs - - - Classes\Sftp\Requests\SftpInitRequestTest.cs - - - Classes\Sftp\Requests\SftpLinkRequestTest.cs - - - Classes\Sftp\Requests\SftpLStatRequestTest.cs - - - Classes\Sftp\Requests\SftpMkDirRequestTest.cs - - - Classes\Sftp\Requests\SftpOpenDirRequestTest.cs - - - Classes\Sftp\Requests\SftpOpenRequestTest.cs - - - Classes\Sftp\Requests\SftpReadDirRequestTest.cs - - - Classes\Sftp\Requests\SftpReadLinkRequestTest.cs - - - Classes\Sftp\Requests\SftpReadRequestTest.cs - - - Classes\Sftp\Requests\SftpRealPathRequestTest.cs - - - Classes\Sftp\Requests\SftpRemoveRequestTest.cs - - - Classes\Sftp\Requests\SftpRenameRequestTest.cs - - - Classes\Sftp\Requests\SftpRmDirRequestTest.cs - - - Classes\Sftp\Requests\SftpSetStatRequestTest.cs - - - Classes\Sftp\Requests\SftpStatRequestTest.cs - - - Classes\Sftp\Requests\SftpSymLinkRequestTest.cs - - - Classes\Sftp\Requests\SftpUnblockRequestTest.cs - - - Classes\Sftp\Requests\SftpWriteRequestTest.cs - - - Classes\Sftp\Responses\ExtendedReplies\StatVfsReplyInfoTest.cs - - - Classes\Sftp\Responses\SftpAttrsResponseTest.cs - - - Classes\Sftp\Responses\SftpDataResponseTest.cs - - - Classes\Sftp\Responses\SftpExtendedReplyResponseTest.cs - - - Classes\Sftp\Responses\SftpHandleResponseTest.cs - - - Classes\Sftp\Responses\SftpNameResponseTest.cs - - - Classes\Sftp\Responses\SftpStatusResponseTest.cs - - - Classes\Sftp\Responses\SftpVersionResponseTest.cs - - - Classes\Sftp\SftpDataResponseBuilder.cs - - - Classes\Sftp\SftpDownloadAsyncResultTest.cs - - - Classes\Sftp\SftpFileAttributesTest.cs - - - Classes\Sftp\SftpFileReaderTestBase.cs - - - Classes\Sftp\SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs - - - Classes\Sftp\SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs - - - Classes\Sftp\SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs - - - Classes\Sftp\SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs - - - Classes\Sftp\SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs - - - Classes\Sftp\SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs - - - Classes\Sftp\SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs - - - Classes\Sftp\SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs - - - Classes\Sftp\SftpFileReaderTest_ReadAheadBeginReadException.cs - - - Classes\Sftp\SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs - - - Classes\Sftp\SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs - - - Classes\Sftp\SftpFileReaderTest_ReadBackBeginReadException.cs - - - Classes\Sftp\SftpFileReaderTest_ReadBackEndInvokeException.cs - - - Classes\Sftp\SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs - - - Classes\Sftp\SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs - - - Classes\Sftp\SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs - - - Classes\Sftp\SftpFileStreamTestBase.cs - - - Classes\Sftp\SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Close_Closed.cs - - - Classes\Sftp\SftpFileStreamTest_Close_Disposed.cs - - - Classes\Sftp\SftpFileStreamTest_Close_SessionNotOpen.cs - - - Classes\Sftp\SftpFileStreamTest_Close_SessionOpen.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileAccessInvalid.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeInvalid.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Dispose_Closed.cs - - - Classes\Sftp\SftpFileStreamTest_Dispose_Disposed.cs - - - Classes\Sftp\SftpFileStreamTest_Dispose_SessionNotOpen.cs - - - Classes\Sftp\SftpFileStreamTest_Dispose_SessionOpen.cs - - - Classes\Sftp\SftpFileStreamTest_Finalize_SessionOpen.cs - - - Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs - - - Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs - - - Classes\Sftp\SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs - - - Classes\Sftp\SftpFileStreamTest_Flush_SessionNotOpen.cs - - - Classes\Sftp\SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs - - - Classes\Sftp\SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs - - - Classes\Sftp\SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs - - - Classes\Sftp\SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs - - - Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs - - - Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs - - - Classes\Sftp\SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs - - - Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetNegative.cs - - - Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs - - - Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetZero.cs - - - Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs - - - Classes\Sftp\SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_Closed.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_Disposed.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_SessionNotOpen.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs - - - Classes\Sftp\SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs - - - Classes\Sftp\SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs - - - Classes\Sftp\SftpFileSystemInformationTest.cs - - - Classes\Sftp\SftpFileTest.cs - - - Classes\Sftp\SftpHandleResponseBuilder.cs - - - Classes\Sftp\SftpInitRequestBuilder.cs - - - Classes\Sftp\SftpListDirectoryAsyncResultTest.cs - - - Classes\Sftp\SftpNameResponseBuilder.cs - - - Classes\Sftp\SftpOpenRequestBuilder.cs - - - Classes\Sftp\SftpReadRequestBuilder.cs - - - Classes\Sftp\SftpRealPathRequestBuilder.cs - - - Classes\Sftp\SftpSessionTest_Connected_RequestRead.cs - - - Classes\Sftp\SftpSessionTest_Connected_RequestStatVfs.cs - - - Classes\Sftp\SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs - - - Classes\Sftp\SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs - - - Classes\Sftp\SftpSessionTest_DataReceived_SingleSftpMessageInSshDataMessage.cs - - - Classes\Sftp\SftpStatVfsRequestBuilder.cs - - - Classes\Sftp\SftpStatVfsResponseBuilder.cs - - - Classes\Sftp\SftpSynchronizeDirectoriesAsyncResultTest.cs - - - Classes\Sftp\SftpUploadAsyncResultTest.cs - - - Classes\Sftp\SftpVersionResponseBuilder.cs - - - Classes\ShellStreamTest.cs - - - Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs - - - Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs - - - Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs - - - Classes\ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs - - - Classes\ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs - - - Classes\ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs - - - Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs - - - Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs - - - Classes\ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs - - - Classes\ShellTestTest.cs - - - Classes\SshClientTest.cs - - - Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs - - - Classes\SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs - - - Classes\SshClientTest_Disconnect_ForwardedPortStarted.cs - - - Classes\SshClientTest_Dispose_ForwardedPortStarted.cs - - - Classes\SshCommandTest.cs - - - Classes\SshCommandTest_BeginExecute_EndExecuteInvokedOnAsyncResultFromPreviousInvocation.cs - - - Classes\SshCommandTest_BeginExecute_EndExecuteNotInvokedOnAsyncResultFromPreviousInvocation.cs - - - Classes\SshCommandTest_Dispose.cs - - - Classes\SshCommandTest_EndExecute.cs - - - Classes\SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs - - - Classes\SshCommandTest_EndExecute_AsyncResultIsNull.cs - - - Classes\SshCommandTest_EndExecute_ChannelOpen.cs - - - Classes\SubsystemSessionStub.cs - - - Classes\SubsystemSession_Connect_Connected.cs - - - Classes\SubsystemSession_Connect_Disconnected.cs - - - Classes\SubsystemSession_Connect_Disposed.cs - - - Classes\SubsystemSession_Connect_NeverConnected.cs - - - Classes\SubsystemSession_Disconnect_Connected.cs - - - Classes\SubsystemSession_Disconnect_Disposed.cs - - - Classes\SubsystemSession_Disconnect_NeverConnected.cs - - - Classes\SubsystemSession_Dispose_Connected.cs - - - Classes\SubsystemSession_Dispose_Disconnected.cs - - - Classes\SubsystemSession_Dispose_Disposed.cs - - - Classes\SubsystemSession_Dispose_NeverConnected.cs - - - Classes\SubsystemSession_OnChannelDataReceived_Connected.cs - - - Classes\SubsystemSession_OnChannelDataReceived_Disposed.cs - - - Classes\SubsystemSession_OnChannelDataReceived_OnDataReceived_Exception.cs - - - Classes\SubsystemSession_OnChannelException_Connected.cs - - - Classes\SubsystemSession_OnChannelException_Disposed.cs - - - Classes\SubsystemSession_OnSessionDisconnected_Connected.cs - - - Classes\SubsystemSession_OnSessionDisconnected_Disposed.cs - - - Classes\SubsystemSession_OnSessionErrorOccurred_Connected.cs - - - Classes\SubsystemSession_OnSessionErrorOccurred_Disposed.cs - - - Classes\SubsystemSession_SendData_Connected.cs - - - Classes\SubsystemSession_SendData_Disconnected.cs - - - Classes\SubsystemSession_SendData_Disposed.cs - - - Classes\SubsystemSession_SendData_NeverConnected.cs - - - Common\ArrayBuilder.cs - - - Common\AsyncSocketListener.cs - - - Common\DictionaryAssert.cs - - - Common\Extensions.cs - - - Common\HttpProxyStub.cs - - - Common\HttpRequest.cs - - - Common\SftpFileAttributesBuilder.cs - - - Common\TestBase.cs - - - - - - - Properties\CommonAssemblyInfo.cs - - - True - True - Resources.resx - - - - - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A} - Renci.SshNet.NET35 - - - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - - - Data\Key.RSA.Encrypted.Aes.128.CBC.12345.txt - - - Data\Key.RSA.Encrypted.Aes.192.CBC.12345.txt - - - Data\Key.RSA.Encrypted.Aes.256.CBC.12345.txt - - - Data\Key.RSA.Encrypted.Des.CBC.12345.txt - - - Data\Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt - - - Data\Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt - - - Data\Key.RSA.txt - - - - - Renci.SshNet.snk - - - - - - Data\Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt - - - Data\Key.SSH2.DSA.txt - - - Data\Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt - - - Data\Key.SSH2.RSA.txt - - - - - - - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.Tests.NET35/packages.config b/src/Renci.SshNet.Tests.NET35/packages.config deleted file mode 100644 index e9365957..00000000 --- a/src/Renci.SshNet.Tests.NET35/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs new file mode 100644 index 00000000..792ab89d --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs @@ -0,0 +1,181 @@ +using System; +using System.Reflection; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Common; +using Renci.SshNet.Security; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class BaseClientTest_Connect_OnConnectedThrowsException + { + private Mock _serviceFactoryMock; + private Mock _sessionMock; + private MyClient _client; + private ConnectionInfo _connectionInfo; + private ApplicationException _onConnectException; + private ApplicationException _actualException; + + [TestInitialize] + public void Setup() + { + Arrange(); + Act(); + } + + [TestCleanup] + public void Cleanup() + { + if (_client != null) + { + _sessionMock.Setup(p => p.OnDisconnecting()); + _sessionMock.Setup(p => p.Dispose()); + _client.Dispose(); + } + } + + private void SetupData() + { + _connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd")); + _onConnectException = new ApplicationException(); + } + + private void CreateMocks() + { + _serviceFactoryMock = new Mock(MockBehavior.Strict); + _sessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo)) + .Returns(_sessionMock.Object); + _sessionMock.Setup(p => p.Connect()); + _sessionMock.Setup(p => p.Dispose()); + } + + protected void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object) + { + OnConnectedException = _onConnectException + }; + } + + protected void Act() + { + try + { + _client.Connect(); + Assert.Fail(); + } + catch (ApplicationException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void ConnectShouldRethrowExceptionThrownByOnConnect() + { + Assert.IsNotNull(_actualException); + Assert.AreSame(_onConnectException, _actualException); + } + + [TestMethod] + public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() + { + _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once); + } + + [TestMethod] + public void ConnectOnSessionShouldBeInvokedOnce() + { + _sessionMock.Verify(p => p.Connect(), Times.Once); + } + + [TestMethod] + public void DisposeOnSessionShouldBeInvokedOnce() + { + _sessionMock.Verify(p => p.Dispose(), Times.Once); + } + + [TestMethod] + public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnBaseClient() + { + var errorOccurredSignalCount = 0; + + _client.ErrorOccurred += (sender, args) => Interlocked.Increment(ref errorOccurredSignalCount); + + _sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); + + Assert.AreEqual(0, errorOccurredSignalCount); + } + + [TestMethod] + public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOnBaseClient() + { + var hostKeyReceivedSignalCount = 0; + + _client.HostKeyReceived += (sender, args) => Interlocked.Increment(ref hostKeyReceivedSignalCount); + + _sessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); + + Assert.AreEqual(0, hostKeyReceivedSignalCount); + } + + [TestMethod] + public void SessionShouldBeNull() + { + Assert.IsNull(_client.Session); + } + + [TestMethod] + public void IsConnectedShouldReturnFalse() + { + Assert.IsFalse(_client.IsConnected); + } + + private static KeyHostAlgorithm GetKeyHostAlgorithm() + { + var executingAssembly = Assembly.GetExecutingAssembly(); + + using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + { + var privateKey = new PrivateKeyFile(s); + return (KeyHostAlgorithm) privateKey.HostKey; + } + } + + private class MyClient : BaseClient + { + private int _onConnectedCount; + + public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory) + { + } + + public Exception OnConnectedException { get; set; } + + protected override void OnConnected() + { + base.OnConnected(); + + Interlocked.Increment(ref _onConnectedCount); + + if (OnConnectedException != null) + { + throw OnConnectedException; + } + } + } + + + } +} diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs new file mode 100644 index 00000000..fb58e1f4 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs @@ -0,0 +1,121 @@ +using System; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class BaseClientTest_Connected_KeepAliveInterval_NegativeOne + { + private Mock _serviceFactoryMock; + private Mock _sessionMock; + private BaseClient _client; + private ConnectionInfo _connectionInfo; + private TimeSpan _keepAliveInterval; + private int _keepAliveCount; + + [TestInitialize] + public void Setup() + { + Arrange(); + Act(); + } + + [TestCleanup] + public void Cleanup() + { + if (_client != null) + { + _sessionMock.Setup(p => p.OnDisconnecting()); + _sessionMock.Setup(p => p.Dispose()); + _client.Dispose(); + } + } + + private void SetupData() + { + _connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd")); + _keepAliveInterval = TimeSpan.FromMilliseconds(100d); + _keepAliveCount = 0; + } + + private void CreateMocks() + { + _serviceFactoryMock = new Mock(MockBehavior.Strict); + _sessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo)) + .Returns(_sessionMock.Object); + _sessionMock.Setup(p => p.Connect()); + _sessionMock.Setup(p => p.IsConnected).Returns(true); + _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true) + .Callback(() => Interlocked.Increment(ref _keepAliveCount)); + } + + protected void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + _client.Connect(); + _client.KeepAliveInterval = _keepAliveInterval; + } + + protected void Act() + { + // allow keep-alive to be sent once + Thread.Sleep(150); + + // disable keep-alive + _client.KeepAliveInterval = TimeSpan.FromMilliseconds(-1); + } + + [TestMethod] + public void KeepAliveIntervalShouldReturnConfiguredValue() + { + Assert.AreEqual(TimeSpan.FromMilliseconds(-1), _client.KeepAliveInterval); + } + + [TestMethod] + public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() + { + _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once); + } + + [TestMethod] + public void ConnectOnSessionShouldBeInvokedOnce() + { + _sessionMock.Verify(p => p.Connect(), Times.Once); + } + + [TestMethod] + public void IsConnectedOnSessionShouldBeInvokedOnce() + { + _sessionMock.Verify(p => p.IsConnected, Times.Once); + } + + [TestMethod] + public void SendMessageOnSessionShouldBeInvokedThreeTimes() + { + // allow keep-alive to be sent once + Thread.Sleep(100); + + _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(1)); + } + + private class MyClient : BaseClient + { + public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory) + { + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs new file mode 100644 index 00000000..a3c807bd --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs @@ -0,0 +1,116 @@ +using System; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne + { + private Mock _serviceFactoryMock; + private Mock _sessionMock; + private BaseClient _client; + private ConnectionInfo _connectionInfo; + private TimeSpan _keepAliveInterval; + private int _keepAliveCount; + + [TestInitialize] + public void Setup() + { + Arrange(); + Act(); + } + + [TestCleanup] + public void Cleanup() + { + if (_client != null) + { + _sessionMock.Setup(p => p.OnDisconnecting()); + _sessionMock.Setup(p => p.Dispose()); + _client.Dispose(); + } + } + + private void SetupData() + { + _connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd")); + _keepAliveInterval = TimeSpan.FromMilliseconds(50d); + _keepAliveCount = 0; + } + + private void CreateMocks() + { + _serviceFactoryMock = new Mock(MockBehavior.Strict); + _sessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo)) + .Returns(_sessionMock.Object); + _sessionMock.Setup(p => p.Connect()); + _sessionMock.Setup(p => p.IsConnected).Returns(true); + _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true) + .Callback(() => Interlocked.Increment(ref _keepAliveCount)); + } + + protected void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + _client.Connect(); + } + + protected void Act() + { + _client.KeepAliveInterval = _keepAliveInterval; + + // allow keep-alive to be sent a few times + Thread.Sleep(195); + } + + [TestMethod] + public void KeepAliveIntervalShouldReturnConfiguredValue() + { + Assert.AreEqual(_keepAliveInterval, _client.KeepAliveInterval); + } + + [TestMethod] + public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() + { + _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once); + } + + [TestMethod] + public void ConnectOnSessionShouldBeInvokedOnce() + { + _sessionMock.Verify(p => p.Connect(), Times.Once); + } + + [TestMethod] + public void IsConnectedOnSessionShouldBeInvokedOnce() + { + _sessionMock.Verify(p => p.IsConnected, Times.Once); + } + + [TestMethod] + public void SendMessageOnSessionShouldBeInvokedThreeTimes() + { + _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(3)); + } + + private class MyClient : BaseClient + { + public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory) + { + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs index 262668d7..4430b657 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs @@ -34,25 +34,38 @@ namespace Renci.SshNet.Tests.Classes } } - protected void Arrange() + private void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd")); _keepAliveSent = new ManualResetEvent(false); + } + private void CreateMocks() + { _serviceFactoryMock = new Mock(MockBehavior.Strict); _sessionMock = new Mock(MockBehavior.Strict); + } + private void SetupMocks() + { _mockSequence = new MockSequence(); _serviceFactoryMock.InSequence(_mockSequence).Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object); _sessionMock.InSequence(_mockSequence).Setup(p => p.Connect()); _sessionMock.InSequence(_mockSequence).Setup(p => p.TrySendMessage(It.IsAny())) - .Returns(true) - .Callback(() => - { - Thread.Sleep(300); - _keepAliveSent.Set(); - }); + .Returns(true) + .Callback(() => + { + Thread.Sleep(300); + _keepAliveSent.Set(); + }); + } + + protected void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object) { diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs new file mode 100644 index 00000000..588bfd83 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs @@ -0,0 +1,113 @@ +using System; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne + { + private Mock _serviceFactoryMock; + private Mock _sessionMock; + private BaseClient _client; + private ConnectionInfo _connectionInfo; + private TimeSpan _keepAliveInterval; + + [TestInitialize] + public void Setup() + { + Arrange(); + Act(); + } + + [TestCleanup] + public void Cleanup() + { + if (_client != null) + { + _sessionMock.Setup(p => p.OnDisconnecting()); + _sessionMock.Setup(p => p.Dispose()); + _client.Dispose(); + } + } + + private void SetupData() + { + _connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd")); + _keepAliveInterval = TimeSpan.FromMilliseconds(50d); + } + + private void CreateMocks() + { + _serviceFactoryMock = new Mock(MockBehavior.Strict); + _sessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo)) + .Returns(_sessionMock.Object); + _sessionMock.Setup(p => p.Connect()); + _sessionMock.Setup(p => p.IsConnected).Returns(false); + _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true); + } + + protected void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + _client.Connect(); + } + + protected void Act() + { + _client.KeepAliveInterval = _keepAliveInterval; + + // allow keep-alive to be sent a few times + Thread.Sleep(195); + } + + [TestMethod] + public void KeepAliveIntervalShouldReturnConfiguredValue() + { + Assert.AreEqual(_keepAliveInterval, _client.KeepAliveInterval); + } + + [TestMethod] + public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() + { + _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo), Times.Once); + } + + [TestMethod] + public void ConnectOnSessionShouldBeInvokedOnce() + { + _sessionMock.Verify(p => p.Connect(), Times.Once); + } + + [TestMethod] + public void IsConnectedOnSessionShouldBeInvokedOnce() + { + _sessionMock.Verify(p => p.IsConnected, Times.Once); + } + + [TestMethod] + public void SendMessageOnSessionShouldNeverBeInvoked() + { + _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Never); + } + + private class MyClient : BaseClient + { + public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory) + { + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs new file mode 100644 index 00000000..dfaa8b27 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs @@ -0,0 +1,102 @@ +using System; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne + { + private Mock _serviceFactoryMock; + private Mock _sessionMock; + private BaseClient _client; + private ConnectionInfo _connectionInfo; + private TimeSpan _keepAliveInterval; + private int _keepAliveCount; + + [TestInitialize] + public void Setup() + { + Arrange(); + Act(); + } + + [TestCleanup] + public void Cleanup() + { + if (_client != null) + { + _sessionMock.Setup(p => p.OnDisconnecting()); + _sessionMock.Setup(p => p.Dispose()); + _client.Dispose(); + } + } + + private void SetupData() + { + _connectionInfo = new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "pwd")); + _keepAliveInterval = TimeSpan.FromMilliseconds(100d); + _keepAliveCount = 0; + } + + private void CreateMocks() + { + _serviceFactoryMock = new Mock(MockBehavior.Strict); + _sessionMock = new Mock(MockBehavior.Strict); + } + + private static void SetupMocks() + { + } + + protected void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + } + + protected void Act() + { + _client.KeepAliveInterval = _keepAliveInterval; + + // allow keep-alive to be sent at least once + Thread.Sleep(150); + } + + [TestMethod] + public void KeepAliveIntervalShouldReturnConfiguredValue() + { + Assert.AreEqual(_keepAliveInterval, _client.KeepAliveInterval); + } + + [TestMethod] + public void ConnectShouldActivateKeepAliveIfSessionIs() + { + _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo)).Returns(_sessionMock.Object); + _sessionMock.Setup(p => p.Connect()); + _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true) + .Callback(() => Interlocked.Increment(ref _keepAliveCount)); + + _client.Connect(); + + // allow keep-alive to be sent twice + Thread.Sleep(250); + + // Exactly two keep-alives should be sent + _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(2)); + } + + private class MyClient : BaseClient + { + public MyClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory) + { + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs index 804e477a..1dce239e 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs @@ -27,6 +27,7 @@ namespace Renci.SshNet.Tests.Classes.Channels private uint _remoteWindowSize; private uint _remotePacketSize; private uint _remoteChannelNumber; + private TimeSpan _channelCloseTimeout; protected override void OnInit() { @@ -40,8 +41,9 @@ namespace Renci.SshNet.Tests.Classes.Channels _port = (uint) random.Next(IPEndPoint.MinPort, IPEndPoint.MaxPort); _localChannelNumber = (uint) random.Next(0, int.MaxValue); _remoteWindowSize = (uint) random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(100, 200); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(100, 200); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _sessionMock = new Mock(MockBehavior.Strict); _forwardedPortMock = new Mock(MockBehavior.Strict); @@ -53,11 +55,14 @@ namespace Renci.SshNet.Tests.Classes.Channels { _sessionMock.Setup(p => p.IsConnected).Returns(true); _sessionMock.Setup(p => p.SendMessage(It.IsAny())) - .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage(((ChannelOpenMessage)m).LocalChannelNumber, _remoteWindowSize, _remotePacketSize, _remoteChannelNumber)))); + .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage(((ChannelOpenMessage) m).LocalChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber)))); _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(p => p.WaitOne(Session.Infinite)); + .Callback(p => p.WaitOne(Session.Infinite)); var localPortEndPoint = new IPEndPoint(IPAddress.Loopback, 8122); using (var localPortListener = new AsyncSocketListener(localPortEndPoint)) @@ -65,25 +70,27 @@ namespace Renci.SshNet.Tests.Classes.Channels localPortListener.Start(); localPortListener.Connected += socket => - { - var channel = new ChannelDirectTcpip(_sessionMock.Object, _localChannelNumber, _localWindowSize, - _localPacketSize); - channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket); + { + var channel = new ChannelDirectTcpip(_sessionMock.Object, + _localChannelNumber, + _localWindowSize, + _localPacketSize); + channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket); - var closeForwardedPortThread = - new Thread(() => - { - // sleep for a short period to allow channel to actually start receiving from socket - Thread.Sleep(100); - // raise Closing event on forwarded port - _forwardedPortMock.Raise(p => p.Closing += null, EventArgs.Empty); - }); - closeForwardedPortThread.Start(); + var closeForwardedPortThread = + new Thread(() => + { + // sleep for a short period to allow channel to actually start receiving from socket + Thread.Sleep(100); + // raise Closing event on forwarded port + _forwardedPortMock.Raise(p => p.Closing += null, EventArgs.Empty); + }); + closeForwardedPortThread.Start(); - channel.Bind(); + channel.Bind(); - closeForwardedPortThread.Join(); - }; + closeForwardedPortThread.Join(); + }; var client = new Socket(localPortEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); client.Connect(localPortEndPoint); @@ -103,11 +110,14 @@ namespace Renci.SshNet.Tests.Classes.Channels { _sessionMock.Setup(p => p.IsConnected).Returns(true); _sessionMock.Setup(p => p.SendMessage(It.IsAny())) - .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage(((ChannelOpenMessage)m).LocalChannelNumber, _remoteWindowSize, _remotePacketSize, _remoteChannelNumber)))); + .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage(((ChannelOpenMessage) m).LocalChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber)))); _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(p => p.WaitOne(Session.Infinite)); + .Callback(p => p.WaitOne(Session.Infinite)); var localPortEndPoint = new IPEndPoint(IPAddress.Loopback, 8122); using (var localPortListener = new AsyncSocketListener(localPortEndPoint)) @@ -116,19 +126,21 @@ namespace Renci.SshNet.Tests.Classes.Channels localPortListener.Connected += socket => { - var channel = new ChannelDirectTcpip(_sessionMock.Object, _localChannelNumber, _localWindowSize, - _localPacketSize); + var channel = new ChannelDirectTcpip(_sessionMock.Object, + _localChannelNumber, + _localWindowSize, + _localPacketSize); channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket); var signalSessionErrorOccurredThread = new Thread(() => - { - // sleep for a short period to allow channel to actually start receiving from socket - Thread.Sleep(100); - // raise ErrorOccured event on session - _sessionMock.Raise(s => s.ErrorOccured += null, - new ExceptionEventArgs(new SystemException())); - }); + { + // sleep for a short period to allow channel to actually start receiving from socket + Thread.Sleep(100); + // raise ErrorOccured event on session + _sessionMock.Raise(s => s.ErrorOccured += null, + new ExceptionEventArgs(new SystemException())); + }); signalSessionErrorOccurredThread.Start(); channel.Bind(); @@ -152,34 +164,49 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void SocketShouldBeClosedAndEofShouldBeSentToServerWhenClientShutsDownSocket() { - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.SendMessage(It.IsAny())) - .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage(((ChannelOpenMessage) m).LocalChannelNumber, - _remoteWindowSize, _remotePacketSize, _remoteChannelNumber)))); - _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(p => p.WaitOne(Session.Infinite)); - _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(60)); - _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) - .Returns(true) - .Callback( - m => new Thread(() => - { - Thread.Sleep(50); - _sessionMock.Raise(s => s.ChannelEofReceived += null, - new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); - }).Start()); - _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) - .Returns(true) - .Callback( - m => new Thread(() => - { - Thread.Sleep(50); - _sessionMock.Raise(s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - }).Start()); + var sequence = new MockSequence(); + + _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + _sessionMock.InSequence(sequence) + .Setup(p => p.SendMessage(It.IsAny())) + .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage(((ChannelOpenMessage) m).LocalChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber)))); + _sessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsAny())) + .Callback(p => p.WaitOne(Session.Infinite)); + _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + _sessionMock.InSequence(sequence) + .Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true) + .Callback( + m => new Thread(() => + { + Thread.Sleep(50); + _sessionMock.Raise(s => s.ChannelEofReceived += null, + new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); + }).Start()); + _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + _sessionMock.InSequence(sequence) + .Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true) + .Callback( + m => new Thread(() => + { + Thread.Sleep(50); + _sessionMock.Raise(s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + }).Start()); + _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); + _connectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + _sessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) + .Returns(WaitResult.Success); + var channelBindFinishedWaitHandle = new ManualResetEvent(false); Socket handler = null; ChannelDirectTcpip channel = null; @@ -190,17 +217,19 @@ namespace Renci.SshNet.Tests.Classes.Channels localPortListener.Start(); localPortListener.Connected += socket => - { - channel = new ChannelDirectTcpip(_sessionMock.Object, _localChannelNumber, _localWindowSize, - _localPacketSize); - channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket); - channel.Bind(); - channel.Dispose(); + { + channel = new ChannelDirectTcpip(_sessionMock.Object, + _localChannelNumber, + _localWindowSize, + _localPacketSize); + channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket); + channel.Bind(); + channel.Dispose(); - handler = socket; + handler = socket; - channelBindFinishedWaitHandle.Set(); - }; + channelBindFinishedWaitHandle.Set(); + }; var client = new Socket(localPortEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); client.Connect(localPortEndPoint); diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs index a99adce1..a75d407d 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs @@ -18,6 +18,7 @@ namespace Renci.SshNet.Tests.Classes.Channels public class ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen { private Mock _sessionMock; + private Mock _connectionInfoMock; private Mock _forwardedPortMock; private ChannelDirectTcpip _channel; private uint _localChannelNumber; @@ -26,6 +27,7 @@ namespace Renci.SshNet.Tests.Classes.Channels private uint _remoteWindowSize; private uint _remotePacketSize; private uint _remoteChannelNumber; + private TimeSpan _channelCloseTimeout; private string _remoteHost; private uint _port; private AsyncSocketListener _listener; @@ -60,9 +62,11 @@ namespace Renci.SshNet.Tests.Classes.Channels private void Arrange() { var random = new Random(); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _localWindowSize = (uint) random.Next(2000, 3000); _localPacketSize = (uint) random.Next(1000, 2000); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _remoteHost = random.Next().ToString(CultureInfo.InvariantCulture); _port = (uint) random.Next(IPEndPoint.MinPort, IPEndPoint.MaxPort); _channelBindFinishedWaitHandle = new ManualResetEvent(false); @@ -74,6 +78,7 @@ namespace Renci.SshNet.Tests.Classes.Channels _remotePacketSize = (uint)random.Next(100, 200); _sessionMock = new Mock(MockBehavior.Strict); + _connectionInfoMock = new Mock(MockBehavior.Strict); _forwardedPortMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); @@ -102,19 +107,20 @@ namespace Renci.SshNet.Tests.Classes.Channels .Returns(true); _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); _sessionMock.InSequence(sequence) - .Setup( - p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Setup(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) .Returns(true); + _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); + _connectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - w.WaitOne(); - }); + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => + { + _sessionMock.Raise( + s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); var localEndpoint = new IPEndPoint(IPAddress.Loopback, 8122); _listener = new AsyncSocketListener(localEndpoint); @@ -122,11 +128,10 @@ namespace Renci.SshNet.Tests.Classes.Channels { try { - _channel = new ChannelDirectTcpip( - _sessionMock.Object, - _localChannelNumber, - _localWindowSize, - _localPacketSize); + _channel = new ChannelDirectTcpip(_sessionMock.Object, + _localChannelNumber, + _localWindowSize, + _localPacketSize); _channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket); _channel.Bind(); } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs index 2ec4c9c9..bbbff6d3 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs @@ -25,6 +25,7 @@ namespace Renci.SshNet.Tests.Classes.Channels private uint _remoteWindowSize; private uint _remotePacketSize; private uint _remoteChannelNumber; + private TimeSpan _channelCloseTimeout; private IPEndPoint _remoteEndpoint; private AsyncSocketListener _remoteListener; private EventWaitHandle _channelBindFinishedWaitHandle; @@ -72,6 +73,7 @@ namespace Renci.SshNet.Tests.Classes.Channels _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(100, 200); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelBindFinishedWaitHandle = new ManualResetEvent(false); _channelException = null; _connectedRegister = new List(); @@ -109,16 +111,18 @@ namespace Renci.SshNet.Tests.Classes.Channels .Setup( p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) .Returns(true); + _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); + _connectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => { _sessionMock.Raise( s => s.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - w.WaitOne(); - }); + waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); _remoteListener = new AsyncSocketListener(_remoteEndpoint); _remoteListener.Connected += socket => _connectedRegister.Add(socket); diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTestBase.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTestBase.cs new file mode 100644 index 00000000..52dfabb9 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTestBase.cs @@ -0,0 +1,37 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace Renci.SshNet.Tests.Classes.Channels +{ + public abstract class ChannelSessionTestBase + { + internal Mock SessionMock { get; private set; } + internal Mock ConnectionInfoMock { get; private set; } + + [TestInitialize] + public void Initialize() + { + Arrange(); + Act(); + } + + protected abstract void SetupData(); + + protected void CreateMocks() + { + SessionMock = new Mock(MockBehavior.Strict); + ConnectionInfoMock = new Mock(MockBehavior.Strict); + } + + protected abstract void SetupMocks(); + + protected virtual void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + } + + protected abstract void Act(); + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs index 75461290..379f7e18 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs @@ -10,10 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_Disposed + public class ChannelSessionTest_Dispose_Disposed : ChannelSessionTestBase { - private Mock _sessionMock; - private Mock _connectionInfoMock; private ChannelSession _channel; private uint _localChannelNumber; private uint _localWindowSize; @@ -21,38 +19,35 @@ namespace Renci.SshNet.Tests.Classes.Channels private uint _remoteWindowSize; private uint _remotePacketSize; private uint _remoteChannelNumber; + private TimeSpan _channelCloseTimeout; private SemaphoreLight _sessionSemaphore; private IList _channelClosedRegister; private List _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); + _localChannelNumber = (uint)random.Next(0, int.MaxValue); _localWindowSize = (uint)random.Next(2000, 3000); _localPacketSize = (uint)random.Next(1000, 2000); _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); _remoteWindowSize = (uint)random.Next(0, int.MaxValue); _remotePacketSize = (uint)random.Next(100, 200); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _sessionSemaphore = new SemaphoreLight(1); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(sequence) + + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) .Setup( p => p.SendMessage( @@ -61,12 +56,12 @@ namespace Renci.SshNet.Tests.Classes.Channels m.LocalChannelNumber == _localChannelNumber && m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(sequence) + SessionMock.InSequence(sequence) .Setup(p => p.WaitOnHandle(It.IsNotNull())) .Callback( w => { - _sessionMock.Raise( + SessionMock.Raise( s => s.ChannelOpenConfirmationReceived += null, new MessageEventArgs( new ChannelOpenConfirmationMessage( @@ -76,31 +71,39 @@ namespace Renci.SshNet.Tests.Classes.Channels _remoteChannelNumber))); w.WaitOne(); }); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) .Setup(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) .Setup(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))).Returns(true); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - w.WaitOne(); - }); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsNotNull(), _channelCloseTimeout)) + .Callback( + (waitHandle, channelCloseTimeout) => + { + SessionMock.Raise( + s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); _channel.Dispose(); } - protected virtual void Act() + protected override void Act() { _channel.Dispose(); } @@ -113,13 +116,13 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void ChannelEofMessageShouldBeSentOnce() { - _sessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); + SessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } [TestMethod] public void ChannelCloseMessageShouldBeSentOnce() { - _sessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); + SessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs index 35e70ac3..be4fdc30 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs @@ -11,52 +11,47 @@ using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) + + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(_sequence) .Setup( p => p.SendMessage( @@ -65,12 +60,12 @@ namespace Renci.SshNet.Tests.Classes.Channels m.LocalChannelNumber == _localChannelNumber && m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(_sequence) .Setup(p => p.WaitOnHandle(It.IsNotNull())) .Callback( w => { - _sessionMock.Raise( + SessionMock.Raise( s => s.ChannelOpenConfirmationReceived += null, new MessageEventArgs( new ChannelOpenConfirmationMessage( @@ -80,15 +75,23 @@ namespace Renci.SshNet.Tests.Classes.Channels _remoteChannelNumber))); w.WaitOne(); }); - _sessionMock.InSequence(_sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(_sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(_sequence) .Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) .Returns(true); - _sessionMock.InSequence(_sequence) - .Setup(s => s.WaitOnHandle(It.IsNotNull())) - .Callback(w => w.WaitOne()); + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(_sequence) + .Setup(p => p.TryWait(It.IsNotNull(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) + .Returns(WaitResult.Success); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => { _channelClosedRegister.Add(args); @@ -97,13 +100,13 @@ namespace Renci.SshNet.Tests.Classes.Channels _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise(p => p.ChannelEofReceived += null, + SessionMock.Raise(p => p.ChannelEofReceived += null, new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); - _sessionMock.Raise(p => p.ChannelCloseReceived += null, + SessionMock.Raise(p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -133,4 +136,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.IsFalse(_channel.IsOpen); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs index 4f5590f4..aac5c837 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs @@ -10,9 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -22,83 +21,82 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(_sequence) - .Setup( - p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) - .Returns(false); - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(_sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(_sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(_sequence) + .Setup( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) + .Returns(false); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelEofReceived += null, new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -128,4 +126,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.IsFalse(_channel.IsOpen); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs index 8f007fb3..dd17c5ab 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs @@ -11,98 +11,100 @@ using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; - private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _localWindowSize = (uint) random.Next(0, int.MaxValue); _localPacketSize = (uint) random.Next(0, int.MaxValue); _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + var sequence = new MockSequence(); - _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.InSequence(_sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(_sequence) - .Setup( - p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(_sequence) - .Setup(s => s.WaitOnHandle(It.IsNotNull())) - .Callback(w => w.WaitOne()); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) + .Setup( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) + .Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsNotNull(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) + .Returns(WaitResult.Success); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelEofReceived += null, new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -132,4 +134,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.IsFalse(_channel.IsOpen); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs index 049d90f1..251adf5d 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs @@ -10,9 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -22,80 +21,79 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(_sequence) - .Setup( - p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) - .Returns(false); - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(_sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(_sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(_sequence) + .Setup( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) + .Returns(false); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -125,4 +123,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.IsFalse(_channel.IsOpen); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs index dcb0a8fb..37dff92f 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs @@ -11,52 +11,46 @@ using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; - private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _localWindowSize = (uint) random.Next(0, int.MaxValue); _localPacketSize = (uint) random.Next(0, int.MaxValue); _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + var sequence = new MockSequence(); - _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) .Setup( p => p.SendMessage( @@ -65,12 +59,12 @@ namespace Renci.SshNet.Tests.Classes.Channels m.LocalChannelNumber == _localChannelNumber && m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(sequence) .Setup(p => p.WaitOnHandle(It.IsNotNull())) .Callback( w => { - _sessionMock.Raise( + SessionMock.Raise( s => s.ChannelOpenConfirmationReceived += null, new MessageEventArgs( new ChannelOpenConfirmationMessage( @@ -80,26 +74,34 @@ namespace Renci.SshNet.Tests.Classes.Channels _remoteChannelNumber))); w.WaitOne(); }); - _sessionMock.InSequence(_sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) .Setup( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) .Returns(true); - _sessionMock.InSequence(_sequence) - .Setup(s => s.WaitOnHandle(It.IsNotNull())) - .Callback(w => w.WaitOne()); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsNotNull(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) + .Returns(WaitResult.Success); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs index 3173232f..83b40b32 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs @@ -10,9 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -22,80 +21,78 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(_sequence) - .Setup( - p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) - .Returns(false); + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(_sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(_sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(_sequence) + .Setup( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) + .Returns(false); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelEofReceived += null, new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -124,4 +121,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.IsFalse(_channel.IsOpen); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs index f0b7bd01..5ab59626 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs @@ -10,52 +10,46 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; - private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _localWindowSize = (uint) random.Next(0, int.MaxValue); _localPacketSize = (uint) random.Next(0, int.MaxValue); _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + var sequence = new MockSequence(); - _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) .Setup( p => p.SendMessage( @@ -64,12 +58,12 @@ namespace Renci.SshNet.Tests.Classes.Channels m.LocalChannelNumber == _localChannelNumber && m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(sequence) .Setup(p => p.WaitOnHandle(It.IsNotNull())) .Callback( w => { - _sessionMock.Raise( + SessionMock.Raise( s => s.ChannelOpenConfirmationReceived += null, new MessageEventArgs( new ChannelOpenConfirmationMessage( @@ -79,33 +73,41 @@ namespace Renci.SshNet.Tests.Classes.Channels _remoteChannelNumber))); w.WaitOne(); }); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(_sequence) + SessionMock.Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) .Setup( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) .Returns(true); - _sessionMock.InSequence(_sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - w.WaitOne(); - }); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsNotNull(), _channelCloseTimeout)) + .Callback( + (waitHandle, channelCloseTimeout) => + { + SessionMock.Raise( + s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelEofReceived += null, new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs index fdd0e469..47c84903 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs @@ -10,10 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived : ChannelSessionTestBase { - private Mock _sessionMock; - private Mock _connectionInfoMock; private ChannelSession _channel; private uint _localChannelNumber; private uint _localWindowSize; @@ -21,89 +19,94 @@ namespace Renci.SshNet.Tests.Classes.Channels private uint _remoteWindowSize; private uint _remotePacketSize; private uint _remoteChannelNumber; + private TimeSpan _channelCloseTimeout; private SemaphoreLight _sessionSemaphore; private IList _channelClosedRegister; private List _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(2000, 3000); - _localPacketSize = (uint)random.Next(1000, 2000); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(100, 200); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(2000, 3000); + _localPacketSize = (uint) random.Next(1000, 2000); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(100, 200); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _sessionSemaphore = new SemaphoreLight(1); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup( - p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup( - p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - w.WaitOne(); - }); - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) + .Setup( + p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) + .Setup( + p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsNotNull(), _channelCloseTimeout)) + .Callback( + (waitHandle, channelCloseTimeout) => + { + SessionMock.Raise( + s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -111,13 +114,13 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void ChannelEofMessageShouldBeSentOnce() { - _sessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); + SessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } [TestMethod] public void ChannelCloseMessageShouldBeSentOnce() { - _sessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); + SessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs index 084d5b1d..ce733bbc 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs @@ -10,10 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure + public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure : ChannelSessionTestBase { - private Mock _sessionMock; - private Mock _connectionInfoMock; private ChannelSession _channel; private uint _localChannelNumber; private uint _localWindowSize; @@ -21,89 +19,93 @@ namespace Renci.SshNet.Tests.Classes.Channels private uint _remoteWindowSize; private uint _remotePacketSize; private uint _remoteChannelNumber; + private TimeSpan _channelCloseTimeout; private SemaphoreLight _sessionSemaphore; private IList _channelClosedRegister; private List _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(2000, 3000); - _localPacketSize = (uint)random.Next(1000, 2000); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(100, 200); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(2000, 3000); + _localPacketSize = (uint) random.Next(1000, 2000); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(100, 200); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _sessionSemaphore = new SemaphoreLight(1); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup( - p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) - .Returns(false); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup( - p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - w.WaitOne(); - }); - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) + .Setup( + p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Returns(false); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence) + .Setup( + p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsNotNull(), _channelCloseTimeout)) + .Callback( + (waitHandle, channelCloseTimeout) => + { + SessionMock.Raise(s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -111,13 +113,13 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void ChannelEofMessageShouldBeSentOnce() { - _sessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); + SessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } [TestMethod] public void ChannelCloseMessageShouldBeSentOnce() { - _sessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); + SessionMock.Verify(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs index b0407c3f..d44f4e0a 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs @@ -10,9 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived + public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -22,79 +21,78 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.Setup(p => p.IsConnected).Returns(false); - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(_sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(_sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.Setup(p => p.IsConnected).Returns(false); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelEofReceived += null, new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -124,4 +122,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.IsFalse(_channel.IsOpen); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs index 7a16c21d..fedd4cd6 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs @@ -10,9 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived + public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -22,76 +21,75 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.Setup(p => p.IsConnected).Returns(false); - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(_sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(_sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.Setup(p => p.IsConnected).Returns(false); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -121,4 +119,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.IsFalse(_channel.IsOpen); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs index ad14e13a..ce8fa16c 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs @@ -10,9 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived + public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -22,72 +21,70 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.Setup(p => p.IsConnected).Returns(false); + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(_sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(_sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + SessionMock.Setup(p => p.IsConnected).Returns(false); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -116,4 +113,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.IsFalse(_channel.IsOpen); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs index 130797cd..584c4e94 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs @@ -11,52 +11,47 @@ using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen + public class ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen : ChannelSessionTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private Mock _connectionInfoMock; private MockSequence _sequence; private SemaphoreLight _sessionSemaphore; private int _initialSessionSemaphoreCount; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _localWindowSize = (uint) random.Next(0, int.MaxValue); _localPacketSize = (uint) random.Next(0, int.MaxValue); _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(_sequence) + + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(_sequence) .Setup( p => p.SendMessage( @@ -65,12 +60,12 @@ namespace Renci.SshNet.Tests.Classes.Channels m.LocalChannelNumber == _localChannelNumber && m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(_sequence) .Setup(p => p.WaitOnHandle(It.IsNotNull())) .Callback( w => { - _sessionMock.Raise( + SessionMock.Raise( s => s.ChannelOpenConfirmationReceived += null, new MessageEventArgs( new ChannelOpenConfirmationMessage( @@ -80,24 +75,32 @@ namespace Renci.SshNet.Tests.Classes.Channels _remoteChannelNumber))); w.WaitOne(); }); - _sessionMock.InSequence(_sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(_sequence) + SessionMock.InSequence(_sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(_sequence) .Setup( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) .Returns(true); - _sessionMock.InSequence(_sequence) - .Setup(s => s.WaitOnHandle(It.IsNotNull())) - .Callback(w => w.WaitOne()); + SessionMock.InSequence(_sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(_sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(_sequence) + .Setup(p => p.TryWait(It.IsNotNull(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) + .Returns(WaitResult.Success); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.Open(); } - private void Act() + protected override void Act() { - _sessionMock.Raise( + SessionMock.Raise( p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs index 54733501..fbb27e38 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs @@ -10,10 +10,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation + public class ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation : ChannelSessionTestBase { - private Mock _sessionMock; - private Mock _connectionInfoMock; private ChannelSession _channel; private uint _localChannelNumber; private uint _localWindowSize; @@ -25,51 +23,51 @@ namespace Renci.SshNet.Tests.Classes.Channels private Exception _waitOnConfirmationException; private SystemException _actualException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(2000, 3000); - _localPacketSize = (uint)random.Next(1000, 2000); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(2000, 3000); + _localPacketSize = (uint) random.Next(1000, 2000); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _waitOnConfirmationException = new SystemException(); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(2); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Throws(_waitOnConfirmationException); - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(2); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Throws(_waitOnConfirmationException); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); } - private void Act() + protected override void Act() { try { @@ -84,7 +82,8 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void OpenShouldHaveRethrownExceptionThrownByWaitOnHandle() { - + Assert.IsNotNull(_actualException); + Assert.AreSame(_waitOnConfirmationException, _actualException); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs index 870d8caa..ab4ba4f6 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs @@ -11,10 +11,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable + public class ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable : ChannelSessionTestBase { - private Mock _sessionMock; - private Mock _connectionInfoMock; private ChannelSession _channel; private uint _localChannelNumber; private uint _localWindowSize; @@ -28,16 +26,10 @@ namespace Renci.SshNet.Tests.Classes.Channels private string _failureLanguage; private SshException _actualException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _localWindowSize = (uint) random.Next(2000, 3000); _localPacketSize = (uint) random.Next(1000, 2000); @@ -50,15 +42,16 @@ namespace Renci.SshNet.Tests.Classes.Channels _failureReasonCode = (uint)random.Next(0, int.MaxValue); _failureDescription = random.Next().ToString(CultureInfo.InvariantCulture); _failureLanguage = random.Next().ToString(CultureInfo.InvariantCulture); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(sequence) + + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) .Setup( p => p.SendMessage( @@ -67,12 +60,12 @@ namespace Renci.SshNet.Tests.Classes.Channels m.LocalChannelNumber == _localChannelNumber && m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(sequence) + SessionMock.InSequence(sequence) .Setup(p => p.WaitOnHandle(It.IsNotNull())) .Callback( w => { - _sessionMock.Raise( + SessionMock.Raise( s => s.ChannelOpenFailureReceived += null, new MessageEventArgs( new ChannelOpenFailureMessage( @@ -83,15 +76,20 @@ namespace Renci.SshNet.Tests.Classes.Channels ))); w.WaitOne(); }); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(1); + } - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); } - private void Act() + protected override void Act() { try { diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs index 4b1edc1d..e6caeb22 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs @@ -11,10 +11,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable + public class ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable : ChannelSessionTestBase { - private Mock _sessionMock; - private Mock _connectionInfoMock; private ChannelSession _channel; private uint _localChannelNumber; private uint _localWindowSize; @@ -30,97 +28,97 @@ namespace Renci.SshNet.Tests.Classes.Channels private string _failureDescription; private string _failureLanguage; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(2000, 3000); - _localPacketSize = (uint)random.Next(1000, 2000); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(2000, 3000); + _localPacketSize = (uint) random.Next(1000, 2000); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _initialSessionSemaphoreCount = random.Next(10, 20); _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); - _failureReasonCode = (uint)random.Next(0, int.MaxValue); + _failureReasonCode = (uint) random.Next(0, int.MaxValue); _failureDescription = random.Next().ToString(CultureInfo.InvariantCulture); _failureLanguage = random.Next().ToString(CultureInfo.InvariantCulture); + } - _sessionMock = new Mock(MockBehavior.Strict); - _connectionInfoMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(2); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenFailureReceived += null, - new MessageEventArgs( - new ChannelOpenFailureMessage( - _localChannelNumber, - _failureDescription, - _failureReasonCode, - _failureLanguage - ))); - w.WaitOne(); - }); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(2); - _sessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); - _sessionMock.InSequence(sequence) - .Setup( - p => - p.SendMessage( - It.Is( - m => - m.LocalChannelNumber == _localChannelNumber && - m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && - m.Info is SessionChannelOpenInfo))); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _channel = new ChannelSession(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(2); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenFailureReceived += null, + new MessageEventArgs( + new ChannelOpenFailureMessage( + _localChannelNumber, + _failureDescription, + _failureReasonCode, + _failureLanguage + ))); + w.WaitOne(); + }); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.RetryAttempts).Returns(2); + SessionMock.Setup(p => p.SessionSemaphore).Returns(_sessionSemaphore); + SessionMock.InSequence(sequence) + .Setup( + p => + p.SendMessage( + It.Is( + m => + m.LocalChannelNumber == _localChannelNumber && + m.InitialWindowSize == _localWindowSize && m.MaximumPacketSize == _localPacketSize && + m.Info is SessionChannelOpenInfo))); + SessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + SessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + w.WaitOne(); + }); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelSession(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); } - private void Act() + protected override void Act() { _channel.Open(); } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTestBase.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTestBase.cs new file mode 100644 index 00000000..f92810cc --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTestBase.cs @@ -0,0 +1,37 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; + +namespace Renci.SshNet.Tests.Classes.Channels +{ + public abstract class ChannelTestBase + { + internal Mock SessionMock { get; private set; } + internal Mock ConnectionInfoMock { get; private set; } + + [TestInitialize] + public void Initialize() + { + Arrange(); + Act(); + } + + protected abstract void SetupData(); + + protected void CreateMocks() + { + SessionMock = new Mock(MockBehavior.Strict); + ConnectionInfoMock = new Mock(MockBehavior.Strict); + } + + protected abstract void SetupMocks(); + + protected virtual void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + } + + protected abstract void Act(); + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs index 67903d6e..8847ff7a 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs @@ -9,9 +9,8 @@ using Renci.SshNet.Messages; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen + public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -19,32 +18,32 @@ namespace Renci.SshNet.Tests.Classes.Channels private List _channelClosedRegister; private IList _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + SessionMock.Setup(p => p.IsConnected).Returns(true); + } - _sessionMock.Setup(p => p.IsConnected).Returns(true); + protected override void Arrange() + { + base.Arrange(); - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -58,7 +57,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void SendMessageOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.SendMessage(It.IsAny()), Times.Never); + SessionMock.Verify(p => p.SendMessage(It.IsAny()), Times.Never); } [TestMethod] @@ -73,4 +72,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs index d002e20a..679e1b8a 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs @@ -10,84 +10,91 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived + public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived : ChannelTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private ChannelStub _channel; private Stopwatch _closeTimer; - private ManualResetEvent _channelClosedWaitHandle; + private ManualResetEvent _channelClosedEventHandlerCompleted; private List _channelClosedRegister; private IList _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _closeTimer = new Stopwatch(); _channelClosedRegister = new List(); - _channelClosedWaitHandle = new ManualResetEvent(false); + _channelClosedEventHandlerCompleted = new ManualResetEvent(false); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(w => - { - new Thread(() => - { - Thread.Sleep(100); - // raise ChannelCloseReceived event to set waithandle for receiving - // SSH_MSG_CHANNEL_CLOSE message from server which is waited on after - // sending the SSH_MSG_CHANNEL_CLOSE message to the server - _sessionMock.Raise(s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - }).Start(); - _closeTimer.Start(); - try - { - w.WaitOne(); - } - finally - { - _closeTimer.Stop(); - } - }); - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => + { + new Thread(() => + { + Thread.Sleep(100); + // raise ChannelCloseReceived event to set waithandle for receiving + // SSH_MSG_CHANNEL_CLOSE message from server which is waited on after + // sending the SSH_MSG_CHANNEL_CLOSE message to the server + SessionMock.Raise(s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + }).Start(); + _closeTimer.Start(); + try + { + waitHandle.WaitOne(); + } + finally + { + _closeTimer.Stop(); + } + }) + .Returns(WaitResult.Success); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => - { - _channelClosedRegister.Add(args); - _channelClosedWaitHandle.Set(); - }; + { + _channelClosedRegister.Add(args); + Thread.Sleep(50); + _channelClosedEventHandlerCompleted.Set(); + }; _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.SetIsOpen(true); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -101,7 +108,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } @@ -109,15 +116,15 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelEofMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } [TestMethod] - public void WaitOnHandleOnSessionShouldBeInvokedOnce() + public void TryWaitOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.WaitOnHandle(It.IsAny()), Times.Once); + SessionMock.Verify(p => p.TryWait(It.IsAny(), _channelCloseTimeout), Times.Once); } [TestMethod] @@ -129,16 +136,20 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void ClosedEventShouldHaveFiredOnce() { - _channelClosedWaitHandle.WaitOne(100); - Assert.AreEqual(1, _channelClosedRegister.Count); Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber); } + [TestMethod] + public void DisposeShouldBlockUntilClosedEventHandlerHasCompleted() + { + Assert.IsTrue(_channelClosedEventHandlerCompleted.WaitOne(0)); + } + [TestMethod] public void ExceptionShouldNeverHaveFired() { Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs index 37392208..e59e95df 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs @@ -10,9 +10,9 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked + [Ignore] + public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked : ChannelTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -21,74 +21,86 @@ namespace Renci.SshNet.Tests.Classes.Channels private uint _remotePacketSize; private ChannelStub _channel; private Stopwatch _closeTimer; - private ManualResetEvent _channelClosedWaitHandle; + private ManualResetEvent _channelClosedEventHandlerCompleted; private List _channelClosedRegister; private IList _channelExceptionRegister; - [TestInitialize] - public void Initialize() + [TestCleanup] + public void TearDown() { - Arrange(); - Act(); + if (_channelClosedEventHandlerCompleted != null) + { + _channelClosedEventHandlerCompleted.Dispose(); + _channelClosedEventHandlerCompleted = null; + } } - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _closeTimer = new Stopwatch(); - _channelClosedWaitHandle = new ManualResetEvent(false); + _channelClosedEventHandlerCompleted = new ManualResetEvent(false); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.SendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(w => - { - new Thread(() => - { - Thread.Sleep(100); - // raise ChannelCloseReceived event to set waithandle for receiving - // SSH_MSG_CHANNEL_CLOSE message from server which is waited on after - // sending the SSH_MSG_CHANNEL_CLOSE message to the server - _sessionMock.Raise(s => s.ChannelCloseReceived += null, - new MessageEventArgs( - new ChannelCloseMessage(_localChannelNumber))); - }).Start(); - _closeTimer.Start(); - try - { - w.WaitOne(); - } - finally - { - _closeTimer.Stop(); - } - }); - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + SessionMock.InSequence(sequence).Setup(p => p.SendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny())) + .Callback(w => + { + new Thread(() => + { + Thread.Sleep(100); + // raise ChannelCloseReceived event to set waithandle for receiving + // SSH_MSG_CHANNEL_CLOSE message from server which is waited on after + // sending the SSH_MSG_CHANNEL_CLOSE message to the server + SessionMock.Raise(s => s.ChannelCloseReceived += null, + new MessageEventArgs( + new ChannelCloseMessage(_localChannelNumber))); + }).Start(); + _closeTimer.Start(); + try + { + w.WaitOne(); + } + finally + { + _closeTimer.Stop(); + } + }); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => - { - _channelClosedRegister.Add(args); - _channelClosedWaitHandle.Set(); - }; + { + _channelClosedRegister.Add(args); + Thread.Sleep(50); + _channelClosedEventHandlerCompleted.Set(); + }; _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.SetIsOpen(true); - _channel.SendEof(); + //_channel.SendEof(); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -102,7 +114,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } @@ -110,7 +122,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void SendMessageOnSessionShouldBeInvokedOnceForChannelEofMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.SendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } @@ -118,7 +130,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void WaitOnHandleOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.WaitOnHandle(It.IsAny()), Times.Once); + SessionMock.Verify(p => p.WaitOnHandle(It.IsAny()), Times.Once); } [TestMethod] @@ -130,16 +142,20 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void ClosedEventShouldHaveFiredOnce() { - _channelClosedWaitHandle.WaitOne(100); - Assert.AreEqual(1, _channelClosedRegister.Count); Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber); } + [TestMethod] + public void DisposeShouldBlockUntilClosedEventHandlerHasCompleted() + { + Assert.IsTrue(_channelClosedEventHandlerCompleted.WaitOne(0)); + } + [TestMethod] public void ExceptionShouldNeverHaveFired() { Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs index 79e1a596..0bb9e862 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs @@ -9,23 +9,24 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived + public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived : ChannelTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private ChannelStub _channel; private List _channelClosedRegister; private List _channelEndOfDataRegister; private IList _channelExceptionRegister; private ManualResetEvent _channelClosedReceived; + private ManualResetEvent _channelClosedEventHandlerCompleted; private Thread _raiseChannelCloseReceivedThread; - private void SetupData() + protected override void SetupData() { var random = new Random(); @@ -35,59 +36,53 @@ namespace Renci.SshNet.Tests.Classes.Channels _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelClosedRegister = new List(); _channelEndOfDataRegister = new List(); _channelExceptionRegister = new List(); _channelClosedReceived = new ManualResetEvent(false); + _channelClosedEventHandlerCompleted = new ManualResetEvent(false); _raiseChannelCloseReceivedThread = null; } - private void CreateMocks() - { - _sessionMock = new Mock(MockBehavior.Strict); - } - - private void SetupMocks() + protected override void SetupMocks() { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(w => - { - _raiseChannelCloseReceivedThread = new Thread(() => - { - Thread.Sleep(100); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => + { + _raiseChannelCloseReceivedThread = new Thread(() => + { + Thread.Sleep(100); - // signal that the ChannelCloseMessage was received; we use this to verify whether we've actually - // waited on the EventWaitHandle to be set; this needs to be set before we raise the ChannelCloseReceived - // to make sure the waithandle is signaled when the Dispose method completes (or else the assert that - // checks whether the handle has been signaled, will sometimes fail) - _channelClosedReceived.Set(); + // signal that the ChannelCloseMessage was received; we use this to verify whether we've actually + // waited on the EventWaitHandle to be set; this needs to be set before we raise the ChannelCloseReceived + // to make sure the waithandle is signaled when the Dispose method completes (or else the assert that + // checks whether the handle has been signaled, will sometimes fail) + _channelClosedReceived.Set(); - // raise ChannelCloseReceived event to set waithandle for receiving SSH_MSG_CHANNEL_CLOSE message - // from server which is waited on after sending the SSH_MSG_CHANNEL_CLOSE message to the server - // - // this will cause a new invocation of Close() that will block until the Close() that was invoked - // as part of Dispose() has released the lock; as such, this thread cannot be joined until that - // lock is released - // - // we're mocking the wait on the ChannelCloseMessage, but we still want - // to get the channel in the state that it would have after actually receiving - // the ChannelCloseMessage - _sessionMock.Raise(s => s.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - }); - _raiseChannelCloseReceivedThread.Start(); - w.WaitOne(); - }); - } - - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); + // raise ChannelCloseReceived event to set waithandle for receiving SSH_MSG_CHANNEL_CLOSE message + // from server which is waited on after sending the SSH_MSG_CHANNEL_CLOSE message to the server + // + // this will cause a new invocation of Close() that will block until the Close() that was invoked + // as part of Dispose() has released the lock; as such, this thread cannot be joined until that + // lock is released + // + // we're mocking the wait on the ChannelCloseMessage, but we still want + // to get the channel in the state that it would have after actually receiving + // the ChannelCloseMessage + SessionMock.Raise(s => s.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + }); + _raiseChannelCloseReceivedThread.Start(); + waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); } [TestCleanup] @@ -106,27 +101,36 @@ namespace Renci.SshNet.Tests.Classes.Channels _raiseChannelCloseReceivedThread.Abort(); } } + + if (_channelClosedEventHandlerCompleted != null) + { + _channelClosedEventHandlerCompleted.Dispose(); + _channelClosedEventHandlerCompleted = null; + } } - private void Arrange() + protected override void Arrange() { - SetupData(); - CreateMocks(); - SetupMocks(); + base.Arrange(); - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); - _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel.Closed += (sender, args) => + { + _channelClosedRegister.Add(args); + Thread.Sleep(50); + _channelClosedEventHandlerCompleted.Set(); + }; _channel.EndOfData += (sender, args) => _channelEndOfDataRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.SetIsOpen(true); - _sessionMock.Raise( + SessionMock.Raise( s => s.ChannelEofReceived += null, new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -140,7 +144,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } @@ -148,15 +152,15 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void TrySendMessageOnSessionShouldNeverBeInvokedForChannelEofMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Never); } [TestMethod] - public void WaitOnHandleOnSessionShouldBeInvokedOnce() + public void TryWaitOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.WaitOnHandle(It.IsAny()), Times.Once); + SessionMock.Verify(p => p.TryWait(It.IsAny(), _channelCloseTimeout), Times.Once); } [TestMethod] @@ -173,7 +177,7 @@ namespace Renci.SshNet.Tests.Classes.Channels } [TestMethod] - public void EndOfDataEventShouldHaveFiredOnce() + public void EndOfDataEventShouldNotHaveFired() { Assert.AreEqual(1, _channelEndOfDataRegister.Count); Assert.AreEqual(_localChannelNumber, _channelEndOfDataRegister[0].ChannelNumber); diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs new file mode 100644 index 00000000..7519c5db --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Connection; + +namespace Renci.SshNet.Tests.Classes.Channels +{ + [TestClass] + public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage : ChannelTestBase + { + private uint _localChannelNumber; + private uint _localWindowSize; + private uint _localPacketSize; + private uint _remoteChannelNumber; + private uint _remoteWindowSize; + private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; + private ChannelStub _channel; + private List _channelClosedRegister; + private List _channelEndOfDataRegister; + private IList _channelExceptionRegister; + + protected override void SetupData() + { + var random = new Random(); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); + _channelClosedRegister = new List(); + _channelEndOfDataRegister = new List(); + _channelExceptionRegister = new List(); + } + + protected override void SetupMocks() + { + var sequence = new MockSequence(); + + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence).Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)).Returns(WaitResult.Disconnected); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel.Closed += (sender, args) => { _channelClosedRegister.Add(args); }; + _channel.EndOfData += (sender, args) => _channelEndOfDataRegister.Add(args); + _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); + _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); + _channel.SetIsOpen(true); + + SessionMock.Raise( + s => s.ChannelEofReceived += null, + new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); + } + + protected override void Act() + { + _channel.Dispose(); + } + + [TestMethod] + public void IsOpenShouldReturnFalse() + { + Assert.IsFalse(_channel.IsOpen); + } + + [TestMethod] + public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage() + { + SessionMock.Verify( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), + Times.Once); + } + + [TestMethod] + public void TrySendMessageOnSessionShouldNeverBeInvokedForChannelEofMessage() + { + SessionMock.Verify( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), + Times.Never); + } + + [TestMethod] + public void TryWaitOnSessionShouldBeInvokedOnce() + { + SessionMock.Verify(p => p.TryWait(It.IsAny(), _channelCloseTimeout), Times.Once); + } + + [TestMethod] + public void ClosedEventShouldNotHaveFired() + { + Assert.AreEqual(0, _channelClosedRegister.Count); + } + + [TestMethod] + public void EndOfDataEventShouldNotHaveFired() + { + Assert.AreEqual(1, _channelEndOfDataRegister.Count); + Assert.AreEqual(_localChannelNumber, _channelEndOfDataRegister[0].ChannelNumber); + } + + [TestMethod] + public void ExceptionShouldNeverHaveFired() + { + Assert.AreEqual(0, _channelExceptionRegister.Count); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs new file mode 100644 index 00000000..a5131338 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Connection; + +namespace Renci.SshNet.Tests.Classes.Channels +{ + [TestClass] + public class ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage : ChannelTestBase + { + private uint _localChannelNumber; + private uint _localWindowSize; + private uint _localPacketSize; + private uint _remoteChannelNumber; + private uint _remoteWindowSize; + private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; + private ChannelStub _channel; + private List _channelClosedRegister; + private List _channelEndOfDataRegister; + private IList _channelExceptionRegister; + + protected override void SetupData() + { + var random = new Random(); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next()); + _channelClosedRegister = new List(); + _channelEndOfDataRegister = new List(); + _channelExceptionRegister = new List(); + } + + protected override void SetupMocks() + { + var sequence = new MockSequence(); + + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence).Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)).Returns(WaitResult.TimedOut); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel.Closed += (sender, args) => { _channelClosedRegister.Add(args); }; + _channel.EndOfData += (sender, args) => _channelEndOfDataRegister.Add(args); + _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); + _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); + _channel.SetIsOpen(true); + + SessionMock.Raise( + s => s.ChannelEofReceived += null, + new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); + } + + protected override void Act() + { + _channel.Dispose(); + } + + [TestMethod] + public void IsOpenShouldReturnFalse() + { + Assert.IsFalse(_channel.IsOpen); + } + + [TestMethod] + public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage() + { + SessionMock.Verify( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), + Times.Once); + } + + [TestMethod] + public void TrySendMessageOnSessionShouldNeverBeInvokedForChannelEofMessage() + { + SessionMock.Verify( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), + Times.Never); + } + + [TestMethod] + public void TryWaitOnSessionShouldBeInvokedOnce() + { + SessionMock.Verify(p => p.TryWait(It.IsAny(), _channelCloseTimeout), Times.Once); + } + + [TestMethod] + public void ClosedEventShouldNotHaveFired() + { + Assert.AreEqual(0, _channelClosedRegister.Count); + } + + [TestMethod] + public void EndOfDataEventShouldNotHaveFired() + { + Assert.AreEqual(1, _channelEndOfDataRegister.Count); + Assert.AreEqual(_localChannelNumber, _channelEndOfDataRegister[0].ChannelNumber); + } + + [TestMethod] + public void ExceptionShouldNeverHaveFired() + { + Assert.AreEqual(0, _channelExceptionRegister.Count); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs index 3ef388d9..d7709464 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs @@ -9,9 +9,8 @@ using Renci.SshNet.Messages; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen + public class ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -19,32 +18,32 @@ namespace Renci.SshNet.Tests.Classes.Channels private List _channelClosedRegister; private IList _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _localWindowSize = (uint) random.Next(0, int.MaxValue); _localPacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + SessionMock.Setup(p => p.IsConnected).Returns(false); + } - _sessionMock.Setup(p => p.IsConnected).Returns(false); + protected override void Arrange() + { + base.Arrange(); - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -58,7 +57,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void SendMessageOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.SendMessage(It.IsAny()), Times.Never); + SessionMock.Verify(p => p.SendMessage(It.IsAny()), Times.Never); } [TestMethod] @@ -73,4 +72,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs index 76fbaa65..d837c734 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen + public class ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -18,33 +17,33 @@ namespace Renci.SshNet.Tests.Classes.Channels private List _channelClosedRegister; private IList _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + SessionMock.Setup(p => p.IsConnected).Returns(false); + } - _sessionMock.Setup(p => p.IsConnected).Returns(false); + protected override void Arrange() + { + base.Arrange(); - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.SetIsOpen(true); } - private void Act() + protected override void Act() { _channel.Dispose(); } @@ -58,7 +57,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void SendMessageOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.SendMessage(It.IsAny()), Times.Never); + SessionMock.Verify(p => p.SendMessage(It.IsAny()), Times.Never); } [TestMethod] @@ -73,4 +72,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs index 1933afb7..102a5769 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception + public class ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -18,32 +17,33 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelExceptionRegister; private Exception _onCloseException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); + _localWindowSize = (uint) random.Next(1000, int.MaxValue); _localPacketSize = _localWindowSize - 1; _localChannelNumber = (uint) random.Next(0, int.MaxValue); _onCloseException = new SystemException(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnCloseException = _onCloseException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ChannelCloseReceived += null, + SessionMock.Raise(s => s.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler.cs new file mode 100644 index 00000000..e8aa9752 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Connection; + +namespace Renci.SshNet.Tests.Classes.Channels +{ + [TestClass] + public class ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler : ChannelTestBase + { + private uint _localChannelNumber; + private uint _localWindowSize; + private uint _localPacketSize; + private uint _remoteChannelNumber; + private uint _remoteWindowSize; + private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; + private ChannelStub _channel; + private List _channelClosedRegister; + private List _channelEndOfDataRegister; + private IList _channelExceptionRegister; + private ManualResetEvent _channelClosedEventHandlerCompleted; + private bool _channelClosedWaitHandleSignaled; + + protected override void SetupData() + { + var random = new Random(); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); + _channelClosedWaitHandleSignaled = false; + _channelClosedRegister = new List(); + _channelEndOfDataRegister = new List(); + _channelExceptionRegister = new List(); + _channelClosedEventHandlerCompleted = new ManualResetEvent(false); + } + + protected override void SetupMocks() + { + var sequence = new MockSequence(); + + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => _channelClosedWaitHandleSignaled = waitHandle.WaitOne(0)) + .Returns(WaitResult.Success); + } + + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel.Closed += (sender, args) => + { + _channelClosedRegister.Add(args); + _channel.Dispose(); + _channelClosedEventHandlerCompleted.Set(); + }; + _channel.EndOfData += (sender, args) => _channelEndOfDataRegister.Add(args); + _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); + _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); + _channel.SetIsOpen(true); + } + + protected override void Act() + { + SessionMock.Raise( + s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + } + + [TestMethod] + public void IsOpenShouldReturnFalse() + { + Assert.IsFalse(_channel.IsOpen); + } + + [TestMethod] + public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage() + { + SessionMock.Verify( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), + Times.Once); + } + + [TestMethod] + public void TrySendMessageOnSessionShouldNeverBeInvokedForChannelEofMessage() + { + SessionMock.Verify( + p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), + Times.Never); + } + + [TestMethod] + public void TryWaitOnSessionShouldBeInvokedOnce() + { + SessionMock.Verify(p => p.TryWait(It.IsAny(), _channelCloseTimeout), Times.Once); + } + + [TestMethod] + public void ChannelCloseWaitHandleShouldHaveBeenSignaledImmediately() + { + Assert.IsTrue(_channelClosedWaitHandleSignaled); + } + + [TestMethod] + public void ClosedEventShouldHaveFiredOnce() + { + Assert.AreEqual(1, _channelClosedRegister.Count); + Assert.AreEqual(_localChannelNumber, _channelClosedRegister[0].ChannelNumber); + } + + [TestMethod] + public void EndOfDataEventShouldNeverHaveFired() + { + Assert.AreEqual(0, _channelEndOfDataRegister.Count); + } + + [TestMethod] + public void ExceptionShouldNeverHaveFired() + { + Assert.AreEqual(0, _channelExceptionRegister.Count); + } + + [TestMethod] + public void ChannelCloseReceivedShouldBlockUntilClosedEventHandlerHasCompleted() + { + Assert.IsTrue(_channelClosedEventHandlerCompleted.WaitOne(0)); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs index 6d6bbd6a..b1d633b5 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs @@ -10,58 +10,69 @@ using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived + public class ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived : ChannelTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private IList _channelClosedRegister; private IList _channelExceptionRegister; + private ManualResetEvent _channelClosedEventHandlerCompleted; private ChannelStub _channel; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + _channelClosedEventHandlerCompleted = new ManualResetEvent(false); + } - _sessionMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); - _sessionMock.InSequence(sequence) - .Setup(s => s.WaitOnHandle(It.IsNotNull())) - .Callback(w => w.WaitOne()); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) + .Returns(WaitResult.Success); + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); - _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel.Closed += (sender, args) => + { + _channelClosedRegister.Add(args); + Thread.Sleep(100); + _channelClosedEventHandlerCompleted.Set(); + }; _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.SetIsOpen(true); } - private void Act() + protected override void Act() { - _sessionMock.Raise(p => p.ChannelCloseReceived += null, + SessionMock.Raise(p => p.ChannelCloseReceived += null, new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } @@ -74,7 +85,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } @@ -82,15 +93,15 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void TrySendMessageOnSessionShouldNeverBeInvokedForChannelEofMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Never); } [TestMethod] - public void WaitOnHandleOnSessionShouldBeInvokedOnce() + public void TryWaitOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.WaitOnHandle(It.IsAny()), Times.Once); + SessionMock.Verify(p => p.TryWait(It.IsAny(), _channelCloseTimeout), Times.Once); } [TestMethod] @@ -105,5 +116,11 @@ namespace Renci.SshNet.Tests.Classes.Channels { Assert.AreEqual(0, _channelExceptionRegister.Count, _channelExceptionRegister.AsString()); } + + [TestMethod] + public void ChannelCloseReceivedShouldBlockUntilClosedEventHandlerHasCompleted() + { + Assert.IsTrue(_channelClosedEventHandlerCompleted.WaitOne(0)); + } } } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs index 589b5665..9f37a40a 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs @@ -10,64 +10,73 @@ using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived + public class ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived : ChannelTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; private uint _remoteChannelNumber; private uint _remoteWindowSize; private uint _remotePacketSize; + private TimeSpan _channelCloseTimeout; private IList _channelClosedRegister; private IList _channelExceptionRegister; + private ManualResetEvent _channelClosedEventHandlerCompleted; private ChannelStub _channel; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); + _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + _channelClosedEventHandlerCompleted = new ManualResetEvent(false); + } - _sessionMock = new Mock(MockBehavior.Strict); - + protected override void SetupMocks() + { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence).Setup( - p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(sequence) - .Setup(s => s.WaitOnHandle(It.IsNotNull())) - .Callback(w => w.WaitOne()); + SessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber))).Returns(true); + SessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(ConnectionInfoMock.Object); + ConnectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); + SessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) + .Returns(WaitResult.Success); + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); - _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel.Closed += (sender, args) => + { + _channelClosedRegister.Add(args); + Thread.Sleep(100); + _channelClosedEventHandlerCompleted.Set(); + }; _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.SetIsOpen(true); - _sessionMock.Raise(p => p.ChannelEofReceived += null, - new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); + SessionMock.Raise(p => p.ChannelEofReceived += null, + new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); } - private void Act() + protected override void Act() { - _sessionMock.Raise(p => p.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + SessionMock.Raise(p => p.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); } [TestMethod] @@ -79,7 +88,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void TrySendMessageOnSessionShouldBeInvokedOnceForChannelCloseMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } @@ -87,15 +96,15 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void SendMessageOnSessionShouldNeverBeInvokedForChannelEofMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.TrySendMessage(It.Is(c => c.LocalChannelNumber == _remoteChannelNumber)), Times.Never); } [TestMethod] - public void WaitOnHandleOnSessionShouldBeInvokedOnce() + public void TryWaitOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.WaitOnHandle(It.IsAny()), Times.Once); + SessionMock.Verify(p => p.TryWait(It.IsAny(), _channelCloseTimeout), Times.Once); } [TestMethod] @@ -110,5 +119,11 @@ namespace Renci.SshNet.Tests.Classes.Channels { Assert.AreEqual(0, _channelExceptionRegister.Count, _channelExceptionRegister.AsString()); } + + [TestMethod] + public void ChannelCloseReceivedShouldBlockUntilClosedEventHandlerHasCompleted() + { + Assert.IsTrue(_channelClosedEventHandlerCompleted.WaitOne(0)); + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs index 6e1b4479..3c2884f2 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelDataReceived_OnData_Exception + public class ChannelTest_OnSessionChannelDataReceived_OnData_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -18,33 +17,34 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelExceptionRegister; private Exception _onDataException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localWindowSize = (uint)random.Next(1000, int.MaxValue); + + _localWindowSize = (uint) random.Next(1000, int.MaxValue); _localPacketSize = _localWindowSize - 1; - _localChannelNumber = (uint)random.Next(0, int.MaxValue); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _onDataException = new SystemException(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnDataException = _onDataException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ChannelDataReceived += null, - new MessageEventArgs(new ChannelDataMessage(_localChannelNumber, new byte[0]))); + SessionMock.Raise(s => s.ChannelDataReceived += null, + new MessageEventArgs(new ChannelDataMessage(_localChannelNumber, new byte[0]))); } [TestMethod] @@ -61,4 +61,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_onDataException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs index ea2ff46e..ff4a38bb 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelEofReceived_Exception + public class ChannelTest_OnSessionChannelEofReceived_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -21,38 +20,39 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelExceptionRegister; private Exception _onEofException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localWindowSize = (uint)random.Next(0, 1000); - _localPacketSize = (uint)random.Next(1001, int.MaxValue); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localWindowSize = (uint) random.Next(0, 1000); + _localPacketSize = (uint) random.Next(1001, int.MaxValue); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _onEofException = new SystemException(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.SetIsOpen(true); _channel.OnEofException = _onEofException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ChannelEofReceived += null, - new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); + SessionMock.Raise(s => s.ChannelEofReceived += null, + new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); } [TestMethod] @@ -69,4 +69,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_onEofException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs index fccb0081..9f582933 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception + public class ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -18,33 +17,34 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelExceptionRegister; private Exception _onExtendedDataException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localWindowSize = (uint)random.Next(1000, int.MaxValue); + + _localWindowSize = (uint) random.Next(1000, int.MaxValue); _localPacketSize = _localWindowSize - 1; - _localChannelNumber = (uint)random.Next(0, int.MaxValue); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _onExtendedDataException = new SystemException(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnExtendedDataException = _onExtendedDataException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ChannelExtendedDataReceived += null, - new MessageEventArgs(new ChannelExtendedDataMessage(_localChannelNumber, 5, new byte[0]))); + SessionMock.Raise(s => s.ChannelExtendedDataReceived += null, + new MessageEventArgs(new ChannelExtendedDataMessage(_localChannelNumber, 5, new byte[0]))); } [TestMethod] @@ -61,4 +61,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_onExtendedDataException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs index 76a9c8ad..935048a2 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception + public class ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -18,33 +17,34 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelExceptionRegister; private Exception _onFailureException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localWindowSize = (uint)random.Next(0, 1000); - _localPacketSize = (uint)random.Next(1001, int.MaxValue); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); + + _localWindowSize = (uint) random.Next(0, 1000); + _localPacketSize = (uint) random.Next(1001, int.MaxValue); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _onFailureException = new SystemException(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnFailureException = _onFailureException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ChannelFailureReceived += null, - new MessageEventArgs(new ChannelFailureMessage(_localChannelNumber))); + SessionMock.Raise(s => s.ChannelFailureReceived += null, + new MessageEventArgs(new ChannelFailureMessage(_localChannelNumber))); } [TestMethod] @@ -61,4 +61,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_onFailureException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs index bcb59532..d5c82801 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception + public class ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -19,36 +18,37 @@ namespace Renci.SshNet.Tests.Classes.Channels private Exception _onRequestException; private SignalRequestInfo _requestInfo; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localWindowSize = (uint)random.Next(1000, int.MaxValue); + + _localWindowSize = (uint) random.Next(1000, int.MaxValue); _localPacketSize = _localWindowSize - 1; - _localChannelNumber = (uint)random.Next(0, int.MaxValue); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _onRequestException = new SystemException(); _channelExceptionRegister = new List(); _requestInfo = new SignalRequestInfo("ABC"); + } - _sessionMock = new Mock(MockBehavior.Strict); - _sessionMock.Setup(p => p.ConnectionInfo) - .Returns(new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "password"))); + protected override void SetupMocks() + { + SessionMock.Setup(p => p.ConnectionInfo) + .Returns(new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "password"))); + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnRequestException = _onRequestException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ChannelRequestReceived += null, - new MessageEventArgs(new ChannelRequestMessage(_localChannelNumber, _requestInfo))); + SessionMock.Raise(s => s.ChannelRequestReceived += null, + new MessageEventArgs(new ChannelRequestMessage(_localChannelNumber, _requestInfo))); } [TestMethod] @@ -65,4 +65,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_onRequestException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs index 4bc8e849..2caa91f1 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception + public class ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -18,33 +17,34 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelExceptionRegister; private Exception _onSuccessException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, 1000); - _localPacketSize = (uint)random.Next(1001, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, 1000); + _localPacketSize = (uint) random.Next(1001, int.MaxValue); _onSuccessException = new SystemException(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnSuccessException = _onSuccessException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ChannelSuccessReceived += null, - new MessageEventArgs(new ChannelSuccessMessage(_localChannelNumber))); + SessionMock.Raise(s => s.ChannelSuccessReceived += null, + new MessageEventArgs(new ChannelSuccessMessage(_localChannelNumber))); } [TestMethod] @@ -61,4 +61,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_onSuccessException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs index e4e0b863..ba223ad9 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception + public class ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -22,38 +21,39 @@ namespace Renci.SshNet.Tests.Classes.Channels private Exception _onWindowAdjustException; private uint _bytesToAdd; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(1000, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(1000, int.MaxValue); _localPacketSize = _localWindowSize - 1; - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(1000, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(1000, int.MaxValue); _remotePacketSize = _localWindowSize - 1; - _bytesToAdd = (uint)random.Next(0, int.MaxValue); + _bytesToAdd = (uint) random.Next(0, int.MaxValue); _onWindowAdjustException = new SystemException(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnWindowAdjustException = _onWindowAdjustException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ChannelWindowAdjustReceived += null, - new MessageEventArgs(new ChannelWindowAdjustMessage(_localChannelNumber, _bytesToAdd))); + SessionMock.Raise(s => s.ChannelWindowAdjustReceived += null, + new MessageEventArgs(new ChannelWindowAdjustMessage(_localChannelNumber, _bytesToAdd))); } [TestMethod] @@ -70,4 +70,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_onWindowAdjustException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs index e570a215..4796c4e6 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs @@ -7,9 +7,8 @@ using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionDisconnected_OnDisconnected_Exception + public class ChannelTest_OnSessionDisconnected_OnDisconnected_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -17,32 +16,33 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelExceptionRegister; private Exception _onDisconnectedException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localWindowSize = (uint)random.Next(1000, int.MaxValue); + + _localWindowSize = (uint) random.Next(1000, int.MaxValue); _localPacketSize = _localWindowSize - 1; - _localChannelNumber = (uint)random.Next(0, int.MaxValue); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _onDisconnectedException = new SystemException(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnDisconnectedException = _onDisconnectedException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.Disconnected += null, EventArgs.Empty); + SessionMock.Raise(s => s.Disconnected += null, EventArgs.Empty); } [TestMethod] @@ -59,4 +59,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_onDisconnectedException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs index c5c890b9..e228c36b 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs @@ -7,9 +7,8 @@ using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen + public class ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen : ChannelTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -20,39 +19,39 @@ namespace Renci.SshNet.Tests.Classes.Channels private List _channelClosedRegister; private IList _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + SessionMock.Setup(p => p.IsConnected).Returns(true); + } - _sessionMock.Setup(p => p.IsConnected).Returns(true); + protected override void Arrange() + { + base.Arrange(); - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.SetIsOpen(true); } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.Disconnected += null, EventArgs.Empty); + SessionMock.Raise(s => s.Disconnected += null, EventArgs.Empty); } [TestMethod] @@ -73,4 +72,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs index 21e8d91d..ddbae080 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs @@ -1,15 +1,13 @@ using System; using System.Collections.Generic; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception + public class ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -18,33 +16,34 @@ namespace Renci.SshNet.Tests.Classes.Channels private Exception _onErrorOccurredException; private Exception _errorOccurredException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localWindowSize = (uint)random.Next(1000, int.MaxValue); + + _localWindowSize = (uint) random.Next(1000, int.MaxValue); _localPacketSize = _localWindowSize - 1; - _localChannelNumber = (uint)random.Next(0, int.MaxValue); + _localChannelNumber = (uint) random.Next(0, int.MaxValue); _onErrorOccurredException = new SystemException(); _channelExceptionRegister = new List(); _errorOccurredException = new SystemException(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.OnErrorOccurredException = _onErrorOccurredException; } - private void Act() + protected override void Act() { - _sessionMock.Raise(s => s.ErrorOccured += null, new ExceptionEventArgs(_errorOccurredException)); + SessionMock.Raise(s => s.ErrorOccured += null, new ExceptionEventArgs(_errorOccurredException)); } [TestMethod] @@ -61,4 +60,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreSame(_errorOccurredException, _channel.OnErrorOccurredInvocations[0]); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs index da712f4b..83d4ac3f 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_SendEof_ChannelIsNotOpen + public class ChannelTest_SendEof_ChannelIsNotOpen : ChannelTestBase { - private Mock _sessionMock; private uint _localWindowSize; private uint _localPacketSize; private uint _localChannelNumber; @@ -19,31 +18,32 @@ namespace Renci.SshNet.Tests.Classes.Channels private IList _channelExceptionRegister; private InvalidOperationException _actualException; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _actualException = null; + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + } - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + protected override void Arrange() + { + base.Arrange(); + + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); } - private void Act() + protected override void Act() { try { @@ -73,7 +73,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void SendMessageOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.SendMessage(It.IsAny()), Times.Never); + SessionMock.Verify(p => p.SendMessage(It.IsAny()), Times.Never); } [TestMethod] @@ -88,4 +88,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs index 9a28db11..ff843491 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs @@ -8,9 +8,8 @@ using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes.Channels { [TestClass] - public class ChannelTest_SendEof_ChannelIsOpen + public class ChannelTest_SendEof_ChannelIsOpen : ChannelTestBase { - private Mock _sessionMock; private uint _localChannelNumber; private uint _localWindowSize; private uint _localPacketSize; @@ -21,37 +20,37 @@ namespace Renci.SshNet.Tests.Classes.Channels private List _channelClosedRegister; private IList _channelExceptionRegister; - [TestInitialize] - public void Initialize() - { - Arrange(); - Act(); - } - - private void Arrange() + protected override void SetupData() { var random = new Random(); - _localChannelNumber = (uint)random.Next(0, int.MaxValue); - _localWindowSize = (uint)random.Next(0, int.MaxValue); - _localPacketSize = (uint)random.Next(0, int.MaxValue); - _remoteChannelNumber = (uint)random.Next(0, int.MaxValue); - _remoteWindowSize = (uint)random.Next(0, int.MaxValue); - _remotePacketSize = (uint)random.Next(0, int.MaxValue); + + _localChannelNumber = (uint) random.Next(0, int.MaxValue); + _localWindowSize = (uint) random.Next(0, int.MaxValue); + _localPacketSize = (uint) random.Next(0, int.MaxValue); + _remoteChannelNumber = (uint) random.Next(0, int.MaxValue); + _remoteWindowSize = (uint) random.Next(0, int.MaxValue); + _remotePacketSize = (uint) random.Next(0, int.MaxValue); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); + } - _sessionMock = new Mock(MockBehavior.Strict); + protected override void SetupMocks() + { + SessionMock.Setup(p => p.SendMessage(It.Is(e => e.LocalChannelNumber == _remoteChannelNumber))); + } - _sessionMock.Setup(p => p.SendMessage(It.Is(e => e.LocalChannelNumber == _remoteChannelNumber))); + protected override void Arrange() + { + base.Arrange(); - _channel = new ChannelStub(_sessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); + _channel = new ChannelStub(SessionMock.Object, _localChannelNumber, _localWindowSize, _localPacketSize); _channel.Closed += (sender, args) => _channelClosedRegister.Add(args); _channel.Exception += (sender, args) => _channelExceptionRegister.Add(args); _channel.InitializeRemoteChannelInfo(_remoteChannelNumber, _remoteWindowSize, _remotePacketSize); _channel.SetIsOpen(true); } - private void Act() + protected override void Act() { _channel.SendEof(); } @@ -65,7 +64,7 @@ namespace Renci.SshNet.Tests.Classes.Channels [TestMethod] public void SendMessageOnSessionShouldBeInvokedOnceWithChannelEofMessage() { - _sessionMock.Verify( + SessionMock.Verify( p => p.SendMessage(It.Is(e => e.LocalChannelNumber == _remoteChannelNumber)), Times.Once); } @@ -82,4 +81,4 @@ namespace Renci.SshNet.Tests.Classes.Channels Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs index 8c6413ef..d60549e5 100644 --- a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs +++ b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs @@ -35,7 +35,6 @@ namespace Renci.SshNet.Tests.Classes { private int _partialSuccessLimit; private ClientAuthentication _clientAuthentication; - private SshAuthenticationException _actualException; protected override void SetupData() { diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs new file mode 100644 index 00000000..f39c45de --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs @@ -0,0 +1,32 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes.Common +{ + [TestClass] + [SuppressMessage("ReSharper", "InvokeAsExtensionMethod")] + public class ExtensionsTest_Pad + { + [TestMethod] + public void ShouldReturnNotPadded() + { + byte[] value = {0x0a, 0x0d}; + byte[] padded = value.Pad(2); + Assert.AreEqual(value, padded); + Assert.AreEqual(value.Length, padded.Length); + } + + [TestMethod] + public void ShouldReturnPadded() + { + byte[] value = { 0x0a, 0x0d }; + byte[] padded = value.Pad(3); + Assert.AreEqual(value.Length + 1, padded.Length); + Assert.AreEqual(0x00, padded[0]); + Assert.AreEqual(0x0a, padded[1]); + Assert.AreEqual(0x0d, padded[2]); + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs new file mode 100644 index 00000000..1299f17a --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs @@ -0,0 +1,40 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes.Common +{ + [TestClass] + [SuppressMessage("ReSharper", "InvokeAsExtensionMethod")] + public class ExtensionsTest_ToBigInteger2 + { + [TestMethod] + public void ShouldNotAppendZero() + { + byte[] value = { 0x0a, 0x0d }; + + var actual = value.ToBigInteger2().ToByteArray().Reverse(); + + Assert.IsNotNull(actual); + Assert.AreEqual(2, actual.Length); + Assert.AreEqual(0x0a, actual[0]); + Assert.AreEqual(0x0d, actual[1]); + } + + [TestMethod] + public void ShouldAppendZero() + { + byte[] value = { 0xff, 0x0a, 0x0d }; + + var actual = value.ToBigInteger2().ToByteArray().Reverse(); + + Assert.IsNotNull(actual); + Assert.AreEqual(4, actual.Length); + Assert.AreEqual(0x00, actual[0]); + Assert.AreEqual(0xff, actual[1]); + Assert.AreEqual(0x0a, actual[2]); + Assert.AreEqual(0x0d, actual[3]); + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs new file mode 100644 index 00000000..986ccdea --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs @@ -0,0 +1,177 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Renci.SshNet.Common; +using System; + +namespace Renci.SshNet.Tests.Classes.Common +{ + [TestClass] + public class PosixPathTest_CreateAbsoluteOrRelativeFilePath + { + [TestMethod] + public void Path_Null() + { + const string path = null; + + try + { + PosixPath.CreateAbsoluteOrRelativeFilePath(path); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("path", ex.ParamName); + } + } + + [TestMethod] + public void Path_Empty() + { + var path = string.Empty; + + try + { + PosixPath.CreateAbsoluteOrRelativeFilePath(path); + Assert.Fail(); + } + catch (ArgumentException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format("The path is a zero-length string.{0}Parameter name: {1}", Environment.NewLine, ex.ParamName), ex.Message); + Assert.AreEqual("path", ex.ParamName); + } + } + + [TestMethod] + public void Path_TrailingForwardSlash() + { + var path = "/abc/"; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/abc", actual.Directory); + Assert.IsNull(actual.File); + } + + [TestMethod] + public void Path_FileWithoutNoDirectory() + { + var path = "abc.log"; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual(".", actual.Directory); + Assert.AreSame(path, actual.File); + } + + [TestMethod] + public void Path_FileInRootDirectory() + { + var path = "/abc.log"; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual.Directory); + Assert.AreEqual("abc.log", actual.File); + } + + [TestMethod] + public void Path_RootDirectoryOnly() + { + var path = "/"; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual.Directory); + Assert.IsNull(actual.File); + } + + [TestMethod] + public void Path_FileInNonRootDirectory() + { + var path = "/home/sshnet/xyz"; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/home/sshnet", actual.Directory); + Assert.AreEqual("xyz", actual.File); + } + + [TestMethod] + public void Path_BackslashIsNotConsideredDirectorySeparator() + { + var path = "/home\\abc.log"; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual.Directory); + Assert.AreEqual("home\\abc.log", actual.File); + } + + [TestMethod] + public void Path_ColonIsNotConsideredPathSeparator() + { + var path = "/home:abc.log"; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual.Directory); + Assert.AreEqual("home:abc.log", actual.File); + } + + [TestMethod] + public void Path_LeadingWhitespace() + { + var path = " / \tabc"; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual(" ", actual.Directory); + Assert.AreEqual(" \tabc", actual.File); + } + + [TestMethod] + public void Path_TrailingWhitespace() + { + var path = "/abc \t "; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual.Directory); + Assert.AreEqual("abc \t ", actual.File); + } + + [TestMethod] + public void Path_OnlyWhitespace() + { + var path = " "; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual(".", actual.Directory); + Assert.AreSame(path, actual.File); + } + + [TestMethod] + public void Path_FileNameOnlyWhitespace() + { + var path = "/home/\t "; + + var actual = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/home", actual.Directory); + Assert.AreEqual("\t ", actual.File); + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs new file mode 100644 index 00000000..db1a38e7 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs @@ -0,0 +1,159 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes.Common +{ + [TestClass] + public class PosixPathTest_GetDirectoryName + { + [TestMethod] + public void Path_Null() + { + const string path = null; + + try + { + PosixPath.GetDirectoryName(path); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("path", ex.ParamName); + } + } + + [TestMethod] + public void Path_Empty() + { + var path = string.Empty; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual(".", actual); + } + + [TestMethod] + public void Path_TrailingForwardSlash() + { + var path = "/abc/"; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/abc", actual); + } + + [TestMethod] + public void Path_FileWithoutNoDirectory() + { + var path = "abc.log"; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual(".", actual); + } + + [TestMethod] + public void Path_FileInRootDirectory() + { + var path = "/abc.log"; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual); + } + + [TestMethod] + public void Path_RootDirectoryOnly() + { + var path = "/"; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual); + } + + [TestMethod] + public void Path_FileInNonRootDirectory() + { + var path = "/home/sshnet/xyz"; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/home/sshnet", actual); + } + + [TestMethod] + public void Path_BackslashIsNotConsideredDirectorySeparator() + { + var path = "/home\\abc.log"; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual); + } + + [TestMethod] + public void Path_ColonIsNotConsideredPathSeparator() + { + var path = "/home:abc.log"; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual); + } + + [TestMethod] + public void Path_LeadingWhitespace() + { + var path = " / \tabc"; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual(" ", actual); + } + + [TestMethod] + public void Path_TrailingWhitespace() + { + var path = "/abc \t "; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/", actual); + } + + [TestMethod] + public void Path_OnlyWhitespace() + { + var path = " "; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual(".", actual); + } + + [TestMethod] + public void Path_FileNameOnlyWhitespace() + { + var path = "/home/\t "; + + var actual = PosixPath.GetDirectoryName(path); + + Assert.IsNotNull(actual); + Assert.AreEqual("/home", actual); + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs index d45f115f..3c7d74e2 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs @@ -17,8 +17,10 @@ namespace Renci.SshNet.Tests.Classes.Common PosixPath.GetFileName(path); Assert.Fail(); } - catch (NullReferenceException) + catch (ArgumentNullException ex) { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("path", ex.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.NET40.cs b/src/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.NET40.cs deleted file mode 100644 index 711878dc..00000000 --- a/src/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.NET40.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - public partial class ProxyExceptionTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.NET40.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.NET40.cs deleted file mode 100644 index 115fe662..00000000 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.NET40.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Net; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Properties; - -namespace Renci.SshNet.Tests.Classes -{ - public partial class ForwardedPortLocalTest - { - [TestMethod] - [TestCategory("integration")] - [ExpectedException(typeof(SshConnectionException))] - public void Test_PortForwarding_Local_Without_Connecting() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); - client.AddForwardedPort(port1); - port1.Exception += delegate(object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - port1.Start(); - - System.Threading.Tasks.Parallel.For(0, 100, - - //new ParallelOptions - //{ - // MaxDegreeOfParallelism = 20, - //}, - (counter) => - { - var start = DateTime.Now; - var req = HttpWebRequest.Create("http://localhost:8084"); - using (var response = req.GetResponse()) - { - var data = ReadStream(response.GetResponseStream()); - var end = DateTime.Now; - - Debug.WriteLine(string.Format("Request# {2}: Lenght: {0} Time: {1}", data.Length, (end - start), counter)); - } - } - ); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_PortForwarding_Local() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); - client.AddForwardedPort(port1); - port1.Exception += delegate(object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - port1.Start(); - - System.Threading.Tasks.Parallel.For(0, 100, - - //new ParallelOptions - //{ - // MaxDegreeOfParallelism = 20, - //}, - (counter) => - { - var start = DateTime.Now; - var req = HttpWebRequest.Create("http://localhost:8084"); - using (var response = req.GetResponse()) - { - var data = ReadStream(response.GetResponseStream()); - var end = DateTime.Now; - - Debug.WriteLine(string.Format("Request# {2}: Length: {0} Time: {1}", data.Length, (end - start), counter)); - } - } - ); - } - } - - private static byte[] ReadStream(Stream stream) - { - byte[] buffer = new byte[1024]; - using (var ms = new MemoryStream()) - { - while (true) - { - int read = stream.Read(buffer, 0, buffer.Length); - if (read > 0) - ms.Write(buffer, 0, read); - else - return ms.ToArray(); - } - } - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs index 26b6dfd1..13b2c81b 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs @@ -187,5 +187,97 @@ namespace Renci.SshNet.Tests.Classes } Assert.Inconclusive("TODO: Implement code to verify target"); } + +#if FEATURE_TPL + [TestMethod] + [TestCategory("integration")] + [ExpectedException(typeof(SshConnectionException))] + public void Test_PortForwarding_Local_Without_Connecting() + { + using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); + client.AddForwardedPort(port1); + port1.Exception += delegate (object sender, ExceptionEventArgs e) + { + Assert.Fail(e.Exception.ToString()); + }; + port1.Start(); + + System.Threading.Tasks.Parallel.For(0, 100, + + //new ParallelOptions + //{ + // MaxDegreeOfParallelism = 20, + //}, + (counter) => + { + var start = DateTime.Now; + var req = HttpWebRequest.Create("http://localhost:8084"); + using (var response = req.GetResponse()) + { + var data = ReadStream(response.GetResponseStream()); + var end = DateTime.Now; + + Debug.WriteLine(string.Format("Request# {2}: Lenght: {0} Time: {1}", data.Length, (end - start), counter)); + } + } + ); + } + } + + [TestMethod] + [TestCategory("integration")] + public void Test_PortForwarding_Local() + { + using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + client.Connect(); + var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); + client.AddForwardedPort(port1); + port1.Exception += delegate (object sender, ExceptionEventArgs e) + { + Assert.Fail(e.Exception.ToString()); + }; + port1.Start(); + + System.Threading.Tasks.Parallel.For(0, 100, + + //new ParallelOptions + //{ + // MaxDegreeOfParallelism = 20, + //}, + (counter) => + { + var start = DateTime.Now; + var req = HttpWebRequest.Create("http://localhost:8084"); + using (var response = req.GetResponse()) + { + var data = ReadStream(response.GetResponseStream()); + var end = DateTime.Now; + + Debug.WriteLine(string.Format("Request# {2}: Length: {0} Time: {1}", data.Length, (end - start), counter)); + } + } + ); + } + } + + private static byte[] ReadStream(System.IO.Stream stream) + { + byte[] buffer = new byte[1024]; + using (var ms = new System.IO.MemoryStream()) + { + while (true) + { + int read = stream.Read(buffer, 0, buffer.Length); + if (read > 0) + ms.Write(buffer, 0, read); + else + return ms.ToArray(); + } + } + } +#endif // FEATURE_TPL } } \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemote.NET40.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemote.NET40.cs deleted file mode 100644 index d57ec634..00000000 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemote.NET40.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Diagnostics; -using System.Threading; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Properties; - -namespace Renci.SshNet.Tests.Classes -{ - public partial class ForwardedPortRemoteTest - { - [TestMethod] - [TestCategory("integration")] - public void Test_PortForwarding_Remote() - { - // ****************************************************************** - // ************* Tests are still in not finished ******************** - // ****************************************************************** - - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var port1 = new ForwardedPortRemote(8082, "www.renci.org", 80); - client.AddForwardedPort(port1); - port1.Exception += delegate(object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - port1.Start(); - var boundport = port1.BoundPort; - - System.Threading.Tasks.Parallel.For(0, 5, - - //new ParallelOptions - //{ - // MaxDegreeOfParallelism = 1, - //}, - (counter) => - { - var cmd = client.CreateCommand(string.Format("wget -O- http://localhost:{0}", boundport)); - var result = cmd.Execute(); - var end = DateTime.Now; - Debug.WriteLine(string.Format("Length: {0}", result.Length)); - } - ); - Thread.Sleep(1000 * 100); - port1.Stop(); - } - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs index fe6f43bf..3a99441d 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs @@ -150,5 +150,46 @@ namespace Renci.SshNet.Tests.Classes ForwardedPortRemote target = new ForwardedPortRemote(boundPort, host, port); Assert.Inconclusive("TODO: Implement code to verify target"); } + +#if FEATURE_TPL + [TestMethod] + [TestCategory("integration")] + public void Test_PortForwarding_Remote() + { + // ****************************************************************** + // ************* Tests are still in not finished ******************** + // ****************************************************************** + + using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + client.Connect(); + var port1 = new ForwardedPortRemote(8082, "www.renci.org", 80); + client.AddForwardedPort(port1); + port1.Exception += delegate (object sender, ExceptionEventArgs e) + { + Assert.Fail(e.Exception.ToString()); + }; + port1.Start(); + var boundport = port1.BoundPort; + + System.Threading.Tasks.Parallel.For(0, 5, + + //new ParallelOptions + //{ + // MaxDegreeOfParallelism = 1, + //}, + (counter) => + { + var cmd = client.CreateCommand(string.Format("wget -O- http://localhost:{0}", boundport)); + var result = cmd.Execute(); + var end = DateTime.Now; + System.Diagnostics.Debug.WriteLine(string.Format("Length: {0}", result.Length)); + } + ); + Thread.Sleep(1000 * 100); + port1.Stop(); + } + } +#endif // FEATURE_TPL } } \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs index 94933439..fbc5e1b4 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs @@ -3,14 +3,15 @@ using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; +using Renci.SshNet.Abstractions; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection { /// - ///This is a test class for ChannelDataMessageTest and is intended - ///to contain all ChannelDataMessageTest Unit Tests - /// + /// This is a test class for ChannelDataMessageTest and is intended + /// to contain all ChannelDataMessageTest Unit Tests + /// [TestClass] public class ChannelDataMessageTest : TestBase { @@ -98,10 +99,9 @@ namespace Renci.SshNet.Tests.Classes.Messages.Connection var random = new Random(); var localChannelNumber = (uint) random.Next(0, int.MaxValue); - var data = new byte[random.Next(10, 20)]; - random.NextBytes(data); - var offset = random.Next(2, 4); - var size = random.Next(5, 9); + var data = CryptoAbstraction.GenerateRandom(random.Next(10, 20)); + var offset = random.Next(0, data.Length - 1); + var size = random.Next(0, data.Length - offset); var target = new ChannelDataMessage(localChannelNumber, data, offset, size); @@ -133,11 +133,10 @@ namespace Renci.SshNet.Tests.Classes.Messages.Connection var random = new Random(); var localChannelNumber = (uint) random.Next(0, int.MaxValue); - var data = new byte[random.Next(10, 20)]; - random.NextBytes(data); + var data = CryptoAbstraction.GenerateRandom(random.Next(10, 20)); - var offset = random.Next(2, 4); - var size = random.Next(5, 9); + var offset = random.Next(0, data.Length - 1); + var size = random.Next(0, data.Length - offset); var channelDataMessage = new ChannelDataMessage(localChannelNumber, data, offset, size); var bytes = channelDataMessage.GetBytes(); var target = new ChannelDataMessage(); diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs index 0f229a07..dbb5d0ed 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Text; +using System.Text; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs index 0fb8e87f..2e424b50 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs @@ -1,8 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; -using System.Globalization; using System.Linq; namespace Renci.SshNet.Tests.Classes.Messages.Transport @@ -25,7 +23,7 @@ namespace Renci.SshNet.Tests.Classes.Messages.Transport Assert.IsTrue(m.HostKey.SequenceEqual(new byte[] { 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0xce, 0x38, 0xdf, 0x0d, 0x04, 0x2c, 0x10, 0x45, 0x8f, 0x5e, 0xeb, 0xc2, 0x35, 0x01, 0xd5, 0x4d, 0x09, 0xa3, 0xee, 0x74, 0x3d, 0x75, 0xcf, 0xf4, 0xf3, 0x4f, 0xc9, 0xf9, 0x2e, 0x59, 0xd6, 0xb8, 0x69, 0x85, 0x16, 0xac, 0x33, 0x5b, 0x2a, 0x2a, 0xf8, 0x9c, 0xc4, 0xc3, 0x87, 0xd6, 0xb8, 0x50, 0x6c, 0xed, 0x60, 0x9c, 0x0f, 0x83, 0x37, 0xb3, 0xa2, 0x25, 0xbe, 0x07, 0xde, 0xb6, 0x1f, 0x28, 0xab, 0x05, 0x21, 0xc0, 0x23, 0xf7, 0xd6, 0xca, 0xcb, 0x03, 0x42, 0x69, 0x31, 0x93, 0x2b, 0x3b, 0x94, 0xb8, 0x3b, 0x90, 0xe6, 0x25, 0x7c, 0x23, 0xc5, 0x24, 0x89, 0x65, 0x37, 0x7b, 0x56, 0x54, 0xa2, 0x23, 0xcb, 0xeb, 0xf0, 0xe9, 0xd1, 0x07, 0x88, 0x36, 0x8f, 0xef, 0x65, 0x71, 0xac, 0x80, 0x5c, 0x81, 0x0a, 0x95, 0x1c, 0xf5, 0xc0, 0x5d, 0xd3, 0xd4, 0x10, 0x0e, 0x4f, 0xcf, 0x87, 0x80, 0xa5, 0xde, 0x6e, 0xff, 0x89, 0x9c, 0xfc, 0x2f, 0x85, 0xf5, 0x93, 0xff, 0x70, 0x8e, 0x48, 0xb6, 0x6e, 0x6e, 0x0a, 0x18, 0xa3, 0xbb, 0x1c, 0x56, 0x60, 0xf1, 0x9d, 0x2a, 0xca, 0xbf, 0xa0, 0x84, 0x73, 0xb1, 0x6d, 0x10, 0x75, 0xcc, 0xa3, 0x20, 0xed, 0x00, 0x52, 0xd0, 0x84, 0x5a, 0xc9, 0xbb, 0x17, 0x84, 0x96, 0x40, 0x48, 0xe2, 0x8e, 0x84, 0x30, 0x82, 0x3b, 0x87, 0xa4, 0x54, 0x55, 0x8c, 0xb5, 0x62, 0x97, 0xd7, 0xf1, 0xa3, 0x8b, 0x44, 0xaa, 0x34, 0xfd, 0xe9, 0xad, 0xda, 0xeb, 0x45, 0x27, 0xfb, 0xad, 0xea, 0x9a, 0x0c, 0x38, 0x30, 0x27, 0x6a, 0x82, 0xc2, 0xc2, 0x0a, 0xa0, 0xed, 0x30, 0x2f, 0x50, 0x9f, 0xdb, 0x1a, 0xfb, 0x29, 0x1c, 0x8a, 0x28, 0x3f, 0xd6, 0xf6, 0xa9, 0xeb, 0x76, 0x60, 0xa2, 0x56, 0xa2, 0x90, 0x32, 0xcd, 0x25, 0x41, 0xb7, 0xc0, 0x9e, 0x13, 0x97, 0xaf })); Assert.IsTrue(m.Signature.SequenceEqual(new byte[] { 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x67, 0x83, 0xa1, 0xb8, 0x0c, 0x65, 0xb8, 0xd3, 0x76, 0x5f, 0x5f, 0x05, 0x51, 0x8c, 0xb3, 0x2d, 0x1e, 0x95, 0x67, 0xd6, 0xe2, 0xe4, 0x86, 0x49, 0x11, 0xca, 0x83, 0xab, 0xdb, 0x80, 0x75, 0x4e, 0x89, 0xa7, 0x3d, 0xb6, 0xc2, 0x92, 0xbb, 0x40, 0x00, 0xb9, 0xb3, 0x03, 0x86, 0x19, 0x9d, 0x67, 0x29, 0x2b, 0x5a, 0xc9, 0x0a, 0x6c, 0xa3, 0x21, 0xaf, 0xd8, 0xd4, 0xa7, 0x84, 0x6a, 0xe5, 0x36, 0x3e, 0xa5, 0x58, 0xd6, 0x36, 0x33, 0x12, 0x2e, 0xf9, 0x22, 0x10, 0xff, 0xae, 0x0e, 0xee, 0xfa, 0xdf, 0x1f, 0xf8, 0x70, 0xfe, 0xc0, 0x30, 0x1d, 0x23, 0xbf, 0x99, 0x20, 0x22, 0x18, 0x78, 0xab, 0x5f, 0xd5, 0xfa, 0x5f, 0xf1, 0x18, 0xc2, 0x20, 0xc5, 0x58, 0x90, 0x63, 0x4b, 0x12, 0xf3, 0xa4, 0xe9, 0x20, 0x03, 0x8f, 0x5a, 0x2d, 0x17, 0xbd, 0x75, 0x0a, 0xaf, 0x6d, 0xc5, 0x15, 0x8a, 0x14, 0x74, 0x7f, 0xa0, 0xd2, 0x0f, 0x6f, 0x96, 0xa5, 0x60, 0xb1, 0xb7, 0x65, 0x0f, 0x48, 0x67, 0x5d, 0x32, 0x0a, 0xcb, 0x8e, 0xdf, 0x0c, 0xa9, 0xd5, 0x14, 0x0b, 0x6d, 0xfb, 0x8b, 0xef, 0xa3, 0x79, 0xaf, 0xdb, 0xa3, 0xb4, 0x6d, 0xbb, 0x40, 0x9e, 0xb3, 0x45, 0x04, 0x7f, 0xd1, 0x84, 0xad, 0x90, 0x8b, 0x2d, 0xb6, 0x13, 0xfb, 0x7a, 0xf5, 0xad, 0xbf, 0xa6, 0x74, 0x75, 0xfa, 0x70, 0x59, 0xae, 0x22, 0xbb, 0xfb, 0x09, 0x68, 0xae, 0xe5, 0x26, 0x5c, 0xbd, 0xe0, 0xae, 0x39, 0xbb, 0xaa, 0x59, 0x4c, 0x73, 0x11, 0x01, 0x64, 0x6d, 0xc1, 0x95, 0x1b, 0x93, 0x6b, 0x14, 0x83, 0x4a, 0xdc, 0x16, 0x67, 0x7b, 0x85, 0xd0, 0x89, 0x2e, 0x3c, 0xa1, 0x05, 0x34, 0xf0, 0xd2, 0xb9, 0x3b, 0x83, 0xf4, 0x02, 0xd4, 0x7f, 0x73, 0x76, 0x5d, 0xc2, 0x67, 0xb9, 0xac, 0x8a, 0xd1, 0xab, 0xd4, 0x82 })); - Assert.IsTrue(m.F.Equals(BigInteger.Parse("139283707184174223973094328642546470115773370503206784462562067731214352325418848176518987606406368553205415627101408281035430394244245366884121855956041981785619368311948822371849754297010084387209814408417993188610908497995240761565618964080251146407679074869975343762660867551322434680855150842669738933549", System.Globalization.NumberStyles.None, CultureInfo.CurrentCulture))); + Assert.IsTrue(m.F.SequenceEqual(new byte[] { 0x00, 0xc6, 0x58, 0xb9, 0xa8, 0x11, 0xfd, 0xb6, 0xd6, 0xe9, 0x0c, 0x51, 0x45, 0xac, 0x51, 0x8a, 0x25, 0x6e, 0x1d, 0x9e, 0xbb, 0x7f, 0x98, 0xe3, 0x94, 0xd5, 0xac, 0x97, 0xd6, 0x35, 0x2e, 0xcc, 0x34, 0x85, 0xe2, 0x29, 0x2c, 0xba, 0x45, 0x6b, 0x39, 0xce, 0xd2, 0xae, 0x2e, 0x9a, 0x30, 0x43, 0x45, 0x09, 0xd2, 0xeb, 0x21, 0x46, 0x95, 0xa8, 0xb9, 0xbc, 0xb4, 0x21, 0xcd, 0x65, 0xeb, 0x0f, 0x48, 0x3c, 0x82, 0xdb, 0x52, 0x0e, 0xa5, 0xa8, 0xca, 0x29, 0x2d, 0xf8, 0x54, 0x38, 0xe4, 0x8f, 0x2c, 0x2d, 0x45, 0x2d, 0x2c, 0xf7, 0x1a, 0x41, 0xef, 0xd4, 0xec, 0x0f, 0xa5, 0xa8, 0xa7, 0x64, 0xb3, 0xe8, 0x7b, 0xa1, 0x40, 0x41, 0x69, 0x70, 0x4d, 0x95, 0x91, 0x8b, 0x5f, 0x28, 0xa2, 0xfc, 0xa7, 0x12, 0x2b, 0x94, 0xf0, 0x0a, 0x82, 0x92, 0x65, 0xdf, 0x8a, 0x35, 0xfb, 0xcc, 0xbe, 0xbd, 0x2d })); } } } \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs index f58fd0d0..d70fea36 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs @@ -5,13 +5,111 @@ using System.Xml; namespace Renci.SshNet.Tests.Classes { - // TODO: Please help with documentation here, as I don't know the details, specially for the methods not documented. - /// - /// - /// [TestClass] - public partial class NetConfClientTest : TestBase + public class NetConfClientTest : TestBase { + private Random _random; + + [TestInitialize] + public void SetUp() + { + _random = new Random(); + } + + [TestMethod] + public void OperationTimeout_Default() + { + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new NetConfClient(connectionInfo); + + var actual = target.OperationTimeout; + + Assert.AreEqual(TimeSpan.FromMilliseconds(-1), actual); + } + + [TestMethod] + public void OperationTimeout_InsideLimits() + { + var operationTimeout = TimeSpan.FromMilliseconds(_random.Next(0, int.MaxValue - 1)); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new NetConfClient(connectionInfo) + { + OperationTimeout = operationTimeout + }; + + var actual = target.OperationTimeout; + + Assert.AreEqual(operationTimeout, actual); + } + + [TestMethod] + public void OperationTimeout_LowerLimit() + { + var operationTimeout = TimeSpan.FromMilliseconds(-1); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new NetConfClient(connectionInfo) + { + OperationTimeout = operationTimeout + }; + + var actual = target.OperationTimeout; + + Assert.AreEqual(operationTimeout, actual); + } + + [TestMethod] + public void OperationTimeout_UpperLimit() + { + var operationTimeout = TimeSpan.FromMilliseconds(int.MaxValue); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new NetConfClient(connectionInfo) + { + OperationTimeout = operationTimeout + }; + + var actual = target.OperationTimeout; + + Assert.AreEqual(operationTimeout, actual); + } + + [TestMethod] + public void OperationTimeout_LessThanLowerLimit() + { + var operationTimeout = TimeSpan.FromMilliseconds(-2); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new NetConfClient(connectionInfo); + + try + { + target.OperationTimeout = operationTimeout; + } + catch (ArgumentOutOfRangeException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive." + Environment.NewLine + "Parameter name: " + ex.ParamName, ex.Message); + Assert.AreEqual("value", ex.ParamName); + } + } + + [TestMethod] + public void OperationTimeout_GreaterThanLowerLimit() + { + var operationTimeout = TimeSpan.FromMilliseconds(int.MaxValue).Add(TimeSpan.FromMilliseconds(1)); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new NetConfClient(connectionInfo); + + try + { + target.OperationTimeout = operationTimeout; + } + catch (ArgumentOutOfRangeException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive." + Environment.NewLine + "Parameter name: " + ex.ParamName, ex.Message); + Assert.AreEqual("value", ex.ParamName); + } + } + /// ///A test for NetConfClient Constructor /// @@ -146,23 +244,6 @@ namespace Renci.SshNet.Tests.Classes Assert.Inconclusive("Verify the correctness of this test method."); } - /// - ///A test for OperationTimeout - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OperationTimeoutTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(connectionInfo); // TODO: Initialize to an appropriate value - TimeSpan expected = new TimeSpan(); // TODO: Initialize to an appropriate value - TimeSpan actual; - target.OperationTimeout = expected; - actual = target.OperationTimeout; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - /// ///A test for ClientCapabilities /// diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs new file mode 100644 index 00000000..64ffb6ce --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs @@ -0,0 +1,140 @@ +using System; +using System.Reflection; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Common; +using Renci.SshNet.NetConf; +using Renci.SshNet.Security; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class NetConfClientTest_Connect_NetConfSessionConnectFailure + { + private Mock _serviceFactoryMock; + private Mock _sessionMock; + private Mock _netConfSessionMock; + private ConnectionInfo _connectionInfo; + private ApplicationException _netConfSessionConnectionException; + private NetConfClient _netConfClient; + private ApplicationException _actualException; + + [TestInitialize] + public void Setup() + { + Arrange(); + Act(); + } + + private void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object); + } + + private void SetupData() + { + _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); + _netConfSessionConnectionException = new ApplicationException(); + } + + private void CreateMocks() + { + _serviceFactoryMock = new Mock(MockBehavior.Strict); + _sessionMock = new Mock(MockBehavior.Strict); + _netConfSessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + var sequence = new MockSequence(); + + _serviceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo)) + .Returns(_sessionMock.Object); + _sessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _serviceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateNetConfSession(_sessionMock.Object, -1)) + .Returns(_netConfSessionMock.Object); + _netConfSessionMock.InSequence(sequence) + .Setup(p => p.Connect()) + .Throws(_netConfSessionConnectionException); + _netConfSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _sessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + } + + private void Act() + { + try + { + _netConfClient.Connect(); + Assert.Fail(); + } + catch (ApplicationException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void ConnectShouldHaveThrownApplicationException() + { + Assert.IsNotNull(_actualException); + Assert.AreSame(_netConfSessionConnectionException, _actualException); + } + + [TestMethod] + public void SessionShouldBeNull() + { + Assert.IsNull(_netConfClient.Session); + } + + [TestMethod] + public void NetConfSessionShouldBeNull() + { + Assert.IsNull(_netConfClient.NetConfSession); + } + + [TestMethod] + public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnNetConfClient() + { + var errorOccurredSignalCount = 0; + + _netConfClient.ErrorOccurred += (sender, args) => Interlocked.Increment(ref errorOccurredSignalCount); + + _sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); + + Assert.AreEqual(0, errorOccurredSignalCount); + } + + [TestMethod] + public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOnSftpClient() + { + var hostKeyReceivedSignalCount = 0; + + _netConfClient.HostKeyReceived += (sender, args) => Interlocked.Increment(ref hostKeyReceivedSignalCount); + + _sessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); + + Assert.AreEqual(0, hostKeyReceivedSignalCount); + } + + private static KeyHostAlgorithm GetKeyHostAlgorithm() + { + var executingAssembly = Assembly.GetExecutingAssembly(); + + using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + { + var privateKey = new PrivateKeyFile(s); + return (KeyHostAlgorithm)privateKey.HostKey; + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 21bd9785..99434d71 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -319,6 +319,72 @@ namespace Renci.SshNet.Tests.Classes } } + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA() + { + using (var stream = GetData("Key.ECDSA.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA384() + { + using (var stream = GetData("Key.ECDSA384.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA521() + { + using (var stream = GetData("Key.ECDSA521.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA_Encrypted() + { + using (var stream = GetData("Key.ECDSA.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA384_Encrypted() + { + using (var stream = GetData("Key.ECDSA384.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_ECDSA521_Encrypted() + { + using (var stream = GetData("Key.ECDSA521.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + /// ///A test for Dispose /// @@ -479,6 +545,34 @@ namespace Renci.SshNet.Tests.Classes } } + /// + /// A test for opening an openssh v1 keyfile where there is no passphrase. + /// + [TestMethod()] + [Owner("bhalbright")] + [TestCategory("PrivateKey")] + public void TestOpenSshV1KeyFileNoPassphrase() + { + using (var stream = GetData("Key.OPENSSH.ED25519.txt")) + { + new PrivateKeyFile(stream); + } + } + + /// + /// A test for opening an openssh v1 keyfile where there is a passphrase. + /// + [TestMethod()] + [Owner("bhalbright")] + [TestCategory("PrivateKey")] + public void TestOpenSshV1KeyFileWithPassphrase() + { + using (var stream = GetData("Key.OPENSSH.ED25519.Encrypted.txt")) + { + new PrivateKeyFile(stream, "password"); + } + } + private void SaveStreamToFile(Stream stream, string fileName) { var buffer = new byte[4000]; @@ -501,4 +595,4 @@ namespace Renci.SshNet.Tests.Classes return tempFile; } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest.NET40.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest.NET40.cs deleted file mode 100644 index fce6e505..00000000 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest.NET40.cs +++ /dev/null @@ -1,109 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Properties; -using System.IO; -using System.Linq; -using System.Threading.Tasks; - -namespace Renci.SshNet.Tests.Classes -{ - /// - /// Provides SCP client functionality. - /// - public partial class ScpClientTest - { - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_File_20_Parallel_Upload_Download() - { - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadFilenames = new string[20]; - for (int i = 0; i < uploadFilenames.Length; i++) - { - uploadFilenames[i] = Path.GetTempFileName(); - this.CreateTestFile(uploadFilenames[i], 1); - } - - Parallel.ForEach(uploadFilenames, - (filename) => - { - scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); - }); - - Parallel.ForEach(uploadFilenames, - (filename) => - { - scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); - }); - - var result = from file in uploadFilenames - where - CalculateMD5(file) == CalculateMD5(string.Format("{0}.down", file)) - select file; - - scp.Disconnect(); - - Assert.IsTrue(result.Count() == uploadFilenames.Length); - } - } - - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_File_Upload_Download_Events() - { - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadFilenames = new string[10]; - - for (int i = 0; i < uploadFilenames.Length; i++) - { - uploadFilenames[i] = Path.GetTempFileName(); - this.CreateTestFile(uploadFilenames[i], 1); - } - - var uploadedFiles = uploadFilenames.ToDictionary((filename) => Path.GetFileName(filename), (filename) => 0L); - var downloadedFiles = uploadFilenames.ToDictionary((filename) => string.Format("{0}.down", Path.GetFileName(filename)), (filename) => 0L); - - scp.Uploading += delegate(object sender, ScpUploadEventArgs e) - { - uploadedFiles[e.Filename] = e.Uploaded; - }; - - scp.Downloading += delegate(object sender, ScpDownloadEventArgs e) - { - downloadedFiles[string.Format("{0}.down", e.Filename)] = e.Downloaded; - }; - - Parallel.ForEach(uploadFilenames, - (filename) => - { - scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); - }); - - Parallel.ForEach(uploadFilenames, - (filename) => - { - scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); - }); - - var result = from uf in uploadedFiles - from df in downloadedFiles - where - string.Format("{0}.down", uf.Key) == df.Key - && uf.Value == df.Value - select uf; - - scp.Disconnect(); - - Assert.IsTrue(result.Count() == uploadFilenames.Length && uploadFilenames.Length == uploadedFiles.Count && uploadedFiles.Count == downloadedFiles.Count); - } - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs index a7f7da14..038d952e 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs @@ -7,6 +7,9 @@ using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; +#if FEATURE_TPL +using System.Threading.Tasks; +#endif // FEATURE_TPL namespace Renci.SshNet.Tests.Classes { @@ -536,6 +539,102 @@ namespace Renci.SshNet.Tests.Classes Assert.Inconclusive("A method that does not return a value cannot be verified."); } +#if FEATURE_TPL + [TestMethod] + [TestCategory("Scp")] + [TestCategory("integration")] + public void Test_Scp_File_20_Parallel_Upload_Download() + { + using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + scp.Connect(); + + var uploadFilenames = new string[20]; + for (int i = 0; i < uploadFilenames.Length; i++) + { + uploadFilenames[i] = Path.GetTempFileName(); + this.CreateTestFile(uploadFilenames[i], 1); + } + + Parallel.ForEach(uploadFilenames, + (filename) => + { + scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); + }); + + Parallel.ForEach(uploadFilenames, + (filename) => + { + scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); + }); + + var result = from file in uploadFilenames + where + CalculateMD5(file) == CalculateMD5(string.Format("{0}.down", file)) + select file; + + scp.Disconnect(); + + Assert.IsTrue(result.Count() == uploadFilenames.Length); + } + } + + [TestMethod] + [TestCategory("Scp")] + [TestCategory("integration")] + public void Test_Scp_File_Upload_Download_Events() + { + using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + scp.Connect(); + + var uploadFilenames = new string[10]; + + for (int i = 0; i < uploadFilenames.Length; i++) + { + uploadFilenames[i] = Path.GetTempFileName(); + this.CreateTestFile(uploadFilenames[i], 1); + } + + var uploadedFiles = uploadFilenames.ToDictionary((filename) => Path.GetFileName(filename), (filename) => 0L); + var downloadedFiles = uploadFilenames.ToDictionary((filename) => string.Format("{0}.down", Path.GetFileName(filename)), (filename) => 0L); + + scp.Uploading += delegate (object sender, ScpUploadEventArgs e) + { + uploadedFiles[e.Filename] = e.Uploaded; + }; + + scp.Downloading += delegate (object sender, ScpDownloadEventArgs e) + { + downloadedFiles[string.Format("{0}.down", e.Filename)] = e.Downloaded; + }; + + Parallel.ForEach(uploadFilenames, + (filename) => + { + scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); + }); + + Parallel.ForEach(uploadFilenames, + (filename) => + { + scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); + }); + + var result = from uf in uploadedFiles + from df in downloadedFiles + where + string.Format("{0}.down", uf.Key) == df.Key + && uf.Value == df.Value + select uf; + + scp.Disconnect(); + + Assert.IsTrue(result.Count() == uploadFilenames.Length && uploadFilenames.Length == uploadedFiles.Count && uploadedFiles.Count == downloadedFiles.Count); + } + } +#endif // FEATURE_TPL + protected static string CalculateMD5(string fileName) { using (var file = new FileStream(fileName, FileMode.Open)) diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs index fc9b75b6..1c47aeae 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -25,7 +24,7 @@ namespace Renci.SshNet.Tests.Classes _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd")); _directoryInfo = new DirectoryInfo("source"); - _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture); + _path = "/home/sshnet/" + random.Next().ToString(); _transformedPath = random.Next().ToString(); _uploadingRegister = new List(); } @@ -48,7 +47,7 @@ namespace Renci.SshNet.Tests.Classes .Setup(p => p.Transform(_path)) .Returns(_transformedPath); _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendExecRequest(string.Format("scp -rt {0}", _transformedPath))) + .Setup(p => p.SendExecRequest(string.Format("scp -r -p -d -t {0}", _transformedPath))) .Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); @@ -87,7 +86,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void SendExecREquestOnChannelSessionShouldBeInvokedOnce() { - _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -rt {0}", _transformedPath)), Times.Once); + _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -r -p -d -t {0}", _transformedPath)), Times.Once); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs index a3d1ca09..0c842a21 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs @@ -13,7 +13,9 @@ namespace Renci.SshNet.Tests.Classes private ConnectionInfo _connectionInfo; private ScpClient _scpClient; private FileInfo _fileInfo; - private string _path; + private string _remoteDirectory; + private string _remoteFile; + private string _remotePath; private string _transformedPath; private string _fileName; private IList _uploadingRegister; @@ -36,7 +38,9 @@ namespace Renci.SshNet.Tests.Classes _fileName = CreateTemporaryFile(new byte[] { 1 }); _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd")); _fileInfo = new FileInfo(_fileName); - _path = "/home/sshnet/" + random.Next(); + _remoteDirectory = "/home/sshnet"; + _remoteFile = random.Next().ToString(); + _remotePath = _remoteDirectory + "/" + _remoteFile; _transformedPath = random.Next().ToString(); _uploadingRegister = new List(); } @@ -56,10 +60,10 @@ namespace Renci.SshNet.Tests.Classes _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); _remotePathTransformationMock.InSequence(sequence) - .Setup(p => p.Transform(_path)) + .Setup(p => p.Transform(_remoteDirectory)) .Returns(_transformedPath); _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath))) + .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) .Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); @@ -78,7 +82,7 @@ namespace Renci.SshNet.Tests.Classes { try { - _scpClient.Upload(_fileInfo, _path); + _scpClient.Upload(_fileInfo, _remotePath); Assert.Fail(); } catch (SshException ex) @@ -98,7 +102,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void SendExecRequestOnChannelSessionShouldBeInvokedOnce() { - _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once); + _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath)), Times.Once); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs index a6ac4a11..c04525e0 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Text; @@ -16,7 +15,9 @@ namespace Renci.SshNet.Tests.Classes private ConnectionInfo _connectionInfo; private ScpClient _scpClient; private FileInfo _fileInfo; - private string _path; + private string _remoteDirectory; + private string _remoteFile; + private string _remotePath; private string _transformedPath; private int _bufferSize; private byte[] _fileContent; @@ -44,7 +45,9 @@ namespace Renci.SshNet.Tests.Classes _fileName = CreateTemporaryFile(_fileContent); _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd")); _fileInfo = new FileInfo(_fileName); - _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture); + _remoteDirectory = "/home/sshnet"; + _remoteFile = random.Next().ToString(); + _remotePath = _remoteDirectory + "/" + _remoteFile; _transformedPath = random.Next().ToString(); _uploadingRegister = new List(); } @@ -64,17 +67,18 @@ namespace Renci.SshNet.Tests.Classes _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); _remotePathTransformationMock.InSequence(sequence) - .Setup(p => p.Transform(_path)) + .Setup(p => p.Transform(_remoteDirectory)) .Returns(_transformedPath); _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath))) + .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) .Returns(true); _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0); _channelSessionMock.InSequence(sequence).Setup(p => p.SendData(It.IsAny())); _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0); _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendData(It.Is(b => b.SequenceEqual(CreateData( - string.Format("C0644 {0} {1}\n", _fileInfo.Length, string.Empty)))))); + .Setup(p => p.SendData(It.Is(b => b.SequenceEqual( + CreateData(string.Format("C0644 {0} {1}\n", _fileInfo.Length, _remoteFile), + _connectionInfo.Encoding))))); _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0); _channelSessionMock.InSequence(sequence) .Setup( @@ -104,13 +108,13 @@ namespace Renci.SshNet.Tests.Classes protected override void Act() { - _scpClient.Upload(_fileInfo, _path); + _scpClient.Upload(_fileInfo, _remotePath); } [TestMethod] public void SendExecRequestOnChannelSessionShouldBeInvokedOnce() { - _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once); + _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath)), Times.Once); } [TestMethod] @@ -143,9 +147,9 @@ namespace Renci.SshNet.Tests.Classes Assert.AreEqual(_fileSize, uploading.Uploaded); } - private static IEnumerable CreateData(string command) + private static IEnumerable CreateData(string command, Encoding encoding) { - return Encoding.Default.GetBytes(command); + return encoding.GetBytes(command); } private static byte[] CreateContent(int length) diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs index b03a4484..d2c6992b 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -14,7 +13,9 @@ namespace Renci.SshNet.Tests.Classes private ConnectionInfo _connectionInfo; private ScpClient _scpClient; private Stream _source; - private string _path; + private string _remoteDirectory; + private string _remoteFile; + private string _remotePath; private string _transformedPath; private IList _uploadingRegister; private SshException _actualException; @@ -34,7 +35,9 @@ namespace Renci.SshNet.Tests.Classes _connectionInfo = new ConnectionInfo("host", 22, "user", new PasswordAuthenticationMethod("user", "pwd")); _source = new MemoryStream(); - _path = "/home/sshnet/" + random.Next().ToString(CultureInfo.InvariantCulture); + _remoteDirectory = "/home/sshnet"; + _remoteFile = random.Next().ToString(); + _remotePath = _remoteDirectory + "/" + _remoteFile; _transformedPath = random.Next().ToString(); _uploadingRegister = new List(); } @@ -54,10 +57,10 @@ namespace Renci.SshNet.Tests.Classes _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); _remotePathTransformationMock.InSequence(sequence) - .Setup(p => p.Transform(_path)) + .Setup(p => p.Transform(_remoteDirectory)) .Returns(_transformedPath); _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath))) + .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) .Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); @@ -76,7 +79,7 @@ namespace Renci.SshNet.Tests.Classes { try { - _scpClient.Upload(_source, _path); + _scpClient.Upload(_source, _remotePath); Assert.Fail(); } catch (SshException ex) @@ -96,7 +99,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void SendExecRequestOnChannelSessionShouldBeInvokedOnce() { - _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t {0}", _transformedPath)), Times.Once); + _channelSessionMock.Verify(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath)), Times.Once); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs index fdf0ffe5..c077a309 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs @@ -14,7 +14,7 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers public class CastCipherTest : TestBase { [TestMethod] - public void Test_Cipher_CastCipher_128_CBC() + public void Encrypt_128_CBC() { var input = new byte[] { 0x00, 0x00, 0x00, 0x2c, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x73, 0x73, 0x68, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x61, 0x75, 0x74, 0x68, 0x30, 0x9e, 0xe0, 0x9c, 0x12, 0xee, 0x3a, 0x30, 0x03, 0x52, 0x1c, 0x1a, 0xe7, 0x3e, 0x0b, 0x9a, 0xcf, 0x9a, 0x57, 0x42, 0x0b, 0x4f, 0x4a, 0x15, 0xa0, 0xf5 }; var key = new byte[] { 0xe4, 0x94, 0xf9, 0xb1, 0x00, 0x4f, 0x16, 0x2a, 0x80, 0x11, 0xea, 0x73, 0x0d, 0xb9, 0xbf, 0x64 }; @@ -23,8 +23,20 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers var testCipher = new CastCipher(key, new CbcCipherMode(iv), null); var r = testCipher.Encrypt(input); - if (!r.SequenceEqual(output)) - Assert.Fail("Invalid encryption"); + Assert.IsTrue(r.SequenceEqual(output)); + } + + [TestMethod] + public void Decrypt_128_CBC() + { + var input = new byte[] { 0x00, 0x00, 0x00, 0x2c, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x73, 0x73, 0x68, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x61, 0x75, 0x74, 0x68, 0x30, 0x9e, 0xe0, 0x9c, 0x12, 0xee, 0x3a, 0x30, 0x03, 0x52, 0x1c, 0x1a, 0xe7, 0x3e, 0x0b, 0x9a, 0xcf, 0x9a, 0x57, 0x42, 0x0b, 0x4f, 0x4a, 0x15, 0xa0, 0xf5 }; + var key = new byte[] { 0xe4, 0x94, 0xf9, 0xb1, 0x00, 0x4f, 0x16, 0x2a, 0x80, 0x11, 0xea, 0x73, 0x0d, 0xb9, 0xbf, 0x64 }; + var iv = new byte[] { 0x74, 0x8b, 0x4f, 0xe6, 0xc1, 0x29, 0xb3, 0x54, 0xec, 0x77, 0x92, 0xf3, 0x15, 0xa0, 0x41, 0xa8 }; + var output = new byte[] { 0x32, 0xef, 0xbd, 0xac, 0xb6, 0xfd, 0x1f, 0xae, 0x1b, 0x13, 0x5f, 0x31, 0x6d, 0x38, 0xcd, 0xb0, 0xe3, 0xca, 0xe1, 0xbc, 0xf8, 0xa7, 0xc2, 0x31, 0x62, 0x14, 0x3a, 0x9a, 0xda, 0xe3, 0xf8, 0xc8, 0x70, 0x87, 0x53, 0x21, 0x5d, 0xb7, 0x94, 0xb7, 0xe8, 0xc6, 0x9d, 0x46, 0x0c, 0x6d, 0x64, 0x6d }; + var testCipher = new CastCipher(key, new CbcCipherMode(iv), null); + var r = testCipher.Decrypt(output); + + Assert.IsTrue(r.SequenceEqual(input)); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs new file mode 100644 index 00000000..744a434f --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs @@ -0,0 +1,61 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Renci.SshNet.Common; +using Renci.SshNet.Security; +using Renci.SshNet.Tests.Common; +using System.Text; + +namespace Renci.SshNet.Tests.Classes.Security +{ + [TestClass] + public class KeyExchangeDiffieHellmanGroup14Sha256Test : TestBase + { + private static readonly byte[] SecondOkleyGroup = + { + 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9, 0x0f, 0xda, 0xa2, + 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, + 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6, + 0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, + 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, + 0xf2, 0x5f, 0x14, 0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, + 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4, 0x4c, 0x42, 0xe9, + 0xa6, 0x37, 0xed, 0x6b, 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, + 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, 0xae, 0x9f, 0x24, 0x11, + 0x7c, 0x4b, 0x1f, 0xe6, 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, + 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, 0x98, 0xda, 0x48, 0x36, + 0x1c, 0x55, 0xd3, 0x9a, 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, + 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, 0x1c, 0x62, 0xf3, 0x56, + 0x20, 0x85, 0x52, 0xbb, 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, + 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, 0xf1, 0x74, 0x6c, 0x08, + 0xca, 0x18, 0x21, 0x7c, 0x32, 0x90, 0x5e, 0x46, 0x2e, 0x36, 0xce, 0x3b, + 0xe3, 0x9e, 0x77, 0x2c, 0x18, 0x0e, 0x86, 0x03, 0x9b, 0x27, 0x83, 0xa2, + 0xec, 0x07, 0xa2, 0x8f, 0xb5, 0xc5, 0x5d, 0xf0, 0x6f, 0x4c, 0x52, 0xc9, + 0xde, 0x2b, 0xcb, 0xf6, 0x95, 0x58, 0x17, 0x18, 0x39, 0x95, 0x49, 0x7c, + 0xea, 0x95, 0x6a, 0xe5, 0x15, 0xd2, 0x26, 0x18, 0x98, 0xfa, 0x05, 0x10, + 0x15, 0x72, 0x8e, 0x5a, 0x8a, 0xac, 0xaa, 0x68, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff + }; + + private KeyExchangeDiffieHellmanGroup14Sha256 _group14; + + protected override void OnInit() + { + base.OnInit(); + + _group14 = new KeyExchangeDiffieHellmanGroup14Sha256(); + } + + [TestMethod] + public void GroupPrimeShouldBeSecondOakleyGroup() + { + var bytes = _group14.GroupPrime.ToByteArray().Reverse(); + Assert.IsTrue(SecondOkleyGroup.IsEqualTo(bytes)); + } + + [TestMethod] + public void NameShouldBeDiffieHellmanGroup14Sha256() + { + Assert.AreEqual("diffie-hellman-group14-sha256", _group14.Name); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs new file mode 100644 index 00000000..45d6f295 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs @@ -0,0 +1,70 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Renci.SshNet.Common; +using Renci.SshNet.Security; +using Renci.SshNet.Tests.Common; + +namespace Renci.SshNet.Tests.Classes.Security +{ + [TestClass] + public class KeyExchangeDiffieHellmanGroup16Sha512Test : TestBase + { + private static readonly byte[] MoreModularExponentialGroup16 = + { + 0x00, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xc9,0x0f,0xda,0xa2,0x21,0x68,0xc2,0x34, + 0xc4,0xc6,0x62,0x8b,0x80,0xdc,0x1c,0xd1,0x29,0x02,0x4e,0x08,0x8a,0x67,0xcc,0x74, + 0x02,0x0b,0xbe,0xa6,0x3b,0x13,0x9b,0x22,0x51,0x4a,0x08,0x79,0x8e,0x34,0x04,0xdd, + 0xef,0x95,0x19,0xb3,0xcd,0x3a,0x43,0x1b,0x30,0x2b,0x0a,0x6d,0xf2,0x5f,0x14,0x37, + 0x4f,0xe1,0x35,0x6d,0x6d,0x51,0xc2,0x45,0xe4,0x85,0xb5,0x76,0x62,0x5e,0x7e,0xc6, + 0xf4,0x4c,0x42,0xe9,0xa6,0x37,0xed,0x6b,0x0b,0xff,0x5c,0xb6,0xf4,0x06,0xb7,0xed, + 0xee,0x38,0x6b,0xfb,0x5a,0x89,0x9f,0xa5,0xae,0x9f,0x24,0x11,0x7c,0x4b,0x1f,0xe6, + 0x49,0x28,0x66,0x51,0xec,0xe4,0x5b,0x3d,0xc2,0x00,0x7c,0xb8,0xa1,0x63,0xbf,0x05, + 0x98,0xda,0x48,0x36,0x1c,0x55,0xd3,0x9a,0x69,0x16,0x3f,0xa8,0xfd,0x24,0xcf,0x5f, + 0x83,0x65,0x5d,0x23,0xdc,0xa3,0xad,0x96,0x1c,0x62,0xf3,0x56,0x20,0x85,0x52,0xbb, + 0x9e,0xd5,0x29,0x07,0x70,0x96,0x96,0x6d,0x67,0x0c,0x35,0x4e,0x4a,0xbc,0x98,0x04, + 0xf1,0x74,0x6c,0x08,0xca,0x18,0x21,0x7c,0x32,0x90,0x5e,0x46,0x2e,0x36,0xce,0x3b, + 0xe3,0x9e,0x77,0x2c,0x18,0x0e,0x86,0x03,0x9b,0x27,0x83,0xa2,0xec,0x07,0xa2,0x8f, + 0xb5,0xc5,0x5d,0xf0,0x6f,0x4c,0x52,0xc9,0xde,0x2b,0xcb,0xf6,0x95,0x58,0x17,0x18, + 0x39,0x95,0x49,0x7c,0xea,0x95,0x6a,0xe5,0x15,0xd2,0x26,0x18,0x98,0xfa,0x05,0x10, + 0x15,0x72,0x8e,0x5a,0x8a,0xaa,0xc4,0x2d,0xad,0x33,0x17,0x0d,0x04,0x50,0x7a,0x33, + 0xa8,0x55,0x21,0xab,0xdf,0x1c,0xba,0x64,0xec,0xfb,0x85,0x04,0x58,0xdb,0xef,0x0a, + 0x8a,0xea,0x71,0x57,0x5d,0x06,0x0c,0x7d,0xb3,0x97,0x0f,0x85,0xa6,0xe1,0xe4,0xc7, + 0xab,0xf5,0xae,0x8c,0xdb,0x09,0x33,0xd7,0x1e,0x8c,0x94,0xe0,0x4a,0x25,0x61,0x9d, + 0xce,0xe3,0xd2,0x26,0x1a,0xd2,0xee,0x6b,0xf1,0x2f,0xfa,0x06,0xd9,0x8a,0x08,0x64, + 0xd8,0x76,0x02,0x73,0x3e,0xc8,0x6a,0x64,0x52,0x1f,0x2b,0x18,0x17,0x7b,0x20,0x0c, + 0xbb,0xe1,0x17,0x57,0x7a,0x61,0x5d,0x6c,0x77,0x09,0x88,0xc0,0xba,0xd9,0x46,0xe2, + 0x08,0xe2,0x4f,0xa0,0x74,0xe5,0xab,0x31,0x43,0xdb,0x5b,0xfc,0xe0,0xfd,0x10,0x8e, + 0x4b,0x82,0xd1,0x20,0xa9,0x21,0x08,0x01,0x1a,0x72,0x3c,0x12,0xa7,0x87,0xe6,0xd7, + 0x88,0x71,0x9a,0x10,0xbd,0xba,0x5b,0x26,0x99,0xc3,0x27,0x18,0x6a,0xf4,0xe2,0x3c, + 0x1a,0x94,0x68,0x34,0xb6,0x15,0x0b,0xda,0x25,0x83,0xe9,0xca,0x2a,0xd4,0x4c,0xe8, + 0xdb,0xbb,0xc2,0xdb,0x04,0xde,0x8e,0xf9,0x2e,0x8e,0xfc,0x14,0x1f,0xbe,0xca,0xa6, + 0x28,0x7c,0x59,0x47,0x4e,0x6b,0xc0,0x5d,0x99,0xb2,0x96,0x4f,0xa0,0x90,0xc3,0xa2, + 0x23,0x3b,0xa1,0x86,0x51,0x5b,0xe7,0xed,0x1f,0x61,0x29,0x70,0xce,0xe2,0xd7,0xaf, + 0xb8,0x1b,0xdd,0x76,0x21,0x70,0x48,0x1c,0xd0,0x06,0x91,0x27,0xd5,0xb0,0x5a,0xa9, + 0x93,0xb4,0xea,0x98,0x8d,0x8f,0xdd,0xc1,0x86,0xff,0xb7,0xdc,0x90,0xa6,0xc0,0x8f, + 0x4d,0xf4,0x35,0xc9,0x34,0x06,0x31,0x99,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff + }; + + private KeyExchangeDiffieHellmanGroup16Sha512 _group16; + + protected override void OnInit() + { + base.OnInit(); + + _group16 = new KeyExchangeDiffieHellmanGroup16Sha512(); + } + + [TestMethod] + public void GroupPrimeShouldBeMoreModularExponentialGroup16() + { + var bytes = _group16.GroupPrime.ToByteArray().Reverse(); + Assert.IsTrue(MoreModularExponentialGroup16.IsEqualTo(bytes)); + } + + [TestMethod] + public void NameShouldBeDiffieHellmanGroup16Sha512() + { + Assert.AreEqual("diffie-hellman-group16-sha512", _group16.Name); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs new file mode 100644 index 00000000..651f2fbc --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Channels; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException + { + private Mock _sessionMock; + private Mock _connectionInfoMock; + private Mock _channelSessionMock; + private ServiceFactory _serviceFactory; + private string _terminalName; + private uint _columns; + private uint _rows; + private uint _width; + private uint _height; + private IDictionary _terminalModeValues; + private int _bufferSize; + private SshException _channelOpenException; + private SshException _actualException; + + private void SetupData() + { + var random = new Random(); + + _terminalName = random.Next().ToString(); + _columns = (uint) random.Next(); + _rows = (uint) random.Next(); + _width = (uint) random.Next(); + _height = (uint) random.Next(); + _terminalModeValues = new Dictionary(); + _bufferSize = random.Next(); + _channelOpenException = new SshException(); + + _actualException = null; + } + + private void CreateMocks() + { + _sessionMock = new Mock(MockBehavior.Strict); + _connectionInfoMock = new Mock(MockBehavior.Strict); + _channelSessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + var sequence = new MockSequence(); + + _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _connectionInfoMock.InSequence(sequence) + .Setup(p => p.Encoding) + .Returns(new UTF8Encoding()); + _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()) + .Throws(_channelOpenException); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + } + + private void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _serviceFactory = new ServiceFactory(); + } + + [TestInitialize] + public void Initialize() + { + Arrange(); + Act(); + } + + private void Act() + { + try + { + _serviceFactory.CreateShellStream(_sessionMock.Object, + _terminalName, + _columns, + _rows, + _width, + _height, + _terminalModeValues, + _bufferSize); + Assert.Fail(); + } + catch (SshException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void CreateShellStreamShouldRethrowExceptionThrownByOpenOnChannelSession() + { + Assert.IsNotNull(_actualException); + Assert.AreSame(_channelOpenException, _actualException); + } + + [TestMethod] + public void DisposeOnChannelSessionShouldHaveBeenInvokedOnce() + { + _channelSessionMock.Verify(p => p.Dispose(), Times.Once); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs new file mode 100644 index 00000000..362351a5 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Channels; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse + { + private Mock _sessionMock; + private Mock _connectionInfoMock; + private Mock _channelSessionMock; + private ServiceFactory _serviceFactory; + private string _terminalName; + private uint _columns; + private uint _rows; + private uint _width; + private uint _height; + private IDictionary _terminalModeValues; + private int _bufferSize; + private SshException _actualException; + + private void SetupData() + { + var random = new Random(); + + _terminalName = random.Next().ToString(); + _columns = (uint)random.Next(); + _rows = (uint)random.Next(); + _width = (uint)random.Next(); + _height = (uint)random.Next(); + _terminalModeValues = new Dictionary(); + _bufferSize = random.Next(); + _actualException = null; + } + + private void CreateMocks() + { + _sessionMock = new Mock(MockBehavior.Strict); + _connectionInfoMock = new Mock(MockBehavior.Strict); + _channelSessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + var sequence = new MockSequence(); + + _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _connectionInfoMock.InSequence(sequence) + .Setup(p => p.Encoding) + .Returns(new UTF8Encoding()); + _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModeValues)) + .Returns(false); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + } + + private void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _serviceFactory = new ServiceFactory(); + } + + [TestInitialize] + public void Initialize() + { + Arrange(); + Act(); + } + + private void Act() + { + try + { + _serviceFactory.CreateShellStream(_sessionMock.Object, + _terminalName, + _columns, + _rows, + _width, + _height, + _terminalModeValues, + _bufferSize); + Assert.Fail(); + } + catch (SshException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void CreateShellStreamShouldThrowSshException() + { + Assert.IsNotNull(_actualException); + Assert.IsNull(_actualException.InnerException); + Assert.AreEqual("The pseudo-terminal request was not accepted by the server. Consult the server log for more information.", _actualException.Message); + } + + [TestMethod] + public void DisposeOnChannelSessionShouldHaveBeenInvokedOnce() + { + _channelSessionMock.Verify(p => p.Dispose(), Times.Once); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs new file mode 100644 index 00000000..67606992 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Channels; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException + { + private Mock _sessionMock; + private Mock _connectionInfoMock; + private Mock _channelSessionMock; + private ServiceFactory _serviceFactory; + private string _terminalName; + private uint _columns; + private uint _rows; + private uint _width; + private uint _height; + private IDictionary _terminalModeValues; + private int _bufferSize; + private SshException _sendPseudoTerminalRequestException; + private SshException _actualException; + + private void SetupData() + { + var random = new Random(); + + _terminalName = random.Next().ToString(); + _columns = (uint) random.Next(); + _rows = (uint) random.Next(); + _width = (uint) random.Next(); + _height = (uint) random.Next(); + _terminalModeValues = new Dictionary(); + _bufferSize = random.Next(); + _sendPseudoTerminalRequestException = new SshException(); + + _actualException = null; + } + + private void CreateMocks() + { + _sessionMock = new Mock(MockBehavior.Strict); + _connectionInfoMock = new Mock(MockBehavior.Strict); + _channelSessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + var sequence = new MockSequence(); + + _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _connectionInfoMock.InSequence(sequence) + .Setup(p => p.Encoding) + .Returns(new UTF8Encoding()); + _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModeValues)) + .Throws(_sendPseudoTerminalRequestException); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + } + + private void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _serviceFactory = new ServiceFactory(); + } + + [TestInitialize] + public void Initialize() + { + Arrange(); + Act(); + } + + private void Act() + { + try + { + _serviceFactory.CreateShellStream(_sessionMock.Object, + _terminalName, + _columns, + _rows, + _width, + _height, + _terminalModeValues, + _bufferSize); + Assert.Fail(); + } + catch (SshException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void CreateShellStreamShouldRethrowExceptionThrownBySendPseudoTerminalRequestOnChannelSession() + { + Assert.IsNotNull(_actualException); + Assert.AreSame(_sendPseudoTerminalRequestException, _actualException); + } + + [TestMethod] + public void DisposeOnChannelSessionShouldHaveBeenInvokedOnce() + { + _channelSessionMock.Verify(p => p.Dispose(), Times.Once); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs new file mode 100644 index 00000000..5a6d4387 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Channels; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse + { + private Mock _sessionMock; + private Mock _connectionInfoMock; + private Mock _channelSessionMock; + private ServiceFactory _serviceFactory; + private string _terminalName; + private uint _columns; + private uint _rows; + private uint _width; + private uint _height; + private IDictionary _terminalModeValues; + private int _bufferSize; + private SshException _actualException; + + private void SetupData() + { + var random = new Random(); + + _terminalName = random.Next().ToString(); + _columns = (uint) random.Next(); + _rows = (uint) random.Next(); + _width = (uint) random.Next(); + _height = (uint) random.Next(); + _terminalModeValues = new Dictionary(); + _bufferSize = random.Next(); + _actualException = null; + } + + private void CreateMocks() + { + _sessionMock = new Mock(MockBehavior.Strict); + _connectionInfoMock = new Mock(MockBehavior.Strict); + _channelSessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + var sequence = new MockSequence(); + + _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _connectionInfoMock.InSequence(sequence) + .Setup(p => p.Encoding) + .Returns(new UTF8Encoding()); + _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModeValues)) + .Returns(true); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendShellRequest()) + .Returns(false); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + } + + private void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _serviceFactory = new ServiceFactory(); + } + + [TestInitialize] + public void Initialize() + { + Arrange(); + Act(); + } + + private void Act() + { + try + { + _serviceFactory.CreateShellStream(_sessionMock.Object, + _terminalName, + _columns, + _rows, + _width, + _height, + _terminalModeValues, + _bufferSize); + Assert.Fail(); + } + catch (SshException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void CreateShellStreamShouldThrowSshException() + { + Assert.IsNotNull(_actualException); + Assert.IsNull(_actualException.InnerException); + Assert.AreEqual("The request to start a shell was not accepted by the server. Consult the server log for more information.", _actualException.Message); + } + + [TestMethod] + public void DisposeOnChannelSessionShouldHaveBeenInvokedOnce() + { + _channelSessionMock.Verify(p => p.Dispose(), Times.Once); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs new file mode 100644 index 00000000..da9cd6be --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Channels; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException + { + private Mock _sessionMock; + private Mock _connectionInfoMock; + private Mock _channelSessionMock; + private ServiceFactory _serviceFactory; + private string _terminalName; + private uint _columns; + private uint _rows; + private uint _width; + private uint _height; + private IDictionary _terminalModeValues; + private int _bufferSize; + private SshException _sendShellRequestException; + private SshException _actualException; + + private void SetupData() + { + var random = new Random(); + + _terminalName = random.Next().ToString(); + _columns = (uint) random.Next(); + _rows = (uint) random.Next(); + _width = (uint) random.Next(); + _height = (uint) random.Next(); + _terminalModeValues = new Dictionary(); + _bufferSize = random.Next(); + _sendShellRequestException = new SshException(); + _actualException = null; + } + + private void CreateMocks() + { + _sessionMock = new Mock(MockBehavior.Strict); + _connectionInfoMock = new Mock(MockBehavior.Strict); + _channelSessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + var sequence = new MockSequence(); + + _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _connectionInfoMock.InSequence(sequence) + .Setup(p => p.Encoding) + .Returns(new UTF8Encoding()); + _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModeValues)) + .Returns(true); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendShellRequest()) + .Throws(_sendShellRequestException); + _channelSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + } + + private void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _serviceFactory = new ServiceFactory(); + } + + [TestInitialize] + public void Initialize() + { + Arrange(); + Act(); + } + + private void Act() + { + try + { + _serviceFactory.CreateShellStream(_sessionMock.Object, + _terminalName, + _columns, + _rows, + _width, + _height, + _terminalModeValues, + _bufferSize); + Assert.Fail(); + } + catch (SshException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void CreateShellStreamShouldRethrowExceptionThrownBySendShellRequestOnChannelSession() + { + Assert.IsNotNull(_actualException); + Assert.AreSame(_sendShellRequestException, _actualException); + } + + [TestMethod] + public void DisposeOnChannelSessionShouldHaveBeenInvokedOnce() + { + _channelSessionMock.Verify(p => p.Dispose(), Times.Once); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream.cs b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_Success.cs similarity index 90% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream.cs rename to src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_Success.cs index 9789fd4b..dbd8377c 100644 --- a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream.cs +++ b/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_Success.cs @@ -9,12 +9,11 @@ using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes { [TestClass] - public class ServiceFactoryTest_CreateShellStream + public class ServiceFactoryTest_CreateShellStream_Success { private Mock _sessionMock; private Mock _connectionInfoMock; private Mock _channelSessionMock; - private MockSequence _mockSequence; private ServiceFactory _serviceFactory; private string _terminalName; private uint _columns; @@ -47,20 +46,20 @@ namespace Renci.SshNet.Tests.Classes private void SetupMocks() { - _mockSequence = new MockSequence(); + var sequence = new MockSequence(); - _sessionMock.InSequence(_mockSequence) + _sessionMock.InSequence(sequence) .Setup(p => p.ConnectionInfo) .Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_mockSequence) + _connectionInfoMock.InSequence(sequence) .Setup(p => p.Encoding) .Returns(new UTF8Encoding()); - _sessionMock.InSequence(_mockSequence) + _sessionMock.InSequence(sequence) .Setup(p => p.CreateChannelSession()) .Returns(_channelSessionMock.Object); - _channelSessionMock.InSequence(_mockSequence) + _channelSessionMock.InSequence(sequence) .Setup(p => p.Open()); - _channelSessionMock.InSequence(_mockSequence) + _channelSessionMock.InSequence(sequence) .Setup(p => p.SendPseudoTerminalRequest(_terminalName, _columns, _rows, @@ -68,7 +67,7 @@ namespace Renci.SshNet.Tests.Classes _height, _terminalModeValues)) .Returns(true); - _channelSessionMock.InSequence(_mockSequence) + _channelSessionMock.InSequence(sequence) .Setup(p => p.SendShellRequest()) .Returns(true); } diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs index d46d3798..0d8f2412 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs @@ -71,7 +71,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void WaitOnHandle_WaitHandle_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() { - WaitHandle waitHandle = null; + const WaitHandle waitHandle = null; try { @@ -88,7 +88,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() { - WaitHandle waitHandle = null; + const WaitHandle waitHandle = null; var timeout = TimeSpan.FromMinutes(5); try @@ -151,7 +151,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_WaitOnHandleShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() { - WaitHandle waitHandle = null; + const WaitHandle waitHandle = null; var session = (ISession) Session; try @@ -165,5 +165,91 @@ namespace Renci.SshNet.Tests.Classes Assert.AreEqual("waitHandle", ex.ParamName); } } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnSuccessIfWaitHandleIsSignaled() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(true); + + var result = session.TryWait(waitHandle, TimeSpan.FromMilliseconds(0)); + + Assert.AreEqual(WaitResult.Success, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnTimedOutIfWaitHandleIsNotSignaled() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, TimeSpan.FromMilliseconds(0)); + + Assert.AreEqual(WaitResult.TimedOut, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() + { + var session = (ISession) Session; + const WaitHandle waitHandle = null; + + try + { + session.TryWait(waitHandle, Session.InfiniteTimeSpan); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("waitHandle", ex.ParamName); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnSuccessIfWaitHandleIsSignaled() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(true); + Exception exception; + + var result = session.TryWait(waitHandle, TimeSpan.FromMilliseconds(0), out exception); + + Assert.AreEqual(WaitResult.Success, result); + Assert.IsNull(exception); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnTimedOutIfWaitHandleIsNotSignaled() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, TimeSpan.FromMilliseconds(0), out exception); + + Assert.AreEqual(WaitResult.TimedOut, result); + Assert.IsNull(exception); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() + { + var session = (ISession) Session; + const WaitHandle waitHandle = null; + Exception exception = null; + + try + { + session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("waitHandle", ex.ParamName); + Assert.IsNull(exception); + } + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs index 074ab059..3e42dac1 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs @@ -97,6 +97,7 @@ namespace Renci.SshNet.Tests.Classes }; ServerListener = new AsyncSocketListener(_serverEndPoint); + ServerListener.ShutdownRemoteCommunicationSocket = false; ServerListener.Connected += socket => { ServerSocket = socket; diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs index 464cf05b..c10e2799 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Net.Sockets; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -69,9 +70,8 @@ namespace Renci.SshNet.Tests.Classes Assert.AreEqual(typeof(SocketException), innerException.GetType()); var socketException = (SocketException) innerException; + Assert.AreSame(connectionException.Message, socketException.Message); Assert.AreEqual(SocketError.ConnectionReset, socketException.SocketErrorCode); - - Assert.AreSame(innerException.Message, connectionException.Message); } [TestMethod] @@ -140,7 +140,7 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void ISession_WaitOnHandleShouldThrowSshConnectionExceptionDetailingConnectionReset() + public void ISession_WaitOnHandle_WaitHandle_ShouldThrowSshConnectionExceptionDetailingConnectionReset() { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); @@ -158,12 +158,63 @@ namespace Renci.SshNet.Tests.Classes Assert.IsNotNull(innerException); Assert.AreEqual(typeof(SocketException), innerException.GetType()); - var socketException = (SocketException)ex.InnerException; - Assert.AreEqual(SocketError.ConnectionReset, socketException.SocketErrorCode); - + var socketException = (SocketException) ex.InnerException; + Assert.IsNotNull(socketException); + Assert.IsNull(socketException.InnerException); Assert.AreSame(innerException.Message, ex.Message); - + Assert.AreEqual(SocketError.ConnectionReset, socketException.SocketErrorCode); } } + + [TestMethod] + public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowSshConnectionExceptionDetailingConnectionReset() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + try + { + session.WaitOnHandle(waitHandle, Session.InfiniteTimeSpan); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.AreEqual(DisconnectReason.ConnectionLost, ex.DisconnectReason); + + var innerException = ex.InnerException; + Assert.IsNotNull(innerException); + Assert.AreEqual(typeof(SocketException), innerException.GetType()); + + var socketException = (SocketException) ex.InnerException; + Assert.IsNotNull(socketException); + Assert.IsNull(socketException.InnerException); + Assert.AreSame(innerException.Message, socketException.Message); + Assert.AreEqual(SocketError.ConnectionReset, socketException.SocketErrorCode); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Disconnected, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Disconnected, result); + Assert.IsNull(exception); + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs index cf2827cc..3aed3027 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Net.Sockets; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -92,7 +93,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_MessageListenerCompletedShouldBeSignaled() { - var session = (ISession)Session; + var session = (ISession) Session; Assert.IsNotNull(session.MessageListenerCompleted); Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); @@ -127,7 +128,7 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void ISession_WaitOnHandleShouldThrowSshConnectionExceptionDetailingBadPacket() + public void ISession_WaitOnHandle_WaitHandle_ShouldThrowSshConnectionExceptionDetailingBadPacket() { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); @@ -144,5 +145,48 @@ namespace Renci.SshNet.Tests.Classes Assert.AreEqual("Client not connected.", ex.Message); } } + + [TestMethod] + public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowSshConnectionExceptionDetailingBadPacket() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + try + { + session.WaitOnHandle(waitHandle, Session.InfiniteTimeSpan); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.AreEqual(DisconnectReason.None, ex.DisconnectReason); + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Client not connected.", ex.Message); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Disconnected, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Disconnected, result); + Assert.IsNull(exception); + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs index 4eaed4a3..df9790f9 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Net.Sockets; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -11,12 +12,20 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public class SessionTest_Connected_ServerSendsBadPacket : SessionTest_ConnectedBase { + private byte[] _packet; + + protected override void SetupData() + { + base.SetupData(); + + _packet = new byte[] {0x0a, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05}; + } + protected override void Act() { - var badPacket = new byte[] { 0x0a, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05 }; - ServerSocket.Send(badPacket, 0, badPacket.Length, SocketFlags.None); + ServerSocket.Send(_packet, 0, _packet.Length, SocketFlags.None); - // give session some time to react to bad packet + // give session some time to process packet Thread.Sleep(200); } @@ -60,7 +69,7 @@ namespace Renci.SshNet.Tests.Classes var exception = errorOccurred.Exception; Assert.IsNotNull(exception); - Assert.AreEqual(typeof (SshConnectionException), exception.GetType()); + Assert.AreEqual(typeof(SshConnectionException), exception.GetType()); var connectionException = (SshConnectionException) exception; Assert.AreEqual(DisconnectReason.ProtocolError, connectionException.DisconnectReason); @@ -109,7 +118,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_MessageListenerCompletedShouldBeSignaled() { - var session = (ISession)Session; + var session = (ISession) Session; Assert.IsNotNull(session.MessageListenerCompleted); Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); @@ -144,7 +153,7 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void ISession_WaitOnHandleShouldThrowSshConnectionExceptionDetailingBadPacket() + public void ISession_WaitOnHandle_WaitHandle_ShouldThrowSshConnectionExceptionDetailingBadPacket() { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); @@ -161,5 +170,48 @@ namespace Renci.SshNet.Tests.Classes Assert.AreEqual("Bad packet length: 168101125.", ex.Message); } } + + [TestMethod] + public void ISession_WaitOnHandleAndTimeout_WaitHandle_ShouldThrowSshConnectionExceptionDetailingBadPacket() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + try + { + session.WaitOnHandle(waitHandle, Session.InfiniteTimeSpan); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.AreEqual(DisconnectReason.ProtocolError, ex.DisconnectReason); + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Bad packet length: 168101125.", ex.Message); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Disconnected, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Disconnected, result); + Assert.IsNull(exception); + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs index 65a64878..1b887dc6 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Globalization; using System.Net.Sockets; using System.Threading; @@ -8,8 +9,10 @@ using Renci.SshNet.Messages.Transport; namespace Renci.SshNet.Tests.Classes { + [TestClass] public class SessionTest_Connected_ServerSendsDisconnectMessage : SessionTest_ConnectedBase { + private byte[] _packet; private DisconnectMessage _disconnectMessage; protected override void SetupData() @@ -17,14 +20,15 @@ namespace Renci.SshNet.Tests.Classes base.SetupData(); _disconnectMessage = new DisconnectMessage(DisconnectReason.ServiceNotAvailable, "Not today!"); + _packet = _disconnectMessage.GetPacket(8, null); } protected override void Act() { - var disconnect = _disconnectMessage.GetPacket(8, null); - ServerSocket.Send(disconnect, 4, disconnect.Length - 4, SocketFlags.None); + ServerSocket.Send(_packet, 4, _packet.Length - 4, SocketFlags.None); - Session.Disconnect(); + // give session some time to process packet + Thread.Sleep(200); } [TestMethod] @@ -110,7 +114,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_MessageListenerCompletedShouldBeSignaled() { - var session = (ISession)Session; + var session = (ISession) Session; Assert.IsNotNull(session.MessageListenerCompleted); Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); @@ -145,9 +149,9 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void ISession_WaitOnHandleShouldThrowSshConnectionExceptionDetailingDisconnectReason() + public void ISession_WaitOnHandle_WaitHandle_ShouldThrowSshConnectionExceptionDetailingDisconnectReason() { - var session = (ISession)Session; + var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); try @@ -159,8 +163,59 @@ namespace Renci.SshNet.Tests.Classes { Assert.AreEqual(DisconnectReason.ServiceNotAvailable, ex.DisconnectReason); Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "The connection was closed by the server: {0} ({1}).", _disconnectMessage.Description, _disconnectMessage.ReasonCode), ex.Message); + Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, + "The connection was closed by the server: {0} ({1}).", + _disconnectMessage.Description, + _disconnectMessage.ReasonCode), + ex.Message); } } + + [TestMethod] + public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowSshConnectionExceptionDetailingDisconnectReason() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + try + { + session.WaitOnHandle(waitHandle, Session.InfiniteTimeSpan); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.AreEqual(DisconnectReason.ServiceNotAvailable, ex.DisconnectReason); + Assert.IsNull(ex.InnerException); + Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, + "The connection was closed by the server: {0} ({1}).", + _disconnectMessage.Description, + _disconnectMessage.ReasonCode), + ex.Message); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Disconnected, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Disconnected, result); + Assert.IsNull(exception); + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs index 0985794a..d8a50a3d 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Globalization; using System.Net.Sockets; using System.Threading; @@ -143,7 +144,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_TrySendMessageShouldReturnFalse() { - var session = (ISession)Session; + var session = (ISession) Session; var actual = session.TrySendMessage(new IgnoreMessage()); @@ -151,9 +152,9 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void ISession_WaitOnHandleShouldThrowSshConnectionExceptionDetailingDisconnectReason() + public void ISession_WaitOnHandle_WaitHandle_ShouldThrowSshConnectionExceptionDetailingDisconnectReason() { - var session = (ISession)Session; + var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); try @@ -165,8 +166,36 @@ namespace Renci.SshNet.Tests.Classes { Assert.AreEqual(DisconnectReason.ServiceNotAvailable, ex.DisconnectReason); Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "The connection was closed by the server: {0} ({1}).", _disconnectMessage.Description, _disconnectMessage.ReasonCode), ex.Message); + Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, + "The connection was closed by the server: {0} ({1}).", + _disconnectMessage.Description, + _disconnectMessage.ReasonCode), + ex.Message); } } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Disconnected, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Disconnected, result); + Assert.IsNull(exception); + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs new file mode 100644 index 00000000..02e998a4 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs @@ -0,0 +1,236 @@ +using System; +using System.Diagnostics; +using System.Net.Sockets; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Tests.Classes +{ + /// + /// This test verifies the current behavior, but this is not necessarily the behavior we want. + /// We should consider treating any exception as a "disconnect" since we're effectively interrupting + /// the message loop. + /// + [TestClass] + public class SessionTest_Connected_ServerSendsUnsupportedMessageType : SessionTest_ConnectedBase + { + private byte[] _packet; + + protected override void SetupData() + { + base.SetupData(); + + _packet = CreatePacketForUnsupportedMessageType(); + } + + protected override void Act() + { + ServerSocket.Send(_packet, 0, _packet.Length, SocketFlags.None); + + // give session some time to process packet + Thread.Sleep(200); + } + + [TestMethod] + public void IsConnectedShouldReturnFalse() + { + Assert.IsFalse(Session.IsConnected); + } + + [TestMethod] + public void DisconnectShouldFinishImmediately() + { + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + Session.Disconnect(); + + stopwatch.Stop(); + Assert.IsTrue(stopwatch.ElapsedMilliseconds < 500); + } + + [TestMethod] + public void DisconnectedIsNeverRaised() + { + Assert.AreEqual(0, DisconnectedRegister.Count); + } + + [TestMethod] + public void DisconnectReceivedIsNeverRaised() + { + Assert.AreEqual(0, DisconnectReceivedRegister.Count); + } + + [TestMethod] + public void ErrorOccurredIsRaisedOnce() + { + Assert.AreEqual(1, ErrorOccurredRegister.Count); + + var errorOccurred = ErrorOccurredRegister[0]; + Assert.IsNotNull(errorOccurred); + + var exception = errorOccurred.Exception; + Assert.IsNotNull(exception); + Assert.AreEqual(typeof(SshException), exception.GetType()); + + var sshException = (SshException) exception; + Assert.IsNull(sshException.InnerException); + Assert.AreEqual("Message type 255 is not supported.", sshException.Message); + } + + [TestMethod] + public void DisposeShouldFinishImmediately() + { + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + Session.Dispose(); + + stopwatch.Stop(); + Assert.IsTrue(stopwatch.ElapsedMilliseconds < 500); + } + + [TestMethod] + public void ReceiveOnServerSocketShouldTimeout() + { + var buffer = new byte[1]; + + ServerSocket.ReceiveTimeout = 500; + try + { + ServerSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None); + Assert.Fail(); + } + catch (SocketException ex) + { + Assert.AreEqual(SocketError.TimedOut, ex.SocketErrorCode); + } + } + + [TestMethod] + public void SendMessageShouldSendMessageToServer() + { + byte[] bytesReceivedByServer = null; + ServerListener.BytesReceived += (received, socket) => bytesReceivedByServer = received; + + Session.SendMessage(new IgnoreMessage()); + + // allow "server" some time to receive message + Thread.Sleep(100); + + Assert.IsNotNull(bytesReceivedByServer); + Assert.AreEqual(24, bytesReceivedByServer.Length); + } + + [TestMethod] + public void ISession_MessageListenerCompletedShouldBeSignaled() + { + var session = (ISession) Session; + + Assert.IsNotNull(session.MessageListenerCompleted); + Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); + } + + [TestMethodAttribute] + public void ISession_SendMessageShouldSendMessageToServer() + { + var session = (ISession) Session; + + byte[] bytesReceivedByServer = null; + ServerListener.BytesReceived += (received, socket) => bytesReceivedByServer = received; + + session.SendMessage(new IgnoreMessage()); + + // allow "server" some time to receive message + Thread.Sleep(100); + + Assert.IsNotNull(bytesReceivedByServer); + Assert.AreEqual(24, bytesReceivedByServer.Length); + } + + [TestMethod] + public void ISession_TrySendMessageShouldReturnTrueAndSendMessageToServer() + { + var session = (ISession) Session; + + byte[] bytesReceivedByServer = null; + ServerListener.BytesReceived += (received, socket) => bytesReceivedByServer = received; + + var actual = session.TrySendMessage(new IgnoreMessage()); + + Assert.IsTrue(actual); + + // allow "server" some time to receive message + Thread.Sleep(100); + + Assert.IsNotNull(bytesReceivedByServer); + Assert.AreEqual(24, bytesReceivedByServer.Length); + } + + [TestMethod] + public void ISession_WaitOnHandleShouldThrowSshExceptionDetailingError() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + try + { + session.WaitOnHandle(waitHandle); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Message type 255 is not supported.", ex.Message); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnFailed() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Failed, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnFailed() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Failed, result); + Assert.IsNotNull(exception); + Assert.AreEqual(typeof(SshException), exception.GetType()); + + var sshException = exception as SshException; + Assert.IsNotNull(sshException); + Assert.IsNull(sshException.InnerException); + Assert.AreEqual("Message type 255 is not supported.", sshException.Message); + } + + private static byte[] CreatePacketForUnsupportedMessageType() + { + byte messageType = 255; + byte messageLength = 1; + byte paddingLength = 10; + var packetDataLength = (uint) messageLength + paddingLength + 1; + + var sshDataStream = new SshDataStream(4 + 1 + messageLength + paddingLength); + sshDataStream.Write(packetDataLength); + sshDataStream.WriteByte(paddingLength); + sshDataStream.WriteByte(messageType); + sshDataStream.Write(new byte[paddingLength]); + + return sshDataStream.ToArray(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs index 5aa48762..5fbfb8a2 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs @@ -146,7 +146,7 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void ISession_WaitOnHandleShouldThrowSshConnectionExceptionDetailingBadPacket() + public void ISession_WaitOnHandle_WaitHandle_ShouldThrowSshConnectionExceptionDetailingBadPacket() { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); @@ -163,5 +163,48 @@ namespace Renci.SshNet.Tests.Classes Assert.AreEqual("An established connection was aborted by the server.", ex.Message); } } + + [TestMethod] + public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowSshConnectionExceptionDetailingBadPacket() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + try + { + session.WaitOnHandle(waitHandle, Session.InfiniteTimeSpan); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.AreEqual(DisconnectReason.ConnectionLost, ex.DisconnectReason); + Assert.IsNull(ex.InnerException); + Assert.AreEqual("An established connection was aborted by the server.", ex.Message); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Disconnected, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Disconnected, result); + Assert.IsNull(exception); + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs index 72e27cd1..02d1f4c7 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Net.Sockets; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -107,7 +108,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_MessageListenerCompletedShouldBeSignaled() { - var session = (ISession)Session; + var session = (ISession) Session; Assert.IsNotNull(session.MessageListenerCompleted); Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); @@ -133,7 +134,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_TrySendMessageShouldReturnFalse() { - var session = (ISession)Session; + var session = (ISession) Session; var actual = session.TrySendMessage(new IgnoreMessage()); @@ -141,9 +142,9 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void ISession_WaitOnHandleShouldThrowSshConnectionExceptionDetailingAbortedConnection() + public void ISession_WaitOnHandle_WaitHandle_ShouldThrowSshConnectionExceptionDetailingAbortedConnection() { - var session = (ISession)Session; + var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); try @@ -157,5 +158,88 @@ namespace Renci.SshNet.Tests.Classes Assert.AreEqual("An established connection was aborted by the server.", ex.Message); } } + + [TestMethod] + public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowSshConnectionExceptionDetailingAbortedConnection() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + try + { + session.WaitOnHandle(waitHandle, Session.InfiniteTimeSpan); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("An established connection was aborted by the server.", ex.Message); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Disconnected, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() + { + var session = (ISession) Session; + const WaitHandle waitHandle = null; + var timeout = TimeSpan.FromMinutes(5); + + try + { + session.TryWait(waitHandle, timeout); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("waitHandle", ex.ParamName); + } + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected() + { + var session = (ISession) Session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Disconnected, result); + Assert.IsNull(exception); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() + { + var session = (ISession) Session; + const WaitHandle waitHandle = null; + var timeout = TimeSpan.FromMinutes(5); + Exception exception = null; + + try + { + session.TryWait(waitHandle, timeout, out exception); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("waitHandle", ex.ParamName); + } + + Assert.IsNull(exception); + } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs index 4638b698..4a8b3ded 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs @@ -81,9 +81,9 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void WaitOnHandle_WaitHandle_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() + public void WaitOnHandle_WaitOnHandle_WaitHandle_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() { - WaitHandle waitHandle = null; + const WaitHandle waitHandle = null; try { @@ -98,9 +98,9 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() + public void WaitOnHandle_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() { - WaitHandle waitHandle = null; + const WaitHandle waitHandle = null; var timeout = TimeSpan.FromMinutes(5); try @@ -115,10 +115,34 @@ namespace Renci.SshNet.Tests.Classes } } + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeout_ShouldReturnDisconnected() + { + var session = (ISession) _session; + var waitHandle = new ManualResetEvent(false); + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan); + + Assert.AreEqual(WaitResult.Disconnected, result); + } + + [TestMethod] + public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDisconnected() + { + var session = (ISession) _session; + var waitHandle = new ManualResetEvent(false); + Exception exception; + + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + + Assert.AreEqual(WaitResult.Disconnected, result); + Assert.IsNull(exception); + } + [TestMethod] public void ISession_ConnectionInfoShouldReturnConnectionInfoPassedThroughConstructor() { - var session = (ISession)_session; + var session = (ISession) _session; Assert.AreSame(_connectionInfo, session.ConnectionInfo); } @@ -134,7 +158,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_SendMessageShouldThrowShhConnectionException() { - var session = (ISession)_session; + var session = (ISession) _session; try { @@ -152,7 +176,7 @@ namespace Renci.SshNet.Tests.Classes [TestMethod] public void ISession_TrySendMessageShouldReturnFalse() { - var session = (ISession)_session; + var session = (ISession) _session; var actual = session.TrySendMessage(new IgnoreMessage()); @@ -160,10 +184,10 @@ namespace Renci.SshNet.Tests.Classes } [TestMethod] - public void ISession_WaitOnHandleShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() + public void ISession_WaitOnHandle_WaitHandle_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() { - WaitHandle waitHandle = null; - var session = (ISession)_session; + const WaitHandle waitHandle = null; + var session = (ISession) _session; try { @@ -177,6 +201,24 @@ namespace Renci.SshNet.Tests.Classes } } + [TestMethod] + public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullExceptionWhenWaitHandleIsNull() + { + const WaitHandle waitHandle = null; + var session = (ISession) _session; + + try + { + session.WaitOnHandle(waitHandle, Session.InfiniteTimeSpan); + Assert.Fail(); + } + catch (ArgumentNullException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("waitHandle", ex.ParamName); + } + } + private static ConnectionInfo CreateConnectionInfo(IPEndPoint serverEndPoint, TimeSpan timeout) { var connectionInfo = new ConnectionInfo( @@ -188,4 +230,4 @@ namespace Renci.SshNet.Tests.Classes return connectionInfo; } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ChangeDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ChangeDirectory.cs index 27fb9ad1..5c58e1fa 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ChangeDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ChangeDirectory.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; namespace Renci.SshNet.Tests.Classes @@ -8,7 +7,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs index 20fb03a4..2c6284a6 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; @@ -9,7 +8,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs index 3092426e..5e981afc 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; @@ -9,7 +8,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs index 5a9446f5..d3a615d4 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs @@ -1,5 +1,4 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; @@ -8,7 +7,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs index e2622447..85a2d7ec 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; using System.IO; @@ -10,7 +9,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs index 49bfcd27..69f90aef 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; using System.Diagnostics; @@ -11,7 +10,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFile.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFile.cs index 7515359a..e1685d09 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFile.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFile.cs @@ -1,5 +1,4 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; using System.IO; @@ -9,7 +8,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.SynchronizeDirectories.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.SynchronizeDirectories.cs index 5fc93358..2c9ddb3e 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.SynchronizeDirectories.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.SynchronizeDirectories.cs @@ -1,5 +1,4 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System.Diagnostics; using System.IO; @@ -10,7 +9,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs index d1211272..aa70e232 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using Renci.SshNet.Sftp; -using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; using System.Collections.Generic; @@ -13,7 +12,7 @@ namespace Renci.SshNet.Tests.Classes /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest : TestBase + public partial class SftpClientTest { [TestMethod] [TestCategory("Sftp")] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs index 6f4ec964..3edd7c7b 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs @@ -16,6 +16,140 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public partial class SftpClientTest : TestBase { + private Random _random; + + [TestInitialize] + public void SetUp() + { + _random = new Random(); + } + + [TestMethod] + public void OperationTimeout_Default() + { + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new SftpClient(connectionInfo); + + var actual = target.OperationTimeout; + + Assert.AreEqual(TimeSpan.FromMilliseconds(-1), actual); + } + + [TestMethod] + public void OperationTimeout_InsideLimits() + { + var operationTimeout = TimeSpan.FromMilliseconds(_random.Next(0, int.MaxValue - 1)); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new SftpClient(connectionInfo) + { + OperationTimeout = operationTimeout + }; + + var actual = target.OperationTimeout; + + Assert.AreEqual(operationTimeout, actual); + } + + [TestMethod] + public void OperationTimeout_LowerLimit() + { + var operationTimeout = TimeSpan.FromMilliseconds(-1); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new SftpClient(connectionInfo) + { + OperationTimeout = operationTimeout + }; + + var actual = target.OperationTimeout; + + Assert.AreEqual(operationTimeout, actual); + } + + [TestMethod] + public void OperationTimeout_UpperLimit() + { + var operationTimeout = TimeSpan.FromMilliseconds(int.MaxValue); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new SftpClient(connectionInfo) + { + OperationTimeout = operationTimeout + }; + + var actual = target.OperationTimeout; + + Assert.AreEqual(operationTimeout, actual); + } + + [TestMethod] + public void OperationTimeout_LessThanLowerLimit() + { + var operationTimeout = TimeSpan.FromMilliseconds(-2); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new SftpClient(connectionInfo); + + try + { + target.OperationTimeout = operationTimeout; + } + catch (ArgumentOutOfRangeException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive." + Environment.NewLine + "Parameter name: " + ex.ParamName, ex.Message); + Assert.AreEqual("value", ex.ParamName); + } + } + + [TestMethod] + public void OperationTimeout_GreaterThanLowerLimit() + { + var operationTimeout = TimeSpan.FromMilliseconds(int.MaxValue).Add(TimeSpan.FromMilliseconds(1)); + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new SftpClient(connectionInfo); + + try + { + target.OperationTimeout = operationTimeout; + } + catch (ArgumentOutOfRangeException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive." + Environment.NewLine + "Parameter name: " + ex.ParamName, ex.Message); + Assert.AreEqual("value", ex.ParamName); + } + } + + [TestMethod] + public void OperationTimeout_Disposed() + { + var connectionInfo = new PasswordConnectionInfo("host", 22, "admin", "pwd"); + var target = new SftpClient(connectionInfo); + target.Dispose(); + + // getter + try + { + var actual = target.OperationTimeout; + Assert.Fail("Should have failed, but returned: " + actual); + } + catch (ObjectDisposedException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(typeof(SftpClient).FullName, ex.ObjectName); + } + + // setter + try + { + target.OperationTimeout = TimeSpan.FromMilliseconds(5); + Assert.Fail(); + } + catch (ObjectDisposedException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual(typeof(SftpClient).FullName, ex.ObjectName); + } + } + /// ///A test for SftpClient Constructor /// diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs new file mode 100644 index 00000000..afbc247b --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs @@ -0,0 +1,145 @@ +using System; +using System.Reflection; +using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Common; +using Renci.SshNet.Security; +using Renci.SshNet.Sftp; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class SftpClientTest_Connect_SftpSessionConnectFailure + { + private Mock _serviceFactoryMock; + private Mock _sessionMock; + private Mock _sftpResponseFactoryMock; + private Mock _sftpSessionMock; + private ConnectionInfo _connectionInfo; + private ApplicationException _sftpSessionConnectionException; + private SftpClient _sftpClient; + private ApplicationException _actualException; + + [TestInitialize] + public void Setup() + { + Arrange(); + Act(); + } + + private void Arrange() + { + SetupData(); + CreateMocks(); + SetupMocks(); + + _sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object); + } + + private void SetupData() + { + _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); + _sftpSessionConnectionException = new ApplicationException(); + } + + private void CreateMocks() + { + _serviceFactoryMock = new Mock(MockBehavior.Strict); + _sessionMock = new Mock(MockBehavior.Strict); + _sftpResponseFactoryMock = new Mock(MockBehavior.Strict); + _sftpSessionMock = new Mock(MockBehavior.Strict); + } + + private void SetupMocks() + { + var sequence = new MockSequence(); + + _serviceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo)) + .Returns(_sessionMock.Object); + _sessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _serviceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpResponseFactory()) + .Returns(_sftpResponseFactoryMock.Object); + _serviceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpSession(_sessionMock.Object, -1, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object)) + .Returns(_sftpSessionMock.Object); + _sftpSessionMock.InSequence(sequence) + .Setup(p => p.Connect()) + .Throws(_sftpSessionConnectionException); + _sftpSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _sessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + } + + private void Act() + { + try + { + _sftpClient.Connect(); + Assert.Fail(); + } + catch (ApplicationException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void ConnectShouldHaveThrownApplicationException() + { + Assert.IsNotNull(_actualException); + Assert.AreSame(_sftpSessionConnectionException, _actualException); + } + + [TestMethod] + public void SessionShouldBeNull() + { + Assert.IsNull(_sftpClient.Session); + } + + [TestMethod] + public void SftpSessionShouldBeNull() + { + Assert.IsNull(_sftpClient.SftpSession); + } + + [TestMethod] + public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnSftpClient() + { + var errorOccurredSignalCount = 0; + + _sftpClient.ErrorOccurred += (sender, args) => Interlocked.Increment(ref errorOccurredSignalCount); + + _sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); + + Assert.AreEqual(0, errorOccurredSignalCount); + } + + [TestMethod] + public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOnSftpClient() + { + var hostKeyReceivedSignalCount = 0; + + _sftpClient.HostKeyReceived += (sender, args) => Interlocked.Increment(ref hostKeyReceivedSignalCount); + + _sessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); + + Assert.AreEqual(0, hostKeyReceivedSignalCount); + } + + private static KeyHostAlgorithm GetKeyHostAlgorithm() + { + var executingAssembly = Assembly.GetExecutingAssembly(); + + using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + { + var privateKey = new PrivateKeyFile(s); + return (KeyHostAlgorithm)privateKey.HostKey; + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/ShellStream.cs b/src/Renci.SshNet.Tests/Classes/ShellStream.cs deleted file mode 100644 index f5d401af..00000000 --- a/src/Renci.SshNet.Tests/Classes/ShellStream.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes -{ - /// - /// Contains operation for working with SSH Shell. - /// - [TestClass] - public class ShellStreamTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest.NET40.cs b/src/Renci.SshNet.Tests/Classes/SshCommandTest.NET40.cs deleted file mode 100644 index 589c6881..00000000 --- a/src/Renci.SshNet.Tests/Classes/SshCommandTest.NET40.cs +++ /dev/null @@ -1,100 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Properties; -using System; -using System.Diagnostics; -using System.Threading.Tasks; - -namespace Renci.SshNet.Tests.Classes -{ - public partial class SshCommandTest - { - - public void Test_MultipleThread_Example_MultipleConnections() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - try - { - #region Example SshCommand RunCommand Parallel - System.Threading.Tasks.Parallel.For(0, 10000, - () => - { - var client = new SshClient(host, username, password); - client.Connect(); - return client; - }, - (int counter, ParallelLoopState pls, SshClient client) => - { - var result = client.RunCommand("echo 123"); - Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); - return client; - }, - (SshClient client) => - { - client.Disconnect(); - client.Dispose(); - } - ); - #endregion - - } - catch (Exception exp) - { - Assert.Fail(exp.ToString()); - } - } - - //[TestMethod] - public void Test_MultipleThread_10000_MultipleConnections() - { - try - { - System.Threading.Tasks.Parallel.For(0, 10000, - () => - { - var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD); - client.Connect(); - return client; - }, - (int counter, ParallelLoopState pls, SshClient client) => - { - var result = ExecuteTestCommand(client); - Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); - Assert.IsTrue(result); - return client; - }, - (SshClient client) => - { - client.Disconnect(); - client.Dispose(); - } - ); - } - catch (Exception exp) - { - Assert.Fail(exp.ToString()); - } - } - - //[TestMethod] - public void Test_MultipleThread_10000_MultipleSessions() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - System.Threading.Tasks.Parallel.For(0, 10000, - (counter) => - { - var result = ExecuteTestCommand(client); - Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); - Assert.IsTrue(result); - } - ); - - client.Disconnect(); - } - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs index c1979ce3..cfd68b07 100644 --- a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs @@ -6,6 +6,10 @@ using System; using System.IO; using System.Text; using System.Threading; +#if FEATURE_TPL +using System.Diagnostics; +using System.Threading.Tasks; +#endif // FEATURE_TPL namespace Renci.SshNet.Tests.Classes { @@ -622,6 +626,100 @@ namespace Renci.SshNet.Tests.Classes Assert.Inconclusive("Verify the correctness of this test method."); } +#if FEATURE_TPL + [TestMethod] + [TestCategory("integration")] + public void Test_MultipleThread_Example_MultipleConnections() + { + var host = Resources.HOST; + var username = Resources.USERNAME; + var password = Resources.PASSWORD; + + try + { +#region Example SshCommand RunCommand Parallel + System.Threading.Tasks.Parallel.For(0, 10000, + () => + { + var client = new SshClient(host, username, password); + client.Connect(); + return client; + }, + (int counter, ParallelLoopState pls, SshClient client) => + { + var result = client.RunCommand("echo 123"); + Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); + return client; + }, + (SshClient client) => + { + client.Disconnect(); + client.Dispose(); + } + ); +#endregion + + } + catch (Exception exp) + { + Assert.Fail(exp.ToString()); + } + } + + [TestMethod] + [TestCategory("integration")] + public void Test_MultipleThread_10000_MultipleConnections() + { + try + { + System.Threading.Tasks.Parallel.For(0, 10000, + () => + { + var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD); + client.Connect(); + return client; + }, + (int counter, ParallelLoopState pls, SshClient client) => + { + var result = ExecuteTestCommand(client); + Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); + Assert.IsTrue(result); + return client; + }, + (SshClient client) => + { + client.Disconnect(); + client.Dispose(); + } + ); + } + catch (Exception exp) + { + Assert.Fail(exp.ToString()); + } + } + + [TestMethod] + [TestCategory("integration")] + public void Test_MultipleThread_10000_MultipleSessions() + { + using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + client.Connect(); + System.Threading.Tasks.Parallel.For(0, 10000, + (counter) => + { + var result = ExecuteTestCommand(client); + Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); + Assert.IsTrue(result); + } + ); + + client.Disconnect(); + } + } +#endif // FEATURE_TPL + private static bool ExecuteTestCommand(SshClient s) { var testValue = Guid.NewGuid().ToString(); diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs index 24e868cb..a8fcb4dd 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Renci.SshNet.Channels; @@ -46,10 +45,9 @@ namespace Renci.SshNet.Tests.Classes _channelMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); _channelMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(true); - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); _subsystemSession.Connect(); diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_SendSubsystemRequestFails.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_SendSubsystemRequestFails.cs new file mode 100644 index 00000000..c3639a40 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_SendSubsystemRequestFails.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Channels; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class SubsystemSession_Connect_SendSubsystemRequestFails + { + private Mock _sessionMock; + private Mock _channelMock; + private string _subsystemName; + private SubsystemSessionStub _subsystemSession; + private int _operationTimeout; + private IList _disconnectedRegister; + private IList _errorOccurredRegister; + private SshException _actualException; + private MockSequence _sequence; + + [TestInitialize] + public void Setup() + { + Arrange(); + Act(); + } + + protected void Arrange() + { + var random = new Random(); + _subsystemName = random.Next().ToString(CultureInfo.InvariantCulture); + _operationTimeout = 30000; + _disconnectedRegister = new List(); + _errorOccurredRegister = new List(); + + _sessionMock = new Mock(MockBehavior.Strict); + _channelMock = new Mock(MockBehavior.Strict); + + _sequence = new MockSequence(); + _sessionMock.InSequence(_sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); + _channelMock.InSequence(_sequence).Setup(p => p.Open()); + _channelMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(false); + _channelMock.InSequence(_sequence).Setup(p => p.Dispose()); + + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); + _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); + _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); + } + + protected void Act() + { + try + { + _subsystemSession.Connect(); + Assert.Fail(); + } + catch (SshException ex) + { + _actualException = ex; + } + } + + [TestMethod] + public void ConnectShouldHaveThrownSshException() + { + Assert.IsNotNull(_actualException); + Assert.IsNull(_actualException.InnerException); + Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Subsystem '{0}' could not be executed.", _subsystemName), _actualException.Message); + } + + [TestMethod] + public void ChannelShouldBeNull() + { + Assert.IsNull(_subsystemSession.Channel); + } + + [TestMethod] + public void DisconnectHasNeverFired() + { + Assert.AreEqual(0, _disconnectedRegister.Count); + } + + [TestMethod] + public void ErrorOccurredHasNeverFired() + { + Assert.AreEqual(0, _errorOccurredRegister.Count); + } + + [TestMethod] + public void IsOpenShouldReturnFalse() + { + Assert.IsFalse(_subsystemSession.IsOpen); + } + + [TestMethod] + public void DisposeOnChannelShouldBeInvokedOnce() + { + _channelMock.Verify(p => p.Dispose(), Times.Once); + } + + [TestMethod] + public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnSubsystemSession() + { + _sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); + + Assert.AreEqual(0, _errorOccurredRegister.Count); + } + + [TestMethod] + public void DisconnectedOnSessionShouldNoLongerBeSignaledViaDisconnectedOnSubsystemSession() + { + _sessionMock.Raise(p => p.Disconnected += null, new EventArgs()); + + Assert.AreEqual(0, _disconnectedRegister.Count); + } + } +} diff --git a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs index 41c04806..dbb6128b 100644 --- a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs +++ b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs @@ -27,8 +27,20 @@ namespace Renci.SshNet.Tests.Common { _endPoint = endPoint; _acceptCallbackDone = new ManualResetEvent(false); + ShutdownRemoteCommunicationSocket = true; } + /// + /// Gets a value indicating whether the is invoked on the + /// that is used to handle the communication with the remote host, when the remote host has closed the connection. + /// + /// + /// to invoke on the that is used + /// to handle the communication with the remote host, when the remote host has closed the connection; otherwise, + /// . The default is . + /// + public bool ShutdownRemoteCommunicationSocket { get; set; } + public void Start() { _listener = new Socket(_endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); @@ -127,7 +139,12 @@ namespace Renci.SshNet.Tests.Common else { SignalDisconnected(handler); - handler.Shutdown(SocketShutdown.Send); + + if (ShutdownRemoteCommunicationSocket) + { + handler.Shutdown(SocketShutdown.Both); + handler.Close(); + } } } diff --git a/src/Renci.SshNet.Tests/Common/TestBase.cs b/src/Renci.SshNet.Tests/Common/TestBase.cs index 345fd1bd..4ae86fb4 100644 --- a/src/Renci.SshNet.Tests/Common/TestBase.cs +++ b/src/Renci.SshNet.Tests/Common/TestBase.cs @@ -8,17 +8,18 @@ namespace Renci.SshNet.Tests.Common [TestClass] public abstract class TestBase { - private static Assembly _executingAssembly = Assembly.GetExecutingAssembly(); - [TestInitialize()] + private static readonly Assembly ExecutingAssembly = Assembly.GetExecutingAssembly(); + + [TestInitialize] public void Init() { - this.OnInit(); + OnInit(); } - [TestCleanup()] + [TestCleanup] public void Cleanup() { - this.OnCleanup(); + OnCleanup(); } protected virtual void OnInit() @@ -50,7 +51,7 @@ namespace Renci.SshNet.Tests.Common protected Stream GetData(string name) { - return _executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", name)); + return ExecutingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", name)); } } } \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt new file mode 100644 index 00000000..f0af5ba7 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,54D46F498C989115AAE14FEA21E3AF11 + +IQdFnndcbzz10d7YQIgEE1TzuzJrm7uYJr4Hvdfz/FshVxMRqxqaqtEgo2vAHHik +BOcPkm+84ERlTNPslcJqLSkKzCdxb7Rz5hfwHuN3Y6Lf01qGakDlzAUEjEyDor+4 +zQtAne+f+gRUJnBvLLoVhH4xdeQFC55GECNUFQpEmos= +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA.txt new file mode 100644 index 00000000..13ac9fb4 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA.txt @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIEdqaFKgJBIibVjyUh1v7Y35LwIQJrocdTaYFLwl7iB0oAoGCCqGSM49 +AwEHoUQDQgAEQD5MO/n9yqSDTszwzVpApLx5SQFecE5ZfDkgxqVdHQecm1BAPozZ +4eKGNhKn72hT79mLlp9HXX+oNEcuVT83Hw== +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt new file mode 100644 index 00000000..00072ce2 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt @@ -0,0 +1,9 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,1D64653C5E18C2AACB0B17E3FE43C219 + +lCtRmcvKSeIACwqTtsf/ei1brtCZ386rsk/j7bSXdkZBpvzcmzbeo6w6CYm206Km +hV9TMl2dIO/I1/ov5/2VIR3ZkaElyDOJD/+Be0e3aus4EZj1H1YM/Dv+4QJId+is +Cw4ycWjfudYPPejGdiyjzt5qjaIJwrrEvGtMg7sWVAqDpjcAjS9KuaCu5nOgdItL +s7oHuz+DTGdJQNfUHAlUnz1JaMRWzpP0MwtxdcaRY+w= +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt new file mode 100644 index 00000000..f2d658ea --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt @@ -0,0 +1,6 @@ +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDCQawHdHLR7NvKa2vPV0sVkbzOE8c0enp95iEysGcGV66RXE1EH//nh +gu5UzeTR4KigBwYFK4EEACKhZANiAAQUk4rVvoOPI1hQzWpNx09Uo6qG+srGcbvB +q15eFK0GnK/T0UBKxdbZ2+//KAYI6SeDHM9t3ORF1aX5EpjTEBI4d7ZY/lV9jX6M +nJ4XuGteJselM2iMmy+p9ZYw83BYB1Y= +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt new file mode 100644 index 00000000..381b30be --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt @@ -0,0 +1,10 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,F995028237EBD79C928530CC6C3E957F + +wT+iajbte4MnpCipVy/7W9t2I8OgwbMjNBw9PB5xmXR1NQX+yWa81DXMTgjHi8++ +6tp+Vlftkr7mY1yvZCVo1Sy4VgcvZeMhtpVKtvYdMCmHJC6gaDOTYX3yee8DJ4FL +fG+IQz0wFyZZ26NFrHiwbufW9z6pXhGNCQZK0KLbFxI9iKwVA0llc7uzTEcmBBpn +0/Snp0CVvX+i6AP9Xj0bBdrFCsvcoT+ZHzS8YWJUfu3m6cpAJksCAy0PXR3ifvus +edTfDpkMxd4/b+DtPB6SMekIAjnQyzbyaTwJCujm8iU= +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt b/src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt new file mode 100644 index 00000000..31abe917 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt @@ -0,0 +1,7 @@ +-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIBn2DAme7AU8sCA+/sd6s3c2FNW26IiPvulGd3FC8k5q+fjBZ5LUWR +iJMGrsf2rJLO8hXMGJYoF9tjZEGaabQ8KVagBwYFK4EEACOhgYkDgYYABABrpVjs +ANqcvqMUo1wo0I1uVCXQ6xrauy4iU86FiOwFmkYRrle4w3oYdRJwniC3TwGMuBuM +PMIoCTXr0UtUzn1vkQESNR/J/jAxVseLlVe+KDfZHKvsvk2+O4XaSa1qMfLwN3sp +wlj08+ylKjlO6V3g0hbz4ZaSVwuiRS7Xsv8W2MV6rg== +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.Encrypted.txt new file mode 100644 index 00000000..50b4d968 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.Encrypted.txt @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABBg +HWh+J0IG6OfYxD74SoT9AAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGFd +yflleGqSPOhgSYZf7ZQFlG0zEL9VDGC69UbtaaByAAAAoDLm8u8wFwlqjzZRfVxj +wzGTYFJFtfkHRqfFBE4xKgknHNRbCT1OQb7rgE7nZbUXIlb1NCTZLbXti9AYNZpz +ycvPD4Dc6lB03b8pNHoFVSkrCwxrWB5bKtIM4OZNcDK1lZDBEWE2aZXf9puRHbu3 +ccrK/F5GjRi2pUa8qnfqThN1mNPZwFTx4oSKeRaUMdeHBrNwDtaxq32A6Q4KHoYO +KPM= +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.txt new file mode 100644 index 00000000..84811f65 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.txt @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz +c2gtZWQyNTUxOQAAACANCWZw0K8UGXDQC32WBuyzwFtTGBBr1VuZ43uzpTBjIgAA +AKBATgCiQE4AogAAAAtzc2gtZWQyNTUxOQAAACANCWZw0K8UGXDQC32WBuyzwFtT +GBBr1VuZ43uzpTBjIgAAAEAAzBF1MPUxrs+ycpJh28zzo/F3m6WcKO+orsSbR5Lw +KQ0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7OlMGMiAAAAFGVkMjU1MTkta2V5 +LTIwMTgxMTI3AQIDBAUGBwgJ +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.Tests/Properties/AssemblyInfo.cs b/src/Renci.SshNet.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 443203d0..00000000 --- a/src/Renci.SshNet.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("SSH.NET Tests .NET 4.0")] -[assembly: Guid("defb66b2-a4b9-40ca-b205-2183d84b7323")] diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 61df8cdc..d7ee81e9 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -1,701 +1,121 @@ - - - - Debug - AnyCPU - 2.0 - {C45379B9-17B1-4E89-BC2E-6D41726413E8} - Library - Properties - Renci.SshNet.Tests - Renci.SshNet.Tests - v4.0 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - true - full - false - bin\Debug\ - TRACE;DEBUG;FEATURE_THREAD_COUNTDOWNEVENT - prompt - 4 - 5 - - - pdbonly - true - bin\Release\ - TRACE;FEATURE_THREAD_COUNTDOWNEVENT - prompt - 0 - - - - - + true - - ..\Renci.SshNet.snk + + + net35;net40;netcoreapp2.1;netcoreapp2.2 + + + net35;net40;netcoreapp2.1;netcoreapp2.2;netcoreapp3.0 + + + + + + + FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL + + + FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL + + + FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL + + + FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL + - - - ..\..\packages\Moq.4.2.1409.1722\lib\net40\Moq.dll - - - - 3.5 - - - - - - - - - False - - - - - Classes\Abstractions\CryptoAbstraction_GenerateRandom.cs - - - Classes\Abstractions\DnsAbstraction_GetHostAddresses.cs - - - Classes\Abstractions\FileSystemAbstraction_EnumerateFiles.cs - - - Classes\Abstractions\ThreadAbstraction_ExecuteThread.cs - - - Classes\ForwardedPortStatusTest_Started.cs - - - Classes\ForwardedPortStatusTest_Starting.cs - - - Classes\ForwardedPortStatusTest_Stopped.cs - - - Classes\ForwardedPortStatusTest_Stopping.cs - - - Classes\SshMessageFactoryTest.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Resources.resx - True - True - - - - Properties\CommonAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - - - - + + + + + + + + - + + + + - - - - - - - Renci.SshNet.snk - - - - - - - - - - + + + + + + + + + + + $(MSBuildProgramFiles32)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + $(MSTestV1UnitTestFrameworkAssemblyCandidate) + + $(MSBuildProgramFiles32)\Microsoft Visual Studio\2017\Professional\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + $(MSTestV1UnitTestFrameworkAssemblyCandidate) + + $(MSBuildProgramFiles32)\Microsoft Visual Studio\2017\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + $(MSTestV1UnitTestFrameworkAssemblyCandidate) + + + + + $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + $(MSTestV1UnitTestFrameworkAssemblyCandidate) + + $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Professional\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + $(MSTestV1UnitTestFrameworkAssemblyCandidate) + + $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + $(MSTestV1UnitTestFrameworkAssemblyCandidate) + + $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Preview\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll + $(MSTestV1UnitTestFrameworkAssemblyCandidate) + + + + + $(MSTestV1UnitTestFrameworkAssembly) + + + + + + $(MSTestV1UnitTestFrameworkAssembly) + + + + + + + + 2.1.0 + + + + + + + + 2.1.0 + + + + + + + + 2.1.0 + + - - {2f5f8c90-0bd1-424f-997c-7bc6280919d1} - Renci.SshNet - + - - - \ No newline at end of file + diff --git a/src/Renci.SshNet.Tests/authorized_keys b/src/Renci.SshNet.Tests/authorized_keys deleted file mode 100644 index 59efb8b0..00000000 --- a/src/Renci.SshNet.Tests/authorized_keys +++ /dev/null @@ -1,4 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA8ZsD8jgH7ySXnd4dprEFFkJ+zs1ne81E8febjR8hekiKrc+D9GjeEykchy0PsrsBrf2F8J3GtLNISVerkl+EnVh1E0pi9Vllc1vcpQHvBeNPG/jl9Dnum/DcaaMKLot+ARXjBuMX/xJVfnlgkvfpBvoq4QzQ6E27rOMbcPlvrN7KeYbaorsTpDMUraHX5u99P1evvw7sOuNl3lc9YpIgmjHT6dWUGTqBx9T2SEKXBRVk2NNbd2UctQkr5BJn1gGehA+1KYS30FMiCSN8F8ZOlpYj1+K6xzs0srq1z30LailIyy7QmYp739BJlOF3cVywdcFXGre35H2cJylcNV2e+Q== rsa_key_without_pass -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuD5SKSM3RAO/h8z9x1RB9bhLbBkophrYVHYG8MdNwQc/iXb4IZ7PlKR2ZQovIYzHdMI5zGEuOsxJnLjxoV7NSUHlHEoGbRYX72rR3S3ZORUArLTJ9TwGZhR4TZRztJto7l4M5LGDUy4YMNN9kpcyT/aqv8v3ZcTB0UthZDXUHrrmrlktPAC+JagUjhESbtq+FAuiSUWd9/SXnAmLya7LkWANw2ScMpeSyXmEvLD+X0eapNtuwXltjRW4PoKS5fWMhiXnT61NXmgXDccrUHjWrOa1oeNjmhOuIGaDpoRtkBH8lCFQdRePgvcBIRnU9D7sjuBjZUAPqin+fDll2ISy2w== rsa_key_with_pass (tester) -ssh-dss AAAAB3NzaC1kc3MAAACBAN1CuvAa+SfAP6lv0am/+8PGPzKoVSDRxS4L+2SObe76VCPzpHB8DxEk5X44/ga2+z3M5KzGK6CKegH+4SJP7qNse/K8l4mnZ+wNYvH+1VFfGmLw3B5t9vjnlHTBVVl2qcUqwBkutABPnz0RS0uDJUAVBtQ/kXPqnHwfwAbSqXJtAAAAFQC5+1DsZ2xUe3w32ZKtj3O2QlXoKQAAAIEA1Ep/297O7PVoZSdQZYgsc7T1KJscrbnl+Su7j//O8Jt1rBZJk6hT68yemUtSE1pUyhLJgT9Ng5m+9sb1S0++vzBkZ00+Km8hcgHGWmv4UfSadLHSqVpHLc8SgNECbDqaxELNVhXe9nxlMRR236mG6u76mfRb0S6DMIweKRVWEkwAAACASHB5nNlWhpqvungn+otYyGKoVoATkRdRfSiUo3fb0mJLTmxrEhEH4UOFA/UFdQ0TYXXW0wRX/amynT4iTEXAx0FjxUNK5ryxloeoXiXEH4FK7D8RtJO11UsaRrN+nqWiSTVAehl6tzoMCPargGcWeFlAZZnPGN76OD9J1GiKZj8= dsa_key_without_pass -ssh-dss AAAAB3NzaC1kc3MAAACBAJU0pDZQHna2HaaGHsL1D0pZlnh/tM7EYAcGQcHqNRUVPLXbcy94ZdF0R9V1qCA9u7at/EEqdtfseXLbjbxLxccJM6sjCFn7GKNvc6N7w7PpAeUbZBdHdszOkNolyqGs+/45Oj0tGHLTLk2rRyOTeBagpJS1PlZQCnVbT8o/gjtvAAAAFQDUe90v8pdAZhtO84F19cRUMrWoqQAAAIBDZwBGOxMRy7nKc0f6aWNh0JX5NnTCuEiXmD6BmBV/2k9J0VJYgiTZw4mzmF4VzrV7aI+XCQz52N8od7cp76O1DXweO0cIqLkT2xLGuoBtUSpHiSqRnHUsL9BDI8s3bQ5fSCb0IwF6d90tArDX/d9mzYqx+Vvp+4ajSiSiyzaGUQAAAIB3vFz1T9jGAZ3hBPkFQ9zl0gniF2EQ/w1UlnHb7ABUyBigBxtnTN0+7yfNwFVfQS/rKxhT6muzYgQB3e1masvv0ky/vstnh5n7EZmLDLEWwIfRefbPmyfLCKK+23QmMZgPg/SGuLmwagw711ReiLyBqn5YiP8quXcDdnReJCJPig== dsa_key_with_pass (tester) \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/packages.config b/src/Renci.SshNet.Tests/packages.config deleted file mode 100644 index f6c56582..00000000 --- a/src/Renci.SshNet.Tests/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj b/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj index 87316c9d..34da9d63 100644 --- a/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj +++ b/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj @@ -23,7 +23,7 @@ full false bin\Debug\ - TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII + TRACE;DEBUG;FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII prompt 4 bin\Debug\Renci.SshNet.xml @@ -34,7 +34,7 @@ pdbonly true bin\Release\ - TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII + TRACE;FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII prompt 4 bin\Release\Renci.SshNet.xml @@ -44,7 +44,7 @@ x86 true bin\x86\Debug\ - TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII + TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII ;2008 full x86 @@ -54,7 +54,7 @@ x86 bin\x86\Release\ - TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII + TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII true ;2008 pdbonly @@ -66,7 +66,7 @@ ARM true bin\ARM\Debug\ - TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII + TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII ;2008 full ARM @@ -76,7 +76,7 @@ ARM bin\ARM\Release\ - TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII + TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII true ;2008 pdbonly @@ -88,7 +88,7 @@ x64 true bin\x64\Debug\ - TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII + TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII ;2008 full x64 @@ -98,7 +98,7 @@ x64 bin\x64\Release\ - TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII + TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII true ;2008 pdbonly @@ -666,12 +666,414 @@ Security\Algorithm.cs + + Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs + + + Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs + + + Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\util\Pack.cs + + + Security\Cryptography\BouncyCastle\math\BigInteger.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\LongArray.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs + + + Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\PrimeField.cs + + + Security\Cryptography\BouncyCastle\math\raw\Mod.cs + + + Security\Cryptography\BouncyCastle\math\raw\Nat.cs + + + Security\Cryptography\BouncyCastle\security\DigestUtilities.cs + + + Security\Cryptography\BouncyCastle\security\SecureRandom.cs + + + Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs + + + Security\Cryptography\BouncyCastle\util\Arrays.cs + + + Security\Cryptography\BouncyCastle\util\BigIntegers.cs + + + Security\Cryptography\BouncyCastle\util\encoders\Hex.cs + + + Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs + + + Security\Cryptography\BouncyCastle\util\Enums.cs + + + Security\Cryptography\BouncyCastle\util\IMemoable.cs + + + Security\Cryptography\BouncyCastle\util\Integers.cs + + + Security\Cryptography\BouncyCastle\util\MemoableResetException.cs + + + Security\Cryptography\BouncyCastle\util\Times.cs + Security\CertificateHostAlgorithm.cs + + Security\Cryptography\Chaos.NaCl\CryptoBytes.cs + + + Security\Cryptography\Chaos.NaCl\Ed25519.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array16.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array8.cs + + + Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs + + + Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs + + + Security\Cryptography\Chaos.NaCl\Sha512.cs + Security\Cryptography\AsymmetricCipher.cs + + Security\Cryptography\Bcrypt.cs + Security\Cryptography\BlockCipher.cs @@ -741,6 +1143,12 @@ Security\Cryptography\DsaKey.cs + + Security\Cryptography\ED25519DigitalSignature.cs + + + Security\Cryptography\ED25519Key.cs + Security\Cryptography\HMACMD5.cs @@ -759,6 +1167,12 @@ Security\Cryptography\Key.cs + + Security\Cryptography\EcdsaDigitalSignature.cs + + + Security\Cryptography\EcdsaKey.cs + Security\Cryptography\RsaDigitalSignature.cs @@ -804,6 +1218,24 @@ Security\KeyExchangeDiffieHellmanGroupSha1.cs + + Security\KeyExchangeEC.cs + + + Security\KeyExchangeECCurve25519.cs + + + Security\KeyExchangeECDH.cs + + + Security\KeyExchangeECDH256.cs + + + Security\KeyExchangeECDH384.cs + + + Security\KeyExchangeECDH521.cs + Security\KeyHostAlgorithm.cs diff --git a/src/Renci.SshNet.VS2012.sln b/src/Renci.SshNet.VS2012.sln index 93b4c3e8..a80b1908 100644 --- a/src/Renci.SshNet.VS2012.sln +++ b/src/Renci.SshNet.VS2012.sln @@ -1,16 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet", "Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" -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}") = "Renci.SshNet.Silverlight", "Renci.SshNet.Silverlight\Renci.SshNet.Silverlight.csproj", "{77C294BB-1DC2-49DC-BE16-963F8F22794D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.NET35", "Renci.SshNet.NET35\Renci.SshNet.NET35.csproj", "{DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Tests.NET35", "Renci.SshNet.Tests.NET35\Renci.SshNet.Tests.NET35.csproj", "{007CE8B3-7827-4AD0-AACD-860505638ABE}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.WindowsPhone", "Renci.SshNet.WindowsPhone\Renci.SshNet.WindowsPhone.csproj", "{3AD3EDF0-702E-4A91-8735-DCE4659AA54C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Silverlight5", "Renci.SshNet.Silverlight5\Renci.SshNet.Silverlight5.csproj", "{E367F791-C1EC-4181-912A-2943CAC6B3BC}" @@ -19,7 +11,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.WindowsPhone8" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" ProjectSection(SolutionItems) = preProject - ..\build\build.cmd = ..\build\build.cmd ..\build\build.proj = ..\build\build.proj EndProjectSection EndProject @@ -50,34 +41,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|ARM.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x64.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.Build.0 = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|ARM.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x64.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x86.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|ARM.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x64.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x86.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.Build.0 = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|ARM.ActiveCfg = Release|Any CPU - {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|x64.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU {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|ARM.ActiveCfg = Debug|Any CPU @@ -92,34 +55,6 @@ Global {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Mixed Platforms.Build.0 = Release|Any CPU {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|x64.ActiveCfg = Release|Any CPU {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|x86.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|ARM.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|x64.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|x86.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Any CPU.Build.0 = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|ARM.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|x64.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|x86.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|ARM.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|x64.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|x86.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|Any CPU.Build.0 = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|ARM.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|x64.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|x86.ActiveCfg = Release|Any CPU {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|Any CPU.Build.0 = Debug|Any CPU {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|ARM.ActiveCfg = Debug|Any CPU diff --git a/src/Renci.SshNet.VS2015.sln b/src/Renci.SshNet.VS2015.sln index 8171be89..81fa7155 100644 --- a/src/Renci.SshNet.VS2015.sln +++ b/src/Renci.SshNet.VS2015.sln @@ -1,11 +1,10 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" ProjectSection(SolutionItems) = preProject - ..\build\build.cmd = ..\build\build.cmd ..\build\build.proj = ..\build\build.proj EndProjectSection EndProject @@ -19,14 +18,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandcastle", "sandcastle", ..\build\sandcastle\SSH.NET.shfbproj = ..\build\sandcastle\SSH.NET.shfbproj EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet", "Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" -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}") = "Renci.SshNet.NET35", "Renci.SshNet.NET35\Renci.SshNet.NET35.csproj", "{DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Tests.NET35", "Renci.SshNet.Tests.NET35\Renci.SshNet.Tests.NET35.csproj", "{007CE8B3-7827-4AD0-AACD-860505638ABE}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Silverlight5", "Renci.SshNet.Silverlight5\Renci.SshNet.Silverlight5.csproj", "{E367F791-C1EC-4181-912A-2943CAC6B3BC}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.WindowsPhone8", "Renci.SshNet.WindowsPhone8\Renci.SshNet.WindowsPhone8.csproj", "{4A6CA785-1C8A-47FE-98C0-30C675A9328B}" @@ -55,62 +46,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|ARM.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x64.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.Build.0 = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|ARM.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x64.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x86.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|ARM.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x64.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x86.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.Build.0 = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|ARM.ActiveCfg = Release|Any CPU - {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|x64.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|ARM.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|x64.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|x86.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Any CPU.Build.0 = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|ARM.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|x64.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|x86.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|ARM.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|x64.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Debug|x86.ActiveCfg = Debug|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|Any CPU.Build.0 = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|ARM.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|x64.ActiveCfg = Release|Any CPU - {007CE8B3-7827-4AD0-AACD-860505638ABE}.Release|x86.ActiveCfg = Release|Any CPU {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Any CPU.Build.0 = Debug|Any CPU {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|ARM.ActiveCfg = Debug|Any CPU diff --git a/src/Renci.SshNet.VS2017.sln b/src/Renci.SshNet.VS2017.sln index 00469f61..9f1ce5e3 100644 --- a/src/Renci.SshNet.VS2017.sln +++ b/src/Renci.SshNet.VS2017.sln @@ -19,13 +19,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandcastle", "sandcastle", ..\build\sandcastle\SSH.NET.shfbproj = ..\build\sandcastle\SSH.NET.shfbproj EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet", "Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet", "Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" 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}") = "Renci.SshNet.NET35", "Renci.SshNet.NET35\Renci.SshNet.NET35.csproj", "{DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.NETCore", "Renci.SshNet.NETCore\Renci.SshNet.NETCore.csproj", "{8E8229EB-6780-4A8A-B470-E2023FA55AB5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Tests", "Renci.SshNet.Tests\Renci.SshNet.Tests.csproj", "{C45379B9-17B1-4E89-BC2E-6D41726413E8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -69,40 +65,6 @@ Global {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x64.ActiveCfg = Release|Any CPU {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|ARM.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|x64.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Debug|x86.ActiveCfg = Debug|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Any CPU.Build.0 = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|ARM.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|x64.ActiveCfg = Release|Any CPU - {DD1C552F-7F48-4269-ABB3-2E4C89B7E43A}.Release|x86.ActiveCfg = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|ARM.ActiveCfg = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|ARM.Build.0 = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|x64.ActiveCfg = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|x64.Build.0 = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|x86.ActiveCfg = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Debug|x86.Build.0 = Debug|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|Any CPU.Build.0 = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|ARM.ActiveCfg = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|ARM.Build.0 = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|x64.ActiveCfg = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|x64.Build.0 = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|x86.ActiveCfg = Release|Any CPU - {8E8229EB-6780-4A8A-B470-E2023FA55AB5}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -111,6 +73,9 @@ Global {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C3D130B3-A070-4B12-A10F-E3E44D6ACEE2} + EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = Renci.SshNet1.vsmdi EndGlobalSection diff --git a/src/Renci.SshNet.VS2019.sln b/src/Renci.SshNet.VS2019.sln new file mode 100644 index 00000000..bc1f6f6d --- /dev/null +++ b/src/Renci.SshNet.VS2019.sln @@ -0,0 +1,82 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29521.150 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" + ProjectSection(SolutionItems) = preProject + ..\build\build.cmd = ..\build\build.cmd + ..\build\build.proj = ..\build\build.proj + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{94EE3919-19FA-4D9B-8DA9-249050B15232}" + ProjectSection(SolutionItems) = preProject + ..\build\nuget\SSH.NET.nuspec = ..\build\nuget\SSH.NET.nuspec + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandcastle", "sandcastle", "{A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1}" + ProjectSection(SolutionItems) = preProject + ..\build\sandcastle\SSH.NET.shfbproj = ..\build\sandcastle\SSH.NET.shfbproj + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet", "Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Tests", "Renci.SshNet.Tests\Renci.SshNet.Tests.csproj", "{C45379B9-17B1-4E89-BC2E-6D41726413E8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|Mixed Platforms = Release|Mixed Platforms + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|ARM.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x64.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x86.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.Build.0 = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|ARM.ActiveCfg = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x64.ActiveCfg = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x86.ActiveCfg = Release|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x64.ActiveCfg = Debug|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x86.ActiveCfg = Debug|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.Build.0 = Release|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|ARM.ActiveCfg = Release|Any CPU + {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|x64.ActiveCfg = Release|Any CPU + {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} + {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BAD6019D-4AF7-4E15-99A0-8036E16FC0E5} + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = Renci.SshNet1.vsmdi + EndGlobalSection +EndGlobal diff --git a/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj b/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj index d5d155ab..61abd53a 100644 --- a/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj +++ b/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj @@ -182,9 +182,6 @@ Common\Extensions.cs - - Common\Extensions.cs - Common\HostKeyEventArgs.cs @@ -584,12 +581,411 @@ Security\Algorithm.cs + + Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs + + + Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs + + + Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\util\Pack.cs + + + Security\Cryptography\BouncyCastle\math\BigInteger.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\LongArray.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs + + + Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\PrimeField.cs + + + Security\Cryptography\BouncyCastle\math\raw\Mod.cs + + + Security\Cryptography\BouncyCastle\math\raw\Nat.cs + + + Security\Cryptography\BouncyCastle\security\DigestUtilities.cs + + + Security\Cryptography\BouncyCastle\security\SecureRandom.cs + + + Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs + + + Security\Cryptography\BouncyCastle\util\Arrays.cs + + + Security\Cryptography\BouncyCastle\util\BigIntegers.cs + + + Security\Cryptography\BouncyCastle\util\encoders\Hex.cs + + + Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs + + + Security\Cryptography\BouncyCastle\util\IMemoable.cs + + + Security\Cryptography\BouncyCastle\util\Integers.cs + + + Security\Cryptography\BouncyCastle\util\MemoableResetException.cs + + + Security\Cryptography\BouncyCastle\util\Times.cs + Security\CertificateHostAlgorithm.cs + + Security\Cryptography\Chaos.NaCl\CryptoBytes.cs + + + Security\Cryptography\Chaos.NaCl\Ed25519.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array16.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array8.cs + + + Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs + + + Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs + + + Security\Cryptography\Chaos.NaCl\Sha512.cs + Security\Cryptography\AsymmetricCipher.cs + + Security\Cryptography\Bcrypt.cs + Security\Cryptography\BlockCipher.cs @@ -656,6 +1052,12 @@ Security\Cryptography\DsaKey.cs + + Security\Cryptography\ED25519DigitalSignature.cs + + + Security\Cryptography\ED25519Key.cs + Security\Cryptography\HMACMD5.cs @@ -719,6 +1121,24 @@ Security\KeyExchangeDiffieHellmanGroupSha1.cs + + Security\KeyExchangeEC.cs + + + Security\KeyExchangeECCurve25519.cs + + + Security\KeyExchangeECDH.cs + + + Security\KeyExchangeECDH256.cs + + + Security\KeyExchangeECDH384.cs + + + Security\KeyExchangeECDH521.cs + Security\KeyHostAlgorithm.cs diff --git a/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj b/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj index f1bd9c40..2588e917 100644 --- a/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj +++ b/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj @@ -223,9 +223,6 @@ Common\Extensions.cs - - Common\Extensions.cs - Common\HostKeyEventArgs.cs @@ -631,12 +628,411 @@ Security\Algorithm.cs + + Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs + + + Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs + + + Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs + + + Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs + + + Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\IDigest.cs + + + Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs + + + Security\Cryptography\BouncyCastle\crypto\util\Pack.cs + + + Security\Cryptography\BouncyCastle\math\BigInteger.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs + + + Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs + + + Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs + + + Security\Cryptography\BouncyCastle\math\ec\LongArray.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs + + + Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs + + + Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs + + + Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs + + + Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs + + + Security\Cryptography\BouncyCastle\math\field\PrimeField.cs + + + Security\Cryptography\BouncyCastle\math\raw\Mod.cs + + + Security\Cryptography\BouncyCastle\math\raw\Nat.cs + + + Security\Cryptography\BouncyCastle\security\DigestUtilities.cs + + + Security\Cryptography\BouncyCastle\security\SecureRandom.cs + + + Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs + + + Security\Cryptography\BouncyCastle\util\Arrays.cs + + + Security\Cryptography\BouncyCastle\util\BigIntegers.cs + + + Security\Cryptography\BouncyCastle\util\encoders\Hex.cs + + + Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs + + + Security\Cryptography\BouncyCastle\util\IMemoable.cs + + + Security\Cryptography\BouncyCastle\util\Integers.cs + + + Security\Cryptography\BouncyCastle\util\MemoableResetException.cs + + + Security\Cryptography\BouncyCastle\util\Times.cs + Security\CertificateHostAlgorithm.cs + + Security\Cryptography\Chaos.NaCl\CryptoBytes.cs + + + Security\Cryptography\Chaos.NaCl\Ed25519.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array16.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Array8.cs + + + Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs + + + Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs + + + Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs + + + Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs + + + Security\Cryptography\Chaos.NaCl\Sha512.cs + Security\Cryptography\AsymmetricCipher.cs + + Security\Cryptography\Bcrypt.cs + Security\Cryptography\BlockCipher.cs @@ -703,6 +1099,12 @@ Security\Cryptography\DsaKey.cs + + Security\Cryptography\ED25519DigitalSignature.cs + + + Security\Cryptography\ED25519Key.cs + Security\Cryptography\HMACMD5.cs @@ -721,6 +1123,12 @@ Security\Cryptography\Key.cs + + Security\Cryptography\EcdsaDigitalSignature.cs + + + Security\Cryptography\EcdsaKey.cs + Security\Cryptography\RsaDigitalSignature.cs @@ -766,6 +1174,24 @@ Security\KeyExchangeDiffieHellmanGroupSha1.cs + + Security\KeyExchangeEC.cs + + + Security\KeyExchangeECCurve25519.cs + + + Security\KeyExchangeECDH.cs + + + Security\KeyExchangeECDH256.cs + + + Security\KeyExchangeECDH384.cs + + + Security\KeyExchangeECDH521.cs + Security\KeyHostAlgorithm.cs diff --git a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs index 0a41c5cb..6fc1308e 100644 --- a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; #if FEATURE_DIAGNOSTICS_TRACESOURCE using System.Threading; #endif // FEATURE_DIAGNOSTICS_TRACESOURCE diff --git a/src/Renci.SshNet/Abstractions/DnsAbstraction.cs b/src/Renci.SshNet/Abstractions/DnsAbstraction.cs index cd9a399b..0af35aee 100644 --- a/src/Renci.SshNet/Abstractions/DnsAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DnsAbstraction.cs @@ -2,18 +2,20 @@ using System.Net; using System.Net.Sockets; -#if FEATURE_DEVICEINFORMATION_APM +#if FEATURE_DNS_SYNC +#elif FEATURE_DNS_APM +using Renci.SshNet.Common; +#elif FEATURE_DNS_TAP +#elif FEATURE_DEVICEINFORMATION_APM using System.Collections.Generic; using System.Linq; using System.Threading; using Microsoft.Phone.Net.NetworkInformation; -#endif // FEATURE_DEVICEINFORMATION_APM - -#if FEATURE_DATAGRAMSOCKET +#elif FEATURE_DATAGRAMSOCKET using System.Collections.Generic; using Windows.Networking; using Windows.Networking.Sockets; -#endif // FEATURE_DATAGRAMSOCKET +#endif namespace Renci.SshNet.Abstractions { @@ -41,7 +43,7 @@ namespace Renci.SshNet.Abstractions throw new SshOperationTimeoutException("Timeout resolving host name."); return Dns.EndGetHostAddresses(asyncResult); #elif FEATURE_DNS_TAP - return Dns.GetHostAddressesAsync(hostNameOrAddress).Result; + return Dns.GetHostAddressesAsync(hostNameOrAddress).GetAwaiter().GetResult(); #else IPAddress address; if (IPAddress.TryParse(hostNameOrAddress, out address)) diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index 396b125c..f15b6034 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -148,10 +148,10 @@ namespace Renci.SshNet.Abstractions var receiveCompleted = new ManualResetEvent(false); var sendReceiveToken = new PartialSendReceiveToken(socket, receiveCompleted); var args = new SocketAsyncEventArgs - { - RemoteEndPoint = socket.RemoteEndPoint, - UserToken = sendReceiveToken - }; + { + RemoteEndPoint = socket.RemoteEndPoint, + UserToken = sendReceiveToken + }; args.Completed += ReceiveCompleted; args.SetBuffer(buffer, offset, size); @@ -166,6 +166,10 @@ namespace Renci.SshNet.Abstractions "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds)); } + else + { + sendReceiveToken.Process(args); + } if (args.SocketError != SocketError.Success) throw new SocketException((int) args.SocketError); @@ -180,7 +184,7 @@ namespace Renci.SshNet.Abstractions receiveCompleted.Dispose(); } #else -#error Receiving data from a Socket is not implemented. + #error Receiving data from a Socket is not implemented. #endif } @@ -242,7 +246,7 @@ namespace Renci.SshNet.Abstractions if (readToken.Exception != null) throw readToken.Exception; #else -#error Receiving data from a Socket is not implemented. + #error Receiving data from a Socket is not implemented. #endif } @@ -278,7 +282,30 @@ namespace Renci.SshNet.Abstractions } /// - /// Receives data from a bound into a receive buffer. + /// Receives data from a bound . + /// + /// + /// The number of bytes to receive. + /// Specifies the amount of time after which the call will time out. + /// + /// The bytes received. + /// + /// + /// If no data is available for reading, the method will + /// block until data is available or the time-out value is exceeded. If the time-out value is exceeded, the + /// call will throw a . + /// If you are in non-blocking mode, and there is no data available in the in the protocol stack buffer, the + /// method will complete immediately and throw a . + /// + public static byte[] Read(Socket socket, int size, TimeSpan timeout) + { + var buffer = new byte[size]; + Read(socket, buffer, 0, size, timeout); + return buffer; + } + + /// + /// Receives data from a bound into a receive buffer. /// /// /// An array of type that is the storage location for the received data. @@ -289,11 +316,11 @@ namespace Renci.SshNet.Abstractions /// The number of bytes received. /// /// - /// If no data is available for reading, the method will - /// block until data is available or the time-out value was exceeded. If the time-out value was exceeded, the - /// call will throw a . + /// If no data is available for reading, the method will + /// block until data is available or the time-out value is exceeded. If the time-out value is exceeded, the + /// call will throw a . /// If you are in non-blocking mode, and there is no data available in the in the protocol stack buffer, the - /// method will complete immediately and throw a . + /// method will complete immediately and throw a . /// public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeSpan timeout) { @@ -336,10 +363,10 @@ namespace Renci.SshNet.Abstractions var sendReceiveToken = new BlockingSendReceiveToken(socket, buffer, offset, size, receiveCompleted); var args = new SocketAsyncEventArgs - { - UserToken = sendReceiveToken, - RemoteEndPoint = socket.RemoteEndPoint - }; + { + UserToken = sendReceiveToken, + RemoteEndPoint = socket.RemoteEndPoint + }; args.Completed += ReceiveCompleted; args.SetBuffer(buffer, offset, size); @@ -351,6 +378,10 @@ namespace Renci.SshNet.Abstractions throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds)); } + else + { + sendReceiveToken.Process(args); + } if (args.SocketError != SocketError.Success) throw new SocketException((int) args.SocketError); @@ -384,11 +415,10 @@ namespace Renci.SshNet.Abstractions { try { - var bytesSent = socket.Send(data, offset + totalBytesSent, totalBytesToSend - totalBytesSent, - SocketFlags.None); + var bytesSent = socket.Send(data, offset + totalBytesSent, totalBytesToSend - totalBytesSent, SocketFlags.None); if (bytesSent == 0) throw new SshConnectionException("An established connection was aborted by the server.", - DisconnectReason.ConnectionLost); + DisconnectReason.ConnectionLost); totalBytesSent += bytesSent; } @@ -407,10 +437,10 @@ namespace Renci.SshNet.Abstractions var sendCompleted = new ManualResetEvent(false); var sendReceiveToken = new BlockingSendReceiveToken(socket, data, offset, size, sendCompleted); var socketAsyncSendArgs = new SocketAsyncEventArgs - { - RemoteEndPoint = socket.RemoteEndPoint, - UserToken = sendReceiveToken - }; + { + RemoteEndPoint = socket.RemoteEndPoint, + UserToken = sendReceiveToken + }; socketAsyncSendArgs.SetBuffer(data, offset, size); socketAsyncSendArgs.Completed += SendCompleted; @@ -421,13 +451,17 @@ namespace Renci.SshNet.Abstractions if (!sendCompleted.WaitOne()) throw new SocketException((int) SocketError.TimedOut); } + else + { + sendReceiveToken.Process(socketAsyncSendArgs); + } if (socketAsyncSendArgs.SocketError != SocketError.Success) throw new SocketException((int) socketAsyncSendArgs.SocketError); if (sendReceiveToken.TotalBytesTransferred == 0) throw new SshConnectionException("An established connection was aborted by the server.", - DisconnectReason.ConnectionLost); + DisconnectReason.ConnectionLost); } finally { @@ -437,7 +471,7 @@ namespace Renci.SshNet.Abstractions sendCompleted.Dispose(); } #else -#error Sending data to a Socket is not implemented. + #error Sending data to a Socket is not implemented. #endif } diff --git a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs index 47175030..ee21ec7e 100644 --- a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs @@ -13,7 +13,7 @@ namespace Renci.SshNet.Abstractions #if FEATURE_THREAD_SLEEP System.Threading.Thread.Sleep(millisecondsTimeout); #elif FEATURE_THREAD_TAP - System.Threading.Tasks.Task.Delay(millisecondsTimeout).Wait(); + System.Threading.Tasks.Task.Delay(millisecondsTimeout).GetAwaiter().GetResult(); #else #error Suspend of the current thread is not implemented. #endif diff --git a/src/Renci.SshNet/AuthenticationMethod.cs b/src/Renci.SshNet/AuthenticationMethod.cs index 294f5dbd..1a285d8c 100644 --- a/src/Renci.SshNet/AuthenticationMethod.cs +++ b/src/Renci.SshNet/AuthenticationMethod.cs @@ -1,6 +1,5 @@ using Renci.SshNet.Common; using System; -using System.Collections.Generic; namespace Renci.SshNet { diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index 54cbe2e2..0b5e627f 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -74,7 +74,8 @@ namespace Renci.SshNet get { CheckDisposed(); - return Session != null && Session.IsConnected; + + return IsSessionConnected(); } } @@ -107,13 +108,25 @@ namespace Renci.SshNet } else { - // change the due time and interval of the timer if has already - // been created (which means the client is connected) - // - // if the client is not yet connected, then the timer will be - // created with the new interval when Connect() is invoked if (_keepAliveTimer != null) + { + // change the due time and interval of the timer if has already + // been created (which means the client is connected) + _keepAliveTimer.Change(value, value); + } + else if (IsSessionConnected()) + { + // if timer has not yet been created and the client is already connected, + // then we need to create the timer now + // + // this means that - before connecting - the keep-alive interval was set to + // negative one (-1) and as such we did not create the timer + _keepAliveTimer = CreateKeepAliveTimer(value, value); + } + + // note that if the client is not yet connected, then the timer will be created with the + // new interval when Connect() is invoked } _keepAliveInterval = value; } @@ -204,16 +217,26 @@ namespace Renci.SshNet // forwarded port with a client instead of with a session // // To be discussed with Oleg (or whoever is interested) - if (Session != null && Session.IsConnected) + if (IsSessionConnected()) throw new InvalidOperationException("The client is already connected."); OnConnecting(); - Session = _serviceFactory.CreateSession(ConnectionInfo); - Session.HostKeyReceived += Session_HostKeyReceived; - Session.ErrorOccured += Session_ErrorOccured; - Session.Connect(); + + Session = CreateAndConnectSession(); + try + { + // Even though the method we invoke makes you believe otherwise, at this point only + // the SSH session itself is connected. + OnConnected(); + } + catch + { + // Only dispose the session as Disconnect() would have side-effects (such as remove forwarded + // ports in SshClient). + DisposeSession(); + throw; + } StartKeepAliveTimer(); - OnConnected(); } /// @@ -228,20 +251,11 @@ namespace Renci.SshNet OnDisconnecting(); - // stop sending keep-alive messages before we close the - // session + // stop sending keep-alive messages before we close the session StopKeepAliveTimer(); - // disconnect and dispose the SSH session - if (Session != null) - { - // a new session is created in Connect(), so we should dispose and - // dereference the current session here - Session.ErrorOccured -= Session_ErrorOccured; - Session.HostKeyReceived -= Session_HostKeyReceived; - Session.Dispose(); - Session = null; - } + // dispose the SSH session + DisposeSession(); OnDisconnected(); } @@ -281,8 +295,11 @@ namespace Renci.SshNet /// protected virtual void OnDisconnecting() { - if (Session != null) - Session.OnDisconnecting(); + var session = Session; + if (session != null) + { + session.OnDisconnecting(); + } } /// @@ -310,7 +327,7 @@ namespace Renci.SshNet } } - #region IDisposable Members +#region IDisposable Members private bool _isDisposed; @@ -369,7 +386,7 @@ namespace Renci.SshNet Dispose(false); } - #endregion +#endregion /// /// Stops the keep-alive timer, and waits until all timer callbacks have been @@ -386,8 +403,10 @@ namespace Renci.SshNet private void SendKeepAliveMessage() { + var session = Session; + // do nothing if we have disposed or disconnected - if (Session == null) + if (session == null) return; // do not send multiple keep-alive messages concurrently @@ -395,7 +414,7 @@ namespace Renci.SshNet { try { - Session.TrySendMessage(new IgnoreMessage()); + session.TrySendMessage(new IgnoreMessage()); } finally { @@ -420,7 +439,70 @@ namespace Renci.SshNet // timer is already started return; - _keepAliveTimer = new Timer(state => SendKeepAliveMessage(), null, _keepAliveInterval, _keepAliveInterval); + _keepAliveTimer = CreateKeepAliveTimer(_keepAliveInterval, _keepAliveInterval); + } + + /// + /// Creates a with the specified due time and interval. + /// + /// The amount of time to delay before the keep-alive message is first sent. Specify negative one (-1) milliseconds to prevent the timer from starting. Specify zero (0) to start the timer immediately. + /// The time interval between attempts to send a keep-alive message. Specify negative one (-1) milliseconds to disable periodic signaling. + /// + /// A with the specified due time and interval. + /// + private Timer CreateKeepAliveTimer(TimeSpan dueTime, TimeSpan period) + { + return new Timer(state => SendKeepAliveMessage(), Session, dueTime, period); + } + + private ISession CreateAndConnectSession() + { + var session = _serviceFactory.CreateSession(ConnectionInfo); + session.HostKeyReceived += Session_HostKeyReceived; + session.ErrorOccured += Session_ErrorOccured; + + try + { + session.Connect(); + return session; + } + catch + { + DisposeSession(session); + throw; + } + } + + private void DisposeSession(ISession session) + { + session.ErrorOccured -= Session_ErrorOccured; + session.HostKeyReceived -= Session_HostKeyReceived; + session.Dispose(); + } + + /// + /// Disposes the SSH session, and assigns null to . + /// + private void DisposeSession() + { + var session = Session; + if (session != null) + { + Session = null; + DisposeSession(session); + } + } + + /// + /// Returns a value indicating whether the SSH session is established. + /// + /// + /// true if the SSH session is established; otherwise, false. + /// + private bool IsSessionConnected() + { + var session = Session; + return session != null && session.IsConnected; } } } diff --git a/src/Renci.SshNet/Channels/Channel.cs b/src/Renci.SshNet/Channels/Channel.cs index a5c449bf..a6311a98 100644 --- a/src/Renci.SshNet/Channels/Channel.cs +++ b/src/Renci.SshNet/Channels/Channel.cs @@ -5,6 +5,7 @@ using Renci.SshNet.Common; using Renci.SshNet.Messages; using Renci.SshNet.Messages.Connection; using System.Globalization; +using Renci.SshNet.Abstractions; namespace Renci.SshNet.Channels { @@ -15,7 +16,6 @@ namespace Renci.SshNet.Channels { private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(false); private EventWaitHandle _channelServerWindowAdjustWaitHandle = new ManualResetEvent(false); - private EventWaitHandle _errorOccuredWaitHandle = new ManualResetEvent(false); private readonly object _serverWindowSizeLock = new object(); private readonly uint _initialWindowSize; private uint? _remoteWindowSize; @@ -327,11 +327,10 @@ namespace Renci.SshNet.Channels { var sizeOfCurrentMessage = GetDataLengthThatCanBeSentInMessage(totalBytesToSend); - var channelDataMessage = new ChannelDataMessage( - RemoteChannelNumber, - data, - offset, - sizeOfCurrentMessage); + var channelDataMessage = new ChannelDataMessage(RemoteChannelNumber, + data, + offset, + sizeOfCurrentMessage); _session.SendMessage(channelDataMessage); totalBytesToSend -= sizeOfCurrentMessage; @@ -400,21 +399,13 @@ namespace Renci.SshNet.Channels { _closeMessageReceived = true; - // signal that SSH_MSG_CHANNEL_CLOSE message was received from server - // we need to signal this before firing the Closed event, as a subscriber - // may very well react to the Closed event by closing or disposing the - // channel which in turn will wait for this handle to be signaled + // Signal that SSH_MSG_CHANNEL_CLOSE message was received from server. + // We need to signal this before invoking Close() as it may very well + // be blocked waiting for this signal. var channelClosedWaitHandle = _channelClosedWaitHandle; if (channelClosedWaitHandle != null) channelClosedWaitHandle.Set(); - // raise event signaling that the server has closed its end of the channel - var closed = Closed; - if (closed != null) - { - closed(this, new ChannelEventArgs(LocalChannelNumber)); - } - // close the channel Close(); } @@ -554,20 +545,33 @@ namespace Renci.SshNet.Channels { _closeMessageSent = true; - // wait for channel to be closed if we actually sent a close message (either to initiate closing - // the channel, or as response to a SSH_MSG_CHANNEL_CLOSE message sent by the server - try + // only wait for the channel to be closed by the server if we didn't send a + // SSH_MSG_CHANNEL_CLOSE as response to a SSH_MSG_CHANNEL_CLOSE sent by the + // server + var closeWaitResult = _session.TryWait(_channelClosedWaitHandle, ConnectionInfo.ChannelCloseTimeout); + if (closeWaitResult != WaitResult.Success) { - WaitOnHandle(_channelClosedWaitHandle); - } - catch (SshConnectionException) - { - // ignore connection failures as we're closing the channel anyway + DiagnosticAbstraction.Log(string.Format("Wait for channel close not successful: {0:G}.", closeWaitResult)); } } } - IsOpen = false; + if (IsOpen) + { + // mark sure the channel is marked closed before we raise the Closed event + // this also ensures don't raise the Closed event more than once + IsOpen = false; + + if (_closeMessageReceived) + { + // raise event signaling that both ends of the channel have been closed + var closed = Closed; + if (closed != null) + { + closed(this, new ChannelEventArgs(LocalChannelNumber)); + } + } + } } } @@ -612,10 +616,6 @@ namespace Renci.SshNet.Channels try { OnErrorOccured(e.Exception); - - var errorOccuredWaitHandle = _errorOccuredWaitHandle; - if (errorOccuredWaitHandle != null) - errorOccuredWaitHandle.Set(); } catch (Exception ex) { @@ -871,13 +871,6 @@ namespace Renci.SshNet.Channels channelServerWindowAdjustWaitHandle.Dispose(); } - var errorOccuredWaitHandle = _errorOccuredWaitHandle; - if (errorOccuredWaitHandle != null) - { - _errorOccuredWaitHandle = null; - errorOccuredWaitHandle.Dispose(); - } - _isDisposed = true; } } diff --git a/src/Renci.SshNet/Common/AsyncResult.cs b/src/Renci.SshNet/Common/AsyncResult.cs index d045c90c..3466a030 100644 --- a/src/Renci.SshNet/Common/AsyncResult.cs +++ b/src/Renci.SshNet/Common/AsyncResult.cs @@ -67,11 +67,15 @@ namespace Renci.SshNet.Common // If the event exists, set it if (_asyncWaitHandle != null) + { _asyncWaitHandle.Set(); + } // If a callback method was set, call it if (_asyncCallback != null) + { _asyncCallback(this); + } } /// diff --git a/src/Renci.SshNet/Common/DerData.cs b/src/Renci.SshNet/Common/DerData.cs index c84c0b17..35178798 100644 --- a/src/Renci.SshNet/Common/DerData.cs +++ b/src/Renci.SshNet/Common/DerData.cs @@ -12,7 +12,7 @@ namespace Renci.SshNet.Common private const byte Boolean = 0x01; private const byte Integer = 0x02; - //private const byte BITSTRING = 0x03; + private const byte BITSTRING = 0x03; private const byte Octetstring = 0x04; private const byte Null = 0x05; private const byte Objectidentifier = 0x06; @@ -70,12 +70,20 @@ namespace Renci.SshNet.Common /// Initializes a new instance of the class. /// /// DER encoded data. - public DerData(byte[] data) + /// its a construct + public DerData(byte[] data, bool construct = false) { _data = new List(data); - ReadByte(); // skip dataType - var length = ReadLength(); - _lastIndex = _readerIndex + length; + if (construct) + { + _lastIndex = _readerIndex + data.Length; + } + else + { + ReadByte(); // skip dataType + var length = ReadLength(); + _lastIndex = _readerIndex + length; + } } /// @@ -101,7 +109,7 @@ namespace Renci.SshNet.Common { var type = ReadByte(); if (type != Integer) - throw new InvalidOperationException("Invalid data type, INTEGER(02) is expected."); + throw new InvalidOperationException(string.Format("Invalid data type, INTEGER(02) is expected, but was {0}", type.ToString("X2"))); var length = ReadLength(); @@ -118,7 +126,7 @@ namespace Renci.SshNet.Common { var type = ReadByte(); if (type != Integer) - throw new InvalidOperationException("Invalid data type, INTEGER(02) is expected."); + throw new InvalidOperationException(string.Format("Invalid data type, INTEGER(02) is expected, but was {0}", type.ToString("X2"))); var length = ReadLength(); @@ -140,6 +148,51 @@ namespace Renci.SshNet.Common return result; } + /// + /// Reads next octetstring data type from internal buffer. + /// + /// data read. + public byte[] ReadOctetString() + { + var type = ReadByte(); + if (type != Octetstring) + throw new InvalidOperationException(string.Format("Invalid data type, OCTETSTRING(04) is expected, but was {0}", type.ToString("X2"))); + + var length = ReadLength(); + var data = ReadBytes(length); + return data; + } + + /// + /// Reads next bitstring data type from internal buffer. + /// + /// data read. + public byte[] ReadBitString() + { + var type = ReadByte(); + if (type != BITSTRING) + throw new InvalidOperationException(string.Format("Invalid data type, BITSTRING(03) is expected, but was {0}", type.ToString("X2"))); + + var length = ReadLength(); + var data = ReadBytes(length); + return data; + } + + /// + /// Reads next object data type from internal buffer. + /// + /// data read. + public byte[] ReadObject() + { + var type = ReadByte(); + if (type != Objectidentifier) + throw new InvalidOperationException(string.Format("Invalid data type, OBJECT(06) is expected, but was {0}", type.ToString("X2"))); + + var length = ReadLength(); + var data = ReadBytes(length); + return data; + } + /// /// Writes BOOLEAN data into internal buffer. /// @@ -189,6 +242,18 @@ namespace Renci.SshNet.Common WriteBytes(data); } + /// + /// Writes BITSTRING data into internal buffer. + /// + /// The data. + public void WriteBitstring(byte[] data) + { + _data.Add(BITSTRING); + var length = GetLength(data.Length); + WriteBytes(length); + WriteBytes(data); + } + /// /// Writes OBJECTIDENTIFIER data into internal buffer. /// @@ -229,6 +294,18 @@ namespace Renci.SshNet.Common WriteBytes(bytes); } + /// + /// Writes OBJECTIDENTIFIER data into internal buffer. + /// + /// The bytes. + public void WriteObjectIdentifier(byte[] bytes) + { + _data.Add(Objectidentifier); + var length = GetLength(bytes.Length); + WriteBytes(length); + WriteBytes(bytes); + } + /// /// Writes NULL data into internal buffer. /// @@ -268,10 +345,13 @@ namespace Renci.SshNet.Common return data; } - return new[] {(byte) length}; + return new[] { (byte)length }; } - - private int ReadLength() + /// + /// Gets Data Length + /// + /// length + public int ReadLength() { int length = ReadByte(); @@ -306,12 +386,19 @@ namespace Renci.SshNet.Common return length; } - private void WriteBytes(IEnumerable data) + /// + /// Write Byte data into internal buffer. + /// + public void WriteBytes(IEnumerable data) { _data.AddRange(data); } - private byte ReadByte() + /// + /// Reads Byte data into internal buffer. + /// + /// data read + public byte ReadByte() { if (_readerIndex > _data.Count) throw new InvalidOperationException("Read out of boundaries."); @@ -319,7 +406,12 @@ namespace Renci.SshNet.Common return _data[_readerIndex++]; } - private byte[] ReadBytes(int length) + /// + /// Reads lengths Bytes data into internal buffer. + /// + /// data read + /// amount of data to read. + public byte[] ReadBytes(int length) { if (_readerIndex + length > _data.Count) throw new InvalidOperationException("Read out of boundaries."); @@ -330,4 +422,4 @@ namespace Renci.SshNet.Common return result; } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs index 9d163bc9..17d72d7f 100644 --- a/src/Renci.SshNet/Common/Extensions.cs +++ b/src/Renci.SshNet/Common/Extensions.cs @@ -72,6 +72,20 @@ namespace Renci.SshNet.Common return new BigInteger(reversed.Reverse()); } + /// + /// Initializes a new instance of the structure using the SSH BigNum2 Format + /// + public static BigInteger ToBigInteger2(this byte[] data) + { + if ((data[0] & (1 << 7)) != 0) + { + var buf = new byte[data.Length + 1]; + Buffer.BlockCopy(data, 0, buf, 1, data.Length); + data = buf; + } + return data.ToBigInteger(); + } + /// /// Reverses the sequence of the elements in the entire one-dimensional . /// @@ -247,6 +261,20 @@ namespace Renci.SshNet.Common return value; } + /// + /// Pads with leading zeros if needed. + /// + /// The data. + /// The length to pad to. + public static byte[] Pad(this byte[] data, int length) + { + if (length <= data.Length) + return data; + var newData = new byte[length]; + Buffer.BlockCopy(data, 0, newData, newData.Length - data.Length, data.Length); + return newData; + } + public static byte[] Concat(this byte[] first, byte[] second) { if (first == null || first.Length == 0) @@ -307,5 +335,32 @@ namespace Renci.SshNet.Common handle.Close(); } #endif // !FEATURE_WAITHANDLE_DISPOSE + +#if !FEATURE_HASHALGORITHM_DISPOSE + /// + /// Disposes the specified algorithm. + /// + /// The algorithm. + [DebuggerNonUserCode] + internal static void Dispose(this System.Security.Cryptography.HashAlgorithm algorithm) + { + if (algorithm == null) + throw new NullReferenceException(); + + algorithm.Clear(); + } +#endif // FEATURE_HASHALGORITHM_DISPOSE + +#if !FEATURE_STRINGBUILDER_CLEAR + /// + /// Clears the contents of the string builder. + /// + /// The to clear. + public static void Clear(this StringBuilder value) + { + value.Length = 0; + value.Capacity = 16; + } +#endif // !FEATURE_STRINGBUILDER_CLEAR } } diff --git a/src/Renci.SshNet/Common/PosixPath.cs b/src/Renci.SshNet/Common/PosixPath.cs index f9c099b8..465916b3 100644 --- a/src/Renci.SshNet/Common/PosixPath.cs +++ b/src/Renci.SshNet/Common/PosixPath.cs @@ -4,6 +4,49 @@ namespace Renci.SshNet.Common { internal class PosixPath { + public string Directory { get; private set; } + public string File { get; private set; } + + public static PosixPath CreateAbsoluteOrRelativeFilePath(string path) + { + if (path == null) + { + throw new ArgumentNullException("path"); + } + + var posixPath = new PosixPath(); + + var pathEnd = path.LastIndexOf('/'); + if (pathEnd == -1) + { + if (path.Length == 0) + { + throw new ArgumentException("The path is a zero-length string.", "path"); + } + + posixPath.Directory = "."; + posixPath.File = path; + } + else if (pathEnd == 0) + { + posixPath.Directory = "/"; + if (path.Length > 1) + { + posixPath.File = path.Substring(pathEnd + 1); + } + } + else + { + posixPath.Directory = path.Substring(0, pathEnd); + if (pathEnd < path.Length - 1) + { + posixPath.File = path.Substring(pathEnd + 1); + } + } + + return posixPath; + } + /// /// Gets the file name part of a given POSIX path. /// @@ -18,11 +61,14 @@ namespace Renci.SshNet.Common /// is returned. /// /// - /// If path has a trailing slash, but return a zero-length string. + /// If path has a trailing slash, return a zero-length string. /// /// public static string GetFileName(string path) { + if (path == null) + throw new ArgumentNullException("path"); + var pathEnd = path.LastIndexOf('/'); if (pathEnd == -1) return path; @@ -30,5 +76,29 @@ namespace Renci.SshNet.Common return string.Empty; return path.Substring(pathEnd + 1); } + + /// + /// Gets the directory name part of a given POSIX path. + /// + /// The POSIX path to get the directory name for. + /// + /// The directory part of the specified , or . if + /// does not contain any directory information. + /// + /// is null. + public static string GetDirectoryName(string path) + { + if (path == null) + throw new ArgumentNullException("path"); + + var pathEnd = path.LastIndexOf('/'); + if (pathEnd == -1) + return "."; + if (pathEnd == 0) + return "/"; + if (pathEnd == path.Length - 1) + return path.Substring(0, pathEnd); + return path.Substring(0, pathEnd); + } } } diff --git a/src/Renci.SshNet/Common/TerminalModes.cs b/src/Renci.SshNet/Common/TerminalModes.cs index 0a6ccadf..98c7b8fe 100644 --- a/src/Renci.SshNet/Common/TerminalModes.cs +++ b/src/Renci.SshNet/Common/TerminalModes.cs @@ -160,6 +160,11 @@ /// IMAXBEL = 41, + /// + /// Terminal input and output is assumed to be encoded in UTF-8. + /// + IUTF8 = 42, + /// /// Enable signals INTR, QUIT, [D]SUSP. /// diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index ba8f38b9..68df9fd4 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -23,6 +23,22 @@ namespace Renci.SshNet { internal static int DefaultPort = 22; + /// + /// The default connection timeout. + /// + /// + /// 30 seconds. + /// + private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30); + + /// + /// The default channel close timeout. + /// + /// + /// 1 second. + /// + private static readonly TimeSpan DefaultChannelCloseTimeout = TimeSpan.FromSeconds(1); + /// /// Gets supported key exchange algorithms for this connection. /// @@ -126,6 +142,18 @@ namespace Renci.SshNet /// public TimeSpan Timeout { get; set; } + /// + /// Gets or sets the timeout to use when waiting for a server to acknowledge closing a channel. + /// + /// + /// The channel close timeout. The default value is 1 second. + /// + /// + /// If a server does not send a SSH_MSG_CHANNEL_CLOSE message before the specified timeout + /// elapses, the channel will be closed immediately. + /// + public TimeSpan ChannelCloseTimeout { get; set; } + /// /// Gets or sets the character encoding. /// @@ -286,23 +314,25 @@ namespace Renci.SshNet throw new ArgumentException("At least one authentication method should be specified.", "authenticationMethods"); // Set default connection values - Timeout = TimeSpan.FromSeconds(30); + Timeout = DefaultTimeout; + ChannelCloseTimeout = DefaultChannelCloseTimeout; RetryAttempts = 10; MaxSessions = 10; Encoding = Encoding.UTF8; KeyExchangeAlgorithms = new Dictionary { + {"curve25519-sha256", typeof(KeyExchangeECCurve25519)}, + {"curve25519-sha256@libssh.org", typeof(KeyExchangeECCurve25519)}, + {"ecdh-sha2-nistp256", typeof(KeyExchangeECDH256)}, + {"ecdh-sha2-nistp384", typeof(KeyExchangeECDH384)}, + {"ecdh-sha2-nistp521", typeof(KeyExchangeECDH521)}, {"diffie-hellman-group-exchange-sha256", typeof (KeyExchangeDiffieHellmanGroupExchangeSha256)}, {"diffie-hellman-group-exchange-sha1", typeof (KeyExchangeDiffieHellmanGroupExchangeSha1)}, + {"diffie-hellman-group16-sha512", typeof(KeyExchangeDiffieHellmanGroup16Sha512)}, + {"diffie-hellman-group14-sha256", typeof (KeyExchangeDiffieHellmanGroup14Sha256)}, {"diffie-hellman-group14-sha1", typeof (KeyExchangeDiffieHellmanGroup14Sha1)}, {"diffie-hellman-group1-sha1", typeof (KeyExchangeDiffieHellmanGroup1Sha1)}, - //{"ecdh-sha2-nistp256", typeof(KeyExchangeEllipticCurveDiffieHellman)}, - //{"ecdh-sha2-nistp256", typeof(...)}, - //{"ecdh-sha2-nistp384", typeof(...)}, - //{"ecdh-sha2-nistp521", typeof(...)}, - //"gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==" - WinSSHD - //"gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==" - WinSSHD }; Encryptions = new Dictionary @@ -348,9 +378,14 @@ namespace Renci.SshNet HostKeyAlgorithms = new Dictionary> { + {"ssh-ed25519", data => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(), data)}, +#if FEATURE_ECDSA + {"ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data)}, + {"ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data)}, + {"ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data)}, +#endif {"ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data)}, {"ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data)}, - //{"ecdsa-sha2-nistp256 "} //{"x509v3-sign-rsa", () => { ... }, //{"x509v3-sign-dss", () => { ... }, //{"spki-sign-rsa", () => { ... }, diff --git a/src/Renci.SshNet/ForwardedPort.cs b/src/Renci.SshNet/ForwardedPort.cs index d71c0d0a..26baaa1d 100644 --- a/src/Renci.SshNet/ForwardedPort.cs +++ b/src/Renci.SshNet/ForwardedPort.cs @@ -122,7 +122,7 @@ namespace Renci.SshNet protected abstract void CheckDisposed(); /// - /// Raises event. + /// Raises event. /// /// The exception. protected void RaiseExceptionEvent(Exception exception) @@ -135,7 +135,7 @@ namespace Renci.SshNet } /// - /// Raises event. + /// Raises event. /// /// Request originator host. /// Request originator port. diff --git a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs index 45c8c64b..36a80455 100644 --- a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs +++ b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs @@ -264,7 +264,12 @@ namespace Renci.SshNet partial void InternalStop(TimeSpan timeout) { _pendingChannelCountdown.Signal(); - _pendingChannelCountdown.Wait(timeout); + if (!_pendingChannelCountdown.Wait(timeout)) + { + // TODO: log as warning + DiagnosticAbstraction.Log("Timeout waiting for pending channels in dynamic forwarded port to close."); + } + } partial void InternalDispose(bool disposing) @@ -328,7 +333,7 @@ namespace Renci.SshNet return false; } - var port = (uint)(portBuffer[0] * 256 + portBuffer[1]); + var port = Pack.BigEndianToUInt16(portBuffer); var ipBuffer = new byte[4]; if (SocketAbstraction.Read(socket, ipBuffer, 0, ipBuffer.Length, timeout) == 0) @@ -387,12 +392,12 @@ namespace Renci.SshNet { // no user authentication is one of the authentication methods supported // by the SOCKS client - SocketAbstraction.Send(socket, new byte[] { 0x05, 0x00 }, 0, 2); + SocketAbstraction.Send(socket, new byte[] {0x05, 0x00}, 0, 2); } else { // the SOCKS client requires authentication, which we currently do not support - SocketAbstraction.Send(socket, new byte[] { 0x05, 0xFF }, 0, 2); + SocketAbstraction.Send(socket, new byte[] {0x05, 0xFF}, 0, 2); // we continue business as usual but expect the client to close the connection // so one of the subsequent reads should return -1 signaling that the client @@ -449,7 +454,7 @@ namespace Renci.SshNet return false; } - var port = (uint)(portBuffer[0] * 256 + portBuffer[1]); + var port = Pack.BigEndianToUInt16(portBuffer); RaiseRequestReceived(host, port); @@ -515,19 +520,21 @@ namespace Renci.SshNet private static byte[] CreateSocks5Reply(bool channelOpen) { - var socksReply = new byte[ - // SOCKS version - 1 + - // Reply field - 1 + - // Reserved; fixed: 0x00 - 1 + - // Address type; fixed: 0x01 - 1 + - // IPv4 server bound address; fixed: {0x00, 0x00, 0x00, 0x00} - 4 + - // server bound port; fixed: {0x00, 0x00} - 2]; + var socksReply = new byte + [ + // SOCKS version + 1 + + // Reply field + 1 + + // Reserved; fixed: 0x00 + 1 + + // Address type; fixed: 0x01 + 1 + + // IPv4 server bound address; fixed: {0x00, 0x00, 0x00, 0x00} + 4 + + // server bound port; fixed: {0x00, 0x00} + 2 + ]; socksReply[0] = 0x05; diff --git a/src/Renci.SshNet/ForwardedPortLocal.NET.cs b/src/Renci.SshNet/ForwardedPortLocal.NET.cs index ed8f89c0..ba01ddbd 100644 --- a/src/Renci.SshNet/ForwardedPortLocal.NET.cs +++ b/src/Renci.SshNet/ForwardedPortLocal.NET.cs @@ -214,7 +214,11 @@ namespace Renci.SshNet partial void InternalStop(TimeSpan timeout) { _pendingChannelCountdown.Signal(); - _pendingChannelCountdown.Wait(timeout); + if (!_pendingChannelCountdown.Wait(timeout)) + { + // TODO: log as warning + DiagnosticAbstraction.Log("Timeout waiting for pending channels in local forwarded port to close."); + } } partial void InternalDispose(bool disposing) diff --git a/src/Renci.SshNet/ForwardedPortRemote.cs b/src/Renci.SshNet/ForwardedPortRemote.cs index 4b5915de..b2ed15fe 100644 --- a/src/Renci.SshNet/ForwardedPortRemote.cs +++ b/src/Renci.SshNet/ForwardedPortRemote.cs @@ -201,7 +201,12 @@ namespace Renci.SshNet // wait for pending channels to close _pendingChannelCountdown.Signal(); - _pendingChannelCountdown.Wait(timeout); + + if (!_pendingChannelCountdown.Wait(timeout)) + { + // TODO: log as warning + DiagnosticAbstraction.Log("Timeout waiting for pending channels in remote forwarded port to close."); + } _status = ForwardedPortStatus.Stopped; } @@ -244,10 +249,7 @@ namespace Renci.SshNet { RaiseRequestReceived(info.OriginatorAddress, info.OriginatorPort); - using ( - var channel = - Session.CreateChannelForwardedTcpip(channelOpenMessage.LocalChannelNumber, - channelOpenMessage.InitialWindowSize, channelOpenMessage.MaximumPacketSize)) + using (var channel = Session.CreateChannelForwardedTcpip(channelOpenMessage.LocalChannelNumber, channelOpenMessage.InitialWindowSize, channelOpenMessage.MaximumPacketSize)) { channel.Exception += Channel_Exception; channel.Bind(new IPEndPoint(HostAddress, (int) Port), this); diff --git a/src/Renci.SshNet/IAuthenticationMethod.cs b/src/Renci.SshNet/IAuthenticationMethod.cs index 6f5551ec..3fd78b09 100644 --- a/src/Renci.SshNet/IAuthenticationMethod.cs +++ b/src/Renci.SshNet/IAuthenticationMethod.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace Renci.SshNet +namespace Renci.SshNet { /// /// Base interface for authentication of a session using a given method. diff --git a/src/Renci.SshNet/IConnectionInfo.cs b/src/Renci.SshNet/IConnectionInfo.cs index 27ad00d5..a50c213b 100644 --- a/src/Renci.SshNet/IConnectionInfo.cs +++ b/src/Renci.SshNet/IConnectionInfo.cs @@ -40,6 +40,18 @@ namespace Renci.SshNet /// internal interface IConnectionInfo { + /// + /// Gets or sets the timeout to used when waiting for a server to acknowledge closing a channel. + /// + /// + /// The channel close timeout. The default value is 1 second. + /// + /// + /// If a server does not send a SSH2_MSG_CHANNEL_CLOSE message before the specified timeout + /// elapses, the channel will be closed immediately. + /// + TimeSpan ChannelCloseTimeout { get; } + /// /// Gets the supported channel requests for this connection. /// diff --git a/src/Renci.SshNet/ISession.cs b/src/Renci.SshNet/ISession.cs index bb778d91..cd950da5 100644 --- a/src/Renci.SshNet/ISession.cs +++ b/src/Renci.SshNet/ISession.cs @@ -156,6 +156,29 @@ namespace Renci.SshNet /// void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout); + /// + /// Waits for the specified to receive a signal, using a + /// to specify the time interval. + /// + /// The that should be signaled. + /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. + /// When this method returns , contains the . + /// + /// A . + /// + WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exception exception); + + /// + /// Waits for the specified to receive a signal, using a + /// to specify the time interval. + /// + /// The that should be signaled. + /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. + /// + /// A . + /// + WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout); + /// /// Occurs when message received /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs index be2d9c01..c8af4724 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs @@ -1,6 +1,4 @@ -using Renci.SshNet.Common; - -namespace Renci.SshNet.Messages.Transport +namespace Renci.SshNet.Messages.Transport { /// /// Represents SSH_MSG_KEX_DH_GEX_INIT message. @@ -8,15 +6,10 @@ namespace Renci.SshNet.Messages.Transport [Message("SSH_MSG_KEX_DH_GEX_INIT", 32)] internal class KeyExchangeDhGroupExchangeInit : Message, IKeyExchangedAllowed { - private byte[] _eBytes; - /// /// Gets the E value. /// - public BigInteger E - { - get { return _eBytes.ToBigInteger(); } - } + public byte[] E { get; private set; } /// /// Gets the size of the message in bytes. @@ -30,7 +23,7 @@ namespace Renci.SshNet.Messages.Transport { var capacity = base.BufferCapacity; capacity += 4; // E length - capacity += _eBytes.Length; // E + capacity += E.Length; // E return capacity; } } @@ -39,9 +32,9 @@ namespace Renci.SshNet.Messages.Transport /// Initializes a new instance of the class. /// /// The client exchange value. - public KeyExchangeDhGroupExchangeInit(BigInteger clientExchangeValue) + public KeyExchangeDhGroupExchangeInit(byte[] clientExchangeValue) { - _eBytes = clientExchangeValue.ToByteArray().Reverse(); + E = clientExchangeValue; } /// @@ -49,7 +42,7 @@ namespace Renci.SshNet.Messages.Transport /// protected override void LoadData() { - _eBytes = ReadBinary(); + E = ReadBinary(); } /// @@ -57,7 +50,7 @@ namespace Renci.SshNet.Messages.Transport /// protected override void SaveData() { - WriteBinaryString(_eBytes); + WriteBinaryString(E); } internal override void Process(Session session) diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs index 8caa1244..88bad74e 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs @@ -10,8 +10,6 @@ namespace Renci.SshNet.Messages.Transport { internal const byte MessageNumber = 33; - private byte[] _fBytes; - /// /// Gets server public host key and certificates /// @@ -21,10 +19,7 @@ namespace Renci.SshNet.Messages.Transport /// /// Gets the F value. /// - public BigInteger F - { - get { return _fBytes.ToBigInteger(); } - } + public byte[] F { get; private set; } /// /// Gets the signature of H. @@ -46,7 +41,7 @@ namespace Renci.SshNet.Messages.Transport capacity += 4; // HostKey length capacity += HostKey.Length; // HostKey capacity += 4; // F length - capacity += _fBytes.Length; // F + capacity += F.Length; // F capacity += 4; // Signature length capacity += Signature.Length; // Signature return capacity; @@ -59,7 +54,7 @@ namespace Renci.SshNet.Messages.Transport protected override void LoadData() { HostKey = ReadBinary(); - _fBytes = ReadBinary(); + F = ReadBinary(); Signature = ReadBinary(); } @@ -69,7 +64,7 @@ namespace Renci.SshNet.Messages.Transport protected override void SaveData() { WriteBinaryString(HostKey); - WriteBinaryString(_fBytes); + WriteBinaryString(F); WriteBinaryString(Signature); } diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs index 8d990e26..9d1d7685 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs @@ -1,6 +1,4 @@ -using Renci.SshNet.Common; - -namespace Renci.SshNet.Messages.Transport +namespace Renci.SshNet.Messages.Transport { /// /// Represents SSH_MSG_KEXDH_INIT message. @@ -8,15 +6,10 @@ namespace Renci.SshNet.Messages.Transport [Message("SSH_MSG_KEXDH_INIT", 30)] internal class KeyExchangeDhInitMessage : Message, IKeyExchangedAllowed { - private byte[] _eBytes; - /// /// Gets the E value. /// - public BigInteger E - { - get { return _eBytes.ToBigInteger(); } - } + public byte[] E { get; private set; } /// /// Gets the size of the message in bytes. @@ -30,7 +23,7 @@ namespace Renci.SshNet.Messages.Transport { var capacity = base.BufferCapacity; capacity += 4; // E length - capacity += _eBytes.Length; // E + capacity += E.Length; // E return capacity; } } @@ -39,9 +32,9 @@ namespace Renci.SshNet.Messages.Transport /// Initializes a new instance of the class. /// /// The client exchange value. - public KeyExchangeDhInitMessage(BigInteger clientExchangeValue) + public KeyExchangeDhInitMessage(byte[] clientExchangeValue) { - _eBytes = clientExchangeValue.ToByteArray().Reverse(); + E = clientExchangeValue; } /// @@ -49,7 +42,7 @@ namespace Renci.SshNet.Messages.Transport /// protected override void LoadData() { - _eBytes = ReadBinary(); + E = ReadBinary(); } /// @@ -57,7 +50,7 @@ namespace Renci.SshNet.Messages.Transport /// protected override void SaveData() { - WriteBinaryString(_eBytes); + WriteBinaryString(E); } internal override void Process(Session session) diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs index 474e29c6..105e5797 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs @@ -1,6 +1,4 @@ -using Renci.SshNet.Common; - -namespace Renci.SshNet.Messages.Transport +namespace Renci.SshNet.Messages.Transport { /// /// Represents SSH_MSG_KEXDH_REPLY message. @@ -8,8 +6,6 @@ namespace Renci.SshNet.Messages.Transport [Message("SSH_MSG_KEXDH_REPLY", 31)] public class KeyExchangeDhReplyMessage : Message { - private byte[] _fBytes; - /// /// Gets server public host key and certificates /// @@ -19,10 +15,7 @@ namespace Renci.SshNet.Messages.Transport /// /// Gets the F value. /// - public BigInteger F - { - get { return _fBytes.ToBigInteger(); } - } + public byte[] F { get; private set; } /// /// Gets the signature of H. @@ -44,7 +37,7 @@ namespace Renci.SshNet.Messages.Transport capacity += 4; // HostKey length capacity += HostKey.Length; // HostKey capacity += 4; // F length - capacity += _fBytes.Length; // F + capacity += F.Length; // F capacity += 4; // Signature length capacity += Signature.Length; // Signature return capacity; @@ -57,7 +50,7 @@ namespace Renci.SshNet.Messages.Transport protected override void LoadData() { HostKey = ReadBinary(); - _fBytes = ReadBinary(); + F = ReadBinary(); Signature = ReadBinary(); } @@ -67,7 +60,7 @@ namespace Renci.SshNet.Messages.Transport protected override void SaveData() { WriteBinaryString(HostKey); - WriteBinaryString(_fBytes); + WriteBinaryString(F); WriteBinaryString(Signature); } diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs index 2620d982..ddcf03f1 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs @@ -1,6 +1,4 @@ -#if false - -using System; +using System; using Renci.SshNet.Common; namespace Renci.SshNet.Messages.Transport @@ -8,7 +6,7 @@ namespace Renci.SshNet.Messages.Transport /// /// Represents SSH_MSG_KEXECDH_INIT message. /// - [Message("SSH_MSG_KEXECDH_INIT", 30)] + [Message("SSH_MSG_KEX_ECDH_INIT", 30)] internal class KeyExchangeEcdhInitMessage : Message, IKeyExchangedAllowed { /// @@ -33,6 +31,14 @@ namespace Renci.SshNet.Messages.Transport } } + /// + /// Initializes a new instance of the class. + /// + public KeyExchangeEcdhInitMessage(byte[] q) + { + QC = q; + } + /// /// Initializes a new instance of the class. /// @@ -63,7 +69,10 @@ namespace Renci.SshNet.Messages.Transport { WriteBinaryString(QC); } - } -} -#endif // false \ No newline at end of file + internal override void Process(Session session) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs index 42c36315..a194caf1 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs @@ -1,11 +1,9 @@ -#if false - -namespace Renci.SshNet.Messages.Transport +namespace Renci.SshNet.Messages.Transport { /// /// Represents SSH_MSG_KEXECDH_REPLY message. /// - [Message("SSH_MSG_KEXECDH_REPLY", 31)] + [Message("SSH_MSG_KEX_ECDH_REPLY", 31)] public class KeyExchangeEcdhReplyMessage : Message { /// @@ -65,7 +63,10 @@ namespace Renci.SshNet.Messages.Transport WriteBinaryString(QS); WriteBinaryString(Signature); } - } -} -#endif // false \ No newline at end of file + internal override void Process(Session session) + { + session.OnKeyExchangeEcdhReplyMessageReceived(this); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/NetConfClient.cs b/src/Renci.SshNet/NetConfClient.cs index 6c108145..b1877c60 100644 --- a/src/Renci.SshNet/NetConfClient.cs +++ b/src/Renci.SshNet/NetConfClient.cs @@ -27,22 +27,34 @@ namespace Renci.SshNet /// The timeout to wait until an operation completes. The default value is negative /// one (-1) milliseconds, which indicates an infinite time-out period. /// + /// represents a value that is less than -1 or greater than milliseconds. public TimeSpan OperationTimeout { get { return TimeSpan.FromMilliseconds(_operationTimeout); } set { var timeoutInMilliseconds = value.TotalMilliseconds; if (timeoutInMilliseconds < -1d || timeoutInMilliseconds > int.MaxValue) - throw new ArgumentOutOfRangeException("timeout", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + throw new ArgumentOutOfRangeException("value", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); _operationTimeout = (int) timeoutInMilliseconds; } } + /// + /// Gets the current NetConf session. + /// + /// + /// The current NetConf session. + /// + internal INetConfSession NetConfSession + { + get { return _netConfSession; } + } + #region Constructors /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The connection info. /// is null. @@ -52,7 +64,7 @@ namespace Renci.SshNet } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Connection port. @@ -68,7 +80,7 @@ namespace Renci.SshNet } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Authentication username. @@ -81,7 +93,7 @@ namespace Renci.SshNet } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Connection port. @@ -97,7 +109,7 @@ namespace Renci.SshNet } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Authentication username. @@ -219,8 +231,7 @@ namespace Renci.SshNet { base.OnConnected(); - _netConfSession = ServiceFactory.CreateNetConfSession(Session, _operationTimeout); - _netConfSession.Connect(); + _netConfSession = CreateAndConnectNetConfSession(); } /// @@ -250,5 +261,20 @@ namespace Renci.SshNet } } } + + private INetConfSession CreateAndConnectNetConfSession() + { + var netConfSession = ServiceFactory.CreateNetConfSession(Session, _operationTimeout); + try + { + netConfSession.Connect(); + return netConfSession; + } + catch + { + netConfSession.Dispose(); + throw; + } + } } } diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index f4467234..31fac7db 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -11,6 +11,7 @@ using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Security.Cryptography.Ciphers.Paddings; using System.Diagnostics.CodeAnalysis; +using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet { @@ -22,7 +23,21 @@ namespace Renci.SshNet /// /// /// - /// Supports RSA and DSA private key in both OpenSSH and ssh.com format. + /// The following private keys are supported: + /// + /// + /// RSA in OpenSSL PEM and ssh.com format + /// + /// + /// DSA in OpenSSL PEM and ssh.com format + /// + /// + /// ECDSA 256/384/521 in OpenSSL PEM format + /// + /// + /// ED25519 in OpenSSH key format + /// + /// /// /// /// The following encryption algorithms are supported: @@ -197,6 +212,16 @@ namespace Renci.SshNet _key = new DsaKey(decryptedData); HostKey = new KeyHostAlgorithm("ssh-dss", _key); break; +#if FEATURE_ECDSA + case "EC": + _key = new EcdsaKey(decryptedData); + HostKey = new KeyHostAlgorithm(_key.ToString(), _key); + break; +#endif + case "OPENSSH": + _key = ParseOpenSshV1Key(decryptedData, passPhrase); + HostKey = new KeyHostAlgorithm(_key.ToString(), _key); + break; case "SSH2 ENCRYPTED": var reader = new SshDataReader(decryptedData); var magicNumber = reader.ReadUInt32(); @@ -341,6 +366,144 @@ namespace Renci.SshNet return cipher.Decrypt(cipherData); } + /// + /// Parses an OpenSSH V1 key file (i.e. ED25519 key) according to the the key spec: + /// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key. + /// + /// the key file data (i.e. base64 encoded data between the header/footer) + /// passphrase or null if there isn't one + /// + private ED25519Key ParseOpenSshV1Key(byte [] keyFileData, string passPhrase) + { + var keyReader = new SshDataReader(keyFileData); + + //check magic header + var authMagic = Encoding.UTF8.GetBytes("openssh-key-v1\0"); + var keyHeaderBytes = keyReader.ReadBytes(authMagic.Length); + if (!authMagic.IsEqualTo(keyHeaderBytes)) + { + throw new SshException("This openssh key does not contain the 'openssh-key-v1' format magic header"); + } + + //cipher will be "aes256-cbc" if using a passphrase, "none" otherwise + var cipherName = keyReader.ReadString(Encoding.UTF8); + //key derivation function (kdf): bcrypt or nothing + var kdfName = keyReader.ReadString(Encoding.UTF8); + //kdf options length: 24 if passphrase, 0 if no passphrase + var kdfOptionsLen = (int)keyReader.ReadUInt32(); + byte[] salt = null; + int rounds = 0; + if (kdfOptionsLen > 0) + { + var saltLength = (int)keyReader.ReadUInt32(); + salt = keyReader.ReadBytes(saltLength); + rounds = (int)keyReader.ReadUInt32(); + } + + //number of public keys, only supporting 1 for now + var numberOfPublicKeys = (int)keyReader.ReadUInt32(); + if (numberOfPublicKeys != 1) + { + throw new SshException("At this time only one public key in the openssh key is supported."); + } + + //length of first public key section + keyReader.ReadUInt32(); + var keyType = keyReader.ReadString(Encoding.UTF8); + if(keyType != "ssh-ed25519") + { + throw new SshException("openssh key type: " + keyType + " is not supported"); + } + + //read public key + var publicKeyLength = (int)keyReader.ReadUInt32(); //32 + var publicKey = keyReader.ReadBytes(publicKeyLength); + + //possibly encrypted private key + var privateKeyLength = (int)keyReader.ReadUInt32(); + var privateKeyBytes = keyReader.ReadBytes(privateKeyLength); + + //decrypt private key if necessary + if (cipherName == "aes256-cbc") + { + if (string.IsNullOrEmpty(passPhrase)) + { + throw new SshPassPhraseNullOrEmptyException("Private key is encrypted but passphrase is empty."); + } + if (string.IsNullOrEmpty(kdfName) || kdfName != "bcrypt") + { + throw new SshException("kdf " + kdfName + " is not supported for openssh key file"); + } + + //inspired by the SSHj library (https://github.com/hierynomus/sshj) + //apply the kdf to derive a key and iv from the passphrase + var passPhraseBytes = Encoding.UTF8.GetBytes(passPhrase); + byte[] keyiv = new byte[48]; + new BCrypt().Pbkdf(passPhraseBytes, salt, rounds, keyiv); + byte[] key = new byte[32]; + Array.Copy(keyiv, 0, key, 0, 32); + byte[] iv = new byte[16]; + Array.Copy(keyiv, 32, iv, 0, 16); + + //now that we have the key/iv, use a cipher to decrypt the bytes + var cipher = new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); + privateKeyBytes = cipher.Decrypt(privateKeyBytes); + } + else if (cipherName != "none") + { + throw new SshException("cipher name " + cipherName + " for openssh key file is not supported"); + } + + //validate private key length + privateKeyLength = privateKeyBytes.Length; + if (privateKeyLength % 8 != 0) + { + throw new SshException("The private key section must be a multiple of the block size (8)"); + } + + //now parse the data we called the private key, it actually contains the public key again + //so we need to parse through it to get the private key bytes, plus there's some + //validation we need to do. + var privateKeyReader = new SshDataReader(privateKeyBytes); + + //check ints should match, they wouldn't match for example if the wrong passphrase was supplied + int checkInt1 = (int)privateKeyReader.ReadUInt32(); + int checkInt2 = (int)privateKeyReader.ReadUInt32(); + if (checkInt1 != checkInt2) + { + throw new SshException("The checkints differed, the openssh key was not correctly decoded."); + } + + //key type, we already know it is ssh-ed25519 + privateKeyReader.ReadString(Encoding.UTF8); + + //public key length/bytes (again) + var publicKeyLength2 = (int)privateKeyReader.ReadUInt32(); + privateKeyReader.ReadBytes(publicKeyLength2); + + //length of private and public key (64) + privateKeyReader.ReadUInt32(); + var unencryptedPrivateKey = privateKeyReader.ReadBytes(32); + //public key (again) + privateKeyReader.ReadBytes(32); + + //comment, we don't need this but we could log it, not sure if necessary + var comment = privateKeyReader.ReadString(Encoding.UTF8); + + //The list of privatekey/comment pairs is padded with the bytes 1, 2, 3, ... + //until the total length is a multiple of the cipher block size. + var padding = privateKeyReader.ReadBytes(); + for (int i = 0; i < padding.Length; i++) + { + if ((int)padding[i] != i + 1) + { + throw new SshException("Padding of openssh key format contained wrong byte at position: " + i); + } + } + + return new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey); + } + #region IDisposable Members private bool _isDisposed; @@ -409,6 +572,11 @@ namespace Renci.SshNet return base.ReadBytes(length); } + public new byte[] ReadBytes() + { + return base.ReadBytes(); + } + /// /// Reads next mpint data type from internal buffer where length specified in bits. /// diff --git a/src/Renci.SshNet/Properties/AssemblyInfo.cs b/src/Renci.SshNet/Properties/AssemblyInfo.cs index 805a316c..22e4125c 100644 --- a/src/Renci.SshNet/Properties/AssemblyInfo.cs +++ b/src/Renci.SshNet/Properties/AssemblyInfo.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using System.Runtime.CompilerServices; -[assembly: AssemblyTitle("SSH.NET .NET 4.0")] +[assembly: AssemblyTitle("SSH.NET")] [assembly: Guid("ad816c5e-6f13-4589-9f3e-59523f8b77a4")] [assembly: InternalsVisibleTo("Renci.SshNet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 0598d18c..124ce9d4 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -1,480 +1,47 @@ - - + - Debug - AnyCPU - 8.0.30703 - 2.0 - {2F5F8C90-0BD1-424F-997C-7BC6280919D1} - Library - Properties - Renci.SshNet + true + true + false Renci.SshNet - v4.0 - 512 - - - true - full - false - bin\Debug\ - TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII - prompt - 4 - bin\Debug\Renci.SshNet.xml - true + ../Renci.SshNet.snk 5 - - - none - true - bin\Release\ - FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SETSOCKETOPTION;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII - prompt - 4 - bin\Release\Renci.SshNet.xml - - - true - 5 - - true + net35;net40;netstandard1.3;netstandard2.0 - - ..\Renci.SshNet.snk + + - \ No newline at end of file + + + + + + + + + + + + + + + + + + + FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA + + + FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA + + + FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_ENCODING_ASCII;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_RNG_CREATE;FEATURE_SOCKET_TAP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_DNS_TAP;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512 + + + FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_ENCODING_ASCII;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_RNG_CREATE;FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_ECDSA + + diff --git a/src/Renci.SshNet/ScpClient.NET.cs b/src/Renci.SshNet/ScpClient.NET.cs index 4665dabf..cb23cb69 100644 --- a/src/Renci.SshNet/ScpClient.NET.cs +++ b/src/Renci.SshNet/ScpClient.NET.cs @@ -20,15 +20,16 @@ namespace Renci.SshNet /// The file system info. /// A relative or absolute path for the remote file. /// is null. - /// is null or empty. + /// is null. + /// is a zero-length . /// A directory with the specified path exists on the remote host. /// The secure copy execution request was rejected by the server. public void Upload(FileInfo fileInfo, string path) { if (fileInfo == null) throw new ArgumentNullException("fileInfo"); - if (string.IsNullOrEmpty(path)) - throw new ArgumentException("path"); + + var posixPath = PosixPath.CreateAbsoluteOrRelativeFilePath(path); using (var input = ServiceFactory.CreatePipeStream()) using (var channel = Session.CreateChannelSession()) @@ -36,7 +37,9 @@ namespace Renci.SshNet channel.DataReceived += (sender, e) => input.Write(e.Data, 0, e.Data.Length); channel.Open(); - if (!channel.SendExecRequest(string.Format("scp -t {0}", _remotePathTransformation.Transform(path)))) + // Pass only the directory part of the path to the server, and use the (hidden) -d option to signal + // that we expect the target to be a directory. + if (!channel.SendExecRequest(string.Format("scp -t -d {0}", _remotePathTransformation.Transform(posixPath.Directory)))) { throw SecureExecutionRequestRejectedException(); } @@ -45,7 +48,7 @@ namespace Renci.SshNet using (var source = fileInfo.OpenRead()) { UploadTimes(channel, input, fileInfo); - UploadFileModeAndName(channel, input, source.Length, string.Empty); + UploadFileModeAndName(channel, input, source.Length, posixPath.File); UploadFileContent(channel, input, source, fileInfo.Name); } } @@ -56,16 +59,19 @@ namespace Renci.SshNet /// /// The directory info. /// A relative or absolute path for the remote directory. - /// fileSystemInfo - /// is null or empty. - /// exists on the remote host, and is not a directory. + /// is null. + /// is null. + /// is a zero-length string. + /// does not exist on the remote host, is not a directory or the user does not have the required permission. /// The secure copy execution request was rejected by the server. public void Upload(DirectoryInfo directoryInfo, string path) { if (directoryInfo == null) throw new ArgumentNullException("directoryInfo"); - if (string.IsNullOrEmpty(path)) - throw new ArgumentException("path"); + if (path == null) + throw new ArgumentNullException("path"); + if (path.Length == 0) + throw new ArgumentException("The path cannot be a zero-length string.", "path"); using (var input = ServiceFactory.CreatePipeStream()) using (var channel = Session.CreateChannelSession()) @@ -73,15 +79,18 @@ namespace Renci.SshNet channel.DataReceived += (sender, e) => input.Write(e.Data, 0, e.Data.Length); channel.Open(); - // start recursive upload - if (!channel.SendExecRequest(string.Format("scp -rt {0}", _remotePathTransformation.Transform(path)))) + // start copy with the following options: + // -p preserve modification and access times + // -r copy directories recursively + // -d expect path to be a directory + // -t copy to remote + if (!channel.SendExecRequest(string.Format("scp -r -p -d -t {0}", _remotePathTransformation.Transform(path)))) { throw SecureExecutionRequestRejectedException(); } + CheckReturnCode(input); - UploadTimes(channel, input, directoryInfo); - UploadDirectoryModeAndName(channel, input, "."); UploadDirectoryContent(channel, input, directoryInfo); } } @@ -311,5 +320,39 @@ namespace Renci.SshNet SendErrorConfirmation(channel, string.Format("\"{0}\" is not valid protocol message.", message)); } } + + /// + /// Return a value indicating whether the specified path is a valid SCP file path. + /// + /// The path to verify. + /// + /// if is a valid SCP file path; otherwise, . + /// + /// + /// To match OpenSSH behavior (introduced as a result of CVE-2018-20685), a file path is considered + /// invalid in any of the following conditions: + /// + /// + /// is a zero-length string. + /// + /// + /// is ".". + /// + /// + /// is "..". + /// + /// + /// contains a forward slash (/). + /// + /// + /// + private static bool IsValidScpFilePath(string path) + { + return path != null && + path.Length != 0 && + path != "." && + path != ".." && + path.IndexOf('/') == -1; + } } } diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index 8fb23ebc..8a252cac 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -93,7 +93,7 @@ namespace Renci.SshNet #region Constructors /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The connection info. /// is null. @@ -103,7 +103,7 @@ namespace Renci.SshNet } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Connection port. @@ -119,7 +119,7 @@ namespace Renci.SshNet } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Authentication username. @@ -132,7 +132,7 @@ namespace Renci.SshNet } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Connection port. @@ -148,7 +148,7 @@ namespace Renci.SshNet } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Authentication username. @@ -202,28 +202,30 @@ namespace Renci.SshNet /// /// The to upload. /// A relative or absolute path for the remote file. + /// is null. + /// is a zero-length . /// A directory with the specified path exists on the remote host. /// The secure copy execution request was rejected by the server. public void Upload(Stream source, string path) { + var posixPath = PosixPath.CreateAbsoluteOrRelativeFilePath(path); + using (var input = ServiceFactory.CreatePipeStream()) using (var channel = Session.CreateChannelSession()) { channel.DataReceived += (sender, e) => input.Write(e.Data, 0, e.Data.Length); channel.Open(); - // pass the full path to ensure the server does not create the directory part - // as a file in case the directory does not exist - if (!channel.SendExecRequest(string.Format("scp -t {0}", _remotePathTransformation.Transform(path)))) + // Pass only the directory part of the path to the server, and use the (hidden) -d option to signal + // that we expect the target to be a directory. + if (!channel.SendExecRequest(string.Format("scp -t -d {0}", _remotePathTransformation.Transform(posixPath.Directory)))) { throw SecureExecutionRequestRejectedException(); } CheckReturnCode(input); - // specify a zero-length file name to avoid creating a file with absolute - // path '/' if directory '' already exists - UploadFileModeAndName(channel, input, source.Length, string.Empty); - UploadFileContent(channel, input, source, PosixPath.GetFileName(path)); + UploadFileModeAndName(channel, input, source.Length, posixPath.File); + UploadFileContent(channel, input, source, posixPath.File); } } diff --git a/src/Renci.SshNet/Security/BouncyCastle/asn1/sec/SECNamedCurves.cs b/src/Renci.SshNet/Security/BouncyCastle/asn1/sec/SECNamedCurves.cs new file mode 100644 index 00000000..dc9462b3 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/asn1/sec/SECNamedCurves.cs @@ -0,0 +1,121 @@ +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9; +using Renci.SshNet.Security.Org.BouncyCastle.Math; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities.Encoders; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Asn1.Sec +{ + internal sealed class SecNamedCurves + { + /* + * secp256r1 + */ + internal class Secp256r1Holder + : X9ECParametersHolder + { + private Secp256r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp256r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1 + BigInteger p = FromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = FromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = FromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"); + byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90"); + BigInteger n = FromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); + BigInteger h = BigInteger.One; + + ECCurve curve = new FpCurve(p, a, b, n, h); + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp384r1 + */ + internal class Secp384r1Holder + : X9ECParametersHolder + { + private Secp384r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp384r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^384 - 2^128 - 2^96 + 2^32 - 1 + BigInteger p = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); + BigInteger a = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"); + BigInteger b = FromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"); + byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); + BigInteger n = FromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); + BigInteger h = BigInteger.One; + + ECCurve curve = new FpCurve(p, a, b, n, h); + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + /* + * secp521r1 + */ + internal class Secp521r1Holder + : X9ECParametersHolder + { + private Secp521r1Holder() {} + + internal static readonly X9ECParametersHolder Instance = new Secp521r1Holder(); + + protected override X9ECParameters CreateParameters() + { + // p = 2^521 - 1 + BigInteger p = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + BigInteger a = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"); + BigInteger b = FromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"); + byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA"); + BigInteger n = FromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); + BigInteger h = BigInteger.One; + + ECCurve curve = new FpCurve(p, a, b, n, h); + X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04" + + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" + + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); + + return new X9ECParameters(curve, G, n, h, S); + } + } + + public static X9ECParameters GetByName( + string name) + { + switch(name) + { + case "P-256": + case "secp256r1": + return Secp256r1Holder.Instance.Parameters; + case "P-384": + case "secp384r1": + return Secp384r1Holder.Instance.Parameters; + case "P-521": + case "secp521r1": + return Secp521r1Holder.Instance.Parameters; + } + + return null; + } + + private static BigInteger FromHex(string hex) + { + return new BigInteger(1, Hex.Decode(hex)); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9Curve.cs b/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9Curve.cs new file mode 100644 index 00000000..1faf777a --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9Curve.cs @@ -0,0 +1,40 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9 +{ + internal class X9Curve + { + private readonly ECCurve curve; + private readonly byte[] seed; + + public X9Curve( + ECCurve curve) + : this(curve, null) + { + } + + public X9Curve( + ECCurve curve, + byte[] seed) + { + if (curve == null) + throw new ArgumentNullException("curve"); + + this.curve = curve; + this.seed = Arrays.Clone(seed); + } + + public ECCurve Curve + { + get { return curve; } + } + + public byte[] GetSeed() + { + return Arrays.Clone(seed); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECParameters.cs b/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECParameters.cs new file mode 100644 index 00000000..f8234b96 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECParameters.cs @@ -0,0 +1,93 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9 +{ + internal class X9ECParameters + { + private byte[] seed; + + public static X9ECParameters GetInstance(Object obj) + { + if (obj is X9ECParameters) + return (X9ECParameters)obj; + + return null; + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n) + : this(curve, g, n, null, null) + { + } + + public X9ECParameters( + ECCurve curve, + X9ECPoint g, + BigInteger n, + BigInteger h) + : this(curve, g, n, h, null) + { + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h) + : this(curve, g, n, h, null) + { + } + + public X9ECParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) + : this(curve, new X9ECPoint(g), n, h, seed) + { + } + + public X9ECParameters( + ECCurve curve, + X9ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) + { + this.Curve = curve; + this.BaseEntry = g; + this.N = n; + this.H = h; + this.seed = seed; + } + + public ECCurve Curve { get; private set; } + + public ECPoint G + { + get { return BaseEntry.Point; } + } + + public BigInteger N { get; private set; } + + public BigInteger H { get; private set; } + + public byte[] GetSeed() + { + return seed; + } + + public X9Curve CurveEntry + { + get { return new X9Curve(Curve, seed); } + } + + public X9ECPoint BaseEntry { get; private set; } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECParametersHolder.cs b/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECParametersHolder.cs new file mode 100644 index 00000000..8574cb03 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECParametersHolder.cs @@ -0,0 +1,25 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9 +{ + internal abstract class X9ECParametersHolder + { + private X9ECParameters parameters; + + public X9ECParameters Parameters + { + get + { + lock (this) + { + if (parameters == null) + { + parameters = CreateParameters(); + } + + return parameters; + } + } + } + + protected abstract X9ECParameters CreateParameters(); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECPoint.cs b/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECPoint.cs new file mode 100644 index 00000000..f4db7106 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/asn1/x9/X9ECPoint.cs @@ -0,0 +1,57 @@ +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9 +{ + internal class X9ECPoint + { + private readonly byte[] encoding; + + private ECCurve c; + private ECPoint p; + + public X9ECPoint(ECPoint p) + : this(p, false) + { + } + + public X9ECPoint(ECPoint p, bool compressed) + { + this.p = p.Normalize(); + this.encoding = p.GetEncoded(compressed); + } + + public X9ECPoint(ECCurve c, byte[] encoding) + { + this.c = c; + this.encoding = Arrays.Clone(encoding); + } + + public byte[] GetPointEncoding() + { + return Arrays.Clone(encoding); + } + + public ECPoint Point + { + get + { + if (p == null) + { + p = c.DecodePoint(encoding).Normalize(); + } + + return p; + } + } + + public bool IsPointCompressed + { + get + { + byte[] octets = encoding; + return octets != null && octets.Length > 0 && (octets[0] == 2 || octets[0] == 3); + } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/AsymmetricCipherKeyPair.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/AsymmetricCipherKeyPair.cs new file mode 100644 index 00000000..e53a66fe --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/AsymmetricCipherKeyPair.cs @@ -0,0 +1,33 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto +{ + internal class AsymmetricCipherKeyPair + { + private readonly AsymmetricKeyParameter publicParameter; + private readonly AsymmetricKeyParameter privateParameter; + + public AsymmetricCipherKeyPair( + AsymmetricKeyParameter publicParameter, + AsymmetricKeyParameter privateParameter) + { + if (publicParameter.IsPrivate) + throw new ArgumentException("Expected a public key", "publicParameter"); + if (!privateParameter.IsPrivate) + throw new ArgumentException("Expected a private key", "privateParameter"); + + this.publicParameter = publicParameter; + this.privateParameter = privateParameter; + } + + public AsymmetricKeyParameter Public + { + get { return publicParameter; } + } + + public AsymmetricKeyParameter Private + { + get { return privateParameter; } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/AsymmetricKeyParameter.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/AsymmetricKeyParameter.cs new file mode 100644 index 00000000..fb66739f --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/AsymmetricKeyParameter.cs @@ -0,0 +1,42 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto +{ + internal abstract class AsymmetricKeyParameter + { + private readonly bool privateKey; + + protected AsymmetricKeyParameter( + bool privateKey) + { + this.privateKey = privateKey; + } + + public bool IsPrivate + { + get { return privateKey; } + } + + public override bool Equals( + object obj) + { + AsymmetricKeyParameter other = obj as AsymmetricKeyParameter; + + if (other == null) + { + return false; + } + + return Equals(other); + } + + protected bool Equals( + AsymmetricKeyParameter other) + { + return privateKey == other.privateKey; + } + + public override int GetHashCode() + { + return privateKey.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/IAsymmetricCipherKeyPairGenerator.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/IAsymmetricCipherKeyPairGenerator.cs new file mode 100644 index 00000000..6c19d1ea --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/IAsymmetricCipherKeyPairGenerator.cs @@ -0,0 +1,9 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto +{ + internal interface IAsymmetricCipherKeyPairGenerator + { + void Init(KeyGenerationParameters parameters); + + AsymmetricCipherKeyPair GenerateKeyPair(); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/IDigest.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/IDigest.cs new file mode 100644 index 00000000..2ff19e3a --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/IDigest.cs @@ -0,0 +1,61 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto +{ + /** + * interface that a message digest conforms to. + */ + internal interface IDigest + { + /** + * return the algorithm name + * + * @return the algorithm name + */ + string AlgorithmName { get; } + + /** + * return the size, in bytes, of the digest produced by this message digest. + * + * @return the size, in bytes, of the digest produced by this message digest. + */ + int GetDigestSize(); + + /** + * return the size, in bytes, of the internal buffer used by this digest. + * + * @return the size, in bytes, of the internal buffer used by this digest. + */ + int GetByteLength(); + + /** + * update the message digest with a single byte. + * + * @param inByte the input byte to be entered. + */ + void Update(byte input); + + /** + * update the message digest with a block of bytes. + * + * @param input the byte array containing the data. + * @param inOff the offset into the byte array where the data starts. + * @param len the length of the data. + */ + void BlockUpdate(byte[] input, int inOff, int length); + + /** + * Close the digest, producing the final digest value. The doFinal + * call leaves the digest reset. + * + * @param output the array the digest is to be copied into. + * @param outOff the offset into the out array the digest is to start at. + */ + int DoFinal(byte[] output, int outOff); + + /** + * reset the digest back to it's initial state. + */ + void Reset(); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/KeyGenerationParameters.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/KeyGenerationParameters.cs new file mode 100644 index 00000000..3be654e4 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/KeyGenerationParameters.cs @@ -0,0 +1,56 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Security; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto +{ + /** + * The base class for parameters to key generators. + */ + internal class KeyGenerationParameters + { + private SecureRandom random; + private int strength; + + /** + * initialise the generator with a source of randomness + * and a strength (in bits). + * + * @param random the random byte source. + * @param strength the size, in bits, of the keys we want to produce. + */ + public KeyGenerationParameters( + SecureRandom random, + int strength) + { + if (random == null) + throw new ArgumentNullException("random"); + if (strength < 1) + throw new ArgumentException("strength must be a positive value", "strength"); + + this.random = random; + this.strength = strength; + } + + /** + * return the random source associated with this + * generator. + * + * @return the generators random source. + */ + public SecureRandom Random + { + get { return random; } + } + + /** + * return the bit strength for keys produced by this generator, + * + * @return the strength of the keys this generator produces (in bits). + */ + public int Strength + { + get { return strength; } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/License.html b/src/Renci.SshNet/Security/BouncyCastle/crypto/License.html new file mode 100644 index 00000000..829aa6ba --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/License.html @@ -0,0 +1,39 @@ + + + + + License + + +

The Bouncy Castle Cryptographic C#® API

+

License:

+The Bouncy Castle License
+Copyright (c) 2000-2018 The Legion of the Bouncy Castle Inc. +(https://www.bouncycastle.org)
+Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), to deal in the +Software without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software.
+THE SOFTWARE IS PROVIDED "AS IS", +WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+
+ + diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/agreement/ECDHCBasicAgreement.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/agreement/ECDHCBasicAgreement.cs new file mode 100644 index 00000000..6814cb17 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/agreement/ECDHCBasicAgreement.cs @@ -0,0 +1,46 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Agreement +{ + internal class ECDHCBasicAgreement + { + private ECPrivateKeyParameters privKey; + + public virtual void Init( + AsymmetricKeyParameter parameters) + { + this.privKey = (ECPrivateKeyParameters)parameters; + } + + public virtual int GetFieldSize() + { + return (privKey.Parameters.Curve.FieldSize + 7) / 8; + } + + public virtual BigInteger CalculateAgreement( + ECPublicKeyParameters pubKey) + { + ECPublicKeyParameters pub = pubKey; + ECDomainParameters dp = privKey.Parameters; + if (!dp.Equals(pub.Parameters)) + throw new InvalidOperationException("ECDHC public key has wrong domain parameters"); + + BigInteger hd = dp.H.Multiply(privKey.D).Mod(dp.N); + + // Always perform calculations on the exact curve specified by our private key's parameters + ECPoint pubPoint = ECAlgorithms.CleanPoint(dp.Curve, pub.Q); + if (pubPoint.IsInfinity) + throw new InvalidOperationException("Infinity is not a valid public key for ECDHC"); + + ECPoint P = pubPoint.Multiply(hd).Normalize(); + if (P.IsInfinity) + throw new InvalidOperationException("Infinity is not a valid agreement value for ECDHC"); + + return P.AffineXCoord.ToBigInteger(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/digests/GeneralDigest.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/digests/GeneralDigest.cs new file mode 100644 index 00000000..718f34ae --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/digests/GeneralDigest.cs @@ -0,0 +1,129 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Digests +{ + internal abstract class GeneralDigest + : IDigest, IMemoable + { + private const int BYTE_LENGTH = 64; + + private byte[] xBuf; + private int xBufOff; + + private long byteCount; + + internal GeneralDigest() + { + xBuf = new byte[4]; + } + + internal GeneralDigest(GeneralDigest t) + { + xBuf = new byte[t.xBuf.Length]; + CopyIn(t); + } + + protected void CopyIn(GeneralDigest t) + { + Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length); + + xBufOff = t.xBufOff; + byteCount = t.byteCount; + } + + public void Update(byte input) + { + xBuf[xBufOff++] = input; + + if (xBufOff == xBuf.Length) + { + ProcessWord(xBuf, 0); + xBufOff = 0; + } + + byteCount++; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int length) + { + length = System.Math.Max(0, length); + + // + // fill the current word + // + int i = 0; + if (xBufOff != 0) + { + while (i < length) + { + xBuf[xBufOff++] = input[inOff + i++]; + if (xBufOff == 4) + { + ProcessWord(xBuf, 0); + xBufOff = 0; + break; + } + } + } + + // + // process whole words. + // + int limit = ((length - i) & ~3) + i; + for (; i < limit; i += 4) + { + ProcessWord(input, inOff + i); + } + + // + // load in the remainder. + // + while (i < length) + { + xBuf[xBufOff++] = input[inOff + i++]; + } + + byteCount += length; + } + + public void Finish() + { + long bitLength = (byteCount << 3); + + // + // add the pad bytes. + // + Update((byte)128); + + while (xBufOff != 0) Update((byte)0); + ProcessLength(bitLength); + ProcessBlock(); + } + + public virtual void Reset() + { + byteCount = 0; + xBufOff = 0; + Array.Clear(xBuf, 0, xBuf.Length); + } + + public int GetByteLength() + { + return BYTE_LENGTH; + } + + internal abstract void ProcessWord(byte[] input, int inOff); + internal abstract void ProcessLength(long bitLength); + internal abstract void ProcessBlock(); + public abstract string AlgorithmName { get; } + public abstract int GetDigestSize(); + public abstract int DoFinal(byte[] output, int outOff); + public abstract IMemoable Copy(); + public abstract void Reset(IMemoable t); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/digests/Sha256Digest.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/digests/Sha256Digest.cs new file mode 100644 index 00000000..da700fcf --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/digests/Sha256Digest.cs @@ -0,0 +1,280 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Utilities; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Digests +{ + internal class Sha256Digest + : GeneralDigest + { + private const int DigestLength = 32; + + private uint H1, H2, H3, H4, H5, H6, H7, H8; + private uint[] X = new uint[64]; + private int xOff; + + public Sha256Digest() + { + initHs(); + } + + /** + * Copy constructor. This will copy the state of the provided + * message digest. + */ + public Sha256Digest(Sha256Digest t) : base(t) + { + CopyIn(t); + } + + private void CopyIn(Sha256Digest t) + { + base.CopyIn(t); + + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + H5 = t.H5; + H6 = t.H6; + H7 = t.H7; + H8 = t.H8; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName + { + get { return "SHA-256"; } + } + + public override int GetDigestSize() + { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) + { + X[xOff] = Pack.BE_To_UInt32(input, inOff); + + if (++xOff == 16) + { + ProcessBlock(); + } + } + + internal override void ProcessLength( + long bitLength) + { + if (xOff > 14) + { + ProcessBlock(); + } + + X[14] = (uint)((ulong)bitLength >> 32); + X[15] = (uint)((ulong)bitLength); + } + + public override int DoFinal( + byte[] output, + int outOff) + { + Finish(); + + Pack.UInt32_To_BE((uint)H1, output, outOff); + Pack.UInt32_To_BE((uint)H2, output, outOff + 4); + Pack.UInt32_To_BE((uint)H3, output, outOff + 8); + Pack.UInt32_To_BE((uint)H4, output, outOff + 12); + Pack.UInt32_To_BE((uint)H5, output, outOff + 16); + Pack.UInt32_To_BE((uint)H6, output, outOff + 20); + Pack.UInt32_To_BE((uint)H7, output, outOff + 24); + Pack.UInt32_To_BE((uint)H8, output, outOff + 28); + + Reset(); + + return DigestLength; + } + + public override void Reset() + { + base.Reset(); + + initHs(); + + xOff = 0; + Array.Clear(X, 0, X.Length); + } + + private void initHs() + { + /* SHA-256 initial hash value + * The first 32 bits of the fractional parts of the square roots + * of the first eight prime numbers + */ + H1 = 0x6a09e667; + H2 = 0xbb67ae85; + H3 = 0x3c6ef372; + H4 = 0xa54ff53a; + H5 = 0x510e527f; + H6 = 0x9b05688c; + H7 = 0x1f83d9ab; + H8 = 0x5be0cd19; + } + + internal override 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. + // + xOff = 0; + Array.Clear(X, 0, 16); + } + + private static uint Sum1Ch( + uint x, + uint y, + uint 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 (((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); + } + + 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 + }; + + public override IMemoable Copy() + { + return new Sha256Digest(this); + } + + public override void Reset(IMemoable other) + { + Sha256Digest d = (Sha256Digest)other; + + CopyIn(d); + } + + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/generators/ECKeyPairGenerator.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/generators/ECKeyPairGenerator.cs new file mode 100644 index 00000000..446c279c --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/generators/ECKeyPairGenerator.cs @@ -0,0 +1,91 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters; +using Renci.SshNet.Security.Org.BouncyCastle.Math; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier; +using Renci.SshNet.Security.Org.BouncyCastle.Security; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Generators +{ + internal class ECKeyPairGenerator + : IAsymmetricCipherKeyPairGenerator + { + private readonly string algorithm; + + private ECDomainParameters parameters; + private SecureRandom random; + + public ECKeyPairGenerator() + : this("EC") + { + } + + public ECKeyPairGenerator( + string algorithm) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + + this.algorithm = ECKeyParameters.VerifyAlgorithmName(algorithm); + } + + public void Init( + KeyGenerationParameters parameters) + { + if (parameters is ECKeyGenerationParameters) + { + ECKeyGenerationParameters ecP = (ECKeyGenerationParameters) parameters; + + this.parameters = ecP.DomainParameters; + } + + this.random = parameters.Random; + + if (this.random == null) + { + this.random = new SecureRandom(); + } + } + + public AsymmetricCipherKeyPair GenerateKeyPair() + { + BigInteger n = parameters.N; + BigInteger d; + int minWeight = n.BitLength >> 2; + + for (;;) + { + d = new BigInteger(n.BitLength, random); + + if (d.CompareTo(BigInteger.Two) < 0 || d.CompareTo(n) >= 0) + continue; + + if (WNafUtilities.GetNafWeight(d) < minWeight) + continue; + + break; + } + + ECPoint q = CreateBasePointMultiplier().Multiply(parameters.G, d); + + return new AsymmetricCipherKeyPair( + new ECPublicKeyParameters(algorithm, q, parameters), + new ECPrivateKeyParameters(algorithm, d, parameters)); + } + + protected virtual ECMultiplier CreateBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } + + internal static ECPublicKeyParameters GetCorrespondingPublicKey( + ECPrivateKeyParameters privKey) + { + ECDomainParameters ec = privKey.Parameters; + ECPoint q = new FixedPointCombMultiplier().Multiply(ec.G, privKey.D); + + return new ECPublicKeyParameters(privKey.AlgorithmName, q, ec); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECDomainParameters.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECDomainParameters.cs new file mode 100644 index 00000000..1d1b037f --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECDomainParameters.cs @@ -0,0 +1,91 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters +{ + internal class ECDomainParameters + { + internal ECCurve curve; + internal byte[] seed; + internal ECPoint g; + internal BigInteger n; + internal BigInteger h; + internal BigInteger hInv; + + public ECDomainParameters( + ECCurve curve, + ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) + { + if (curve == null) + throw new ArgumentNullException("curve"); + if (g == null) + throw new ArgumentNullException("g"); + if (n == null) + throw new ArgumentNullException("n"); + // we can't check for h == null here as h is optional in X9.62 as it is not required for ECDSA + + this.curve = curve; + this.g = Validate(curve, g); + this.n = n; + this.h = h; + this.seed = Arrays.Clone(seed); + } + + public ECCurve Curve + { + get { return curve; } + } + + public ECPoint G + { + get { return g; } + } + + public BigInteger N + { + get { return n; } + } + + public BigInteger H + { + get { return h; } + } + + public BigInteger HInv + { + get + { + lock (this) + { + if (hInv == null) + { + hInv = h.ModInverse(n); + } + return hInv; + } + } + } + + internal static ECPoint Validate(ECCurve c, ECPoint q) + { + if (q == null) + throw new ArgumentException("Point has null value", "q"); + + q = ECAlgorithms.ImportPoint(c, q).Normalize(); + + if (q.IsInfinity) + throw new ArgumentException("Point at infinity", "q"); + + if (!q.IsValid()) + throw new ArgumentException("Point not on curve", "q"); + + return q; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECKeyGenerationParameters.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECKeyGenerationParameters.cs new file mode 100644 index 00000000..88e33e3d --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECKeyGenerationParameters.cs @@ -0,0 +1,23 @@ +using Renci.SshNet.Security.Org.BouncyCastle.Security; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters +{ + internal class ECKeyGenerationParameters + : KeyGenerationParameters + { + private readonly ECDomainParameters domainParams; + + public ECKeyGenerationParameters( + ECDomainParameters domainParameters, + SecureRandom random) + : base(random, domainParameters.N.BitLength) + { + this.domainParams = domainParameters; + } + + public ECDomainParameters DomainParameters + { + get { return domainParams; } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECKeyParameters.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECKeyParameters.cs new file mode 100644 index 00000000..50426c54 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECKeyParameters.cs @@ -0,0 +1,79 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Security; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters +{ + internal abstract class ECKeyParameters + : AsymmetricKeyParameter + { + private static readonly string[] algorithms = { "EC", "ECDH" }; + + private readonly string algorithm; + private readonly ECDomainParameters parameters; + + protected ECKeyParameters( + string algorithm, + bool isPrivate, + ECDomainParameters parameters) + : base(isPrivate) + { + if (algorithm == null) + throw new ArgumentNullException("algorithm"); + if (parameters == null) + throw new ArgumentNullException("parameters"); + + this.algorithm = VerifyAlgorithmName(algorithm); + this.parameters = parameters; + } + + public string AlgorithmName + { + get { return algorithm; } + } + + public ECDomainParameters Parameters + { + get { return parameters; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ECDomainParameters other = obj as ECDomainParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECKeyParameters other) + { + return parameters.Equals(other.parameters) && base.Equals(other); + } + + public override int GetHashCode() + { + return parameters.GetHashCode() ^ base.GetHashCode(); + } + + internal ECKeyGenerationParameters CreateKeyGenerationParameters( + SecureRandom random) + { + return new ECKeyGenerationParameters(parameters, random); + } + + internal static string VerifyAlgorithmName(string algorithm) + { + if (Array.IndexOf(algorithms, algorithm, 0, algorithms.Length) < 0) + throw new ArgumentException("unrecognised algorithm: " + algorithm, "algorithm"); + return algorithm.ToUpper(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECPrivateKeyParameters.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECPrivateKeyParameters.cs new file mode 100644 index 00000000..a11233c8 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECPrivateKeyParameters.cs @@ -0,0 +1,61 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters +{ + internal class ECPrivateKeyParameters + : ECKeyParameters + { + private readonly BigInteger d; + + public ECPrivateKeyParameters( + BigInteger d, + ECDomainParameters parameters) + : this("EC", d, parameters) + { + } + + public ECPrivateKeyParameters( + string algorithm, + BigInteger d, + ECDomainParameters parameters) + : base(algorithm, true, parameters) + { + if (d == null) + throw new ArgumentNullException("d"); + + this.d = d; + } + + public BigInteger D + { + get { return d; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + ECPrivateKeyParameters other = obj as ECPrivateKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECPrivateKeyParameters other) + { + return d.Equals(other.d) && base.Equals(other); + } + + public override int GetHashCode() + { + return d.GetHashCode() ^ base.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECPublicKeyParameters.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECPublicKeyParameters.cs new file mode 100644 index 00000000..6b1f3ec5 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/parameters/ECPublicKeyParameters.cs @@ -0,0 +1,60 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters +{ + internal class ECPublicKeyParameters + : ECKeyParameters + { + private readonly ECPoint q; + + public ECPublicKeyParameters( + ECPoint q, + ECDomainParameters parameters) + : this("EC", q, parameters) + { + } + + public ECPublicKeyParameters( + string algorithm, + ECPoint q, + ECDomainParameters parameters) + : base(algorithm, false, parameters) + { + if (q == null) + throw new ArgumentNullException("q"); + + this.q = ECDomainParameters.Validate(Parameters.Curve, q); + } + + public ECPoint Q + { + get { return q; } + } + + public override bool Equals(object obj) + { + if (obj == this) + return true; + + ECPublicKeyParameters other = obj as ECPublicKeyParameters; + + if (other == null) + return false; + + return Equals(other); + } + + protected bool Equals( + ECPublicKeyParameters other) + { + return q.Equals(other.q) && base.Equals(other); + } + + public override int GetHashCode() + { + return q.GetHashCode() ^ base.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/CryptoApiRandomGenerator.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/CryptoApiRandomGenerator.cs new file mode 100644 index 00000000..5dd468b0 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/CryptoApiRandomGenerator.cs @@ -0,0 +1,69 @@ +using System; +using System.Security.Cryptography; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Prng +{ + internal class CryptoApiRandomGenerator + : IRandomGenerator + { + private readonly RandomNumberGenerator rndProv; + + public CryptoApiRandomGenerator() +#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP + : this(Abstractions.CryptoAbstraction.CreateRandomNumberGenerator()) +#endif + { + } + + public CryptoApiRandomGenerator(RandomNumberGenerator rng) + { + this.rndProv = rng; + } + + #region IRandomGenerator Members + + public virtual void AddSeedMaterial(byte[] seed) + { + // We don't care about the seed + } + + public virtual void AddSeedMaterial(long seed) + { + // We don't care about the seed + } + + public virtual void NextBytes(byte[] bytes) + { +#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP + rndProv.GetBytes(bytes); +#else + if (bytes == null) + throw new ArgumentNullException("bytes"); + + var buffer = Windows.Security.Cryptography.CryptographicBuffer.GenerateRandom((uint)bytes.Length); + System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.CopyTo(buffer, bytes); +#endif + } + + public virtual void NextBytes(byte[] bytes, int start, int len) + { + if (start < 0) + throw new ArgumentException("Start offset cannot be negative", "start"); + if (bytes.Length < (start + len)) + throw new ArgumentException("Byte array too small for requested offset and length"); + + if (bytes.Length == len && start == 0) + { + NextBytes(bytes); + } + else + { + byte[] tmpBuf = new byte[len]; + NextBytes(tmpBuf); + Array.Copy(tmpBuf, 0, bytes, start, len); + } + } + + #endregion + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/DigestRandomGenerator.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/DigestRandomGenerator.cs new file mode 100644 index 00000000..b0b69b7b --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/DigestRandomGenerator.cs @@ -0,0 +1,117 @@ +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Prng +{ + internal class DigestRandomGenerator + : IRandomGenerator + { + private const long CYCLE_COUNT = 10; + + private long stateCounter; + private long seedCounter; + private IDigest digest; + private byte[] state; + private byte[] seed; + + public DigestRandomGenerator( + IDigest digest) + { + this.digest = digest; + + this.seed = new byte[digest.GetDigestSize()]; + this.seedCounter = 1; + + this.state = new byte[digest.GetDigestSize()]; + this.stateCounter = 1; + } + + public void AddSeedMaterial( + byte[] inSeed) + { + lock (this) + { + DigestUpdate(inSeed); + DigestUpdate(seed); + DigestDoFinal(seed); + } + } + + public void AddSeedMaterial( + long rSeed) + { + lock (this) + { + DigestAddCounter(rSeed); + DigestUpdate(seed); + DigestDoFinal(seed); + } + } + + public void NextBytes( + byte[] bytes) + { + NextBytes(bytes, 0, bytes.Length); + } + + public void NextBytes( + byte[] bytes, + int start, + int len) + { + lock (this) + { + int stateOff = 0; + + GenerateState(); + + int end = start + len; + for (int i = start; i < end; ++i) + { + if (stateOff == state.Length) + { + GenerateState(); + stateOff = 0; + } + bytes[i] = state[stateOff++]; + } + } + } + + private void CycleSeed() + { + DigestUpdate(seed); + DigestAddCounter(seedCounter++); + DigestDoFinal(seed); + } + + private void GenerateState() + { + DigestAddCounter(stateCounter++); + DigestUpdate(state); + DigestUpdate(seed); + DigestDoFinal(state); + + if ((stateCounter % CYCLE_COUNT) == 0) + { + CycleSeed(); + } + } + + private void DigestAddCounter(long seedVal) + { + byte[] bytes = new byte[8]; + Pack.UInt64_To_LE((ulong)seedVal, bytes); + digest.BlockUpdate(bytes, 0, bytes.Length); + } + + private void DigestUpdate(byte[] inSeed) + { + digest.BlockUpdate(inSeed, 0, inSeed.Length); + } + + private void DigestDoFinal(byte[] result) + { + digest.DoFinal(result, 0); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/IRandomGenerator.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/IRandomGenerator.cs new file mode 100644 index 00000000..5bb0c354 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/IRandomGenerator.cs @@ -0,0 +1,26 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Prng +{ + /// Generic interface for objects generating random bytes. + internal interface IRandomGenerator + { + /// Add more seed material to the generator. + /// A byte array to be mixed into the generator's state. + void AddSeedMaterial(byte[] seed); + + /// Add more seed material to the generator. + /// A long value to be mixed into the generator's state. + void AddSeedMaterial(long seed); + + /// Fill byte array with random values. + /// Array to be filled. + void NextBytes(byte[] bytes); + + /// Fill byte array with random values. + /// Array to receive bytes. + /// Index to start filling at. + /// Length of segment to fill. + void NextBytes(byte[] bytes, int start, int len); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/util/Pack.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/util/Pack.cs new file mode 100644 index 00000000..594959eb --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/util/Pack.cs @@ -0,0 +1,345 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Crypto.Utilities +{ + internal sealed class Pack + { + private Pack() + { + } + + internal static void UInt16_To_BE(ushort n, byte[] bs) + { + bs[0] = (byte)(n >> 8); + bs[1] = (byte)(n); + } + + internal static void UInt16_To_BE(ushort n, byte[] bs, int off) + { + bs[off] = (byte)(n >> 8); + bs[off + 1] = (byte)(n); + } + + internal static ushort BE_To_UInt16(byte[] bs) + { + uint n = (uint)bs[0] << 8 + | (uint)bs[1]; + return (ushort)n; + } + + internal static ushort BE_To_UInt16(byte[] bs, int off) + { + uint n = (uint)bs[off] << 8 + | (uint)bs[off + 1]; + return (ushort)n; + } + + internal static byte[] UInt32_To_BE(uint n) + { + byte[] bs = new byte[4]; + UInt32_To_BE(n, bs, 0); + return bs; + } + + internal static void UInt32_To_BE(uint n, byte[] bs) + { + bs[0] = (byte)(n >> 24); + bs[1] = (byte)(n >> 16); + bs[2] = (byte)(n >> 8); + bs[3] = (byte)(n); + } + + internal static void UInt32_To_BE(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n >> 24); + bs[off + 1] = (byte)(n >> 16); + bs[off + 2] = (byte)(n >> 8); + bs[off + 3] = (byte)(n); + } + + internal static byte[] UInt32_To_BE(uint[] ns) + { + byte[] bs = new byte[4 * ns.Length]; + UInt32_To_BE(ns, bs, 0); + return bs; + } + + internal static void UInt32_To_BE(uint[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.Length; ++i) + { + UInt32_To_BE(ns[i], bs, off); + off += 4; + } + } + + internal static uint BE_To_UInt32(byte[] bs) + { + return (uint)bs[0] << 24 + | (uint)bs[1] << 16 + | (uint)bs[2] << 8 + | (uint)bs[3]; + } + + internal static uint BE_To_UInt32(byte[] bs, int off) + { + return (uint)bs[off] << 24 + | (uint)bs[off + 1] << 16 + | (uint)bs[off + 2] << 8 + | (uint)bs[off + 3]; + } + + internal static void BE_To_UInt32(byte[] bs, int off, uint[] ns) + { + for (int i = 0; i < ns.Length; ++i) + { + ns[i] = BE_To_UInt32(bs, off); + off += 4; + } + } + + internal static byte[] UInt64_To_BE(ulong n) + { + byte[] bs = new byte[8]; + UInt64_To_BE(n, bs, 0); + return bs; + } + + internal static void UInt64_To_BE(ulong n, byte[] bs) + { + UInt32_To_BE((uint)(n >> 32), bs); + UInt32_To_BE((uint)(n), bs, 4); + } + + internal static void UInt64_To_BE(ulong n, byte[] bs, int off) + { + UInt32_To_BE((uint)(n >> 32), bs, off); + UInt32_To_BE((uint)(n), bs, off + 4); + } + + internal static byte[] UInt64_To_BE(ulong[] ns) + { + byte[] bs = new byte[8 * ns.Length]; + UInt64_To_BE(ns, bs, 0); + return bs; + } + + internal static void UInt64_To_BE(ulong[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.Length; ++i) + { + UInt64_To_BE(ns[i], bs, off); + off += 8; + } + } + + internal static ulong BE_To_UInt64(byte[] bs) + { + uint hi = BE_To_UInt32(bs); + uint lo = BE_To_UInt32(bs, 4); + return ((ulong)hi << 32) | (ulong)lo; + } + + internal static ulong BE_To_UInt64(byte[] bs, int off) + { + uint hi = BE_To_UInt32(bs, off); + uint lo = BE_To_UInt32(bs, off + 4); + return ((ulong)hi << 32) | (ulong)lo; + } + + internal static void BE_To_UInt64(byte[] bs, int off, ulong[] ns) + { + for (int i = 0; i < ns.Length; ++i) + { + ns[i] = BE_To_UInt64(bs, off); + off += 8; + } + } + + internal static void UInt16_To_LE(ushort n, byte[] bs) + { + bs[0] = (byte)(n); + bs[1] = (byte)(n >> 8); + } + + internal static void UInt16_To_LE(ushort n, byte[] bs, int off) + { + bs[off] = (byte)(n); + bs[off + 1] = (byte)(n >> 8); + } + + internal static ushort LE_To_UInt16(byte[] bs) + { + uint n = (uint)bs[0] + | (uint)bs[1] << 8; + return (ushort)n; + } + + internal static ushort LE_To_UInt16(byte[] bs, int off) + { + uint n = (uint)bs[off] + | (uint)bs[off + 1] << 8; + return (ushort)n; + } + + internal static byte[] UInt32_To_LE(uint n) + { + byte[] bs = new byte[4]; + UInt32_To_LE(n, bs, 0); + return bs; + } + + internal static void UInt32_To_LE(uint n, byte[] bs) + { + bs[0] = (byte)(n); + bs[1] = (byte)(n >> 8); + bs[2] = (byte)(n >> 16); + bs[3] = (byte)(n >> 24); + } + + internal static void UInt32_To_LE(uint n, byte[] bs, int off) + { + bs[off] = (byte)(n); + bs[off + 1] = (byte)(n >> 8); + bs[off + 2] = (byte)(n >> 16); + bs[off + 3] = (byte)(n >> 24); + } + + internal static byte[] UInt32_To_LE(uint[] ns) + { + byte[] bs = new byte[4 * ns.Length]; + UInt32_To_LE(ns, bs, 0); + return bs; + } + + internal static void UInt32_To_LE(uint[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.Length; ++i) + { + UInt32_To_LE(ns[i], bs, off); + off += 4; + } + } + + internal static uint LE_To_UInt32(byte[] bs) + { + return (uint)bs[0] + | (uint)bs[1] << 8 + | (uint)bs[2] << 16 + | (uint)bs[3] << 24; + } + + internal static uint LE_To_UInt32(byte[] bs, int off) + { + return (uint)bs[off] + | (uint)bs[off + 1] << 8 + | (uint)bs[off + 2] << 16 + | (uint)bs[off + 3] << 24; + } + + internal static void LE_To_UInt32(byte[] bs, int off, uint[] ns) + { + for (int i = 0; i < ns.Length; ++i) + { + ns[i] = LE_To_UInt32(bs, off); + off += 4; + } + } + + internal static void LE_To_UInt32(byte[] bs, int bOff, uint[] ns, int nOff, int count) + { + for (int i = 0; i < count; ++i) + { + ns[nOff + i] = LE_To_UInt32(bs, bOff); + bOff += 4; + } + } + + internal static uint[] LE_To_UInt32(byte[] bs, int off, int count) + { + uint[] ns = new uint[count]; + for (int i = 0; i < ns.Length; ++i) + { + ns[i] = LE_To_UInt32(bs, off); + off += 4; + } + return ns; + } + + internal static byte[] UInt64_To_LE(ulong n) + { + byte[] bs = new byte[8]; + UInt64_To_LE(n, bs, 0); + return bs; + } + + internal static void UInt64_To_LE(ulong n, byte[] bs) + { + UInt32_To_LE((uint)(n), bs); + UInt32_To_LE((uint)(n >> 32), bs, 4); + } + + internal static void UInt64_To_LE(ulong n, byte[] bs, int off) + { + UInt32_To_LE((uint)(n), bs, off); + UInt32_To_LE((uint)(n >> 32), bs, off + 4); + } + + internal static byte[] UInt64_To_LE(ulong[] ns) + { + byte[] bs = new byte[8 * ns.Length]; + UInt64_To_LE(ns, bs, 0); + return bs; + } + + internal static void UInt64_To_LE(ulong[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.Length; ++i) + { + UInt64_To_LE(ns[i], bs, off); + off += 8; + } + } + + internal static void UInt64_To_LE(ulong[] ns, int nsOff, int nsLen, byte[] bs, int bsOff) + { + for (int i = 0; i < nsLen; ++i) + { + UInt64_To_LE(ns[nsOff + i], bs, bsOff); + bsOff += 8; + } + } + + internal static ulong LE_To_UInt64(byte[] bs) + { + uint lo = LE_To_UInt32(bs); + uint hi = LE_To_UInt32(bs, 4); + return ((ulong)hi << 32) | (ulong)lo; + } + + internal static ulong LE_To_UInt64(byte[] bs, int off) + { + uint lo = LE_To_UInt32(bs, off); + uint hi = LE_To_UInt32(bs, off + 4); + return ((ulong)hi << 32) | (ulong)lo; + } + + internal static void LE_To_UInt64(byte[] bs, int off, ulong[] ns) + { + for (int i = 0; i < ns.Length; ++i) + { + ns[i] = LE_To_UInt64(bs, off); + off += 8; + } + } + + internal static void LE_To_UInt64(byte[] bs, int bsOff, ulong[] ns, int nsOff, int nsLen) + { + for (int i = 0; i < nsLen; ++i) + { + ns[nsOff + i] = LE_To_UInt64(bs, bsOff); + bsOff += 8; + } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/BigInteger.cs b/src/Renci.SshNet/Security/BouncyCastle/math/BigInteger.cs new file mode 100644 index 00000000..635a2540 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/BigInteger.cs @@ -0,0 +1,3601 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text; + +using Renci.SshNet.Security.Org.BouncyCastle.Security; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math +{ +#if FEATURE_BINARY_SERIALIZATION + [Serializable] +#endif + internal class BigInteger + { + // The first few odd primes + /* + 3 5 7 11 13 17 19 23 29 + 31 37 41 43 47 53 59 61 67 71 + 73 79 83 89 97 101 103 107 109 113 + 127 131 137 139 149 151 157 163 167 173 + 179 181 191 193 197 199 211 223 227 229 + 233 239 241 251 257 263 269 271 277 281 + 283 293 307 311 313 317 331 337 347 349 + 353 359 367 373 379 383 389 397 401 409 + 419 421 431 433 439 443 449 457 461 463 + 467 479 487 491 499 503 509 521 523 541 + 547 557 563 569 571 577 587 593 599 601 + 607 613 617 619 631 641 643 647 653 659 + 661 673 677 683 691 701 709 719 727 733 + 739 743 751 757 761 769 773 787 797 809 + 811 821 823 827 829 839 853 857 859 863 + 877 881 883 887 907 911 919 929 937 941 + 947 953 967 971 977 983 991 997 1009 + 1013 1019 1021 1031 1033 1039 1049 1051 + 1061 1063 1069 1087 1091 1093 1097 1103 + 1109 1117 1123 1129 1151 1153 1163 1171 + 1181 1187 1193 1201 1213 1217 1223 1229 + 1231 1237 1249 1259 1277 1279 1283 1289 + */ + + // Each list has a product < 2^31 + internal static readonly int[][] primeLists = new int[][] + { + new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 }, + new int[]{ 29, 31, 37, 41, 43 }, + new int[]{ 47, 53, 59, 61, 67 }, + new int[]{ 71, 73, 79, 83 }, + new int[]{ 89, 97, 101, 103 }, + + new int[]{ 107, 109, 113, 127 }, + new int[]{ 131, 137, 139, 149 }, + new int[]{ 151, 157, 163, 167 }, + new int[]{ 173, 179, 181, 191 }, + new int[]{ 193, 197, 199, 211 }, + + new int[]{ 223, 227, 229 }, + new int[]{ 233, 239, 241 }, + new int[]{ 251, 257, 263 }, + new int[]{ 269, 271, 277 }, + new int[]{ 281, 283, 293 }, + + new int[]{ 307, 311, 313 }, + new int[]{ 317, 331, 337 }, + new int[]{ 347, 349, 353 }, + new int[]{ 359, 367, 373 }, + new int[]{ 379, 383, 389 }, + + new int[]{ 397, 401, 409 }, + new int[]{ 419, 421, 431 }, + new int[]{ 433, 439, 443 }, + new int[]{ 449, 457, 461 }, + new int[]{ 463, 467, 479 }, + + new int[]{ 487, 491, 499 }, + new int[]{ 503, 509, 521 }, + new int[]{ 523, 541, 547 }, + new int[]{ 557, 563, 569 }, + new int[]{ 571, 577, 587 }, + + new int[]{ 593, 599, 601 }, + new int[]{ 607, 613, 617 }, + new int[]{ 619, 631, 641 }, + new int[]{ 643, 647, 653 }, + new int[]{ 659, 661, 673 }, + + new int[]{ 677, 683, 691 }, + new int[]{ 701, 709, 719 }, + new int[]{ 727, 733, 739 }, + new int[]{ 743, 751, 757 }, + new int[]{ 761, 769, 773 }, + + new int[]{ 787, 797, 809 }, + new int[]{ 811, 821, 823 }, + new int[]{ 827, 829, 839 }, + new int[]{ 853, 857, 859 }, + new int[]{ 863, 877, 881 }, + + new int[]{ 883, 887, 907 }, + new int[]{ 911, 919, 929 }, + new int[]{ 937, 941, 947 }, + new int[]{ 953, 967, 971 }, + new int[]{ 977, 983, 991 }, + + new int[]{ 997, 1009, 1013 }, + new int[]{ 1019, 1021, 1031 }, + new int[]{ 1033, 1039, 1049 }, + new int[]{ 1051, 1061, 1063 }, + new int[]{ 1069, 1087, 1091 }, + + new int[]{ 1093, 1097, 1103 }, + new int[]{ 1109, 1117, 1123 }, + new int[]{ 1129, 1151, 1153 }, + new int[]{ 1163, 1171, 1181 }, + new int[]{ 1187, 1193, 1201 }, + + new int[]{ 1213, 1217, 1223 }, + new int[]{ 1229, 1231, 1237 }, + new int[]{ 1249, 1259, 1277 }, + new int[]{ 1279, 1283, 1289 }, + }; + + internal static readonly int[] primeProducts; + + private const long IMASK = 0xFFFFFFFFL; + private const ulong UIMASK = 0xFFFFFFFFUL; + + private static readonly int[] ZeroMagnitude = new int[0]; + private static readonly byte[] ZeroEncoding = new byte[0]; + + private static readonly BigInteger[] SMALL_CONSTANTS = new BigInteger[17]; + public static readonly BigInteger Zero; + public static readonly BigInteger One; + public static readonly BigInteger Two; + public static readonly BigInteger Three; + public static readonly BigInteger Ten; + + //private readonly static byte[] BitCountTable = + //{ + // 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + // 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + // 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + // 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + // 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + // 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + // 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + // 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + // 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + // 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + // 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 + //}; + + private readonly static byte[] BitLengthTable = + { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 + }; + + // TODO Parse radix-2 64 bits at a time and radix-8 63 bits at a time + private const int chunk2 = 1, chunk8 = 1, chunk10 = 19, chunk16 = 16; + private static readonly BigInteger radix2, radix2E, radix8, radix8E, radix10, radix10E, radix16, radix16E; + + private static readonly SecureRandom RandomSource = new SecureRandom(); + + /* + * These are the threshold bit-lengths (of an exponent) where we increase the window size. + * They are calculated according to the expected savings in multiplications. + * Some squares will also be saved on average, but we offset these against the extra storage costs. + */ + private static readonly int[] ExpWindowThresholds = { 7, 25, 81, 241, 673, 1793, 4609, Int32.MaxValue }; + + private const int BitsPerByte = 8; + private const int BitsPerInt = 32; + private const int BytesPerInt = 4; + + static BigInteger() + { + Zero = new BigInteger(0, ZeroMagnitude, false); + Zero.nBits = 0; Zero.nBitLength = 0; + + SMALL_CONSTANTS[0] = Zero; + for (uint i = 1; i < SMALL_CONSTANTS.Length; ++i) + { + SMALL_CONSTANTS[i] = CreateUValueOf(i); + } + + One = SMALL_CONSTANTS[1]; + Two = SMALL_CONSTANTS[2]; + Three = SMALL_CONSTANTS[3]; + Ten = SMALL_CONSTANTS[10]; + + radix2 = ValueOf(2); + radix2E = radix2.Pow(chunk2); + + radix8 = ValueOf(8); + radix8E = radix8.Pow(chunk8); + + radix10 = ValueOf(10); + radix10E = radix10.Pow(chunk10); + + radix16 = ValueOf(16); + radix16E = radix16.Pow(chunk16); + + primeProducts = new int[primeLists.Length]; + + for (int i = 0; i < primeLists.Length; ++i) + { + int[] primeList = primeLists[i]; + int product = primeList[0]; + for (int j = 1; j < primeList.Length; ++j) + { + product *= primeList[j]; + } + primeProducts[i] = product; + } + } + + private int[] magnitude; // array of ints with [0] being the most significant + private int sign; // -1 means -ve; +1 means +ve; 0 means 0; + private int nBits = -1; // cache BitCount() value + private int nBitLength = -1; // cache BitLength() value + private int mQuote = 0; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.), 0 when uninitialised + + private static int GetByteLength( + int nBits) + { + return (nBits + BitsPerByte - 1) / BitsPerByte; + } + + internal static BigInteger Arbitrary(int sizeInBits) + { + return new BigInteger(sizeInBits, RandomSource); + } + + private BigInteger( + int signum, + int[] mag, + bool checkMag) + { + if (checkMag) + { + int i = 0; + while (i < mag.Length && mag[i] == 0) + { + ++i; + } + + if (i == mag.Length) + { + this.sign = 0; + this.magnitude = ZeroMagnitude; + } + else + { + this.sign = signum; + + if (i == 0) + { + this.magnitude = mag; + } + else + { + // strip leading 0 words + this.magnitude = new int[mag.Length - i]; + Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length); + } + } + } + else + { + this.sign = signum; + this.magnitude = mag; + } + } + + public BigInteger( + string value) + : this(value, 10) + { + } + + public BigInteger( + string str, + int radix) + { + if (str.Length == 0) + throw new FormatException("Zero length BigInteger"); + + NumberStyles style; + int chunk; + BigInteger r; + BigInteger rE; + + switch (radix) + { + case 2: + // Is there anyway to restrict to binary digits? + style = NumberStyles.Integer; + chunk = chunk2; + r = radix2; + rE = radix2E; + break; + case 8: + // Is there anyway to restrict to octal digits? + style = NumberStyles.Integer; + chunk = chunk8; + r = radix8; + rE = radix8E; + break; + case 10: + // This style seems to handle spaces and minus sign already (our processing redundant?) + style = NumberStyles.Integer; + chunk = chunk10; + r = radix10; + rE = radix10E; + break; + case 16: + // TODO Should this be HexNumber? + style = NumberStyles.AllowHexSpecifier; + chunk = chunk16; + r = radix16; + rE = radix16E; + break; + default: + throw new FormatException("Only bases 2, 8, 10, or 16 allowed"); + } + + + int index = 0; + sign = 1; + + if (str[0] == '-') + { + if (str.Length == 1) + throw new FormatException("Zero length BigInteger"); + + sign = -1; + index = 1; + } + + // strip leading zeros from the string str + while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0) + { + index++; + } + + if (index >= str.Length) + { + // zero value - we're done + sign = 0; + magnitude = ZeroMagnitude; + return; + } + + ////// + // could we work out the max number of ints required to store + // str.Length digits in the given base, then allocate that + // storage in one hit?, then Generate the magnitude in one hit too? + ////// + + BigInteger b = Zero; + + + int next = index + chunk; + + if (next <= str.Length) + { + do + { + string s = str.Substring(index, chunk); + ulong i = ulong.Parse(s, style); + BigInteger bi = CreateUValueOf(i); + + switch (radix) + { + case 2: + // TODO Need this because we are parsing in radix 10 above + if (i >= 2) + throw new FormatException("Bad character in radix 2 string: " + s); + + // TODO Parse 64 bits at a time + b = b.ShiftLeft(1); + break; + case 8: + // TODO Need this because we are parsing in radix 10 above + if (i >= 8) + throw new FormatException("Bad character in radix 8 string: " + s); + + // TODO Parse 63 bits at a time + b = b.ShiftLeft(3); + break; + case 16: + b = b.ShiftLeft(64); + break; + default: + b = b.Multiply(rE); + break; + } + + b = b.Add(bi); + + index = next; + next += chunk; + } + while (next <= str.Length); + } + + if (index < str.Length) + { + string s = str.Substring(index); + ulong i = ulong.Parse(s, style); + BigInteger bi = CreateUValueOf(i); + + if (b.sign > 0) + { + if (radix == 2) + { + // NB: Can't reach here since we are parsing one char at a time + Debug.Assert(false); + + // TODO Parse all bits at once +// b = b.ShiftLeft(s.Length); + } + else if (radix == 8) + { + // NB: Can't reach here since we are parsing one char at a time + Debug.Assert(false); + + // TODO Parse all bits at once +// b = b.ShiftLeft(s.Length * 3); + } + else if (radix == 16) + { + b = b.ShiftLeft(s.Length << 2); + } + else + { + b = b.Multiply(r.Pow(s.Length)); + } + + b = b.Add(bi); + } + else + { + b = bi; + } + } + + // Note: This is the previous (slower) algorithm +// while (index < value.Length) +// { +// char c = value[index]; +// string s = c.ToString(); +// int i = Int32.Parse(s, style); +// +// b = b.Multiply(r).Add(ValueOf(i)); +// index++; +// } + + magnitude = b.magnitude; + } + + public BigInteger( + byte[] bytes) + : this(bytes, 0, bytes.Length) + { + } + + public BigInteger( + byte[] bytes, + int offset, + int length) + { + if (length == 0) + throw new FormatException("Zero length BigInteger"); + + // TODO Move this processing into MakeMagnitude (provide sign argument) + if ((sbyte)bytes[offset] < 0) + { + this.sign = -1; + + int end = offset + length; + + int iBval; + // strip leading sign bytes + for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++) + { + } + + if (iBval >= end) + { + this.magnitude = One.magnitude; + } + else + { + int numBytes = end - iBval; + byte[] inverse = new byte[numBytes]; + + int index = 0; + while (index < numBytes) + { + inverse[index++] = (byte)~bytes[iBval++]; + } + + Debug.Assert(iBval == end); + + while (inverse[--index] == byte.MaxValue) + { + inverse[index] = byte.MinValue; + } + + inverse[index]++; + + this.magnitude = MakeMagnitude(inverse, 0, inverse.Length); + } + } + else + { + // strip leading zero bytes and return magnitude bytes + this.magnitude = MakeMagnitude(bytes, offset, length); + this.sign = this.magnitude.Length > 0 ? 1 : 0; + } + } + + private static int[] MakeMagnitude( + byte[] bytes, + int offset, + int length) + { + int end = offset + length; + + // strip leading zeros + int firstSignificant; + for (firstSignificant = offset; firstSignificant < end + && bytes[firstSignificant] == 0; firstSignificant++) + { + } + + if (firstSignificant >= end) + { + return ZeroMagnitude; + } + + int nInts = (end - firstSignificant + 3) / BytesPerInt; + int bCount = (end - firstSignificant) % BytesPerInt; + if (bCount == 0) + { + bCount = BytesPerInt; + } + + if (nInts < 1) + { + return ZeroMagnitude; + } + + int[] mag = new int[nInts]; + + int v = 0; + int magnitudeIndex = 0; + for (int i = firstSignificant; i < end; ++i) + { + v <<= 8; + v |= bytes[i] & 0xff; + bCount--; + if (bCount <= 0) + { + mag[magnitudeIndex] = v; + magnitudeIndex++; + bCount = BytesPerInt; + v = 0; + } + } + + if (magnitudeIndex < mag.Length) + { + mag[magnitudeIndex] = v; + } + + return mag; + } + + public BigInteger( + int sign, + byte[] bytes) + : this(sign, bytes, 0, bytes.Length) + { + } + + public BigInteger( + int sign, + byte[] bytes, + int offset, + int length) + { + if (sign < -1 || sign > 1) + throw new FormatException("Invalid sign value"); + + if (sign == 0) + { + this.sign = 0; + this.magnitude = ZeroMagnitude; + } + else + { + // copy bytes + this.magnitude = MakeMagnitude(bytes, offset, length); + this.sign = this.magnitude.Length < 1 ? 0 : sign; + } + } + + public BigInteger( + int sizeInBits, + Random random) + { + if (sizeInBits < 0) + throw new ArgumentException("sizeInBits must be non-negative"); + + this.nBits = -1; + this.nBitLength = -1; + + if (sizeInBits == 0) + { + this.sign = 0; + this.magnitude = ZeroMagnitude; + return; + } + + int nBytes = GetByteLength(sizeInBits); + byte[] b = new byte[nBytes]; + random.NextBytes(b); + + // strip off any excess bits in the MSB + int xBits = BitsPerByte * nBytes - sizeInBits; + b[0] &= (byte)(255U >> xBits); + + this.magnitude = MakeMagnitude(b, 0, b.Length); + this.sign = this.magnitude.Length < 1 ? 0 : 1; + } + + public BigInteger( + int bitLength, + int certainty, + Random random) + { + if (bitLength < 2) + throw new ArithmeticException("bitLength < 2"); + + this.sign = 1; + this.nBitLength = bitLength; + + if (bitLength == 2) + { + this.magnitude = random.Next(2) == 0 + ? Two.magnitude + : Three.magnitude; + return; + } + + int nBytes = GetByteLength(bitLength); + byte[] b = new byte[nBytes]; + + int xBits = BitsPerByte * nBytes - bitLength; + byte mask = (byte)(255U >> xBits); + byte lead = (byte)(1 << (7 - xBits)); + + for (;;) + { + random.NextBytes(b); + + // strip off any excess bits in the MSB + b[0] &= mask; + + // ensure the leading bit is 1 (to meet the strength requirement) + b[0] |= lead; + + // ensure the trailing bit is 1 (i.e. must be odd) + b[nBytes - 1] |= 1; + + this.magnitude = MakeMagnitude(b, 0, b.Length); + this.nBits = -1; + this.mQuote = 0; + + if (certainty < 1) + break; + + if (CheckProbablePrime(certainty, random, true)) + break; + + for (int j = 1; j < (magnitude.Length - 1); ++j) + { + this.magnitude[j] ^= random.Next(); + + if (CheckProbablePrime(certainty, random, true)) + return; + } + } + } + + public BigInteger Abs() + { + return sign >= 0 ? this : Negate(); + } + + /** + * return a = a + b - b preserved. + */ + private static int[] AddMagnitudes( + int[] a, + int[] b) + { + int tI = a.Length - 1; + int vI = b.Length - 1; + long m = 0; + + while (vI >= 0) + { + m += ((long)(uint)a[tI] + (long)(uint)b[vI--]); + a[tI--] = (int)m; + m = (long)((ulong)m >> 32); + } + + if (m != 0) + { + while (tI >= 0 && ++a[tI--] == 0) + { + } + } + + return a; + } + + public BigInteger Add( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (this.sign != value.sign) + { + if (value.sign == 0) + return this; + + if (value.sign < 0) + return Subtract(value.Negate()); + + return value.Subtract(Negate()); + } + + return AddToMagnitude(value.magnitude); + } + + private BigInteger AddToMagnitude( + int[] magToAdd) + { + int[] big, small; + if (this.magnitude.Length < magToAdd.Length) + { + big = magToAdd; + small = this.magnitude; + } + else + { + big = this.magnitude; + small = magToAdd; + } + + // Conservatively avoid over-allocation when no overflow possible + uint limit = uint.MaxValue; + if (big.Length == small.Length) + limit -= (uint) small[0]; + + bool possibleOverflow = (uint) big[0] >= limit; + + int[] bigCopy; + if (possibleOverflow) + { + bigCopy = new int[big.Length + 1]; + big.CopyTo(bigCopy, 1); + } + else + { + bigCopy = (int[]) big.Clone(); + } + + bigCopy = AddMagnitudes(bigCopy, small); + + return new BigInteger(this.sign, bigCopy, possibleOverflow); + } + + public BigInteger And( + BigInteger value) + { + if (this.sign == 0 || value.sign == 0) + { + return Zero; + } + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + bool resultNeg = sign < 0 && value.sign < 0; + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord & bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger AndNot( + BigInteger val) + { + return And(val.Not()); + } + + public int BitCount + { + get + { + if (nBits == -1) + { + if (sign < 0) + { + // TODO Optimise this case + nBits = Not().BitCount; + } + else + { + int sum = 0; + for (int i = 0; i < magnitude.Length; ++i) + { + sum += BitCnt(magnitude[i]); + } + nBits = sum; + } + } + + return nBits; + } + } + + public static int BitCnt(int i) + { + uint u = (uint)i; + u = u - ((u >> 1) & 0x55555555); + u = (u & 0x33333333) + ((u >> 2) & 0x33333333); + u = (u + (u >> 4)) & 0x0f0f0f0f; + u += (u >> 8); + u += (u >> 16); + u &= 0x3f; + return (int)u; + } + + private static int CalcBitLength(int sign, int indx, int[] mag) + { + for (;;) + { + if (indx >= mag.Length) + return 0; + + if (mag[indx] != 0) + break; + + ++indx; + } + + // bit length for everything after the first int + int bitLength = 32 * ((mag.Length - indx) - 1); + + // and determine bitlength of first int + int firstMag = mag[indx]; + bitLength += BitLen(firstMag); + + // Check for negative powers of two + if (sign < 0 && ((firstMag & -firstMag) == firstMag)) + { + do + { + if (++indx >= mag.Length) + { + --bitLength; + break; + } + } + while (mag[indx] == 0); + } + + return bitLength; + } + + public int BitLength + { + get + { + if (nBitLength == -1) + { + nBitLength = sign == 0 + ? 0 + : CalcBitLength(sign, 0, magnitude); + } + + return nBitLength; + } + } + + // + // BitLen(value) is the number of bits in value. + // + internal static int BitLen(int w) + { + uint v = (uint)w; + uint t = v >> 24; + if (t != 0) + return 24 + BitLengthTable[t]; + t = v >> 16; + if (t != 0) + return 16 + BitLengthTable[t]; + t = v >> 8; + if (t != 0) + return 8 + BitLengthTable[t]; + return BitLengthTable[v]; + } + + private bool QuickPow2Check() + { + return sign > 0 && nBits == 1; + } + + public int CompareTo( + object obj) + { + return CompareTo((BigInteger)obj); + } + + /** + * unsigned comparison on two arrays - note the arrays may + * start with leading zeros. + */ + private static int CompareTo( + int xIndx, + int[] x, + int yIndx, + int[] y) + { + while (xIndx != x.Length && x[xIndx] == 0) + { + xIndx++; + } + + while (yIndx != y.Length && y[yIndx] == 0) + { + yIndx++; + } + + return CompareNoLeadingZeroes(xIndx, x, yIndx, y); + } + + private static int CompareNoLeadingZeroes( + int xIndx, + int[] x, + int yIndx, + int[] y) + { + int diff = (x.Length - y.Length) - (xIndx - yIndx); + + if (diff != 0) + { + return diff < 0 ? -1 : 1; + } + + // lengths of magnitudes the same, test the magnitude values + + while (xIndx < x.Length) + { + uint v1 = (uint)x[xIndx++]; + uint v2 = (uint)y[yIndx++]; + + if (v1 != v2) + return v1 < v2 ? -1 : 1; + } + + return 0; + } + + public int CompareTo( + BigInteger value) + { + return sign < value.sign ? -1 + : sign > value.sign ? 1 + : sign == 0 ? 0 + : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude); + } + + /** + * return z = x / y - done in place (z value preserved, x contains the + * remainder) + */ + private int[] Divide( + int[] x, + int[] y) + { + int xStart = 0; + while (xStart < x.Length && x[xStart] == 0) + { + ++xStart; + } + + int yStart = 0; + while (yStart < y.Length && y[yStart] == 0) + { + ++yStart; + } + + Debug.Assert(yStart < y.Length); + + int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + int[] count; + + if (xyCmp > 0) + { + int yBitLength = CalcBitLength(1, yStart, y); + int xBitLength = CalcBitLength(1, xStart, x); + int shift = xBitLength - yBitLength; + + int[] iCount; + int iCountStart = 0; + + int[] c; + int cStart = 0; + int cBitLength = yBitLength; + if (shift > 0) + { +// iCount = ShiftLeft(One.magnitude, shift); + iCount = new int[(shift >> 5) + 1]; + iCount[0] = 1 << (shift % 32); + + c = ShiftLeft(y, shift); + cBitLength += shift; + } + else + { + iCount = new int[] { 1 }; + + int len = y.Length - yStart; + c = new int[len]; + Array.Copy(y, yStart, c, 0, len); + } + + count = new int[iCount.Length]; + + for (;;) + { + if (cBitLength < xBitLength + || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) + { + Subtract(xStart, x, cStart, c); + AddMagnitudes(count, iCount); + + while (x[xStart] == 0) + { + if (++xStart == x.Length) + return count; + } + + //xBitLength = CalcBitLength(xStart, x); + xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); + + if (xBitLength <= yBitLength) + { + if (xBitLength < yBitLength) + return count; + + xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp <= 0) + break; + } + } + + shift = cBitLength - xBitLength; + + // NB: The case where c[cStart] is 1-bit is harmless + if (shift == 1) + { + uint firstC = (uint) c[cStart] >> 1; + uint firstX = (uint) x[xStart]; + if (firstC > firstX) + ++shift; + } + + if (shift < 2) + { + ShiftRightOneInPlace(cStart, c); + --cBitLength; + ShiftRightOneInPlace(iCountStart, iCount); + } + else + { + ShiftRightInPlace(cStart, c, shift); + cBitLength -= shift; + ShiftRightInPlace(iCountStart, iCount, shift); + } + + //cStart = c.Length - ((cBitLength + 31) / 32); + while (c[cStart] == 0) + { + ++cStart; + } + + while (iCount[iCountStart] == 0) + { + ++iCountStart; + } + } + } + else + { + count = new int[1]; + } + + if (xyCmp == 0) + { + AddMagnitudes(count, One.magnitude); + Array.Clear(x, xStart, x.Length - xStart); + } + + return count; + } + + public BigInteger Divide( + BigInteger val) + { + if (val.sign == 0) + throw new ArithmeticException("Division by zero error"); + + if (sign == 0) + return Zero; + + if (val.QuickPow2Check()) // val is power of two + { + BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1); + return val.sign == this.sign ? result : result.Negate(); + } + + int[] mag = (int[]) this.magnitude.Clone(); + + return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true); + } + + public BigInteger[] DivideAndRemainder( + BigInteger val) + { + if (val.sign == 0) + throw new ArithmeticException("Division by zero error"); + + BigInteger[] biggies = new BigInteger[2]; + + if (sign == 0) + { + biggies[0] = Zero; + biggies[1] = Zero; + } + else if (val.QuickPow2Check()) // val is power of two + { + int e = val.Abs().BitLength - 1; + BigInteger quotient = this.Abs().ShiftRight(e); + int[] remainder = this.LastNBits(e); + + biggies[0] = val.sign == this.sign ? quotient : quotient.Negate(); + biggies[1] = new BigInteger(this.sign, remainder, true); + } + else + { + int[] remainder = (int[]) this.magnitude.Clone(); + int[] quotient = Divide(remainder, val.magnitude); + + biggies[0] = new BigInteger(this.sign * val.sign, quotient, true); + biggies[1] = new BigInteger(this.sign, remainder, true); + } + + return biggies; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + BigInteger biggie = obj as BigInteger; + if (biggie == null) + return false; + + return sign == biggie.sign && IsEqualMagnitude(biggie); + } + + private bool IsEqualMagnitude(BigInteger x) + { + int[] xMag = x.magnitude; + if (magnitude.Length != x.magnitude.Length) + return false; + for (int i = 0; i < magnitude.Length; i++) + { + if (magnitude[i] != x.magnitude[i]) + return false; + } + return true; + } + + public BigInteger Gcd( + BigInteger value) + { + if (value.sign == 0) + return Abs(); + + if (sign == 0) + return value.Abs(); + + BigInteger r; + BigInteger u = this; + BigInteger v = value; + + while (v.sign != 0) + { + r = u.Mod(v); + u = v; + v = r; + } + + return u; + } + + public override int GetHashCode() + { + int hc = magnitude.Length; + if (magnitude.Length > 0) + { + hc ^= magnitude[0]; + + if (magnitude.Length > 1) + { + hc ^= magnitude[magnitude.Length - 1]; + } + } + + return sign < 0 ? ~hc : hc; + } + + // TODO Make public? + private BigInteger Inc() + { + if (this.sign == 0) + return One; + + if (this.sign < 0) + return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true); + + return AddToMagnitude(One.magnitude); + } + + public int IntValue + { + get + { + if (sign == 0) + return 0; + + int n = magnitude.Length; + + int v = magnitude[n - 1]; + + return sign < 0 ? -v : v; + } + } + + /** + * return whether or not a BigInteger is probably prime with a + * probability of 1 - (1/2)**certainty. + *

From Knuth Vol 2, pg 395.

+ */ + public bool IsProbablePrime(int certainty) + { + return IsProbablePrime(certainty, false); + } + + internal bool IsProbablePrime(int certainty, bool randomlySelected) + { + if (certainty <= 0) + return true; + + BigInteger n = Abs(); + + if (!n.TestBit(0)) + return n.Equals(Two); + + if (n.Equals(One)) + return false; + + return n.CheckProbablePrime(certainty, RandomSource, randomlySelected); + } + + private bool CheckProbablePrime(int certainty, Random random, bool randomlySelected) + { + Debug.Assert(certainty > 0); + Debug.Assert(CompareTo(Two) > 0); + Debug.Assert(TestBit(0)); + + + // Try to reduce the penalty for really small numbers + int numLists = System.Math.Min(BitLength - 1, primeLists.Length); + + for (int i = 0; i < numLists; ++i) + { + int test = Remainder(primeProducts[i]); + + int[] primeList = primeLists[i]; + for (int j = 0; j < primeList.Length; ++j) + { + int prime = primeList[j]; + int qRem = test % prime; + if (qRem == 0) + { + // We may find small numbers in the list + return BitLength < 16 && IntValue == prime; + } + } + } + + + // TODO Special case for < 10^16 (RabinMiller fixed list) +// if (BitLength < 30) +// { +// RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient +// } + + + // TODO Is it worth trying to create a hybrid of these two? + return RabinMillerTest(certainty, random, randomlySelected); +// return SolovayStrassenTest(certainty, random); + +// bool rbTest = RabinMillerTest(certainty, random); +// bool ssTest = SolovayStrassenTest(certainty, random); +// +// Debug.Assert(rbTest == ssTest); +// +// return rbTest; + } + + public bool RabinMillerTest(int certainty, Random random) + { + return RabinMillerTest(certainty, random, false); + } + + internal bool RabinMillerTest(int certainty, Random random, bool randomlySelected) + { + int bits = BitLength; + + Debug.Assert(certainty > 0); + Debug.Assert(bits > 2); + Debug.Assert(TestBit(0)); + + int iterations = ((certainty - 1) / 2) + 1; + if (randomlySelected) + { + int itersFor100Cert = bits >= 1024 ? 4 + : bits >= 512 ? 8 + : bits >= 256 ? 16 + : 50; + + if (certainty < 100) + { + iterations = System.Math.Min(itersFor100Cert, iterations); + } + else + { + iterations -= 50; + iterations += itersFor100Cert; + } + } + + // let n = 1 + d . 2^s + BigInteger n = this; + int s = n.GetLowestSetBitMaskFirst(-1 << 1); + Debug.Assert(s >= 1); + BigInteger r = n.ShiftRight(s); + + // NOTE: Avoid conversion to/from Montgomery form and check for R/-R as result instead + + BigInteger montRadix = One.ShiftLeft(32 * n.magnitude.Length).Remainder(n); + BigInteger minusMontRadix = n.Subtract(montRadix); + + do + { + BigInteger a; + do + { + a = new BigInteger(n.BitLength, random); + } + while (a.sign == 0 || a.CompareTo(n) >= 0 + || a.IsEqualMagnitude(montRadix) || a.IsEqualMagnitude(minusMontRadix)); + + BigInteger y = ModPowMonty(a, r, n, false); + + if (!y.Equals(montRadix)) + { + int j = 0; + while (!y.Equals(minusMontRadix)) + { + if (++j == s) + return false; + + y = ModPowMonty(y, Two, n, false); + + if (y.Equals(montRadix)) + return false; + } + } + } + while (--iterations > 0); + + return true; + } + +// private bool SolovayStrassenTest( +// int certainty, +// Random random) +// { +// Debug.Assert(certainty > 0); +// Debug.Assert(CompareTo(Two) > 0); +// Debug.Assert(TestBit(0)); +// +// BigInteger n = this; +// BigInteger nMinusOne = n.Subtract(One); +// BigInteger e = nMinusOne.ShiftRight(1); +// +// do +// { +// BigInteger a; +// do +// { +// a = new BigInteger(nBitLength, random); +// } +// // NB: Spec says 0 < x < n, but 1 is trivial +// while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0); +// +// +// // TODO Check this is redundant given the way Jacobi() works? +//// if (!a.Gcd(n).Equals(One)) +//// return false; +// +// int x = Jacobi(a, n); +// +// if (x == 0) +// return false; +// +// BigInteger check = a.ModPow(e, n); +// +// if (x == 1 && !check.Equals(One)) +// return false; +// +// if (x == -1 && !check.Equals(nMinusOne)) +// return false; +// +// --certainty; +// } +// while (certainty > 0); +// +// return true; +// } +// +// private static int Jacobi( +// BigInteger a, +// BigInteger b) +// { +// Debug.Assert(a.sign >= 0); +// Debug.Assert(b.sign > 0); +// Debug.Assert(b.TestBit(0)); +// Debug.Assert(a.CompareTo(b) < 0); +// +// int totalS = 1; +// for (;;) +// { +// if (a.sign == 0) +// return 0; +// +// if (a.Equals(One)) +// break; +// +// int e = a.GetLowestSetBit(); +// +// int bLsw = b.magnitude[b.magnitude.Length - 1]; +// if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5)) +// totalS = -totalS; +// +// // TODO Confirm this is faster than later a1.Equals(One) test +// if (a.BitLength == e + 1) +// break; +// BigInteger a1 = a.ShiftRight(e); +//// if (a1.Equals(One)) +//// break; +// +// int a1Lsw = a1.magnitude[a1.magnitude.Length - 1]; +// if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3) +// totalS = -totalS; +// +//// a = b.Mod(a1); +// a = b.Remainder(a1); +// b = a1; +// } +// return totalS; +// } + + public long LongValue + { + get + { + if (sign == 0) + return 0; + + int n = magnitude.Length; + + long v = magnitude[n - 1] & IMASK; + if (n > 1) + { + v |= (magnitude[n - 2] & IMASK) << 32; + } + + return sign < 0 ? -v : v; + } + } + + public BigInteger Max( + BigInteger value) + { + return CompareTo(value) > 0 ? this : value; + } + + public BigInteger Min( + BigInteger value) + { + return CompareTo(value) < 0 ? this : value; + } + + public BigInteger Mod( + BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + BigInteger biggie = Remainder(m); + + return (biggie.sign >= 0 ? biggie : biggie.Add(m)); + } + + public BigInteger ModInverse( + BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + // TODO Too slow at the moment +// // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel +// if (m.TestBit(0)) +// { +// //The Almost Inverse Algorithm +// int k = 0; +// BigInteger B = One, C = Zero, F = this, G = m, tmp; +// +// for (;;) +// { +// // While F is even, do F=F/u, C=C*u, k=k+1. +// int zeroes = F.GetLowestSetBit(); +// if (zeroes > 0) +// { +// F = F.ShiftRight(zeroes); +// C = C.ShiftLeft(zeroes); +// k += zeroes; +// } +// +// // If F = 1, then return B,k. +// if (F.Equals(One)) +// { +// BigInteger half = m.Add(One).ShiftRight(1); +// BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m); +// return B.Multiply(halfK).Mod(m); +// } +// +// if (F.CompareTo(G) < 0) +// { +// tmp = G; G = F; F = tmp; +// tmp = B; B = C; C = tmp; +// } +// +// F = F.Add(G); +// B = B.Add(C); +// } +// } + + if (m.QuickPow2Check()) + { + return ModInversePow2(m); + } + + BigInteger d = this.Remainder(m); + BigInteger x; + BigInteger gcd = ExtEuclid(d, m, out x); + + if (!gcd.Equals(One)) + throw new ArithmeticException("Numbers not relatively prime."); + + if (x.sign < 0) + { + x = x.Add(m); + } + + return x; + } + + private BigInteger ModInversePow2(BigInteger m) + { + Debug.Assert(m.SignValue > 0); + Debug.Assert(m.BitCount == 1); + + if (!TestBit(0)) + { + throw new ArithmeticException("Numbers not relatively prime."); + } + + int pow = m.BitLength - 1; + + long inv64 = ModInverse64(LongValue); + if (pow < 64) + { + inv64 &= ((1L << pow) - 1); + } + + BigInteger x = BigInteger.ValueOf(inv64); + + if (pow > 64) + { + BigInteger d = this.Remainder(m); + int bitsCorrect = 64; + + do + { + BigInteger t = x.Multiply(d).Remainder(m); + x = x.Multiply(Two.Subtract(t)).Remainder(m); + bitsCorrect <<= 1; + } + while (bitsCorrect < pow); + } + + if (x.sign < 0) + { + x = x.Add(m); + } + + return x; + } + + private static int ModInverse32(int d) + { + // Newton's method with initial estimate "correct to 4 bits" + Debug.Assert((d & 1) != 0); + int x = d + (((d + 1) & 4) << 1); // d.x == 1 mod 2**4 + Debug.Assert(((d * x) & 15) == 1); + x *= 2 - d * x; // d.x == 1 mod 2**8 + x *= 2 - d * x; // d.x == 1 mod 2**16 + x *= 2 - d * x; // d.x == 1 mod 2**32 + Debug.Assert(d * x == 1); + return x; + } + + private static long ModInverse64(long d) + { + // Newton's method with initial estimate "correct to 4 bits" + Debug.Assert((d & 1L) != 0); + long x = d + (((d + 1L) & 4L) << 1); // d.x == 1 mod 2**4 + Debug.Assert(((d * x) & 15L) == 1L); + x *= 2 - d * x; // d.x == 1 mod 2**8 + x *= 2 - d * x; // d.x == 1 mod 2**16 + x *= 2 - d * x; // d.x == 1 mod 2**32 + x *= 2 - d * x; // d.x == 1 mod 2**64 + Debug.Assert(d * x == 1L); + return x; + } + + /** + * Calculate the numbers u1, u2, and u3 such that: + * + * u1 * a + u2 * b = u3 + * + * where u3 is the greatest common divider of a and b. + * a and b using the extended Euclid algorithm (refer p. 323 + * of The Art of Computer Programming vol 2, 2nd ed). + * This also seems to have the side effect of calculating + * some form of multiplicative inverse. + * + * @param a First number to calculate gcd for + * @param b Second number to calculate gcd for + * @param u1Out the return object for the u1 value + * @return The greatest common divisor of a and b + */ + private static BigInteger ExtEuclid(BigInteger a, BigInteger b, out BigInteger u1Out) + { + BigInteger u1 = One, v1 = Zero; + BigInteger u3 = a, v3 = b; + + if (v3.sign > 0) + { + for (;;) + { + BigInteger[] q = u3.DivideAndRemainder(v3); + u3 = v3; + v3 = q[1]; + + BigInteger oldU1 = u1; + u1 = v1; + + if (v3.sign <= 0) + break; + + v1 = oldU1.Subtract(v1.Multiply(q[0])); + } + } + + u1Out = u1; + + return u3; + } + + private static void ZeroOut( + int[] x) + { + Array.Clear(x, 0, x.Length); + } + + public BigInteger ModPow(BigInteger e, BigInteger m) + { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + if (m.Equals(One)) + return Zero; + + if (e.sign == 0) + return One; + + if (sign == 0) + return Zero; + + bool negExp = e.sign < 0; + if (negExp) + e = e.Negate(); + + BigInteger result = this.Mod(m); + if (!e.Equals(One)) + { + if ((m.magnitude[m.magnitude.Length - 1] & 1) == 0) + { + result = ModPowBarrett(result, e, m); + } + else + { + result = ModPowMonty(result, e, m, true); + } + } + + if (negExp) + result = result.ModInverse(m); + + return result; + } + + private static BigInteger ModPowBarrett(BigInteger b, BigInteger e, BigInteger m) + { + int k = m.magnitude.Length; + BigInteger mr = One.ShiftLeft((k + 1) << 5); + BigInteger yu = One.ShiftLeft(k << 6).Divide(m); + + // Sliding window from MSW to LSW + int extraBits = 0, expLength = e.BitLength; + while (expLength > ExpWindowThresholds[extraBits]) + { + ++extraBits; + } + + int numPowers = 1 << extraBits; + BigInteger[] oddPowers = new BigInteger[numPowers]; + oddPowers[0] = b; + + BigInteger b2 = ReduceBarrett(b.Square(), m, mr, yu); + + for (int i = 1; i < numPowers; ++i) + { + oddPowers[i] = ReduceBarrett(oddPowers[i - 1].Multiply(b2), m, mr, yu); + } + + int[] windowList = GetWindowList(e.magnitude, extraBits); + Debug.Assert(windowList.Length > 0); + + int window = windowList[0]; + int mult = window & 0xFF, lastZeroes = window >> 8; + + BigInteger y; + if (mult == 1) + { + y = b2; + --lastZeroes; + } + else + { + y = oddPowers[mult >> 1]; + } + + int windowPos = 1; + while ((window = windowList[windowPos++]) != -1) + { + mult = window & 0xFF; + + int bits = lastZeroes + BitLengthTable[mult]; + for (int j = 0; j < bits; ++j) + { + y = ReduceBarrett(y.Square(), m, mr, yu); + } + + y = ReduceBarrett(y.Multiply(oddPowers[mult >> 1]), m, mr, yu); + + lastZeroes = window >> 8; + } + + for (int i = 0; i < lastZeroes; ++i) + { + y = ReduceBarrett(y.Square(), m, mr, yu); + } + + return y; + } + + private static BigInteger ReduceBarrett(BigInteger x, BigInteger m, BigInteger mr, BigInteger yu) + { + int xLen = x.BitLength, mLen = m.BitLength; + if (xLen < mLen) + return x; + + if (xLen - mLen > 1) + { + int k = m.magnitude.Length; + + BigInteger q1 = x.DivideWords(k - 1); + BigInteger q2 = q1.Multiply(yu); // TODO Only need partial multiplication here + BigInteger q3 = q2.DivideWords(k + 1); + + BigInteger r1 = x.RemainderWords(k + 1); + BigInteger r2 = q3.Multiply(m); // TODO Only need partial multiplication here + BigInteger r3 = r2.RemainderWords(k + 1); + + x = r1.Subtract(r3); + if (x.sign < 0) + { + x = x.Add(mr); + } + } + + while (x.CompareTo(m) >= 0) + { + x = x.Subtract(m); + } + + return x; + } + + private static BigInteger ModPowMonty(BigInteger b, BigInteger e, BigInteger m, bool convert) + { + int n = m.magnitude.Length; + int powR = 32 * n; + bool smallMontyModulus = m.BitLength + 2 <= powR; + uint mDash = (uint)m.GetMQuote(); + + // tmp = this * R mod m + if (convert) + { + b = b.ShiftLeft(powR).Remainder(m); + } + + int[] yAccum = new int[n + 1]; + + int[] zVal = b.magnitude; + Debug.Assert(zVal.Length <= n); + if (zVal.Length < n) + { + int[] tmp = new int[n]; + zVal.CopyTo(tmp, n - zVal.Length); + zVal = tmp; + } + + // Sliding window from MSW to LSW + + int extraBits = 0; + + // Filter the common case of small RSA exponents with few bits set + if (e.magnitude.Length > 1 || e.BitCount > 2) + { + int expLength = e.BitLength; + while (expLength > ExpWindowThresholds[extraBits]) + { + ++extraBits; + } + } + + int numPowers = 1 << extraBits; + int[][] oddPowers = new int[numPowers][]; + oddPowers[0] = zVal; + + int[] zSquared = Arrays.Clone(zVal); + SquareMonty(yAccum, zSquared, m.magnitude, mDash, smallMontyModulus); + + for (int i = 1; i < numPowers; ++i) + { + oddPowers[i] = Arrays.Clone(oddPowers[i - 1]); + MultiplyMonty(yAccum, oddPowers[i], zSquared, m.magnitude, mDash, smallMontyModulus); + } + + int[] windowList = GetWindowList(e.magnitude, extraBits); + Debug.Assert(windowList.Length > 1); + + int window = windowList[0]; + int mult = window & 0xFF, lastZeroes = window >> 8; + + int[] yVal; + if (mult == 1) + { + yVal = zSquared; + --lastZeroes; + } + else + { + yVal = Arrays.Clone(oddPowers[mult >> 1]); + } + + int windowPos = 1; + while ((window = windowList[windowPos++]) != -1) + { + mult = window & 0xFF; + + int bits = lastZeroes + BitLengthTable[mult]; + for (int j = 0; j < bits; ++j) + { + SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus); + } + + MultiplyMonty(yAccum, yVal, oddPowers[mult >> 1], m.magnitude, mDash, smallMontyModulus); + + lastZeroes = window >> 8; + } + + for (int i = 0; i < lastZeroes; ++i) + { + SquareMonty(yAccum, yVal, m.magnitude, mDash, smallMontyModulus); + } + + if (convert) + { + // Return y * R^(-1) mod m + MontgomeryReduce(yVal, m.magnitude, mDash); + } + else if (smallMontyModulus && CompareTo(0, yVal, 0, m.magnitude) >= 0) + { + Subtract(0, yVal, 0, m.magnitude); + } + + return new BigInteger(1, yVal, true); + } + + private static int[] GetWindowList(int[] mag, int extraBits) + { + int v = mag[0]; + Debug.Assert(v != 0); + + int leadingBits = BitLen(v); + + int resultSize = (((mag.Length - 1) << 5) + leadingBits) / (1 + extraBits) + 2; + int[] result = new int[resultSize]; + int resultPos = 0; + + int bitPos = 33 - leadingBits; + v <<= bitPos; + + int mult = 1, multLimit = 1 << extraBits; + int zeroes = 0; + + int i = 0; + for (; ; ) + { + for (; bitPos < 32; ++bitPos) + { + if (mult < multLimit) + { + mult = (mult << 1) | (int)((uint)v >> 31); + } + else if (v < 0) + { + result[resultPos++] = CreateWindowEntry(mult, zeroes); + mult = 1; + zeroes = 0; + } + else + { + ++zeroes; + } + + v <<= 1; + } + + if (++i == mag.Length) + { + result[resultPos++] = CreateWindowEntry(mult, zeroes); + break; + } + + v = mag[i]; + bitPos = 0; + } + + result[resultPos] = -1; + return result; + } + + private static int CreateWindowEntry(int mult, int zeroes) + { + while ((mult & 1) == 0) + { + mult >>= 1; + ++zeroes; + } + + return mult | (zeroes << 8); + } + + /** + * return w with w = x * x - w is assumed to have enough space. + */ + private static int[] Square( + int[] w, + int[] x) + { + // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit +// if (w.Length != 2 * x.Length) +// throw new ArgumentException("no I don't think so..."); + + ulong c; + + int wBase = w.Length - 1; + + for (int i = x.Length - 1; i > 0; --i) + { + ulong v = (uint)x[i]; + + c = v * v + (uint)w[wBase]; + w[wBase] = (int)c; + c >>= 32; + + for (int j = i - 1; j >= 0; --j) + { + ulong prod = v * (uint)x[j]; + + c += ((uint)w[--wBase] & UIMASK) + ((uint)prod << 1); + w[wBase] = (int)c; + c = (c >> 32) + (prod >> 31); + } + + c += (uint)w[--wBase]; + w[wBase] = (int)c; + + if (--wBase >= 0) + { + w[wBase] = (int)(c >> 32); + } + else + { + Debug.Assert((c >> 32) == 0); + } + + wBase += i; + } + + c = (uint)x[0]; + + c = c * c + (uint)w[wBase]; + w[wBase] = (int)c; + + if (--wBase >= 0) + { + w[wBase] += (int)(c >> 32); + } + else + { + Debug.Assert((c >> 32) == 0); + } + + return w; + } + + /** + * return x with x = y * z - x is assumed to have enough space. + */ + private static int[] Multiply(int[] x, int[] y, int[] z) + { + int i = z.Length; + + if (i < 1) + return x; + + int xBase = x.Length - y.Length; + + do + { + long a = z[--i] & IMASK; + long val = 0; + + if (a != 0) + { + for (int j = y.Length - 1; j >= 0; j--) + { + val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK); + + x[xBase + j] = (int)val; + + val = (long)((ulong)val >> 32); + } + } + + --xBase; + + if (xBase >= 0) + { + x[xBase] = (int)val; + } + else + { + Debug.Assert(val == 0); + } + } + while (i > 0); + + return x; + } + + /** + * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size) + */ + private int GetMQuote() + { + if (mQuote != 0) + { + return mQuote; // already calculated + } + + Debug.Assert(this.sign > 0); + + int d = -magnitude[magnitude.Length - 1]; + + Debug.Assert((d & 1) != 0); + + return mQuote = ModInverse32(d); + } + + private static void MontgomeryReduce(int[] x, int[] m, uint mDash) // mDash = -m^(-1) mod b + { + // NOTE: Not a general purpose reduction (which would allow x up to twice the bitlength of m) + Debug.Assert(x.Length == m.Length); + + int n = m.Length; + + for (int i = n - 1; i >= 0; --i) + { + uint x0 = (uint)x[n - 1]; + ulong t = x0 * mDash; + + ulong carry = t * (uint)m[n - 1] + x0; + Debug.Assert((uint)carry == 0); + carry >>= 32; + + for (int j = n - 2; j >= 0; --j) + { + carry += t * (uint)m[j] + (uint)x[j]; + x[j + 1] = (int)carry; + carry >>= 32; + } + + x[0] = (int)carry; + Debug.Assert(carry >> 32 == 0); + } + + if (CompareTo(0, x, 0, m) >= 0) + { + Subtract(0, x, 0, m); + } + } + + /** + * Montgomery multiplication: a = x * y * R^(-1) mod m + *
+ * Based algorithm 14.36 of Handbook of Applied Cryptography. + *
+ *
  • m, x, y should have length n
  • + *
  • a should have length (n + 1)
  • + *
  • b = 2^32, R = b^n
  • + *
    + * The result is put in x + *
    + * NOTE: the indices of x, y, m, a different in HAC and in Java + */ + private static void MultiplyMonty(int[] a, int[] x, int[] y, int[] m, uint mDash, bool smallMontyModulus) + // mDash = -m^(-1) mod b + { + int n = m.Length; + + if (n == 1) + { + x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], mDash); + return; + } + + uint y0 = (uint)y[n - 1]; + int aMax; + + { + ulong xi = (uint)x[n - 1]; + + ulong carry = xi * y0; + ulong t = (uint)carry * mDash; + + ulong prod2 = t * (uint)m[n - 1]; + carry += (uint)prod2; + Debug.Assert((uint)carry == 0); + carry = (carry >> 32) + (prod2 >> 32); + + for (int j = n - 2; j >= 0; --j) + { + ulong prod1 = xi * (uint)y[j]; + prod2 = t * (uint)m[j]; + + carry += (prod1 & UIMASK) + (uint)prod2; + a[j + 2] = (int)carry; + carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32); + } + + a[1] = (int)carry; + aMax = (int)(carry >> 32); + } + + for (int i = n - 2; i >= 0; --i) + { + uint a0 = (uint)a[n]; + ulong xi = (uint)x[i]; + + ulong prod1 = xi * y0; + ulong carry = (prod1 & UIMASK) + a0; + ulong t = (uint)carry * mDash; + + ulong prod2 = t * (uint)m[n - 1]; + carry += (uint)prod2; + Debug.Assert((uint)carry == 0); + carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32); + + for (int j = n - 2; j >= 0; --j) + { + prod1 = xi * (uint)y[j]; + prod2 = t * (uint)m[j]; + + carry += (prod1 & UIMASK) + (uint)prod2 + (uint)a[j + 1]; + a[j + 2] = (int)carry; + carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32); + } + + carry += (uint)aMax; + a[1] = (int)carry; + aMax = (int)(carry >> 32); + } + + a[0] = aMax; + + if (!smallMontyModulus && CompareTo(0, a, 0, m) >= 0) + { + Subtract(0, a, 0, m); + } + + Array.Copy(a, 1, x, 0, n); + } + + private static void SquareMonty(int[] a, int[] x, int[] m, uint mDash, bool smallMontyModulus) + // mDash = -m^(-1) mod b + { + int n = m.Length; + + if (n == 1) + { + uint xVal = (uint)x[0]; + x[0] = (int)MultiplyMontyNIsOne(xVal, xVal, (uint)m[0], mDash); + return; + } + + ulong x0 = (uint)x[n - 1]; + int aMax; + + { + ulong carry = x0 * x0; + ulong t = (uint)carry * mDash; + + ulong prod2 = t * (uint)m[n - 1]; + carry += (uint)prod2; + Debug.Assert((uint)carry == 0); + carry = (carry >> 32) + (prod2 >> 32); + + for (int j = n - 2; j >= 0; --j) + { + ulong prod1 = x0 * (uint)x[j]; + prod2 = t * (uint)m[j]; + + carry += (prod2 & UIMASK) + ((uint)prod1 << 1); + a[j + 2] = (int)carry; + carry = (carry >> 32) + (prod1 >> 31) + (prod2 >> 32); + } + + a[1] = (int)carry; + aMax = (int)(carry >> 32); + } + + for (int i = n - 2; i >= 0; --i) + { + uint a0 = (uint)a[n]; + ulong t = a0 * mDash; + + ulong carry = t * (uint)m[n - 1] + a0; + Debug.Assert((uint)carry == 0); + carry >>= 32; + + for (int j = n - 2; j > i; --j) + { + carry += t * (uint)m[j] + (uint)a[j + 1]; + a[j + 2] = (int)carry; + carry >>= 32; + } + + ulong xi = (uint)x[i]; + + { + ulong prod1 = xi * xi; + ulong prod2 = t * (uint)m[i]; + + carry += (prod1 & UIMASK) + (uint)prod2 + (uint)a[i + 1]; + a[i + 2] = (int)carry; + carry = (carry >> 32) + (prod1 >> 32) + (prod2 >> 32); + } + + for (int j = i - 1; j >= 0; --j) + { + ulong prod1 = xi * (uint)x[j]; + ulong prod2 = t * (uint)m[j]; + + carry += (prod2 & UIMASK) + ((uint)prod1 << 1) + (uint)a[j + 1]; + a[j + 2] = (int)carry; + carry = (carry >> 32) + (prod1 >> 31) + (prod2 >> 32); + } + + carry += (uint)aMax; + a[1] = (int)carry; + aMax = (int)(carry >> 32); + } + + a[0] = aMax; + + if (!smallMontyModulus && CompareTo(0, a, 0, m) >= 0) + { + Subtract(0, a, 0, m); + } + + Array.Copy(a, 1, x, 0, n); + } + + private static uint MultiplyMontyNIsOne(uint x, uint y, uint m, uint mDash) + { + ulong carry = (ulong)x * y; + uint t = (uint)carry * mDash; + ulong um = m; + ulong prod2 = um * t; + carry += (uint)prod2; + Debug.Assert((uint)carry == 0); + carry = (carry >> 32) + (prod2 >> 32); + if (carry > um) + { + carry -= um; + } + Debug.Assert(carry < um); + return (uint)carry; + } + + public BigInteger Multiply( + BigInteger val) + { + if (val == this) + return Square(); + + if ((sign & val.sign) == 0) + return Zero; + + if (val.QuickPow2Check()) // val is power of two + { + BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1); + return val.sign > 0 ? result : result.Negate(); + } + + if (this.QuickPow2Check()) // this is power of two + { + BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1); + return this.sign > 0 ? result : result.Negate(); + } + + int resLength = magnitude.Length + val.magnitude.Length; + int[] res = new int[resLength]; + + Multiply(res, this.magnitude, val.magnitude); + + int resSign = sign ^ val.sign ^ 1; + return new BigInteger(resSign, res, true); + } + + public BigInteger Square() + { + if (sign == 0) + return Zero; + if (this.QuickPow2Check()) + return ShiftLeft(Abs().BitLength - 1); + int resLength = magnitude.Length << 1; + if ((uint)magnitude[0] >> 16 == 0) + --resLength; + int[] res = new int[resLength]; + Square(res, magnitude); + return new BigInteger(1, res, false); + } + + public BigInteger Negate() + { + if (sign == 0) + return this; + + return new BigInteger(-sign, magnitude, false); + } + + public BigInteger NextProbablePrime() + { + if (sign < 0) + throw new ArithmeticException("Cannot be called on value < 0"); + + if (CompareTo(Two) < 0) + return Two; + + BigInteger n = Inc().SetBit(0); + + while (!n.CheckProbablePrime(100, RandomSource, false)) + { + n = n.Add(Two); + } + + return n; + } + + public BigInteger Not() + { + return Inc().Negate(); + } + + public BigInteger Pow(int exp) + { + if (exp <= 0) + { + if (exp < 0) + throw new ArithmeticException("Negative exponent"); + + return One; + } + + if (sign == 0) + { + return this; + } + + if (QuickPow2Check()) + { + long powOf2 = (long)exp * (BitLength - 1); + if (powOf2 > Int32.MaxValue) + { + throw new ArithmeticException("Result too large"); + } + return One.ShiftLeft((int)powOf2); + } + + BigInteger y = One; + BigInteger z = this; + + for (;;) + { + if ((exp & 0x1) == 1) + { + y = y.Multiply(z); + } + exp >>= 1; + if (exp == 0) break; + z = z.Multiply(z); + } + + return y; + } + + public static BigInteger ProbablePrime( + int bitLength, + Random random) + { + return new BigInteger(bitLength, 100, random); + } + + private int Remainder( + int m) + { + Debug.Assert(m > 0); + + long acc = 0; + for (int pos = 0; pos < magnitude.Length; ++pos) + { + long posVal = (uint) magnitude[pos]; + acc = (acc << 32 | posVal) % m; + } + + return (int) acc; + } + + /** + * return x = x % y - done in place (y value preserved) + */ + private static int[] Remainder( + int[] x, + int[] y) + { + int xStart = 0; + while (xStart < x.Length && x[xStart] == 0) + { + ++xStart; + } + + int yStart = 0; + while (yStart < y.Length && y[yStart] == 0) + { + ++yStart; + } + + Debug.Assert(yStart < y.Length); + + int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp > 0) + { + int yBitLength = CalcBitLength(1, yStart, y); + int xBitLength = CalcBitLength(1, xStart, x); + int shift = xBitLength - yBitLength; + + int[] c; + int cStart = 0; + int cBitLength = yBitLength; + if (shift > 0) + { + c = ShiftLeft(y, shift); + cBitLength += shift; + Debug.Assert(c[0] != 0); + } + else + { + int len = y.Length - yStart; + c = new int[len]; + Array.Copy(y, yStart, c, 0, len); + } + + for (;;) + { + if (cBitLength < xBitLength + || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) + { + Subtract(xStart, x, cStart, c); + + while (x[xStart] == 0) + { + if (++xStart == x.Length) + return x; + } + + //xBitLength = CalcBitLength(xStart, x); + xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); + + if (xBitLength <= yBitLength) + { + if (xBitLength < yBitLength) + return x; + + xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp <= 0) + break; + } + } + + shift = cBitLength - xBitLength; + + // NB: The case where c[cStart] is 1-bit is harmless + if (shift == 1) + { + uint firstC = (uint) c[cStart] >> 1; + uint firstX = (uint) x[xStart]; + if (firstC > firstX) + ++shift; + } + + if (shift < 2) + { + ShiftRightOneInPlace(cStart, c); + --cBitLength; + } + else + { + ShiftRightInPlace(cStart, c, shift); + cBitLength -= shift; + } + + //cStart = c.Length - ((cBitLength + 31) / 32); + while (c[cStart] == 0) + { + ++cStart; + } + } + } + + if (xyCmp == 0) + { + Array.Clear(x, xStart, x.Length - xStart); + } + + return x; + } + + public BigInteger Remainder( + BigInteger n) + { + if (n.sign == 0) + throw new ArithmeticException("Division by zero error"); + + if (this.sign == 0) + return Zero; + + // For small values, use fast remainder method + if (n.magnitude.Length == 1) + { + int val = n.magnitude[0]; + + if (val > 0) + { + if (val == 1) + return Zero; + + // TODO Make this func work on uint, and handle val == 1? + int rem = Remainder(val); + + return rem == 0 + ? Zero + : new BigInteger(sign, new int[]{ rem }, false); + } + } + + if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0) + return this; + + int[] result; + if (n.QuickPow2Check()) // n is power of two + { + // TODO Move before small values branch above? + result = LastNBits(n.Abs().BitLength - 1); + } + else + { + result = (int[]) this.magnitude.Clone(); + result = Remainder(result, n.magnitude); + } + + return new BigInteger(sign, result, true); + } + + private int[] LastNBits( + int n) + { + if (n < 1) + return ZeroMagnitude; + + int numWords = (n + BitsPerInt - 1) / BitsPerInt; + numWords = System.Math.Min(numWords, this.magnitude.Length); + int[] result = new int[numWords]; + + Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords); + + int excessBits = (numWords << 5) - n; + if (excessBits > 0) + { + result[0] &= (int)(UInt32.MaxValue >> excessBits); + } + + return result; + } + + private BigInteger DivideWords(int w) + { + Debug.Assert(w >= 0); + int n = magnitude.Length; + if (w >= n) + return Zero; + int[] mag = new int[n - w]; + Array.Copy(magnitude, 0, mag, 0, n - w); + return new BigInteger(sign, mag, false); + } + + private BigInteger RemainderWords(int w) + { + Debug.Assert(w >= 0); + int n = magnitude.Length; + if (w >= n) + return this; + int[] mag = new int[w]; + Array.Copy(magnitude, n - w, mag, 0, w); + return new BigInteger(sign, mag, false); + } + + /** + * do a left shift - this returns a new array. + */ + private static int[] ShiftLeft( + int[] mag, + int n) + { + int nInts = (int)((uint)n >> 5); + int nBits = n & 0x1f; + int magLen = mag.Length; + int[] newMag; + + if (nBits == 0) + { + newMag = new int[magLen + nInts]; + mag.CopyTo(newMag, 0); + } + else + { + int i = 0; + int nBits2 = 32 - nBits; + int highBits = (int)((uint)mag[0] >> nBits2); + + if (highBits != 0) + { + newMag = new int[magLen + nInts + 1]; + newMag[i++] = highBits; + } + else + { + newMag = new int[magLen + nInts]; + } + + int m = mag[0]; + for (int j = 0; j < magLen - 1; j++) + { + int next = mag[j + 1]; + + newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2); + m = next; + } + + newMag[i] = mag[magLen - 1] << nBits; + } + + return newMag; + } + + private static int ShiftLeftOneInPlace(int[] x, int carry) + { + Debug.Assert(carry == 0 || carry == 1); + int pos = x.Length; + while (--pos >= 0) + { + uint val = (uint)x[pos]; + x[pos] = (int)(val << 1) | carry; + carry = (int)(val >> 31); + } + return carry; + } + + public BigInteger ShiftLeft( + int n) + { + if (sign == 0 || magnitude.Length == 0) + return Zero; + + if (n == 0) + return this; + + if (n < 0) + return ShiftRight(-n); + + BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true); + + if (this.nBits != -1) + { + result.nBits = sign > 0 + ? this.nBits + : this.nBits + n; + } + + if (this.nBitLength != -1) + { + result.nBitLength = this.nBitLength + n; + } + + return result; + } + + /** + * do a right shift - this does it in place. + */ + private static void ShiftRightInPlace( + int start, + int[] mag, + int n) + { + int nInts = (int)((uint)n >> 5) + start; + int nBits = n & 0x1f; + int magEnd = mag.Length - 1; + + if (nInts != start) + { + int delta = (nInts - start); + + for (int i = magEnd; i >= nInts; i--) + { + mag[i] = mag[i - delta]; + } + for (int i = nInts - 1; i >= start; i--) + { + mag[i] = 0; + } + } + + if (nBits != 0) + { + int nBits2 = 32 - nBits; + int m = mag[magEnd]; + + for (int i = magEnd; i > nInts; --i) + { + int next = mag[i - 1]; + + mag[i] = (int)((uint)m >> nBits) | (next << nBits2); + m = next; + } + + mag[nInts] = (int)((uint)mag[nInts] >> nBits); + } + } + + /** + * do a right shift by one - this does it in place. + */ + private static void ShiftRightOneInPlace( + int start, + int[] mag) + { + int i = mag.Length; + int m = mag[i - 1]; + + while (--i > start) + { + int next = mag[i - 1]; + mag[i] = ((int)((uint)m >> 1)) | (next << 31); + m = next; + } + + mag[start] = (int)((uint)mag[start] >> 1); + } + + public BigInteger ShiftRight( + int n) + { + if (n == 0) + return this; + + if (n < 0) + return ShiftLeft(-n); + + if (n >= BitLength) + return (this.sign < 0 ? One.Negate() : Zero); + +// int[] res = (int[]) this.magnitude.Clone(); +// +// ShiftRightInPlace(0, res, n); +// +// return new BigInteger(this.sign, res, true); + + int resultLength = (BitLength - n + 31) >> 5; + int[] res = new int[resultLength]; + + int numInts = n >> 5; + int numBits = n & 31; + + if (numBits == 0) + { + Array.Copy(this.magnitude, 0, res, 0, res.Length); + } + else + { + int numBits2 = 32 - numBits; + + int magPos = this.magnitude.Length - 1 - numInts; + for (int i = resultLength - 1; i >= 0; --i) + { + res[i] = (int)((uint) this.magnitude[magPos--] >> numBits); + + if (magPos >= 0) + { + res[i] |= this.magnitude[magPos] << numBits2; + } + } + } + + Debug.Assert(res[0] != 0); + + return new BigInteger(this.sign, res, false); + } + + public int SignValue + { + get { return sign; } + } + + /** + * returns x = x - y - we assume x is >= y + */ + private static int[] Subtract( + int xStart, + int[] x, + int yStart, + int[] y) + { + Debug.Assert(yStart < y.Length); + Debug.Assert(x.Length - xStart >= y.Length - yStart); + + int iT = x.Length; + int iV = y.Length; + long m; + int borrow = 0; + + do + { + m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow; + x[iT] = (int) m; + +// borrow = (m < 0) ? -1 : 0; + borrow = (int)(m >> 63); + } + while (iV > yStart); + + if (borrow != 0) + { + while (--x[--iT] == -1) + { + } + } + + return x; + } + + public BigInteger Subtract( + BigInteger n) + { + if (n.sign == 0) + return this; + + if (this.sign == 0) + return n.Negate(); + + if (this.sign != n.sign) + return Add(n.Negate()); + + int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude); + if (compare == 0) + return Zero; + + BigInteger bigun, lilun; + if (compare < 0) + { + bigun = n; + lilun = this; + } + else + { + bigun = this; + lilun = n; + } + + return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true); + } + + private static int[] doSubBigLil( + int[] bigMag, + int[] lilMag) + { + int[] res = (int[]) bigMag.Clone(); + + return Subtract(0, res, 0, lilMag); + } + + public byte[] ToByteArray() + { + return ToByteArray(false); + } + + public byte[] ToByteArrayUnsigned() + { + return ToByteArray(true); + } + + private byte[] ToByteArray( + bool unsigned) + { + if (sign == 0) + return unsigned ? ZeroEncoding : new byte[1]; + + int nBits = (unsigned && sign > 0) + ? BitLength + : BitLength + 1; + + int nBytes = GetByteLength(nBits); + byte[] bytes = new byte[nBytes]; + + int magIndex = magnitude.Length; + int bytesIndex = bytes.Length; + + if (sign > 0) + { + while (magIndex > 1) + { + uint mag = (uint) magnitude[--magIndex]; + bytes[--bytesIndex] = (byte) mag; + bytes[--bytesIndex] = (byte)(mag >> 8); + bytes[--bytesIndex] = (byte)(mag >> 16); + bytes[--bytesIndex] = (byte)(mag >> 24); + } + + uint lastMag = (uint) magnitude[0]; + while (lastMag > byte.MaxValue) + { + bytes[--bytesIndex] = (byte) lastMag; + lastMag >>= 8; + } + + bytes[--bytesIndex] = (byte) lastMag; + } + else // sign < 0 + { + bool carry = true; + + while (magIndex > 1) + { + uint mag = ~((uint) magnitude[--magIndex]); + + if (carry) + { + carry = (++mag == uint.MinValue); + } + + bytes[--bytesIndex] = (byte) mag; + bytes[--bytesIndex] = (byte)(mag >> 8); + bytes[--bytesIndex] = (byte)(mag >> 16); + bytes[--bytesIndex] = (byte)(mag >> 24); + } + + uint lastMag = (uint) magnitude[0]; + + if (carry) + { + // Never wraps because magnitude[0] != 0 + --lastMag; + } + + while (lastMag > byte.MaxValue) + { + bytes[--bytesIndex] = (byte) ~lastMag; + lastMag >>= 8; + } + + bytes[--bytesIndex] = (byte) ~lastMag; + + if (bytesIndex > 0) + { + bytes[--bytesIndex] = byte.MaxValue; + } + } + + return bytes; + } + + public override string ToString() + { + return ToString(10); + } + + public string ToString(int radix) + { + // TODO Make this method work for other radices (ideally 2 <= radix <= 36 as in Java) + + switch (radix) + { + case 2: + case 8: + case 10: + case 16: + break; + default: + throw new FormatException("Only bases 2, 8, 10, 16 are allowed"); + } + + // NB: Can only happen to internally managed instances + if (magnitude == null) + return "null"; + + if (sign == 0) + return "0"; + + + // NOTE: This *should* be unnecessary, since the magnitude *should* never have leading zero digits + int firstNonZero = 0; + while (firstNonZero < magnitude.Length) + { + if (magnitude[firstNonZero] != 0) + { + break; + } + ++firstNonZero; + } + + if (firstNonZero == magnitude.Length) + { + return "0"; + } + + + StringBuilder sb = new StringBuilder(); + if (sign == -1) + { + sb.Append('-'); + } + + switch (radix) + { + case 2: + { + int pos = firstNonZero; + sb.Append(Convert.ToString(magnitude[pos], 2)); + while (++pos < magnitude.Length) + { + AppendZeroExtendedString(sb, Convert.ToString(magnitude[pos], 2), 32); + } + break; + } + case 8: + { + int mask = (1 << 30) - 1; + BigInteger u = this.Abs(); + int bits = u.BitLength; + IList S = new List(); + while (bits > 30) + { + S.Add(Convert.ToString(u.IntValue & mask, 8)); + u = u.ShiftRight(30); + bits -= 30; + } + sb.Append(Convert.ToString(u.IntValue, 8)); + for (int i = S.Count - 1; i >= 0; --i) + { + AppendZeroExtendedString(sb, (string)S[i], 10); + } + break; + } + case 16: + { + int pos = firstNonZero; + sb.Append(Convert.ToString(magnitude[pos], 16)); + while (++pos < magnitude.Length) + { + AppendZeroExtendedString(sb, Convert.ToString(magnitude[pos], 16), 8); + } + break; + } + // TODO This could work for other radices if there is an alternative to Convert.ToString method + //default: + case 10: + { + BigInteger q = this.Abs(); + if (q.BitLength < 64) + { + sb.Append(Convert.ToString(q.LongValue, radix)); + break; + } + + // TODO Could cache the moduli for each radix (soft reference?) + IList moduli = new List(); + BigInteger R = BigInteger.ValueOf(radix); + while (R.CompareTo(q) <= 0) + { + moduli.Add(R); + R = R.Square(); + } + + int scale = moduli.Count; + sb.EnsureCapacity(sb.Length + (1 << scale)); + + ToString(sb, radix, moduli, scale, q); + + break; + } + } + + return sb.ToString(); + } + + private static void ToString(StringBuilder sb, int radix, IList moduli, int scale, BigInteger pos) + { + if (pos.BitLength < 64) + { + string s = Convert.ToString(pos.LongValue, radix); + if (sb.Length > 1 || (sb.Length == 1 && sb[0] != '-')) + { + AppendZeroExtendedString(sb, s, 1 << scale); + } + else if (pos.SignValue != 0) + { + sb.Append(s); + } + return; + } + + BigInteger[] qr = pos.DivideAndRemainder((BigInteger)moduli[--scale]); + + ToString(sb, radix, moduli, scale, qr[0]); + ToString(sb, radix, moduli, scale, qr[1]); + } + + private static void AppendZeroExtendedString(StringBuilder sb, string s, int minLength) + { + for (int len = s.Length; len < minLength; ++len) + { + sb.Append('0'); + } + sb.Append(s); + } + + private static BigInteger CreateUValueOf( + ulong value) + { + int msw = (int)(value >> 32); + int lsw = (int)value; + + if (msw != 0) + return new BigInteger(1, new int[] { msw, lsw }, false); + + if (lsw != 0) + { + BigInteger n = new BigInteger(1, new int[] { lsw }, false); + // Check for a power of two + if ((lsw & -lsw) == lsw) + { + n.nBits = 1; + } + return n; + } + + return Zero; + } + + private static BigInteger CreateValueOf( + long value) + { + if (value < 0) + { + if (value == long.MinValue) + return CreateValueOf(~value).Not(); + + return CreateValueOf(-value).Negate(); + } + + return CreateUValueOf((ulong)value); + } + + public static BigInteger ValueOf( + long value) + { + if (value >= 0 && value < SMALL_CONSTANTS.Length) + { + return SMALL_CONSTANTS[value]; + } + + return CreateValueOf(value); + } + + public int GetLowestSetBit() + { + if (this.sign == 0) + return -1; + + return GetLowestSetBitMaskFirst(-1); + } + + private int GetLowestSetBitMaskFirst(int firstWordMask) + { + int w = magnitude.Length, offset = 0; + + uint word = (uint)(magnitude[--w] & firstWordMask); + Debug.Assert(magnitude[0] != 0); + + while (word == 0) + { + word = (uint)magnitude[--w]; + offset += 32; + } + + while ((word & 0xFF) == 0) + { + word >>= 8; + offset += 8; + } + + while ((word & 1) == 0) + { + word >>= 1; + ++offset; + } + + return offset; + } + + public bool TestBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit position must not be negative"); + + if (sign < 0) + return !Not().TestBit(n); + + int wordNum = n / 32; + if (wordNum >= magnitude.Length) + return false; + + int word = magnitude[magnitude.Length - 1 - wordNum]; + return ((word >> (n % 32)) & 1) > 0; + } + + public BigInteger Or( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (value.sign == 0) + return this; + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + bool resultNeg = sign < 0 || value.sign < 0; + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord | bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger Xor( + BigInteger value) + { + if (this.sign == 0) + return value; + + if (value.sign == 0) + return this; + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + // TODO Can just replace with sign != value.sign? + bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0); + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) + { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) + { + aWord = ~aWord; + } + + if (value.sign < 0) + { + bWord = ~bWord; + } + + resultMag[i] = aWord ^ bWord; + + if (resultNeg) + { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) + { + result = result.Not(); + } + + return result; + } + + public BigInteger SetBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + if (TestBit(n)) + return this; + + // TODO Handle negative values and zero + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return Or(One.ShiftLeft(n)); + } + + public BigInteger ClearBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + if (!TestBit(n)) + return this; + + // TODO Handle negative values + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return AndNot(One.ShiftLeft(n)); + } + + public BigInteger FlipBit( + int n) + { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + // TODO Handle negative values and zero + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return Xor(One.ShiftLeft(n)); + } + + private BigInteger FlipExistingBit( + int n) + { + Debug.Assert(sign > 0); + Debug.Assert(n >= 0); + Debug.Assert(n < BitLength - 1); + + int[] mag = (int[]) this.magnitude.Clone(); + mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit + //mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32)); + return new BigInteger(this.sign, mag, false); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECAlgorithms.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECAlgorithms.cs new file mode 100644 index 00000000..1347a9af --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECAlgorithms.cs @@ -0,0 +1,496 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Endo; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier; +using Renci.SshNet.Security.Org.BouncyCastle.Math.Field; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC +{ + internal class ECAlgorithms + { + public static bool IsF2mCurve(ECCurve c) + { + return IsF2mField(c.Field); + } + + public static bool IsF2mField(IFiniteField field) + { + return field.Dimension > 1 && field.Characteristic.Equals(BigInteger.Two) + && field is IPolynomialExtensionField; + } + + public static bool IsFpCurve(ECCurve c) + { + return IsFpField(c.Field); + } + + public static bool IsFpField(IFiniteField field) + { + return field.Dimension == 1; + } + + public static ECPoint SumOfMultiplies(ECPoint[] ps, BigInteger[] ks) + { + if (ps == null || ks == null || ps.Length != ks.Length || ps.Length < 1) + throw new ArgumentException("point and scalar arrays should be non-null, and of equal, non-zero, length"); + + int count = ps.Length; + switch (count) + { + case 1: + return ps[0].Multiply(ks[0]); + case 2: + return SumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]); + default: + break; + } + + ECPoint p = ps[0]; + ECCurve c = p.Curve; + + ECPoint[] imported = new ECPoint[count]; + imported[0] = p; + for (int i = 1; i < count; ++i) + { + imported[i] = ImportPoint(c, ps[i]); + } + + GlvEndomorphism glvEndomorphism = c.GetEndomorphism() as GlvEndomorphism; + if (glvEndomorphism != null) + { + return ImplCheckResult(ImplSumOfMultipliesGlv(imported, ks, glvEndomorphism)); + } + + return ImplCheckResult(ImplSumOfMultiplies(imported, ks)); + } + + public static ECPoint SumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b) + { + ECCurve cp = P.Curve; + Q = ImportPoint(cp, Q); + + // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick + { + AbstractF2mCurve f2mCurve = cp as AbstractF2mCurve; + if (f2mCurve != null && f2mCurve.IsKoblitz) + { + return ImplCheckResult(P.Multiply(a).Add(Q.Multiply(b))); + } + } + + GlvEndomorphism glvEndomorphism = cp.GetEndomorphism() as GlvEndomorphism; + if (glvEndomorphism != null) + { + return ImplCheckResult( + ImplSumOfMultipliesGlv(new ECPoint[] { P, Q }, new BigInteger[] { a, b }, glvEndomorphism)); + } + + return ImplCheckResult(ImplShamirsTrickWNaf(P, a, Q, b)); + } + + /* + * "Shamir's Trick", originally due to E. G. Straus + * (Addition chains of vectors. American Mathematical Monthly, + * 71(7):806-808, Aug./Sept. 1964) + * + * Input: The points P, Q, scalar k = (km?, ... , k1, k0) + * and scalar l = (lm?, ... , l1, l0). + * Output: R = k * P + l * Q. + * 1: Z <- P + Q + * 2: R <- O + * 3: for i from m-1 down to 0 do + * 4: R <- R + R {point doubling} + * 5: if (ki = 1) and (li = 0) then R <- R + P end if + * 6: if (ki = 0) and (li = 1) then R <- R + Q end if + * 7: if (ki = 1) and (li = 1) then R <- R + Z end if + * 8: end for + * 9: return R + */ + public static ECPoint ShamirsTrick(ECPoint P, BigInteger k, ECPoint Q, BigInteger l) + { + ECCurve cp = P.Curve; + Q = ImportPoint(cp, Q); + + return ImplCheckResult(ImplShamirsTrickJsf(P, k, Q, l)); + } + + public static ECPoint ImportPoint(ECCurve c, ECPoint p) + { + ECCurve cp = p.Curve; + if (!c.Equals(cp)) + throw new ArgumentException("Point must be on the same curve"); + + return c.ImportPoint(p); + } + + public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len) + { + MontgomeryTrick(zs, off, len, null); + } + + public static void MontgomeryTrick(ECFieldElement[] zs, int off, int len, ECFieldElement scale) + { + /* + * Uses the "Montgomery Trick" to invert many field elements, with only a single actual + * field inversion. See e.g. the paper: + * "Fast Multi-scalar Multiplication Methods on Elliptic Curves with Precomputation Strategy Using Montgomery Trick" + * by Katsuyuki Okeya, Kouichi Sakurai. + */ + + ECFieldElement[] c = new ECFieldElement[len]; + c[0] = zs[off]; + + int i = 0; + while (++i < len) + { + c[i] = c[i - 1].Multiply(zs[off + i]); + } + + --i; + + if (scale != null) + { + c[i] = c[i].Multiply(scale); + } + + ECFieldElement u = c[i].Invert(); + + while (i > 0) + { + int j = off + i--; + ECFieldElement tmp = zs[j]; + zs[j] = c[i].Multiply(u); + u = u.Multiply(tmp); + } + + zs[off] = u; + } + + /** + * Simple shift-and-add multiplication. Serves as reference implementation + * to verify (possibly faster) implementations, and for very small scalars. + * + * @param p + * The point to multiply. + * @param k + * The multiplier. + * @return The result of the point multiplication kP. + */ + public static ECPoint ReferenceMultiply(ECPoint p, BigInteger k) + { + BigInteger x = k.Abs(); + ECPoint q = p.Curve.Infinity; + int t = x.BitLength; + if (t > 0) + { + if (x.TestBit(0)) + { + q = p; + } + for (int i = 1; i < t; i++) + { + p = p.Twice(); + if (x.TestBit(i)) + { + q = q.Add(p); + } + } + } + return k.SignValue < 0 ? q.Negate() : q; + } + + public static ECPoint ValidatePoint(ECPoint p) + { + if (!p.IsValid()) + throw new InvalidOperationException("Invalid point"); + + return p; + } + + public static ECPoint CleanPoint(ECCurve c, ECPoint p) + { + ECCurve cp = p.Curve; + if (!c.Equals(cp)) + throw new ArgumentException("Point must be on the same curve", "p"); + + return c.DecodePoint(p.GetEncoded(false)); + } + + internal static ECPoint ImplCheckResult(ECPoint p) + { + if (!p.IsValidPartial()) + throw new InvalidOperationException("Invalid result"); + + return p; + } + + internal static ECPoint ImplShamirsTrickJsf(ECPoint P, BigInteger k, ECPoint Q, BigInteger l) + { + ECCurve curve = P.Curve; + ECPoint infinity = curve.Infinity; + + // TODO conjugate co-Z addition (ZADDC) can return both of these + ECPoint PaddQ = P.Add(Q); + ECPoint PsubQ = P.Subtract(Q); + + ECPoint[] points = new ECPoint[] { Q, PsubQ, P, PaddQ }; + curve.NormalizeAll(points); + + ECPoint[] table = new ECPoint[] { + points[3].Negate(), points[2].Negate(), points[1].Negate(), + points[0].Negate(), infinity, points[0], + points[1], points[2], points[3] }; + + byte[] jsf = WNafUtilities.GenerateJsf(k, l); + + ECPoint R = infinity; + + int i = jsf.Length; + while (--i >= 0) + { + int jsfi = jsf[i]; + + // NOTE: The shifting ensures the sign is extended correctly + int kDigit = ((jsfi << 24) >> 28), lDigit = ((jsfi << 28) >> 28); + + int index = 4 + (kDigit * 3) + lDigit; + R = R.TwicePlus(table[index]); + } + + return R; + } + + internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k, + ECPoint Q, BigInteger l) + { + bool negK = k.SignValue < 0, negL = l.SignValue < 0; + + k = k.Abs(); + l = l.Abs(); + + int widthP = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(k.BitLength))); + int widthQ = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(l.BitLength))); + + WNafPreCompInfo infoP = WNafUtilities.Precompute(P, widthP, true); + WNafPreCompInfo infoQ = WNafUtilities.Precompute(Q, widthQ, true); + + ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp; + ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp; + ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg; + ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg; + + byte[] wnafP = WNafUtilities.GenerateWindowNaf(widthP, k); + byte[] wnafQ = WNafUtilities.GenerateWindowNaf(widthQ, l); + + return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ); + } + + internal static ECPoint ImplShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l) + { + bool negK = k.SignValue < 0, negL = l.SignValue < 0; + + k = k.Abs(); + l = l.Abs(); + + int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(k.BitLength, l.BitLength)))); + + ECPoint Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMapQ); + WNafPreCompInfo infoP = WNafUtilities.GetWNafPreCompInfo(P); + WNafPreCompInfo infoQ = WNafUtilities.GetWNafPreCompInfo(Q); + + ECPoint[] preCompP = negK ? infoP.PreCompNeg : infoP.PreComp; + ECPoint[] preCompQ = negL ? infoQ.PreCompNeg : infoQ.PreComp; + ECPoint[] preCompNegP = negK ? infoP.PreComp : infoP.PreCompNeg; + ECPoint[] preCompNegQ = negL ? infoQ.PreComp : infoQ.PreCompNeg; + + byte[] wnafP = WNafUtilities.GenerateWindowNaf(width, k); + byte[] wnafQ = WNafUtilities.GenerateWindowNaf(width, l); + + return ImplShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ); + } + + private static ECPoint ImplShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP, + ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ) + { + int len = System.Math.Max(wnafP.Length, wnafQ.Length); + + ECCurve curve = preCompP[0].Curve; + ECPoint infinity = curve.Infinity; + + ECPoint R = infinity; + int zeroes = 0; + + for (int i = len - 1; i >= 0; --i) + { + int wiP = i < wnafP.Length ? (int)(sbyte)wnafP[i] : 0; + int wiQ = i < wnafQ.Length ? (int)(sbyte)wnafQ[i] : 0; + + if ((wiP | wiQ) == 0) + { + ++zeroes; + continue; + } + + ECPoint r = infinity; + if (wiP != 0) + { + int nP = System.Math.Abs(wiP); + ECPoint[] tableP = wiP < 0 ? preCompNegP : preCompP; + r = r.Add(tableP[nP >> 1]); + } + if (wiQ != 0) + { + int nQ = System.Math.Abs(wiQ); + ECPoint[] tableQ = wiQ < 0 ? preCompNegQ : preCompQ; + r = r.Add(tableQ[nQ >> 1]); + } + + if (zeroes > 0) + { + R = R.TimesPow2(zeroes); + zeroes = 0; + } + + R = R.TwicePlus(r); + } + + if (zeroes > 0) + { + R = R.TimesPow2(zeroes); + } + + return R; + } + + internal static ECPoint ImplSumOfMultiplies(ECPoint[] ps, BigInteger[] ks) + { + int count = ps.Length; + bool[] negs = new bool[count]; + WNafPreCompInfo[] infos = new WNafPreCompInfo[count]; + byte[][] wnafs = new byte[count][]; + + for (int i = 0; i < count; ++i) + { + BigInteger ki = ks[i]; negs[i] = ki.SignValue < 0; ki = ki.Abs(); + + int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(ki.BitLength))); + infos[i] = WNafUtilities.Precompute(ps[i], width, true); + wnafs[i] = WNafUtilities.GenerateWindowNaf(width, ki); + } + + return ImplSumOfMultiplies(negs, infos, wnafs); + } + + internal static ECPoint ImplSumOfMultipliesGlv(ECPoint[] ps, BigInteger[] ks, GlvEndomorphism glvEndomorphism) + { + BigInteger n = ps[0].Curve.Order; + + int len = ps.Length; + + BigInteger[] abs = new BigInteger[len << 1]; + for (int i = 0, j = 0; i < len; ++i) + { + BigInteger[] ab = glvEndomorphism.DecomposeScalar(ks[i].Mod(n)); + abs[j++] = ab[0]; + abs[j++] = ab[1]; + } + + ECPointMap pointMap = glvEndomorphism.PointMap; + if (glvEndomorphism.HasEfficientPointMap) + { + return ECAlgorithms.ImplSumOfMultiplies(ps, pointMap, abs); + } + + ECPoint[] pqs = new ECPoint[len << 1]; + for (int i = 0, j = 0; i < len; ++i) + { + ECPoint p = ps[i], q = pointMap.Map(p); + pqs[j++] = p; + pqs[j++] = q; + } + + return ECAlgorithms.ImplSumOfMultiplies(pqs, abs); + } + + internal static ECPoint ImplSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks) + { + int halfCount = ps.Length, fullCount = halfCount << 1; + + bool[] negs = new bool[fullCount]; + WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount]; + byte[][] wnafs = new byte[fullCount][]; + + for (int i = 0; i < halfCount; ++i) + { + int j0 = i << 1, j1 = j0 + 1; + + BigInteger kj0 = ks[j0]; negs[j0] = kj0.SignValue < 0; kj0 = kj0.Abs(); + BigInteger kj1 = ks[j1]; negs[j1] = kj1.SignValue < 0; kj1 = kj1.Abs(); + + int width = System.Math.Max(2, System.Math.Min(16, WNafUtilities.GetWindowSize(System.Math.Max(kj0.BitLength, kj1.BitLength)))); + + ECPoint P = ps[i], Q = WNafUtilities.MapPointWithPrecomp(P, width, true, pointMap); + infos[j0] = WNafUtilities.GetWNafPreCompInfo(P); + infos[j1] = WNafUtilities.GetWNafPreCompInfo(Q); + wnafs[j0] = WNafUtilities.GenerateWindowNaf(width, kj0); + wnafs[j1] = WNafUtilities.GenerateWindowNaf(width, kj1); + } + + return ImplSumOfMultiplies(negs, infos, wnafs); + } + + private static ECPoint ImplSumOfMultiplies(bool[] negs, WNafPreCompInfo[] infos, byte[][] wnafs) + { + int len = 0, count = wnafs.Length; + for (int i = 0; i < count; ++i) + { + len = System.Math.Max(len, wnafs[i].Length); + } + + ECCurve curve = infos[0].PreComp[0].Curve; + ECPoint infinity = curve.Infinity; + + ECPoint R = infinity; + int zeroes = 0; + + for (int i = len - 1; i >= 0; --i) + { + ECPoint r = infinity; + + for (int j = 0; j < count; ++j) + { + byte[] wnaf = wnafs[j]; + int wi = i < wnaf.Length ? (int)(sbyte)wnaf[i] : 0; + if (wi != 0) + { + int n = System.Math.Abs(wi); + WNafPreCompInfo info = infos[j]; + ECPoint[] table = (wi < 0 == negs[j]) ? info.PreComp : info.PreCompNeg; + r = r.Add(table[n >> 1]); + } + } + + if (r == infinity) + { + ++zeroes; + continue; + } + + if (zeroes > 0) + { + R = R.TimesPow2(zeroes); + zeroes = 0; + } + + R = R.TwicePlus(r); + } + + if (zeroes > 0) + { + R = R.TimesPow2(zeroes); + } + + return R; + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECCurve.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECCurve.cs new file mode 100644 index 00000000..46c69184 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECCurve.cs @@ -0,0 +1,1278 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Abc; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Endo; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier; +using Renci.SshNet.Security.Org.BouncyCastle.Math.Field; +using Renci.SshNet.Security.Org.BouncyCastle.Math.Raw; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC +{ + /// Base class for an elliptic curve. + internal abstract class ECCurve + { + public const int COORD_AFFINE = 0; + public const int COORD_HOMOGENEOUS = 1; + public const int COORD_JACOBIAN = 2; + public const int COORD_JACOBIAN_CHUDNOVSKY = 3; + public const int COORD_JACOBIAN_MODIFIED = 4; + public const int COORD_LAMBDA_AFFINE = 5; + public const int COORD_LAMBDA_PROJECTIVE = 6; + public const int COORD_SKEWED = 7; + + public static int[] GetAllCoordinateSystems() + { + return new int[]{ COORD_AFFINE, COORD_HOMOGENEOUS, COORD_JACOBIAN, COORD_JACOBIAN_CHUDNOVSKY, + COORD_JACOBIAN_MODIFIED, COORD_LAMBDA_AFFINE, COORD_LAMBDA_PROJECTIVE, COORD_SKEWED }; + } + + internal class Config + { + protected ECCurve outer; + protected int coord; + protected ECEndomorphism endomorphism; + protected ECMultiplier multiplier; + + internal Config(ECCurve outer, int coord, ECEndomorphism endomorphism, ECMultiplier multiplier) + { + this.outer = outer; + this.coord = coord; + this.endomorphism = endomorphism; + this.multiplier = multiplier; + } + + public Config SetCoordinateSystem(int coord) + { + this.coord = coord; + return this; + } + + public Config SetEndomorphism(ECEndomorphism endomorphism) + { + this.endomorphism = endomorphism; + return this; + } + + public Config SetMultiplier(ECMultiplier multiplier) + { + this.multiplier = multiplier; + return this; + } + + public ECCurve Create() + { + if (!outer.SupportsCoordinateSystem(coord)) + { + throw new InvalidOperationException("unsupported coordinate system"); + } + + ECCurve c = outer.CloneCurve(); + if (c == outer) + { + throw new InvalidOperationException("implementation returned current curve"); + } + + c.m_coord = coord; + c.m_endomorphism = endomorphism; + c.m_multiplier = multiplier; + + return c; + } + } + + protected readonly IFiniteField m_field; + protected ECFieldElement m_a, m_b; + protected BigInteger m_order, m_cofactor; + + protected int m_coord = COORD_AFFINE; + protected ECEndomorphism m_endomorphism = null; + protected ECMultiplier m_multiplier = null; + + protected ECCurve(IFiniteField field) + { + this.m_field = field; + } + + public abstract int FieldSize { get; } + public abstract ECFieldElement FromBigInteger(BigInteger x); + public abstract bool IsValidFieldElement(BigInteger x); + + public virtual Config Configure() + { + return new Config(this, this.m_coord, this.m_endomorphism, this.m_multiplier); + } + + public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y) + { + ECPoint p = CreatePoint(x, y); + if (!p.IsValid()) + { + throw new ArgumentException("Invalid point coordinates"); + } + return p; + } + + public virtual ECPoint ValidatePoint(BigInteger x, BigInteger y, bool withCompression) + { + ECPoint p = CreatePoint(x, y, withCompression); + if (!p.IsValid()) + { + throw new ArgumentException("Invalid point coordinates"); + } + return p; + } + + public virtual ECPoint CreatePoint(BigInteger x, BigInteger y) + { + return CreatePoint(x, y, false); + } + + public virtual ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression) + { + return CreateRawPoint(FromBigInteger(x), FromBigInteger(y), withCompression); + } + + protected abstract ECCurve CloneCurve(); + + protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression); + + protected internal abstract ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression); + + protected virtual ECMultiplier CreateDefaultMultiplier() + { + GlvEndomorphism glvEndomorphism = m_endomorphism as GlvEndomorphism; + if (glvEndomorphism != null) + { + return new GlvMultiplier(this, glvEndomorphism); + } + + return new WNafL2RMultiplier(); + } + + public virtual bool SupportsCoordinateSystem(int coord) + { + return coord == COORD_AFFINE; + } + + public virtual PreCompInfo GetPreCompInfo(ECPoint point, string name) + { + CheckPoint(point); + + IDictionary table; + lock (point) + { + table = point.m_preCompTable; + } + + if (null == table) + return null; + + lock (table) + { + return (PreCompInfo)table[name]; + } + } + + /** + * Compute a PreCompInfo for a point on this curve, under a given name. Used by + * ECMultipliers to save the precomputation for this ECPoint for use + * by subsequent multiplication. + * + * @param point + * The ECPoint to store precomputations for. + * @param name + * A String used to index precomputations of different types. + * @param callback + * Called to calculate the PreCompInfo. + */ + public virtual PreCompInfo Precompute(ECPoint point, string name, IPreCompCallback callback) + { + CheckPoint(point); + + IDictionary table; + lock (point) + { + table = point.m_preCompTable; + if (null == table) + { + point.m_preCompTable = table = new Dictionary(4); + } + } + + lock (table) + { + PreCompInfo existing = (PreCompInfo)table[name]; + PreCompInfo result = callback.Precompute(existing); + + if (result != existing) + { + table[name] = result; + } + + return result; + } + } + + public virtual ECPoint ImportPoint(ECPoint p) + { + if (this == p.Curve) + { + return p; + } + if (p.IsInfinity) + { + return Infinity; + } + + // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates. + p = p.Normalize(); + + return CreatePoint(p.XCoord.ToBigInteger(), p.YCoord.ToBigInteger(), p.IsCompressed); + } + + /** + * Normalization ensures that any projective coordinate is 1, and therefore that the x, y + * coordinates reflect those of the equivalent point in an affine coordinate system. Where more + * than one point is to be normalized, this method will generally be more efficient than + * normalizing each point separately. + * + * @param points + * An array of points that will be updated in place with their normalized versions, + * where necessary + */ + public virtual void NormalizeAll(ECPoint[] points) + { + NormalizeAll(points, 0, points.Length, null); + } + + /** + * Normalization ensures that any projective coordinate is 1, and therefore that the x, y + * coordinates reflect those of the equivalent point in an affine coordinate system. Where more + * than one point is to be normalized, this method will generally be more efficient than + * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively + * each z coordinate is scaled by this value prior to normalization (but only one + * actual multiplication is needed). + * + * @param points + * An array of points that will be updated in place with their normalized versions, + * where necessary + * @param off + * The start of the range of points to normalize + * @param len + * The length of the range of points to normalize + * @param iso + * The (optional) z-scaling factor - can be null + */ + public virtual void NormalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso) + { + CheckPoints(points, off, len); + + switch (this.CoordinateSystem) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + if (iso != null) + throw new ArgumentException("not valid for affine coordinates", "iso"); + + return; + } + } + + /* + * Figure out which of the points actually need to be normalized + */ + ECFieldElement[] zs = new ECFieldElement[len]; + int[] indices = new int[len]; + int count = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + if (null != p && (iso != null || !p.IsNormalized())) + { + zs[count] = p.GetZCoord(0); + indices[count++] = off + i; + } + } + + if (count == 0) + { + return; + } + + ECAlgorithms.MontgomeryTrick(zs, 0, count, iso); + + for (int j = 0; j < count; ++j) + { + int index = indices[j]; + points[index] = points[index].Normalize(zs[j]); + } + } + + public abstract ECPoint Infinity { get; } + + public virtual IFiniteField Field + { + get { return m_field; } + } + + public virtual ECFieldElement A + { + get { return m_a; } + } + + public virtual ECFieldElement B + { + get { return m_b; } + } + + public virtual BigInteger Order + { + get { return m_order; } + } + + public virtual BigInteger Cofactor + { + get { return m_cofactor; } + } + + public virtual int CoordinateSystem + { + get { return m_coord; } + } + + /** + * Create a cache-safe lookup table for the specified sequence of points. All the points MUST + * belong to this ECCurve instance, and MUST already be normalized. + */ + public virtual ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + int FE_BYTES = (FieldSize + 7) / 8; + byte[] table = new byte[len * FE_BYTES * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + byte[] px = p.RawXCoord.ToBigInteger().ToByteArray(); + byte[] py = p.RawYCoord.ToBigInteger().ToByteArray(); + + int pxStart = px.Length > FE_BYTES ? 1 : 0, pxLen = px.Length - pxStart; + int pyStart = py.Length > FE_BYTES ? 1 : 0, pyLen = py.Length - pyStart; + + Array.Copy(px, pxStart, table, pos + FE_BYTES - pxLen, pxLen); pos += FE_BYTES; + Array.Copy(py, pyStart, table, pos + FE_BYTES - pyLen, pyLen); pos += FE_BYTES; + } + } + + return new DefaultLookupTable(this, table, len); + } + + protected virtual void CheckPoint(ECPoint point) + { + if (null == point || (this != point.Curve)) + throw new ArgumentException("must be non-null and on this curve", "point"); + } + + protected virtual void CheckPoints(ECPoint[] points) + { + CheckPoints(points, 0, points.Length); + } + + protected virtual void CheckPoints(ECPoint[] points, int off, int len) + { + if (points == null) + throw new ArgumentNullException("points"); + if (off < 0 || len < 0 || (off > (points.Length - len))) + throw new ArgumentException("invalid range specified", "points"); + + for (int i = 0; i < len; ++i) + { + ECPoint point = points[off + i]; + if (null != point && this != point.Curve) + throw new ArgumentException("entries must be null or on this curve", "points"); + } + } + + public virtual bool Equals(ECCurve other) + { + if (this == other) + return true; + if (null == other) + return false; + return Field.Equals(other.Field) + && A.ToBigInteger().Equals(other.A.ToBigInteger()) + && B.ToBigInteger().Equals(other.B.ToBigInteger()); + } + + public override bool Equals(object obj) + { + return Equals(obj as ECCurve); + } + + public override int GetHashCode() + { + return Field.GetHashCode() + ^ Integers.RotateLeft(A.ToBigInteger().GetHashCode(), 8) + ^ Integers.RotateLeft(B.ToBigInteger().GetHashCode(), 16); + } + + protected abstract ECPoint DecompressPoint(int yTilde, BigInteger X1); + + public virtual ECEndomorphism GetEndomorphism() + { + return m_endomorphism; + } + + /** + * Sets the default ECMultiplier, unless already set. + */ + public virtual ECMultiplier GetMultiplier() + { + lock (this) + { + if (this.m_multiplier == null) + { + this.m_multiplier = CreateDefaultMultiplier(); + } + return this.m_multiplier; + } + } + + /** + * Decode a point on this curve from its ASN.1 encoding. The different + * encodings are taken account of, including point compression for + * Fp (X9.62 s 4.2.1 pg 17). + * @return The decoded point. + */ + public virtual ECPoint DecodePoint(byte[] encoded) + { + ECPoint p = null; + int expectedLength = (FieldSize + 7) / 8; + + byte type = encoded[0]; + switch (type) + { + case 0x00: // infinity + { + if (encoded.Length != 1) + throw new ArgumentException("Incorrect length for infinity encoding", "encoded"); + + p = Infinity; + break; + } + + case 0x02: // compressed + case 0x03: // compressed + { + if (encoded.Length != (expectedLength + 1)) + throw new ArgumentException("Incorrect length for compressed encoding", "encoded"); + + int yTilde = type & 1; + BigInteger X = new BigInteger(1, encoded, 1, expectedLength); + + p = DecompressPoint(yTilde, X); + if (!p.ImplIsValid(true, true)) + throw new ArgumentException("Invalid point"); + + break; + } + + case 0x04: // uncompressed + { + if (encoded.Length != (2 * expectedLength + 1)) + throw new ArgumentException("Incorrect length for uncompressed encoding", "encoded"); + + BigInteger X = new BigInteger(1, encoded, 1, expectedLength); + BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength); + + p = ValidatePoint(X, Y); + break; + } + + case 0x06: // hybrid + case 0x07: // hybrid + { + if (encoded.Length != (2 * expectedLength + 1)) + throw new ArgumentException("Incorrect length for hybrid encoding", "encoded"); + + BigInteger X = new BigInteger(1, encoded, 1, expectedLength); + BigInteger Y = new BigInteger(1, encoded, 1 + expectedLength, expectedLength); + + if (Y.TestBit(0) != (type == 0x07)) + throw new ArgumentException("Inconsistent Y coordinate in hybrid encoding", "encoded"); + + p = ValidatePoint(X, Y); + break; + } + + default: + throw new FormatException("Invalid point encoding " + type); + } + + if (type != 0x00 && p.IsInfinity) + throw new ArgumentException("Invalid infinity encoding", "encoded"); + + return p; + } + + private class DefaultLookupTable + : ECLookupTable + { + private readonly ECCurve m_outer; + private readonly byte[] m_table; + private readonly int m_size; + + internal DefaultLookupTable(ECCurve outer, byte[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + int FE_BYTES = (m_outer.FieldSize + 7) / 8; + byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES]; + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + byte MASK = (byte)(((i ^ index) - 1) >> 31); + + for (int j = 0; j < FE_BYTES; ++j) + { + x[j] ^= (byte)(m_table[pos + j] & MASK); + y[j] ^= (byte)(m_table[pos + FE_BYTES + j] & MASK); + } + + pos += (FE_BYTES * 2); + } + + ECFieldElement X = m_outer.FromBigInteger(new BigInteger(1, x)); + ECFieldElement Y = m_outer.FromBigInteger(new BigInteger(1, y)); + return m_outer.CreateRawPoint(X, Y, false); + } + } + } + + internal abstract class AbstractFpCurve + : ECCurve + { + protected AbstractFpCurve(BigInteger q) + : base(FiniteFields.GetPrimeField(q)) + { + } + + public override bool IsValidFieldElement(BigInteger x) + { + return x != null && x.SignValue >= 0 && x.CompareTo(Field.Characteristic) < 0; + } + + protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement x = FromBigInteger(X1); + ECFieldElement rhs = x.Square().Add(A).Multiply(x).Add(B); + ECFieldElement y = rhs.Sqrt(); + + /* + * If y is not a square, then we haven't got a point on the curve + */ + if (y == null) + throw new ArgumentException("Invalid point compression"); + + if (y.TestBitZero() != (yTilde == 1)) + { + // Use the other root + y = y.Negate(); + } + + return CreateRawPoint(x, y, true); + } + } + + /** + * Elliptic curve over Fp + */ + internal class FpCurve + : AbstractFpCurve + { + private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED; + + protected readonly BigInteger m_q, m_r; + protected readonly FpPoint m_infinity; + + public FpCurve(BigInteger q, BigInteger a, BigInteger b) + : this(q, a, b, null, null) + { + } + + public FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor) + : base(q) + { + this.m_q = q; + this.m_r = FpFieldElement.CalculateResidue(q); + this.m_infinity = new FpPoint(this, null, null, false); + + this.m_a = FromBigInteger(a); + this.m_b = FromBigInteger(b); + this.m_order = order; + this.m_cofactor = cofactor; + this.m_coord = FP_DEFAULT_COORDS; + } + + protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b) + : this(q, r, a, b, null, null) + { + } + + protected FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) + : base(q) + { + this.m_q = q; + this.m_r = r; + this.m_infinity = new FpPoint(this, null, null, false); + + this.m_a = a; + this.m_b = b; + this.m_order = order; + this.m_cofactor = cofactor; + this.m_coord = FP_DEFAULT_COORDS; + } + + protected override ECCurve CloneCurve() + { + return new FpCurve(m_q, m_r, m_a, m_b, m_order, m_cofactor); + } + + public override bool SupportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_AFFINE: + case COORD_HOMOGENEOUS: + case COORD_JACOBIAN: + case COORD_JACOBIAN_MODIFIED: + return true; + default: + return false; + } + } + + public virtual BigInteger Q + { + get { return m_q; } + } + + public override ECPoint Infinity + { + get { return m_infinity; } + } + + public override int FieldSize + { + get { return m_q.BitLength; } + } + + public override ECFieldElement FromBigInteger(BigInteger x) + { + return new FpFieldElement(this.m_q, this.m_r, x); + } + + protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression) + { + return new FpPoint(this, x, y, withCompression); + } + + protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + { + return new FpPoint(this, x, y, zs, withCompression); + } + + public override ECPoint ImportPoint(ECPoint p) + { + if (this != p.Curve && this.CoordinateSystem == COORD_JACOBIAN && !p.IsInfinity) + { + switch (p.Curve.CoordinateSystem) + { + case COORD_JACOBIAN: + case COORD_JACOBIAN_CHUDNOVSKY: + case COORD_JACOBIAN_MODIFIED: + return new FpPoint(this, + FromBigInteger(p.RawXCoord.ToBigInteger()), + FromBigInteger(p.RawYCoord.ToBigInteger()), + new ECFieldElement[] { FromBigInteger(p.GetZCoord(0).ToBigInteger()) }, + p.IsCompressed); + default: + break; + } + } + + return base.ImportPoint(p); + } + } + + internal abstract class AbstractF2mCurve + : ECCurve + { + public static BigInteger Inverse(int m, int[] ks, BigInteger x) + { + return new LongArray(x).ModInverse(m, ks).ToBigInteger(); + } + + /** + * The auxiliary values s0 and + * s1 used for partial modular reduction for + * Koblitz curves. + */ + private BigInteger[] si = null; + + private static IFiniteField BuildField(int m, int k1, int k2, int k3) + { + if (k1 == 0) + { + throw new ArgumentException("k1 must be > 0"); + } + + if (k2 == 0) + { + if (k3 != 0) + { + throw new ArgumentException("k3 must be 0 if k2 == 0"); + } + + return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, m }); + } + + if (k2 <= k1) + { + throw new ArgumentException("k2 must be > k1"); + } + + if (k3 <= k2) + { + throw new ArgumentException("k3 must be > k2"); + } + + return FiniteFields.GetBinaryExtensionField(new int[]{ 0, k1, k2, k3, m }); + } + + protected AbstractF2mCurve(int m, int k1, int k2, int k3) + : base(BuildField(m, k1, k2, k3)) + { + } + + public override bool IsValidFieldElement(BigInteger x) + { + return x != null && x.SignValue >= 0 && x.BitLength <= FieldSize; + } + + public override ECPoint CreatePoint(BigInteger x, BigInteger y, bool withCompression) + { + ECFieldElement X = FromBigInteger(x), Y = FromBigInteger(y); + + switch (this.CoordinateSystem) + { + case COORD_LAMBDA_AFFINE: + case COORD_LAMBDA_PROJECTIVE: + { + if (X.IsZero) + { + if (!Y.Square().Equals(B)) + throw new ArgumentException(); + } + else + { + // Y becomes Lambda (X + Y/X) here + Y = Y.Divide(X).Add(X); + } + break; + } + default: + { + break; + } + } + + return CreateRawPoint(X, Y, withCompression); + } + + protected override ECPoint DecompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement xp = FromBigInteger(X1), yp = null; + if (xp.IsZero) + { + yp = B.Sqrt(); + } + else + { + ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp); + ECFieldElement z = SolveQuadraticEquation(beta); + + if (z != null) + { + if (z.TestBitZero() != (yTilde == 1)) + { + z = z.AddOne(); + } + + switch (this.CoordinateSystem) + { + case COORD_LAMBDA_AFFINE: + case COORD_LAMBDA_PROJECTIVE: + { + yp = z.Add(xp); + break; + } + default: + { + yp = z.Multiply(xp); + break; + } + } + } + } + + if (yp == null) + throw new ArgumentException("Invalid point compression"); + + return CreateRawPoint(xp, yp, true); + } + + /** + * Solves a quadratic equation z2 + z = beta(X9.62 + * D.1.6) The other solution is z + 1. + * + * @param beta + * The value to solve the quadratic equation for. + * @return the solution for z2 + z = beta or + * null if no solution exists. + */ + internal ECFieldElement SolveQuadraticEquation(ECFieldElement beta) + { + if (beta.IsZero) + return beta; + + ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero); + + int m = FieldSize; + do + { + ECFieldElement t = FromBigInteger(BigInteger.Arbitrary(m)); + z = zeroElement; + ECFieldElement w = beta; + for (int i = 1; i < m; i++) + { + ECFieldElement w2 = w.Square(); + z = z.Square().Add(w2.Multiply(t)); + w = w2.Add(beta); + } + if (!w.IsZero) + { + return null; + } + gamma = z.Square().Add(z); + } + while (gamma.IsZero); + + return z; + } + + /** + * @return the auxiliary values s0 and + * s1 used for partial modular reduction for + * Koblitz curves. + */ + internal virtual BigInteger[] GetSi() + { + if (si == null) + { + lock (this) + { + if (si == null) + { + si = Tnaf.GetSi(this); + } + } + } + return si; + } + + /** + * Returns true if this is a Koblitz curve (ABC curve). + * @return true if this is a Koblitz curve (ABC curve), false otherwise + */ + public virtual bool IsKoblitz + { + get + { + return m_order != null && m_cofactor != null && m_b.IsOne && (m_a.IsZero || m_a.IsOne); + } + } + } + + /** + * Elliptic curves over F2m. The Weierstrass equation is given by + * y2 + xy = x3 + ax2 + b. + */ + internal class F2mCurve + : AbstractF2mCurve + { + private const int F2M_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + + /** + * The exponent m of F2m. + */ + private readonly int m; + + /** + * TPB: The integer k where xm + + * xk + 1 represents the reduction polynomial + * f(z).
    + * PPB: The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
    + */ + private readonly int k1; + + /** + * TPB: Always set to 0
    + * PPB: The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
    + */ + private readonly int k2; + + /** + * TPB: Always set to 0
    + * PPB: The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
    + */ + private readonly int k3; + + /** + * The point at infinity on this curve. + */ + protected readonly F2mPoint m_infinity; + + /** + * Constructor for Trinomial Polynomial Basis (TPB). + * @param m The exponent m of + * F2m. + * @param k The integer k where xm + + * xk + 1 represents the reduction + * polynomial f(z). + * @param a The coefficient a in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param b The coefficient b in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + */ + [Obsolete("Use constructor taking order/cofactor")] + public F2mCurve( + int m, + int k, + BigInteger a, + BigInteger b) + : this(m, k, 0, 0, a, b, null, null) + { + } + + /** + * Constructor for Trinomial Polynomial Basis (TPB). + * @param m The exponent m of + * F2m. + * @param k The integer k where xm + + * xk + 1 represents the reduction + * polynomial f(z). + * @param a The coefficient a in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param b The coefficient b in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param order The order of the main subgroup of the elliptic curve. + * @param cofactor The cofactor of the elliptic curve, i.e. + * #Ea(F2m) = h * n. + */ + public F2mCurve( + int m, + int k, + BigInteger a, + BigInteger b, + BigInteger order, + BigInteger cofactor) + : this(m, k, 0, 0, a, b, order, cofactor) + { + } + + /** + * Constructor for Pentanomial Polynomial Basis (PPB). + * @param m The exponent m of + * F2m. + * @param k1 The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k2 The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k3 The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param a The coefficient a in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param b The coefficient b in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + */ + [Obsolete("Use constructor taking order/cofactor")] + public F2mCurve( + int m, + int k1, + int k2, + int k3, + BigInteger a, + BigInteger b) + : this(m, k1, k2, k3, a, b, null, null) + { + } + + /** + * Constructor for Pentanomial Polynomial Basis (PPB). + * @param m The exponent m of + * F2m. + * @param k1 The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k2 The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k3 The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param a The coefficient a in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param b The coefficient b in the Weierstrass equation + * for non-supersingular elliptic curves over + * F2m. + * @param order The order of the main subgroup of the elliptic curve. + * @param cofactor The cofactor of the elliptic curve, i.e. + * #Ea(F2m) = h * n. + */ + public F2mCurve( + int m, + int k1, + int k2, + int k3, + BigInteger a, + BigInteger b, + BigInteger order, + BigInteger cofactor) + : base(m, k1, k2, k3) + { + this.m = m; + this.k1 = k1; + this.k2 = k2; + this.k3 = k3; + this.m_order = order; + this.m_cofactor = cofactor; + this.m_infinity = new F2mPoint(this, null, null, false); + + if (k1 == 0) + throw new ArgumentException("k1 must be > 0"); + + if (k2 == 0) + { + if (k3 != 0) + throw new ArgumentException("k3 must be 0 if k2 == 0"); + } + else + { + if (k2 <= k1) + throw new ArgumentException("k2 must be > k1"); + + if (k3 <= k2) + throw new ArgumentException("k3 must be > k2"); + } + + this.m_a = FromBigInteger(a); + this.m_b = FromBigInteger(b); + this.m_coord = F2M_DEFAULT_COORDS; + } + + protected F2mCurve(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) + : base(m, k1, k2, k3) + { + this.m = m; + this.k1 = k1; + this.k2 = k2; + this.k3 = k3; + this.m_order = order; + this.m_cofactor = cofactor; + + this.m_infinity = new F2mPoint(this, null, null, false); + this.m_a = a; + this.m_b = b; + this.m_coord = F2M_DEFAULT_COORDS; + } + + protected override ECCurve CloneCurve() + { + return new F2mCurve(m, k1, k2, k3, m_a, m_b, m_order, m_cofactor); + } + + public override bool SupportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_AFFINE: + case COORD_HOMOGENEOUS: + case COORD_LAMBDA_PROJECTIVE: + return true; + default: + return false; + } + } + + protected override ECMultiplier CreateDefaultMultiplier() + { + if (IsKoblitz) + { + return new WTauNafMultiplier(); + } + + return base.CreateDefaultMultiplier(); + } + + public override int FieldSize + { + get { return m; } + } + + public override ECFieldElement FromBigInteger(BigInteger x) + { + return new F2mFieldElement(this.m, this.k1, this.k2, this.k3, x); + } + + protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, bool withCompression) + { + return new F2mPoint(this, x, y, withCompression); + } + + protected internal override ECPoint CreateRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + { + return new F2mPoint(this, x, y, zs, withCompression); + } + + public override ECPoint Infinity + { + get { return m_infinity; } + } + + public int M + { + get { return m; } + } + + /** + * Return true if curve uses a Trinomial basis. + * + * @return true if curve Trinomial, false otherwise. + */ + public bool IsTrinomial() + { + return k2 == 0 && k3 == 0; + } + + public int K1 + { + get { return k1; } + } + + public int K2 + { + get { return k2; } + } + + public int K3 + { + get { return k3; } + } + + public override ECLookupTable CreateCacheSafeLookupTable(ECPoint[] points, int off, int len) + { + int FE_LONGS = (m + 63) / 64; + + long[] table = new long[len * FE_LONGS * 2]; + { + int pos = 0; + for (int i = 0; i < len; ++i) + { + ECPoint p = points[off + i]; + ((F2mFieldElement)p.RawXCoord).x.CopyTo(table, pos); pos += FE_LONGS; + ((F2mFieldElement)p.RawYCoord).x.CopyTo(table, pos); pos += FE_LONGS; + } + } + + return new DefaultF2mLookupTable(this, table, len); + } + + private class DefaultF2mLookupTable + : ECLookupTable + { + private readonly F2mCurve m_outer; + private readonly long[] m_table; + private readonly int m_size; + + internal DefaultF2mLookupTable(F2mCurve outer, long[] table, int size) + { + this.m_outer = outer; + this.m_table = table; + this.m_size = size; + } + + public virtual int Size + { + get { return m_size; } + } + + public virtual ECPoint Lookup(int index) + { + int m = m_outer.m; + int[] ks = m_outer.IsTrinomial() ? new int[]{ m_outer.k1 } : new int[]{ m_outer.k1, m_outer.k2, m_outer.k3 }; + + int FE_LONGS = (m_outer.m + 63) / 64; + long[] x = new long[FE_LONGS], y = new long[FE_LONGS]; + int pos = 0; + + for (int i = 0; i < m_size; ++i) + { + long MASK =((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] ^= m_table[pos + j] & MASK; + y[j] ^= m_table[pos + FE_LONGS + j] & MASK; + } + + pos += (FE_LONGS * 2); + } + + ECFieldElement X = new F2mFieldElement(m, ks, new LongArray(x)); + ECFieldElement Y = new F2mFieldElement(m, ks, new LongArray(y)); + return m_outer.CreateRawPoint(X, Y, false); + } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECFieldElement.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECFieldElement.cs new file mode 100644 index 00000000..3ebb3332 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECFieldElement.cs @@ -0,0 +1,972 @@ +using System; +using System.Diagnostics; + +using Renci.SshNet.Security.Org.BouncyCastle.Math.Raw; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC +{ + internal abstract class ECFieldElement + { + public abstract BigInteger ToBigInteger(); + public abstract string FieldName { get; } + public abstract int FieldSize { get; } + public abstract ECFieldElement Add(ECFieldElement b); + public abstract ECFieldElement AddOne(); + public abstract ECFieldElement Subtract(ECFieldElement b); + public abstract ECFieldElement Multiply(ECFieldElement b); + public abstract ECFieldElement Divide(ECFieldElement b); + public abstract ECFieldElement Negate(); + public abstract ECFieldElement Square(); + public abstract ECFieldElement Invert(); + public abstract ECFieldElement Sqrt(); + + public virtual int BitLength + { + get { return ToBigInteger().BitLength; } + } + + public virtual bool IsOne + { + get { return BitLength == 1; } + } + + public virtual bool IsZero + { + get { return 0 == ToBigInteger().SignValue; } + } + + public virtual ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return Multiply(b).Subtract(x.Multiply(y)); + } + + public virtual ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return Multiply(b).Add(x.Multiply(y)); + } + + public virtual ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y) + { + return Square().Subtract(x.Multiply(y)); + } + + public virtual ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y) + { + return Square().Add(x.Multiply(y)); + } + + public virtual ECFieldElement SquarePow(int pow) + { + ECFieldElement r = this; + for (int i = 0; i < pow; ++i) + { + r = r.Square(); + } + return r; + } + + public virtual bool TestBitZero() + { + return ToBigInteger().TestBit(0); + } + + public override bool Equals(object obj) + { + return Equals(obj as ECFieldElement); + } + + public virtual bool Equals(ECFieldElement other) + { + if (this == other) + return true; + if (null == other) + return false; + return ToBigInteger().Equals(other.ToBigInteger()); + } + + public override int GetHashCode() + { + return ToBigInteger().GetHashCode(); + } + + public override string ToString() + { + return this.ToBigInteger().ToString(16); + } + + public virtual byte[] GetEncoded() + { + return BigIntegers.AsUnsignedByteArray((FieldSize + 7) / 8, ToBigInteger()); + } + } + + internal abstract class AbstractFpFieldElement + : ECFieldElement + { + } + + internal class FpFieldElement + : AbstractFpFieldElement + { + private readonly BigInteger q, r, x; + + internal static BigInteger CalculateResidue(BigInteger p) + { + int bitLength = p.BitLength; + if (bitLength >= 96) + { + BigInteger firstWord = p.ShiftRight(bitLength - 64); + if (firstWord.LongValue == -1L) + { + return BigInteger.One.ShiftLeft(bitLength).Subtract(p); + } + if ((bitLength & 7) == 0) + { + return BigInteger.One.ShiftLeft(bitLength << 1).Divide(p).Negate(); + } + } + return null; + } + + [Obsolete("Use ECCurve.FromBigInteger to construct field elements")] + public FpFieldElement(BigInteger q, BigInteger x) + : this(q, CalculateResidue(q), x) + { + } + + internal FpFieldElement(BigInteger q, BigInteger r, BigInteger x) + { + if (x == null || x.SignValue < 0 || x.CompareTo(q) >= 0) + throw new ArgumentException("value invalid in Fp field element", "x"); + + this.q = q; + this.r = r; + this.x = x; + } + + public override BigInteger ToBigInteger() + { + return x; + } + + /** + * return the field name for this field. + * + * @return the string "Fp". + */ + public override string FieldName + { + get { return "Fp"; } + } + + public override int FieldSize + { + get { return q.BitLength; } + } + + public BigInteger Q + { + get { return q; } + } + + public override ECFieldElement Add( + ECFieldElement b) + { + return new FpFieldElement(q, r, ModAdd(x, b.ToBigInteger())); + } + + public override ECFieldElement AddOne() + { + BigInteger x2 = x.Add(BigInteger.One); + if (x2.CompareTo(q) == 0) + { + x2 = BigInteger.Zero; + } + return new FpFieldElement(q, r, x2); + } + + public override ECFieldElement Subtract( + ECFieldElement b) + { + return new FpFieldElement(q, r, ModSubtract(x, b.ToBigInteger())); + } + + public override ECFieldElement Multiply( + ECFieldElement b) + { + return new FpFieldElement(q, r, ModMult(x, b.ToBigInteger())); + } + + public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, bx = b.ToBigInteger(), xx = x.ToBigInteger(), yx = y.ToBigInteger(); + BigInteger ab = ax.Multiply(bx); + BigInteger xy = xx.Multiply(yx); + return new FpFieldElement(q, r, ModReduce(ab.Subtract(xy))); + } + + public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, bx = b.ToBigInteger(), xx = x.ToBigInteger(), yx = y.ToBigInteger(); + BigInteger ab = ax.Multiply(bx); + BigInteger xy = xx.Multiply(yx); + BigInteger sum = ab.Add(xy); + if (r != null && r.SignValue < 0 && sum.BitLength > (q.BitLength << 1)) + { + sum = sum.Subtract(q.ShiftLeft(q.BitLength)); + } + return new FpFieldElement(q, r, ModReduce(sum)); + } + + public override ECFieldElement Divide( + ECFieldElement b) + { + return new FpFieldElement(q, r, ModMult(x, ModInverse(b.ToBigInteger()))); + } + + public override ECFieldElement Negate() + { + return x.SignValue == 0 ? this : new FpFieldElement(q, r, q.Subtract(x)); + } + + public override ECFieldElement Square() + { + return new FpFieldElement(q, r, ModMult(x, x)); + } + + public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, xx = x.ToBigInteger(), yx = y.ToBigInteger(); + BigInteger aa = ax.Multiply(ax); + BigInteger xy = xx.Multiply(yx); + return new FpFieldElement(q, r, ModReduce(aa.Subtract(xy))); + } + + public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, xx = x.ToBigInteger(), yx = y.ToBigInteger(); + BigInteger aa = ax.Multiply(ax); + BigInteger xy = xx.Multiply(yx); + BigInteger sum = aa.Add(xy); + if (r != null && r.SignValue < 0 && sum.BitLength > (q.BitLength << 1)) + { + sum = sum.Subtract(q.ShiftLeft(q.BitLength)); + } + return new FpFieldElement(q, r, ModReduce(sum)); + } + + public override ECFieldElement Invert() + { + // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime. + return new FpFieldElement(q, r, ModInverse(x)); + } + + /** + * return a sqrt root - the routine verifies that the calculation + * returns the right value - if none exists it returns null. + */ + public override ECFieldElement Sqrt() + { + if (IsZero || IsOne) + return this; + + if (!q.TestBit(0)) + throw new NotImplementedException("even value of q"); + + if (q.TestBit(1)) // q == 4m + 3 + { + BigInteger e = q.ShiftRight(2).Add(BigInteger.One); + return CheckSqrt(new FpFieldElement(q, r, x.ModPow(e, q))); + } + + if (q.TestBit(2)) // q == 8m + 5 + { + BigInteger t1 = x.ModPow(q.ShiftRight(3), q); + BigInteger t2 = ModMult(t1, x); + BigInteger t3 = ModMult(t2, t1); + + if (t3.Equals(BigInteger.One)) + { + return CheckSqrt(new FpFieldElement(q, r, t2)); + } + + // TODO This is constant and could be precomputed + BigInteger t4 = BigInteger.Two.ModPow(q.ShiftRight(2), q); + + BigInteger y = ModMult(t2, t4); + + return CheckSqrt(new FpFieldElement(q, r, y)); + } + + // q == 8m + 1 + + BigInteger legendreExponent = q.ShiftRight(1); + if (!(x.ModPow(legendreExponent, q).Equals(BigInteger.One))) + return null; + + BigInteger X = this.x; + BigInteger fourX = ModDouble(ModDouble(X)); ; + + BigInteger k = legendreExponent.Add(BigInteger.One), qMinusOne = q.Subtract(BigInteger.One); + + BigInteger U, V; + do + { + BigInteger P; + do + { + P = BigInteger.Arbitrary(q.BitLength); + } + while (P.CompareTo(q) >= 0 + || !ModReduce(P.Multiply(P).Subtract(fourX)).ModPow(legendreExponent, q).Equals(qMinusOne)); + + BigInteger[] result = LucasSequence(P, X, k); + U = result[0]; + V = result[1]; + + if (ModMult(V, V).Equals(fourX)) + { + return new FpFieldElement(q, r, ModHalfAbs(V)); + } + } + while (U.Equals(BigInteger.One) || U.Equals(qMinusOne)); + + return null; + } + + private ECFieldElement CheckSqrt(ECFieldElement z) + { + return z.Square().Equals(this) ? z : null; + } + + private BigInteger[] LucasSequence( + BigInteger P, + BigInteger Q, + BigInteger k) + { + // TODO Research and apply "common-multiplicand multiplication here" + + int n = k.BitLength; + int s = k.GetLowestSetBit(); + + Debug.Assert(k.TestBit(s)); + + BigInteger Uh = BigInteger.One; + BigInteger Vl = BigInteger.Two; + BigInteger Vh = P; + BigInteger Ql = BigInteger.One; + BigInteger Qh = BigInteger.One; + + for (int j = n - 1; j >= s + 1; --j) + { + Ql = ModMult(Ql, Qh); + + if (k.TestBit(j)) + { + Qh = ModMult(Ql, Q); + Uh = ModMult(Uh, Vh); + Vl = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql))); + Vh = ModReduce(Vh.Multiply(Vh).Subtract(Qh.ShiftLeft(1))); + } + else + { + Qh = Ql; + Uh = ModReduce(Uh.Multiply(Vl).Subtract(Ql)); + Vh = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql))); + Vl = ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1))); + } + } + + Ql = ModMult(Ql, Qh); + Qh = ModMult(Ql, Q); + Uh = ModReduce(Uh.Multiply(Vl).Subtract(Ql)); + Vl = ModReduce(Vh.Multiply(Vl).Subtract(P.Multiply(Ql))); + Ql = ModMult(Ql, Qh); + + for (int j = 1; j <= s; ++j) + { + Uh = ModMult(Uh, Vl); + Vl = ModReduce(Vl.Multiply(Vl).Subtract(Ql.ShiftLeft(1))); + Ql = ModMult(Ql, Ql); + } + + return new BigInteger[] { Uh, Vl }; + } + + protected virtual BigInteger ModAdd(BigInteger x1, BigInteger x2) + { + BigInteger x3 = x1.Add(x2); + if (x3.CompareTo(q) >= 0) + { + x3 = x3.Subtract(q); + } + return x3; + } + + protected virtual BigInteger ModDouble(BigInteger x) + { + BigInteger _2x = x.ShiftLeft(1); + if (_2x.CompareTo(q) >= 0) + { + _2x = _2x.Subtract(q); + } + return _2x; + } + + protected virtual BigInteger ModHalf(BigInteger x) + { + if (x.TestBit(0)) + { + x = q.Add(x); + } + return x.ShiftRight(1); + } + + protected virtual BigInteger ModHalfAbs(BigInteger x) + { + if (x.TestBit(0)) + { + x = q.Subtract(x); + } + return x.ShiftRight(1); + } + + protected virtual BigInteger ModInverse(BigInteger x) + { + int bits = FieldSize; + int len = (bits + 31) >> 5; + uint[] p = Nat.FromBigInteger(bits, q); + uint[] n = Nat.FromBigInteger(bits, x); + uint[] z = Nat.Create(len); + Mod.Invert(p, n, z); + return Nat.ToBigInteger(len, z); + } + + protected virtual BigInteger ModMult(BigInteger x1, BigInteger x2) + { + return ModReduce(x1.Multiply(x2)); + } + + protected virtual BigInteger ModReduce(BigInteger x) + { + if (r == null) + { + x = x.Mod(q); + } + else + { + bool negative = x.SignValue < 0; + if (negative) + { + x = x.Abs(); + } + int qLen = q.BitLength; + if (r.SignValue > 0) + { + BigInteger qMod = BigInteger.One.ShiftLeft(qLen); + bool rIsOne = r.Equals(BigInteger.One); + while (x.BitLength > (qLen + 1)) + { + BigInteger u = x.ShiftRight(qLen); + BigInteger v = x.Remainder(qMod); + if (!rIsOne) + { + u = u.Multiply(r); + } + x = u.Add(v); + } + } + else + { + int d = ((qLen - 1) & 31) + 1; + BigInteger mu = r.Negate(); + BigInteger u = mu.Multiply(x.ShiftRight(qLen - d)); + BigInteger quot = u.ShiftRight(qLen + d); + BigInteger v = quot.Multiply(q); + BigInteger bk1 = BigInteger.One.ShiftLeft(qLen + d); + v = v.Remainder(bk1); + x = x.Remainder(bk1); + x = x.Subtract(v); + if (x.SignValue < 0) + { + x = x.Add(bk1); + } + } + while (x.CompareTo(q) >= 0) + { + x = x.Subtract(q); + } + if (negative && x.SignValue != 0) + { + x = q.Subtract(x); + } + } + return x; + } + + protected virtual BigInteger ModSubtract(BigInteger x1, BigInteger x2) + { + BigInteger x3 = x1.Subtract(x2); + if (x3.SignValue < 0) + { + x3 = x3.Add(q); + } + return x3; + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + FpFieldElement other = obj as FpFieldElement; + + if (other == null) + return false; + + return Equals(other); + } + + public virtual bool Equals( + FpFieldElement other) + { + return q.Equals(other.q) && base.Equals(other); + } + + public override int GetHashCode() + { + return q.GetHashCode() ^ base.GetHashCode(); + } + } + + internal abstract class AbstractF2mFieldElement + : ECFieldElement + { + public virtual ECFieldElement HalfTrace() + { + int m = FieldSize; + if ((m & 1) == 0) + throw new InvalidOperationException("Half-trace only defined for odd m"); + + ECFieldElement fe = this; + ECFieldElement ht = fe; + for (int i = 2; i < m; i += 2) + { + fe = fe.SquarePow(2); + ht = ht.Add(fe); + } + + return ht; + } + + public virtual int Trace() + { + int m = FieldSize; + ECFieldElement fe = this; + ECFieldElement tr = fe; + for (int i = 1; i < m; ++i) + { + fe = fe.Square(); + tr = tr.Add(fe); + } + if (tr.IsZero) + return 0; + if (tr.IsOne) + return 1; + + throw new InvalidOperationException("Internal error in trace calculation"); + } + } + + /** + * Class representing the Elements of the finite field + * F2m in polynomial basis (PB) + * representation. Both trinomial (Tpb) and pentanomial (Ppb) polynomial + * basis representations are supported. Gaussian normal basis (GNB) + * representation is not supported. + */ + internal class F2mFieldElement + : AbstractF2mFieldElement + { + /** + * Indicates gaussian normal basis representation (GNB). Number chosen + * according to X9.62. GNB is not implemented at present. + */ + public const int Gnb = 1; + + /** + * Indicates trinomial basis representation (Tpb). Number chosen + * according to X9.62. + */ + public const int Tpb = 2; + + /** + * Indicates pentanomial basis representation (Ppb). Number chosen + * according to X9.62. + */ + public const int Ppb = 3; + + /** + * Tpb or Ppb. + */ + private int representation; + + /** + * The exponent m of F2m. + */ + private int m; + + private int[] ks; + + /** + * The LongArray holding the bits. + */ + internal LongArray x; + + /** + * Constructor for Ppb. + * @param m The exponent m of + * F2m. + * @param k1 The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k2 The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param k3 The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z). + * @param x The BigInteger representing the value of the field element. + */ + public F2mFieldElement( + int m, + int k1, + int k2, + int k3, + BigInteger x) + { + if (x == null || x.SignValue < 0 || x.BitLength > m) + throw new ArgumentException("value invalid in F2m field element", "x"); + + if ((k2 == 0) && (k3 == 0)) + { + this.representation = Tpb; + this.ks = new int[] { k1 }; + } + else + { + if (k2 >= k3) + throw new ArgumentException("k2 must be smaller than k3"); + if (k2 <= 0) + throw new ArgumentException("k2 must be larger than 0"); + + this.representation = Ppb; + this.ks = new int[] { k1, k2, k3 }; + } + + this.m = m; + this.x = new LongArray(x); + } + + /** + * Constructor for Tpb. + * @param m The exponent m of + * F2m. + * @param k The integer k where xm + + * xk + 1 represents the reduction + * polynomial f(z). + * @param x The BigInteger representing the value of the field element. + */ + public F2mFieldElement( + int m, + int k, + BigInteger x) + : this(m, k, 0, 0, x) + { + // Set k1 to k, and set k2 and k3 to 0 + } + + internal F2mFieldElement(int m, int[] ks, LongArray x) + { + this.m = m; + this.representation = (ks.Length == 1) ? Tpb : Ppb; + this.ks = ks; + this.x = x; + } + + public override int BitLength + { + get { return x.Degree(); } + } + + public override bool IsOne + { + get { return x.IsOne(); } + } + + public override bool IsZero + { + get { return x.IsZero(); } + } + + public override bool TestBitZero() + { + return x.TestBitZero(); + } + + public override BigInteger ToBigInteger() + { + return x.ToBigInteger(); + } + + public override string FieldName + { + get { return "F2m"; } + } + + public override int FieldSize + { + get { return m; } + } + + /** + * Checks, if the ECFieldElements a and b + * are elements of the same field F2m + * (having the same representation). + * @param a field element. + * @param b field element to be compared. + * @throws ArgumentException if a and b + * are not elements of the same field + * F2m (having the same + * representation). + */ + public static void CheckFieldElements( + ECFieldElement a, + ECFieldElement b) + { + if (!(a is F2mFieldElement) || !(b is F2mFieldElement)) + { + throw new ArgumentException("Field elements are not " + + "both instances of F2mFieldElement"); + } + + F2mFieldElement aF2m = (F2mFieldElement)a; + F2mFieldElement bF2m = (F2mFieldElement)b; + + if (aF2m.representation != bF2m.representation) + { + // Should never occur + throw new ArgumentException("One of the F2m field elements has incorrect representation"); + } + + if ((aF2m.m != bF2m.m) || !Arrays.AreEqual(aF2m.ks, bF2m.ks)) + { + throw new ArgumentException("Field elements are not elements of the same field F2m"); + } + } + + public override ECFieldElement Add( + ECFieldElement b) + { + // No check performed here for performance reasons. Instead the + // elements involved are checked in ECPoint.F2m + // checkFieldElements(this, b); + LongArray iarrClone = this.x.Copy(); + F2mFieldElement bF2m = (F2mFieldElement)b; + iarrClone.AddShiftedByWords(bF2m.x, 0); + return new F2mFieldElement(m, ks, iarrClone); + } + + public override ECFieldElement AddOne() + { + return new F2mFieldElement(m, ks, x.AddOne()); + } + + public override ECFieldElement Subtract( + ECFieldElement b) + { + // Addition and subtraction are the same in F2m + return Add(b); + } + + public override ECFieldElement Multiply( + ECFieldElement b) + { + // Right-to-left comb multiplication in the LongArray + // Input: Binary polynomials a(z) and b(z) of degree at most m-1 + // Output: c(z) = a(z) * b(z) mod f(z) + + // No check performed here for performance reasons. Instead the + // elements involved are checked in ECPoint.F2m + // checkFieldElements(this, b); + return new F2mFieldElement(m, ks, x.ModMultiply(((F2mFieldElement)b).x, m, ks)); + } + + public override ECFieldElement MultiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return MultiplyPlusProduct(b, x, y); + } + + public override ECFieldElement MultiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + LongArray ax = this.x, bx = ((F2mFieldElement)b).x, xx = ((F2mFieldElement)x).x, yx = ((F2mFieldElement)y).x; + + LongArray ab = ax.Multiply(bx, m, ks); + LongArray xy = xx.Multiply(yx, m, ks); + + if (ab == ax || ab == bx) + { + ab = (LongArray)ab.Copy(); + } + + ab.AddShiftedByWords(xy, 0); + ab.Reduce(m, ks); + + return new F2mFieldElement(m, ks, ab); + } + + public override ECFieldElement Divide( + ECFieldElement b) + { + // There may be more efficient implementations + ECFieldElement bInv = b.Invert(); + return Multiply(bInv); + } + + public override ECFieldElement Negate() + { + // -x == x holds for all x in F2m + return this; + } + + public override ECFieldElement Square() + { + return new F2mFieldElement(m, ks, x.ModSquare(m, ks)); + } + + public override ECFieldElement SquareMinusProduct(ECFieldElement x, ECFieldElement y) + { + return SquarePlusProduct(x, y); + } + + public override ECFieldElement SquarePlusProduct(ECFieldElement x, ECFieldElement y) + { + LongArray ax = this.x, xx = ((F2mFieldElement)x).x, yx = ((F2mFieldElement)y).x; + + LongArray aa = ax.Square(m, ks); + LongArray xy = xx.Multiply(yx, m, ks); + + if (aa == ax) + { + aa = (LongArray)aa.Copy(); + } + + aa.AddShiftedByWords(xy, 0); + aa.Reduce(m, ks); + + return new F2mFieldElement(m, ks, aa); + } + + public override ECFieldElement SquarePow(int pow) + { + return pow < 1 ? this : new F2mFieldElement(m, ks, x.ModSquareN(pow, m, ks)); + } + + public override ECFieldElement Invert() + { + return new F2mFieldElement(this.m, this.ks, this.x.ModInverse(m, ks)); + } + + public override ECFieldElement Sqrt() + { + return (x.IsZero() || x.IsOne()) ? this : SquarePow(m - 1); + } + + /** + * @return the representation of the field + * F2m, either of + * {@link F2mFieldElement.Tpb} (trinomial + * basis representation) or + * {@link F2mFieldElement.Ppb} (pentanomial + * basis representation). + */ + public int Representation + { + get { return this.representation; } + } + + /** + * @return the degree m of the reduction polynomial + * f(z). + */ + public int M + { + get { return this.m; } + } + + /** + * @return Tpb: The integer k where xm + + * xk + 1 represents the reduction polynomial + * f(z).
    + * Ppb: The integer k1 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
    + */ + public int K1 + { + get { return this.ks[0]; } + } + + /** + * @return Tpb: Always returns 0
    + * Ppb: The integer k2 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
    + */ + public int K2 + { + get { return this.ks.Length >= 2 ? this.ks[1] : 0; } + } + + /** + * @return Tpb: Always set to 0
    + * Ppb: The integer k3 where xm + + * xk3 + xk2 + xk1 + 1 + * represents the reduction polynomial f(z).
    + */ + public int K3 + { + get { return this.ks.Length >= 3 ? this.ks[2] : 0; } + } + + public override bool Equals( + object obj) + { + if (obj == this) + return true; + + F2mFieldElement other = obj as F2mFieldElement; + + if (other == null) + return false; + + return Equals(other); + } + + public virtual bool Equals( + F2mFieldElement other) + { + return ((this.m == other.m) + && (this.representation == other.representation) + && Arrays.AreEqual(this.ks, other.ks) + && (this.x.Equals(other.x))); + } + + public override int GetHashCode() + { + return x.GetHashCode() ^ m ^ Arrays.GetHashCode(ks); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECLookupTable.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECLookupTable.cs new file mode 100644 index 00000000..0b9a3999 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECLookupTable.cs @@ -0,0 +1,10 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC +{ + internal interface ECLookupTable + { + int Size { get; } + ECPoint Lookup(int index); + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECPoint.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECPoint.cs new file mode 100644 index 00000000..3a93c3e7 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECPoint.cs @@ -0,0 +1,2122 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.Text; + +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC +{ + /** + * base class for points on elliptic curves. + */ + internal abstract class ECPoint + { + protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0]; + + protected static ECFieldElement[] GetInitialZCoords(ECCurve curve) + { + // Cope with null curve, most commonly used by implicitlyCa + int coord = null == curve ? ECCurve.COORD_AFFINE : curve.CoordinateSystem; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + return EMPTY_ZS; + default: + break; + } + + ECFieldElement one = curve.FromBigInteger(BigInteger.One); + + switch (coord) + { + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + return new ECFieldElement[] { one }; + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + return new ECFieldElement[] { one, one, one }; + case ECCurve.COORD_JACOBIAN_MODIFIED: + return new ECFieldElement[] { one, curve.A }; + default: + throw new ArgumentException("unknown coordinate system"); + } + } + + protected internal readonly ECCurve m_curve; + protected internal readonly ECFieldElement m_x, m_y; + protected internal readonly ECFieldElement[] m_zs; + protected internal readonly bool m_withCompression; + + // Dictionary is (string -> PreCompInfo) + protected internal IDictionary m_preCompTable = null; + + protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) + : this(curve, x, y, GetInitialZCoords(curve), withCompression) + { + } + + internal ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + { + this.m_curve = curve; + this.m_x = x; + this.m_y = y; + this.m_zs = zs; + this.m_withCompression = withCompression; + } + + protected abstract bool SatisfiesCurveEquation(); + + protected virtual bool SatisfiesOrder() + { + if (BigInteger.One.Equals(Curve.Cofactor)) + return true; + + BigInteger n = Curve.Order; + + // TODO Require order to be available for all curves + + return n == null || ECAlgorithms.ReferenceMultiply(this, n).IsInfinity; + } + + public ECPoint GetDetachedPoint() + { + return Normalize().Detach(); + } + + public virtual ECCurve Curve + { + get { return m_curve; } + } + + protected abstract ECPoint Detach(); + + protected virtual int CurveCoordinateSystem + { + get + { + // Cope with null curve, most commonly used by implicitlyCa + return null == m_curve ? ECCurve.COORD_AFFINE : m_curve.CoordinateSystem; + } + } + + /** + * Returns the affine x-coordinate after checking that this point is normalized. + * + * @return The affine x-coordinate of this point + * @throws IllegalStateException if the point is not normalized + */ + public virtual ECFieldElement AffineXCoord + { + get + { + CheckNormalized(); + return XCoord; + } + } + + /** + * Returns the affine y-coordinate after checking that this point is normalized + * + * @return The affine y-coordinate of this point + * @throws IllegalStateException if the point is not normalized + */ + public virtual ECFieldElement AffineYCoord + { + get + { + CheckNormalized(); + return YCoord; + } + } + + /** + * Returns the x-coordinate. + * + * Caution: depending on the curve's coordinate system, this may not be the same value as in an + * affine coordinate system; use Normalize() to get a point where the coordinates have their + * affine values, or use AffineXCoord if you expect the point to already have been normalized. + * + * @return the x-coordinate of this point + */ + public virtual ECFieldElement XCoord + { + get { return m_x; } + } + + /** + * Returns the y-coordinate. + * + * Caution: depending on the curve's coordinate system, this may not be the same value as in an + * affine coordinate system; use Normalize() to get a point where the coordinates have their + * affine values, or use AffineYCoord if you expect the point to already have been normalized. + * + * @return the y-coordinate of this point + */ + public virtual ECFieldElement YCoord + { + get { return m_y; } + } + + public virtual ECFieldElement GetZCoord(int index) + { + return (index < 0 || index >= m_zs.Length) ? null : m_zs[index]; + } + + public virtual ECFieldElement[] GetZCoords() + { + int zsLen = m_zs.Length; + if (zsLen == 0) + { + return m_zs; + } + ECFieldElement[] copy = new ECFieldElement[zsLen]; + Array.Copy(m_zs, 0, copy, 0, zsLen); + return copy; + } + + protected internal ECFieldElement RawXCoord + { + get { return m_x; } + } + + protected internal ECFieldElement RawYCoord + { + get { return m_y; } + } + + protected internal ECFieldElement[] RawZCoords + { + get { return m_zs; } + } + + protected virtual void CheckNormalized() + { + if (!IsNormalized()) + throw new InvalidOperationException("point not in normal form"); + } + + public virtual bool IsNormalized() + { + int coord = this.CurveCoordinateSystem; + + return coord == ECCurve.COORD_AFFINE + || coord == ECCurve.COORD_LAMBDA_AFFINE + || IsInfinity + || RawZCoords[0].IsOne; + } + + /** + * Normalization ensures that any projective coordinate is 1, and therefore that the x, y + * coordinates reflect those of the equivalent point in an affine coordinate system. + * + * @return a new ECPoint instance representing the same point, but with normalized coordinates + */ + public virtual ECPoint Normalize() + { + if (this.IsInfinity) + { + return this; + } + + switch (this.CurveCoordinateSystem) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + return this; + } + default: + { + ECFieldElement Z1 = RawZCoords[0]; + if (Z1.IsOne) + { + return this; + } + + return Normalize(Z1.Invert()); + } + } + } + + internal virtual ECPoint Normalize(ECFieldElement zInv) + { + switch (this.CurveCoordinateSystem) + { + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + return CreateScaledPoint(zInv, zInv); + } + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + ECFieldElement zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv); + return CreateScaledPoint(zInv2, zInv3); + } + default: + { + throw new InvalidOperationException("not a projective coordinate system"); + } + } + } + + protected virtual ECPoint CreateScaledPoint(ECFieldElement sx, ECFieldElement sy) + { + return Curve.CreateRawPoint(RawXCoord.Multiply(sx), RawYCoord.Multiply(sy), IsCompressed); + } + + public bool IsInfinity + { + get { return m_x == null && m_y == null; } + } + + public bool IsCompressed + { + get { return m_withCompression; } + } + + public bool IsValid() + { + return ImplIsValid(false, true); + } + + internal bool IsValidPartial() + { + return ImplIsValid(false, false); + } + + internal bool ImplIsValid(bool decompressed, bool checkOrder) + { + if (IsInfinity) + return true; + + ValidityCallback callback = new ValidityCallback(this, decompressed, checkOrder); + ValidityPreCompInfo validity = (ValidityPreCompInfo)Curve.Precompute(this, ValidityPreCompInfo.PRECOMP_NAME, callback); + return !validity.HasFailed(); + } + + public virtual ECPoint ScaleX(ECFieldElement scale) + { + return IsInfinity + ? this + : Curve.CreateRawPoint(RawXCoord.Multiply(scale), RawYCoord, RawZCoords, IsCompressed); + } + + public virtual ECPoint ScaleY(ECFieldElement scale) + { + return IsInfinity + ? this + : Curve.CreateRawPoint(RawXCoord, RawYCoord.Multiply(scale), RawZCoords, IsCompressed); + } + + public override bool Equals(object obj) + { + return Equals(obj as ECPoint); + } + + public virtual bool Equals(ECPoint other) + { + if (this == other) + return true; + if (null == other) + return false; + + ECCurve c1 = this.Curve, c2 = other.Curve; + bool n1 = (null == c1), n2 = (null == c2); + bool i1 = IsInfinity, i2 = other.IsInfinity; + + if (i1 || i2) + { + return (i1 && i2) && (n1 || n2 || c1.Equals(c2)); + } + + ECPoint p1 = this, p2 = other; + if (n1 && n2) + { + // Points with null curve are in affine form, so already normalized + } + else if (n1) + { + p2 = p2.Normalize(); + } + else if (n2) + { + p1 = p1.Normalize(); + } + else if (!c1.Equals(c2)) + { + return false; + } + else + { + // TODO Consider just requiring already normalized, to avoid silent performance degradation + + ECPoint[] points = new ECPoint[] { this, c1.ImportPoint(p2) }; + + // TODO This is a little strong, really only requires coZNormalizeAll to get Zs equal + c1.NormalizeAll(points); + + p1 = points[0]; + p2 = points[1]; + } + + return p1.XCoord.Equals(p2.XCoord) && p1.YCoord.Equals(p2.YCoord); + } + + public override int GetHashCode() + { + ECCurve c = this.Curve; + int hc = (null == c) ? 0 : ~c.GetHashCode(); + + if (!this.IsInfinity) + { + // TODO Consider just requiring already normalized, to avoid silent performance degradation + + ECPoint p = Normalize(); + + hc ^= p.XCoord.GetHashCode() * 17; + hc ^= p.YCoord.GetHashCode() * 257; + } + + return hc; + } + + public override string ToString() + { + if (this.IsInfinity) + { + return "INF"; + } + + StringBuilder sb = new StringBuilder(); + sb.Append('('); + sb.Append(RawXCoord); + sb.Append(','); + sb.Append(RawYCoord); + for (int i = 0; i < m_zs.Length; ++i) + { + sb.Append(','); + sb.Append(m_zs[i]); + } + sb.Append(')'); + return sb.ToString(); + } + + public virtual byte[] GetEncoded() + { + return GetEncoded(m_withCompression); + } + + public abstract byte[] GetEncoded(bool compressed); + + protected internal abstract bool CompressionYTilde { get; } + + public abstract ECPoint Add(ECPoint b); + public abstract ECPoint Subtract(ECPoint b); + public abstract ECPoint Negate(); + + public virtual ECPoint TimesPow2(int e) + { + if (e < 0) + throw new ArgumentException("cannot be negative", "e"); + + ECPoint p = this; + while (--e >= 0) + { + p = p.Twice(); + } + return p; + } + + public abstract ECPoint Twice(); + public abstract ECPoint Multiply(BigInteger b); + + public virtual ECPoint TwicePlus(ECPoint b) + { + return Twice().Add(b); + } + + public virtual ECPoint ThreeTimes() + { + return TwicePlus(this); + } + + private class ValidityCallback + : IPreCompCallback + { + private readonly ECPoint m_outer; + private readonly bool m_decompressed, m_checkOrder; + + internal ValidityCallback(ECPoint outer, bool decompressed, bool checkOrder) + { + this.m_outer = outer; + this.m_decompressed = decompressed; + this.m_checkOrder = checkOrder; + } + + public PreCompInfo Precompute(PreCompInfo existing) + { + ValidityPreCompInfo info = existing as ValidityPreCompInfo; + if (info == null) + { + info = new ValidityPreCompInfo(); + } + + if (info.HasFailed()) + return info; + + if (!info.HasCurveEquationPassed()) + { + if (!m_decompressed && !m_outer.SatisfiesCurveEquation()) + { + info.ReportFailed(); + return info; + } + info.ReportCurveEquationPassed(); + } + if (m_checkOrder && !info.HasOrderPassed()) + { + if (!m_outer.SatisfiesOrder()) + { + info.ReportFailed(); + return info; + } + info.ReportOrderPassed(); + } + return info; + } + } + } + + internal abstract class ECPointBase + : ECPoint + { + protected internal ECPointBase( + ECCurve curve, + ECFieldElement x, + ECFieldElement y, + bool withCompression) + : base(curve, x, y, withCompression) + { + } + + protected internal ECPointBase(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + : base(curve, x, y, zs, withCompression) + { + } + + /** + * return the field element encoded with point compression. (S 4.3.6) + */ + public override byte[] GetEncoded(bool compressed) + { + if (this.IsInfinity) + { + return new byte[1]; + } + + ECPoint normed = Normalize(); + + byte[] X = normed.XCoord.GetEncoded(); + + if (compressed) + { + byte[] PO = new byte[X.Length + 1]; + PO[0] = (byte)(normed.CompressionYTilde ? 0x03 : 0x02); + Array.Copy(X, 0, PO, 1, X.Length); + return PO; + } + + byte[] Y = normed.YCoord.GetEncoded(); + + { + byte[] PO = new byte[X.Length + Y.Length + 1]; + PO[0] = 0x04; + Array.Copy(X, 0, PO, 1, X.Length); + Array.Copy(Y, 0, PO, X.Length + 1, Y.Length); + return PO; + } + } + + /** + * Multiplies this ECPoint by the given number. + * @param k The multiplicator. + * @return k * this. + */ + public override ECPoint Multiply(BigInteger k) + { + return this.Curve.GetMultiplier().Multiply(this, k); + } + } + + internal abstract class AbstractFpPoint + : ECPointBase + { + protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) + : base(curve, x, y, withCompression) + { + } + + protected AbstractFpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + : base(curve, x, y, zs, withCompression) + { + } + + protected internal override bool CompressionYTilde + { + get { return this.AffineYCoord.TestBitZero(); } + } + + protected override bool SatisfiesCurveEquation() + { + ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = Curve.A, B = Curve.B; + ECFieldElement lhs = Y.Square(); + + switch (CurveCoordinateSystem) + { + case ECCurve.COORD_AFFINE: + break; + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Z = this.RawZCoords[0]; + if (!Z.IsOne) + { + ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2); + lhs = lhs.Multiply(Z); + A = A.Multiply(Z2); + B = B.Multiply(Z3); + } + break; + } + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + ECFieldElement Z = this.RawZCoords[0]; + if (!Z.IsOne) + { + ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square(), Z6 = Z2.Multiply(Z4); + A = A.Multiply(Z4); + B = B.Multiply(Z6); + } + break; + } + default: + throw new InvalidOperationException("unsupported coordinate system"); + } + + ECFieldElement rhs = X.Square().Add(A).Multiply(X).Add(B); + return lhs.Equals(rhs); + } + + public override ECPoint Subtract(ECPoint b) + { + if (b.IsInfinity) + return this; + + // Add -b + return Add(b.Negate()); + } + } + + /** + * Elliptic curve points over Fp + */ + internal class FpPoint + : AbstractFpPoint + { + /** + * Create a point which encodes without point compression. + * + * @param curve the curve to use + * @param x affine x co-ordinate + * @param y affine y co-ordinate + */ + public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y) + : this(curve, x, y, false) + { + } + + /** + * Create a point that encodes with or without point compression. + * + * @param curve the curve to use + * @param x affine x co-ordinate + * @param y affine y co-ordinate + * @param withCompression if true encode with point compression + */ + public FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) + : base(curve, x, y, withCompression) + { + if ((x == null) != (y == null)) + throw new ArgumentException("Exactly one of the field elements is null"); + } + + internal FpPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + : base(curve, x, y, zs, withCompression) + { + } + + protected override ECPoint Detach() + { + return new FpPoint(null, AffineXCoord, AffineYCoord, false); + } + + public override ECFieldElement GetZCoord(int index) + { + if (index == 1 && ECCurve.COORD_JACOBIAN_MODIFIED == this.CurveCoordinateSystem) + { + return GetJacobianModifiedW(); + } + + return base.GetZCoord(index); + } + + // B.3 pg 62 + public override ECPoint Add(ECPoint b) + { + if (this.IsInfinity) + return b; + if (b.IsInfinity) + return this; + if (this == b) + return Twice(); + + ECCurve curve = this.Curve; + int coord = curve.CoordinateSystem; + + ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord; + ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1); + + if (dx.IsZero) + { + if (dy.IsZero) + { + // this == b, i.e. this must be doubled + return Twice(); + } + + // this == -b, i.e. the result is the point at infinity + return Curve.Infinity; + } + + ECFieldElement gamma = dy.Divide(dx); + ECFieldElement X3 = gamma.Square().Subtract(X1).Subtract(X2); + ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1); + + return new FpPoint(Curve, X3, Y3, IsCompressed); + } + + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Z1 = this.RawZCoords[0]; + ECFieldElement Z2 = b.RawZCoords[0]; + + bool Z1IsOne = Z1.IsOne; + bool Z2IsOne = Z2.IsOne; + + ECFieldElement u1 = Z1IsOne ? Y2 : Y2.Multiply(Z1); + ECFieldElement u2 = Z2IsOne ? Y1 : Y1.Multiply(Z2); + ECFieldElement u = u1.Subtract(u2); + ECFieldElement v1 = Z1IsOne ? X2 : X2.Multiply(Z1); + ECFieldElement v2 = Z2IsOne ? X1 : X1.Multiply(Z2); + ECFieldElement v = v1.Subtract(v2); + + // Check if b == this or b == -this + if (v.IsZero) + { + if (u.IsZero) + { + // this == b, i.e. this must be doubled + return this.Twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.Infinity; + } + + // TODO Optimize for when w == 1 + ECFieldElement w = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2); + ECFieldElement vSquared = v.Square(); + ECFieldElement vCubed = vSquared.Multiply(v); + ECFieldElement vSquaredV2 = vSquared.Multiply(v2); + ECFieldElement A = u.Square().Multiply(w).Subtract(vCubed).Subtract(Two(vSquaredV2)); + + ECFieldElement X3 = v.Multiply(A); + ECFieldElement Y3 = vSquaredV2.Subtract(A).MultiplyMinusProduct(u, u2, vCubed); + ECFieldElement Z3 = vCubed.Multiply(w); + + return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed); + } + + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + ECFieldElement Z1 = this.RawZCoords[0]; + ECFieldElement Z2 = b.RawZCoords[0]; + + bool Z1IsOne = Z1.IsOne; + + ECFieldElement X3, Y3, Z3, Z3Squared = null; + + if (!Z1IsOne && Z1.Equals(Z2)) + { + // TODO Make this available as public method coZAdd? + + ECFieldElement dx = X1.Subtract(X2), dy = Y1.Subtract(Y2); + if (dx.IsZero) + { + if (dy.IsZero) + { + return Twice(); + } + return curve.Infinity; + } + + ECFieldElement C = dx.Square(); + ECFieldElement W1 = X1.Multiply(C), W2 = X2.Multiply(C); + ECFieldElement A1 = W1.Subtract(W2).Multiply(Y1); + + X3 = dy.Square().Subtract(W1).Subtract(W2); + Y3 = W1.Subtract(X3).Multiply(dy).Subtract(A1); + Z3 = dx; + + if (Z1IsOne) + { + Z3Squared = C; + } + else + { + Z3 = Z3.Multiply(Z1); + } + } + else + { + ECFieldElement Z1Squared, U2, S2; + if (Z1IsOne) + { + Z1Squared = Z1; U2 = X2; S2 = Y2; + } + else + { + Z1Squared = Z1.Square(); + U2 = Z1Squared.Multiply(X2); + ECFieldElement Z1Cubed = Z1Squared.Multiply(Z1); + S2 = Z1Cubed.Multiply(Y2); + } + + bool Z2IsOne = Z2.IsOne; + ECFieldElement Z2Squared, U1, S1; + if (Z2IsOne) + { + Z2Squared = Z2; U1 = X1; S1 = Y1; + } + else + { + Z2Squared = Z2.Square(); + U1 = Z2Squared.Multiply(X1); + ECFieldElement Z2Cubed = Z2Squared.Multiply(Z2); + S1 = Z2Cubed.Multiply(Y1); + } + + ECFieldElement H = U1.Subtract(U2); + ECFieldElement R = S1.Subtract(S2); + + // Check if b == this or b == -this + if (H.IsZero) + { + if (R.IsZero) + { + // this == b, i.e. this must be doubled + return this.Twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.Infinity; + } + + ECFieldElement HSquared = H.Square(); + ECFieldElement G = HSquared.Multiply(H); + ECFieldElement V = HSquared.Multiply(U1); + + X3 = R.Square().Add(G).Subtract(Two(V)); + Y3 = V.Subtract(X3).MultiplyMinusProduct(R, G, S1); + + Z3 = H; + if (!Z1IsOne) + { + Z3 = Z3.Multiply(Z1); + } + if (!Z2IsOne) + { + Z3 = Z3.Multiply(Z2); + } + + // Alternative calculation of Z3 using fast square + //X3 = four(X3); + //Y3 = eight(Y3); + //Z3 = doubleProductFromSquares(Z1, Z2, Z1Squared, Z2Squared).Multiply(H); + + if (Z3 == H) + { + Z3Squared = HSquared; + } + } + + ECFieldElement[] zs; + if (coord == ECCurve.COORD_JACOBIAN_MODIFIED) + { + // TODO If the result will only be used in a subsequent addition, we don't need W3 + ECFieldElement W3 = CalculateJacobianModifiedW(Z3, Z3Squared); + + zs = new ECFieldElement[] { Z3, W3 }; + } + else + { + zs = new ECFieldElement[] { Z3 }; + } + + return new FpPoint(curve, X3, Y3, zs, IsCompressed); + } + + default: + { + throw new InvalidOperationException("unsupported coordinate system"); + } + } + } + + // B.3 pg 62 + public override ECPoint Twice() + { + if (this.IsInfinity) + return this; + + ECCurve curve = this.Curve; + + ECFieldElement Y1 = this.RawYCoord; + if (Y1.IsZero) + return curve.Infinity; + + int coord = curve.CoordinateSystem; + + ECFieldElement X1 = this.RawXCoord; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement X1Squared = X1.Square(); + ECFieldElement gamma = Three(X1Squared).Add(this.Curve.A).Divide(Two(Y1)); + ECFieldElement X3 = gamma.Square().Subtract(Two(X1)); + ECFieldElement Y3 = gamma.Multiply(X1.Subtract(X3)).Subtract(Y1); + + return new FpPoint(Curve, X3, Y3, IsCompressed); + } + + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Z1 = this.RawZCoords[0]; + + bool Z1IsOne = Z1.IsOne; + + // TODO Optimize for small negative a4 and -3 + ECFieldElement w = curve.A; + if (!w.IsZero && !Z1IsOne) + { + w = w.Multiply(Z1.Square()); + } + w = w.Add(Three(X1.Square())); + + ECFieldElement s = Z1IsOne ? Y1 : Y1.Multiply(Z1); + ECFieldElement t = Z1IsOne ? Y1.Square() : s.Multiply(Y1); + ECFieldElement B = X1.Multiply(t); + ECFieldElement _4B = Four(B); + ECFieldElement h = w.Square().Subtract(Two(_4B)); + + ECFieldElement _2s = Two(s); + ECFieldElement X3 = h.Multiply(_2s); + ECFieldElement _2t = Two(t); + ECFieldElement Y3 = _4B.Subtract(h).Multiply(w).Subtract(Two(_2t.Square())); + ECFieldElement _4sSquared = Z1IsOne ? Two(_2t) : _2s.Square(); + ECFieldElement Z3 = Two(_4sSquared).Multiply(s); + + return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed); + } + + case ECCurve.COORD_JACOBIAN: + { + ECFieldElement Z1 = this.RawZCoords[0]; + + bool Z1IsOne = Z1.IsOne; + + ECFieldElement Y1Squared = Y1.Square(); + ECFieldElement T = Y1Squared.Square(); + + ECFieldElement a4 = curve.A; + ECFieldElement a4Neg = a4.Negate(); + + ECFieldElement M, S; + if (a4Neg.ToBigInteger().Equals(BigInteger.ValueOf(3))) + { + ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square(); + M = Three(X1.Add(Z1Squared).Multiply(X1.Subtract(Z1Squared))); + S = Four(Y1Squared.Multiply(X1)); + } + else + { + ECFieldElement X1Squared = X1.Square(); + M = Three(X1Squared); + if (Z1IsOne) + { + M = M.Add(a4); + } + else if (!a4.IsZero) + { + ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.Square(); + ECFieldElement Z1Pow4 = Z1Squared.Square(); + if (a4Neg.BitLength < a4.BitLength) + { + M = M.Subtract(Z1Pow4.Multiply(a4Neg)); + } + else + { + M = M.Add(Z1Pow4.Multiply(a4)); + } + } + //S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T)); + S = Four(X1.Multiply(Y1Squared)); + } + + ECFieldElement X3 = M.Square().Subtract(Two(S)); + ECFieldElement Y3 = S.Subtract(X3).Multiply(M).Subtract(Eight(T)); + + ECFieldElement Z3 = Two(Y1); + if (!Z1IsOne) + { + Z3 = Z3.Multiply(Z1); + } + + // Alternative calculation of Z3 using fast square + //ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared); + + return new FpPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed); + } + + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + return TwiceJacobianModified(true); + } + + default: + { + throw new InvalidOperationException("unsupported coordinate system"); + } + } + } + + public override ECPoint TwicePlus(ECPoint b) + { + if (this == b) + return ThreeTimes(); + if (this.IsInfinity) + return b; + if (b.IsInfinity) + return Twice(); + + ECFieldElement Y1 = this.RawYCoord; + if (Y1.IsZero) + return b; + + ECCurve curve = this.Curve; + int coord = curve.CoordinateSystem; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement X1 = this.RawXCoord; + ECFieldElement X2 = b.RawXCoord, Y2 = b.RawYCoord; + + ECFieldElement dx = X2.Subtract(X1), dy = Y2.Subtract(Y1); + + if (dx.IsZero) + { + if (dy.IsZero) + { + // this == b i.e. the result is 3P + return ThreeTimes(); + } + + // this == -b, i.e. the result is P + return this; + } + + /* + * Optimized calculation of 2P + Q, as described in "Trading Inversions for + * Multiplications in Elliptic Curve Cryptography", by Ciet, Joye, Lauter, Montgomery. + */ + + ECFieldElement X = dx.Square(), Y = dy.Square(); + ECFieldElement d = X.Multiply(Two(X1).Add(X2)).Subtract(Y); + if (d.IsZero) + { + return Curve.Infinity; + } + + ECFieldElement D = d.Multiply(dx); + ECFieldElement I = D.Invert(); + ECFieldElement L1 = d.Multiply(I).Multiply(dy); + ECFieldElement L2 = Two(Y1).Multiply(X).Multiply(dx).Multiply(I).Subtract(L1); + ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X2); + ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1); + + return new FpPoint(Curve, X4, Y4, IsCompressed); + } + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + return TwiceJacobianModified(false).Add(b); + } + default: + { + return Twice().Add(b); + } + } + } + + public override ECPoint ThreeTimes() + { + if (this.IsInfinity) + return this; + + ECFieldElement Y1 = this.RawYCoord; + if (Y1.IsZero) + return this; + + ECCurve curve = this.Curve; + int coord = curve.CoordinateSystem; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement X1 = this.RawXCoord; + + ECFieldElement _2Y1 = Two(Y1); + ECFieldElement X = _2Y1.Square(); + ECFieldElement Z = Three(X1.Square()).Add(Curve.A); + ECFieldElement Y = Z.Square(); + + ECFieldElement d = Three(X1).Multiply(X).Subtract(Y); + if (d.IsZero) + { + return Curve.Infinity; + } + + ECFieldElement D = d.Multiply(_2Y1); + ECFieldElement I = D.Invert(); + ECFieldElement L1 = d.Multiply(I).Multiply(Z); + ECFieldElement L2 = X.Square().Multiply(I).Subtract(L1); + + ECFieldElement X4 = (L2.Subtract(L1)).Multiply(L1.Add(L2)).Add(X1); + ECFieldElement Y4 = (X1.Subtract(X4)).Multiply(L2).Subtract(Y1); + return new FpPoint(Curve, X4, Y4, IsCompressed); + } + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + return TwiceJacobianModified(false).Add(this); + } + default: + { + // NOTE: Be careful about recursions between TwicePlus and ThreeTimes + return Twice().Add(this); + } + } + } + + public override ECPoint TimesPow2(int e) + { + if (e < 0) + throw new ArgumentException("cannot be negative", "e"); + if (e == 0 || this.IsInfinity) + return this; + if (e == 1) + return Twice(); + + ECCurve curve = this.Curve; + + ECFieldElement Y1 = this.RawYCoord; + if (Y1.IsZero) + return curve.Infinity; + + int coord = curve.CoordinateSystem; + + ECFieldElement W1 = curve.A; + ECFieldElement X1 = this.RawXCoord; + ECFieldElement Z1 = this.RawZCoords.Length < 1 ? curve.FromBigInteger(BigInteger.One) : this.RawZCoords[0]; + + if (!Z1.IsOne) + { + switch (coord) + { + case ECCurve.COORD_HOMOGENEOUS: + ECFieldElement Z1Sq = Z1.Square(); + X1 = X1.Multiply(Z1); + Y1 = Y1.Multiply(Z1Sq); + W1 = CalculateJacobianModifiedW(Z1, Z1Sq); + break; + case ECCurve.COORD_JACOBIAN: + W1 = CalculateJacobianModifiedW(Z1, null); + break; + case ECCurve.COORD_JACOBIAN_MODIFIED: + W1 = GetJacobianModifiedW(); + break; + } + } + + for (int i = 0; i < e; ++i) + { + if (Y1.IsZero) + return curve.Infinity; + + ECFieldElement X1Squared = X1.Square(); + ECFieldElement M = Three(X1Squared); + ECFieldElement _2Y1 = Two(Y1); + ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1); + ECFieldElement S = Two(X1.Multiply(_2Y1Squared)); + ECFieldElement _4T = _2Y1Squared.Square(); + ECFieldElement _8T = Two(_4T); + + if (!W1.IsZero) + { + M = M.Add(W1); + W1 = Two(_8T.Multiply(W1)); + } + + X1 = M.Square().Subtract(Two(S)); + Y1 = M.Multiply(S.Subtract(X1)).Subtract(_8T); + Z1 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1); + } + + switch (coord) + { + case ECCurve.COORD_AFFINE: + ECFieldElement zInv = Z1.Invert(), zInv2 = zInv.Square(), zInv3 = zInv2.Multiply(zInv); + return new FpPoint(curve, X1.Multiply(zInv2), Y1.Multiply(zInv3), IsCompressed); + case ECCurve.COORD_HOMOGENEOUS: + X1 = X1.Multiply(Z1); + Z1 = Z1.Multiply(Z1.Square()); + return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed); + case ECCurve.COORD_JACOBIAN: + return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1 }, IsCompressed); + case ECCurve.COORD_JACOBIAN_MODIFIED: + return new FpPoint(curve, X1, Y1, new ECFieldElement[] { Z1, W1 }, IsCompressed); + default: + throw new InvalidOperationException("unsupported coordinate system"); + } + } + + protected virtual ECFieldElement Two(ECFieldElement x) + { + return x.Add(x); + } + + protected virtual ECFieldElement Three(ECFieldElement x) + { + return Two(x).Add(x); + } + + protected virtual ECFieldElement Four(ECFieldElement x) + { + return Two(Two(x)); + } + + protected virtual ECFieldElement Eight(ECFieldElement x) + { + return Four(Two(x)); + } + + protected virtual ECFieldElement DoubleProductFromSquares(ECFieldElement a, ECFieldElement b, + ECFieldElement aSquared, ECFieldElement bSquared) + { + /* + * NOTE: If squaring in the field is faster than multiplication, then this is a quicker + * way to calculate 2.A.B, if A^2 and B^2 are already known. + */ + return a.Add(b).Square().Subtract(aSquared).Subtract(bSquared); + } + + public override ECPoint Negate() + { + if (IsInfinity) + return this; + + ECCurve curve = Curve; + int coord = curve.CoordinateSystem; + + if (ECCurve.COORD_AFFINE != coord) + { + return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), RawZCoords, IsCompressed); + } + + return new FpPoint(curve, RawXCoord, RawYCoord.Negate(), IsCompressed); + } + + protected virtual ECFieldElement CalculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared) + { + ECFieldElement a4 = this.Curve.A; + if (a4.IsZero || Z.IsOne) + return a4; + + if (ZSquared == null) + { + ZSquared = Z.Square(); + } + + ECFieldElement W = ZSquared.Square(); + ECFieldElement a4Neg = a4.Negate(); + if (a4Neg.BitLength < a4.BitLength) + { + W = W.Multiply(a4Neg).Negate(); + } + else + { + W = W.Multiply(a4); + } + return W; + } + + protected virtual ECFieldElement GetJacobianModifiedW() + { + ECFieldElement[] ZZ = this.RawZCoords; + ECFieldElement W = ZZ[1]; + if (W == null) + { + // NOTE: Rarely, TwicePlus will result in the need for a lazy W1 calculation here + ZZ[1] = W = CalculateJacobianModifiedW(ZZ[0], null); + } + return W; + } + + protected virtual FpPoint TwiceJacobianModified(bool calculateW) + { + ECFieldElement X1 = this.RawXCoord, Y1 = this.RawYCoord, Z1 = this.RawZCoords[0], W1 = GetJacobianModifiedW(); + + ECFieldElement X1Squared = X1.Square(); + ECFieldElement M = Three(X1Squared).Add(W1); + ECFieldElement _2Y1 = Two(Y1); + ECFieldElement _2Y1Squared = _2Y1.Multiply(Y1); + ECFieldElement S = Two(X1.Multiply(_2Y1Squared)); + ECFieldElement X3 = M.Square().Subtract(Two(S)); + ECFieldElement _4T = _2Y1Squared.Square(); + ECFieldElement _8T = Two(_4T); + ECFieldElement Y3 = M.Multiply(S.Subtract(X3)).Subtract(_8T); + ECFieldElement W3 = calculateW ? Two(_8T.Multiply(W1)) : null; + ECFieldElement Z3 = Z1.IsOne ? _2Y1 : _2Y1.Multiply(Z1); + + return new FpPoint(this.Curve, X3, Y3, new ECFieldElement[] { Z3, W3 }, IsCompressed); + } + } + + internal abstract class AbstractF2mPoint + : ECPointBase + { + protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, bool withCompression) + : base(curve, x, y, withCompression) + { + } + + protected AbstractF2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + : base(curve, x, y, zs, withCompression) + { + } + + protected override bool SatisfiesCurveEquation() + { + ECCurve curve = Curve; + ECFieldElement X = this.RawXCoord, Y = this.RawYCoord, A = curve.A, B = curve.B; + ECFieldElement lhs, rhs; + + int coord = curve.CoordinateSystem; + if (coord == ECCurve.COORD_LAMBDA_PROJECTIVE) + { + ECFieldElement Z = this.RawZCoords[0]; + bool ZIsOne = Z.IsOne; + + if (X.IsZero) + { + // NOTE: For x == 0, we expect the affine-y instead of the lambda-y + lhs = Y.Square(); + rhs = B; + if (!ZIsOne) + { + ECFieldElement Z2 = Z.Square(); + rhs = rhs.Multiply(Z2); + } + } + else + { + ECFieldElement L = Y, X2 = X.Square(); + if (ZIsOne) + { + lhs = L.Square().Add(L).Add(A); + rhs = X2.Square().Add(B); + } + else + { + ECFieldElement Z2 = Z.Square(), Z4 = Z2.Square(); + lhs = L.Add(Z).MultiplyPlusProduct(L, A, Z2); + // TODO If sqrt(b) is precomputed this can be simplified to a single square + rhs = X2.SquarePlusProduct(B, Z4); + } + lhs = lhs.Multiply(X2); + } + } + else + { + lhs = Y.Add(X).Multiply(Y); + + switch (coord) + { + case ECCurve.COORD_AFFINE: + break; + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Z = this.RawZCoords[0]; + if (!Z.IsOne) + { + ECFieldElement Z2 = Z.Square(), Z3 = Z.Multiply(Z2); + lhs = lhs.Multiply(Z); + A = A.Multiply(Z); + B = B.Multiply(Z3); + } + break; + } + default: + throw new InvalidOperationException("unsupported coordinate system"); + } + + rhs = X.Add(A).Multiply(X.Square()).Add(B); + } + + return lhs.Equals(rhs); + } + + protected override bool SatisfiesOrder() + { + ECCurve curve = Curve; + BigInteger cofactor = curve.Cofactor; + if (BigInteger.Two.Equals(cofactor)) + { + /* + * Check that the trace of (X + A) is 0, then there exists a solution to L^2 + L = X + A, + * and so a halving is possible, so this point is the double of another. + */ + ECPoint N = this.Normalize(); + ECFieldElement X = N.AffineXCoord; + ECFieldElement rhs = X.Add(curve.A); + return ((AbstractF2mFieldElement)rhs).Trace() == 0; + } + if (BigInteger.ValueOf(4).Equals(cofactor)) + { + /* + * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not). + * Generate both possibilities for the square of the half-point's x-coordinate (w), + * and check if Tr(w + A) == 0 for at least one; then a second halving is possible + * (see comments for cofactor 2 above), so this point is four times another. + * + * Note: Tr(x^2) == Tr(x). + */ + ECPoint N = this.Normalize(); + ECFieldElement X = N.AffineXCoord; + ECFieldElement lambda = ((AbstractF2mCurve)curve).SolveQuadraticEquation(X.Add(curve.A)); + if (lambda == null) + return false; + + ECFieldElement w = X.Multiply(lambda).Add(N.AffineYCoord); + ECFieldElement t = w.Add(curve.A); + return ((AbstractF2mFieldElement)t).Trace() == 0 + || ((AbstractF2mFieldElement)(t.Add(X))).Trace() == 0; + } + + return base.SatisfiesOrder(); + } + + public override ECPoint ScaleX(ECFieldElement scale) + { + if (this.IsInfinity) + return this; + + switch (CurveCoordinateSystem) + { + case ECCurve.COORD_LAMBDA_AFFINE: + { + // Y is actually Lambda (X + Y/X) here + ECFieldElement X = RawXCoord, L = RawYCoord; + + ECFieldElement X2 = X.Multiply(scale); + ECFieldElement L2 = L.Add(X).Divide(scale).Add(X2); + + return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed); + } + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + // Y is actually Lambda (X + Y/X) here + ECFieldElement X = RawXCoord, L = RawYCoord, Z = RawZCoords[0]; + + // We scale the Z coordinate also, to avoid an inversion + ECFieldElement X2 = X.Multiply(scale.Square()); + ECFieldElement L2 = L.Add(X).Add(X2); + ECFieldElement Z2 = Z.Multiply(scale); + + return Curve.CreateRawPoint(X, L2, new ECFieldElement[] { Z2 }, IsCompressed); + } + default: + { + return base.ScaleX(scale); + } + } + } + + public override ECPoint ScaleY(ECFieldElement scale) + { + if (this.IsInfinity) + return this; + + switch (CurveCoordinateSystem) + { + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement X = RawXCoord, L = RawYCoord; + + // Y is actually Lambda (X + Y/X) here + ECFieldElement L2 = L.Add(X).Multiply(scale).Add(X); + + return Curve.CreateRawPoint(X, L2, RawZCoords, IsCompressed); + } + default: + { + return base.ScaleY(scale); + } + } + } + + public override ECPoint Subtract(ECPoint b) + { + if (b.IsInfinity) + return this; + + // Add -b + return Add(b.Negate()); + } + + public virtual AbstractF2mPoint Tau() + { + if (this.IsInfinity) + return this; + + ECCurve curve = this.Curve; + int coord = curve.CoordinateSystem; + + ECFieldElement X1 = this.RawXCoord; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + ECFieldElement Y1 = this.RawYCoord; + return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(), IsCompressed); + } + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0]; + return (AbstractF2mPoint)curve.CreateRawPoint(X1.Square(), Y1.Square(), + new ECFieldElement[] { Z1.Square() }, IsCompressed); + } + default: + { + throw new InvalidOperationException("unsupported coordinate system"); + } + } + } + + public virtual AbstractF2mPoint TauPow(int pow) + { + if (this.IsInfinity) + return this; + + ECCurve curve = this.Curve; + int coord = curve.CoordinateSystem; + + ECFieldElement X1 = this.RawXCoord; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + ECFieldElement Y1 = this.RawYCoord; + return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow), IsCompressed); + } + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0]; + return (AbstractF2mPoint)curve.CreateRawPoint(X1.SquarePow(pow), Y1.SquarePow(pow), + new ECFieldElement[] { Z1.SquarePow(pow) }, IsCompressed); + } + default: + { + throw new InvalidOperationException("unsupported coordinate system"); + } + } + } + } + + /** + * Elliptic curve points over F2m + */ + internal class F2mPoint + : AbstractF2mPoint + { + /** + * @param curve base curve + * @param x x point + * @param y y point + */ + public F2mPoint( + ECCurve curve, + ECFieldElement x, + ECFieldElement y) + : this(curve, x, y, false) + { + } + + /** + * @param curve base curve + * @param x x point + * @param y y point + * @param withCompression true if encode with point compression. + */ + public F2mPoint( + ECCurve curve, + ECFieldElement x, + ECFieldElement y, + bool withCompression) + : base(curve, x, y, withCompression) + { + if ((x == null) != (y == null)) + { + throw new ArgumentException("Exactly one of the field elements is null"); + } + + if (x != null) + { + // Check if x and y are elements of the same field + F2mFieldElement.CheckFieldElements(x, y); + + // Check if x and a are elements of the same field + if (curve != null) + { + F2mFieldElement.CheckFieldElements(x, curve.A); + } + } + } + + internal F2mPoint(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, bool withCompression) + : base(curve, x, y, zs, withCompression) + { + } + + protected override ECPoint Detach() + { + return new F2mPoint(null, AffineXCoord, AffineYCoord, false); + } + + public override ECFieldElement YCoord + { + get + { + int coord = this.CurveCoordinateSystem; + + switch (coord) + { + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement X = RawXCoord, L = RawYCoord; + + if (this.IsInfinity || X.IsZero) + return L; + + // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly + ECFieldElement Y = L.Add(X).Multiply(X); + if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord) + { + ECFieldElement Z = RawZCoords[0]; + if (!Z.IsOne) + { + Y = Y.Divide(Z); + } + } + return Y; + } + default: + { + return RawYCoord; + } + } + } + } + + protected internal override bool CompressionYTilde + { + get + { + ECFieldElement X = this.RawXCoord; + if (X.IsZero) + { + return false; + } + + ECFieldElement Y = this.RawYCoord; + + switch (this.CurveCoordinateSystem) + { + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + // Y is actually Lambda (X + Y/X) here + return Y.TestBitZero() != X.TestBitZero(); + } + default: + { + return Y.Divide(X).TestBitZero(); + } + } + } + } + + public override ECPoint Add(ECPoint b) + { + if (this.IsInfinity) + return b; + if (b.IsInfinity) + return this; + + ECCurve curve = this.Curve; + int coord = curve.CoordinateSystem; + + ECFieldElement X1 = this.RawXCoord; + ECFieldElement X2 = b.RawXCoord; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement Y1 = this.RawYCoord; + ECFieldElement Y2 = b.RawYCoord; + + ECFieldElement dx = X1.Add(X2), dy = Y1.Add(Y2); + if (dx.IsZero) + { + if (dy.IsZero) + { + return Twice(); + } + + return curve.Infinity; + } + + ECFieldElement L = dy.Divide(dx); + + ECFieldElement X3 = L.Square().Add(L).Add(dx).Add(curve.A); + ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1); + + return new F2mPoint(curve, X3, Y3, IsCompressed); + } + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0]; + ECFieldElement Y2 = b.RawYCoord, Z2 = b.RawZCoords[0]; + + bool Z1IsOne = Z1.IsOne; + ECFieldElement U1 = Y2, V1 = X2; + if (!Z1IsOne) + { + U1 = U1.Multiply(Z1); + V1 = V1.Multiply(Z1); + } + + bool Z2IsOne = Z2.IsOne; + ECFieldElement U2 = Y1, V2 = X1; + if (!Z2IsOne) + { + U2 = U2.Multiply(Z2); + V2 = V2.Multiply(Z2); + } + + ECFieldElement U = U1.Add(U2); + ECFieldElement V = V1.Add(V2); + + if (V.IsZero) + { + if (U.IsZero) + { + return Twice(); + } + + return curve.Infinity; + } + + ECFieldElement VSq = V.Square(); + ECFieldElement VCu = VSq.Multiply(V); + ECFieldElement W = Z1IsOne ? Z2 : Z2IsOne ? Z1 : Z1.Multiply(Z2); + ECFieldElement uv = U.Add(V); + ECFieldElement A = uv.MultiplyPlusProduct(U, VSq, curve.A).Multiply(W).Add(VCu); + + ECFieldElement X3 = V.Multiply(A); + ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.Multiply(Z2); + ECFieldElement Y3 = U.MultiplyPlusProduct(X1, V, Y1).MultiplyPlusProduct(VSqZ2, uv, A); + ECFieldElement Z3 = VCu.Multiply(W); + + return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed); + } + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + if (X1.IsZero) + { + if (X2.IsZero) + return curve.Infinity; + + return b.Add(this); + } + + ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0]; + ECFieldElement L2 = b.RawYCoord, Z2 = b.RawZCoords[0]; + + bool Z1IsOne = Z1.IsOne; + ECFieldElement U2 = X2, S2 = L2; + if (!Z1IsOne) + { + U2 = U2.Multiply(Z1); + S2 = S2.Multiply(Z1); + } + + bool Z2IsOne = Z2.IsOne; + ECFieldElement U1 = X1, S1 = L1; + if (!Z2IsOne) + { + U1 = U1.Multiply(Z2); + S1 = S1.Multiply(Z2); + } + + ECFieldElement A = S1.Add(S2); + ECFieldElement B = U1.Add(U2); + + if (B.IsZero) + { + if (A.IsZero) + { + return Twice(); + } + + return curve.Infinity; + } + + ECFieldElement X3, L3, Z3; + if (X2.IsZero) + { + // TODO This can probably be optimized quite a bit + ECPoint p = this.Normalize(); + X1 = p.RawXCoord; + ECFieldElement Y1 = p.YCoord; + + ECFieldElement Y2 = L2; + ECFieldElement L = Y1.Add(Y2).Divide(X1); + + X3 = L.Square().Add(L).Add(X1).Add(curve.A); + if (X3.IsZero) + { + return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed); + } + + ECFieldElement Y3 = L.Multiply(X1.Add(X3)).Add(X3).Add(Y1); + L3 = Y3.Divide(X3).Add(X3); + Z3 = curve.FromBigInteger(BigInteger.One); + } + else + { + B = B.Square(); + + ECFieldElement AU1 = A.Multiply(U1); + ECFieldElement AU2 = A.Multiply(U2); + + X3 = AU1.Multiply(AU2); + if (X3.IsZero) + { + return new F2mPoint(curve, X3, curve.B.Sqrt(), IsCompressed); + } + + ECFieldElement ABZ2 = A.Multiply(B); + if (!Z2IsOne) + { + ABZ2 = ABZ2.Multiply(Z2); + } + + L3 = AU2.Add(B).SquarePlusProduct(ABZ2, L1.Add(Z1)); + + Z3 = ABZ2; + if (!Z1IsOne) + { + Z3 = Z3.Multiply(Z1); + } + } + + return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed); + } + default: + { + throw new InvalidOperationException("unsupported coordinate system"); + } + } + } + + /* (non-Javadoc) + * @see Org.BouncyCastle.Math.EC.ECPoint#twice() + */ + public override ECPoint Twice() + { + if (this.IsInfinity) + return this; + + ECCurve curve = this.Curve; + + ECFieldElement X1 = this.RawXCoord; + if (X1.IsZero) + { + // A point with X == 0 is it's own additive inverse + return curve.Infinity; + } + + int coord = curve.CoordinateSystem; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement Y1 = this.RawYCoord; + + ECFieldElement L1 = Y1.Divide(X1).Add(X1); + + ECFieldElement X3 = L1.Square().Add(L1).Add(curve.A); + ECFieldElement Y3 = X1.SquarePlusProduct(X3, L1.AddOne()); + + return new F2mPoint(curve, X3, Y3, IsCompressed); + } + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Y1 = this.RawYCoord, Z1 = this.RawZCoords[0]; + + bool Z1IsOne = Z1.IsOne; + ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1); + ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.Multiply(Z1); + + ECFieldElement X1Sq = X1.Square(); + ECFieldElement S = X1Sq.Add(Y1Z1); + ECFieldElement V = X1Z1; + ECFieldElement vSquared = V.Square(); + ECFieldElement sv = S.Add(V); + ECFieldElement h = sv.MultiplyPlusProduct(S, vSquared, curve.A); + + ECFieldElement X3 = V.Multiply(h); + ECFieldElement Y3 = X1Sq.Square().MultiplyPlusProduct(V, h, sv); + ECFieldElement Z3 = V.Multiply(vSquared); + + return new F2mPoint(curve, X3, Y3, new ECFieldElement[] { Z3 }, IsCompressed); + } + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0]; + + bool Z1IsOne = Z1.IsOne; + ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.Multiply(Z1); + ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.Square(); + ECFieldElement a = curve.A; + ECFieldElement aZ1Sq = Z1IsOne ? a : a.Multiply(Z1Sq); + ECFieldElement T = L1.Square().Add(L1Z1).Add(aZ1Sq); + if (T.IsZero) + { + return new F2mPoint(curve, T, curve.B.Sqrt(), IsCompressed); + } + + ECFieldElement X3 = T.Square(); + ECFieldElement Z3 = Z1IsOne ? T : T.Multiply(Z1Sq); + + ECFieldElement b = curve.B; + ECFieldElement L3; + if (b.BitLength < (curve.FieldSize >> 1)) + { + ECFieldElement t1 = L1.Add(X1).Square(); + ECFieldElement t2; + if (b.IsOne) + { + t2 = aZ1Sq.Add(Z1Sq).Square(); + } + else + { + // TODO Can be calculated with one square if we pre-compute sqrt(b) + t2 = aZ1Sq.SquarePlusProduct(b, Z1Sq.Square()); + } + L3 = t1.Add(T).Add(Z1Sq).Multiply(t1).Add(t2).Add(X3); + if (a.IsZero) + { + L3 = L3.Add(Z3); + } + else if (!a.IsOne) + { + L3 = L3.Add(a.AddOne().Multiply(Z3)); + } + } + else + { + ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.Multiply(Z1); + L3 = X1Z1.SquarePlusProduct(T, L1Z1).Add(X3).Add(Z3); + } + + return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed); + } + default: + { + throw new InvalidOperationException("unsupported coordinate system"); + } + } + } + + public override ECPoint TwicePlus(ECPoint b) + { + if (this.IsInfinity) + return b; + if (b.IsInfinity) + return Twice(); + + ECCurve curve = this.Curve; + + ECFieldElement X1 = this.RawXCoord; + if (X1.IsZero) + { + // A point with X == 0 is it's own additive inverse + return b; + } + + int coord = curve.CoordinateSystem; + + switch (coord) + { + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + // NOTE: twicePlus() only optimized for lambda-affine argument + ECFieldElement X2 = b.RawXCoord, Z2 = b.RawZCoords[0]; + if (X2.IsZero || !Z2.IsOne) + { + return Twice().Add(b); + } + + ECFieldElement L1 = this.RawYCoord, Z1 = this.RawZCoords[0]; + ECFieldElement L2 = b.RawYCoord; + + ECFieldElement X1Sq = X1.Square(); + ECFieldElement L1Sq = L1.Square(); + ECFieldElement Z1Sq = Z1.Square(); + ECFieldElement L1Z1 = L1.Multiply(Z1); + + ECFieldElement T = curve.A.Multiply(Z1Sq).Add(L1Sq).Add(L1Z1); + ECFieldElement L2plus1 = L2.AddOne(); + ECFieldElement A = curve.A.Add(L2plus1).Multiply(Z1Sq).Add(L1Sq).MultiplyPlusProduct(T, X1Sq, Z1Sq); + ECFieldElement X2Z1Sq = X2.Multiply(Z1Sq); + ECFieldElement B = X2Z1Sq.Add(T).Square(); + + if (B.IsZero) + { + if (A.IsZero) + { + return b.Twice(); + } + + return curve.Infinity; + } + + if (A.IsZero) + { + return new F2mPoint(curve, A, curve.B.Sqrt(), IsCompressed); + } + + ECFieldElement X3 = A.Square().Multiply(X2Z1Sq); + ECFieldElement Z3 = A.Multiply(B).Multiply(Z1Sq); + ECFieldElement L3 = A.Add(B).Square().MultiplyPlusProduct(T, L2plus1, Z3); + + return new F2mPoint(curve, X3, L3, new ECFieldElement[] { Z3 }, IsCompressed); + } + default: + { + return Twice().Add(b); + } + } + } + + public override ECPoint Negate() + { + if (this.IsInfinity) + return this; + + ECFieldElement X = this.RawXCoord; + if (X.IsZero) + return this; + + ECCurve curve = this.Curve; + int coord = curve.CoordinateSystem; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + { + ECFieldElement Y = this.RawYCoord; + return new F2mPoint(curve, X, Y.Add(X), IsCompressed); + } + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Y = this.RawYCoord, Z = this.RawZCoords[0]; + return new F2mPoint(curve, X, Y.Add(X), new ECFieldElement[] { Z }, IsCompressed); + } + case ECCurve.COORD_LAMBDA_AFFINE: + { + ECFieldElement L = this.RawYCoord; + return new F2mPoint(curve, X, L.AddOne(), IsCompressed); + } + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + // L is actually Lambda (X + Y/X) here + ECFieldElement L = this.RawYCoord, Z = this.RawZCoords[0]; + return new F2mPoint(curve, X, L.Add(Z), new ECFieldElement[] { Z }, IsCompressed); + } + default: + { + throw new InvalidOperationException("unsupported coordinate system"); + } + } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECPointMap.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECPointMap.cs new file mode 100644 index 00000000..9f281995 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/ECPointMap.cs @@ -0,0 +1,9 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC +{ + internal interface ECPointMap + { + ECPoint Map(ECPoint p); + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/LongArray.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/LongArray.cs new file mode 100644 index 00000000..6b51b5ff --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/LongArray.cs @@ -0,0 +1,2206 @@ +using System; +using System.Text; + +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC +{ + internal class LongArray + { + //private static long DEInterleave_MASK = 0x5555555555555555L; + + /* + * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits. + * In a binary field, this operation is the same as squaring an 8 bit number. + */ + private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[] + { + 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, + 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, + 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, + 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, + 0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, + 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, + 0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, + 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, + 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, + 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, + 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, + 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, + 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, + 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, + 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, + 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, + 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, + 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, + 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, + 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, + 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, + 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, + 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, + 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, + 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, + 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, + 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, + 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, + 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, + 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, + 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, + 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 + }; + + /* + * This expands 7 bit indices into 21 bit contents (high bit 18), by inserting 0s between bits. + */ + private static readonly int[] INTERLEAVE3_TABLE = new int[] + { + 0x00000, 0x00001, 0x00008, 0x00009, 0x00040, 0x00041, 0x00048, 0x00049, + 0x00200, 0x00201, 0x00208, 0x00209, 0x00240, 0x00241, 0x00248, 0x00249, + 0x01000, 0x01001, 0x01008, 0x01009, 0x01040, 0x01041, 0x01048, 0x01049, + 0x01200, 0x01201, 0x01208, 0x01209, 0x01240, 0x01241, 0x01248, 0x01249, + 0x08000, 0x08001, 0x08008, 0x08009, 0x08040, 0x08041, 0x08048, 0x08049, + 0x08200, 0x08201, 0x08208, 0x08209, 0x08240, 0x08241, 0x08248, 0x08249, + 0x09000, 0x09001, 0x09008, 0x09009, 0x09040, 0x09041, 0x09048, 0x09049, + 0x09200, 0x09201, 0x09208, 0x09209, 0x09240, 0x09241, 0x09248, 0x09249, + 0x40000, 0x40001, 0x40008, 0x40009, 0x40040, 0x40041, 0x40048, 0x40049, + 0x40200, 0x40201, 0x40208, 0x40209, 0x40240, 0x40241, 0x40248, 0x40249, + 0x41000, 0x41001, 0x41008, 0x41009, 0x41040, 0x41041, 0x41048, 0x41049, + 0x41200, 0x41201, 0x41208, 0x41209, 0x41240, 0x41241, 0x41248, 0x41249, + 0x48000, 0x48001, 0x48008, 0x48009, 0x48040, 0x48041, 0x48048, 0x48049, + 0x48200, 0x48201, 0x48208, 0x48209, 0x48240, 0x48241, 0x48248, 0x48249, + 0x49000, 0x49001, 0x49008, 0x49009, 0x49040, 0x49041, 0x49048, 0x49049, + 0x49200, 0x49201, 0x49208, 0x49209, 0x49240, 0x49241, 0x49248, 0x49249 + }; + + /* + * This expands 8 bit indices into 32 bit contents (high bit 28), by inserting 0s between bits. + */ + private static readonly int[] INTERLEAVE4_TABLE = new int[] + { + 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, 0x00000101, 0x00000110, 0x00000111, + 0x00001000, 0x00001001, 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, 0x00001111, + 0x00010000, 0x00010001, 0x00010010, 0x00010011, 0x00010100, 0x00010101, 0x00010110, 0x00010111, + 0x00011000, 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, 0x00011110, 0x00011111, + 0x00100000, 0x00100001, 0x00100010, 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111, + 0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, 0x00101101, 0x00101110, 0x00101111, + 0x00110000, 0x00110001, 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, 0x00110111, + 0x00111000, 0x00111001, 0x00111010, 0x00111011, 0x00111100, 0x00111101, 0x00111110, 0x00111111, + 0x01000000, 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, 0x01000110, 0x01000111, + 0x01001000, 0x01001001, 0x01001010, 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111, + 0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, 0x01010101, 0x01010110, 0x01010111, + 0x01011000, 0x01011001, 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, 0x01011111, + 0x01100000, 0x01100001, 0x01100010, 0x01100011, 0x01100100, 0x01100101, 0x01100110, 0x01100111, + 0x01101000, 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, 0x01101110, 0x01101111, + 0x01110000, 0x01110001, 0x01110010, 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111, + 0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, 0x01111101, 0x01111110, 0x01111111, + 0x10000000, 0x10000001, 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, 0x10000111, + 0x10001000, 0x10001001, 0x10001010, 0x10001011, 0x10001100, 0x10001101, 0x10001110, 0x10001111, + 0x10010000, 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, 0x10010110, 0x10010111, + 0x10011000, 0x10011001, 0x10011010, 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111, + 0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, 0x10100101, 0x10100110, 0x10100111, + 0x10101000, 0x10101001, 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, 0x10101111, + 0x10110000, 0x10110001, 0x10110010, 0x10110011, 0x10110100, 0x10110101, 0x10110110, 0x10110111, + 0x10111000, 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, 0x10111110, 0x10111111, + 0x11000000, 0x11000001, 0x11000010, 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111, + 0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, 0x11001101, 0x11001110, 0x11001111, + 0x11010000, 0x11010001, 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, 0x11010111, + 0x11011000, 0x11011001, 0x11011010, 0x11011011, 0x11011100, 0x11011101, 0x11011110, 0x11011111, + 0x11100000, 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, 0x11100110, 0x11100111, + 0x11101000, 0x11101001, 0x11101010, 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111, + 0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, 0x11110101, 0x11110110, 0x11110111, + 0x11111000, 0x11111001, 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, 0x11111111 + }; + + /* + * This expands 7 bit indices into 35 bit contents (high bit 30), by inserting 0s between bits. + */ + private static readonly int[] INTERLEAVE5_TABLE = new int[] { + 0x00000000, 0x00000001, 0x00000020, 0x00000021, 0x00000400, 0x00000401, 0x00000420, 0x00000421, + 0x00008000, 0x00008001, 0x00008020, 0x00008021, 0x00008400, 0x00008401, 0x00008420, 0x00008421, + 0x00100000, 0x00100001, 0x00100020, 0x00100021, 0x00100400, 0x00100401, 0x00100420, 0x00100421, + 0x00108000, 0x00108001, 0x00108020, 0x00108021, 0x00108400, 0x00108401, 0x00108420, 0x00108421, + 0x02000000, 0x02000001, 0x02000020, 0x02000021, 0x02000400, 0x02000401, 0x02000420, 0x02000421, + 0x02008000, 0x02008001, 0x02008020, 0x02008021, 0x02008400, 0x02008401, 0x02008420, 0x02008421, + 0x02100000, 0x02100001, 0x02100020, 0x02100021, 0x02100400, 0x02100401, 0x02100420, 0x02100421, + 0x02108000, 0x02108001, 0x02108020, 0x02108021, 0x02108400, 0x02108401, 0x02108420, 0x02108421, + 0x40000000, 0x40000001, 0x40000020, 0x40000021, 0x40000400, 0x40000401, 0x40000420, 0x40000421, + 0x40008000, 0x40008001, 0x40008020, 0x40008021, 0x40008400, 0x40008401, 0x40008420, 0x40008421, + 0x40100000, 0x40100001, 0x40100020, 0x40100021, 0x40100400, 0x40100401, 0x40100420, 0x40100421, + 0x40108000, 0x40108001, 0x40108020, 0x40108021, 0x40108400, 0x40108401, 0x40108420, 0x40108421, + 0x42000000, 0x42000001, 0x42000020, 0x42000021, 0x42000400, 0x42000401, 0x42000420, 0x42000421, + 0x42008000, 0x42008001, 0x42008020, 0x42008021, 0x42008400, 0x42008401, 0x42008420, 0x42008421, + 0x42100000, 0x42100001, 0x42100020, 0x42100021, 0x42100400, 0x42100401, 0x42100420, 0x42100421, + 0x42108000, 0x42108001, 0x42108020, 0x42108021, 0x42108400, 0x42108401, 0x42108420, 0x42108421 + }; + + /* + * This expands 9 bit indices into 63 bit (long) contents (high bit 56), by inserting 0s between bits. + */ + private static readonly long[] INTERLEAVE7_TABLE = new long[] + { + 0x0000000000000000L, 0x0000000000000001L, 0x0000000000000080L, 0x0000000000000081L, + 0x0000000000004000L, 0x0000000000004001L, 0x0000000000004080L, 0x0000000000004081L, + 0x0000000000200000L, 0x0000000000200001L, 0x0000000000200080L, 0x0000000000200081L, + 0x0000000000204000L, 0x0000000000204001L, 0x0000000000204080L, 0x0000000000204081L, + 0x0000000010000000L, 0x0000000010000001L, 0x0000000010000080L, 0x0000000010000081L, + 0x0000000010004000L, 0x0000000010004001L, 0x0000000010004080L, 0x0000000010004081L, + 0x0000000010200000L, 0x0000000010200001L, 0x0000000010200080L, 0x0000000010200081L, + 0x0000000010204000L, 0x0000000010204001L, 0x0000000010204080L, 0x0000000010204081L, + 0x0000000800000000L, 0x0000000800000001L, 0x0000000800000080L, 0x0000000800000081L, + 0x0000000800004000L, 0x0000000800004001L, 0x0000000800004080L, 0x0000000800004081L, + 0x0000000800200000L, 0x0000000800200001L, 0x0000000800200080L, 0x0000000800200081L, + 0x0000000800204000L, 0x0000000800204001L, 0x0000000800204080L, 0x0000000800204081L, + 0x0000000810000000L, 0x0000000810000001L, 0x0000000810000080L, 0x0000000810000081L, + 0x0000000810004000L, 0x0000000810004001L, 0x0000000810004080L, 0x0000000810004081L, + 0x0000000810200000L, 0x0000000810200001L, 0x0000000810200080L, 0x0000000810200081L, + 0x0000000810204000L, 0x0000000810204001L, 0x0000000810204080L, 0x0000000810204081L, + 0x0000040000000000L, 0x0000040000000001L, 0x0000040000000080L, 0x0000040000000081L, + 0x0000040000004000L, 0x0000040000004001L, 0x0000040000004080L, 0x0000040000004081L, + 0x0000040000200000L, 0x0000040000200001L, 0x0000040000200080L, 0x0000040000200081L, + 0x0000040000204000L, 0x0000040000204001L, 0x0000040000204080L, 0x0000040000204081L, + 0x0000040010000000L, 0x0000040010000001L, 0x0000040010000080L, 0x0000040010000081L, + 0x0000040010004000L, 0x0000040010004001L, 0x0000040010004080L, 0x0000040010004081L, + 0x0000040010200000L, 0x0000040010200001L, 0x0000040010200080L, 0x0000040010200081L, + 0x0000040010204000L, 0x0000040010204001L, 0x0000040010204080L, 0x0000040010204081L, + 0x0000040800000000L, 0x0000040800000001L, 0x0000040800000080L, 0x0000040800000081L, + 0x0000040800004000L, 0x0000040800004001L, 0x0000040800004080L, 0x0000040800004081L, + 0x0000040800200000L, 0x0000040800200001L, 0x0000040800200080L, 0x0000040800200081L, + 0x0000040800204000L, 0x0000040800204001L, 0x0000040800204080L, 0x0000040800204081L, + 0x0000040810000000L, 0x0000040810000001L, 0x0000040810000080L, 0x0000040810000081L, + 0x0000040810004000L, 0x0000040810004001L, 0x0000040810004080L, 0x0000040810004081L, + 0x0000040810200000L, 0x0000040810200001L, 0x0000040810200080L, 0x0000040810200081L, + 0x0000040810204000L, 0x0000040810204001L, 0x0000040810204080L, 0x0000040810204081L, + 0x0002000000000000L, 0x0002000000000001L, 0x0002000000000080L, 0x0002000000000081L, + 0x0002000000004000L, 0x0002000000004001L, 0x0002000000004080L, 0x0002000000004081L, + 0x0002000000200000L, 0x0002000000200001L, 0x0002000000200080L, 0x0002000000200081L, + 0x0002000000204000L, 0x0002000000204001L, 0x0002000000204080L, 0x0002000000204081L, + 0x0002000010000000L, 0x0002000010000001L, 0x0002000010000080L, 0x0002000010000081L, + 0x0002000010004000L, 0x0002000010004001L, 0x0002000010004080L, 0x0002000010004081L, + 0x0002000010200000L, 0x0002000010200001L, 0x0002000010200080L, 0x0002000010200081L, + 0x0002000010204000L, 0x0002000010204001L, 0x0002000010204080L, 0x0002000010204081L, + 0x0002000800000000L, 0x0002000800000001L, 0x0002000800000080L, 0x0002000800000081L, + 0x0002000800004000L, 0x0002000800004001L, 0x0002000800004080L, 0x0002000800004081L, + 0x0002000800200000L, 0x0002000800200001L, 0x0002000800200080L, 0x0002000800200081L, + 0x0002000800204000L, 0x0002000800204001L, 0x0002000800204080L, 0x0002000800204081L, + 0x0002000810000000L, 0x0002000810000001L, 0x0002000810000080L, 0x0002000810000081L, + 0x0002000810004000L, 0x0002000810004001L, 0x0002000810004080L, 0x0002000810004081L, + 0x0002000810200000L, 0x0002000810200001L, 0x0002000810200080L, 0x0002000810200081L, + 0x0002000810204000L, 0x0002000810204001L, 0x0002000810204080L, 0x0002000810204081L, + 0x0002040000000000L, 0x0002040000000001L, 0x0002040000000080L, 0x0002040000000081L, + 0x0002040000004000L, 0x0002040000004001L, 0x0002040000004080L, 0x0002040000004081L, + 0x0002040000200000L, 0x0002040000200001L, 0x0002040000200080L, 0x0002040000200081L, + 0x0002040000204000L, 0x0002040000204001L, 0x0002040000204080L, 0x0002040000204081L, + 0x0002040010000000L, 0x0002040010000001L, 0x0002040010000080L, 0x0002040010000081L, + 0x0002040010004000L, 0x0002040010004001L, 0x0002040010004080L, 0x0002040010004081L, + 0x0002040010200000L, 0x0002040010200001L, 0x0002040010200080L, 0x0002040010200081L, + 0x0002040010204000L, 0x0002040010204001L, 0x0002040010204080L, 0x0002040010204081L, + 0x0002040800000000L, 0x0002040800000001L, 0x0002040800000080L, 0x0002040800000081L, + 0x0002040800004000L, 0x0002040800004001L, 0x0002040800004080L, 0x0002040800004081L, + 0x0002040800200000L, 0x0002040800200001L, 0x0002040800200080L, 0x0002040800200081L, + 0x0002040800204000L, 0x0002040800204001L, 0x0002040800204080L, 0x0002040800204081L, + 0x0002040810000000L, 0x0002040810000001L, 0x0002040810000080L, 0x0002040810000081L, + 0x0002040810004000L, 0x0002040810004001L, 0x0002040810004080L, 0x0002040810004081L, + 0x0002040810200000L, 0x0002040810200001L, 0x0002040810200080L, 0x0002040810200081L, + 0x0002040810204000L, 0x0002040810204001L, 0x0002040810204080L, 0x0002040810204081L, + 0x0100000000000000L, 0x0100000000000001L, 0x0100000000000080L, 0x0100000000000081L, + 0x0100000000004000L, 0x0100000000004001L, 0x0100000000004080L, 0x0100000000004081L, + 0x0100000000200000L, 0x0100000000200001L, 0x0100000000200080L, 0x0100000000200081L, + 0x0100000000204000L, 0x0100000000204001L, 0x0100000000204080L, 0x0100000000204081L, + 0x0100000010000000L, 0x0100000010000001L, 0x0100000010000080L, 0x0100000010000081L, + 0x0100000010004000L, 0x0100000010004001L, 0x0100000010004080L, 0x0100000010004081L, + 0x0100000010200000L, 0x0100000010200001L, 0x0100000010200080L, 0x0100000010200081L, + 0x0100000010204000L, 0x0100000010204001L, 0x0100000010204080L, 0x0100000010204081L, + 0x0100000800000000L, 0x0100000800000001L, 0x0100000800000080L, 0x0100000800000081L, + 0x0100000800004000L, 0x0100000800004001L, 0x0100000800004080L, 0x0100000800004081L, + 0x0100000800200000L, 0x0100000800200001L, 0x0100000800200080L, 0x0100000800200081L, + 0x0100000800204000L, 0x0100000800204001L, 0x0100000800204080L, 0x0100000800204081L, + 0x0100000810000000L, 0x0100000810000001L, 0x0100000810000080L, 0x0100000810000081L, + 0x0100000810004000L, 0x0100000810004001L, 0x0100000810004080L, 0x0100000810004081L, + 0x0100000810200000L, 0x0100000810200001L, 0x0100000810200080L, 0x0100000810200081L, + 0x0100000810204000L, 0x0100000810204001L, 0x0100000810204080L, 0x0100000810204081L, + 0x0100040000000000L, 0x0100040000000001L, 0x0100040000000080L, 0x0100040000000081L, + 0x0100040000004000L, 0x0100040000004001L, 0x0100040000004080L, 0x0100040000004081L, + 0x0100040000200000L, 0x0100040000200001L, 0x0100040000200080L, 0x0100040000200081L, + 0x0100040000204000L, 0x0100040000204001L, 0x0100040000204080L, 0x0100040000204081L, + 0x0100040010000000L, 0x0100040010000001L, 0x0100040010000080L, 0x0100040010000081L, + 0x0100040010004000L, 0x0100040010004001L, 0x0100040010004080L, 0x0100040010004081L, + 0x0100040010200000L, 0x0100040010200001L, 0x0100040010200080L, 0x0100040010200081L, + 0x0100040010204000L, 0x0100040010204001L, 0x0100040010204080L, 0x0100040010204081L, + 0x0100040800000000L, 0x0100040800000001L, 0x0100040800000080L, 0x0100040800000081L, + 0x0100040800004000L, 0x0100040800004001L, 0x0100040800004080L, 0x0100040800004081L, + 0x0100040800200000L, 0x0100040800200001L, 0x0100040800200080L, 0x0100040800200081L, + 0x0100040800204000L, 0x0100040800204001L, 0x0100040800204080L, 0x0100040800204081L, + 0x0100040810000000L, 0x0100040810000001L, 0x0100040810000080L, 0x0100040810000081L, + 0x0100040810004000L, 0x0100040810004001L, 0x0100040810004080L, 0x0100040810004081L, + 0x0100040810200000L, 0x0100040810200001L, 0x0100040810200080L, 0x0100040810200081L, + 0x0100040810204000L, 0x0100040810204001L, 0x0100040810204080L, 0x0100040810204081L, + 0x0102000000000000L, 0x0102000000000001L, 0x0102000000000080L, 0x0102000000000081L, + 0x0102000000004000L, 0x0102000000004001L, 0x0102000000004080L, 0x0102000000004081L, + 0x0102000000200000L, 0x0102000000200001L, 0x0102000000200080L, 0x0102000000200081L, + 0x0102000000204000L, 0x0102000000204001L, 0x0102000000204080L, 0x0102000000204081L, + 0x0102000010000000L, 0x0102000010000001L, 0x0102000010000080L, 0x0102000010000081L, + 0x0102000010004000L, 0x0102000010004001L, 0x0102000010004080L, 0x0102000010004081L, + 0x0102000010200000L, 0x0102000010200001L, 0x0102000010200080L, 0x0102000010200081L, + 0x0102000010204000L, 0x0102000010204001L, 0x0102000010204080L, 0x0102000010204081L, + 0x0102000800000000L, 0x0102000800000001L, 0x0102000800000080L, 0x0102000800000081L, + 0x0102000800004000L, 0x0102000800004001L, 0x0102000800004080L, 0x0102000800004081L, + 0x0102000800200000L, 0x0102000800200001L, 0x0102000800200080L, 0x0102000800200081L, + 0x0102000800204000L, 0x0102000800204001L, 0x0102000800204080L, 0x0102000800204081L, + 0x0102000810000000L, 0x0102000810000001L, 0x0102000810000080L, 0x0102000810000081L, + 0x0102000810004000L, 0x0102000810004001L, 0x0102000810004080L, 0x0102000810004081L, + 0x0102000810200000L, 0x0102000810200001L, 0x0102000810200080L, 0x0102000810200081L, + 0x0102000810204000L, 0x0102000810204001L, 0x0102000810204080L, 0x0102000810204081L, + 0x0102040000000000L, 0x0102040000000001L, 0x0102040000000080L, 0x0102040000000081L, + 0x0102040000004000L, 0x0102040000004001L, 0x0102040000004080L, 0x0102040000004081L, + 0x0102040000200000L, 0x0102040000200001L, 0x0102040000200080L, 0x0102040000200081L, + 0x0102040000204000L, 0x0102040000204001L, 0x0102040000204080L, 0x0102040000204081L, + 0x0102040010000000L, 0x0102040010000001L, 0x0102040010000080L, 0x0102040010000081L, + 0x0102040010004000L, 0x0102040010004001L, 0x0102040010004080L, 0x0102040010004081L, + 0x0102040010200000L, 0x0102040010200001L, 0x0102040010200080L, 0x0102040010200081L, + 0x0102040010204000L, 0x0102040010204001L, 0x0102040010204080L, 0x0102040010204081L, + 0x0102040800000000L, 0x0102040800000001L, 0x0102040800000080L, 0x0102040800000081L, + 0x0102040800004000L, 0x0102040800004001L, 0x0102040800004080L, 0x0102040800004081L, + 0x0102040800200000L, 0x0102040800200001L, 0x0102040800200080L, 0x0102040800200081L, + 0x0102040800204000L, 0x0102040800204001L, 0x0102040800204080L, 0x0102040800204081L, + 0x0102040810000000L, 0x0102040810000001L, 0x0102040810000080L, 0x0102040810000081L, + 0x0102040810004000L, 0x0102040810004001L, 0x0102040810004080L, 0x0102040810004081L, + 0x0102040810200000L, 0x0102040810200001L, 0x0102040810200080L, 0x0102040810200081L, + 0x0102040810204000L, 0x0102040810204001L, 0x0102040810204080L, 0x0102040810204081L + }; + + // For toString(); must have length 64 + private const string ZEROES = "0000000000000000000000000000000000000000000000000000000000000000"; + + internal static readonly byte[] BitLengths = + { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 + }; + + // TODO make m fixed for the LongArray, and hence compute T once and for all + + private long[] m_ints; + + public LongArray(int intLen) + { + m_ints = new long[intLen]; + } + + public LongArray(long[] ints) + { + m_ints = ints; + } + + public LongArray(long[] ints, int off, int len) + { + if (off == 0 && len == ints.Length) + { + m_ints = ints; + } + else + { + m_ints = new long[len]; + Array.Copy(ints, off, m_ints, 0, len); + } + } + + public LongArray(BigInteger bigInt) + { + if (bigInt == null || bigInt.SignValue < 0) + { + throw new ArgumentException("invalid F2m field value", "bigInt"); + } + + if (bigInt.SignValue == 0) + { + m_ints = new long[] { 0L }; + return; + } + + byte[] barr = bigInt.ToByteArray(); + int barrLen = barr.Length; + int barrStart = 0; + if (barr[0] == 0) + { + // First byte is 0 to enforce highest (=sign) bit is zero. + // In this case ignore barr[0]. + barrLen--; + barrStart = 1; + } + int intLen = (barrLen + 7) / 8; + m_ints = new long[intLen]; + + int iarrJ = intLen - 1; + int rem = barrLen % 8 + barrStart; + long temp = 0; + int barrI = barrStart; + if (barrStart < rem) + { + for (; barrI < rem; barrI++) + { + temp <<= 8; + uint barrBarrI = barr[barrI]; + temp |= barrBarrI; + } + m_ints[iarrJ--] = temp; + } + + for (; iarrJ >= 0; iarrJ--) + { + temp = 0; + for (int i = 0; i < 8; i++) + { + temp <<= 8; + uint barrBarrI = barr[barrI++]; + temp |= barrBarrI; + } + m_ints[iarrJ] = temp; + } + } + + internal void CopyTo(long[] z, int zOff) + { + Array.Copy(m_ints, 0, z, zOff, m_ints.Length); + } + + public bool IsOne() + { + long[] a = m_ints; + if (a[0] != 1L) + { + return false; + } + for (int i = 1; i < a.Length; ++i) + { + if (a[i] != 0L) + { + return false; + } + } + return true; + } + + public bool IsZero() + { + long[] a = m_ints; + for (int i = 0; i < a.Length; ++i) + { + if (a[i] != 0L) + { + return false; + } + } + return true; + } + + public int GetUsedLength() + { + return GetUsedLengthFrom(m_ints.Length); + } + + public int GetUsedLengthFrom(int from) + { + long[] a = m_ints; + from = System.Math.Min(from, a.Length); + + if (from < 1) + { + return 0; + } + + // Check if first element will act as sentinel + if (a[0] != 0) + { + while (a[--from] == 0) + { + } + return from + 1; + } + + do + { + if (a[--from] != 0) + { + return from + 1; + } + } + while (from > 0); + + return 0; + } + + public int Degree() + { + int i = m_ints.Length; + long w; + do + { + if (i == 0) + { + return 0; + } + w = m_ints[--i]; + } + while (w == 0); + + return (i << 6) + BitLength(w); + } + + private int DegreeFrom(int limit) + { + int i = (int)(((uint)limit + 62) >> 6); + long w; + do + { + if (i == 0) + { + return 0; + } + w = m_ints[--i]; + } + while (w == 0); + + return (i << 6) + BitLength(w); + } + + // private int lowestCoefficient() + // { + // for (int i = 0; i < m_ints.Length; ++i) + // { + // long mi = m_ints[i]; + // if (mi != 0) + // { + // int j = 0; + // while ((mi & 0xFFL) == 0) + // { + // j += 8; + // mi >>>= 8; + // } + // while ((mi & 1L) == 0) + // { + // ++j; + // mi >>>= 1; + // } + // return (i << 6) + j; + // } + // } + // return -1; + // } + + private static int BitLength(long w) + { + int u = (int)((ulong)w >> 32), b; + if (u == 0) + { + u = (int)w; + b = 0; + } + else + { + b = 32; + } + + int t = (int)((uint)u >> 16), k; + if (t == 0) + { + t = (int)((uint)u >> 8); + k = (t == 0) ? BitLengths[u] : 8 + BitLengths[t]; + } + else + { + int v = (int)((uint)t >> 8); + k = (v == 0) ? 16 + BitLengths[t] : 24 + BitLengths[v]; + } + + return b + k; + } + + private long[] ResizedInts(int newLen) + { + long[] newInts = new long[newLen]; + Array.Copy(m_ints, 0, newInts, 0, System.Math.Min(m_ints.Length, newLen)); + return newInts; + } + + public BigInteger ToBigInteger() + { + int usedLen = GetUsedLength(); + if (usedLen == 0) + { + return BigInteger.Zero; + } + + long highestInt = m_ints[usedLen - 1]; + byte[] temp = new byte[8]; + int barrI = 0; + bool trailingZeroBytesDone = false; + for (int j = 7; j >= 0; j--) + { + byte thisByte = (byte)((ulong)highestInt >> (8 * j)); + if (trailingZeroBytesDone || (thisByte != 0)) + { + trailingZeroBytesDone = true; + temp[barrI++] = thisByte; + } + } + + int barrLen = 8 * (usedLen - 1) + barrI; + byte[] barr = new byte[barrLen]; + for (int j = 0; j < barrI; j++) + { + barr[j] = temp[j]; + } + // Highest value int is done now + + for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--) + { + long mi = m_ints[iarrJ]; + for (int j = 7; j >= 0; j--) + { + barr[barrI++] = (byte)((ulong)mi >> (8 * j)); + } + } + return new BigInteger(1, barr); + } + + // private static long shiftUp(long[] x, int xOff, int count) + // { + // long prev = 0; + // for (int i = 0; i < count; ++i) + // { + // long next = x[xOff + i]; + // x[xOff + i] = (next << 1) | prev; + // prev = next >>> 63; + // } + // return prev; + // } + + private static long ShiftUp(long[] x, int xOff, int count, int shift) + { + int shiftInv = 64 - shift; + long prev = 0; + for (int i = 0; i < count; ++i) + { + long next = x[xOff + i]; + x[xOff + i] = (next << shift) | prev; + prev = (long)((ulong)next >> shiftInv); + } + return prev; + } + + private static long ShiftUp(long[] x, int xOff, long[] z, int zOff, int count, int shift) + { + int shiftInv = 64 - shift; + long prev = 0; + for (int i = 0; i < count; ++i) + { + long next = x[xOff + i]; + z[zOff + i] = (next << shift) | prev; + prev = (long)((ulong)next >> shiftInv); + } + return prev; + } + + public LongArray AddOne() + { + if (m_ints.Length == 0) + { + return new LongArray(new long[]{ 1L }); + } + + int resultLen = System.Math.Max(1, GetUsedLength()); + long[] ints = ResizedInts(resultLen); + ints[0] ^= 1L; + return new LongArray(ints); + } + + // private void addShiftedByBits(LongArray other, int bits) + // { + // int words = bits >>> 6; + // int shift = bits & 0x3F; + // + // if (shift == 0) + // { + // addShiftedByWords(other, words); + // return; + // } + // + // int otherUsedLen = other.GetUsedLength(); + // if (otherUsedLen == 0) + // { + // return; + // } + // + // int minLen = otherUsedLen + words + 1; + // if (minLen > m_ints.Length) + // { + // m_ints = resizedInts(minLen); + // } + // + // long carry = addShiftedByBits(m_ints, words, other.m_ints, 0, otherUsedLen, shift); + // m_ints[otherUsedLen + words] ^= carry; + // } + + private void AddShiftedByBitsSafe(LongArray other, int otherDegree, int bits) + { + int otherLen = (int)((uint)(otherDegree + 63) >> 6); + + int words = (int)((uint)bits >> 6); + int shift = bits & 0x3F; + + if (shift == 0) + { + Add(m_ints, words, other.m_ints, 0, otherLen); + return; + } + + long carry = AddShiftedUp(m_ints, words, other.m_ints, 0, otherLen, shift); + if (carry != 0L) + { + m_ints[otherLen + words] ^= carry; + } + } + + private static long AddShiftedUp(long[] x, int xOff, long[] y, int yOff, int count, int shift) + { + int shiftInv = 64 - shift; + long prev = 0; + for (int i = 0; i < count; ++i) + { + long next = y[yOff + i]; + x[xOff + i] ^= (next << shift) | prev; + prev = (long)((ulong)next >> shiftInv); + } + return prev; + } + + private static long AddShiftedDown(long[] x, int xOff, long[] y, int yOff, int count, int shift) + { + int shiftInv = 64 - shift; + long prev = 0; + int i = count; + while (--i >= 0) + { + long next = y[yOff + i]; + x[xOff + i] ^= (long)((ulong)next >> shift) | prev; + prev = next << shiftInv; + } + return prev; + } + + public void AddShiftedByWords(LongArray other, int words) + { + int otherUsedLen = other.GetUsedLength(); + if (otherUsedLen == 0) + { + return; + } + + int minLen = otherUsedLen + words; + if (minLen > m_ints.Length) + { + m_ints = ResizedInts(minLen); + } + + Add(m_ints, words, other.m_ints, 0, otherUsedLen); + } + + private static void Add(long[] x, int xOff, long[] y, int yOff, int count) + { + for (int i = 0; i < count; ++i) + { + x[xOff + i] ^= y[yOff + i]; + } + } + + private static void Add(long[] x, int xOff, long[] y, int yOff, long[] z, int zOff, int count) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = x[xOff + i] ^ y[yOff + i]; + } + } + + private static void AddBoth(long[] x, int xOff, long[] y1, int y1Off, long[] y2, int y2Off, int count) + { + for (int i = 0; i < count; ++i) + { + x[xOff + i] ^= y1[y1Off + i] ^ y2[y2Off + i]; + } + } + + private static void Distribute(long[] x, int src, int dst1, int dst2, int count) + { + for (int i = 0; i < count; ++i) + { + long v = x[src + i]; + x[dst1 + i] ^= v; + x[dst2 + i] ^= v; + } + } + + public int Length + { + get { return m_ints.Length; } + } + + private static void FlipWord(long[] buf, int off, int bit, long word) + { + int n = off + (int)((uint)bit >> 6); + int shift = bit & 0x3F; + if (shift == 0) + { + buf[n] ^= word; + } + else + { + buf[n] ^= word << shift; + word = (long)((ulong)word >> (64 - shift)); + if (word != 0) + { + buf[++n] ^= word; + } + } + } + + // private static long getWord(long[] buf, int off, int len, int bit) + // { + // int n = off + (bit >>> 6); + // int shift = bit & 0x3F; + // if (shift == 0) + // { + // return buf[n]; + // } + // long result = buf[n] >>> shift; + // if (++n < len) + // { + // result |= buf[n] << (64 - shift); + // } + // return result; + // } + + public bool TestBitZero() + { + return m_ints.Length > 0 && (m_ints[0] & 1L) != 0; + } + + private static bool TestBit(long[] buf, int off, int n) + { + // theInt = n / 64 + int theInt = (int)((uint)n >> 6); + // theBit = n % 64 + int theBit = n & 0x3F; + long tester = 1L << theBit; + return (buf[off + theInt] & tester) != 0; + } + + private static void FlipBit(long[] buf, int off, int n) + { + // theInt = n / 64 + int theInt = (int)((uint)n >> 6); + // theBit = n % 64 + int theBit = n & 0x3F; + long flipper = 1L << theBit; + buf[off + theInt] ^= flipper; + } + + // private static void SetBit(long[] buf, int off, int n) + // { + // // theInt = n / 64 + // int theInt = n >>> 6; + // // theBit = n % 64 + // int theBit = n & 0x3F; + // long setter = 1L << theBit; + // buf[off + theInt] |= setter; + // } + // + // private static void ClearBit(long[] buf, int off, int n) + // { + // // theInt = n / 64 + // int theInt = n >>> 6; + // // theBit = n % 64 + // int theBit = n & 0x3F; + // long setter = 1L << theBit; + // buf[off + theInt] &= ~setter; + // } + + private static void MultiplyWord(long a, long[] b, int bLen, long[] c, int cOff) + { + if ((a & 1L) != 0L) + { + Add(c, cOff, b, 0, bLen); + } + int k = 1; + while ((a = (long)((ulong)a >> 1)) != 0L) + { + if ((a & 1L) != 0L) + { + long carry = AddShiftedUp(c, cOff, b, 0, bLen, k); + if (carry != 0L) + { + c[cOff + bLen] ^= carry; + } + } + ++k; + } + } + + public LongArray ModMultiplyLD(LongArray other, int m, int[] ks) + { + /* + * Find out the degree of each argument and handle the zero cases + */ + int aDeg = Degree(); + if (aDeg == 0) + { + return this; + } + int bDeg = other.Degree(); + if (bDeg == 0) + { + return other; + } + + /* + * Swap if necessary so that A is the smaller argument + */ + LongArray A = this, B = other; + if (aDeg > bDeg) + { + A = other; B = this; + int tmp = aDeg; aDeg = bDeg; bDeg = tmp; + } + + /* + * Establish the word lengths of the arguments and result + */ + int aLen = (int)((uint)(aDeg + 63) >> 6); + int bLen = (int)((uint)(bDeg + 63) >> 6); + int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); + + if (aLen == 1) + { + long a0 = A.m_ints[0]; + if (a0 == 1L) + { + return B; + } + + /* + * Fast path for small A, with performance dependent only on the number of set bits + */ + long[] c0 = new long[cLen]; + MultiplyWord(a0, B.m_ints, bLen, c0, 0); + + /* + * Reduce the raw answer against the reduction coefficients + */ + return ReduceResult(c0, 0, cLen, m, ks); + } + + /* + * Determine if B will get bigger during shifting + */ + int bMax = (int)((uint)(bDeg + 7 + 63) >> 6); + + /* + * Lookup table for the offset of each B in the tables + */ + int[] ti = new int[16]; + + /* + * Precompute table of all 4-bit products of B + */ + long[] T0 = new long[bMax << 4]; + int tOff = bMax; + ti[1] = tOff; + Array.Copy(B.m_ints, 0, T0, tOff, bLen); + for (int i = 2; i < 16; ++i) + { + ti[i] = (tOff += bMax); + if ((i & 1) == 0) + { + ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1); + } + else + { + Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); + } + } + + /* + * Second table with all 4-bit products of B shifted 4 bits + */ + long[] T1 = new long[T0.Length]; + ShiftUp(T0, 0, T1, 0, T0.Length, 4); + // shiftUp(T0, bMax, T1, bMax, tOff, 4); + + long[] a = A.m_ints; + long[] c = new long[cLen]; + + int MASK = 0xF; + + /* + * Lopez-Dahab algorithm + */ + + for (int k = 56; k >= 0; k -= 8) + { + for (int j = 1; j < aLen; j += 2) + { + int aVal = (int)((ulong)a[j] >> k); + int u = aVal & MASK; + int v = (int)((uint)aVal >> 4) & MASK; + AddBoth(c, j - 1, T0, ti[u], T1, ti[v], bMax); + } + ShiftUp(c, 0, cLen, 8); + } + + for (int k = 56; k >= 0; k -= 8) + { + for (int j = 0; j < aLen; j += 2) + { + int aVal = (int)((ulong)a[j] >> k); + int u = aVal & MASK; + int v = (int)((uint)aVal >> 4) & MASK; + AddBoth(c, j, T0, ti[u], T1, ti[v], bMax); + } + if (k > 0) + { + ShiftUp(c, 0, cLen, 8); + } + } + + /* + * Finally the raw answer is collected, reduce it against the reduction coefficients + */ + return ReduceResult(c, 0, cLen, m, ks); + } + + public LongArray ModMultiply(LongArray other, int m, int[] ks) + { + /* + * Find out the degree of each argument and handle the zero cases + */ + int aDeg = Degree(); + if (aDeg == 0) + { + return this; + } + int bDeg = other.Degree(); + if (bDeg == 0) + { + return other; + } + + /* + * Swap if necessary so that A is the smaller argument + */ + LongArray A = this, B = other; + if (aDeg > bDeg) + { + A = other; B = this; + int tmp = aDeg; aDeg = bDeg; bDeg = tmp; + } + + /* + * Establish the word lengths of the arguments and result + */ + int aLen = (int)((uint)(aDeg + 63) >> 6); + int bLen = (int)((uint)(bDeg + 63) >> 6); + int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); + + if (aLen == 1) + { + long a0 = A.m_ints[0]; + if (a0 == 1L) + { + return B; + } + + /* + * Fast path for small A, with performance dependent only on the number of set bits + */ + long[] c0 = new long[cLen]; + MultiplyWord(a0, B.m_ints, bLen, c0, 0); + + /* + * Reduce the raw answer against the reduction coefficients + */ + return ReduceResult(c0, 0, cLen, m, ks); + } + + /* + * Determine if B will get bigger during shifting + */ + int bMax = (int)((uint)(bDeg + 7 + 63) >> 6); + + /* + * Lookup table for the offset of each B in the tables + */ + int[] ti = new int[16]; + + /* + * Precompute table of all 4-bit products of B + */ + long[] T0 = new long[bMax << 4]; + int tOff = bMax; + ti[1] = tOff; + Array.Copy(B.m_ints, 0, T0, tOff, bLen); + for (int i = 2; i < 16; ++i) + { + ti[i] = (tOff += bMax); + if ((i & 1) == 0) + { + ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1); + } + else + { + Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); + } + } + + /* + * Second table with all 4-bit products of B shifted 4 bits + */ + long[] T1 = new long[T0.Length]; + ShiftUp(T0, 0, T1, 0, T0.Length, 4); + // ShiftUp(T0, bMax, T1, bMax, tOff, 4); + + long[] a = A.m_ints; + long[] c = new long[cLen << 3]; + + int MASK = 0xF; + + /* + * Lopez-Dahab (Modified) algorithm + */ + + for (int aPos = 0; aPos < aLen; ++aPos) + { + long aVal = a[aPos]; + int cOff = aPos; + for (;;) + { + int u = (int)aVal & MASK; + aVal = (long)((ulong)aVal >> 4); + int v = (int)aVal & MASK; + AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); + aVal = (long)((ulong)aVal >> 4); + if (aVal == 0L) + { + break; + } + cOff += cLen; + } + } + + { + int cOff = c.Length; + while ((cOff -= cLen) != 0) + { + AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); + } + } + + /* + * Finally the raw answer is collected, reduce it against the reduction coefficients + */ + return ReduceResult(c, 0, cLen, m, ks); + } + + public LongArray ModMultiplyAlt(LongArray other, int m, int[] ks) + { + /* + * Find out the degree of each argument and handle the zero cases + */ + int aDeg = Degree(); + if (aDeg == 0) + { + return this; + } + int bDeg = other.Degree(); + if (bDeg == 0) + { + return other; + } + + /* + * Swap if necessary so that A is the smaller argument + */ + LongArray A = this, B = other; + if (aDeg > bDeg) + { + A = other; B = this; + int tmp = aDeg; aDeg = bDeg; bDeg = tmp; + } + + /* + * Establish the word lengths of the arguments and result + */ + int aLen = (int)((uint)(aDeg + 63) >> 6); + int bLen = (int)((uint)(bDeg + 63) >> 6); + int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); + + if (aLen == 1) + { + long a0 = A.m_ints[0]; + if (a0 == 1L) + { + return B; + } + + /* + * Fast path for small A, with performance dependent only on the number of set bits + */ + long[] c0 = new long[cLen]; + MultiplyWord(a0, B.m_ints, bLen, c0, 0); + + /* + * Reduce the raw answer against the reduction coefficients + */ + return ReduceResult(c0, 0, cLen, m, ks); + } + + // NOTE: This works, but is slower than width 4 processing + // if (aLen == 2) + // { + // /* + // * Use common-multiplicand optimization to save ~1/4 of the adds + // */ + // long a1 = A.m_ints[0], a2 = A.m_ints[1]; + // long aa = a1 & a2; a1 ^= aa; a2 ^= aa; + // + // long[] b = B.m_ints; + // long[] c = new long[cLen]; + // multiplyWord(aa, b, bLen, c, 1); + // add(c, 0, c, 1, cLen - 1); + // multiplyWord(a1, b, bLen, c, 0); + // multiplyWord(a2, b, bLen, c, 1); + // + // /* + // * Reduce the raw answer against the reduction coefficients + // */ + // return ReduceResult(c, 0, cLen, m, ks); + // } + + /* + * Determine the parameters of the Interleaved window algorithm: the 'width' in bits to + * process together, the number of evaluation 'positions' implied by that width, and the + * 'top' position at which the regular window algorithm stops. + */ + int width, positions, top, banks; + + // NOTE: width 4 is the fastest over the entire range of sizes used in current crypto + // width = 1; positions = 64; top = 64; banks = 4; + // width = 2; positions = 32; top = 64; banks = 4; + // width = 3; positions = 21; top = 63; banks = 3; + width = 4; positions = 16; top = 64; banks = 8; + // width = 5; positions = 13; top = 65; banks = 7; + // width = 7; positions = 9; top = 63; banks = 9; + // width = 8; positions = 8; top = 64; banks = 8; + + /* + * Determine if B will get bigger during shifting + */ + int shifts = top < 64 ? positions : positions - 1; + int bMax = (int)((uint)(bDeg + shifts + 63) >> 6); + + int bTotal = bMax * banks, stride = width * banks; + + /* + * Create a single temporary buffer, with an offset table to find the positions of things in it + */ + int[] ci = new int[1 << width]; + int cTotal = aLen; + { + ci[0] = cTotal; + cTotal += bTotal; + ci[1] = cTotal; + for (int i = 2; i < ci.Length; ++i) + { + cTotal += cLen; + ci[i] = cTotal; + } + cTotal += cLen; + } + // NOTE: Provide a safe dump for "high zeroes" since we are adding 'bMax' and not 'bLen' + ++cTotal; + + long[] c = new long[cTotal]; + + // Prepare A in Interleaved form, according to the chosen width + Interleave(A.m_ints, 0, c, 0, aLen, width); + + // Make a working copy of B, since we will be shifting it + { + int bOff = aLen; + Array.Copy(B.m_ints, 0, c, bOff, bLen); + for (int bank = 1; bank < banks; ++bank) + { + ShiftUp(c, aLen, c, bOff += bMax, bMax, bank); + } + } + + /* + * The main loop analyzes the Interleaved windows in A, and for each non-zero window + * a single word-array XOR is performed to a carefully selected slice of 'c'. The loop is + * breadth-first, checking the lowest window in each word, then looping again for the + * next higher window position. + */ + int MASK = (1 << width) - 1; + + int k = 0; + for (;;) + { + int aPos = 0; + do + { + long aVal = (long)((ulong)c[aPos] >> k); + int bank = 0, bOff = aLen; + for (;;) + { + int index = (int)(aVal) & MASK; + if (index != 0) + { + /* + * Add to a 'c' buffer based on the bit-pattern of 'index'. Since A is in + * Interleaved form, the bits represent the current B shifted by 0, 'positions', + * 'positions' * 2, ..., 'positions' * ('width' - 1) + */ + Add(c, aPos + ci[index], c, bOff, bMax); + } + if (++bank == banks) + { + break; + } + bOff += bMax; + aVal = (long)((ulong)aVal >> width); + } + } + while (++aPos < aLen); + + if ((k += stride) >= top) + { + if (k >= 64) + { + break; + } + + /* + * Adjustment for window setups with top == 63, the final bit (if any) is processed + * as the top-bit of a window + */ + k = 64 - width; + MASK &= MASK << (top - k); + } + + /* + * After each position has been checked for all words of A, B is shifted up 1 place + */ + ShiftUp(c, aLen, bTotal, banks); + } + + int ciPos = ci.Length; + while (--ciPos > 1) + { + if ((ciPos & 1L) == 0L) + { + /* + * For even numbers, shift contents and add to the half-position + */ + AddShiftedUp(c, ci[(uint)ciPos >> 1], c, ci[ciPos], cLen, positions); + } + else + { + /* + * For odd numbers, 'distribute' contents to the result and the next-lowest position + */ + Distribute(c, ci[ciPos], ci[ciPos - 1], ci[1], cLen); + } + } + + /* + * Finally the raw answer is collected, reduce it against the reduction coefficients + */ + return ReduceResult(c, ci[1], cLen, m, ks); + } + + public LongArray ModReduce(int m, int[] ks) + { + long[] buf = Arrays.Clone(m_ints); + int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks); + return new LongArray(buf, 0, rLen); + } + + public LongArray Multiply(LongArray other, int m, int[] ks) + { + /* + * Find out the degree of each argument and handle the zero cases + */ + int aDeg = Degree(); + if (aDeg == 0) + { + return this; + } + int bDeg = other.Degree(); + if (bDeg == 0) + { + return other; + } + + /* + * Swap if necessary so that A is the smaller argument + */ + LongArray A = this, B = other; + if (aDeg > bDeg) + { + A = other; B = this; + int tmp = aDeg; aDeg = bDeg; bDeg = tmp; + } + + /* + * Establish the word lengths of the arguments and result + */ + int aLen = (int)((uint)(aDeg + 63) >> 6); + int bLen = (int)((uint)(bDeg + 63) >> 6); + int cLen = (int)((uint)(aDeg + bDeg + 62) >> 6); + + if (aLen == 1) + { + long a0 = A.m_ints[0]; + if (a0 == 1L) + { + return B; + } + + /* + * Fast path for small A, with performance dependent only on the number of set bits + */ + long[] c0 = new long[cLen]; + MultiplyWord(a0, B.m_ints, bLen, c0, 0); + + /* + * Reduce the raw answer against the reduction coefficients + */ + //return ReduceResult(c0, 0, cLen, m, ks); + return new LongArray(c0, 0, cLen); + } + + /* + * Determine if B will get bigger during shifting + */ + int bMax = (int)((uint)(bDeg + 7 + 63) >> 6); + + /* + * Lookup table for the offset of each B in the tables + */ + int[] ti = new int[16]; + + /* + * Precompute table of all 4-bit products of B + */ + long[] T0 = new long[bMax << 4]; + int tOff = bMax; + ti[1] = tOff; + Array.Copy(B.m_ints, 0, T0, tOff, bLen); + for (int i = 2; i < 16; ++i) + { + ti[i] = (tOff += bMax); + if ((i & 1) == 0) + { + ShiftUp(T0, (int)((uint)tOff >> 1), T0, tOff, bMax, 1); + } + else + { + Add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); + } + } + + /* + * Second table with all 4-bit products of B shifted 4 bits + */ + long[] T1 = new long[T0.Length]; + ShiftUp(T0, 0, T1, 0, T0.Length, 4); + // ShiftUp(T0, bMax, T1, bMax, tOff, 4); + + long[] a = A.m_ints; + long[] c = new long[cLen << 3]; + + int MASK = 0xF; + + /* + * Lopez-Dahab (Modified) algorithm + */ + + for (int aPos = 0; aPos < aLen; ++aPos) + { + long aVal = a[aPos]; + int cOff = aPos; + for (; ; ) + { + int u = (int)aVal & MASK; + aVal = (long)((ulong)aVal >> 4); + int v = (int)aVal & MASK; + AddBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); + aVal = (long)((ulong)aVal >> 4); + if (aVal == 0L) + { + break; + } + cOff += cLen; + } + } + + { + int cOff = c.Length; + while ((cOff -= cLen) != 0) + { + AddShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); + } + } + + /* + * Finally the raw answer is collected, reduce it against the reduction coefficients + */ + //return ReduceResult(c, 0, cLen, m, ks); + return new LongArray(c, 0, cLen); + } + + public void Reduce(int m, int[] ks) + { + long[] buf = m_ints; + int rLen = ReduceInPlace(buf, 0, buf.Length, m, ks); + if (rLen < buf.Length) + { + m_ints = new long[rLen]; + Array.Copy(buf, 0, m_ints, 0, rLen); + } + } + + private static LongArray ReduceResult(long[] buf, int off, int len, int m, int[] ks) + { + int rLen = ReduceInPlace(buf, off, len, m, ks); + return new LongArray(buf, off, rLen); + } + + // private static void deInterleave(long[] x, int xOff, long[] z, int zOff, int count, int rounds) + // { + // for (int i = 0; i < count; ++i) + // { + // z[zOff + i] = deInterleave(x[zOff + i], rounds); + // } + // } + // + // private static long deInterleave(long x, int rounds) + // { + // while (--rounds >= 0) + // { + // x = deInterleave32(x & DEInterleave_MASK) | (deInterleave32((x >>> 1) & DEInterleave_MASK) << 32); + // } + // return x; + // } + // + // private static long deInterleave32(long x) + // { + // x = (x | (x >>> 1)) & 0x3333333333333333L; + // x = (x | (x >>> 2)) & 0x0F0F0F0F0F0F0F0FL; + // x = (x | (x >>> 4)) & 0x00FF00FF00FF00FFL; + // x = (x | (x >>> 8)) & 0x0000FFFF0000FFFFL; + // x = (x | (x >>> 16)) & 0x00000000FFFFFFFFL; + // return x; + // } + + private static int ReduceInPlace(long[] buf, int off, int len, int m, int[] ks) + { + int mLen = (m + 63) >> 6; + if (len < mLen) + { + return len; + } + + int numBits = System.Math.Min(len << 6, (m << 1) - 1); // TODO use actual degree? + int excessBits = (len << 6) - numBits; + while (excessBits >= 64) + { + --len; + excessBits -= 64; + } + + int kLen = ks.Length, kMax = ks[kLen - 1], kNext = kLen > 1 ? ks[kLen - 2] : 0; + int wordWiseLimit = System.Math.Max(m, kMax + 64); + int vectorableWords = (excessBits + System.Math.Min(numBits - wordWiseLimit, m - kNext)) >> 6; + if (vectorableWords > 1) + { + int vectorWiseWords = len - vectorableWords; + ReduceVectorWise(buf, off, len, vectorWiseWords, m, ks); + while (len > vectorWiseWords) + { + buf[off + --len] = 0L; + } + numBits = vectorWiseWords << 6; + } + + if (numBits > wordWiseLimit) + { + ReduceWordWise(buf, off, len, wordWiseLimit, m, ks); + numBits = wordWiseLimit; + } + + if (numBits > m) + { + ReduceBitWise(buf, off, numBits, m, ks); + } + + return mLen; + } + + private static void ReduceBitWise(long[] buf, int off, int BitLength, int m, int[] ks) + { + while (--BitLength >= m) + { + if (TestBit(buf, off, BitLength)) + { + ReduceBit(buf, off, BitLength, m, ks); + } + } + } + + private static void ReduceBit(long[] buf, int off, int bit, int m, int[] ks) + { + FlipBit(buf, off, bit); + int n = bit - m; + int j = ks.Length; + while (--j >= 0) + { + FlipBit(buf, off, ks[j] + n); + } + FlipBit(buf, off, n); + } + + private static void ReduceWordWise(long[] buf, int off, int len, int toBit, int m, int[] ks) + { + int toPos = (int)((uint)toBit >> 6); + + while (--len > toPos) + { + long word = buf[off + len]; + if (word != 0) + { + buf[off + len] = 0; + ReduceWord(buf, off, (len << 6), word, m, ks); + } + } + + { + int partial = toBit & 0x3F; + long word = (long)((ulong)buf[off + toPos] >> partial); + if (word != 0) + { + buf[off + toPos] ^= word << partial; + ReduceWord(buf, off, toBit, word, m, ks); + } + } + } + + private static void ReduceWord(long[] buf, int off, int bit, long word, int m, int[] ks) + { + int offset = bit - m; + int j = ks.Length; + while (--j >= 0) + { + FlipWord(buf, off, offset + ks[j], word); + } + FlipWord(buf, off, offset, word); + } + + private static void ReduceVectorWise(long[] buf, int off, int len, int words, int m, int[] ks) + { + /* + * NOTE: It's important we go from highest coefficient to lowest, because for the highest + * one (only) we allow the ranges to partially overlap, and therefore any changes must take + * effect for the subsequent lower coefficients. + */ + int baseBit = (words << 6) - m; + int j = ks.Length; + while (--j >= 0) + { + FlipVector(buf, off, buf, off + words, len - words, baseBit + ks[j]); + } + FlipVector(buf, off, buf, off + words, len - words, baseBit); + } + + private static void FlipVector(long[] x, int xOff, long[] y, int yOff, int yLen, int bits) + { + xOff += (int)((uint)bits >> 6); + bits &= 0x3F; + + if (bits == 0) + { + Add(x, xOff, y, yOff, yLen); + } + else + { + long carry = AddShiftedDown(x, xOff + 1, y, yOff, yLen, 64 - bits); + x[xOff] ^= carry; + } + } + + public LongArray ModSquare(int m, int[] ks) + { + int len = GetUsedLength(); + if (len == 0) + { + return this; + } + + int _2len = len << 1; + long[] r = new long[_2len]; + + int pos = 0; + while (pos < _2len) + { + long mi = m_ints[(uint)pos >> 1]; + r[pos++] = Interleave2_32to64((int)mi); + r[pos++] = Interleave2_32to64((int)((ulong)mi >> 32)); + } + + return new LongArray(r, 0, ReduceInPlace(r, 0, r.Length, m, ks)); + } + + public LongArray ModSquareN(int n, int m, int[] ks) + { + int len = GetUsedLength(); + if (len == 0) + { + return this; + } + + int mLen = (m + 63) >> 6; + long[] r = new long[mLen << 1]; + Array.Copy(m_ints, 0, r, 0, len); + + while (--n >= 0) + { + SquareInPlace(r, len, m, ks); + len = ReduceInPlace(r, 0, r.Length, m, ks); + } + + return new LongArray(r, 0, len); + } + + public LongArray Square(int m, int[] ks) + { + int len = GetUsedLength(); + if (len == 0) + { + return this; + } + + int _2len = len << 1; + long[] r = new long[_2len]; + + int pos = 0; + while (pos < _2len) + { + long mi = m_ints[(uint)pos >> 1]; + r[pos++] = Interleave2_32to64((int)mi); + r[pos++] = Interleave2_32to64((int)((ulong)mi >> 32)); + } + + return new LongArray(r, 0, r.Length); + } + + private static void SquareInPlace(long[] x, int xLen, int m, int[] ks) + { + int pos = xLen << 1; + while (--xLen >= 0) + { + long xVal = x[xLen]; + x[--pos] = Interleave2_32to64((int)((ulong)xVal >> 32)); + x[--pos] = Interleave2_32to64((int)xVal); + } + } + + private static void Interleave(long[] x, int xOff, long[] z, int zOff, int count, int width) + { + switch (width) + { + case 3: + Interleave3(x, xOff, z, zOff, count); + break; + case 5: + Interleave5(x, xOff, z, zOff, count); + break; + case 7: + Interleave7(x, xOff, z, zOff, count); + break; + default: + Interleave2_n(x, xOff, z, zOff, count, BitLengths[width] - 1); + break; + } + } + + private static void Interleave3(long[] x, int xOff, long[] z, int zOff, int count) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = Interleave3(x[xOff + i]); + } + } + + private static long Interleave3(long x) + { + long z = x & (1L << 63); + return z + | Interleave3_21to63((int)x & 0x1FFFFF) + | Interleave3_21to63((int)((ulong)x >> 21) & 0x1FFFFF) << 1 + | Interleave3_21to63((int)((ulong)x >> 42) & 0x1FFFFF) << 2; + + // int zPos = 0, wPos = 0, xPos = 0; + // for (;;) + // { + // z |= ((x >>> xPos) & 1L) << zPos; + // if (++zPos == 63) + // { + // String sz2 = Long.toBinaryString(z); + // return z; + // } + // if ((xPos += 21) >= 63) + // { + // xPos = ++wPos; + // } + // } + } + + private static long Interleave3_21to63(int x) + { + int r00 = INTERLEAVE3_TABLE[x & 0x7F]; + int r21 = INTERLEAVE3_TABLE[((uint)x >> 7) & 0x7F]; + int r42 = INTERLEAVE3_TABLE[(uint)x >> 14]; + return (r42 & 0xFFFFFFFFL) << 42 | (r21 & 0xFFFFFFFFL) << 21 | (r00 & 0xFFFFFFFFL); + } + + private static void Interleave5(long[] x, int xOff, long[] z, int zOff, int count) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = Interleave5(x[xOff + i]); + } + } + + private static long Interleave5(long x) + { + return Interleave3_13to65((int)x & 0x1FFF) + | Interleave3_13to65((int)((ulong)x >> 13) & 0x1FFF) << 1 + | Interleave3_13to65((int)((ulong)x >> 26) & 0x1FFF) << 2 + | Interleave3_13to65((int)((ulong)x >> 39) & 0x1FFF) << 3 + | Interleave3_13to65((int)((ulong)x >> 52) & 0x1FFF) << 4; + + // long z = 0; + // int zPos = 0, wPos = 0, xPos = 0; + // for (;;) + // { + // z |= ((x >>> xPos) & 1L) << zPos; + // if (++zPos == 64) + // { + // return z; + // } + // if ((xPos += 13) >= 64) + // { + // xPos = ++wPos; + // } + // } + } + + private static long Interleave3_13to65(int x) + { + int r00 = INTERLEAVE5_TABLE[x & 0x7F]; + int r35 = INTERLEAVE5_TABLE[(uint)x >> 7]; + return (r35 & 0xFFFFFFFFL) << 35 | (r00 & 0xFFFFFFFFL); + } + + private static void Interleave7(long[] x, int xOff, long[] z, int zOff, int count) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = Interleave7(x[xOff + i]); + } + } + + private static long Interleave7(long x) + { + long z = x & (1L << 63); + return z + | INTERLEAVE7_TABLE[(int)x & 0x1FF] + | INTERLEAVE7_TABLE[(int)((ulong)x >> 9) & 0x1FF] << 1 + | INTERLEAVE7_TABLE[(int)((ulong)x >> 18) & 0x1FF] << 2 + | INTERLEAVE7_TABLE[(int)((ulong)x >> 27) & 0x1FF] << 3 + | INTERLEAVE7_TABLE[(int)((ulong)x >> 36) & 0x1FF] << 4 + | INTERLEAVE7_TABLE[(int)((ulong)x >> 45) & 0x1FF] << 5 + | INTERLEAVE7_TABLE[(int)((ulong)x >> 54) & 0x1FF] << 6; + + // int zPos = 0, wPos = 0, xPos = 0; + // for (;;) + // { + // z |= ((x >>> xPos) & 1L) << zPos; + // if (++zPos == 63) + // { + // return z; + // } + // if ((xPos += 9) >= 63) + // { + // xPos = ++wPos; + // } + // } + } + + private static void Interleave2_n(long[] x, int xOff, long[] z, int zOff, int count, int rounds) + { + for (int i = 0; i < count; ++i) + { + z[zOff + i] = Interleave2_n(x[xOff + i], rounds); + } + } + + private static long Interleave2_n(long x, int rounds) + { + while (rounds > 1) + { + rounds -= 2; + x = Interleave4_16to64((int)x & 0xFFFF) + | Interleave4_16to64((int)((ulong)x >> 16) & 0xFFFF) << 1 + | Interleave4_16to64((int)((ulong)x >> 32) & 0xFFFF) << 2 + | Interleave4_16to64((int)((ulong)x >> 48) & 0xFFFF) << 3; + } + if (rounds > 0) + { + x = Interleave2_32to64((int)x) | Interleave2_32to64((int)((ulong)x >> 32)) << 1; + } + return x; + } + + private static long Interleave4_16to64(int x) + { + int r00 = INTERLEAVE4_TABLE[x & 0xFF]; + int r32 = INTERLEAVE4_TABLE[(uint)x >> 8]; + return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL); + } + + private static long Interleave2_32to64(int x) + { + int r00 = INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[((uint)x >> 8) & 0xFF] << 16; + int r32 = INTERLEAVE2_TABLE[((uint)x >> 16) & 0xFF] | INTERLEAVE2_TABLE[(uint)x >> 24] << 16; + return (r32 & 0xFFFFFFFFL) << 32 | (r00 & 0xFFFFFFFFL); + } + + // private static LongArray ExpItohTsujii2(LongArray B, int n, int m, int[] ks) + // { + // LongArray t1 = B, t3 = new LongArray(new long[]{ 1L }); + // int scale = 1; + // + // int numTerms = n; + // while (numTerms > 1) + // { + // if ((numTerms & 1) != 0) + // { + // t3 = t3.ModMultiply(t1, m, ks); + // t1 = t1.modSquareN(scale, m, ks); + // } + // + // LongArray t2 = t1.modSquareN(scale, m, ks); + // t1 = t1.ModMultiply(t2, m, ks); + // numTerms >>>= 1; scale <<= 1; + // } + // + // return t3.ModMultiply(t1, m, ks); + // } + // + // private static LongArray ExpItohTsujii23(LongArray B, int n, int m, int[] ks) + // { + // LongArray t1 = B, t3 = new LongArray(new long[]{ 1L }); + // int scale = 1; + // + // int numTerms = n; + // while (numTerms > 1) + // { + // bool m03 = numTerms % 3 == 0; + // bool m14 = !m03 && (numTerms & 1) != 0; + // + // if (m14) + // { + // t3 = t3.ModMultiply(t1, m, ks); + // t1 = t1.modSquareN(scale, m, ks); + // } + // + // LongArray t2 = t1.modSquareN(scale, m, ks); + // t1 = t1.ModMultiply(t2, m, ks); + // + // if (m03) + // { + // t2 = t2.modSquareN(scale, m, ks); + // t1 = t1.ModMultiply(t2, m, ks); + // numTerms /= 3; scale *= 3; + // } + // else + // { + // numTerms >>>= 1; scale <<= 1; + // } + // } + // + // return t3.ModMultiply(t1, m, ks); + // } + // + // private static LongArray ExpItohTsujii235(LongArray B, int n, int m, int[] ks) + // { + // LongArray t1 = B, t4 = new LongArray(new long[]{ 1L }); + // int scale = 1; + // + // int numTerms = n; + // while (numTerms > 1) + // { + // if (numTerms % 5 == 0) + // { + //// t1 = ExpItohTsujii23(t1, 5, m, ks); + // + // LongArray t3 = t1; + // t1 = t1.modSquareN(scale, m, ks); + // + // LongArray t2 = t1.modSquareN(scale, m, ks); + // t1 = t1.ModMultiply(t2, m, ks); + // t2 = t1.modSquareN(scale << 1, m, ks); + // t1 = t1.ModMultiply(t2, m, ks); + // + // t1 = t1.ModMultiply(t3, m, ks); + // + // numTerms /= 5; scale *= 5; + // continue; + // } + // + // bool m03 = numTerms % 3 == 0; + // bool m14 = !m03 && (numTerms & 1) != 0; + // + // if (m14) + // { + // t4 = t4.ModMultiply(t1, m, ks); + // t1 = t1.modSquareN(scale, m, ks); + // } + // + // LongArray t2 = t1.modSquareN(scale, m, ks); + // t1 = t1.ModMultiply(t2, m, ks); + // + // if (m03) + // { + // t2 = t2.modSquareN(scale, m, ks); + // t1 = t1.ModMultiply(t2, m, ks); + // numTerms /= 3; scale *= 3; + // } + // else + // { + // numTerms >>>= 1; scale <<= 1; + // } + // } + // + // return t4.ModMultiply(t1, m, ks); + // } + + public LongArray ModInverse(int m, int[] ks) + { + /* + * Fermat's Little Theorem + */ + // LongArray A = this; + // LongArray B = A.modSquare(m, ks); + // LongArray R0 = B, R1 = B; + // for (int i = 2; i < m; ++i) + // { + // R1 = R1.modSquare(m, ks); + // R0 = R0.ModMultiply(R1, m, ks); + // } + // + // return R0; + + /* + * Itoh-Tsujii + */ + // LongArray B = modSquare(m, ks); + // switch (m) + // { + // case 409: + // return ExpItohTsujii23(B, m - 1, m, ks); + // case 571: + // return ExpItohTsujii235(B, m - 1, m, ks); + // case 163: + // case 233: + // case 283: + // default: + // return ExpItohTsujii2(B, m - 1, m, ks); + // } + + /* + * Inversion in F2m using the extended Euclidean algorithm + * + * Input: A nonzero polynomial a(z) of degree at most m-1 + * Output: a(z)^(-1) mod f(z) + */ + int uzDegree = Degree(); + if (uzDegree == 0) + { + throw new InvalidOperationException(); + } + if (uzDegree == 1) + { + return this; + } + + // u(z) := a(z) + LongArray uz = (LongArray)Copy(); + + int t = (m + 63) >> 6; + + // v(z) := f(z) + LongArray vz = new LongArray(t); + ReduceBit(vz.m_ints, 0, m, m, ks); + + // g1(z) := 1, g2(z) := 0 + LongArray g1z = new LongArray(t); + g1z.m_ints[0] = 1L; + LongArray g2z = new LongArray(t); + + int[] uvDeg = new int[]{ uzDegree, m + 1 }; + LongArray[] uv = new LongArray[]{ uz, vz }; + + int[] ggDeg = new int[]{ 1, 0 }; + LongArray[] gg = new LongArray[]{ g1z, g2z }; + + int b = 1; + int duv1 = uvDeg[b]; + int dgg1 = ggDeg[b]; + int j = duv1 - uvDeg[1 - b]; + + for (;;) + { + if (j < 0) + { + j = -j; + uvDeg[b] = duv1; + ggDeg[b] = dgg1; + b = 1 - b; + duv1 = uvDeg[b]; + dgg1 = ggDeg[b]; + } + + uv[b].AddShiftedByBitsSafe(uv[1 - b], uvDeg[1 - b], j); + + int duv2 = uv[b].DegreeFrom(duv1); + if (duv2 == 0) + { + return gg[1 - b]; + } + + { + int dgg2 = ggDeg[1 - b]; + gg[b].AddShiftedByBitsSafe(gg[1 - b], dgg2, j); + dgg2 += j; + + if (dgg2 > dgg1) + { + dgg1 = dgg2; + } + else if (dgg2 == dgg1) + { + dgg1 = gg[b].DegreeFrom(dgg1); + } + } + + j += (duv2 - duv1); + duv1 = duv2; + } + } + + public override bool Equals(object obj) + { + return Equals(obj as LongArray); + } + + public virtual bool Equals(LongArray other) + { + if (this == other) + return true; + if (null == other) + return false; + int usedLen = GetUsedLength(); + if (other.GetUsedLength() != usedLen) + { + return false; + } + for (int i = 0; i < usedLen; i++) + { + if (m_ints[i] != other.m_ints[i]) + { + return false; + } + } + return true; + } + + public override int GetHashCode() + { + int usedLen = GetUsedLength(); + int hash = 1; + for (int i = 0; i < usedLen; i++) + { + long mi = m_ints[i]; + hash *= 31; + hash ^= (int)mi; + hash *= 31; + hash ^= (int)((ulong)mi >> 32); + } + return hash; + } + + public LongArray Copy() + { + return new LongArray(Arrays.Clone(m_ints)); + } + + public override string ToString() + { + int i = GetUsedLength(); + if (i == 0) + { + return "0"; + } + + StringBuilder sb = new StringBuilder(Convert.ToString(m_ints[--i], 2)); + while (--i >= 0) + { + string s = Convert.ToString(m_ints[i], 2); + + // Add leading zeroes, except for highest significant word + int len = s.Length; + if (len < 64) + { + sb.Append(ZEROES.Substring(len)); + } + + sb.Append(s); + } + return sb.ToString(); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/SimpleBigDecimal.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/SimpleBigDecimal.cs new file mode 100644 index 00000000..23604d1b --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/SimpleBigDecimal.cs @@ -0,0 +1,241 @@ +using System; +using System.Text; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Abc +{ + /** + * Class representing a simple version of a big decimal. A + * SimpleBigDecimal is basically a + * {@link java.math.BigInteger BigInteger} with a few digits on the right of + * the decimal point. The number of (binary) digits on the right of the decimal + * point is called the scale of the SimpleBigDecimal. + * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted + * automatically, but must be set manually. All SimpleBigDecimals + * taking part in the same arithmetic operation must have equal scale. The + * result of a multiplication of two SimpleBigDecimals returns a + * SimpleBigDecimal with double scale. + */ + internal class SimpleBigDecimal + // : Number + { + // private static final long serialVersionUID = 1L; + + private readonly BigInteger bigInt; + private readonly int scale; + + /** + * Returns a SimpleBigDecimal representing the same numerical + * value as value. + * @param value The value of the SimpleBigDecimal to be + * created. + * @param scale The scale of the SimpleBigDecimal to be + * created. + * @return The such created SimpleBigDecimal. + */ + public static SimpleBigDecimal GetInstance(BigInteger val, int scale) + { + return new SimpleBigDecimal(val.ShiftLeft(scale), scale); + } + + /** + * Constructor for SimpleBigDecimal. The value of the + * constructed SimpleBigDecimal Equals bigInt / + * 2scale. + * @param bigInt The bigInt value parameter. + * @param scale The scale of the constructed SimpleBigDecimal. + */ + public SimpleBigDecimal(BigInteger bigInt, int scale) + { + if (scale < 0) + throw new ArgumentException("scale may not be negative"); + + this.bigInt = bigInt; + this.scale = scale; + } + + private SimpleBigDecimal(SimpleBigDecimal limBigDec) + { + bigInt = limBigDec.bigInt; + scale = limBigDec.scale; + } + + private void CheckScale(SimpleBigDecimal b) + { + if (scale != b.scale) + throw new ArgumentException("Only SimpleBigDecimal of same scale allowed in arithmetic operations"); + } + + public SimpleBigDecimal AdjustScale(int newScale) + { + if (newScale < 0) + throw new ArgumentException("scale may not be negative"); + + if (newScale == scale) + return this; + + return new SimpleBigDecimal(bigInt.ShiftLeft(newScale - scale), newScale); + } + + public SimpleBigDecimal Add(SimpleBigDecimal b) + { + CheckScale(b); + return new SimpleBigDecimal(bigInt.Add(b.bigInt), scale); + } + + public SimpleBigDecimal Add(BigInteger b) + { + return new SimpleBigDecimal(bigInt.Add(b.ShiftLeft(scale)), scale); + } + + public SimpleBigDecimal Negate() + { + return new SimpleBigDecimal(bigInt.Negate(), scale); + } + + public SimpleBigDecimal Subtract(SimpleBigDecimal b) + { + return Add(b.Negate()); + } + + public SimpleBigDecimal Subtract(BigInteger b) + { + return new SimpleBigDecimal(bigInt.Subtract(b.ShiftLeft(scale)), scale); + } + + public SimpleBigDecimal Multiply(SimpleBigDecimal b) + { + CheckScale(b); + return new SimpleBigDecimal(bigInt.Multiply(b.bigInt), scale + scale); + } + + public SimpleBigDecimal Multiply(BigInteger b) + { + return new SimpleBigDecimal(bigInt.Multiply(b), scale); + } + + public SimpleBigDecimal Divide(SimpleBigDecimal b) + { + CheckScale(b); + BigInteger dividend = bigInt.ShiftLeft(scale); + return new SimpleBigDecimal(dividend.Divide(b.bigInt), scale); + } + + public SimpleBigDecimal Divide(BigInteger b) + { + return new SimpleBigDecimal(bigInt.Divide(b), scale); + } + + public SimpleBigDecimal ShiftLeft(int n) + { + return new SimpleBigDecimal(bigInt.ShiftLeft(n), scale); + } + + public int CompareTo(SimpleBigDecimal val) + { + CheckScale(val); + return bigInt.CompareTo(val.bigInt); + } + + public int CompareTo(BigInteger val) + { + return bigInt.CompareTo(val.ShiftLeft(scale)); + } + + public BigInteger Floor() + { + return bigInt.ShiftRight(scale); + } + + public BigInteger Round() + { + SimpleBigDecimal oneHalf = new SimpleBigDecimal(BigInteger.One, 1); + return Add(oneHalf.AdjustScale(scale)).Floor(); + } + + public int IntValue + { + get { return Floor().IntValue; } + } + + public long LongValue + { + get { return Floor().LongValue; } + } + +// public double doubleValue() +// { +// return new Double(ToString()).doubleValue(); +// } +// +// public float floatValue() +// { +// return new Float(ToString()).floatValue(); +// } + + public int Scale + { + get { return scale; } + } + + public override string ToString() + { + if (scale == 0) + return bigInt.ToString(); + + BigInteger floorBigInt = Floor(); + + BigInteger fract = bigInt.Subtract(floorBigInt.ShiftLeft(scale)); + if (bigInt.SignValue < 0) + { + fract = BigInteger.One.ShiftLeft(scale).Subtract(fract); + } + + if ((floorBigInt.SignValue == -1) && (!(fract.Equals(BigInteger.Zero)))) + { + floorBigInt = floorBigInt.Add(BigInteger.One); + } + string leftOfPoint = floorBigInt.ToString(); + + char[] fractCharArr = new char[scale]; + string fractStr = fract.ToString(2); + int fractLen = fractStr.Length; + int zeroes = scale - fractLen; + for (int i = 0; i < zeroes; i++) + { + fractCharArr[i] = '0'; + } + for (int j = 0; j < fractLen; j++) + { + fractCharArr[zeroes + j] = fractStr[j]; + } + string rightOfPoint = new string(fractCharArr); + + StringBuilder sb = new StringBuilder(leftOfPoint); + sb.Append("."); + sb.Append(rightOfPoint); + + return sb.ToString(); + } + + public override bool Equals( + object obj) + { + if (this == obj) + return true; + + SimpleBigDecimal other = obj as SimpleBigDecimal; + + if (other == null) + return false; + + return bigInt.Equals(other.bigInt) + && scale == other.scale; + } + + public override int GetHashCode() + { + return bigInt.GetHashCode() ^ scale; + } + + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/Tnaf.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/Tnaf.cs new file mode 100644 index 00000000..86e582f2 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/Tnaf.cs @@ -0,0 +1,845 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Abc +{ + /** + * Class holding methods for point multiplication based on the window + * τ-adic nonadjacent form (WTNAF). The algorithms are based on the + * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves" + * by Jerome A. Solinas. The paper first appeared in the Proceedings of + * Crypto 1997. + */ + internal class Tnaf + { + private static readonly BigInteger MinusOne = BigInteger.One.Negate(); + private static readonly BigInteger MinusTwo = BigInteger.Two.Negate(); + private static readonly BigInteger MinusThree = BigInteger.Three.Negate(); + private static readonly BigInteger Four = BigInteger.ValueOf(4); + + /** + * The window width of WTNAF. The standard value of 4 is slightly less + * than optimal for running time, but keeps space requirements for + * precomputation low. For typical curves, a value of 5 or 6 results in + * a better running time. When changing this value, the + * αu's must be computed differently, see + * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson, + * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004, + * p. 121-122 + */ + public const sbyte Width = 4; + + /** + * 24 + */ + public const sbyte Pow2Width = 16; + + /** + * The αu's for a=0 as an array + * of ZTauElements. + */ + public static readonly ZTauElement[] Alpha0 = + { + null, + new ZTauElement(BigInteger.One, BigInteger.Zero), null, + new ZTauElement(MinusThree, MinusOne), null, + new ZTauElement(MinusOne, MinusOne), null, + new ZTauElement(BigInteger.One, MinusOne), null + }; + + /** + * The αu's for a=0 as an array + * of TNAFs. + */ + public static readonly sbyte[][] Alpha0Tnaf = + { + null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, 1} + }; + + /** + * The αu's for a=1 as an array + * of ZTauElements. + */ + public static readonly ZTauElement[] Alpha1 = + { + null, + new ZTauElement(BigInteger.One, BigInteger.Zero), null, + new ZTauElement(MinusThree, BigInteger.One), null, + new ZTauElement(MinusOne, BigInteger.One), null, + new ZTauElement(BigInteger.One, BigInteger.One), null + }; + + /** + * The αu's for a=1 as an array + * of TNAFs. + */ + public static readonly sbyte[][] Alpha1Tnaf = + { + null, new sbyte[]{1}, null, new sbyte[]{-1, 0, 1}, null, new sbyte[]{1, 0, 1}, null, new sbyte[]{-1, 0, 0, -1} + }; + + /** + * Computes the norm of an element λ of + * Z[τ]. + * @param mu The parameter μ of the elliptic curve. + * @param lambda The element λ of + * Z[τ]. + * @return The norm of λ. + */ + public static BigInteger Norm(sbyte mu, ZTauElement lambda) + { + BigInteger norm; + + // s1 = u^2 + BigInteger s1 = lambda.u.Multiply(lambda.u); + + // s2 = u * v + BigInteger s2 = lambda.u.Multiply(lambda.v); + + // s3 = 2 * v^2 + BigInteger s3 = lambda.v.Multiply(lambda.v).ShiftLeft(1); + + if (mu == 1) + { + norm = s1.Add(s2).Add(s3); + } + else if (mu == -1) + { + norm = s1.Subtract(s2).Add(s3); + } + else + { + throw new ArgumentException("mu must be 1 or -1"); + } + + return norm; + } + + /** + * Computes the norm of an element λ of + * R[τ], where λ = u + vτ + * and u and u are real numbers (elements of + * R). + * @param mu The parameter μ of the elliptic curve. + * @param u The real part of the element λ of + * R[τ]. + * @param v The τ-adic part of the element + * λ of R[τ]. + * @return The norm of λ. + */ + public static SimpleBigDecimal Norm(sbyte mu, SimpleBigDecimal u, SimpleBigDecimal v) + { + SimpleBigDecimal norm; + + // s1 = u^2 + SimpleBigDecimal s1 = u.Multiply(u); + + // s2 = u * v + SimpleBigDecimal s2 = u.Multiply(v); + + // s3 = 2 * v^2 + SimpleBigDecimal s3 = v.Multiply(v).ShiftLeft(1); + + if (mu == 1) + { + norm = s1.Add(s2).Add(s3); + } + else if (mu == -1) + { + norm = s1.Subtract(s2).Add(s3); + } + else + { + throw new ArgumentException("mu must be 1 or -1"); + } + + return norm; + } + + /** + * Rounds an element λ of R[τ] + * to an element of Z[τ], such that their difference + * has minimal norm. λ is given as + * λ = λ0 + λ1τ. + * @param lambda0 The component λ0. + * @param lambda1 The component λ1. + * @param mu The parameter μ of the elliptic curve. Must + * equal 1 or -1. + * @return The rounded element of Z[τ]. + * @throws ArgumentException if lambda0 and + * lambda1 do not have same scale. + */ + public static ZTauElement Round(SimpleBigDecimal lambda0, + SimpleBigDecimal lambda1, sbyte mu) + { + int scale = lambda0.Scale; + if (lambda1.Scale != scale) + throw new ArgumentException("lambda0 and lambda1 do not have same scale"); + + if (!((mu == 1) || (mu == -1))) + throw new ArgumentException("mu must be 1 or -1"); + + BigInteger f0 = lambda0.Round(); + BigInteger f1 = lambda1.Round(); + + SimpleBigDecimal eta0 = lambda0.Subtract(f0); + SimpleBigDecimal eta1 = lambda1.Subtract(f1); + + // eta = 2*eta0 + mu*eta1 + SimpleBigDecimal eta = eta0.Add(eta0); + if (mu == 1) + { + eta = eta.Add(eta1); + } + else + { + // mu == -1 + eta = eta.Subtract(eta1); + } + + // check1 = eta0 - 3*mu*eta1 + // check2 = eta0 + 4*mu*eta1 + SimpleBigDecimal threeEta1 = eta1.Add(eta1).Add(eta1); + SimpleBigDecimal fourEta1 = threeEta1.Add(eta1); + SimpleBigDecimal check1; + SimpleBigDecimal check2; + if (mu == 1) + { + check1 = eta0.Subtract(threeEta1); + check2 = eta0.Add(fourEta1); + } + else + { + // mu == -1 + check1 = eta0.Add(threeEta1); + check2 = eta0.Subtract(fourEta1); + } + + sbyte h0 = 0; + sbyte h1 = 0; + + // if eta >= 1 + if (eta.CompareTo(BigInteger.One) >= 0) + { + if (check1.CompareTo(MinusOne) < 0) + { + h1 = mu; + } + else + { + h0 = 1; + } + } + else + { + // eta < 1 + if (check2.CompareTo(BigInteger.Two) >= 0) + { + h1 = mu; + } + } + + // if eta < -1 + if (eta.CompareTo(MinusOne) < 0) + { + if (check1.CompareTo(BigInteger.One) >= 0) + { + h1 = (sbyte)-mu; + } + else + { + h0 = -1; + } + } + else + { + // eta >= -1 + if (check2.CompareTo(MinusTwo) < 0) + { + h1 = (sbyte)-mu; + } + } + + BigInteger q0 = f0.Add(BigInteger.ValueOf(h0)); + BigInteger q1 = f1.Add(BigInteger.ValueOf(h1)); + return new ZTauElement(q0, q1); + } + + /** + * Approximate division by n. For an integer + * k, the value λ = s k / n is + * computed to c bits of accuracy. + * @param k The parameter k. + * @param s The curve parameter s0 or + * s1. + * @param vm The Lucas Sequence element Vm. + * @param a The parameter a of the elliptic curve. + * @param m The bit length of the finite field + * Fm. + * @param c The number of bits of accuracy, i.e. the scale of the returned + * SimpleBigDecimal. + * @return The value λ = s k / n computed to + * c bits of accuracy. + */ + public static SimpleBigDecimal ApproximateDivisionByN(BigInteger k, + BigInteger s, BigInteger vm, sbyte a, int m, int c) + { + int _k = (m + 5)/2 + c; + BigInteger ns = k.ShiftRight(m - _k - 2 + a); + + BigInteger gs = s.Multiply(ns); + + BigInteger hs = gs.ShiftRight(m); + + BigInteger js = vm.Multiply(hs); + + BigInteger gsPlusJs = gs.Add(js); + BigInteger ls = gsPlusJs.ShiftRight(_k-c); + if (gsPlusJs.TestBit(_k-c-1)) + { + // round up + ls = ls.Add(BigInteger.One); + } + + return new SimpleBigDecimal(ls, c); + } + + /** + * Computes the τ-adic NAF (non-adjacent form) of an + * element λ of Z[τ]. + * @param mu The parameter μ of the elliptic curve. + * @param lambda The element λ of + * Z[τ]. + * @return The τ-adic NAF of λ. + */ + public static sbyte[] TauAdicNaf(sbyte mu, ZTauElement lambda) + { + if (!((mu == 1) || (mu == -1))) + throw new ArgumentException("mu must be 1 or -1"); + + BigInteger norm = Norm(mu, lambda); + + // Ceiling of log2 of the norm + int log2Norm = norm.BitLength; + + // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52 + int maxLength = log2Norm > 30 ? log2Norm + 4 : 34; + + // The array holding the TNAF + sbyte[] u = new sbyte[maxLength]; + int i = 0; + + // The actual length of the TNAF + int length = 0; + + BigInteger r0 = lambda.u; + BigInteger r1 = lambda.v; + + while(!((r0.Equals(BigInteger.Zero)) && (r1.Equals(BigInteger.Zero)))) + { + // If r0 is odd + if (r0.TestBit(0)) + { + u[i] = (sbyte) BigInteger.Two.Subtract((r0.Subtract(r1.ShiftLeft(1))).Mod(Four)).IntValue; + + // r0 = r0 - u[i] + if (u[i] == 1) + { + r0 = r0.ClearBit(0); + } + else + { + // u[i] == -1 + r0 = r0.Add(BigInteger.One); + } + length = i; + } + else + { + u[i] = 0; + } + + BigInteger t = r0; + BigInteger s = r0.ShiftRight(1); + if (mu == 1) + { + r0 = r1.Add(s); + } + else + { + // mu == -1 + r0 = r1.Subtract(s); + } + + r1 = t.ShiftRight(1).Negate(); + i++; + } + + length++; + + // Reduce the TNAF array to its actual length + sbyte[] tnaf = new sbyte[length]; + Array.Copy(u, 0, tnaf, 0, length); + return tnaf; + } + + /** + * Applies the operation τ() to an + * AbstractF2mPoint. + * @param p The AbstractF2mPoint to which τ() is applied. + * @return τ(p) + */ + public static AbstractF2mPoint Tau(AbstractF2mPoint p) + { + return p.Tau(); + } + + /** + * Returns the parameter μ of the elliptic curve. + * @param curve The elliptic curve from which to obtain μ. + * The curve must be a Koblitz curve, i.e. a Equals + * 0 or 1 and b Equals + * 1. + * @return μ of the elliptic curve. + * @throws ArgumentException if the given ECCurve is not a Koblitz + * curve. + */ + public static sbyte GetMu(AbstractF2mCurve curve) + { + BigInteger a = curve.A.ToBigInteger(); + + sbyte mu; + if (a.SignValue == 0) + { + mu = -1; + } + else if (a.Equals(BigInteger.One)) + { + mu = 1; + } + else + { + throw new ArgumentException("No Koblitz curve (ABC), TNAF multiplication not possible"); + } + return mu; + } + + public static sbyte GetMu(ECFieldElement curveA) + { + return (sbyte)(curveA.IsZero ? -1 : 1); + } + + public static sbyte GetMu(int curveA) + { + return (sbyte)(curveA == 0 ? -1 : 1); + } + + /** + * Calculates the Lucas Sequence elements Uk-1 and + * Uk or Vk-1 and + * Vk. + * @param mu The parameter μ of the elliptic curve. + * @param k The index of the second element of the Lucas Sequence to be + * returned. + * @param doV If set to true, computes Vk-1 and + * Vk, otherwise Uk-1 and + * Uk. + * @return An array with 2 elements, containing Uk-1 + * and Uk or Vk-1 + * and Vk. + */ + public static BigInteger[] GetLucas(sbyte mu, int k, bool doV) + { + if (!(mu == 1 || mu == -1)) + throw new ArgumentException("mu must be 1 or -1"); + + BigInteger u0; + BigInteger u1; + BigInteger u2; + + if (doV) + { + u0 = BigInteger.Two; + u1 = BigInteger.ValueOf(mu); + } + else + { + u0 = BigInteger.Zero; + u1 = BigInteger.One; + } + + for (int i = 1; i < k; i++) + { + // u2 = mu*u1 - 2*u0; + BigInteger s = null; + if (mu == 1) + { + s = u1; + } + else + { + // mu == -1 + s = u1.Negate(); + } + + u2 = s.Subtract(u0.ShiftLeft(1)); + u0 = u1; + u1 = u2; + // System.out.println(i + ": " + u2); + // System.out.println(); + } + + BigInteger[] retVal = {u0, u1}; + return retVal; + } + + /** + * Computes the auxiliary value tw. If the width is + * 4, then for mu = 1, tw = 6 and for + * mu = -1, tw = 10 + * @param mu The parameter μ of the elliptic curve. + * @param w The window width of the WTNAF. + * @return the auxiliary value tw + */ + public static BigInteger GetTw(sbyte mu, int w) + { + if (w == 4) + { + if (mu == 1) + { + return BigInteger.ValueOf(6); + } + else + { + // mu == -1 + return BigInteger.ValueOf(10); + } + } + else + { + // For w <> 4, the values must be computed + BigInteger[] us = GetLucas(mu, w, false); + BigInteger twoToW = BigInteger.Zero.SetBit(w); + BigInteger u1invert = us[1].ModInverse(twoToW); + BigInteger tw; + tw = BigInteger.Two.Multiply(us[0]).Multiply(u1invert).Mod(twoToW); + //System.out.println("mu = " + mu); + //System.out.println("tw = " + tw); + return tw; + } + } + + /** + * Computes the auxiliary values s0 and + * s1 used for partial modular reduction. + * @param curve The elliptic curve for which to compute + * s0 and s1. + * @throws ArgumentException if curve is not a + * Koblitz curve (Anomalous Binary Curve, ABC). + */ + public static BigInteger[] GetSi(AbstractF2mCurve curve) + { + if (!curve.IsKoblitz) + throw new ArgumentException("si is defined for Koblitz curves only"); + + int m = curve.FieldSize; + int a = curve.A.ToBigInteger().IntValue; + sbyte mu = GetMu(a); + int shifts = GetShiftsForCofactor(curve.Cofactor); + int index = m + 3 - a; + BigInteger[] ui = GetLucas(mu, index, false); + + if (mu == 1) + { + ui[0] = ui[0].Negate(); + ui[1] = ui[1].Negate(); + } + + BigInteger dividend0 = BigInteger.One.Add(ui[1]).ShiftRight(shifts); + BigInteger dividend1 = BigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate(); + + return new BigInteger[] { dividend0, dividend1 }; + } + + public static BigInteger[] GetSi(int fieldSize, int curveA, BigInteger cofactor) + { + sbyte mu = GetMu(curveA); + int shifts = GetShiftsForCofactor(cofactor); + int index = fieldSize + 3 - curveA; + BigInteger[] ui = GetLucas(mu, index, false); + if (mu == 1) + { + ui[0] = ui[0].Negate(); + ui[1] = ui[1].Negate(); + } + + BigInteger dividend0 = BigInteger.One.Add(ui[1]).ShiftRight(shifts); + BigInteger dividend1 = BigInteger.One.Add(ui[0]).ShiftRight(shifts).Negate(); + + return new BigInteger[] { dividend0, dividend1 }; + } + + protected static int GetShiftsForCofactor(BigInteger h) + { + if (h != null && h.BitLength < 4) + { + int hi = h.IntValue; + if (hi == 2) + return 1; + if (hi == 4) + return 2; + } + + throw new ArgumentException("h (Cofactor) must be 2 or 4"); + } + + /** + * Partial modular reduction modulo + * m - 1)/(τ - 1). + * @param k The integer to be reduced. + * @param m The bitlength of the underlying finite field. + * @param a The parameter a of the elliptic curve. + * @param s The auxiliary values s0 and + * s1. + * @param mu The parameter μ of the elliptic curve. + * @param c The precision (number of bits of accuracy) of the partial + * modular reduction. + * @return ρ := k partmod (τm - 1)/(τ - 1) + */ + public static ZTauElement PartModReduction(BigInteger k, int m, sbyte a, + BigInteger[] s, sbyte mu, sbyte c) + { + // d0 = s[0] + mu*s[1]; mu is either 1 or -1 + BigInteger d0; + if (mu == 1) + { + d0 = s[0].Add(s[1]); + } + else + { + d0 = s[0].Subtract(s[1]); + } + + BigInteger[] v = GetLucas(mu, m, true); + BigInteger vm = v[1]; + + SimpleBigDecimal lambda0 = ApproximateDivisionByN( + k, s[0], vm, a, m, c); + + SimpleBigDecimal lambda1 = ApproximateDivisionByN( + k, s[1], vm, a, m, c); + + ZTauElement q = Round(lambda0, lambda1, mu); + + // r0 = n - d0*q0 - 2*s1*q1 + BigInteger r0 = k.Subtract(d0.Multiply(q.u)).Subtract( + BigInteger.ValueOf(2).Multiply(s[1]).Multiply(q.v)); + + // r1 = s1*q0 - s0*q1 + BigInteger r1 = s[1].Multiply(q.u).Subtract(s[0].Multiply(q.v)); + + return new ZTauElement(r0, r1); + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint} + * by a BigInteger using the reduced τ-adic + * NAF (RTNAF) method. + * @param p The AbstractF2mPoint to Multiply. + * @param k The BigInteger by which to Multiply p. + * @return k * p + */ + public static AbstractF2mPoint MultiplyRTnaf(AbstractF2mPoint p, BigInteger k) + { + AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve; + int m = curve.FieldSize; + int a = curve.A.ToBigInteger().IntValue; + sbyte mu = GetMu(a); + BigInteger[] s = curve.GetSi(); + ZTauElement rho = PartModReduction(k, m, (sbyte)a, s, mu, (sbyte)10); + + return MultiplyTnaf(p, rho); + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint} + * by an element λ of Z[τ] + * using the τ-adic NAF (TNAF) method. + * @param p The AbstractF2mPoint to Multiply. + * @param lambda The element λ of + * Z[τ]. + * @return λ * p + */ + public static AbstractF2mPoint MultiplyTnaf(AbstractF2mPoint p, ZTauElement lambda) + { + AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve; + sbyte mu = GetMu(curve.A); + sbyte[] u = TauAdicNaf(mu, lambda); + + AbstractF2mPoint q = MultiplyFromTnaf(p, u); + + return q; + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint} + * by an element λ of Z[τ] + * using the τ-adic NAF (TNAF) method, given the TNAF + * of λ. + * @param p The AbstractF2mPoint to Multiply. + * @param u The the TNAF of λ.. + * @return λ * p + */ + public static AbstractF2mPoint MultiplyFromTnaf(AbstractF2mPoint p, sbyte[] u) + { + ECCurve curve = p.Curve; + AbstractF2mPoint q = (AbstractF2mPoint)curve.Infinity; + AbstractF2mPoint pNeg = (AbstractF2mPoint)p.Negate(); + int tauCount = 0; + for (int i = u.Length - 1; i >= 0; i--) + { + ++tauCount; + sbyte ui = u[i]; + if (ui != 0) + { + q = q.TauPow(tauCount); + tauCount = 0; + + ECPoint x = ui > 0 ? p : pNeg; + q = (AbstractF2mPoint)q.Add(x); + } + } + if (tauCount > 0) + { + q = q.TauPow(tauCount); + } + return q; + } + + /** + * Computes the [τ]-adic window NAF of an element + * λ of Z[τ]. + * @param mu The parameter μ of the elliptic curve. + * @param lambda The element λ of + * Z[τ] of which to compute the + * [τ]-adic NAF. + * @param width The window width of the resulting WNAF. + * @param pow2w 2width. + * @param tw The auxiliary value tw. + * @param alpha The αu's for the window width. + * @return The [τ]-adic window NAF of + * λ. + */ + public static sbyte[] TauAdicWNaf(sbyte mu, ZTauElement lambda, + sbyte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha) + { + if (!((mu == 1) || (mu == -1))) + throw new ArgumentException("mu must be 1 or -1"); + + BigInteger norm = Norm(mu, lambda); + + // Ceiling of log2 of the norm + int log2Norm = norm.BitLength; + + // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52 + int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width; + + // The array holding the TNAF + sbyte[] u = new sbyte[maxLength]; + + // 2^(width - 1) + BigInteger pow2wMin1 = pow2w.ShiftRight(1); + + // Split lambda into two BigIntegers to simplify calculations + BigInteger r0 = lambda.u; + BigInteger r1 = lambda.v; + int i = 0; + + // while lambda <> (0, 0) + while (!((r0.Equals(BigInteger.Zero))&&(r1.Equals(BigInteger.Zero)))) + { + // if r0 is odd + if (r0.TestBit(0)) + { + // uUnMod = r0 + r1*tw Mod 2^width + BigInteger uUnMod + = r0.Add(r1.Multiply(tw)).Mod(pow2w); + + sbyte uLocal; + // if uUnMod >= 2^(width - 1) + if (uUnMod.CompareTo(pow2wMin1) >= 0) + { + uLocal = (sbyte) uUnMod.Subtract(pow2w).IntValue; + } + else + { + uLocal = (sbyte) uUnMod.IntValue; + } + // uLocal is now in [-2^(width-1), 2^(width-1)-1] + + u[i] = uLocal; + bool s = true; + if (uLocal < 0) + { + s = false; + uLocal = (sbyte)-uLocal; + } + // uLocal is now >= 0 + + if (s) + { + r0 = r0.Subtract(alpha[uLocal].u); + r1 = r1.Subtract(alpha[uLocal].v); + } + else + { + r0 = r0.Add(alpha[uLocal].u); + r1 = r1.Add(alpha[uLocal].v); + } + } + else + { + u[i] = 0; + } + + BigInteger t = r0; + + if (mu == 1) + { + r0 = r1.Add(r0.ShiftRight(1)); + } + else + { + // mu == -1 + r0 = r1.Subtract(r0.ShiftRight(1)); + } + r1 = t.ShiftRight(1).Negate(); + i++; + } + return u; + } + + /** + * Does the precomputation for WTNAF multiplication. + * @param p The ECPoint for which to do the precomputation. + * @param a The parameter a of the elliptic curve. + * @return The precomputation array for p. + */ + public static AbstractF2mPoint[] GetPreComp(AbstractF2mPoint p, sbyte a) + { + sbyte[][] alphaTnaf = (a == 0) ? Tnaf.Alpha0Tnaf : Tnaf.Alpha1Tnaf; + + AbstractF2mPoint[] pu = new AbstractF2mPoint[(uint)(alphaTnaf.Length + 1) >> 1]; + pu[0] = p; + + uint precompLen = (uint)alphaTnaf.Length; + for (uint i = 3; i < precompLen; i += 2) + { + pu[i >> 1] = Tnaf.MultiplyFromTnaf(p, alphaTnaf[i]); + } + + p.Curve.NormalizeAll(pu); + + return pu; + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/ZTauElement.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/ZTauElement.cs new file mode 100644 index 00000000..0b74e48d --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/abc/ZTauElement.cs @@ -0,0 +1,36 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Abc +{ + /** + * Class representing an element of Z[τ]. Let + * λ be an element of Z[τ]. Then + * λ is given as λ = u + vτ. The + * components u and v may be used directly, there + * are no accessor methods. + * Immutable class. + */ + internal class ZTauElement + { + /** + * The "real" part of λ. + */ + public readonly BigInteger u; + + /** + * The "τ-adic" part of λ. + */ + public readonly BigInteger v; + + /** + * Constructor for an element λ of + * Z[τ]. + * @param u The "real" part of λ. + * @param v The "τ-adic" part of + * λ. + */ + public ZTauElement(BigInteger u, BigInteger v) + { + this.u = u; + this.v = v; + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/ECEndomorphism.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/ECEndomorphism.cs new file mode 100644 index 00000000..8dbbace4 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/ECEndomorphism.cs @@ -0,0 +1,11 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Endo +{ + internal interface ECEndomorphism + { + ECPointMap PointMap { get; } + + bool HasEfficientPointMap { get; } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/GlvEndomorphism.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/GlvEndomorphism.cs new file mode 100644 index 00000000..143a369b --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/GlvEndomorphism.cs @@ -0,0 +1,10 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Endo +{ + internal interface GlvEndomorphism + : ECEndomorphism + { + BigInteger[] DecomposeScalar(BigInteger k); + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/AbstractECMultiplier.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/AbstractECMultiplier.cs new file mode 100644 index 00000000..9c9b4cb2 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/AbstractECMultiplier.cs @@ -0,0 +1,29 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + internal abstract class AbstractECMultiplier + : ECMultiplier + { + public virtual ECPoint Multiply(ECPoint p, BigInteger k) + { + int sign = k.SignValue; + if (sign == 0 || p.IsInfinity) + return p.Curve.Infinity; + + ECPoint positive = MultiplyPositive(p, k.Abs()); + ECPoint result = sign > 0 ? positive : positive.Negate(); + + /* + * Although the various multipliers ought not to produce invalid output under normal + * circumstances, a final check here is advised to guard against fault attacks. + */ + return CheckResult(result); + } + + protected abstract ECPoint MultiplyPositive(ECPoint p, BigInteger k); + + protected virtual ECPoint CheckResult(ECPoint p) + { + return ECAlgorithms.ImplCheckResult(p); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/ECMultiplier.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/ECMultiplier.cs new file mode 100644 index 00000000..97fe1d13 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/ECMultiplier.cs @@ -0,0 +1,18 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Interface for classes encapsulating a point multiplication algorithm + * for ECPoints. + */ + internal interface ECMultiplier + { + /** + * Multiplies the ECPoint p by k, i.e. + * p is added k times to itself. + * @param p The ECPoint to be multiplied. + * @param k The factor by which p is multiplied. + * @return p multiplied by k. + */ + ECPoint Multiply(ECPoint p, BigInteger k); + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointCombMultiplier.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointCombMultiplier.cs new file mode 100644 index 00000000..a63e18e2 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointCombMultiplier.cs @@ -0,0 +1,58 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math.Raw; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + internal class FixedPointCombMultiplier + : AbstractECMultiplier + { + protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k) + { + ECCurve c = p.Curve; + int size = FixedPointUtilities.GetCombSize(c); + + if (k.BitLength > size) + { + /* + * TODO The comb works best when the scalars are less than the (possibly unknown) order. + * Still, if we want to handle larger scalars, we could allow customization of the comb + * size, or alternatively we could deal with the 'extra' bits either by running the comb + * multiple times as necessary, or by using an alternative multiplier as prelude. + */ + throw new InvalidOperationException("fixed-point comb doesn't support scalars larger than the curve order"); + } + + FixedPointPreCompInfo info = FixedPointUtilities.Precompute(p); + ECLookupTable lookupTable = info.LookupTable; + int width = info.Width; + + int d = (size + width - 1) / width; + + ECPoint R = c.Infinity; + + int fullComb = d * width; + uint[] K = Nat.FromBigInteger(fullComb, k); + + int top = fullComb - 1; + for (int i = 0; i < d; ++i) + { + uint secretIndex = 0; + + for (int j = top - i; j >= 0; j -= d) + { + uint secretBit = K[j >> 5] >> (j & 0x1F); + secretIndex ^= secretBit >> 1; + secretIndex <<= 1; + secretIndex ^= secretBit; + } + + ECPoint add = lookupTable.Lookup((int)secretIndex); + + R = R.TwicePlus(add); + } + + return R.Add(info.Offset); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointPreCompInfo.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointPreCompInfo.cs new file mode 100644 index 00000000..d5411657 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointPreCompInfo.cs @@ -0,0 +1,43 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class holding precomputation data for fixed-point multiplications. + */ + internal class FixedPointPreCompInfo + : PreCompInfo + { + protected ECPoint m_offset = null; + + /** + * Lookup table for the precomputed ECPoints used for a fixed point multiplication. + */ + protected ECLookupTable m_lookupTable = null; + + /** + * The width used for the precomputation. If a larger width precomputation + * is already available this may be larger than was requested, so calling + * code should refer to the actual width. + */ + protected int m_width = -1; + + public virtual ECLookupTable LookupTable + { + get { return m_lookupTable; } + set { this.m_lookupTable = value; } + } + + public virtual ECPoint Offset + { + get { return m_offset; } + set { this.m_offset = value; } + } + + public virtual int Width + { + get { return m_width; } + set { this.m_width = value; } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointUtilities.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointUtilities.cs new file mode 100644 index 00000000..14dea10a --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/FixedPointUtilities.cs @@ -0,0 +1,95 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + internal class FixedPointUtilities + { + public static readonly string PRECOMP_NAME = "bc_fixed_point"; + + public static int GetCombSize(ECCurve c) + { + BigInteger order = c.Order; + return order == null ? c.FieldSize + 1 : order.BitLength; + } + + public static FixedPointPreCompInfo GetFixedPointPreCompInfo(PreCompInfo preCompInfo) + { + return preCompInfo as FixedPointPreCompInfo; + } + + public static FixedPointPreCompInfo Precompute(ECPoint p) + { + return (FixedPointPreCompInfo)p.Curve.Precompute(p, PRECOMP_NAME, new FixedPointCallback(p)); + } + + private class FixedPointCallback + : IPreCompCallback + { + private readonly ECPoint m_p; + + internal FixedPointCallback(ECPoint p) + { + this.m_p = p; + } + + public PreCompInfo Precompute(PreCompInfo existing) + { + FixedPointPreCompInfo existingFP = (existing is FixedPointPreCompInfo) ? (FixedPointPreCompInfo)existing : null; + + ECCurve c = m_p.Curve; + int bits = FixedPointUtilities.GetCombSize(c); + int minWidth = bits > 250 ? 6 : 5; + int n = 1 << minWidth; + + if (CheckExisting(existingFP, n)) + return existingFP; + + int d = (bits + minWidth - 1) / minWidth; + + ECPoint[] pow2Table = new ECPoint[minWidth + 1]; + pow2Table[0] = m_p; + for (int i = 1; i < minWidth; ++i) + { + pow2Table[i] = pow2Table[i - 1].TimesPow2(d); + } + + // This will be the 'offset' value + pow2Table[minWidth] = pow2Table[0].Subtract(pow2Table[1]); + + c.NormalizeAll(pow2Table); + + ECPoint[] lookupTable = new ECPoint[n]; + lookupTable[0] = pow2Table[0]; + + for (int bit = minWidth - 1; bit >= 0; --bit) + { + ECPoint pow2 = pow2Table[bit]; + + int step = 1 << bit; + for (int i = step; i < n; i += (step << 1)) + { + lookupTable[i] = lookupTable[i - step].Add(pow2); + } + } + + c.NormalizeAll(lookupTable); + + FixedPointPreCompInfo result = new FixedPointPreCompInfo(); + result.LookupTable = c.CreateCacheSafeLookupTable(lookupTable, 0, lookupTable.Length); + result.Offset = pow2Table[minWidth]; + result.Width = minWidth; + return result; + } + + private bool CheckExisting(FixedPointPreCompInfo existingFP, int n) + { + return existingFP != null && CheckTable(existingFP.LookupTable, n); + } + + private bool CheckTable(ECLookupTable table, int n) + { + return table != null && table.Size >= n; + } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/GlvMultiplier.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/GlvMultiplier.cs new file mode 100644 index 00000000..e255b3ee --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/GlvMultiplier.cs @@ -0,0 +1,40 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Endo; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + internal class GlvMultiplier + : AbstractECMultiplier + { + protected readonly ECCurve curve; + protected readonly GlvEndomorphism glvEndomorphism; + + public GlvMultiplier(ECCurve curve, GlvEndomorphism glvEndomorphism) + { + if (curve == null || curve.Order == null) + throw new ArgumentException("Need curve with known group order", "curve"); + + this.curve = curve; + this.glvEndomorphism = glvEndomorphism; + } + + protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k) + { + if (!curve.Equals(p.Curve)) + throw new InvalidOperationException(); + + BigInteger n = p.Curve.Order; + BigInteger[] ab = glvEndomorphism.DecomposeScalar(k.Mod(n)); + BigInteger a = ab[0], b = ab[1]; + + ECPointMap pointMap = glvEndomorphism.PointMap; + if (glvEndomorphism.HasEfficientPointMap) + { + return ECAlgorithms.ImplShamirsTrickWNaf(p, a, pointMap, b); + } + + return ECAlgorithms.ImplShamirsTrickWNaf(p, a, pointMap.Map(p), b); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/IPreCompCallback.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/IPreCompCallback.cs new file mode 100644 index 00000000..87199889 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/IPreCompCallback.cs @@ -0,0 +1,9 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + internal interface IPreCompCallback + { + PreCompInfo Precompute(PreCompInfo existing); + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/PreCompInfo.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/PreCompInfo.cs new file mode 100644 index 00000000..32c40216 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/PreCompInfo.cs @@ -0,0 +1,11 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Interface for classes storing precomputation data for multiplication + * algorithms. Used as a Memento (see GOF patterns) for + * WNafMultiplier. + */ + internal interface PreCompInfo + { + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/ValidityPreCompInfo.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/ValidityPreCompInfo.cs new file mode 100644 index 00000000..78dabc26 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/ValidityPreCompInfo.cs @@ -0,0 +1,44 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + internal class ValidityPreCompInfo + : PreCompInfo + { + internal static readonly string PRECOMP_NAME = "bc_validity"; + + private bool failed = false; + private bool curveEquationPassed = false; + private bool orderPassed = false; + + internal bool HasFailed() + { + return failed; + } + + internal void ReportFailed() + { + failed = true; + } + + internal bool HasCurveEquationPassed() + { + return curveEquationPassed; + } + + internal void ReportCurveEquationPassed() + { + curveEquationPassed = true; + } + + internal bool HasOrderPassed() + { + return orderPassed; + } + + internal void ReportOrderPassed() + { + orderPassed = true; + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafL2RMultiplier.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafL2RMultiplier.cs new file mode 100644 index 00000000..04341566 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafL2RMultiplier.cs @@ -0,0 +1,98 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class implementing the WNAF (Window Non-Adjacent Form) multiplication + * algorithm. + */ + internal class WNafL2RMultiplier + : AbstractECMultiplier + { + /** + * Multiplies this by an integer k using the + * Window NAF method. + * @param k The integer by which this is multiplied. + * @return A new ECPoint which equals this + * multiplied by k. + */ + protected override ECPoint MultiplyPositive(ECPoint p, BigInteger k) + { + // Clamp the window width in the range [2, 16] + int width = System.Math.Max(2, System.Math.Min(16, GetWindowSize(k.BitLength))); + + WNafPreCompInfo wnafPreCompInfo = WNafUtilities.Precompute(p, width, true); + ECPoint[] preComp = wnafPreCompInfo.PreComp; + ECPoint[] preCompNeg = wnafPreCompInfo.PreCompNeg; + + int[] wnaf = WNafUtilities.GenerateCompactWindowNaf(width, k); + + ECPoint R = p.Curve.Infinity; + + int i = wnaf.Length; + + /* + * NOTE: We try to optimize the first window using the precomputed points to substitute an + * addition for 2 or more doublings. + */ + if (i > 1) + { + int wi = wnaf[--i]; + int digit = wi >> 16, zeroes = wi & 0xFFFF; + + int n = System.Math.Abs(digit); + ECPoint[] table = digit < 0 ? preCompNeg : preComp; + + // Optimization can only be used for values in the lower half of the table + if ((n << 2) < (1 << width)) + { + int highest = LongArray.BitLengths[n]; + + // TODO Get addition/doubling cost ratio from curve and compare to 'scale' to see if worth substituting? + int scale = width - highest; + int lowBits = n ^ (1 << (highest - 1)); + + int i1 = ((1 << (width - 1)) - 1); + int i2 = (lowBits << scale) + 1; + R = table[i1 >> 1].Add(table[i2 >> 1]); + + zeroes -= scale; + + //Console.WriteLine("Optimized: 2^" + scale + " * " + n + " = " + i1 + " + " + i2); + } + else + { + R = table[n >> 1]; + } + + R = R.TimesPow2(zeroes); + } + + while (i > 0) + { + int wi = wnaf[--i]; + int digit = wi >> 16, zeroes = wi & 0xFFFF; + + int n = System.Math.Abs(digit); + ECPoint[] table = digit < 0 ? preCompNeg : preComp; + ECPoint r = table[n >> 1]; + + R = R.TwicePlus(r); + R = R.TimesPow2(zeroes); + } + + return R; + } + + /** + * Determine window width to use for a scalar multiplication of the given size. + * + * @param bits the bit-length of the scalar to multiply by + * @return the window size to use + */ + protected virtual int GetWindowSize(int bits) + { + return WNafUtilities.GetWindowSize(bits); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafPreCompInfo.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafPreCompInfo.cs new file mode 100644 index 00000000..91d56512 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafPreCompInfo.cs @@ -0,0 +1,46 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class holding precomputation data for the WNAF (Window Non-Adjacent Form) + * algorithm. + */ + internal class WNafPreCompInfo + : PreCompInfo + { + /** + * Array holding the precomputed ECPoints used for a Window + * NAF multiplication. + */ + protected ECPoint[] m_preComp = null; + + /** + * Array holding the negations of the precomputed ECPoints used + * for a Window NAF multiplication. + */ + protected ECPoint[] m_preCompNeg = null; + + /** + * Holds an ECPoint representing Twice(this). Used for the + * Window NAF multiplication to create or extend the precomputed values. + */ + protected ECPoint m_twice = null; + + public virtual ECPoint[] PreComp + { + get { return m_preComp; } + set { this.m_preComp = value; } + } + + public virtual ECPoint[] PreCompNeg + { + get { return m_preCompNeg; } + set { this.m_preCompNeg = value; } + } + + public virtual ECPoint Twice + { + get { return m_twice; } + set { this.m_twice = value; } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafUtilities.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafUtilities.cs new file mode 100644 index 00000000..8dbe7ef7 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WNafUtilities.cs @@ -0,0 +1,579 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + internal abstract class WNafUtilities + { + public static readonly string PRECOMP_NAME = "bc_wnaf"; + + private static readonly int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 }; + + private static readonly ECPoint[] EMPTY_POINTS = new ECPoint[0]; + + public static int[] GenerateCompactNaf(BigInteger k) + { + if ((k.BitLength >> 16) != 0) + throw new ArgumentException("must have bitlength < 2^16", "k"); + if (k.SignValue == 0) + return Arrays.EmptyInts; + + BigInteger _3k = k.ShiftLeft(1).Add(k); + + int bits = _3k.BitLength; + int[] naf = new int[bits >> 1]; + + BigInteger diff = _3k.Xor(k); + + int highBit = bits - 1, length = 0, zeroes = 0; + for (int i = 1; i < highBit; ++i) + { + if (!diff.TestBit(i)) + { + ++zeroes; + continue; + } + + int digit = k.TestBit(i) ? -1 : 1; + naf[length++] = (digit << 16) | zeroes; + zeroes = 1; + ++i; + } + + naf[length++] = (1 << 16) | zeroes; + + if (naf.Length > length) + { + naf = Trim(naf, length); + } + + return naf; + } + + public static int[] GenerateCompactWindowNaf(int width, BigInteger k) + { + if (width == 2) + { + return GenerateCompactNaf(k); + } + + if (width < 2 || width > 16) + throw new ArgumentException("must be in the range [2, 16]", "width"); + if ((k.BitLength >> 16) != 0) + throw new ArgumentException("must have bitlength < 2^16", "k"); + if (k.SignValue == 0) + return Arrays.EmptyInts; + + int[] wnaf = new int[k.BitLength / width + 1]; + + // 2^width and a mask and sign bit set accordingly + int pow2 = 1 << width; + int mask = pow2 - 1; + int sign = pow2 >> 1; + + bool carry = false; + int length = 0, pos = 0; + + while (pos <= k.BitLength) + { + if (k.TestBit(pos) == carry) + { + ++pos; + continue; + } + + k = k.ShiftRight(pos); + + int digit = k.IntValue & mask; + if (carry) + { + ++digit; + } + + carry = (digit & sign) != 0; + if (carry) + { + digit -= pow2; + } + + int zeroes = length > 0 ? pos - 1 : pos; + wnaf[length++] = (digit << 16) | zeroes; + pos = width; + } + + // Reduce the WNAF array to its actual length + if (wnaf.Length > length) + { + wnaf = Trim(wnaf, length); + } + + return wnaf; + } + + public static byte[] GenerateJsf(BigInteger g, BigInteger h) + { + int digits = System.Math.Max(g.BitLength, h.BitLength) + 1; + byte[] jsf = new byte[digits]; + + BigInteger k0 = g, k1 = h; + int j = 0, d0 = 0, d1 = 0; + + int offset = 0; + while ((d0 | d1) != 0 || k0.BitLength > offset || k1.BitLength > offset) + { + int n0 = ((int)((uint)k0.IntValue >> offset) + d0) & 7; + int n1 = ((int)((uint)k1.IntValue >> offset) + d1) & 7; + + int u0 = n0 & 1; + if (u0 != 0) + { + u0 -= (n0 & 2); + if ((n0 + u0) == 4 && (n1 & 3) == 2) + { + u0 = -u0; + } + } + + int u1 = n1 & 1; + if (u1 != 0) + { + u1 -= (n1 & 2); + if ((n1 + u1) == 4 && (n0 & 3) == 2) + { + u1 = -u1; + } + } + + if ((d0 << 1) == 1 + u0) + { + d0 ^= 1; + } + if ((d1 << 1) == 1 + u1) + { + d1 ^= 1; + } + + if (++offset == 30) + { + offset = 0; + k0 = k0.ShiftRight(30); + k1 = k1.ShiftRight(30); + } + + jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF)); + } + + // Reduce the JSF array to its actual length + if (jsf.Length > j) + { + jsf = Trim(jsf, j); + } + + return jsf; + } + + public static byte[] GenerateNaf(BigInteger k) + { + if (k.SignValue == 0) + return Arrays.EmptyBytes; + + BigInteger _3k = k.ShiftLeft(1).Add(k); + + int digits = _3k.BitLength - 1; + byte[] naf = new byte[digits]; + + BigInteger diff = _3k.Xor(k); + + for (int i = 1; i < digits; ++i) + { + if (diff.TestBit(i)) + { + naf[i - 1] = (byte)(k.TestBit(i) ? -1 : 1); + ++i; + } + } + + naf[digits - 1] = 1; + + return naf; + } + + /** + * Computes the Window NAF (non-adjacent Form) of an integer. + * @param width The width w of the Window NAF. The width is + * defined as the minimal number w, such that for any + * w consecutive digits in the resulting representation, at + * most one is non-zero. + * @param k The integer of which the Window NAF is computed. + * @return The Window NAF of the given width, such that the following holds: + * k = &sum;i=0l-1 ki2i + * , where the ki denote the elements of the + * returned byte[]. + */ + public static byte[] GenerateWindowNaf(int width, BigInteger k) + { + if (width == 2) + { + return GenerateNaf(k); + } + + if (width < 2 || width > 8) + throw new ArgumentException("must be in the range [2, 8]", "width"); + if (k.SignValue == 0) + return Arrays.EmptyBytes; + + byte[] wnaf = new byte[k.BitLength + 1]; + + // 2^width and a mask and sign bit set accordingly + int pow2 = 1 << width; + int mask = pow2 - 1; + int sign = pow2 >> 1; + + bool carry = false; + int length = 0, pos = 0; + + while (pos <= k.BitLength) + { + if (k.TestBit(pos) == carry) + { + ++pos; + continue; + } + + k = k.ShiftRight(pos); + + int digit = k.IntValue & mask; + if (carry) + { + ++digit; + } + + carry = (digit & sign) != 0; + if (carry) + { + digit -= pow2; + } + + length += (length > 0) ? pos - 1 : pos; + wnaf[length++] = (byte)digit; + pos = width; + } + + // Reduce the WNAF array to its actual length + if (wnaf.Length > length) + { + wnaf = Trim(wnaf, length); + } + + return wnaf; + } + + public static int GetNafWeight(BigInteger k) + { + if (k.SignValue == 0) + return 0; + + BigInteger _3k = k.ShiftLeft(1).Add(k); + BigInteger diff = _3k.Xor(k); + + return diff.BitCount; + } + + public static WNafPreCompInfo GetWNafPreCompInfo(ECPoint p) + { + return GetWNafPreCompInfo(p.Curve.GetPreCompInfo(p, PRECOMP_NAME)); + } + + public static WNafPreCompInfo GetWNafPreCompInfo(PreCompInfo preCompInfo) + { + return preCompInfo as WNafPreCompInfo; + } + + /** + * Determine window width to use for a scalar multiplication of the given size. + * + * @param bits the bit-length of the scalar to multiply by + * @return the window size to use + */ + public static int GetWindowSize(int bits) + { + return GetWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS); + } + + /** + * Determine window width to use for a scalar multiplication of the given size. + * + * @param bits the bit-length of the scalar to multiply by + * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width + * @return the window size to use + */ + public static int GetWindowSize(int bits, int[] windowSizeCutoffs) + { + int w = 0; + for (; w < windowSizeCutoffs.Length; ++w) + { + if (bits < windowSizeCutoffs[w]) + { + break; + } + } + return w + 2; + } + + public static ECPoint MapPointWithPrecomp(ECPoint p, int width, bool includeNegated, + ECPointMap pointMap) + { + ECCurve c = p.Curve; + WNafPreCompInfo wnafPreCompP = Precompute(p, width, includeNegated); + + ECPoint q = pointMap.Map(p); + c.Precompute(q, PRECOMP_NAME, new MapPointCallback(wnafPreCompP, includeNegated, pointMap)); + return q; + } + + public static WNafPreCompInfo Precompute(ECPoint p, int width, bool includeNegated) + { + return (WNafPreCompInfo)p.Curve.Precompute(p, PRECOMP_NAME, new WNafCallback(p, width, includeNegated)); + } + + private static byte[] Trim(byte[] a, int length) + { + byte[] result = new byte[length]; + Array.Copy(a, 0, result, 0, result.Length); + return result; + } + + private static int[] Trim(int[] a, int length) + { + int[] result = new int[length]; + Array.Copy(a, 0, result, 0, result.Length); + return result; + } + + private static ECPoint[] ResizeTable(ECPoint[] a, int length) + { + ECPoint[] result = new ECPoint[length]; + Array.Copy(a, 0, result, 0, a.Length); + return result; + } + + private class MapPointCallback + : IPreCompCallback + { + private readonly WNafPreCompInfo m_wnafPreCompP; + private readonly bool m_includeNegated; + private readonly ECPointMap m_pointMap; + + internal MapPointCallback(WNafPreCompInfo wnafPreCompP, bool includeNegated, ECPointMap pointMap) + { + this.m_wnafPreCompP = wnafPreCompP; + this.m_includeNegated = includeNegated; + this.m_pointMap = pointMap; + } + + public PreCompInfo Precompute(PreCompInfo existing) + { + WNafPreCompInfo result = new WNafPreCompInfo(); + + ECPoint twiceP = m_wnafPreCompP.Twice; + if (twiceP != null) + { + ECPoint twiceQ = m_pointMap.Map(twiceP); + result.Twice = twiceQ; + } + + ECPoint[] preCompP = m_wnafPreCompP.PreComp; + ECPoint[] preCompQ = new ECPoint[preCompP.Length]; + for (int i = 0; i < preCompP.Length; ++i) + { + preCompQ[i] = m_pointMap.Map(preCompP[i]); + } + result.PreComp = preCompQ; + + if (m_includeNegated) + { + ECPoint[] preCompNegQ = new ECPoint[preCompQ.Length]; + for (int i = 0; i < preCompNegQ.Length; ++i) + { + preCompNegQ[i] = preCompQ[i].Negate(); + } + result.PreCompNeg = preCompNegQ; + } + + return result; + } + } + + private class WNafCallback + : IPreCompCallback + { + private readonly ECPoint m_p; + private readonly int m_width; + private readonly bool m_includeNegated; + + internal WNafCallback(ECPoint p, int width, bool includeNegated) + { + this.m_p = p; + this.m_width = width; + this.m_includeNegated = includeNegated; + } + + public PreCompInfo Precompute(PreCompInfo existing) + { + WNafPreCompInfo existingWNaf = existing as WNafPreCompInfo; + + int reqPreCompLen = 1 << System.Math.Max(0, m_width - 2); + + if (CheckExisting(existingWNaf, reqPreCompLen, m_includeNegated)) + return existingWNaf; + + ECCurve c = m_p.Curve; + ECPoint[] preComp = null, preCompNeg = null; + ECPoint twiceP = null; + + if (existingWNaf != null) + { + preComp = existingWNaf.PreComp; + preCompNeg = existingWNaf.PreCompNeg; + twiceP = existingWNaf.Twice; + } + + int iniPreCompLen = 0; + if (preComp == null) + { + preComp = EMPTY_POINTS; + } + else + { + iniPreCompLen = preComp.Length; + } + + if (iniPreCompLen < reqPreCompLen) + { + preComp = WNafUtilities.ResizeTable(preComp, reqPreCompLen); + + if (reqPreCompLen == 1) + { + preComp[0] = m_p.Normalize(); + } + else + { + int curPreCompLen = iniPreCompLen; + if (curPreCompLen == 0) + { + preComp[0] = m_p; + curPreCompLen = 1; + } + + ECFieldElement iso = null; + + if (reqPreCompLen == 2) + { + preComp[1] = m_p.ThreeTimes(); + } + else + { + ECPoint isoTwiceP = twiceP, last = preComp[curPreCompLen - 1]; + if (isoTwiceP == null) + { + isoTwiceP = preComp[0].Twice(); + twiceP = isoTwiceP; + + /* + * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism + * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This + * also requires scaling the initial point's X, Y coordinates, and reversing the + * isomorphism as part of the subsequent normalization. + * + * NOTE: The correctness of this optimization depends on: + * 1) additions do not use the curve's A, B coefficients. + * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ... + */ + if (!twiceP.IsInfinity && ECAlgorithms.IsFpCurve(c) && c.FieldSize >= 64) + { + switch (c.CoordinateSystem) + { + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + iso = twiceP.GetZCoord(0); + isoTwiceP = c.CreatePoint(twiceP.XCoord.ToBigInteger(), + twiceP.YCoord.ToBigInteger()); + + ECFieldElement iso2 = iso.Square(), iso3 = iso2.Multiply(iso); + last = last.ScaleX(iso2).ScaleY(iso3); + + if (iniPreCompLen == 0) + { + preComp[0] = last; + } + break; + } + } + } + } + + while (curPreCompLen < reqPreCompLen) + { + /* + * Compute the new ECPoints for the precomputation array. The values 1, 3, + * 5, ..., 2^(width-1)-1 times p are computed + */ + preComp[curPreCompLen++] = last = last.Add(isoTwiceP); + } + } + + /* + * Having oft-used operands in affine form makes operations faster. + */ + c.NormalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso); + } + } + + if (m_includeNegated) + { + int pos; + if (preCompNeg == null) + { + pos = 0; + preCompNeg = new ECPoint[reqPreCompLen]; + } + else + { + pos = preCompNeg.Length; + if (pos < reqPreCompLen) + { + preCompNeg = WNafUtilities.ResizeTable(preCompNeg, reqPreCompLen); + } + } + + while (pos < reqPreCompLen) + { + preCompNeg[pos] = preComp[pos].Negate(); + ++pos; + } + } + + WNafPreCompInfo result = new WNafPreCompInfo(); + result.PreComp = preComp; + result.PreCompNeg = preCompNeg; + result.Twice = twiceP; + return result; + } + + private bool CheckExisting(WNafPreCompInfo existingWNaf, int reqPreCompLen, bool includeNegated) + { + return existingWNaf != null + && CheckTable(existingWNaf.PreComp, reqPreCompLen) + && (!includeNegated || CheckTable(existingWNaf.PreCompNeg, reqPreCompLen)); + } + + private bool CheckTable(ECPoint[] table, int reqLen) + { + return table != null && table.Length >= reqLen; + } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WTauNafMultiplier.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WTauNafMultiplier.cs new file mode 100644 index 00000000..1d19bdb6 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WTauNafMultiplier.cs @@ -0,0 +1,138 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Abc; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class implementing the WTNAF (Window + * τ-adic Non-Adjacent Form) algorithm. + */ + internal class WTauNafMultiplier + : AbstractECMultiplier + { + // TODO Create WTauNafUtilities class and move various functionality into it + internal static readonly string PRECOMP_NAME = "bc_wtnaf"; + + /** + * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint} + * by k using the reduced τ-adic NAF (RTNAF) + * method. + * @param p The AbstractF2mPoint to multiply. + * @param k The integer by which to multiply k. + * @return p multiplied by k. + */ + protected override ECPoint MultiplyPositive(ECPoint point, BigInteger k) + { + if (!(point is AbstractF2mPoint)) + throw new ArgumentException("Only AbstractF2mPoint can be used in WTauNafMultiplier"); + + AbstractF2mPoint p = (AbstractF2mPoint)point; + AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve; + int m = curve.FieldSize; + sbyte a = (sbyte)curve.A.ToBigInteger().IntValue; + sbyte mu = Tnaf.GetMu(a); + BigInteger[] s = curve.GetSi(); + + ZTauElement rho = Tnaf.PartModReduction(k, m, a, s, mu, (sbyte)10); + + return MultiplyWTnaf(p, rho, a, mu); + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint} + * by an element λ of Z[τ] using + * the τ-adic NAF (TNAF) method. + * @param p The AbstractF2mPoint to multiply. + * @param lambda The element λ of + * Z[τ] of which to compute the + * [τ]-adic NAF. + * @return p multiplied by λ. + */ + private AbstractF2mPoint MultiplyWTnaf(AbstractF2mPoint p, ZTauElement lambda, + sbyte a, sbyte mu) + { + ZTauElement[] alpha = (a == 0) ? Tnaf.Alpha0 : Tnaf.Alpha1; + + BigInteger tw = Tnaf.GetTw(mu, Tnaf.Width); + + sbyte[]u = Tnaf.TauAdicWNaf(mu, lambda, Tnaf.Width, + BigInteger.ValueOf(Tnaf.Pow2Width), tw, alpha); + + return MultiplyFromWTnaf(p, u); + } + + /** + * Multiplies a {@link org.bouncycastle.math.ec.AbstractF2mPoint AbstractF2mPoint} + * by an element λ of Z[τ] + * using the window τ-adic NAF (TNAF) method, given the + * WTNAF of λ. + * @param p The AbstractF2mPoint to multiply. + * @param u The the WTNAF of λ.. + * @return λ * p + */ + private static AbstractF2mPoint MultiplyFromWTnaf(AbstractF2mPoint p, sbyte[] u) + { + AbstractF2mCurve curve = (AbstractF2mCurve)p.Curve; + sbyte a = (sbyte)curve.A.ToBigInteger().IntValue; + + WTauNafCallback callback = new WTauNafCallback(p, a); + WTauNafPreCompInfo preCompInfo = (WTauNafPreCompInfo)curve.Precompute(p, PRECOMP_NAME, callback); + AbstractF2mPoint[] pu = preCompInfo.PreComp; + + // TODO Include negations in precomp (optionally) and use from here + AbstractF2mPoint[] puNeg = new AbstractF2mPoint[pu.Length]; + for (int i = 0; i < pu.Length; ++i) + { + puNeg[i] = (AbstractF2mPoint)pu[i].Negate(); + } + + + // q = infinity + AbstractF2mPoint q = (AbstractF2mPoint) p.Curve.Infinity; + + int tauCount = 0; + for (int i = u.Length - 1; i >= 0; i--) + { + ++tauCount; + int ui = u[i]; + if (ui != 0) + { + q = q.TauPow(tauCount); + tauCount = 0; + + ECPoint x = ui > 0 ? pu[ui >> 1] : puNeg[(-ui) >> 1]; + q = (AbstractF2mPoint)q.Add(x); + } + } + if (tauCount > 0) + { + q = q.TauPow(tauCount); + } + return q; + } + + private class WTauNafCallback + : IPreCompCallback + { + private readonly AbstractF2mPoint m_p; + private readonly sbyte m_a; + + internal WTauNafCallback(AbstractF2mPoint p, sbyte a) + { + this.m_p = p; + this.m_a = a; + } + + public PreCompInfo Precompute(PreCompInfo existing) + { + if (existing is WTauNafPreCompInfo) + return existing; + + WTauNafPreCompInfo result = new WTauNafPreCompInfo(); + result.PreComp = Tnaf.GetPreComp(m_p, m_a); + return result; + } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WTauNafPreCompInfo.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WTauNafPreCompInfo.cs new file mode 100644 index 00000000..f0a6f489 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/multiplier/WTauNafPreCompInfo.cs @@ -0,0 +1,24 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Multiplier +{ + /** + * Class holding precomputation data for the WTNAF (Window + * τ-adic Non-Adjacent Form) algorithm. + */ + internal class WTauNafPreCompInfo + : PreCompInfo + { + /** + * Array holding the precomputed AbstractF2mPoints used for the + * WTNAF multiplication in + * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply() + * WTauNafMultiplier.multiply()}. + */ + protected AbstractF2mPoint[] m_preComp; + + public virtual AbstractF2mPoint[] PreComp + { + get { return m_preComp; } + set { this.m_preComp = value; } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/field/FiniteFields.cs b/src/Renci.SshNet/Security/BouncyCastle/math/field/FiniteFields.cs new file mode 100644 index 00000000..77533c76 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/field/FiniteFields.cs @@ -0,0 +1,54 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Field +{ + internal abstract class FiniteFields + { + internal static readonly IFiniteField GF_2 = new PrimeField(BigInteger.ValueOf(2)); + internal static readonly IFiniteField GF_3 = new PrimeField(BigInteger.ValueOf(3)); + + public static IPolynomialExtensionField GetBinaryExtensionField(int[] exponents) + { + if (exponents[0] != 0) + { + throw new ArgumentException("Irreducible polynomials in GF(2) must have constant term", "exponents"); + } + for (int i = 1; i < exponents.Length; ++i) + { + if (exponents[i] <= exponents[i - 1]) + { + throw new ArgumentException("Polynomial exponents must be montonically increasing", "exponents"); + } + } + + return new GenericPolynomialExtensionField(GF_2, new GF2Polynomial(exponents)); + } + + // public static IPolynomialExtensionField GetTernaryExtensionField(Term[] terms) + // { + // return new GenericPolynomialExtensionField(GF_3, new GF3Polynomial(terms)); + // } + + public static IFiniteField GetPrimeField(BigInteger characteristic) + { + int bitLength = characteristic.BitLength; + if (characteristic.SignValue <= 0 || bitLength < 2) + { + throw new ArgumentException("Must be >= 2", "characteristic"); + } + + if (bitLength < 3) + { + switch (characteristic.IntValue) + { + case 2: + return GF_2; + case 3: + return GF_3; + } + } + + return new PrimeField(characteristic); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/field/GF2Polynomial.cs b/src/Renci.SshNet/Security/BouncyCastle/math/field/GF2Polynomial.cs new file mode 100644 index 00000000..a7c916db --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/field/GF2Polynomial.cs @@ -0,0 +1,46 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Field +{ + internal class GF2Polynomial + : IPolynomial + { + protected readonly int[] exponents; + + internal GF2Polynomial(int[] exponents) + { + this.exponents = Arrays.Clone(exponents); + } + + public virtual int Degree + { + get { return exponents[exponents.Length - 1]; } + } + + public virtual int[] GetExponentsPresent() + { + return Arrays.Clone(exponents); + } + + public override bool Equals(object obj) + { + if (this == obj) + { + return true; + } + GF2Polynomial other = obj as GF2Polynomial; + if (null == other) + { + return false; + } + return Arrays.AreEqual(exponents, other.exponents); + } + + public override int GetHashCode() + { + return Arrays.GetHashCode(exponents); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/field/GenericPolynomialExtensionField.cs b/src/Renci.SshNet/Security/BouncyCastle/math/field/GenericPolynomialExtensionField.cs new file mode 100644 index 00000000..29b4f57d --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/field/GenericPolynomialExtensionField.cs @@ -0,0 +1,63 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Field +{ + internal class GenericPolynomialExtensionField + : IPolynomialExtensionField + { + protected readonly IFiniteField subfield; + protected readonly IPolynomial minimalPolynomial; + + internal GenericPolynomialExtensionField(IFiniteField subfield, IPolynomial polynomial) + { + this.subfield = subfield; + this.minimalPolynomial = polynomial; + } + + public virtual BigInteger Characteristic + { + get { return subfield.Characteristic; } + } + + public virtual int Dimension + { + get { return subfield.Dimension * minimalPolynomial.Degree; } + } + + public virtual IFiniteField Subfield + { + get { return subfield; } + } + + public virtual int Degree + { + get { return minimalPolynomial.Degree; } + } + + public virtual IPolynomial MinimalPolynomial + { + get { return minimalPolynomial; } + } + + public override bool Equals(object obj) + { + if (this == obj) + { + return true; + } + GenericPolynomialExtensionField other = obj as GenericPolynomialExtensionField; + if (null == other) + { + return false; + } + return subfield.Equals(other.subfield) && minimalPolynomial.Equals(other.minimalPolynomial); + } + + public override int GetHashCode() + { + return subfield.GetHashCode() ^ Integers.RotateLeft(minimalPolynomial.GetHashCode(), 16); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/field/IExtensionField.cs b/src/Renci.SshNet/Security/BouncyCastle/math/field/IExtensionField.cs new file mode 100644 index 00000000..242bcd00 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/field/IExtensionField.cs @@ -0,0 +1,12 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Field +{ + internal interface IExtensionField + : IFiniteField + { + IFiniteField Subfield { get; } + + int Degree { get; } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/field/IFiniteField.cs b/src/Renci.SshNet/Security/BouncyCastle/math/field/IFiniteField.cs new file mode 100644 index 00000000..fa6b6fca --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/field/IFiniteField.cs @@ -0,0 +1,11 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Field +{ + internal interface IFiniteField + { + BigInteger Characteristic { get; } + + int Dimension { get; } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/field/IPolynomial.cs b/src/Renci.SshNet/Security/BouncyCastle/math/field/IPolynomial.cs new file mode 100644 index 00000000..06a61663 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/field/IPolynomial.cs @@ -0,0 +1,13 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Field +{ + internal interface IPolynomial + { + int Degree { get; } + + //BigInteger[] GetCoefficients(); + + int[] GetExponentsPresent(); + + //Term[] GetNonZeroTerms(); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/field/IPolynomialExtensionField.cs b/src/Renci.SshNet/Security/BouncyCastle/math/field/IPolynomialExtensionField.cs new file mode 100644 index 00000000..a419bec8 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/field/IPolynomialExtensionField.cs @@ -0,0 +1,8 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Field +{ + internal interface IPolynomialExtensionField + : IExtensionField + { + IPolynomial MinimalPolynomial { get; } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/field/PrimeField.cs b/src/Renci.SshNet/Security/BouncyCastle/math/field/PrimeField.cs new file mode 100644 index 00000000..c0651e14 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/field/PrimeField.cs @@ -0,0 +1,42 @@ +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Field +{ + internal class PrimeField + : IFiniteField + { + protected readonly BigInteger characteristic; + + internal PrimeField(BigInteger characteristic) + { + this.characteristic = characteristic; + } + + public virtual BigInteger Characteristic + { + get { return characteristic; } + } + + public virtual int Dimension + { + get { return 1; } + } + + public override bool Equals(object obj) + { + if (this == obj) + { + return true; + } + PrimeField other = obj as PrimeField; + if (null == other) + { + return false; + } + return characteristic.Equals(other.characteristic); + } + + public override int GetHashCode() + { + return characteristic.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/raw/Mod.cs b/src/Renci.SshNet/Security/BouncyCastle/math/raw/Mod.cs new file mode 100644 index 00000000..1fa6b6da --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/raw/Mod.cs @@ -0,0 +1,185 @@ +using System; +using System.Diagnostics; + +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Utilities; +using Renci.SshNet.Security.Org.BouncyCastle.Security; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Raw +{ + internal abstract class Mod + { + private static readonly SecureRandom RandomSource = new SecureRandom(); + + public static void Invert(uint[] p, uint[] x, uint[] z) + { + int len = p.Length; + if (Nat.IsZero(len, x)) + throw new ArgumentException("cannot be 0", "x"); + if (Nat.IsOne(len, x)) + { + Array.Copy(x, 0, z, 0, len); + return; + } + + uint[] u = Nat.Copy(len, x); + uint[] a = Nat.Create(len); + a[0] = 1; + int ac = 0; + + if ((u[0] & 1) == 0) + { + InversionStep(p, u, len, a, ref ac); + } + if (Nat.IsOne(len, u)) + { + InversionResult(p, ac, a, z); + return; + } + + uint[] v = Nat.Copy(len, p); + uint[] b = Nat.Create(len); + int bc = 0; + + int uvLen = len; + + for (;;) + { + while (u[uvLen - 1] == 0 && v[uvLen - 1] == 0) + { + --uvLen; + } + + if (Nat.Gte(len, u, v)) + { + Nat.SubFrom(len, v, u); + Debug.Assert((u[0] & 1) == 0); + ac += Nat.SubFrom(len, b, a) - bc; + InversionStep(p, u, uvLen, a, ref ac); + if (Nat.IsOne(len, u)) + { + InversionResult(p, ac, a, z); + return; + } + } + else + { + Nat.SubFrom(len, u, v); + Debug.Assert((v[0] & 1) == 0); + bc += Nat.SubFrom(len, a, b) - ac; + InversionStep(p, v, uvLen, b, ref bc); + if (Nat.IsOne(len, v)) + { + InversionResult(p, bc, b, z); + return; + } + } + } + } + + public static uint[] Random(uint[] p) + { + int len = p.Length; + uint[] s = Nat.Create(len); + + uint m = p[len - 1]; + m |= m >> 1; + m |= m >> 2; + m |= m >> 4; + m |= m >> 8; + m |= m >> 16; + + do + { + byte[] bytes = new byte[len << 2]; + RandomSource.NextBytes(bytes); + Pack.BE_To_UInt32(bytes, 0, s); + s[len - 1] &= m; + } + while (Nat.Gte(len, s, p)); + + return s; + } + + public static void Add(uint[] p, uint[] x, uint[] y, uint[] z) + { + int len = p.Length; + uint c = Nat.Add(len, x, y, z); + if (c != 0) + { + Nat.SubFrom(len, p, z); + } + } + + public static void Subtract(uint[] p, uint[] x, uint[] y, uint[] z) + { + int len = p.Length; + int c = Nat.Sub(len, x, y, z); + if (c != 0) + { + Nat.AddTo(len, p, z); + } + } + + private static void InversionResult(uint[] p, int ac, uint[] a, uint[] z) + { + if (ac < 0) + { + Nat.Add(p.Length, a, p, z); + } + else + { + Array.Copy(a, 0, z, 0, p.Length); + } + } + + private static void InversionStep(uint[] p, uint[] u, int uLen, uint[] x, ref int xc) + { + int len = p.Length; + int count = 0; + while (u[0] == 0) + { + Nat.ShiftDownWord(uLen, u, 0); + count += 32; + } + + { + int zeroes = GetTrailingZeroes(u[0]); + if (zeroes > 0) + { + Nat.ShiftDownBits(uLen, u, zeroes, 0); + count += zeroes; + } + } + + for (int i = 0; i < count; ++i) + { + if ((x[0] & 1) != 0) + { + if (xc < 0) + { + xc += (int)Nat.AddTo(len, p, x); + } + else + { + xc += Nat.SubFrom(len, p, x); + } + } + + Debug.Assert(xc == 0 || xc == -1); + Nat.ShiftDownBit(len, x, (uint)xc); + } + } + + private static int GetTrailingZeroes(uint x) + { + Debug.Assert(x != 0); + int count = 0; + while ((x & 1) == 0) + { + x >>= 1; + ++count; + } + return count; + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/raw/Nat.cs b/src/Renci.SshNet/Security/BouncyCastle/math/raw/Nat.cs new file mode 100644 index 00000000..710c2497 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/math/raw/Nat.cs @@ -0,0 +1,1153 @@ +using System; +using System.Diagnostics; + +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Math.Raw +{ + internal abstract class Nat + { + private const ulong M = 0xFFFFFFFFUL; + + public static uint Add(int len, uint[] x, uint[] y, uint[] z) + { + ulong c = 0; + for (int i = 0; i < len; ++i) + { + c += (ulong)x[i] + y[i]; + z[i] = (uint)c; + c >>= 32; + } + return (uint)c; + } + + public static uint Add33At(int len, uint x, uint[] z, int zPos) + { + Debug.Assert(zPos <= (len - 2)); + ulong c = (ulong)z[zPos + 0] + x; + z[zPos + 0] = (uint)c; + c >>= 32; + c += (ulong)z[zPos + 1] + 1; + z[zPos + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zPos + 2); + } + + public static uint Add33At(int len, uint x, uint[] z, int zOff, int zPos) + { + Debug.Assert(zPos <= (len - 2)); + ulong c = (ulong)z[zOff + zPos] + x; + z[zOff + zPos] = (uint)c; + c >>= 32; + c += (ulong)z[zOff + zPos + 1] + 1; + z[zOff + zPos + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 2); + } + + public static uint Add33To(int len, uint x, uint[] z) + { + ulong c = (ulong)z[0] + x; + z[0] = (uint)c; + c >>= 32; + c += (ulong)z[1] + 1; + z[1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, 2); + } + + public static uint Add33To(int len, uint x, uint[] z, int zOff) + { + ulong c = (ulong)z[zOff + 0] + x; + z[zOff + 0] = (uint)c; + c >>= 32; + c += (ulong)z[zOff + 1] + 1; + z[zOff + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zOff, 2); + } + + public static uint AddBothTo(int len, uint[] x, uint[] y, uint[] z) + { + ulong c = 0; + for (int i = 0; i < len; ++i) + { + c += (ulong)x[i] + y[i] + z[i]; + z[i] = (uint)c; + c >>= 32; + } + return (uint)c; + } + + public static uint AddBothTo(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff) + { + ulong c = 0; + for (int i = 0; i < len; ++i) + { + c += (ulong)x[xOff + i] + y[yOff + i] + z[zOff + i]; + z[zOff + i] = (uint)c; + c >>= 32; + } + return (uint)c; + } + + public static uint AddDWordAt(int len, ulong x, uint[] z, int zPos) + { + Debug.Assert(zPos <= (len - 2)); + ulong c = (ulong)z[zPos + 0] + (x & M); + z[zPos + 0] = (uint)c; + c >>= 32; + c += (ulong)z[zPos + 1] + (x >> 32); + z[zPos + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zPos + 2); + } + + public static uint AddDWordAt(int len, ulong x, uint[] z, int zOff, int zPos) + { + Debug.Assert(zPos <= (len - 2)); + ulong c = (ulong)z[zOff + zPos] + (x & M); + z[zOff + zPos] = (uint)c; + c >>= 32; + c += (ulong)z[zOff + zPos + 1] + (x >> 32); + z[zOff + zPos + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 2); + } + + public static uint AddDWordTo(int len, ulong x, uint[] z) + { + ulong c = (ulong)z[0] + (x & M); + z[0] = (uint)c; + c >>= 32; + c += (ulong)z[1] + (x >> 32); + z[1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, 2); + } + + public static uint AddDWordTo(int len, ulong x, uint[] z, int zOff) + { + ulong c = (ulong)z[zOff + 0] + (x & M); + z[zOff + 0] = (uint)c; + c >>= 32; + c += (ulong)z[zOff + 1] + (x >> 32); + z[zOff + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zOff, 2); + } + + public static uint AddTo(int len, uint[] x, uint[] z) + { + ulong c = 0; + for (int i = 0; i < len; ++i) + { + c += (ulong)x[i] + z[i]; + z[i] = (uint)c; + c >>= 32; + } + return (uint)c; + } + + public static uint AddTo(int len, uint[] x, int xOff, uint[] z, int zOff) + { + ulong c = 0; + for (int i = 0; i < len; ++i) + { + c += (ulong)x[xOff + i] + z[zOff + i]; + z[zOff + i] = (uint)c; + c >>= 32; + } + return (uint)c; + } + + public static uint AddWordAt(int len, uint x, uint[] z, int zPos) + { + Debug.Assert(zPos <= (len - 1)); + ulong c = (ulong)x + z[zPos]; + z[zPos] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zPos + 1); + } + + public static uint AddWordAt(int len, uint x, uint[] z, int zOff, int zPos) + { + Debug.Assert(zPos <= (len - 1)); + ulong c = (ulong)x + z[zOff + zPos]; + z[zOff + zPos] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zOff, zPos + 1); + } + + public static uint AddWordTo(int len, uint x, uint[] z) + { + ulong c = (ulong)x + z[0]; + z[0] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, 1); + } + + public static uint AddWordTo(int len, uint x, uint[] z, int zOff) + { + ulong c = (ulong)x + z[zOff]; + z[zOff] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zOff, 1); + } + + public static uint CAdd(int len, int mask, uint[] x, uint[] y, uint[] z) + { + uint MASK = (uint)-(mask & 1); + + ulong c = 0; + for (int i = 0; i < len; ++i) + { + c += (ulong)x[i] + (y[i] & MASK); + z[i] = (uint)c; + c >>= 32; + } + return (uint)c; + } + + public static void CMov(int len, int mask, uint[] x, int xOff, uint[] z, int zOff) + { + uint MASK = (uint)-(mask & 1); + + for (int i = 0; i < len; ++i) + { + uint z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + z_i ^= (diff & MASK); + z[zOff + i] = z_i; + } + + //uint half = 0x55555555U, rest = half << (-(int)MASK); + + //for (int i = 0; i < len; ++i) + //{ + // uint z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + // z_i ^= (diff & half); + // z_i ^= (diff & rest); + // z[zOff + i] = z_i; + //} + } + + public static void CMov(int len, int mask, int[] x, int xOff, int[] z, int zOff) + { + mask = -(mask & 1); + + for (int i = 0; i < len; ++i) + { + int z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + z_i ^= (diff & mask); + z[zOff + i] = z_i; + } + + //int half = 0x55555555, rest = half << (-mask); + + //for (int i = 0; i < len; ++i) + //{ + // int z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + // z_i ^= (diff & half); + // z_i ^= (diff & rest); + // z[zOff + i] = z_i; + //} + } + + public static void Copy(int len, uint[] x, uint[] z) + { + Array.Copy(x, 0, z, 0, len); + } + + public static uint[] Copy(int len, uint[] x) + { + uint[] z = new uint[len]; + Array.Copy(x, 0, z, 0, len); + return z; + } + + public static void Copy(int len, uint[] x, int xOff, uint[] z, int zOff) + { + Array.Copy(x, xOff, z, zOff, len); + } + + public static uint[] Create(int len) + { + return new uint[len]; + } + + public static ulong[] Create64(int len) + { + return new ulong[len]; + } + + public static int Dec(int len, uint[] z) + { + for (int i = 0; i < len; ++i) + { + if (--z[i] != uint.MaxValue) + { + return 0; + } + } + return -1; + } + + public static int Dec(int len, uint[] x, uint[] z) + { + int i = 0; + while (i < len) + { + uint c = x[i] - 1; + z[i] = c; + ++i; + if (c != uint.MaxValue) + { + while (i < len) + { + z[i] = x[i]; + ++i; + } + return 0; + } + } + return -1; + } + + public static int DecAt(int len, uint[] z, int zPos) + { + Debug.Assert(zPos <= len); + for (int i = zPos; i < len; ++i) + { + if (--z[i] != uint.MaxValue) + { + return 0; + } + } + return -1; + } + + public static int DecAt(int len, uint[] z, int zOff, int zPos) + { + Debug.Assert(zPos <= len); + for (int i = zPos; i < len; ++i) + { + if (--z[zOff + i] != uint.MaxValue) + { + return 0; + } + } + return -1; + } + + public static bool Eq(int len, uint[] x, uint[] y) + { + for (int i = len - 1; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + + public static uint[] FromBigInteger(int bits, BigInteger x) + { + if (x.SignValue < 0 || x.BitLength > bits) + throw new ArgumentException(); + + int len = (bits + 31) >> 5; + uint[] z = Create(len); + int i = 0; + while (x.SignValue != 0) + { + z[i++] = (uint)x.IntValue; + x = x.ShiftRight(32); + } + return z; + } + + public static uint GetBit(uint[] x, int bit) + { + if (bit == 0) + { + return x[0] & 1; + } + int w = bit >> 5; + if (w < 0 || w >= x.Length) + { + return 0; + } + int b = bit & 31; + return (x[w] >> b) & 1; + } + + public static bool Gte(int len, uint[] x, uint[] y) + { + for (int i = len - 1; i >= 0; --i) + { + uint x_i = x[i], y_i = y[i]; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static uint Inc(int len, uint[] z) + { + for (int i = 0; i < len; ++i) + { + if (++z[i] != uint.MinValue) + { + return 0; + } + } + return 1; + } + + public static uint Inc(int len, uint[] x, uint[] z) + { + int i = 0; + while (i < len) + { + uint c = x[i] + 1; + z[i] = c; + ++i; + if (c != 0) + { + while (i < len) + { + z[i] = x[i]; + ++i; + } + return 0; + } + } + return 1; + } + + public static uint IncAt(int len, uint[] z, int zPos) + { + Debug.Assert(zPos <= len); + for (int i = zPos; i < len; ++i) + { + if (++z[i] != uint.MinValue) + { + return 0; + } + } + return 1; + } + + public static uint IncAt(int len, uint[] z, int zOff, int zPos) + { + Debug.Assert(zPos <= len); + for (int i = zPos; i < len; ++i) + { + if (++z[zOff + i] != uint.MinValue) + { + return 0; + } + } + return 1; + } + + public static bool IsOne(int len, uint[] x) + { + if (x[0] != 1) + { + return false; + } + for (int i = 1; i < len; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static bool IsZero(int len, uint[] x) + { + if (x[0] != 0) + { + return false; + } + for (int i = 1; i < len; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static void Mul(int len, uint[] x, uint[] y, uint[] zz) + { + zz[len] = MulWord(len, x[0], y, zz); + + for (int i = 1; i < len; ++i) + { + zz[i + len] = MulWordAddTo(len, x[i], y, 0, zz, i); + } + } + + public static void Mul(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff) + { + zz[zzOff + len] = MulWord(len, x[xOff], y, yOff, zz, zzOff); + + for (int i = 1; i < len; ++i) + { + zz[zzOff + i + len] = MulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i); + } + } + + public static void Mul(uint[] x, int xOff, int xLen, uint[] y, int yOff, int yLen, uint[] zz, int zzOff) + { + zz[zzOff + yLen] = MulWord(yLen, x[xOff], y, yOff, zz, zzOff); + + for (int i = 1; i < xLen; ++i) + { + zz[zzOff + i + yLen] = MulWordAddTo(yLen, x[xOff + i], y, yOff, zz, zzOff + i); + } + } + + public static uint MulAddTo(int len, uint[] x, uint[] y, uint[] zz) + { + ulong zc = 0; + for (int i = 0; i < len; ++i) + { + ulong c = MulWordAddTo(len, x[i], y, 0, zz, i) & M; + c += zc + (zz[i + len] & M); + zz[i + len] = (uint)c; + zc = c >> 32; + } + return (uint)zc; + } + + public static uint MulAddTo(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] zz, int zzOff) + { + ulong zc = 0; + for (int i = 0; i < len; ++i) + { + ulong c = MulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M; + c += zc + (zz[zzOff + len] & M); + zz[zzOff + len] = (uint)c; + zc = c >> 32; + ++zzOff; + } + return (uint)zc; + } + + public static uint Mul31BothAdd(int len, uint a, uint[] x, uint b, uint[] y, uint[] z, int zOff) + { + ulong c = 0, aVal = (ulong)a, bVal = (ulong)b; + int i = 0; + do + { + c += aVal * x[i] + bVal * y[i] + z[zOff + i]; + z[zOff + i] = (uint)c; + c >>= 32; + } + while (++i < len); + return (uint)c; + } + + public static uint MulWord(int len, uint x, uint[] y, uint[] z) + { + ulong c = 0, xVal = (ulong)x; + int i = 0; + do + { + c += xVal * y[i]; + z[i] = (uint)c; + c >>= 32; + } + while (++i < len); + return (uint)c; + } + + public static uint MulWord(int len, uint x, uint[] y, int yOff, uint[] z, int zOff) + { + ulong c = 0, xVal = (ulong)x; + int i = 0; + do + { + c += xVal * y[yOff + i]; + z[zOff + i] = (uint)c; + c >>= 32; + } + while (++i < len); + return (uint)c; + } + + public static uint MulWordAddTo(int len, uint x, uint[] y, int yOff, uint[] z, int zOff) + { + ulong c = 0, xVal = (ulong)x; + int i = 0; + do + { + c += xVal * y[yOff + i] + z[zOff + i]; + z[zOff + i] = (uint)c; + c >>= 32; + } + while (++i < len); + return (uint)c; + } + + public static uint MulWordDwordAddAt(int len, uint x, ulong y, uint[] z, int zPos) + { + Debug.Assert(zPos <= (len - 3)); + ulong c = 0, xVal = (ulong)x; + c += xVal * (uint)y + z[zPos + 0]; + z[zPos + 0] = (uint)c; + c >>= 32; + c += xVal * (y >> 32) + z[zPos + 1]; + z[zPos + 1] = (uint)c; + c >>= 32; + c += (ulong)z[zPos + 2]; + z[zPos + 2] = (uint)c; + c >>= 32; + return c == 0 ? 0 : IncAt(len, z, zPos + 3); + } + + public static uint ShiftDownBit(int len, uint[] z, uint c) + { + int i = len; + while (--i >= 0) + { + uint next = z[i]; + z[i] = (next >> 1) | (c << 31); + c = next; + } + return c << 31; + } + + public static uint ShiftDownBit(int len, uint[] z, int zOff, uint c) + { + int i = len; + while (--i >= 0) + { + uint next = z[zOff + i]; + z[zOff + i] = (next >> 1) | (c << 31); + c = next; + } + return c << 31; + } + + public static uint ShiftDownBit(int len, uint[] x, uint c, uint[] z) + { + int i = len; + while (--i >= 0) + { + uint next = x[i]; + z[i] = (next >> 1) | (c << 31); + c = next; + } + return c << 31; + } + + public static uint ShiftDownBit(int len, uint[] x, int xOff, uint c, uint[] z, int zOff) + { + int i = len; + while (--i >= 0) + { + uint next = x[xOff + i]; + z[zOff + i] = (next >> 1) | (c << 31); + c = next; + } + return c << 31; + } + + public static uint ShiftDownBits(int len, uint[] z, int bits, uint c) + { + Debug.Assert(bits > 0 && bits < 32); + int i = len; + while (--i >= 0) + { + uint next = z[i]; + z[i] = (next >> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static uint ShiftDownBits(int len, uint[] z, int zOff, int bits, uint c) + { + Debug.Assert(bits > 0 && bits < 32); + int i = len; + while (--i >= 0) + { + uint next = z[zOff + i]; + z[zOff + i] = (next >> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static uint ShiftDownBits(int len, uint[] x, int bits, uint c, uint[] z) + { + Debug.Assert(bits > 0 && bits < 32); + int i = len; + while (--i >= 0) + { + uint next = x[i]; + z[i] = (next >> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static uint ShiftDownBits(int len, uint[] x, int xOff, int bits, uint c, uint[] z, int zOff) + { + Debug.Assert(bits > 0 && bits < 32); + int i = len; + while (--i >= 0) + { + uint next = x[xOff + i]; + z[zOff + i] = (next >> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static uint ShiftDownWord(int len, uint[] z, uint c) + { + int i = len; + while (--i >= 0) + { + uint next = z[i]; + z[i] = c; + c = next; + } + return c; + } + + public static uint ShiftUpBit(int len, uint[] z, uint c) + { + for (int i = 0; i < len; ++i) + { + uint next = z[i]; + z[i] = (next << 1) | (c >> 31); + c = next; + } + return c >> 31; + } + + public static uint ShiftUpBit(int len, uint[] z, int zOff, uint c) + { + for (int i = 0; i < len; ++i) + { + uint next = z[zOff + i]; + z[zOff + i] = (next << 1) | (c >> 31); + c = next; + } + return c >> 31; + } + + public static uint ShiftUpBit(int len, uint[] x, uint c, uint[] z) + { + for (int i = 0; i < len; ++i) + { + uint next = x[i]; + z[i] = (next << 1) | (c >> 31); + c = next; + } + return c >> 31; + } + + public static uint ShiftUpBit(int len, uint[] x, int xOff, uint c, uint[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + uint next = x[xOff + i]; + z[zOff + i] = (next << 1) | (c >> 31); + c = next; + } + return c >> 31; + } + + public static ulong ShiftUpBit64(int len, ulong[] x, int xOff, ulong c, ulong[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + ulong next = x[xOff + i]; + z[zOff + i] = (next << 1) | (c >> 63); + c = next; + } + return c >> 63; + } + + public static uint ShiftUpBits(int len, uint[] z, int bits, uint c) + { + Debug.Assert(bits > 0 && bits < 32); + for (int i = 0; i < len; ++i) + { + uint next = z[i]; + z[i] = (next << bits) | (c >> -bits); + c = next; + } + return c >> -bits; + } + + public static uint ShiftUpBits(int len, uint[] z, int zOff, int bits, uint c) + { + Debug.Assert(bits > 0 && bits < 32); + for (int i = 0; i < len; ++i) + { + uint next = z[zOff + i]; + z[zOff + i] = (next << bits) | (c >> -bits); + c = next; + } + return c >> -bits; + } + + public static ulong ShiftUpBits64(int len, ulong[] z, int zOff, int bits, ulong c) + { + Debug.Assert(bits > 0 && bits < 64); + for (int i = 0; i < len; ++i) + { + ulong next = z[zOff + i]; + z[zOff + i] = (next << bits) | (c >> -bits); + c = next; + } + return c >> -bits; + } + + public static uint ShiftUpBits(int len, uint[] x, int bits, uint c, uint[] z) + { + Debug.Assert(bits > 0 && bits < 32); + for (int i = 0; i < len; ++i) + { + uint next = x[i]; + z[i] = (next << bits) | (c >> -bits); + c = next; + } + return c >> -bits; + } + + public static uint ShiftUpBits(int len, uint[] x, int xOff, int bits, uint c, uint[] z, int zOff) + { + Debug.Assert(bits > 0 && bits < 32); + for (int i = 0; i < len; ++i) + { + uint next = x[xOff + i]; + z[zOff + i] = (next << bits) | (c >> -bits); + c = next; + } + return c >> -bits; + } + + public static ulong ShiftUpBits64(int len, ulong[] x, int xOff, int bits, ulong c, ulong[] z, int zOff) + { + Debug.Assert(bits > 0 && bits < 64); + for (int i = 0; i < len; ++i) + { + ulong next = x[xOff + i]; + z[zOff + i] = (next << bits) | (c >> -bits); + c = next; + } + return c >> -bits; + } + + public static void Square(int len, uint[] x, uint[] zz) + { + int extLen = len << 1; + uint c = 0; + int j = len, k = extLen; + do + { + ulong xVal = (ulong)x[--j]; + ulong p = xVal * xVal; + zz[--k] = (c << 31) | (uint)(p >> 33); + zz[--k] = (uint)(p >> 1); + c = (uint)p; + } + while (j > 0); + + for (int i = 1; i < len; ++i) + { + c = SquareWordAdd(x, i, zz); + AddWordAt(extLen, c, zz, i << 1); + } + + ShiftUpBit(extLen, zz, x[0] << 31); + } + + public static void Square(int len, uint[] x, int xOff, uint[] zz, int zzOff) + { + int extLen = len << 1; + uint c = 0; + int j = len, k = extLen; + do + { + ulong xVal = (ulong)x[xOff + --j]; + ulong p = xVal * xVal; + zz[zzOff + --k] = (c << 31) | (uint)(p >> 33); + zz[zzOff + --k] = (uint)(p >> 1); + c = (uint)p; + } + while (j > 0); + + for (int i = 1; i < len; ++i) + { + c = SquareWordAdd(x, xOff, i, zz, zzOff); + AddWordAt(extLen, c, zz, zzOff, i << 1); + } + + ShiftUpBit(extLen, zz, zzOff, x[xOff] << 31); + } + + public static uint SquareWordAdd(uint[] x, int xPos, uint[] z) + { + ulong c = 0, xVal = (ulong)x[xPos]; + int i = 0; + do + { + c += xVal * x[i] + z[xPos + i]; + z[xPos + i] = (uint)c; + c >>= 32; + } + while (++i < xPos); + return (uint)c; + } + + public static uint SquareWordAdd(uint[] x, int xOff, int xPos, uint[] z, int zOff) + { + ulong c = 0, xVal = (ulong)x[xOff + xPos]; + int i = 0; + do + { + c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M); + z[xPos + zOff] = (uint)c; + c >>= 32; + ++zOff; + } + while (++i < xPos); + return (uint)c; + } + + public static int Sub(int len, uint[] x, uint[] y, uint[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (long)x[i] - y[i]; + z[i] = (uint)c; + c >>= 32; + } + return (int)c; + } + + public static int Sub(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (long)x[xOff + i] - y[yOff + i]; + z[zOff + i] = (uint)c; + c >>= 32; + } + return (int)c; + } + public static int Sub33At(int len, uint x, uint[] z, int zPos) + { + Debug.Assert(zPos <= (len - 2)); + long c = (long)z[zPos + 0] - x; + z[zPos + 0] = (uint)c; + c >>= 32; + c += (long)z[zPos + 1] - 1; + z[zPos + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zPos + 2); + } + + public static int Sub33At(int len, uint x, uint[] z, int zOff, int zPos) + { + Debug.Assert(zPos <= (len - 2)); + long c = (long)z[zOff + zPos] - x; + z[zOff + zPos] = (uint)c; + c >>= 32; + c += (long)z[zOff + zPos + 1] - 1; + z[zOff + zPos + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zOff, zPos + 2); + } + + public static int Sub33From(int len, uint x, uint[] z) + { + long c = (long)z[0] - x; + z[0] = (uint)c; + c >>= 32; + c += (long)z[1] - 1; + z[1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, 2); + } + + public static int Sub33From(int len, uint x, uint[] z, int zOff) + { + long c = (long)z[zOff + 0] - x; + z[zOff + 0] = (uint)c; + c >>= 32; + c += (long)z[zOff + 1] - 1; + z[zOff + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zOff, 2); + } + + public static int SubBothFrom(int len, uint[] x, uint[] y, uint[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (long)z[i] - x[i] - y[i]; + z[i] = (uint)c; + c >>= 32; + } + return (int)c; + } + + public static int SubBothFrom(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (long)z[zOff + i] - x[xOff + i] - y[yOff + i]; + z[zOff + i] = (uint)c; + c >>= 32; + } + return (int)c; + } + + public static int SubDWordAt(int len, ulong x, uint[] z, int zPos) + { + Debug.Assert(zPos <= (len - 2)); + long c = (long)z[zPos + 0] - (long)(x & M); + z[zPos + 0] = (uint)c; + c >>= 32; + c += (long)z[zPos + 1] - (long)(x >> 32); + z[zPos + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zPos + 2); + } + + public static int SubDWordAt(int len, ulong x, uint[] z, int zOff, int zPos) + { + Debug.Assert(zPos <= (len - 2)); + long c = (long)z[zOff + zPos] - (long)(x & M); + z[zOff + zPos] = (uint)c; + c >>= 32; + c += (long)z[zOff + zPos + 1] - (long)(x >> 32); + z[zOff + zPos + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zOff, zPos + 2); + } + + public static int SubDWordFrom(int len, ulong x, uint[] z) + { + long c = (long)z[0] - (long)(x & M); + z[0] = (uint)c; + c >>= 32; + c += (long)z[1] - (long)(x >> 32); + z[1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, 2); + } + + public static int SubDWordFrom(int len, ulong x, uint[] z, int zOff) + { + long c = (long)z[zOff + 0] - (long)(x & M); + z[zOff + 0] = (uint)c; + c >>= 32; + c += (long)z[zOff + 1] - (long)(x >> 32); + z[zOff + 1] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zOff, 2); + } + + public static int SubFrom(int len, uint[] x, uint[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (long)z[i] - x[i]; + z[i] = (uint)c; + c >>= 32; + } + return (int)c; + } + + public static int SubFrom(int len, uint[] x, int xOff, uint[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (long)z[zOff + i] - x[xOff + i]; + z[zOff + i] = (uint)c; + c >>= 32; + } + return (int)c; + } + + public static int SubWordAt(int len, uint x, uint[] z, int zPos) + { + Debug.Assert(zPos <= (len - 1)); + long c = (long)z[zPos] - x; + z[zPos] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zPos + 1); + } + + public static int SubWordAt(int len, uint x, uint[] z, int zOff, int zPos) + { + Debug.Assert(zPos <= (len - 1)); + long c = (long)z[zOff + zPos] - x; + z[zOff + zPos] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zOff, zPos + 1); + } + + public static int SubWordFrom(int len, uint x, uint[] z) + { + long c = (long)z[0] - x; + z[0] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, 1); + } + + public static int SubWordFrom(int len, uint x, uint[] z, int zOff) + { + long c = (long)z[zOff + 0] - x; + z[zOff + 0] = (uint)c; + c >>= 32; + return c == 0 ? 0 : DecAt(len, z, zOff, 1); + } + + public static BigInteger ToBigInteger(int len, uint[] x) + { + byte[] bs = new byte[len << 2]; + for (int i = 0; i < len; ++i) + { + uint x_i = x[i]; + if (x_i != 0) + { + Pack.UInt32_To_BE(x_i, bs, (len - 1 - i) << 2); + } + } + return new BigInteger(1, bs); + } + + public static void Zero(int len, uint[] z) + { + for (int i = 0; i < len; ++i) + { + z[i] = 0; + } + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/security/DigestUtilities.cs b/src/Renci.SshNet/Security/BouncyCastle/security/DigestUtilities.cs new file mode 100644 index 00000000..06fbd9a6 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/security/DigestUtilities.cs @@ -0,0 +1,34 @@ +using Renci.SshNet.Security.Org.BouncyCastle.Crypto; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Security +{ + /// + /// Utility class for creating IDigest objects from their names/Oids + /// + internal sealed class DigestUtilities + { + private enum DigestAlgorithm { + SHA_256 + }; + + private DigestUtilities() + { + } + + public static byte[] DoFinal( + IDigest digest) + { + byte[] b = new byte[digest.GetDigestSize()]; + digest.DoFinal(b, 0); + return b; + } + + public static byte[] DoFinal( + IDigest digest, + byte[] input) + { + digest.BlockUpdate(input, 0, input.Length); + return DoFinal(digest); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/security/SecureRandom.cs b/src/Renci.SshNet/Security/BouncyCastle/security/SecureRandom.cs new file mode 100644 index 00000000..377817e0 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/security/SecureRandom.cs @@ -0,0 +1,177 @@ +using System; +using System.Threading; + +using Renci.SshNet.Security.Org.BouncyCastle.Crypto; +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Digests; +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Prng; +using Renci.SshNet.Security.Org.BouncyCastle.Utilities; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Security +{ + internal class SecureRandom + : Random + { + private static long counter = Times.NanoTime(); + + private static long NextCounterValue() + { + return Interlocked.Increment(ref counter); + } + + private static readonly SecureRandom master = new SecureRandom(new CryptoApiRandomGenerator()); + private static SecureRandom Master + { + get { return master; } + } + + private static DigestRandomGenerator CreatePrng(IDigest digest, bool autoSeed) + { + DigestRandomGenerator prng = new DigestRandomGenerator(digest); + if (autoSeed) + { + prng.AddSeedMaterial(NextCounterValue()); + prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize())); + } + return prng; + } + + public static byte[] GetNextBytes(SecureRandom secureRandom, int length) + { + byte[] result = new byte[length]; + secureRandom.NextBytes(result); + return result; + } + + protected readonly IRandomGenerator generator; + + public SecureRandom() + : this(CreatePrng(new Sha256Digest(), true)) + { + } + + /// Use the specified instance of IRandomGenerator as random source. + /// + /// This constructor performs no seeding of either the IRandomGenerator or the + /// constructed SecureRandom. It is the responsibility of the client to provide + /// proper seed material as necessary/appropriate for the given IRandomGenerator + /// implementation. + /// + /// The source to generate all random bytes from. + public SecureRandom(IRandomGenerator generator) + : base(0) + { + this.generator = generator; + } + + public virtual byte[] GenerateSeed(int length) + { + return GetNextBytes(Master, length); + } + + public virtual void SetSeed(byte[] seed) + { + generator.AddSeedMaterial(seed); + } + + public virtual void SetSeed(long seed) + { + generator.AddSeedMaterial(seed); + } + + public override int Next() + { + return NextInt() & int.MaxValue; + } + + public override int Next(int maxValue) + { + + if (maxValue < 2) + { + if (maxValue < 0) + throw new ArgumentOutOfRangeException("maxValue", "cannot be negative"); + + return 0; + } + + int bits; + + // Test whether maxValue is a power of 2 + if ((maxValue & (maxValue - 1)) == 0) + { + bits = NextInt() & int.MaxValue; + return (int)(((long)bits * maxValue) >> 31); + } + + int result; + do + { + bits = NextInt() & int.MaxValue; + result = bits % maxValue; + } + while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow + + return result; + } + + public override int Next(int minValue, int maxValue) + { + if (maxValue <= minValue) + { + if (maxValue == minValue) + return minValue; + + throw new ArgumentException("maxValue cannot be less than minValue"); + } + + int diff = maxValue - minValue; + if (diff > 0) + return minValue + Next(diff); + + for (;;) + { + int i = NextInt(); + + if (i >= minValue && i < maxValue) + return i; + } + } + + public override void NextBytes(byte[] buf) + { + generator.NextBytes(buf); + } + + public virtual void NextBytes(byte[] buf, int off, int len) + { + generator.NextBytes(buf, off, len); + } + + private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0); + + public override double NextDouble() + { + return Convert.ToDouble((ulong) NextLong()) / DoubleScale; + } + + public virtual int NextInt() + { + byte[] bytes = new byte[4]; + NextBytes(bytes); + + uint result = bytes[0]; + result <<= 8; + result |= bytes[1]; + result <<= 8; + result |= bytes[2]; + result <<= 8; + result |= bytes[3]; + return (int)result; + } + + public virtual long NextLong() + { + return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt(); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/security/SecurityUtilityException.cs b/src/Renci.SshNet/Security/BouncyCastle/security/SecurityUtilityException.cs new file mode 100644 index 00000000..25a442e4 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/security/SecurityUtilityException.cs @@ -0,0 +1,36 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Security +{ +#if FEATURE_BINARY_SERIALIZATION + [Serializable] +#endif + internal class SecurityUtilityException + : Exception + { + /** + * base constructor. + */ + public SecurityUtilityException() + { + } + + /** + * create a SecurityUtilityException with the given message. + * + * @param message the message to be carried with the exception. + */ + public SecurityUtilityException( + string message) + : base(message) + { + } + + public SecurityUtilityException( + string message, + Exception exception) + : base(message, exception) + { + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/util/Arrays.cs b/src/Renci.SshNet/Security/BouncyCastle/util/Arrays.cs new file mode 100644 index 00000000..3e894754 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/util/Arrays.cs @@ -0,0 +1,718 @@ +using System; +using System.Text; + +using Renci.SshNet.Security.Org.BouncyCastle.Math; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Utilities +{ + /// General array utilities. + internal abstract class Arrays + { + public static readonly byte[] EmptyBytes = new byte[0]; + public static readonly int[] EmptyInts = new int[0]; + + public static bool AreAllZeroes(byte[] buf, int off, int len) + { + uint bits = 0; + for (int i = 0; i < len; ++i) + { + bits |= buf[off + i]; + } + return bits == 0; + } + + public static bool AreEqual( + bool[] a, + bool[] b) + { + if (a == b) + return true; + + if (a == null || b == null) + return false; + + return HaveSameContents(a, b); + } + + public static bool AreEqual( + char[] a, + char[] b) + { + if (a == b) + return true; + + if (a == null || b == null) + return false; + + return HaveSameContents(a, b); + } + + /// + /// Are two arrays equal. + /// + /// Left side. + /// Right side. + /// True if equal. + public static bool AreEqual( + byte[] a, + byte[] b) + { + if (a == b) + return true; + + if (a == null || b == null) + return false; + + return HaveSameContents(a, b); + } + + [Obsolete("Use 'AreEqual' method instead")] + public static bool AreSame( + byte[] a, + byte[] b) + { + return AreEqual(a, b); + } + + /// + /// A constant time equals comparison - does not terminate early if + /// test will fail. + /// + /// first array + /// second array + /// true if arrays equal, false otherwise. + public static bool ConstantTimeAreEqual( + byte[] a, + byte[] b) + { + int i = a.Length; + if (i != b.Length) + return false; + int cmp = 0; + while (i != 0) + { + --i; + cmp |= (a[i] ^ b[i]); + } + return cmp == 0; + } + + public static bool AreEqual( + int[] a, + int[] b) + { + if (a == b) + return true; + + if (a == null || b == null) + return false; + + return HaveSameContents(a, b); + } + + public static bool AreEqual(uint[] a, uint[] b) + { + if (a == b) + return true; + + if (a == null || b == null) + return false; + + return HaveSameContents(a, b); + } + + private static bool HaveSameContents( + bool[] a, + bool[] b) + { + int i = a.Length; + if (i != b.Length) + return false; + while (i != 0) + { + --i; + if (a[i] != b[i]) + return false; + } + return true; + } + + private static bool HaveSameContents( + char[] a, + char[] b) + { + int i = a.Length; + if (i != b.Length) + return false; + while (i != 0) + { + --i; + if (a[i] != b[i]) + return false; + } + return true; + } + + private static bool HaveSameContents( + byte[] a, + byte[] b) + { + int i = a.Length; + if (i != b.Length) + return false; + while (i != 0) + { + --i; + if (a[i] != b[i]) + return false; + } + return true; + } + + private static bool HaveSameContents( + int[] a, + int[] b) + { + int i = a.Length; + if (i != b.Length) + return false; + while (i != 0) + { + --i; + if (a[i] != b[i]) + return false; + } + return true; + } + + private static bool HaveSameContents(uint[] a, uint[] b) + { + int i = a.Length; + if (i != b.Length) + return false; + while (i != 0) + { + --i; + if (a[i] != b[i]) + return false; + } + return true; + } + + public static string ToString( + object[] a) + { + StringBuilder sb = new StringBuilder('['); + if (a.Length > 0) + { + sb.Append(a[0]); + for (int index = 1; index < a.Length; ++index) + { + sb.Append(", ").Append(a[index]); + } + } + sb.Append(']'); + return sb.ToString(); + } + + public static int GetHashCode(byte[] data) + { + if (data == null) + { + return 0; + } + + int i = data.Length; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[i]; + } + + return hc; + } + + public static int GetHashCode(byte[] data, int off, int len) + { + if (data == null) + { + return 0; + } + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[off + i]; + } + + return hc; + } + + public static int GetHashCode(int[] data) + { + if (data == null) + return 0; + + int i = data.Length; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[i]; + } + + return hc; + } + + public static int GetHashCode(int[] data, int off, int len) + { + if (data == null) + return 0; + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[off + i]; + } + + return hc; + } + + public static int GetHashCode(uint[] data) + { + if (data == null) + return 0; + + int i = data.Length; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= (int)data[i]; + } + + return hc; + } + + public static int GetHashCode(uint[] data, int off, int len) + { + if (data == null) + return 0; + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= (int)data[off + i]; + } + + return hc; + } + + public static int GetHashCode(ulong[] data) + { + if (data == null) + return 0; + + int i = data.Length; + int hc = i + 1; + + while (--i >= 0) + { + ulong di = data[i]; + hc *= 257; + hc ^= (int)di; + hc *= 257; + hc ^= (int)(di >> 32); + } + + return hc; + } + + public static int GetHashCode(ulong[] data, int off, int len) + { + if (data == null) + return 0; + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + ulong di = data[off + i]; + hc *= 257; + hc ^= (int)di; + hc *= 257; + hc ^= (int)(di >> 32); + } + + return hc; + } + + public static byte[] Clone( + byte[] data) + { + return data == null ? null : (byte[])data.Clone(); + } + + public static byte[] Clone( + byte[] data, + byte[] existing) + { + if (data == null) + { + return null; + } + if ((existing == null) || (existing.Length != data.Length)) + { + return Clone(data); + } + Array.Copy(data, 0, existing, 0, existing.Length); + return existing; + } + + public static int[] Clone( + int[] data) + { + return data == null ? null : (int[])data.Clone(); + } + + internal static uint[] Clone(uint[] data) + { + return data == null ? null : (uint[])data.Clone(); + } + + public static long[] Clone(long[] data) + { + return data == null ? null : (long[])data.Clone(); + } + + public static ulong[] Clone( + ulong[] data) + { + return data == null ? null : (ulong[]) data.Clone(); + } + + public static ulong[] Clone( + ulong[] data, + ulong[] existing) + { + if (data == null) + { + return null; + } + if ((existing == null) || (existing.Length != data.Length)) + { + return Clone(data); + } + Array.Copy(data, 0, existing, 0, existing.Length); + return existing; + } + + public static bool Contains(byte[] a, byte n) + { + for (int i = 0; i < a.Length; ++i) + { + if (a[i] == n) + return true; + } + return false; + } + + public static bool Contains(short[] a, short n) + { + for (int i = 0; i < a.Length; ++i) + { + if (a[i] == n) + return true; + } + return false; + } + + public static bool Contains(int[] a, int n) + { + for (int i = 0; i < a.Length; ++i) + { + if (a[i] == n) + return true; + } + return false; + } + + public static void Fill( + byte[] buf, + byte b) + { + int i = buf.Length; + while (i > 0) + { + buf[--i] = b; + } + } + + public static void Fill(byte[] buf, int from, int to, byte b) + { + for (int i = from; i < to; ++i) + { + buf[i] = b; + } + } + + public static byte[] CopyOf(byte[] data, int newLength) + { + byte[] tmp = new byte[newLength]; + Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length)); + return tmp; + } + + public static char[] CopyOf(char[] data, int newLength) + { + char[] tmp = new char[newLength]; + Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length)); + return tmp; + } + + public static int[] CopyOf(int[] data, int newLength) + { + int[] tmp = new int[newLength]; + Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length)); + return tmp; + } + + public static long[] CopyOf(long[] data, int newLength) + { + long[] tmp = new long[newLength]; + Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length)); + return tmp; + } + + public static BigInteger[] CopyOf(BigInteger[] data, int newLength) + { + BigInteger[] tmp = new BigInteger[newLength]; + Array.Copy(data, 0, tmp, 0, System.Math.Min(newLength, data.Length)); + return tmp; + } + + /** + * Make a copy of a range of bytes from the passed in data array. The range can + * extend beyond the end of the input array, in which case the return array will + * be padded with zeroes. + * + * @param data the array from which the data is to be copied. + * @param from the start index at which the copying should take place. + * @param to the final index of the range (exclusive). + * + * @return a new byte array containing the range given. + */ + public static byte[] CopyOfRange(byte[] data, int from, int to) + { + int newLength = GetLength(from, to); + byte[] tmp = new byte[newLength]; + Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from)); + return tmp; + } + + public static int[] CopyOfRange(int[] data, int from, int to) + { + int newLength = GetLength(from, to); + int[] tmp = new int[newLength]; + Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from)); + return tmp; + } + + public static long[] CopyOfRange(long[] data, int from, int to) + { + int newLength = GetLength(from, to); + long[] tmp = new long[newLength]; + Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from)); + return tmp; + } + + public static BigInteger[] CopyOfRange(BigInteger[] data, int from, int to) + { + int newLength = GetLength(from, to); + BigInteger[] tmp = new BigInteger[newLength]; + Array.Copy(data, from, tmp, 0, System.Math.Min(newLength, data.Length - from)); + return tmp; + } + + private static int GetLength(int from, int to) + { + int newLength = to - from; + if (newLength < 0) + throw new ArgumentException(from + " > " + to); + return newLength; + } + + public static byte[] Append(byte[] a, byte b) + { + if (a == null) + return new byte[] { b }; + + int length = a.Length; + byte[] result = new byte[length + 1]; + Array.Copy(a, 0, result, 0, length); + result[length] = b; + return result; + } + + public static short[] Append(short[] a, short b) + { + if (a == null) + return new short[] { b }; + + int length = a.Length; + short[] result = new short[length + 1]; + Array.Copy(a, 0, result, 0, length); + result[length] = b; + return result; + } + + public static int[] Append(int[] a, int b) + { + if (a == null) + return new int[] { b }; + + int length = a.Length; + int[] result = new int[length + 1]; + Array.Copy(a, 0, result, 0, length); + result[length] = b; + return result; + } + + public static byte[] Concatenate(byte[] a, byte[] b) + { + if (a == null) + return Clone(b); + if (b == null) + return Clone(a); + + byte[] rv = new byte[a.Length + b.Length]; + Array.Copy(a, 0, rv, 0, a.Length); + Array.Copy(b, 0, rv, a.Length, b.Length); + return rv; + } + + public static byte[] ConcatenateAll(params byte[][] vs) + { + byte[][] nonNull = new byte[vs.Length][]; + int count = 0; + int totalLength = 0; + + for (int i = 0; i < vs.Length; ++i) + { + byte[] v = vs[i]; + if (v != null) + { + nonNull[count++] = v; + totalLength += v.Length; + } + } + + byte[] result = new byte[totalLength]; + int pos = 0; + + for (int j = 0; j < count; ++j) + { + byte[] v = nonNull[j]; + Array.Copy(v, 0, result, pos, v.Length); + pos += v.Length; + } + + return result; + } + + public static int[] Concatenate(int[] a, int[] b) + { + if (a == null) + return Clone(b); + if (b == null) + return Clone(a); + + int[] rv = new int[a.Length + b.Length]; + Array.Copy(a, 0, rv, 0, a.Length); + Array.Copy(b, 0, rv, a.Length, b.Length); + return rv; + } + + public static byte[] Prepend(byte[] a, byte b) + { + if (a == null) + return new byte[] { b }; + + int length = a.Length; + byte[] result = new byte[length + 1]; + Array.Copy(a, 0, result, 1, length); + result[0] = b; + return result; + } + + public static short[] Prepend(short[] a, short b) + { + if (a == null) + return new short[] { b }; + + int length = a.Length; + short[] result = new short[length + 1]; + Array.Copy(a, 0, result, 1, length); + result[0] = b; + return result; + } + + public static int[] Prepend(int[] a, int b) + { + if (a == null) + return new int[] { b }; + + int length = a.Length; + int[] result = new int[length + 1]; + Array.Copy(a, 0, result, 1, length); + result[0] = b; + return result; + } + + public static byte[] Reverse(byte[] a) + { + if (a == null) + return null; + + int p1 = 0, p2 = a.Length; + byte[] result = new byte[p2]; + + while (--p2 >= 0) + { + result[p2] = a[p1++]; + } + + return result; + } + + public static int[] Reverse(int[] a) + { + if (a == null) + return null; + + int p1 = 0, p2 = a.Length; + int[] result = new int[p2]; + + while (--p2 >= 0) + { + result[p2] = a[p1++]; + } + + return result; + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/util/BigIntegers.cs b/src/Renci.SshNet/Security/BouncyCastle/util/BigIntegers.cs new file mode 100644 index 00000000..6e1b8c85 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/util/BigIntegers.cs @@ -0,0 +1,95 @@ +using System; + +using Renci.SshNet.Security.Org.BouncyCastle.Math; +using Renci.SshNet.Security.Org.BouncyCastle.Security; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Utilities +{ + /** + * BigInteger utilities. + */ + internal abstract class BigIntegers + { + private const int MaxIterations = 1000; + + /** + * Return the passed in value as an unsigned byte array. + * + * @param value value to be converted. + * @return a byte array without a leading zero byte if present in the signed encoding. + */ + public static byte[] AsUnsignedByteArray( + BigInteger n) + { + return n.ToByteArrayUnsigned(); + } + + /** + * Return the passed in value as an unsigned byte array of specified length, zero-extended as necessary. + * + * @param length desired length of result array. + * @param n value to be converted. + * @return a byte array of specified length, with leading zeroes as necessary given the size of n. + */ + public static byte[] AsUnsignedByteArray(int length, BigInteger n) + { + byte[] bytes = n.ToByteArrayUnsigned(); + + if (bytes.Length > length) + throw new ArgumentException("standard length exceeded", "n"); + + if (bytes.Length == length) + return bytes; + + byte[] tmp = new byte[length]; + Array.Copy(bytes, 0, tmp, tmp.Length - bytes.Length, bytes.Length); + return tmp; + } + + /** + * Return a random BigInteger not less than 'min' and not greater than 'max' + * + * @param min the least value that may be generated + * @param max the greatest value that may be generated + * @param random the source of randomness + * @return a random BigInteger value in the range [min,max] + */ + public static BigInteger CreateRandomInRange( + BigInteger min, + BigInteger max, + // TODO Should have been just Random class + SecureRandom random) + { + int cmp = min.CompareTo(max); + if (cmp >= 0) + { + if (cmp > 0) + throw new ArgumentException("'min' may not be greater than 'max'"); + + return min; + } + + if (min.BitLength > max.BitLength / 2) + { + return CreateRandomInRange(BigInteger.Zero, max.Subtract(min), random).Add(min); + } + + for (int i = 0; i < MaxIterations; ++i) + { + BigInteger x = new BigInteger(max.BitLength, random); + if (x.CompareTo(min) >= 0 && x.CompareTo(max) <= 0) + { + return x; + } + } + + // fall back to a faster (restricted) method + return new BigInteger(max.Subtract(min).BitLength - 1, random).Add(min); + } + + public static int GetUnsignedByteLength(BigInteger n) + { + return (n.BitLength + 7) / 8; + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/util/IMemoable.cs b/src/Renci.SshNet/Security/BouncyCastle/util/IMemoable.cs new file mode 100644 index 00000000..9f94275f --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/util/IMemoable.cs @@ -0,0 +1,29 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Utilities +{ + internal interface IMemoable + { + /// + /// Produce a copy of this object with its configuration and in its current state. + /// + /// + /// The returned object may be used simply to store the state, or may be used as a similar object + /// starting from the copied state. + /// + IMemoable Copy(); + + /// + /// Restore a copied object state into this object. + /// + /// + /// Implementations of this method should try to avoid or minimise memory allocation to perform the reset. + /// + /// an object originally {@link #copy() copied} from an object of the same type as this instance. + /// if the provided object is not of the correct type. + /// if the other parameter is in some other way invalid. + void Reset(IMemoable other); + } + +} + diff --git a/src/Renci.SshNet/Security/BouncyCastle/util/Integers.cs b/src/Renci.SshNet/Security/BouncyCastle/util/Integers.cs new file mode 100644 index 00000000..29a858cc --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/util/Integers.cs @@ -0,0 +1,27 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Utilities +{ + internal abstract class Integers + { + public static int RotateLeft(int i, int distance) + { + return (i << distance) ^ (int)((uint)i >> -distance); + } + + public static uint RotateLeft(uint i, int distance) + { + return (i << distance) ^ (i >> -distance); + } + + public static int RotateRight(int i, int distance) + { + return (int)((uint)i >> distance) ^ (i << -distance); + } + + public static uint RotateRight(uint i, int distance) + { + return (i >> distance) ^ (i << -distance); + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/util/MemoableResetException.cs b/src/Renci.SshNet/Security/BouncyCastle/util/MemoableResetException.cs new file mode 100644 index 00000000..3b5ac38c --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/util/MemoableResetException.cs @@ -0,0 +1,27 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Utilities +{ + /** + * Exception to be thrown on a failure to reset an object implementing Memoable. + *

    + * The exception extends InvalidCastException to enable users to have a single handling case, + * only introducing specific handling of this one if required. + *

    + */ + internal class MemoableResetException + : InvalidCastException + { + /** + * Basic Constructor. + * + * @param msg message to be associated with this exception. + */ + public MemoableResetException(string msg) + : base(msg) + { + } + } + +} + diff --git a/src/Renci.SshNet/Security/BouncyCastle/util/Times.cs b/src/Renci.SshNet/Security/BouncyCastle/util/Times.cs new file mode 100644 index 00000000..6ef1f65f --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/util/Times.cs @@ -0,0 +1,14 @@ +using System; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Utilities +{ + internal sealed class Times + { + private static long NanosecondsPerTick = 100L; + + public static long NanoTime() + { + return DateTime.UtcNow.Ticks * NanosecondsPerTick; + } + } +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/util/encoders/Hex.cs b/src/Renci.SshNet/Security/BouncyCastle/util/encoders/Hex.cs new file mode 100644 index 00000000..658eb6fe --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/util/encoders/Hex.cs @@ -0,0 +1,129 @@ +using System.IO; +using System.Text; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Utilities.Encoders +{ + /// + /// Class to decode and encode Hex. + /// + internal sealed class Hex + { + private static readonly HexEncoder encoder = new HexEncoder(); + + private Hex() + { + } + + public static string ToHexString( + byte[] data) + { + return ToHexString(data, 0, data.Length); + } + + public static string ToHexString( + byte[] data, + int off, + int length) + { + byte[] hex = Encode(data, off, length); + return Encoding.UTF8.GetString(hex, 0, hex.Length); + } + + /** + * encode the input data producing a Hex encoded byte array. + * + * @return a byte array containing the Hex encoded data. + */ + public static byte[] Encode( + byte[] data) + { + return Encode(data, 0, data.Length); + } + + /** + * encode the input data producing a Hex encoded byte array. + * + * @return a byte array containing the Hex encoded data. + */ + public static byte[] Encode( + byte[] data, + int off, + int length) + { + MemoryStream bOut = new MemoryStream(length * 2); + + encoder.Encode(data, off, length, bOut); + + return bOut.ToArray(); + } + + /** + * Hex encode the byte data writing it to the given output stream. + * + * @return the number of bytes produced. + */ + public static int Encode( + byte[] data, + Stream outStream) + { + return encoder.Encode(data, 0, data.Length, outStream); + } + + /** + * Hex encode the byte data writing it to the given output stream. + * + * @return the number of bytes produced. + */ + public static int Encode( + byte[] data, + int off, + int length, + Stream outStream) + { + return encoder.Encode(data, off, length, outStream); + } + + /** + * decode the Hex encoded input data. It is assumed the input data is valid. + * + * @return a byte array representing the decoded data. + */ + public static byte[] Decode( + byte[] data) + { + MemoryStream bOut = new MemoryStream((data.Length + 1) / 2); + + encoder.Decode(data, 0, data.Length, bOut); + + return bOut.ToArray(); + } + + /** + * decode the Hex encoded string data - whitespace will be ignored. + * + * @return a byte array representing the decoded data. + */ + public static byte[] Decode( + string data) + { + MemoryStream bOut = new MemoryStream((data.Length + 1) / 2); + + encoder.DecodeString(data, bOut); + + return bOut.ToArray(); + } + + /** + * decode the Hex encoded string data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public static int Decode( + string data, + Stream outStream) + { + return encoder.DecodeString(data, outStream); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/BouncyCastle/util/encoders/HexEncoder.cs b/src/Renci.SshNet/Security/BouncyCastle/util/encoders/HexEncoder.cs new file mode 100644 index 00000000..dd4e1ec2 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/util/encoders/HexEncoder.cs @@ -0,0 +1,174 @@ +using System.IO; + +namespace Renci.SshNet.Security.Org.BouncyCastle.Utilities.Encoders +{ + internal class HexEncoder + { + protected readonly byte[] encodingTable = + { + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', + (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' + }; + + /* + * set up the decoding table. + */ + protected readonly byte[] decodingTable = new byte[128]; + + protected void InitialiseDecodingTable() + { + Arrays.Fill(decodingTable, (byte)0xff); + + for (int i = 0; i < encodingTable.Length; i++) + { + decodingTable[encodingTable[i]] = (byte)i; + } + + decodingTable['A'] = decodingTable['a']; + decodingTable['B'] = decodingTable['b']; + decodingTable['C'] = decodingTable['c']; + decodingTable['D'] = decodingTable['d']; + decodingTable['E'] = decodingTable['e']; + decodingTable['F'] = decodingTable['f']; + } + + public HexEncoder() + { + InitialiseDecodingTable(); + } + + /** + * encode the input data producing a Hex output stream. + * + * @return the number of bytes produced. + */ + public int Encode( + byte[] data, + int off, + int length, + Stream outStream) + { + for (int i = off; i < (off + length); i++) + { + int v = data[i]; + + outStream.WriteByte(encodingTable[v >> 4]); + outStream.WriteByte(encodingTable[v & 0xf]); + } + + return length * 2; + } + + private static bool Ignore(char c) + { + return c == '\n' || c =='\r' || c == '\t' || c == ' '; + } + + /** + * decode the Hex encoded byte data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public int Decode( + byte[] data, + int off, + int length, + Stream outStream) + { + byte b1, b2; + int outLen = 0; + int end = off + length; + + while (end > off) + { + if (!Ignore((char)data[end - 1])) + { + break; + } + + end--; + } + + int i = off; + while (i < end) + { + while (i < end && Ignore((char)data[i])) + { + i++; + } + + b1 = decodingTable[data[i++]]; + + while (i < end && Ignore((char)data[i])) + { + i++; + } + + b2 = decodingTable[data[i++]]; + + if ((b1 | b2) >= 0x80) + throw new IOException("invalid characters encountered in Hex data"); + + outStream.WriteByte((byte)((b1 << 4) | b2)); + + outLen++; + } + + return outLen; + } + + /** + * decode the Hex encoded string data writing it to the given output stream, + * whitespace characters will be ignored. + * + * @return the number of bytes produced. + */ + public int DecodeString( + string data, + Stream outStream) + { + byte b1, b2; + int length = 0; + + int end = data.Length; + + while (end > 0) + { + if (!Ignore(data[end - 1])) + { + break; + } + + end--; + } + + int i = 0; + while (i < end) + { + while (i < end && Ignore(data[i])) + { + i++; + } + + b1 = decodingTable[data[i++]]; + + while (i < end && Ignore(data[i])) + { + i++; + } + + b2 = decodingTable[data[i++]]; + + if ((b1 | b2) >= 0x80) + throw new IOException("invalid characters encountered in Hex data"); + + outStream.WriteByte((byte)((b1 << 4) | b2)); + + length++; + } + + return length; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/CryptoBytes.cs b/src/Renci.SshNet/Security/Chaos.NaCl/CryptoBytes.cs new file mode 100644 index 00000000..03229182 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/CryptoBytes.cs @@ -0,0 +1,190 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Renci.SshNet.Security.Chaos.NaCl +{ + internal static class CryptoBytes + { + internal static bool ConstantTimeEquals(byte[] x, byte[] y) + { + if (x == null) + throw new ArgumentNullException("x"); + if (y == null) + throw new ArgumentNullException("y"); + if (x.Length != y.Length) + throw new ArgumentException("x.Length must equal y.Length"); + return InternalConstantTimeEquals(x, 0, y, 0, x.Length) != 0; + } + + internal static bool ConstantTimeEquals(ArraySegment x, ArraySegment y) + { + if (x.Array == null) + throw new ArgumentNullException("x.Array"); + if (y.Array == null) + throw new ArgumentNullException("y.Array"); + if (x.Count != y.Count) + throw new ArgumentException("x.Count must equal y.Count"); + + return InternalConstantTimeEquals(x.Array, x.Offset, y.Array, y.Offset, x.Count) != 0; + } + + internal static bool ConstantTimeEquals(byte[] x, int xOffset, byte[] y, int yOffset, int length) + { + if (x == null) + throw new ArgumentNullException("x"); + if (xOffset < 0) + throw new ArgumentOutOfRangeException("xOffset", "xOffset < 0"); + if (y == null) + throw new ArgumentNullException("y"); + if (yOffset < 0) + throw new ArgumentOutOfRangeException("yOffset", "yOffset < 0"); + if (length < 0) + throw new ArgumentOutOfRangeException("length", "length < 0"); + if (x.Length - xOffset < length) + throw new ArgumentException("xOffset + length > x.Length"); + if (y.Length - yOffset < length) + throw new ArgumentException("yOffset + length > y.Length"); + + return InternalConstantTimeEquals(x, xOffset, y, yOffset, length) != 0; + } + + private static uint InternalConstantTimeEquals(byte[] x, int xOffset, byte[] y, int yOffset, int length) + { + int differentbits = 0; + for (int i = 0; i < length; i++) + differentbits |= x[xOffset + i] ^ y[yOffset + i]; + return (1 & (unchecked((uint)differentbits - 1) >> 8)); + } + + internal static void Wipe(byte[] data) + { + if (data == null) + throw new ArgumentNullException("data"); + InternalWipe(data, 0, data.Length); + } + + internal static void Wipe(byte[] data, int offset, int count) + { + if (data == null) + throw new ArgumentNullException("data"); + if (offset < 0) + throw new ArgumentOutOfRangeException("offset"); + if (count < 0) + throw new ArgumentOutOfRangeException("count", "Requires count >= 0"); + if ((uint)offset + (uint)count > (uint)data.Length) + throw new ArgumentException("Requires offset + count <= data.Length"); + InternalWipe(data, offset, count); + } + + internal static void Wipe(ArraySegment data) + { + if (data.Array == null) + throw new ArgumentNullException("data.Array"); + InternalWipe(data.Array, data.Offset, data.Count); + } + + // Secure wiping is hard + // * the GC can move around and copy memory + // Perhaps this can be avoided by using unmanaged memory or by fixing the position of the array in memory + // * Swap files and error dumps can contain secret information + // It seems possible to lock memory in RAM, no idea about error dumps + // * Compiler could optimize out the wiping if it knows that data won't be read back + // I hope this is enough, suppressing inlining + // but perhaps `RtlSecureZeroMemory` is needed + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void InternalWipe(byte[] data, int offset, int count) + { + Array.Clear(data, offset, count); + } + + // shallow wipe of structs + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void InternalWipe(ref T data) + where T : struct + { + data = default(T); + } + + // constant time hex conversion + // see http://stackoverflow.com/a/14333437/445517 + // + // An explanation of the weird bit fiddling: + // + // 1. `bytes[i] >> 4` extracts the high nibble of a byte + // `bytes[i] & 0xF` extracts the low nibble of a byte + // 2. `b - 10` + // is `< 0` for values `b < 10`, which will become a decimal digit + // is `>= 0` for values `b > 10`, which will become a letter from `A` to `F`. + // 3. Using `i >> 31` on a signed 32 bit integer extracts the sign, thanks to sign extension. + // It will be `-1` for `i < 0` and `0` for `i >= 0`. + // 4. Combining 2) and 3), shows that `(b-10)>>31` will be `0` for letters and `-1` for digits. + // 5. Looking at the case for letters, the last summand becomes `0`, and `b` is in the range 10 to 15. We want to map it to `A`(65) to `F`(70), which implies adding 55 (`'A'-10`). + // 6. Looking at the case for digits, we want to adapt the last summand so it maps `b` from the range 0 to 9 to the range `0`(48) to `9`(57). This means it needs to become -7 (`'0' - 55`). + // Now we could just multiply with 7. But since -1 is represented by all bits being 1, we can instead use `& -7` since `(0 & -7) == 0` and `(-1 & -7) == -7`. + // + // Some further considerations: + // + // * I didn't use a second loop variable to index into `c`, since measurement shows that calculating it from `i` is cheaper. + // * Using exactly `i < bytes.Length` as upper bound of the loop allows the JITter to eliminate bounds checks on `bytes[i]`, so I chose that variant. + // * Making `b` an int avoids unnecessary conversions from and to byte. + internal static string ToHexStringUpper(byte[] data) + { + if (data == null) + return null; + char[] c = new char[data.Length * 2]; + int b; + for (int i = 0; i < data.Length; i++) + { + b = data[i] >> 4; + c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7)); + b = data[i] & 0xF; + c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7)); + } + return new string(c); + } + + // Explanation is similar to ToHexStringUpper + // constant 55 -> 87 and -7 -> -39 to compensate for the offset 32 between lowercase and uppercase letters + internal static string ToHexStringLower(byte[] data) + { + if (data == null) + return null; + char[] c = new char[data.Length * 2]; + int b; + for (int i = 0; i < data.Length; i++) + { + b = data[i] >> 4; + c[i * 2] = (char)(87 + b + (((b - 10) >> 31) & -39)); + b = data[i] & 0xF; + c[i * 2 + 1] = (char)(87 + b + (((b - 10) >> 31) & -39)); + } + return new string(c); + } + + internal static byte[] FromHexString(string hexString) + { + if (hexString == null) + return null; + if (hexString.Length % 2 != 0) + throw new FormatException("The hex string is invalid because it has an odd length"); + var result = new byte[hexString.Length / 2]; + for (int i = 0; i < result.Length; i++) + result[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16); + return result; + } + + internal static string ToBase64String(byte[] data) + { + if (data == null) + return null; + return Convert.ToBase64String(data); + } + + internal static byte[] FromBase64String(string s) + { + if (s == null) + return null; + return Convert.FromBase64String(s); + } + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Ed25519.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Ed25519.cs new file mode 100644 index 00000000..5a085225 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Ed25519.cs @@ -0,0 +1,147 @@ +using System; +using Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10; + +namespace Renci.SshNet.Security.Chaos.NaCl +{ + internal static class Ed25519 + { + public static readonly int PublicKeySizeInBytes = 32; + public static readonly int SignatureSizeInBytes = 64; + public static readonly int ExpandedPrivateKeySizeInBytes = 32 * 2; + public static readonly int PrivateKeySeedSizeInBytes = 32; + public static readonly int SharedKeySizeInBytes = 32; + + public static bool Verify(ArraySegment signature, ArraySegment message, ArraySegment publicKey) + { + if (signature.Count != SignatureSizeInBytes) + throw new ArgumentException(string.Format("Signature size must be {0}", SignatureSizeInBytes), "signature.Count"); + if (publicKey.Count != PublicKeySizeInBytes) + throw new ArgumentException(string.Format("Public key size must be {0}", PublicKeySizeInBytes), "publicKey.Count"); + return Ed25519Operations.crypto_sign_verify(signature.Array, signature.Offset, message.Array, message.Offset, message.Count, publicKey.Array, publicKey.Offset); + } + + public static bool Verify(byte[] signature, byte[] message, byte[] publicKey) + { + if (signature == null) + throw new ArgumentNullException("signature"); + if (message == null) + throw new ArgumentNullException("message"); + if (publicKey == null) + throw new ArgumentNullException("publicKey"); + if (signature.Length != SignatureSizeInBytes) + throw new ArgumentException(string.Format("Signature size must be {0}", SignatureSizeInBytes), "signature.Length"); + if (publicKey.Length != PublicKeySizeInBytes) + throw new ArgumentException(string.Format("Public key size must be {0}", PublicKeySizeInBytes), "publicKey.Length"); + return Ed25519Operations.crypto_sign_verify(signature, 0, message, 0, message.Length, publicKey, 0); + } + + public static void Sign(ArraySegment signature, ArraySegment message, ArraySegment expandedPrivateKey) + { + if (signature.Array == null) + throw new ArgumentNullException("signature.Array"); + if (signature.Count != SignatureSizeInBytes) + throw new ArgumentException("signature.Count"); + if (expandedPrivateKey.Array == null) + throw new ArgumentNullException("expandedPrivateKey.Array"); + if (expandedPrivateKey.Count != ExpandedPrivateKeySizeInBytes) + throw new ArgumentException("expandedPrivateKey.Count"); + if (message.Array == null) + throw new ArgumentNullException("message.Array"); + Ed25519Operations.crypto_sign2(signature.Array, signature.Offset, message.Array, message.Offset, message.Count, expandedPrivateKey.Array, expandedPrivateKey.Offset); + } + + public static byte[] Sign(byte[] message, byte[] expandedPrivateKey) + { + var signature = new byte[SignatureSizeInBytes]; + Sign(new ArraySegment(signature), new ArraySegment(message), new ArraySegment(expandedPrivateKey)); + return signature; + } + + public static byte[] PublicKeyFromSeed(byte[] privateKeySeed) + { + byte[] privateKey; + byte[] publicKey; + KeyPairFromSeed(out publicKey, out privateKey, privateKeySeed); + CryptoBytes.Wipe(privateKey); + return publicKey; + } + + public static byte[] ExpandedPrivateKeyFromSeed(byte[] privateKeySeed) + { + byte[] privateKey; + byte[] publicKey; + KeyPairFromSeed(out publicKey, out privateKey, privateKeySeed); + CryptoBytes.Wipe(publicKey); + return privateKey; + } + + public static void KeyPairFromSeed(out byte[] publicKey, out byte[] expandedPrivateKey, byte[] privateKeySeed) + { + if (privateKeySeed == null) + throw new ArgumentNullException("privateKeySeed"); + if (privateKeySeed.Length != PrivateKeySeedSizeInBytes) + throw new ArgumentException("privateKeySeed"); + var pk = new byte[PublicKeySizeInBytes]; + var sk = new byte[ExpandedPrivateKeySizeInBytes]; + Ed25519Operations.crypto_sign_keypair(pk, 0, sk, 0, privateKeySeed, 0); + publicKey = pk; + expandedPrivateKey = sk; + } + + public static void KeyPairFromSeed(ArraySegment publicKey, ArraySegment expandedPrivateKey, ArraySegment privateKeySeed) + { + if (publicKey.Array == null) + throw new ArgumentNullException("publicKey.Array"); + if (expandedPrivateKey.Array == null) + throw new ArgumentNullException("expandedPrivateKey.Array"); + if (privateKeySeed.Array == null) + throw new ArgumentNullException("privateKeySeed.Array"); + if (publicKey.Count != PublicKeySizeInBytes) + throw new ArgumentException("publicKey.Count"); + if (expandedPrivateKey.Count != ExpandedPrivateKeySizeInBytes) + throw new ArgumentException("expandedPrivateKey.Count"); + if (privateKeySeed.Count != PrivateKeySeedSizeInBytes) + throw new ArgumentException("privateKeySeed.Count"); + Ed25519Operations.crypto_sign_keypair( + publicKey.Array, publicKey.Offset, + expandedPrivateKey.Array, expandedPrivateKey.Offset, + privateKeySeed.Array, privateKeySeed.Offset); + } + + [Obsolete("Needs more testing")] + public static byte[] KeyExchange(byte[] publicKey, byte[] privateKey) + { + var sharedKey = new byte[SharedKeySizeInBytes]; + KeyExchange(new ArraySegment(sharedKey), new ArraySegment(publicKey), new ArraySegment(privateKey)); + return sharedKey; + } + + [Obsolete("Needs more testing")] + public static void KeyExchange(ArraySegment sharedKey, ArraySegment publicKey, ArraySegment privateKey) + { + if (sharedKey.Array == null) + throw new ArgumentNullException("sharedKey.Array"); + if (publicKey.Array == null) + throw new ArgumentNullException("publicKey.Array"); + if (privateKey.Array == null) + throw new ArgumentNullException("privateKey"); + if (sharedKey.Count != 32) + throw new ArgumentException("sharedKey.Count != 32"); + if (publicKey.Count != 32) + throw new ArgumentException("publicKey.Count != 32"); + if (privateKey.Count != 64) + throw new ArgumentException("privateKey.Count != 64"); + + FieldElement montgomeryX, edwardsY, edwardsZ, sharedMontgomeryX; + FieldOperations.fe_frombytes(out edwardsY, publicKey.Array, publicKey.Offset); + FieldOperations.fe_1(out edwardsZ); + MontgomeryCurve25519.EdwardsToMontgomeryX(out montgomeryX, ref edwardsY, ref edwardsZ); + byte[] h = Sha512.Hash(privateKey.Array, privateKey.Offset, 32);//ToDo: Remove alloc + ScalarOperations.sc_clamp(h, 0); + MontgomeryOperations.scalarmult(out sharedMontgomeryX, h, 0, ref montgomeryX); + CryptoBytes.Wipe(h); + FieldOperations.fe_tobytes(sharedKey.Array, sharedKey.Offset, ref sharedMontgomeryX); + MontgomeryCurve25519.KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Array16.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Array16.cs new file mode 100644 index 00000000..dc2b08f5 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Array16.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal +{ + // Array16 Salsa20 state + // Array16 SHA-512 block + internal struct Array16 + { + public T x0; + public T x1; + public T x2; + public T x3; + public T x4; + public T x5; + public T x6; + public T x7; + public T x8; + public T x9; + public T x10; + public T x11; + public T x12; + public T x13; + public T x14; + public T x15; + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Array8.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Array8.cs new file mode 100644 index 00000000..1aeeb09c --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Array8.cs @@ -0,0 +1,18 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal +{ + // Array8 Poly1305 key + // Array8 SHA-512 state/output + internal struct Array8 + { + public T x0; + public T x1; + public T x2; + public T x3; + public T x4; + public T x5; + public T x6; + public T x7; + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/ByteIntegerConverter.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/ByteIntegerConverter.cs new file mode 100644 index 00000000..72f4e8af --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/ByteIntegerConverter.cs @@ -0,0 +1,416 @@ +using System; +using System.Collections.Generic; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal +{ + // Loops? Arrays? Never heard of that stuff + // Library avoids unnecessary heap allocations and unsafe code + // so this ugly code becomes necessary :( + internal static class ByteIntegerConverter + { + #region Individual + + internal static UInt32 LoadLittleEndian32(byte[] buf, int offset) + { + return + (UInt32)(buf[offset + 0]) + | (((UInt32)(buf[offset + 1])) << 8) + | (((UInt32)(buf[offset + 2])) << 16) + | (((UInt32)(buf[offset + 3])) << 24); + } + + internal static void StoreLittleEndian32(byte[] buf, int offset, UInt32 value) + { + buf[offset + 0] = unchecked((byte)value); + buf[offset + 1] = unchecked((byte)(value >> 8)); + buf[offset + 2] = unchecked((byte)(value >> 16)); + buf[offset + 3] = unchecked((byte)(value >> 24)); + } + + internal static UInt64 LoadBigEndian64(byte[] buf, int offset) + { + return + (UInt64)(buf[offset + 7]) + | (((UInt64)(buf[offset + 6])) << 8) + | (((UInt64)(buf[offset + 5])) << 16) + | (((UInt64)(buf[offset + 4])) << 24) + | (((UInt64)(buf[offset + 3])) << 32) + | (((UInt64)(buf[offset + 2])) << 40) + | (((UInt64)(buf[offset + 1])) << 48) + | (((UInt64)(buf[offset + 0])) << 56); + } + + internal static void StoreBigEndian64(byte[] buf, int offset, UInt64 value) + { + buf[offset + 7] = unchecked((byte)value); + buf[offset + 6] = unchecked((byte)(value >> 8)); + buf[offset + 5] = unchecked((byte)(value >> 16)); + buf[offset + 4] = unchecked((byte)(value >> 24)); + buf[offset + 3] = unchecked((byte)(value >> 32)); + buf[offset + 2] = unchecked((byte)(value >> 40)); + buf[offset + 1] = unchecked((byte)(value >> 48)); + buf[offset + 0] = unchecked((byte)(value >> 56)); + } + + /*internal static void XorLittleEndian32(byte[] buf, int offset, UInt32 value) + { + buf[offset + 0] ^= (byte)value; + buf[offset + 1] ^= (byte)(value >> 8); + buf[offset + 2] ^= (byte)(value >> 16); + buf[offset + 3] ^= (byte)(value >> 24); + }*/ + + /*internal static void XorLittleEndian32(byte[] output, int outputOffset, byte[] input, int inputOffset, UInt32 value) + { + output[outputOffset + 0] = (byte)(input[inputOffset + 0] ^ value); + output[outputOffset + 1] = (byte)(input[inputOffset + 1] ^ (value >> 8)); + output[outputOffset + 2] = (byte)(input[inputOffset + 2] ^ (value >> 16)); + output[outputOffset + 3] = (byte)(input[inputOffset + 3] ^ (value >> 24)); + }*/ + + #endregion + + #region Array8 + + internal static void Array8LoadLittleEndian32(out Array8 output, byte[] input, int inputOffset) + { + output.x0 = LoadLittleEndian32(input, inputOffset + 0); + output.x1 = LoadLittleEndian32(input, inputOffset + 4); + output.x2 = LoadLittleEndian32(input, inputOffset + 8); + output.x3 = LoadLittleEndian32(input, inputOffset + 12); + output.x4 = LoadLittleEndian32(input, inputOffset + 16); + output.x5 = LoadLittleEndian32(input, inputOffset + 20); + output.x6 = LoadLittleEndian32(input, inputOffset + 24); + output.x7 = LoadLittleEndian32(input, inputOffset + 28); + } + + /* internal static void Array8LoadLittleEndian32(out Array8 output, byte[] input, int inputOffset, int inputLength) + { + #if DEBUG + if (inputLength <= 0) + throw new ArgumentException(); + #endif + int inputEnd = inputOffset + inputLength; + UInt32 highestInt; + switch (inputLength & 3) + { + case 1: + highestInt = input[inputEnd - 1]; + break; + case 2: + highestInt = (uint)( + (input[inputEnd - 1] << 8) | + (input[inputEnd - 2])); + break; + case 3: + highestInt = (uint)( + (input[inputEnd - 1] << 16) | + (input[inputEnd - 2] << 8) | + (input[inputEnd - 3])); + break; + case 0: + highestInt = (uint)( + (input[inputEnd - 1] << 24) | + (input[inputEnd - 2] << 16) | + (input[inputEnd - 3] << 8) | + (input[inputEnd - 4])); + break; + default: + throw new InvalidOperationException(); + } + switch ((inputLength - 1) >> 2) + { + case 7: + output.x7 = highestInt; + output.x6 = LoadLittleEndian32(input, inputOffset + 6 * 4); + output.x5 = LoadLittleEndian32(input, inputOffset + 5 * 4); + output.x4 = LoadLittleEndian32(input, inputOffset + 4 * 4); + output.x3 = LoadLittleEndian32(input, inputOffset + 3 * 4); + output.x2 = LoadLittleEndian32(input, inputOffset + 2 * 4); + output.x1 = LoadLittleEndian32(input, inputOffset + 1 * 4); + output.x0 = LoadLittleEndian32(input, inputOffset + 0 * 4); + return; + case 6: + output.x7 = 0; + output.x6 = highestInt; + output.x5 = LoadLittleEndian32(input, inputOffset + 5 * 4); + output.x4 = LoadLittleEndian32(input, inputOffset + 4 * 4); + output.x3 = LoadLittleEndian32(input, inputOffset + 3 * 4); + output.x2 = LoadLittleEndian32(input, inputOffset + 2 * 4); + output.x1 = LoadLittleEndian32(input, inputOffset + 1 * 4); + output.x0 = LoadLittleEndian32(input, inputOffset + 0 * 4); + return; + case 5: + output.x7 = 0; + output.x6 = 0; + output.x5 = highestInt; + output.x4 = LoadLittleEndian32(input, inputOffset + 4 * 4); + output.x3 = LoadLittleEndian32(input, inputOffset + 3 * 4); + output.x2 = LoadLittleEndian32(input, inputOffset + 2 * 4); + output.x1 = LoadLittleEndian32(input, inputOffset + 1 * 4); + output.x0 = LoadLittleEndian32(input, inputOffset + 0 * 4); + return; + case 4: + output.x7 = 0; + output.x6 = 0; + output.x5 = 0; + output.x4 = highestInt; + output.x3 = LoadLittleEndian32(input, inputOffset + 3 * 4); + output.x2 = LoadLittleEndian32(input, inputOffset + 2 * 4); + output.x1 = LoadLittleEndian32(input, inputOffset + 1 * 4); + output.x0 = LoadLittleEndian32(input, inputOffset + 0 * 4); + return; + case 3: + output.x7 = 0; + output.x6 = 0; + output.x5 = 0; + output.x4 = 0; + output.x3 = highestInt; + output.x2 = LoadLittleEndian32(input, inputOffset + 2 * 4); + output.x1 = LoadLittleEndian32(input, inputOffset + 1 * 4); + output.x0 = LoadLittleEndian32(input, inputOffset + 0 * 4); + return; + case 2: + output.x7 = 0; + output.x6 = 0; + output.x5 = 0; + output.x4 = 0; + output.x3 = 0; + output.x2 = highestInt; + output.x1 = LoadLittleEndian32(input, inputOffset + 1 * 4); + output.x0 = LoadLittleEndian32(input, inputOffset + 0 * 4); + return; + case 1: + output.x7 = 0; + output.x6 = 0; + output.x5 = 0; + output.x4 = 0; + output.x3 = 0; + output.x2 = 0; + output.x1 = highestInt; + output.x0 = LoadLittleEndian32(input, inputOffset + 0 * 4); + return; + case 0: + output.x7 = 0; + output.x6 = 0; + output.x5 = 0; + output.x4 = 0; + output.x3 = 0; + output.x2 = 0; + output.x1 = 0; + output.x0 = highestInt; + return; + default: + throw new InvalidOperationException(); + } + }*/ + + /*internal static void Array8XorLittleEndian(byte[] output, int outputOffset, byte[] input, int inputOffset, ref Array8 keyStream, int length) + { +#if DEBUG + InternalAssert(length > 0); +#endif + int outputEnd = outputOffset + length; + UInt32 highestInt; + switch ((length - 1) >> 2) + { + case 7: + highestInt = keyStream.x7; + XorLittleEndian32(output, outputOffset + 6 * 4, input, inputOffset + 6 * 4, keyStream.x6); + XorLittleEndian32(output, outputOffset + 5 * 4, input, inputOffset + 6 * 4, keyStream.x5); + XorLittleEndian32(output, outputOffset + 4 * 4, input, inputOffset + 6 * 4, keyStream.x4); + XorLittleEndian32(output, outputOffset + 3 * 4, input, inputOffset + 6 * 4, keyStream.x3); + XorLittleEndian32(output, outputOffset + 2 * 4, input, inputOffset + 6 * 4, keyStream.x2); + XorLittleEndian32(output, outputOffset + 1 * 4, input, inputOffset + 6 * 4, keyStream.x1); + XorLittleEndian32(output, outputOffset + 0 * 4, input, inputOffset + 6 * 4, keyStream.x0); + break; + case 6: + highestInt = keyStream.x6; + XorLittleEndian32(output, outputOffset + 5 * 4, input, inputOffset + 6 * 4, keyStream.x5); + XorLittleEndian32(output, outputOffset + 4 * 4, input, inputOffset + 6 * 4, keyStream.x4); + XorLittleEndian32(output, outputOffset + 3 * 4, input, inputOffset + 6 * 4, keyStream.x3); + XorLittleEndian32(output, outputOffset + 2 * 4, input, inputOffset + 6 * 4, keyStream.x2); + XorLittleEndian32(output, outputOffset + 1 * 4, input, inputOffset + 6 * 4, keyStream.x1); + XorLittleEndian32(output, outputOffset + 0 * 4, input, inputOffset + 6 * 4, keyStream.x0); + break; + case 5: + highestInt = keyStream.x5; + XorLittleEndian32(output, outputOffset + 4 * 4, input, inputOffset + 6 * 4, keyStream.x4); + XorLittleEndian32(output, outputOffset + 3 * 4, input, inputOffset + 6 * 4, keyStream.x3); + XorLittleEndian32(output, outputOffset + 2 * 4, input, inputOffset + 6 * 4, keyStream.x2); + XorLittleEndian32(output, outputOffset + 1 * 4, input, inputOffset + 6 * 4, keyStream.x1); + XorLittleEndian32(output, outputOffset + 0 * 4, input, inputOffset + 6 * 4, keyStream.x0); + break; + case 4: + highestInt = keyStream.x4; + XorLittleEndian32(output, outputOffset + 3 * 4, input, inputOffset + 6 * 4, keyStream.x3); + XorLittleEndian32(output, outputOffset + 2 * 4, input, inputOffset + 6 * 4, keyStream.x2); + XorLittleEndian32(output, outputOffset + 1 * 4, input, inputOffset + 6 * 4, keyStream.x1); + XorLittleEndian32(output, outputOffset + 0 * 4, input, inputOffset + 6 * 4, keyStream.x0); + break; + case 3: + highestInt = keyStream.x3; + XorLittleEndian32(output, outputOffset + 2 * 4, input, inputOffset + 6 * 4, keyStream.x2); + XorLittleEndian32(output, outputOffset + 1 * 4, input, inputOffset + 6 * 4, keyStream.x1); + XorLittleEndian32(output, outputOffset + 0 * 4, input, inputOffset + 6 * 4, keyStream.x0); + break; + case 2: + highestInt = keyStream.x2; + XorLittleEndian32(output, outputOffset + 1 * 4, input, inputOffset + 6 * 4, keyStream.x1); + XorLittleEndian32(output, outputOffset + 0 * 4, input, inputOffset + 6 * 4, keyStream.x0); + break; + case 1: + highestInt = keyStream.x1; + XorLittleEndian32(output, outputOffset + 0 * 4, input, inputOffset + 6 * 4, keyStream.x0); + break; + case 0: + highestInt = keyStream.x0; + break; + default: + throw new InvalidOperationException(); + } + switch (length & 3) + { + case 1: + output[outputEnd - 1] ^= (byte)highestInt; + break; + case 2: + output[outputEnd - 1] ^= (byte)(highestInt >> 8); + output[outputEnd - 2] ^= (byte)highestInt; + break; + case 3: + output[outputEnd - 1] ^= (byte)(highestInt >> 16); + output[outputEnd - 2] ^= (byte)(highestInt >> 8); + output[outputEnd - 3] ^= (byte)highestInt; + break; + case 0: + output[outputEnd - 1] ^= (byte)(highestInt >> 24); + output[outputEnd - 2] ^= (byte)(highestInt >> 16); + output[outputEnd - 3] ^= (byte)(highestInt >> 8); + output[outputEnd - 4] ^= (byte)highestInt; + break; + default: + throw new InvalidOperationException(); + } + }*/ + + /*internal static void Array8StoreLittleEndian32(byte[] output, int outputOffset, ref Array8 input) + { + StoreLittleEndian32(output, outputOffset + 0, input.x0); + StoreLittleEndian32(output, outputOffset + 4, input.x1); + StoreLittleEndian32(output, outputOffset + 8, input.x2); + StoreLittleEndian32(output, outputOffset + 12, input.x3); + StoreLittleEndian32(output, outputOffset + 16, input.x4); + StoreLittleEndian32(output, outputOffset + 20, input.x5); + StoreLittleEndian32(output, outputOffset + 24, input.x6); + StoreLittleEndian32(output, outputOffset + 28, input.x7); + }*/ + #endregion + + internal static void Array16LoadBigEndian64(out Array16 output, byte[] input, int inputOffset) + { + output.x0 = LoadBigEndian64(input, inputOffset + 0); + output.x1 = LoadBigEndian64(input, inputOffset + 8); + output.x2 = LoadBigEndian64(input, inputOffset + 16); + output.x3 = LoadBigEndian64(input, inputOffset + 24); + output.x4 = LoadBigEndian64(input, inputOffset + 32); + output.x5 = LoadBigEndian64(input, inputOffset + 40); + output.x6 = LoadBigEndian64(input, inputOffset + 48); + output.x7 = LoadBigEndian64(input, inputOffset + 56); + output.x8 = LoadBigEndian64(input, inputOffset + 64); + output.x9 = LoadBigEndian64(input, inputOffset + 72); + output.x10 = LoadBigEndian64(input, inputOffset + 80); + output.x11 = LoadBigEndian64(input, inputOffset + 88); + output.x12 = LoadBigEndian64(input, inputOffset + 96); + output.x13 = LoadBigEndian64(input, inputOffset + 104); + output.x14 = LoadBigEndian64(input, inputOffset + 112); + output.x15 = LoadBigEndian64(input, inputOffset + 120); + } + + // ToDo: Only used in tests. Remove? + internal static void Array16LoadLittleEndian32(out Array16 output, byte[] input, int inputOffset) + { + output.x0 = LoadLittleEndian32(input, inputOffset + 0); + output.x1 = LoadLittleEndian32(input, inputOffset + 4); + output.x2 = LoadLittleEndian32(input, inputOffset + 8); + output.x3 = LoadLittleEndian32(input, inputOffset + 12); + output.x4 = LoadLittleEndian32(input, inputOffset + 16); + output.x5 = LoadLittleEndian32(input, inputOffset + 20); + output.x6 = LoadLittleEndian32(input, inputOffset + 24); + output.x7 = LoadLittleEndian32(input, inputOffset + 28); + output.x8 = LoadLittleEndian32(input, inputOffset + 32); + output.x9 = LoadLittleEndian32(input, inputOffset + 36); + output.x10 = LoadLittleEndian32(input, inputOffset + 40); + output.x11 = LoadLittleEndian32(input, inputOffset + 44); + output.x12 = LoadLittleEndian32(input, inputOffset + 48); + output.x13 = LoadLittleEndian32(input, inputOffset + 52); + output.x14 = LoadLittleEndian32(input, inputOffset + 56); + output.x15 = LoadLittleEndian32(input, inputOffset + 60); + } + + /*internal static void Array16LoadLittleEndian32(out Array16 output, byte[] input, int inputOffset, int inputLength) + { + Array8 temp; + if (inputLength > 32) + { + output.x0 = LoadLittleEndian32(input, inputOffset + 0); + output.x1 = LoadLittleEndian32(input, inputOffset + 4); + output.x2 = LoadLittleEndian32(input, inputOffset + 8); + output.x3 = LoadLittleEndian32(input, inputOffset + 12); + output.x4 = LoadLittleEndian32(input, inputOffset + 16); + output.x5 = LoadLittleEndian32(input, inputOffset + 20); + output.x6 = LoadLittleEndian32(input, inputOffset + 24); + output.x7 = LoadLittleEndian32(input, inputOffset + 28); + Array8LoadLittleEndian32(out temp, input, inputOffset + 32, inputLength - 32); + output.x8 = temp.x0; + output.x9 = temp.x1; + output.x10 = temp.x2; + output.x11 = temp.x3; + output.x12 = temp.x4; + output.x13 = temp.x5; + output.x14 = temp.x6; + output.x15 = temp.x7; + } + else + { + Array8LoadLittleEndian32(out temp, input, inputOffset, inputLength); + output.x0 = temp.x0; + output.x1 = temp.x1; + output.x2 = temp.x2; + output.x3 = temp.x3; + output.x4 = temp.x4; + output.x5 = temp.x5; + output.x6 = temp.x6; + output.x7 = temp.x7; + output.x8 = 0; + output.x9 = 0; + output.x10 = 0; + output.x11 = 0; + output.x12 = 0; + output.x13 = 0; + output.x14 = 0; + output.x15 = 0; + } + }*/ + + internal static void Array16StoreLittleEndian32(byte[] output, int outputOffset, ref Array16 input) + { + StoreLittleEndian32(output, outputOffset + 0, input.x0); + StoreLittleEndian32(output, outputOffset + 4, input.x1); + StoreLittleEndian32(output, outputOffset + 8, input.x2); + StoreLittleEndian32(output, outputOffset + 12, input.x3); + StoreLittleEndian32(output, outputOffset + 16, input.x4); + StoreLittleEndian32(output, outputOffset + 20, input.x5); + StoreLittleEndian32(output, outputOffset + 24, input.x6); + StoreLittleEndian32(output, outputOffset + 28, input.x7); + StoreLittleEndian32(output, outputOffset + 32, input.x8); + StoreLittleEndian32(output, outputOffset + 36, input.x9); + StoreLittleEndian32(output, outputOffset + 40, input.x10); + StoreLittleEndian32(output, outputOffset + 44, input.x11); + StoreLittleEndian32(output, outputOffset + 48, input.x12); + StoreLittleEndian32(output, outputOffset + 52, input.x13); + StoreLittleEndian32(output, outputOffset + 56, input.x14); + StoreLittleEndian32(output, outputOffset + 60, input.x15); + } + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/FieldElement.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/FieldElement.cs new file mode 100644 index 00000000..c8b32488 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/FieldElement.cs @@ -0,0 +1,36 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal struct FieldElement + { + internal int x0; + internal int x1; + internal int x2; + internal int x3; + internal int x4; + internal int x5; + internal int x6; + internal int x7; + internal int x8; + internal int x9; + + //internal static readonly FieldElement Zero = new FieldElement(); + //internal static readonly FieldElement One = new FieldElement() { x0 = 1 }; + + internal FieldElement(params int[] elements) + { + InternalAssert.Assert(elements.Length == 10, "elements.Length != 10"); + x0 = elements[0]; + x1 = elements[1]; + x2 = elements[2]; + x3 = elements[3]; + x4 = elements[4]; + x5 = elements[5]; + x6 = elements[6]; + x7 = elements[7]; + x8 = elements[8]; + x9 = elements[9]; + } + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/GroupElement.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/GroupElement.cs new file mode 100644 index 00000000..8203281c --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/GroupElement.cs @@ -0,0 +1,63 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + /* + ge means group element. + + Here the group is the set of pairs (x,y) of field elements (see fe.h) + satisfying -x^2 + y^2 = 1 + d x^2y^2 + where d = -121665/121666. + + Representations: + ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z + ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT + ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T + ge_precomp (Duif): (y+x,y-x,2dxy) + */ + + internal struct GroupElementP2 + { + public FieldElement X; + public FieldElement Y; + public FieldElement Z; + } ; + + internal struct GroupElementP3 + { + public FieldElement X; + public FieldElement Y; + public FieldElement Z; + public FieldElement T; + } ; + + internal struct GroupElementP1P1 + { + public FieldElement X; + public FieldElement Y; + public FieldElement Z; + public FieldElement T; + } ; + + internal struct GroupElementPreComp + { + public FieldElement yplusx; + public FieldElement yminusx; + public FieldElement xy2d; + + public GroupElementPreComp(FieldElement yplusx, FieldElement yminusx, FieldElement xy2d) + { + this.yplusx = yplusx; + this.yminusx = yminusx; + this.xy2d = xy2d; + } + } ; + + internal struct GroupElementCached + { + public FieldElement YplusX; + public FieldElement YminusX; + public FieldElement Z; + public FieldElement T2d; + } ; +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/base.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/base.cs new file mode 100644 index 00000000..0e3359a3 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/base.cs @@ -0,0 +1,1357 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class LookupTables + { + /* base[i][j] = (j+1)*256^i*B */ + //32*8 + internal static GroupElementPreComp[][] Base = new GroupElementPreComp[][] + { + new[]{ + new GroupElementPreComp( + new FieldElement( 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 ), + new FieldElement( -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 ), + new FieldElement( -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 ) + ), + new GroupElementPreComp( + new FieldElement( -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 ), + new FieldElement( -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 ), + new FieldElement( 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 ) + ), + new GroupElementPreComp( + new FieldElement( 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 ), + new FieldElement( 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 ), + new FieldElement( 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 ) + ), + new GroupElementPreComp( + new FieldElement( -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 ), + new FieldElement( 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 ), + new FieldElement( 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 ) + ), + new GroupElementPreComp( + new FieldElement( 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 ), + new FieldElement( 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 ), + new FieldElement( 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 ) + ), + new GroupElementPreComp( + new FieldElement( -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 ), + new FieldElement( -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 ), + new FieldElement( -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 ) + ), + new GroupElementPreComp( + new FieldElement( 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 ), + new FieldElement( -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 ), + new FieldElement( 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 ) + ), + new GroupElementPreComp( + new FieldElement( 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 ), + new FieldElement( -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 ), + new FieldElement( 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 ), + new FieldElement( 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 ), + new FieldElement( 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 ) + ), + new GroupElementPreComp( + new FieldElement( -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 ), + new FieldElement( 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 ), + new FieldElement( 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 ) + ), + new GroupElementPreComp( + new FieldElement( -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 ), + new FieldElement( 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 ), + new FieldElement( 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 ) + ), + new GroupElementPreComp( + new FieldElement( -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 ), + new FieldElement( -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 ), + new FieldElement( -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 ) + ), + new GroupElementPreComp( + new FieldElement( 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 ), + new FieldElement( 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 ), + new FieldElement( 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 ) + ), + new GroupElementPreComp( + new FieldElement( -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 ), + new FieldElement( -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 ), + new FieldElement( -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 ) + ), + new GroupElementPreComp( + new FieldElement( 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 ), + new FieldElement( -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 ), + new FieldElement( -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 ) + ), + new GroupElementPreComp( + new FieldElement( 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 ), + new FieldElement( 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 ), + new FieldElement( 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 ), + new FieldElement( 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 ), + new FieldElement( -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 ) + ), + new GroupElementPreComp( + new FieldElement( 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 ), + new FieldElement( -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 ), + new FieldElement( -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 ) + ), + new GroupElementPreComp( + new FieldElement( -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 ), + new FieldElement( 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 ), + new FieldElement( 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 ) + ), + new GroupElementPreComp( + new FieldElement( -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 ), + new FieldElement( 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 ), + new FieldElement( 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 ) + ), + new GroupElementPreComp( + new FieldElement( -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 ), + new FieldElement( 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 ), + new FieldElement( -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 ) + ), + new GroupElementPreComp( + new FieldElement( -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 ), + new FieldElement( -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 ), + new FieldElement( 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 ) + ), + new GroupElementPreComp( + new FieldElement( 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 ), + new FieldElement( -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 ), + new FieldElement( -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 ) + ), + new GroupElementPreComp( + new FieldElement( 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 ), + new FieldElement( 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 ), + new FieldElement( -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 ), + new FieldElement( -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 ), + new FieldElement( -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 ) + ), + new GroupElementPreComp( + new FieldElement( -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 ), + new FieldElement( 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 ), + new FieldElement( -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 ) + ), + new GroupElementPreComp( + new FieldElement( 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 ), + new FieldElement( 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 ), + new FieldElement( -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 ) + ), + new GroupElementPreComp( + new FieldElement( 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 ), + new FieldElement( 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 ), + new FieldElement( 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 ) + ), + new GroupElementPreComp( + new FieldElement( 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 ), + new FieldElement( 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 ), + new FieldElement( 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 ) + ), + new GroupElementPreComp( + new FieldElement( 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 ), + new FieldElement( -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 ), + new FieldElement( -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 ) + ), + new GroupElementPreComp( + new FieldElement( -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 ), + new FieldElement( -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 ), + new FieldElement( 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 ) + ), + new GroupElementPreComp( + new FieldElement( 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 ), + new FieldElement( -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 ), + new FieldElement( 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 ), + new FieldElement( -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 ), + new FieldElement( 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 ) + ), + new GroupElementPreComp( + new FieldElement( 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 ), + new FieldElement( 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 ), + new FieldElement( -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 ) + ), + new GroupElementPreComp( + new FieldElement( -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 ), + new FieldElement( 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 ), + new FieldElement( 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 ) + ), + new GroupElementPreComp( + new FieldElement( -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 ), + new FieldElement( -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 ), + new FieldElement( 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 ) + ), + new GroupElementPreComp( + new FieldElement( -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 ), + new FieldElement( -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 ), + new FieldElement( -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 ) + ), + new GroupElementPreComp( + new FieldElement( -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 ), + new FieldElement( -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 ), + new FieldElement( 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 ) + ), + new GroupElementPreComp( + new FieldElement( -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 ), + new FieldElement( -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 ), + new FieldElement( -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 ) + ), + new GroupElementPreComp( + new FieldElement( -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 ), + new FieldElement( 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 ), + new FieldElement( -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 ), + new FieldElement( -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 ), + new FieldElement( 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 ) + ), + new GroupElementPreComp( + new FieldElement( -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 ), + new FieldElement( -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 ), + new FieldElement( -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 ) + ), + new GroupElementPreComp( + new FieldElement( -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 ), + new FieldElement( 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 ), + new FieldElement( -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 ) + ), + new GroupElementPreComp( + new FieldElement( -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 ), + new FieldElement( -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 ), + new FieldElement( -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 ) + ), + new GroupElementPreComp( + new FieldElement( -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 ), + new FieldElement( -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 ), + new FieldElement( -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 ) + ), + new GroupElementPreComp( + new FieldElement( 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 ), + new FieldElement( -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 ), + new FieldElement( -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 ) + ), + new GroupElementPreComp( + new FieldElement( 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 ), + new FieldElement( -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 ), + new FieldElement( -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 ) + ), + new GroupElementPreComp( + new FieldElement( 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 ), + new FieldElement( -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 ), + new FieldElement( 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 ), + new FieldElement( 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 ), + new FieldElement( -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 ) + ), + new GroupElementPreComp( + new FieldElement( -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 ), + new FieldElement( 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 ), + new FieldElement( 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 ) + ), + new GroupElementPreComp( + new FieldElement( 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 ), + new FieldElement( 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 ), + new FieldElement( -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 ) + ), + new GroupElementPreComp( + new FieldElement( -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 ), + new FieldElement( -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 ), + new FieldElement( -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 ) + ), + new GroupElementPreComp( + new FieldElement( -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 ), + new FieldElement( -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 ), + new FieldElement( -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 ) + ), + new GroupElementPreComp( + new FieldElement( -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 ), + new FieldElement( -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 ), + new FieldElement( -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 ) + ), + new GroupElementPreComp( + new FieldElement( 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 ), + new FieldElement( 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 ), + new FieldElement( -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 ) + ), + new GroupElementPreComp( + new FieldElement( 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 ), + new FieldElement( 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 ), + new FieldElement( 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 ), + new FieldElement( 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 ), + new FieldElement( -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 ) + ), + new GroupElementPreComp( + new FieldElement( 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 ), + new FieldElement( -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 ), + new FieldElement( -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 ) + ), + new GroupElementPreComp( + new FieldElement( -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 ), + new FieldElement( -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 ), + new FieldElement( -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 ) + ), + new GroupElementPreComp( + new FieldElement( 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 ), + new FieldElement( -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 ), + new FieldElement( 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 ) + ), + new GroupElementPreComp( + new FieldElement( 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 ), + new FieldElement( -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 ), + new FieldElement( -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 ) + ), + new GroupElementPreComp( + new FieldElement( 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 ), + new FieldElement( -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 ), + new FieldElement( -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 ) + ), + new GroupElementPreComp( + new FieldElement( 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 ), + new FieldElement( 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 ), + new FieldElement( 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 ) + ), + new GroupElementPreComp( + new FieldElement( 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 ), + new FieldElement( 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 ), + new FieldElement( 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 ), + new FieldElement( 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 ), + new FieldElement( 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 ) + ), + new GroupElementPreComp( + new FieldElement( -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 ), + new FieldElement( -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 ), + new FieldElement( 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 ) + ), + new GroupElementPreComp( + new FieldElement( 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 ), + new FieldElement( -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 ), + new FieldElement( -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 ) + ), + new GroupElementPreComp( + new FieldElement( -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 ), + new FieldElement( 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 ), + new FieldElement( 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 ) + ), + new GroupElementPreComp( + new FieldElement( 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 ), + new FieldElement( -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 ), + new FieldElement( 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 ) + ), + new GroupElementPreComp( + new FieldElement( -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 ), + new FieldElement( -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 ), + new FieldElement( -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 ) + ), + new GroupElementPreComp( + new FieldElement( 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 ), + new FieldElement( 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 ), + new FieldElement( 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 ) + ), + new GroupElementPreComp( + new FieldElement( -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 ), + new FieldElement( -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 ), + new FieldElement( -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 ), + new FieldElement( -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 ), + new FieldElement( 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 ) + ), + new GroupElementPreComp( + new FieldElement( 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 ), + new FieldElement( -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 ), + new FieldElement( -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 ) + ), + new GroupElementPreComp( + new FieldElement( -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 ), + new FieldElement( -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 ), + new FieldElement( -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 ) + ), + new GroupElementPreComp( + new FieldElement( -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 ), + new FieldElement( 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 ), + new FieldElement( -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 ) + ), + new GroupElementPreComp( + new FieldElement( -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 ), + new FieldElement( 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 ), + new FieldElement( -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 ) + ), + new GroupElementPreComp( + new FieldElement( -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 ), + new FieldElement( -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 ), + new FieldElement( -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 ) + ), + new GroupElementPreComp( + new FieldElement( 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 ), + new FieldElement( 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 ), + new FieldElement( -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 ) + ), + new GroupElementPreComp( + new FieldElement( 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 ), + new FieldElement( 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 ), + new FieldElement( 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 ), + new FieldElement( 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 ), + new FieldElement( -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 ) + ), + new GroupElementPreComp( + new FieldElement( 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 ), + new FieldElement( 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 ), + new FieldElement( 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 ) + ), + new GroupElementPreComp( + new FieldElement( 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 ), + new FieldElement( -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 ), + new FieldElement( 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 ) + ), + new GroupElementPreComp( + new FieldElement( 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 ), + new FieldElement( 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 ), + new FieldElement( 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 ) + ), + new GroupElementPreComp( + new FieldElement( -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 ), + new FieldElement( 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 ), + new FieldElement( 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 ) + ), + new GroupElementPreComp( + new FieldElement( -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 ), + new FieldElement( -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 ), + new FieldElement( -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 ) + ), + new GroupElementPreComp( + new FieldElement( -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 ), + new FieldElement( -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 ), + new FieldElement( -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 ) + ), + new GroupElementPreComp( + new FieldElement( 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 ), + new FieldElement( 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 ), + new FieldElement( 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 ), + new FieldElement( -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 ), + new FieldElement( 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 ) + ), + new GroupElementPreComp( + new FieldElement( -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 ), + new FieldElement( -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 ), + new FieldElement( -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 ) + ), + new GroupElementPreComp( + new FieldElement( -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 ), + new FieldElement( -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 ), + new FieldElement( 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 ) + ), + new GroupElementPreComp( + new FieldElement( 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 ), + new FieldElement( 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 ), + new FieldElement( 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 ) + ), + new GroupElementPreComp( + new FieldElement( 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 ), + new FieldElement( -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 ), + new FieldElement( 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 ) + ), + new GroupElementPreComp( + new FieldElement( 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 ), + new FieldElement( 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 ), + new FieldElement( 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 ) + ), + new GroupElementPreComp( + new FieldElement( 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 ), + new FieldElement( 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 ), + new FieldElement( 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 ) + ), + new GroupElementPreComp( + new FieldElement( -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 ), + new FieldElement( -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 ), + new FieldElement( -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 ), + new FieldElement( 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 ), + new FieldElement( 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 ) + ), + new GroupElementPreComp( + new FieldElement( 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 ), + new FieldElement( 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 ), + new FieldElement( 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 ) + ), + new GroupElementPreComp( + new FieldElement( 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 ), + new FieldElement( 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 ), + new FieldElement( -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 ) + ), + new GroupElementPreComp( + new FieldElement( 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 ), + new FieldElement( 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 ), + new FieldElement( -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 ) + ), + new GroupElementPreComp( + new FieldElement( 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 ), + new FieldElement( 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 ), + new FieldElement( 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 ) + ), + new GroupElementPreComp( + new FieldElement( 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 ), + new FieldElement( -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 ), + new FieldElement( 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 ) + ), + new GroupElementPreComp( + new FieldElement( -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 ), + new FieldElement( -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 ), + new FieldElement( -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 ) + ), + new GroupElementPreComp( + new FieldElement( 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 ), + new FieldElement( -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 ), + new FieldElement( -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 ), + new FieldElement( 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 ), + new FieldElement( -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 ) + ), + new GroupElementPreComp( + new FieldElement( 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 ), + new FieldElement( 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 ), + new FieldElement( -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 ) + ), + new GroupElementPreComp( + new FieldElement( 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 ), + new FieldElement( 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 ), + new FieldElement( 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 ) + ), + new GroupElementPreComp( + new FieldElement( 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 ), + new FieldElement( -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 ), + new FieldElement( -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 ) + ), + new GroupElementPreComp( + new FieldElement( 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 ), + new FieldElement( -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 ), + new FieldElement( 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 ) + ), + new GroupElementPreComp( + new FieldElement( -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 ), + new FieldElement( -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 ), + new FieldElement( -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 ) + ), + new GroupElementPreComp( + new FieldElement( 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 ), + new FieldElement( -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 ), + new FieldElement( -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 ) + ), + new GroupElementPreComp( + new FieldElement( -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 ), + new FieldElement( -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 ), + new FieldElement( -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 ), + new FieldElement( -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 ), + new FieldElement( 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 ) + ), + new GroupElementPreComp( + new FieldElement( -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 ), + new FieldElement( 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 ), + new FieldElement( 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 ) + ), + new GroupElementPreComp( + new FieldElement( -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 ), + new FieldElement( 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 ), + new FieldElement( 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 ) + ), + new GroupElementPreComp( + new FieldElement( 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 ), + new FieldElement( -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 ), + new FieldElement( 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 ) + ), + new GroupElementPreComp( + new FieldElement( -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 ), + new FieldElement( -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 ), + new FieldElement( 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 ) + ), + new GroupElementPreComp( + new FieldElement( 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 ), + new FieldElement( -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 ), + new FieldElement( 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 ) + ), + new GroupElementPreComp( + new FieldElement( -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 ), + new FieldElement( 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 ), + new FieldElement( 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 ) + ), + new GroupElementPreComp( + new FieldElement( 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 ), + new FieldElement( -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 ), + new FieldElement( -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 ), + new FieldElement( 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 ), + new FieldElement( 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 ) + ), + new GroupElementPreComp( + new FieldElement( 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 ), + new FieldElement( 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 ), + new FieldElement( -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 ) + ), + new GroupElementPreComp( + new FieldElement( -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 ), + new FieldElement( 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 ), + new FieldElement( -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 ) + ), + new GroupElementPreComp( + new FieldElement( 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 ), + new FieldElement( 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 ), + new FieldElement( 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 ) + ), + new GroupElementPreComp( + new FieldElement( 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 ), + new FieldElement( -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 ), + new FieldElement( -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 ) + ), + new GroupElementPreComp( + new FieldElement( 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 ), + new FieldElement( 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 ), + new FieldElement( 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 ) + ), + new GroupElementPreComp( + new FieldElement( 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 ), + new FieldElement( -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 ), + new FieldElement( -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 ) + ), + new GroupElementPreComp( + new FieldElement( -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 ), + new FieldElement( 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 ), + new FieldElement( 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 ), + new FieldElement( -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 ), + new FieldElement( -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 ) + ), + new GroupElementPreComp( + new FieldElement( 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 ), + new FieldElement( 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 ), + new FieldElement( -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 ) + ), + new GroupElementPreComp( + new FieldElement( 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 ), + new FieldElement( 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 ), + new FieldElement( 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 ) + ), + new GroupElementPreComp( + new FieldElement( 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 ), + new FieldElement( 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 ), + new FieldElement( -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 ) + ), + new GroupElementPreComp( + new FieldElement( 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 ), + new FieldElement( -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 ), + new FieldElement( -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 ) + ), + new GroupElementPreComp( + new FieldElement( 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 ), + new FieldElement( -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 ), + new FieldElement( -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 ) + ), + new GroupElementPreComp( + new FieldElement( 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 ), + new FieldElement( -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 ), + new FieldElement( -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 ) + ), + new GroupElementPreComp( + new FieldElement( -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 ), + new FieldElement( 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 ), + new FieldElement( -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 ), + new FieldElement( -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 ), + new FieldElement( -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 ) + ), + new GroupElementPreComp( + new FieldElement( 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 ), + new FieldElement( -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 ), + new FieldElement( -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 ) + ), + new GroupElementPreComp( + new FieldElement( -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 ), + new FieldElement( 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 ), + new FieldElement( -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 ) + ), + new GroupElementPreComp( + new FieldElement( 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 ), + new FieldElement( 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 ), + new FieldElement( 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 ) + ), + new GroupElementPreComp( + new FieldElement( 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 ), + new FieldElement( 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 ), + new FieldElement( -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 ) + ), + new GroupElementPreComp( + new FieldElement( -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 ), + new FieldElement( -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 ), + new FieldElement( -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 ) + ), + new GroupElementPreComp( + new FieldElement( -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 ), + new FieldElement( -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 ), + new FieldElement( 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 ) + ), + new GroupElementPreComp( + new FieldElement( 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 ), + new FieldElement( 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 ), + new FieldElement( -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 ), + new FieldElement( 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 ), + new FieldElement( -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 ) + ), + new GroupElementPreComp( + new FieldElement( -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 ), + new FieldElement( -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 ), + new FieldElement( -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 ) + ), + new GroupElementPreComp( + new FieldElement( 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 ), + new FieldElement( 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 ), + new FieldElement( 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 ) + ), + new GroupElementPreComp( + new FieldElement( 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 ), + new FieldElement( -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 ), + new FieldElement( 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 ) + ), + new GroupElementPreComp( + new FieldElement( -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 ), + new FieldElement( 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 ), + new FieldElement( 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 ) + ), + new GroupElementPreComp( + new FieldElement( -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 ), + new FieldElement( 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 ), + new FieldElement( 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 ) + ), + new GroupElementPreComp( + new FieldElement( -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 ), + new FieldElement( -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 ), + new FieldElement( -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 ) + ), + new GroupElementPreComp( + new FieldElement( 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 ), + new FieldElement( -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 ), + new FieldElement( -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 ), + new FieldElement( -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 ), + new FieldElement( -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 ) + ), + new GroupElementPreComp( + new FieldElement( -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 ), + new FieldElement( -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 ), + new FieldElement( 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 ) + ), + new GroupElementPreComp( + new FieldElement( 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 ), + new FieldElement( -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 ), + new FieldElement( -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 ) + ), + new GroupElementPreComp( + new FieldElement( -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 ), + new FieldElement( 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 ), + new FieldElement( 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 ) + ), + new GroupElementPreComp( + new FieldElement( 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 ), + new FieldElement( 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 ), + new FieldElement( -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 ) + ), + new GroupElementPreComp( + new FieldElement( 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 ), + new FieldElement( -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 ), + new FieldElement( 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 ) + ), + new GroupElementPreComp( + new FieldElement( 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 ), + new FieldElement( 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 ), + new FieldElement( -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 ) + ), + new GroupElementPreComp( + new FieldElement( 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 ), + new FieldElement( -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 ), + new FieldElement( 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 ), + new FieldElement( 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 ), + new FieldElement( -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 ) + ), + new GroupElementPreComp( + new FieldElement( -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 ), + new FieldElement( 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 ), + new FieldElement( 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 ) + ), + new GroupElementPreComp( + new FieldElement( 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 ), + new FieldElement( -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 ), + new FieldElement( -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 ) + ), + new GroupElementPreComp( + new FieldElement( 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 ), + new FieldElement( 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 ), + new FieldElement( 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 ) + ), + new GroupElementPreComp( + new FieldElement( -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 ), + new FieldElement( -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 ), + new FieldElement( 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 ) + ), + new GroupElementPreComp( + new FieldElement( -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 ), + new FieldElement( 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 ), + new FieldElement( -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 ) + ), + new GroupElementPreComp( + new FieldElement( -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 ), + new FieldElement( -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 ), + new FieldElement( -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 ) + ), + new GroupElementPreComp( + new FieldElement( -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 ), + new FieldElement( -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 ), + new FieldElement( 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 ), + new FieldElement( 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 ), + new FieldElement( -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 ) + ), + new GroupElementPreComp( + new FieldElement( -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 ), + new FieldElement( 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 ), + new FieldElement( -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 ) + ), + new GroupElementPreComp( + new FieldElement( 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 ), + new FieldElement( -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 ), + new FieldElement( -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 ) + ), + new GroupElementPreComp( + new FieldElement( -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 ), + new FieldElement( 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 ), + new FieldElement( 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 ) + ), + new GroupElementPreComp( + new FieldElement( 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 ), + new FieldElement( -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 ), + new FieldElement( -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 ) + ), + new GroupElementPreComp( + new FieldElement( 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 ), + new FieldElement( -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 ), + new FieldElement( -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 ) + ), + new GroupElementPreComp( + new FieldElement( -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 ), + new FieldElement( -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 ), + new FieldElement( 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 ) + ), + new GroupElementPreComp( + new FieldElement( 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 ), + new FieldElement( -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 ), + new FieldElement( -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 ), + new FieldElement( -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 ), + new FieldElement( 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 ) + ), + new GroupElementPreComp( + new FieldElement( -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 ), + new FieldElement( 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 ), + new FieldElement( -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 ) + ), + new GroupElementPreComp( + new FieldElement( 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 ), + new FieldElement( 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 ), + new FieldElement( 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 ) + ), + new GroupElementPreComp( + new FieldElement( -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 ), + new FieldElement( -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 ), + new FieldElement( -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 ) + ), + new GroupElementPreComp( + new FieldElement( -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 ), + new FieldElement( -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 ), + new FieldElement( -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 ) + ), + new GroupElementPreComp( + new FieldElement( 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 ), + new FieldElement( 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 ), + new FieldElement( 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 ) + ), + new GroupElementPreComp( + new FieldElement( -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 ), + new FieldElement( -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 ), + new FieldElement( 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 ) + ), + new GroupElementPreComp( + new FieldElement( 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 ), + new FieldElement( 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 ), + new FieldElement( 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 ), + new FieldElement( -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 ), + new FieldElement( -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 ) + ), + new GroupElementPreComp( + new FieldElement( 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 ), + new FieldElement( 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 ), + new FieldElement( 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 ) + ), + new GroupElementPreComp( + new FieldElement( -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 ), + new FieldElement( 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 ), + new FieldElement( 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 ) + ), + new GroupElementPreComp( + new FieldElement( 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 ), + new FieldElement( -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 ), + new FieldElement( -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 ) + ), + new GroupElementPreComp( + new FieldElement( -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 ), + new FieldElement( 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 ), + new FieldElement( -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 ) + ), + new GroupElementPreComp( + new FieldElement( 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 ), + new FieldElement( -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 ), + new FieldElement( -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 ) + ), + new GroupElementPreComp( + new FieldElement( 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 ), + new FieldElement( -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 ), + new FieldElement( -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 ) + ), + new GroupElementPreComp( + new FieldElement( 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 ), + new FieldElement( 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 ), + new FieldElement( -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 ), + new FieldElement( 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 ), + new FieldElement( -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 ) + ), + new GroupElementPreComp( + new FieldElement( 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 ), + new FieldElement( 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 ), + new FieldElement( 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 ) + ), + new GroupElementPreComp( + new FieldElement( -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 ), + new FieldElement( 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 ), + new FieldElement( -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 ) + ), + new GroupElementPreComp( + new FieldElement( -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 ), + new FieldElement( -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 ), + new FieldElement( -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 ) + ), + new GroupElementPreComp( + new FieldElement( -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 ), + new FieldElement( 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 ), + new FieldElement( 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 ) + ), + new GroupElementPreComp( + new FieldElement( -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 ), + new FieldElement( 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 ), + new FieldElement( 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 ) + ), + new GroupElementPreComp( + new FieldElement( -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 ), + new FieldElement( -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 ), + new FieldElement( 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 ) + ), + new GroupElementPreComp( + new FieldElement( 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 ), + new FieldElement( 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 ), + new FieldElement( -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 ), + new FieldElement( 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 ), + new FieldElement( -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 ) + ), + new GroupElementPreComp( + new FieldElement( 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 ), + new FieldElement( 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 ), + new FieldElement( -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 ) + ), + new GroupElementPreComp( + new FieldElement( -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 ), + new FieldElement( -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 ), + new FieldElement( -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 ) + ), + new GroupElementPreComp( + new FieldElement( -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 ), + new FieldElement( -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 ), + new FieldElement( -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 ) + ), + new GroupElementPreComp( + new FieldElement( -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 ), + new FieldElement( -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 ), + new FieldElement( 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 ) + ), + new GroupElementPreComp( + new FieldElement( -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 ), + new FieldElement( 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 ), + new FieldElement( -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 ) + ), + new GroupElementPreComp( + new FieldElement( -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 ), + new FieldElement( -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 ), + new FieldElement( 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 ) + ), + new GroupElementPreComp( + new FieldElement( -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 ), + new FieldElement( 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 ), + new FieldElement( -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 ), + new FieldElement( -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 ), + new FieldElement( 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 ) + ), + new GroupElementPreComp( + new FieldElement( 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 ), + new FieldElement( -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 ), + new FieldElement( -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 ) + ), + new GroupElementPreComp( + new FieldElement( -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 ), + new FieldElement( -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 ), + new FieldElement( 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 ) + ), + new GroupElementPreComp( + new FieldElement( 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 ), + new FieldElement( 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 ), + new FieldElement( 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 ) + ), + new GroupElementPreComp( + new FieldElement( 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 ), + new FieldElement( 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 ), + new FieldElement( 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 ) + ), + new GroupElementPreComp( + new FieldElement( 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 ), + new FieldElement( 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 ), + new FieldElement( 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 ) + ), + new GroupElementPreComp( + new FieldElement( 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 ), + new FieldElement( 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 ), + new FieldElement( 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 ) + ), + new GroupElementPreComp( + new FieldElement( -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 ), + new FieldElement( -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 ), + new FieldElement( 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 ), + new FieldElement( -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 ), + new FieldElement( -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 ) + ), + new GroupElementPreComp( + new FieldElement( 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 ), + new FieldElement( 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 ), + new FieldElement( -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 ) + ), + new GroupElementPreComp( + new FieldElement( 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 ), + new FieldElement( 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 ), + new FieldElement( -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 ) + ), + new GroupElementPreComp( + new FieldElement( -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 ), + new FieldElement( 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 ), + new FieldElement( 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 ) + ), + new GroupElementPreComp( + new FieldElement( -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 ), + new FieldElement( -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 ), + new FieldElement( 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 ) + ), + new GroupElementPreComp( + new FieldElement( 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 ), + new FieldElement( -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 ), + new FieldElement( -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 ) + ), + new GroupElementPreComp( + new FieldElement( -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 ), + new FieldElement( 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 ), + new FieldElement( 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 ) + ), + new GroupElementPreComp( + new FieldElement( -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 ), + new FieldElement( 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 ), + new FieldElement( 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 ), + new FieldElement( -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 ), + new FieldElement( 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 ) + ), + new GroupElementPreComp( + new FieldElement( -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 ), + new FieldElement( -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 ), + new FieldElement( -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 ) + ), + new GroupElementPreComp( + new FieldElement( -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 ), + new FieldElement( -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 ), + new FieldElement( -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 ) + ), + new GroupElementPreComp( + new FieldElement( -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 ), + new FieldElement( -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 ), + new FieldElement( -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 ) + ), + new GroupElementPreComp( + new FieldElement( -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 ), + new FieldElement( 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 ), + new FieldElement( -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 ) + ), + new GroupElementPreComp( + new FieldElement( 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 ), + new FieldElement( -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 ), + new FieldElement( -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 ) + ), + new GroupElementPreComp( + new FieldElement( 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 ), + new FieldElement( 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 ), + new FieldElement( -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 ) + ), + new GroupElementPreComp( + new FieldElement( 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 ), + new FieldElement( 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 ), + new FieldElement( -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 ), + new FieldElement( 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 ), + new FieldElement( -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 ) + ), + new GroupElementPreComp( + new FieldElement( -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 ), + new FieldElement( -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 ), + new FieldElement( 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 ) + ), + new GroupElementPreComp( + new FieldElement( -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 ), + new FieldElement( -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 ), + new FieldElement( 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 ) + ), + new GroupElementPreComp( + new FieldElement( 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 ), + new FieldElement( -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 ), + new FieldElement( 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 ) + ), + new GroupElementPreComp( + new FieldElement( -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 ), + new FieldElement( 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 ), + new FieldElement( -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 ) + ), + new GroupElementPreComp( + new FieldElement( 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 ), + new FieldElement( 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 ), + new FieldElement( -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 ) + ), + new GroupElementPreComp( + new FieldElement( -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 ), + new FieldElement( 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 ), + new FieldElement( 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 ) + ), + new GroupElementPreComp( + new FieldElement( 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 ), + new FieldElement( 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 ), + new FieldElement( -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 ), + new FieldElement( -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 ), + new FieldElement( -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 ) + ), + new GroupElementPreComp( + new FieldElement( -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 ), + new FieldElement( -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 ), + new FieldElement( 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 ) + ), + new GroupElementPreComp( + new FieldElement( 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 ), + new FieldElement( -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 ), + new FieldElement( -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 ) + ), + new GroupElementPreComp( + new FieldElement( -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 ), + new FieldElement( 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 ), + new FieldElement( 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 ) + ), + new GroupElementPreComp( + new FieldElement( 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 ), + new FieldElement( -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 ), + new FieldElement( -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 ) + ), + new GroupElementPreComp( + new FieldElement( 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 ), + new FieldElement( 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 ), + new FieldElement( 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 ) + ), + new GroupElementPreComp( + new FieldElement( -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 ), + new FieldElement( 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 ), + new FieldElement( 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 ) + ), + new GroupElementPreComp( + new FieldElement( -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 ), + new FieldElement( 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 ), + new FieldElement( -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 ) + ), + }, + new[]{ + new GroupElementPreComp( + new FieldElement( 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 ), + new FieldElement( -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 ), + new FieldElement( 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 ) + ), + new GroupElementPreComp( + new FieldElement( -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 ), + new FieldElement( -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 ), + new FieldElement( -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 ) + ), + new GroupElementPreComp( + new FieldElement( -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 ), + new FieldElement( -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 ), + new FieldElement( 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 ) + ), + new GroupElementPreComp( + new FieldElement( -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 ), + new FieldElement( -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 ), + new FieldElement( 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 ) + ), + new GroupElementPreComp( + new FieldElement( -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 ), + new FieldElement( 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 ), + new FieldElement( -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 ) + ), + new GroupElementPreComp( + new FieldElement( 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 ), + new FieldElement( 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 ), + new FieldElement( -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 ) + ), + new GroupElementPreComp( + new FieldElement( -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 ), + new FieldElement( -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 ), + new FieldElement( -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 ) + ), + new GroupElementPreComp( + new FieldElement( -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 ), + new FieldElement( 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 ), + new FieldElement( -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 ) + ) + } + }; + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/base2.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/base2.cs new file mode 100644 index 00000000..cbd022b3 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/base2.cs @@ -0,0 +1,50 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class LookupTables + { + internal static readonly GroupElementPreComp[] Base2 = new GroupElementPreComp[]{ + new GroupElementPreComp( + new FieldElement( 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 ), + new FieldElement( -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 ), + new FieldElement( -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 ) + ), + new GroupElementPreComp( + new FieldElement( 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 ), + new FieldElement( 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 ), + new FieldElement( 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 ) + ), + new GroupElementPreComp( + new FieldElement( 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 ), + new FieldElement( 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 ), + new FieldElement( 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 ) + ), + new GroupElementPreComp( + new FieldElement( 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 ), + new FieldElement( -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 ), + new FieldElement( 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 ) + ), + new GroupElementPreComp( + new FieldElement( -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 ), + new FieldElement( -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 ), + new FieldElement( 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 ) + ), + new GroupElementPreComp( + new FieldElement( -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 ), + new FieldElement( 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 ), + new FieldElement( 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 ) + ), + new GroupElementPreComp( + new FieldElement( -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 ), + new FieldElement( -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 ), + new FieldElement( -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 ) + ), + new GroupElementPreComp( + new FieldElement( -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 ), + new FieldElement( -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 ), + new FieldElement( -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 ) + ) + }; + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/d.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/d.cs new file mode 100644 index 00000000..e341aeea --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/d.cs @@ -0,0 +1,9 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class LookupTables + { + internal static FieldElement d = new FieldElement(-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/d2.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/d2.cs new file mode 100644 index 00000000..bf94d24d --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/d2.cs @@ -0,0 +1,9 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class LookupTables + { + internal static FieldElement d2 = new FieldElement(-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_0.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_0.cs new file mode 100644 index 00000000..cf27c4da --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_0.cs @@ -0,0 +1,12 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + internal static void fe_0(out FieldElement h) + { + h = default(FieldElement); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_1.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_1.cs new file mode 100644 index 00000000..348f919a --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_1.cs @@ -0,0 +1,13 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + internal static void fe_1(out FieldElement h) + { + h = default(FieldElement); + h.x0 = 1; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_add.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_add.cs new file mode 100644 index 00000000..a3d2faaa --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_add.cs @@ -0,0 +1,63 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f + g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + //void fe_add(fe h,const fe f,const fe g) + internal static void fe_add(out FieldElement h, ref FieldElement f, ref FieldElement g) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 g0 = g.x0; + Int32 g1 = g.x1; + Int32 g2 = g.x2; + Int32 g3 = g.x3; + Int32 g4 = g.x4; + Int32 g5 = g.x5; + Int32 g6 = g.x6; + Int32 g7 = g.x7; + Int32 g8 = g.x8; + Int32 g9 = g.x9; + Int32 h0 = f0 + g0; + Int32 h1 = f1 + g1; + Int32 h2 = f2 + g2; + Int32 h3 = f3 + g3; + Int32 h4 = f4 + g4; + Int32 h5 = f5 + g5; + Int32 h6 = f6 + g6; + Int32 h7 = f7 + g7; + Int32 h8 = f8 + g8; + Int32 h9 = f9 + g9; + h.x0 = h0; + h.x1 = h1; + h.x2 = h2; + h.x3 = h3; + h.x4 = h4; + h.x5 = h5; + h.x6 = h6; + h.x7 = h7; + h.x8 = h8; + h.x9 = h9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_cmov.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_cmov.cs new file mode 100644 index 00000000..a24a8efb --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_cmov.cs @@ -0,0 +1,70 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + Replace (f,g) with (g,g) if b == 1; + replace (f,g) with (f,g) if b == 0. + + Preconditions: b in {0,1}. + */ + + //void fe_cmov(fe f,const fe g,unsigned int b) + internal static void fe_cmov(ref FieldElement f, ref FieldElement g, int b) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 g0 = g.x0; + Int32 g1 = g.x1; + Int32 g2 = g.x2; + Int32 g3 = g.x3; + Int32 g4 = g.x4; + Int32 g5 = g.x5; + Int32 g6 = g.x6; + Int32 g7 = g.x7; + Int32 g8 = g.x8; + Int32 g9 = g.x9; + Int32 x0 = f0 ^ g0; + Int32 x1 = f1 ^ g1; + Int32 x2 = f2 ^ g2; + Int32 x3 = f3 ^ g3; + Int32 x4 = f4 ^ g4; + Int32 x5 = f5 ^ g5; + Int32 x6 = f6 ^ g6; + Int32 x7 = f7 ^ g7; + Int32 x8 = f8 ^ g8; + Int32 x9 = f9 ^ g9; + b = -b; + x0 &= b; + x1 &= b; + x2 &= b; + x3 &= b; + x4 &= b; + x5 &= b; + x6 &= b; + x7 &= b; + x8 &= b; + x9 &= b; + f.x0 = f0 ^ x0; + f.x1 = f1 ^ x1; + f.x2 = f2 ^ x2; + f.x3 = f3 ^ x3; + f.x4 = f4 ^ x4; + f.x5 = f5 ^ x5; + f.x6 = f6 ^ x6; + f.x7 = f7 ^ x7; + f.x8 = f8 ^ x8; + f.x9 = f9 ^ x9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_cswap.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_cswap.cs new file mode 100644 index 00000000..f251eebc --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_cswap.cs @@ -0,0 +1,78 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + Replace (f,g) with (g,f) if b == 1; + replace (f,g) with (f,g) if b == 0. + + Preconditions: b in {0,1}. + */ + internal static void fe_cswap(ref FieldElement f, ref FieldElement g, uint b) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 g0 = g.x0; + Int32 g1 = g.x1; + Int32 g2 = g.x2; + Int32 g3 = g.x3; + Int32 g4 = g.x4; + Int32 g5 = g.x5; + Int32 g6 = g.x6; + Int32 g7 = g.x7; + Int32 g8 = g.x8; + Int32 g9 = g.x9; + Int32 x0 = f0 ^ g0; + Int32 x1 = f1 ^ g1; + Int32 x2 = f2 ^ g2; + Int32 x3 = f3 ^ g3; + Int32 x4 = f4 ^ g4; + Int32 x5 = f5 ^ g5; + Int32 x6 = f6 ^ g6; + Int32 x7 = f7 ^ g7; + Int32 x8 = f8 ^ g8; + Int32 x9 = f9 ^ g9; + int negb = unchecked((int)-b); + x0 &= negb; + x1 &= negb; + x2 &= negb; + x3 &= negb; + x4 &= negb; + x5 &= negb; + x6 &= negb; + x7 &= negb; + x8 &= negb; + x9 &= negb; + f.x0 = f0 ^ x0; + f.x1 = f1 ^ x1; + f.x2 = f2 ^ x2; + f.x3 = f3 ^ x3; + f.x4 = f4 ^ x4; + f.x5 = f5 ^ x5; + f.x6 = f6 ^ x6; + f.x7 = f7 ^ x7; + f.x8 = f8 ^ x8; + f.x9 = f9 ^ x9; + g.x0 = g0 ^ x0; + g.x1 = g1 ^ x1; + g.x2 = g2 ^ x2; + g.x3 = g3 ^ x3; + g.x4 = g4 ^ x4; + g.x5 = g5 ^ x5; + g.x6 = g6 ^ x6; + g.x7 = g7 ^ x7; + g.x8 = g8 ^ x8; + g.x9 = g9 ^ x9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_frombytes.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_frombytes.cs new file mode 100644 index 00000000..37abf8d5 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_frombytes.cs @@ -0,0 +1,122 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + private static Int64 load_3(byte[] data, int offset) + { + uint result; + result = (uint)data[offset + 0]; + result |= (uint)data[offset + 1] << 8; + result |= (uint)data[offset + 2] << 16; + return (Int64)(UInt64)result; + } + + private static Int64 load_4(byte[] data, int offset) + { + uint result; + result = (uint)data[offset + 0]; + result |= (uint)data[offset + 1] << 8; + result |= (uint)data[offset + 2] << 16; + result |= (uint)data[offset + 3] << 24; + return (Int64)(UInt64)result; + } + + // Ignores top bit of h. + internal static void fe_frombytes(out FieldElement h, byte[] data, int offset) + { + Int64 h0 = load_4(data, offset); + Int64 h1 = load_3(data, offset + 4) << 6; + Int64 h2 = load_3(data, offset + 7) << 5; + Int64 h3 = load_3(data, offset + 10) << 3; + Int64 h4 = load_3(data, offset + 13) << 2; + Int64 h5 = load_4(data, offset + 16); + Int64 h6 = load_3(data, offset + 20) << 7; + Int64 h7 = load_3(data, offset + 23) << 5; + Int64 h8 = load_3(data, offset + 26) << 4; + Int64 h9 = (load_3(data, offset + 29) & 8388607) << 2; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (Int64)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (Int64)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (Int64)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + + // does NOT ignore top bit + internal static void fe_frombytes2(out FieldElement h, byte[] data, int offset) + { + Int64 h0 = load_4(data, offset); + Int64 h1 = load_3(data, offset + 4) << 6; + Int64 h2 = load_3(data, offset + 7) << 5; + Int64 h3 = load_3(data, offset + 10) << 3; + Int64 h4 = load_3(data, offset + 13) << 2; + Int64 h5 = load_4(data, offset + 16); + Int64 h6 = load_3(data, offset + 20) << 7; + Int64 h7 = load_3(data, offset + 23) << 5; + Int64 h8 = load_3(data, offset + 26) << 4; + Int64 h9 = load_3(data, offset + 29) << 2; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (Int64)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (Int64)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (Int64)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_invert.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_invert.cs new file mode 100644 index 00000000..8ff9a3a6 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_invert.cs @@ -0,0 +1,179 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + internal static void fe_invert(out FieldElement result, ref FieldElement z) + { + FieldElement t0; + FieldElement t1; + FieldElement t2; + FieldElement t3; + int i; + + /* qhasm: fe z1 */ + + /* qhasm: fe z2 */ + + /* qhasm: fe z8 */ + + /* qhasm: fe z9 */ + + /* qhasm: fe z11 */ + + /* qhasm: fe z22 */ + + /* qhasm: fe z_5_0 */ + + /* qhasm: fe z_10_5 */ + + /* qhasm: fe z_10_0 */ + + /* qhasm: fe z_20_10 */ + + /* qhasm: fe z_20_0 */ + + /* qhasm: fe z_40_20 */ + + /* qhasm: fe z_40_0 */ + + /* qhasm: fe z_50_10 */ + + /* qhasm: fe z_50_0 */ + + /* qhasm: fe z_100_50 */ + + /* qhasm: fe z_100_0 */ + + /* qhasm: fe z_200_100 */ + + /* qhasm: fe z_200_0 */ + + /* qhasm: fe z_250_50 */ + + /* qhasm: fe z_250_0 */ + + /* qhasm: fe z_255_5 */ + + /* qhasm: fe z_255_21 */ + + /* qhasm: enter pow225521 */ + + /* qhasm: z2 = z1^2^1 */ + /* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ + /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ + fe_sq(out t0, ref z); //for (i = 1; i < 1; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z8 = z2^2^2 */ + /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ + /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 2; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z9 = z1*z8 */ + /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#3,z22=fe#3,>z22=fe#3); */ + /* asm 2: fe_sq(>z22=t2,z22=t2,>z22=t2); */ + fe_sq(out t2, ref t0); //for (i = 1; i < 1; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_5_0 = z9*z22 */ + /* asm 1: fe_mul(>z_5_0=fe#2,z_5_0=t1,z_10_5=fe#3,z_10_5=fe#3,>z_10_5=fe#3); */ + /* asm 2: fe_sq(>z_10_5=t2,z_10_5=t2,>z_10_5=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 5; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_10_0 = z_10_5*z_5_0 */ + /* asm 1: fe_mul(>z_10_0=fe#2,z_10_0=t1,z_20_10=fe#3,z_20_10=fe#3,>z_20_10=fe#3); */ + /* asm 2: fe_sq(>z_20_10=t2,z_20_10=t2,>z_20_10=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 10; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_20_0 = z_20_10*z_10_0 */ + /* asm 1: fe_mul(>z_20_0=fe#3,z_20_0=t2,z_40_20=fe#4,z_40_20=fe#4,>z_40_20=fe#4); */ + /* asm 2: fe_sq(>z_40_20=t3,z_40_20=t3,>z_40_20=t3); */ + fe_sq(out t3, ref t2); for (i = 1; i < 20; ++i) fe_sq(out t3, ref t3); + + /* qhasm: z_40_0 = z_40_20*z_20_0 */ + /* asm 1: fe_mul(>z_40_0=fe#3,z_40_0=t2,z_50_10=fe#3,z_50_10=fe#3,>z_50_10=fe#3); */ + /* asm 2: fe_sq(>z_50_10=t2,z_50_10=t2,>z_50_10=t2); */ + fe_sq(out t2, ref t2); for (i = 1; i < 10; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_50_0 = z_50_10*z_10_0 */ + /* asm 1: fe_mul(>z_50_0=fe#2,z_50_0=t1,z_100_50=fe#3,z_100_50=fe#3,>z_100_50=fe#3); */ + /* asm 2: fe_sq(>z_100_50=t2,z_100_50=t2,>z_100_50=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 50; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_100_0 = z_100_50*z_50_0 */ + /* asm 1: fe_mul(>z_100_0=fe#3,z_100_0=t2,z_200_100=fe#4,z_200_100=fe#4,>z_200_100=fe#4); */ + /* asm 2: fe_sq(>z_200_100=t3,z_200_100=t3,>z_200_100=t3); */ + fe_sq(out t3, ref t2); for (i = 1; i < 100; ++i) fe_sq(out t3, ref t3); + + /* qhasm: z_200_0 = z_200_100*z_100_0 */ + /* asm 1: fe_mul(>z_200_0=fe#3,z_200_0=t2,z_250_50=fe#3,z_250_50=fe#3,>z_250_50=fe#3); */ + /* asm 2: fe_sq(>z_250_50=t2,z_250_50=t2,>z_250_50=t2); */ + fe_sq(out t2, ref t2); for (i = 1; i < 50; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_250_0 = z_250_50*z_50_0 */ + /* asm 1: fe_mul(>z_250_0=fe#2,z_250_0=t1,z_255_5=fe#2,z_255_5=fe#2,>z_255_5=fe#2); */ + /* asm 2: fe_sq(>z_255_5=t1,z_255_5=t1,>z_255_5=t1); */ + fe_sq(out t1, ref t1); for (i = 1; i < 5; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_255_21 = z_255_5*z11 */ + /* asm 1: fe_mul(>z_255_21=fe#12,z_255_21=out,> 31) ^ 1); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_mul.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_mul.cs new file mode 100644 index 00000000..a060dba8 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_mul.cs @@ -0,0 +1,258 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f * g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + + /* + Notes on implementation strategy: + + Using schoolbook multiplication. + Karatsuba would save a little in some cost models. + + Most multiplications by 2 and 19 are 32-bit precomputations; + cheaper than 64-bit postcomputations. + + There is one remaining multiplication by 19 in the carry chain; + one *19 precomputation can be merged into this, + but the resulting data flow is considerably less clean. + + There are 12 carries below. + 10 of them are 2-way parallelizable and vectorizable. + Can get away with 11 carries, but then data flow is much deeper. + + With tighter constraints on inputs can squeeze carries into int32. + */ + + internal static void fe_mul(out FieldElement h, ref FieldElement f, ref FieldElement g) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 g0 = g.x0; + Int32 g1 = g.x1; + Int32 g2 = g.x2; + Int32 g3 = g.x3; + Int32 g4 = g.x4; + Int32 g5 = g.x5; + Int32 g6 = g.x6; + Int32 g7 = g.x7; + Int32 g8 = g.x8; + Int32 g9 = g.x9; + Int32 g1_19 = 19 * g1; /* 1.959375*2^29 */ + Int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + Int32 g3_19 = 19 * g3; + Int32 g4_19 = 19 * g4; + Int32 g5_19 = 19 * g5; + Int32 g6_19 = 19 * g6; + Int32 g7_19 = 19 * g7; + Int32 g8_19 = 19 * g8; + Int32 g9_19 = 19 * g9; + Int32 f1_2 = 2 * f1; + Int32 f3_2 = 2 * f3; + Int32 f5_2 = 2 * f5; + Int32 f7_2 = 2 * f7; + Int32 f9_2 = 2 * f9; + Int64 f0g0 = f0 * (Int64)g0; + Int64 f0g1 = f0 * (Int64)g1; + Int64 f0g2 = f0 * (Int64)g2; + Int64 f0g3 = f0 * (Int64)g3; + Int64 f0g4 = f0 * (Int64)g4; + Int64 f0g5 = f0 * (Int64)g5; + Int64 f0g6 = f0 * (Int64)g6; + Int64 f0g7 = f0 * (Int64)g7; + Int64 f0g8 = f0 * (Int64)g8; + Int64 f0g9 = f0 * (Int64)g9; + Int64 f1g0 = f1 * (Int64)g0; + Int64 f1g1_2 = f1_2 * (Int64)g1; + Int64 f1g2 = f1 * (Int64)g2; + Int64 f1g3_2 = f1_2 * (Int64)g3; + Int64 f1g4 = f1 * (Int64)g4; + Int64 f1g5_2 = f1_2 * (Int64)g5; + Int64 f1g6 = f1 * (Int64)g6; + Int64 f1g7_2 = f1_2 * (Int64)g7; + Int64 f1g8 = f1 * (Int64)g8; + Int64 f1g9_38 = f1_2 * (Int64)g9_19; + Int64 f2g0 = f2 * (Int64)g0; + Int64 f2g1 = f2 * (Int64)g1; + Int64 f2g2 = f2 * (Int64)g2; + Int64 f2g3 = f2 * (Int64)g3; + Int64 f2g4 = f2 * (Int64)g4; + Int64 f2g5 = f2 * (Int64)g5; + Int64 f2g6 = f2 * (Int64)g6; + Int64 f2g7 = f2 * (Int64)g7; + Int64 f2g8_19 = f2 * (Int64)g8_19; + Int64 f2g9_19 = f2 * (Int64)g9_19; + Int64 f3g0 = f3 * (Int64)g0; + Int64 f3g1_2 = f3_2 * (Int64)g1; + Int64 f3g2 = f3 * (Int64)g2; + Int64 f3g3_2 = f3_2 * (Int64)g3; + Int64 f3g4 = f3 * (Int64)g4; + Int64 f3g5_2 = f3_2 * (Int64)g5; + Int64 f3g6 = f3 * (Int64)g6; + Int64 f3g7_38 = f3_2 * (Int64)g7_19; + Int64 f3g8_19 = f3 * (Int64)g8_19; + Int64 f3g9_38 = f3_2 * (Int64)g9_19; + Int64 f4g0 = f4 * (Int64)g0; + Int64 f4g1 = f4 * (Int64)g1; + Int64 f4g2 = f4 * (Int64)g2; + Int64 f4g3 = f4 * (Int64)g3; + Int64 f4g4 = f4 * (Int64)g4; + Int64 f4g5 = f4 * (Int64)g5; + Int64 f4g6_19 = f4 * (Int64)g6_19; + Int64 f4g7_19 = f4 * (Int64)g7_19; + Int64 f4g8_19 = f4 * (Int64)g8_19; + Int64 f4g9_19 = f4 * (Int64)g9_19; + Int64 f5g0 = f5 * (Int64)g0; + Int64 f5g1_2 = f5_2 * (Int64)g1; + Int64 f5g2 = f5 * (Int64)g2; + Int64 f5g3_2 = f5_2 * (Int64)g3; + Int64 f5g4 = f5 * (Int64)g4; + Int64 f5g5_38 = f5_2 * (Int64)g5_19; + Int64 f5g6_19 = f5 * (Int64)g6_19; + Int64 f5g7_38 = f5_2 * (Int64)g7_19; + Int64 f5g8_19 = f5 * (Int64)g8_19; + Int64 f5g9_38 = f5_2 * (Int64)g9_19; + Int64 f6g0 = f6 * (Int64)g0; + Int64 f6g1 = f6 * (Int64)g1; + Int64 f6g2 = f6 * (Int64)g2; + Int64 f6g3 = f6 * (Int64)g3; + Int64 f6g4_19 = f6 * (Int64)g4_19; + Int64 f6g5_19 = f6 * (Int64)g5_19; + Int64 f6g6_19 = f6 * (Int64)g6_19; + Int64 f6g7_19 = f6 * (Int64)g7_19; + Int64 f6g8_19 = f6 * (Int64)g8_19; + Int64 f6g9_19 = f6 * (Int64)g9_19; + Int64 f7g0 = f7 * (Int64)g0; + Int64 f7g1_2 = f7_2 * (Int64)g1; + Int64 f7g2 = f7 * (Int64)g2; + Int64 f7g3_38 = f7_2 * (Int64)g3_19; + Int64 f7g4_19 = f7 * (Int64)g4_19; + Int64 f7g5_38 = f7_2 * (Int64)g5_19; + Int64 f7g6_19 = f7 * (Int64)g6_19; + Int64 f7g7_38 = f7_2 * (Int64)g7_19; + Int64 f7g8_19 = f7 * (Int64)g8_19; + Int64 f7g9_38 = f7_2 * (Int64)g9_19; + Int64 f8g0 = f8 * (Int64)g0; + Int64 f8g1 = f8 * (Int64)g1; + Int64 f8g2_19 = f8 * (Int64)g2_19; + Int64 f8g3_19 = f8 * (Int64)g3_19; + Int64 f8g4_19 = f8 * (Int64)g4_19; + Int64 f8g5_19 = f8 * (Int64)g5_19; + Int64 f8g6_19 = f8 * (Int64)g6_19; + Int64 f8g7_19 = f8 * (Int64)g7_19; + Int64 f8g8_19 = f8 * (Int64)g8_19; + Int64 f8g9_19 = f8 * (Int64)g9_19; + Int64 f9g0 = f9 * (Int64)g0; + Int64 f9g1_38 = f9_2 * (Int64)g1_19; + Int64 f9g2_19 = f9 * (Int64)g2_19; + Int64 f9g3_38 = f9_2 * (Int64)g3_19; + Int64 f9g4_19 = f9 * (Int64)g4_19; + Int64 f9g5_38 = f9_2 * (Int64)g5_19; + Int64 f9g6_19 = f9 * (Int64)g6_19; + Int64 f9g7_38 = f9_2 * (Int64)g7_19; + Int64 f9g8_19 = f9 * (Int64)g8_19; + Int64 f9g9_38 = f9_2 * (Int64)g9_19; + Int64 h0 = f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38; + Int64 h1 = f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19; + Int64 h2 = f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38; + Int64 h3 = f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19; + Int64 h4 = f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38; + Int64 h5 = f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19; + Int64 h6 = f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38; + Int64 h7 = f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19; + Int64 h8 = f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38; + Int64 h9 = f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (Int64)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (Int64)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (Int64)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h.x0 = (Int32)h0; + h.x1 = (Int32)h1; + h.x2 = (Int32)h2; + h.x3 = (Int32)h3; + h.x4 = (Int32)h4; + h.x5 = (Int32)h5; + h.x6 = (Int32)h6; + h.x7 = (Int32)h7; + h.x8 = (Int32)h8; + h.x9 = (Int32)h9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_mul121666.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_mul121666.cs new file mode 100644 index 00000000..5112f527 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_mul121666.cs @@ -0,0 +1,76 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + + /* + h = f * 121666 + Can overlap h with f. + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + + Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + */ + + internal static void fe_mul121666(out FieldElement h, ref FieldElement f) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int64 h0 = f0 * (Int64)121666; + Int64 h1 = f1 * (Int64)121666; + Int64 h2 = f2 * (Int64)121666; + Int64 h3 = f3 * (Int64)121666; + Int64 h4 = f4 * (Int64)121666; + Int64 h5 = f5 * (Int64)121666; + Int64 h6 = f6 * (Int64)121666; + Int64 h7 = f7 * (Int64)121666; + Int64 h8 = f8 * (Int64)121666; + Int64 h9 = f9 * (Int64)121666; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (Int64)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (Int64)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (Int64)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h.x0 = (int)h0; + h.x1 = (int)h1; + h.x2 = (int)h2; + h.x3 = (int)h3; + h.x4 = (int)h4; + h.x5 = (int)h5; + h.x6 = (int)h6; + h.x7 = (int)h7; + h.x8 = (int)h8; + h.x9 = (int)h9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_neg.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_neg.cs new file mode 100644 index 00000000..f73bd4a5 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_neg.cs @@ -0,0 +1,50 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = -f + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + */ + internal static void fe_neg(out FieldElement h, ref FieldElement f) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 h0 = -f0; + Int32 h1 = -f1; + Int32 h2 = -f2; + Int32 h3 = -f3; + Int32 h4 = -f4; + Int32 h5 = -f5; + Int32 h6 = -f6; + Int32 h7 = -f7; + Int32 h8 = -f8; + Int32 h9 = -f9; + h.x0 = h0; + h.x1 = h1; + h.x2 = h2; + h.x3 = h3; + h.x4 = h4; + h.x5 = h5; + h.x6 = h6; + h.x7 = h7; + h.x8 = h8; + h.x9 = h9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_pow22523.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_pow22523.cs new file mode 100644 index 00000000..0686e2d5 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_pow22523.cs @@ -0,0 +1,175 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + internal static void fe_pow22523(out FieldElement result, ref FieldElement z) + { + FieldElement t0; + FieldElement t1; + FieldElement t2; + int i; + + /* qhasm: fe z1 */ + + /* qhasm: fe z2 */ + + /* qhasm: fe z8 */ + + /* qhasm: fe z9 */ + + /* qhasm: fe z11 */ + + /* qhasm: fe z22 */ + + /* qhasm: fe z_5_0 */ + + /* qhasm: fe z_10_5 */ + + /* qhasm: fe z_10_0 */ + + /* qhasm: fe z_20_10 */ + + /* qhasm: fe z_20_0 */ + + /* qhasm: fe z_40_20 */ + + /* qhasm: fe z_40_0 */ + + /* qhasm: fe z_50_10 */ + + /* qhasm: fe z_50_0 */ + + /* qhasm: fe z_100_50 */ + + /* qhasm: fe z_100_0 */ + + /* qhasm: fe z_200_100 */ + + /* qhasm: fe z_200_0 */ + + /* qhasm: fe z_250_50 */ + + /* qhasm: fe z_250_0 */ + + /* qhasm: fe z_252_2 */ + + /* qhasm: fe z_252_3 */ + + /* qhasm: enter pow22523 */ + + /* qhasm: z2 = z1^2^1 */ + /* asm 1: fe_sq(>z2=fe#1,z2=fe#1,>z2=fe#1); */ + /* asm 2: fe_sq(>z2=t0,z2=t0,>z2=t0); */ + fe_sq(out t0, ref z); //for (i = 1; i < 1; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z8 = z2^2^2 */ + /* asm 1: fe_sq(>z8=fe#2,z8=fe#2,>z8=fe#2); */ + /* asm 2: fe_sq(>z8=t1,z8=t1,>z8=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 2; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z9 = z1*z8 */ + /* asm 1: fe_mul(>z9=fe#2,z9=t1,z11=fe#1,z11=t0,z22=fe#1,z22=fe#1,>z22=fe#1); */ + /* asm 2: fe_sq(>z22=t0,z22=t0,>z22=t0); */ + fe_sq(out t0, ref t0); //for (i = 1; i < 1; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z_5_0 = z9*z22 */ + /* asm 1: fe_mul(>z_5_0=fe#1,z_5_0=t0,z_10_5=fe#2,z_10_5=fe#2,>z_10_5=fe#2); */ + /* asm 2: fe_sq(>z_10_5=t1,z_10_5=t1,>z_10_5=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 5; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_10_0 = z_10_5*z_5_0 */ + /* asm 1: fe_mul(>z_10_0=fe#1,z_10_0=t0,z_20_10=fe#2,z_20_10=fe#2,>z_20_10=fe#2); */ + /* asm 2: fe_sq(>z_20_10=t1,z_20_10=t1,>z_20_10=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 10; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_20_0 = z_20_10*z_10_0 */ + /* asm 1: fe_mul(>z_20_0=fe#2,z_20_0=t1,z_40_20=fe#3,z_40_20=fe#3,>z_40_20=fe#3); */ + /* asm 2: fe_sq(>z_40_20=t2,z_40_20=t2,>z_40_20=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 20; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_40_0 = z_40_20*z_20_0 */ + /* asm 1: fe_mul(>z_40_0=fe#2,z_40_0=t1,z_50_10=fe#2,z_50_10=fe#2,>z_50_10=fe#2); */ + /* asm 2: fe_sq(>z_50_10=t1,z_50_10=t1,>z_50_10=t1); */ + fe_sq(out t1, ref t1); for (i = 1; i < 10; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_50_0 = z_50_10*z_10_0 */ + /* asm 1: fe_mul(>z_50_0=fe#1,z_50_0=t0,z_100_50=fe#2,z_100_50=fe#2,>z_100_50=fe#2); */ + /* asm 2: fe_sq(>z_100_50=t1,z_100_50=t1,>z_100_50=t1); */ + fe_sq(out t1, ref t0); for (i = 1; i < 50; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_100_0 = z_100_50*z_50_0 */ + /* asm 1: fe_mul(>z_100_0=fe#2,z_100_0=t1,z_200_100=fe#3,z_200_100=fe#3,>z_200_100=fe#3); */ + /* asm 2: fe_sq(>z_200_100=t2,z_200_100=t2,>z_200_100=t2); */ + fe_sq(out t2, ref t1); for (i = 1; i < 100; ++i) fe_sq(out t2, ref t2); + + /* qhasm: z_200_0 = z_200_100*z_100_0 */ + /* asm 1: fe_mul(>z_200_0=fe#2,z_200_0=t1,z_250_50=fe#2,z_250_50=fe#2,>z_250_50=fe#2); */ + /* asm 2: fe_sq(>z_250_50=t1,z_250_50=t1,>z_250_50=t1); */ + fe_sq(out t1, ref t1); for (i = 1; i < 50; ++i) fe_sq(out t1, ref t1); + + /* qhasm: z_250_0 = z_250_50*z_50_0 */ + /* asm 1: fe_mul(>z_250_0=fe#1,z_250_0=t0,z_252_2=fe#1,z_252_2=fe#1,>z_252_2=fe#1); */ + /* asm 2: fe_sq(>z_252_2=t0,z_252_2=t0,>z_252_2=t0); */ + fe_sq(out t0, ref t0); for (i = 1; i < 2; ++i) fe_sq(out t0, ref t0); + + /* qhasm: z_252_3 = z_252_2*z1 */ + /* asm 1: fe_mul(>z_252_3=fe#12,z_252_3=out,> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + carry1 = (h1 + (Int64)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + + carry2 = (h2 + (Int64)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + + carry3 = (h3 + (Int64)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h.x0 = (Int32)h0; + h.x1 = (Int32)h1; + h.x2 = (Int32)h2; + h.x3 = (Int32)h3; + h.x4 = (Int32)h4; + h.x5 = (Int32)h5; + h.x6 = (Int32)h6; + h.x7 = (Int32)h7; + h.x8 = (Int32)h8; + h.x9 = (Int32)h9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_sq2.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_sq2.cs new file mode 100644 index 00000000..a869311b --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_sq2.cs @@ -0,0 +1,164 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* +h = 2 * f * f +Can overlap h with f. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + + /* + See fe_mul.c for discussion of implementation strategy. + */ + internal static void fe_sq2(out FieldElement h, ref FieldElement f) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 f0_2 = 2 * f0; + Int32 f1_2 = 2 * f1; + Int32 f2_2 = 2 * f2; + Int32 f3_2 = 2 * f3; + Int32 f4_2 = 2 * f4; + Int32 f5_2 = 2 * f5; + Int32 f6_2 = 2 * f6; + Int32 f7_2 = 2 * f7; + Int32 f5_38 = 38 * f5; /* 1.959375*2^30 */ + Int32 f6_19 = 19 * f6; /* 1.959375*2^30 */ + Int32 f7_38 = 38 * f7; /* 1.959375*2^30 */ + Int32 f8_19 = 19 * f8; /* 1.959375*2^30 */ + Int32 f9_38 = 38 * f9; /* 1.959375*2^30 */ + Int64 f0f0 = f0 * (Int64)f0; + Int64 f0f1_2 = f0_2 * (Int64)f1; + Int64 f0f2_2 = f0_2 * (Int64)f2; + Int64 f0f3_2 = f0_2 * (Int64)f3; + Int64 f0f4_2 = f0_2 * (Int64)f4; + Int64 f0f5_2 = f0_2 * (Int64)f5; + Int64 f0f6_2 = f0_2 * (Int64)f6; + Int64 f0f7_2 = f0_2 * (Int64)f7; + Int64 f0f8_2 = f0_2 * (Int64)f8; + Int64 f0f9_2 = f0_2 * (Int64)f9; + Int64 f1f1_2 = f1_2 * (Int64)f1; + Int64 f1f2_2 = f1_2 * (Int64)f2; + Int64 f1f3_4 = f1_2 * (Int64)f3_2; + Int64 f1f4_2 = f1_2 * (Int64)f4; + Int64 f1f5_4 = f1_2 * (Int64)f5_2; + Int64 f1f6_2 = f1_2 * (Int64)f6; + Int64 f1f7_4 = f1_2 * (Int64)f7_2; + Int64 f1f8_2 = f1_2 * (Int64)f8; + Int64 f1f9_76 = f1_2 * (Int64)f9_38; + Int64 f2f2 = f2 * (Int64)f2; + Int64 f2f3_2 = f2_2 * (Int64)f3; + Int64 f2f4_2 = f2_2 * (Int64)f4; + Int64 f2f5_2 = f2_2 * (Int64)f5; + Int64 f2f6_2 = f2_2 * (Int64)f6; + Int64 f2f7_2 = f2_2 * (Int64)f7; + Int64 f2f8_38 = f2_2 * (Int64)f8_19; + Int64 f2f9_38 = f2 * (Int64)f9_38; + Int64 f3f3_2 = f3_2 * (Int64)f3; + Int64 f3f4_2 = f3_2 * (Int64)f4; + Int64 f3f5_4 = f3_2 * (Int64)f5_2; + Int64 f3f6_2 = f3_2 * (Int64)f6; + Int64 f3f7_76 = f3_2 * (Int64)f7_38; + Int64 f3f8_38 = f3_2 * (Int64)f8_19; + Int64 f3f9_76 = f3_2 * (Int64)f9_38; + Int64 f4f4 = f4 * (Int64)f4; + Int64 f4f5_2 = f4_2 * (Int64)f5; + Int64 f4f6_38 = f4_2 * (Int64)f6_19; + Int64 f4f7_38 = f4 * (Int64)f7_38; + Int64 f4f8_38 = f4_2 * (Int64)f8_19; + Int64 f4f9_38 = f4 * (Int64)f9_38; + Int64 f5f5_38 = f5 * (Int64)f5_38; + Int64 f5f6_38 = f5_2 * (Int64)f6_19; + Int64 f5f7_76 = f5_2 * (Int64)f7_38; + Int64 f5f8_38 = f5_2 * (Int64)f8_19; + Int64 f5f9_76 = f5_2 * (Int64)f9_38; + Int64 f6f6_19 = f6 * (Int64)f6_19; + Int64 f6f7_38 = f6 * (Int64)f7_38; + Int64 f6f8_38 = f6_2 * (Int64)f8_19; + Int64 f6f9_38 = f6 * (Int64)f9_38; + Int64 f7f7_38 = f7 * (Int64)f7_38; + Int64 f7f8_38 = f7_2 * (Int64)f8_19; + Int64 f7f9_76 = f7_2 * (Int64)f9_38; + Int64 f8f8_19 = f8 * (Int64)f8_19; + Int64 f8f9_38 = f8 * (Int64)f9_38; + Int64 f9f9_38 = f9 * (Int64)f9_38; + Int64 h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + Int64 h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + Int64 h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + Int64 h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + Int64 h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + Int64 h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + Int64 h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + Int64 h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + Int64 h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + Int64 h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + carry1 = (h1 + (Int64)(1 << 24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (Int64)(1 << 24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + + carry2 = (h2 + (Int64)(1 << 25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (Int64)(1 << 25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + + carry3 = (h3 + (Int64)(1 << 24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (Int64)(1 << 24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (Int64)(1 << 25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (Int64)(1 << 25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + carry9 = (h9 + (Int64)(1 << 24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (Int64)(1 << 25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h.x0 = (Int32)h0; + h.x1 = (Int32)h1; + h.x2 = (Int32)h2; + h.x3 = (Int32)h3; + h.x4 = (Int32)h4; + h.x5 = (Int32)h5; + h.x6 = (Int32)h6; + h.x7 = (Int32)h7; + h.x8 = (Int32)h8; + h.x9 = (Int32)h9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_sub.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_sub.cs new file mode 100644 index 00000000..7eec1c60 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_sub.cs @@ -0,0 +1,63 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + h = f - g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + */ + + internal static void fe_sub(out FieldElement h, ref FieldElement f, ref FieldElement g) + { + Int32 f0 = f.x0; + Int32 f1 = f.x1; + Int32 f2 = f.x2; + Int32 f3 = f.x3; + Int32 f4 = f.x4; + Int32 f5 = f.x5; + Int32 f6 = f.x6; + Int32 f7 = f.x7; + Int32 f8 = f.x8; + Int32 f9 = f.x9; + Int32 g0 = g.x0; + Int32 g1 = g.x1; + Int32 g2 = g.x2; + Int32 g3 = g.x3; + Int32 g4 = g.x4; + Int32 g5 = g.x5; + Int32 g6 = g.x6; + Int32 g7 = g.x7; + Int32 g8 = g.x8; + Int32 g9 = g.x9; + Int32 h0 = f0 - g0; + Int32 h1 = f1 - g1; + Int32 h2 = f2 - g2; + Int32 h3 = f3 - g3; + Int32 h4 = f4 - g4; + Int32 h5 = f5 - g5; + Int32 h6 = f6 - g6; + Int32 h7 = f7 - g7; + Int32 h8 = f8 - g8; + Int32 h9 = f9 - g9; + h.x0 = h0; + h.x1 = h1; + h.x2 = h2; + h.x3 = h3; + h.x4 = h4; + h.x5 = h5; + h.x6 = h6; + h.x7 = h7; + h.x8 = h8; + h.x9 = h9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_tobytes.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_tobytes.cs new file mode 100644 index 00000000..27167e41 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/fe_tobytes.cs @@ -0,0 +1,154 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class FieldOperations + { + /* + Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + + Write p=2^255-19; q=floor(h/p). + Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + + Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 0); + s[offset + 1] = (byte) (h0 >> 8); + s[offset + 2] = (byte) (h0 >> 16); + s[offset + 3] = (byte) ((h0 >> 24) | (h1 << 2)); + s[offset + 4] = (byte) (h1 >> 6); + s[offset + 5] = (byte) (h1 >> 14); + s[offset + 6] = (byte) ((h1 >> 22) | (h2 << 3)); + s[offset + 7] = (byte) (h2 >> 5); + s[offset + 8] = (byte) (h2 >> 13); + s[offset + 9] = (byte) ((h2 >> 21) | (h3 << 5)); + s[offset + 10] = (byte) (h3 >> 3); + s[offset + 11] = (byte) (h3 >> 11); + s[offset + 12] = (byte) ((h3 >> 19) | (h4 << 6)); + s[offset + 13] = (byte) (h4 >> 2); + s[offset + 14] = (byte) (h4 >> 10); + s[offset + 15] = (byte) (h4 >> 18); + s[offset + 16] = (byte) (h5 >> 0); + s[offset + 17] = (byte) (h5 >> 8); + s[offset + 18] = (byte) (h5 >> 16); + s[offset + 19] = (byte) ((h5 >> 24) | (h6 << 1)); + s[offset + 20] = (byte) (h6 >> 7); + s[offset + 21] = (byte) (h6 >> 15); + s[offset + 22] = (byte) ((h6 >> 23) | (h7 << 3)); + s[offset + 23] = (byte) (h7 >> 5); + s[offset + 24] = (byte) (h7 >> 13); + s[offset + 25] = (byte) ((h7 >> 21) | (h8 << 4)); + s[offset + 26] = (byte) (h8 >> 4); + s[offset + 27] = (byte) (h8 >> 12); + s[offset + 28] = (byte) ((h8 >> 20) | (h9 << 6)); + s[offset + 29] = (byte) (h9 >> 2); + s[offset + 30] = (byte) (h9 >> 10); + s[offset + 31] = (byte) (h9 >> 18); + } + } + + internal static void fe_reduce(out FieldElement hr, ref FieldElement h) + { + Int32 h0 = h.x0; + Int32 h1 = h.x1; + Int32 h2 = h.x2; + Int32 h3 = h.x3; + Int32 h4 = h.x4; + Int32 h5 = h.x5; + Int32 h6 = h.x6; + Int32 h7 = h.x7; + Int32 h8 = h.x8; + Int32 h9 = h.x9; + Int32 q; + Int32 carry0; + Int32 carry1; + Int32 carry2; + Int32 carry3; + Int32 carry4; + Int32 carry5; + Int32 carry6; + Int32 carry7; + Int32 carry8; + Int32 carry9; + + q = (19 * h9 + (((Int32)1) << 24)) >> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26; + carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25; + carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26; + carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25; + carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26; + carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25; + carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26; + carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25; + carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26; + carry9 = h9 >> 25; h9 -= carry9 << 25; + /* h10 = carry9 */ + + hr.x0 = h0; + hr.x1 = h1; + hr.x2 = h2; + hr.x3 = h3; + hr.x4 = h4; + hr.x5 = h5; + hr.x6 = h6; + hr.x7 = h7; + hr.x8 = h8; + hr.x9 = h9; + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_add.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_add.cs new file mode 100644 index 00000000..9b1129c1 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_add.cs @@ -0,0 +1,113 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class GroupOperations + { + /* + r = p + q + */ + + internal static void ge_add(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementCached q) + { + FieldElement t0; + + /* qhasm: enter GroupElementadd */ + + /* qhasm: fe X1 */ + + /* qhasm: fe Y1 */ + + /* qhasm: fe Z1 */ + + /* qhasm: fe Z2 */ + + /* qhasm: fe T1 */ + + /* qhasm: fe ZZ */ + + /* qhasm: fe YpX2 */ + + /* qhasm: fe YmX2 */ + + /* qhasm: fe T2d2 */ + + /* qhasm: fe X3 */ + + /* qhasm: fe Y3 */ + + /* qhasm: fe Z3 */ + + /* qhasm: fe T3 */ + + /* qhasm: fe YpX1 */ + + /* qhasm: fe YmX1 */ + + /* qhasm: fe A */ + + /* qhasm: fe B */ + + /* qhasm: fe C */ + + /* qhasm: fe D */ + + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,ZZ=fe#1,ZZ=r.X,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,> 3] >> (i & 7))); + + for (i = 0; i < 256; ++i) + if (r[i] != 0) + { + for (b = 1; b <= 6 && i + b < 256; ++b) + { + if (r[i + b] != 0) + { + if (r[i] + (r[i + b] << b) <= 15) + { + r[i] += (sbyte)(r[i + b] << b); r[i + b] = 0; + } + else if (r[i] - (r[i + b] << b) >= -15) + { + r[i] -= (sbyte)(r[i + b] << b); + for (k = i + b; k < 256; ++k) + { + if (r[k] == 0) + { + r[k] = 1; + break; + } + r[k] = 0; + } + } + else + break; + } + } + } + + } + + /* + r = a * A + b * B + where a = a[0]+256*a[1]+...+256^31 a[31]. + and b = b[0]+256*b[1]+...+256^31 b[31]. + B is the Ed25519 base point (x,4/5) with x positive. + */ + + internal static void ge_double_scalarmult_vartime(out GroupElementP2 r, byte[] a, ref GroupElementP3 A, byte[] b) + { + GroupElementPreComp[] Bi = LookupTables.Base2; + // todo: Perhaps remove these allocations? + sbyte[] aslide = new sbyte[256]; + sbyte[] bslide = new sbyte[256]; + GroupElementCached[] Ai = new GroupElementCached[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ + GroupElementP1P1 t; + GroupElementP3 u; + GroupElementP3 A2; + int i; + + slide(aslide, a); + slide(bslide, b); + + ge_p3_to_cached(out Ai[0], ref A); + ge_p3_dbl(out t, ref A); ge_p1p1_to_p3(out A2, ref t); + ge_add(out t, ref A2, ref Ai[0]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[1], ref u); + ge_add(out t, ref A2, ref Ai[1]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[2], ref u); + ge_add(out t, ref A2, ref Ai[2]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[3], ref u); + ge_add(out t, ref A2, ref Ai[3]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[4], ref u); + ge_add(out t, ref A2, ref Ai[4]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[5], ref u); + ge_add(out t, ref A2, ref Ai[5]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[6], ref u); + ge_add(out t, ref A2, ref Ai[6]); ge_p1p1_to_p3(out u, ref t); ge_p3_to_cached(out Ai[7], ref u); + + ge_p2_0(out r); + + for (i = 255; i >= 0; --i) + { + if ((aslide[i] != 0) || (bslide[i] != 0)) break; + } + + for (; i >= 0; --i) + { + ge_p2_dbl(out t, ref r); + + if (aslide[i] > 0) + { + ge_p1p1_to_p3(out u, ref t); + ge_add(out t, ref u, ref Ai[aslide[i] / 2]); + } + else if (aslide[i] < 0) + { + ge_p1p1_to_p3(out u, ref t); + ge_sub(out t, ref u, ref Ai[(-aslide[i]) / 2]); + } + + if (bslide[i] > 0) + { + ge_p1p1_to_p3(out u, ref t); + ge_madd(out t, ref u, ref Bi[bslide[i] / 2]); + } + else if (bslide[i] < 0) + { + ge_p1p1_to_p3(out u, ref t); + ge_msub(out t, ref u, ref Bi[(-bslide[i]) / 2]); + } + + ge_p1p1_to_p2(out r, ref t); + } + } + + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_frombytes.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_frombytes.cs new file mode 100644 index 00000000..38bfcfeb --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_frombytes.cs @@ -0,0 +1,54 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class GroupOperations + { + internal static int ge_frombytes_negate_vartime(out GroupElementP3 h, byte[] data, int offset) + { + FieldElement u; + FieldElement v; + FieldElement v3; + FieldElement vxx; + FieldElement check; + + FieldOperations.fe_frombytes(out h.Y, data, offset); + FieldOperations.fe_1(out h.Z); + FieldOperations.fe_sq(out u, ref h.Y); + FieldOperations.fe_mul(out v, ref u, ref LookupTables.d); + FieldOperations.fe_sub(out u, ref u, ref h.Z); /* u = y^2-1 */ + FieldOperations.fe_add(out v, ref v, ref h.Z); /* v = dy^2+1 */ + + FieldOperations.fe_sq(out v3, ref v); + FieldOperations.fe_mul(out v3, ref v3, ref v); /* v3 = v^3 */ + FieldOperations.fe_sq(out h.X, ref v3); + FieldOperations.fe_mul(out h.X, ref h.X, ref v); + FieldOperations.fe_mul(out h.X, ref h.X, ref u); /* x = uv^7 */ + + FieldOperations.fe_pow22523(out h.X, ref h.X); /* x = (uv^7)^((q-5)/8) */ + FieldOperations.fe_mul(out h.X, ref h.X, ref v3); + FieldOperations.fe_mul(out h.X, ref h.X, ref u); /* x = uv^3(uv^7)^((q-5)/8) */ + + FieldOperations.fe_sq(out vxx, ref h.X); + FieldOperations.fe_mul(out vxx, ref vxx, ref v); + FieldOperations.fe_sub(out check, ref vxx, ref u); /* vx^2-u */ + if (FieldOperations.fe_isnonzero(ref check) != 0) + { + FieldOperations.fe_add(out check, ref vxx, ref u); /* vx^2+u */ + if (FieldOperations.fe_isnonzero(ref check) != 0) + { + h = default(GroupElementP3); + return -1; + } + FieldOperations.fe_mul(out h.X, ref h.X, ref LookupTables.sqrtm1); + } + + if (FieldOperations.fe_isnegative(ref h.X) == (data[offset + 31] >> 7)) + FieldOperations.fe_neg(out h.X, ref h.X); + + FieldOperations.fe_mul(out h.T, ref h.X, ref h.Y); + return 0; + } + + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_madd.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_madd.cs new file mode 100644 index 00000000..8832d3e9 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_madd.cs @@ -0,0 +1,105 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class GroupOperations + { + /* + r = p + q + */ + internal static void ge_madd(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementPreComp q) + { + FieldElement t0; + + /* qhasm: enter ge_madd */ + + /* qhasm: fe X1 */ + + /* qhasm: fe Y1 */ + + /* qhasm: fe Z1 */ + + /* qhasm: fe T1 */ + + /* qhasm: fe ypx2 */ + + /* qhasm: fe ymx2 */ + + /* qhasm: fe xy2d2 */ + + /* qhasm: fe X3 */ + + /* qhasm: fe Y3 */ + + /* qhasm: fe Z3 */ + + /* qhasm: fe T3 */ + + /* qhasm: fe YpX1 */ + + /* qhasm: fe YmX1 */ + + /* qhasm: fe A */ + + /* qhasm: fe B */ + + /* qhasm: fe C */ + + /* qhasm: fe D */ + + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,XX=fe#1,XX=r.X,YY=fe#3,YY=r.Z,B=fe#4,B=r.T,A=fe#2,A=r.Y,AA=fe#5,AA=t0,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,X3=fe#1,X3=r.X,T3=fe#4,T3=r.T,>= 31; /* 1: yes; 0: no */ + return (byte)y; + } + + static byte negative(sbyte b) + { + ulong x = unchecked((ulong)(long)b); /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return (byte)x; + } + + static void cmov(ref GroupElementPreComp t, ref GroupElementPreComp u, byte b) + { + FieldOperations.fe_cmov(ref t.yplusx, ref u.yplusx, b); + FieldOperations.fe_cmov(ref t.yminusx, ref u.yminusx, b); + FieldOperations.fe_cmov(ref t.xy2d, ref u.xy2d, b); + } + + static void select(out GroupElementPreComp t, int pos, sbyte b) + { + GroupElementPreComp minust; + byte bnegative = negative(b); + byte babs = (byte)(b - (((-bnegative) & b) << 1)); + + ge_precomp_0(out t); + var table = LookupTables.Base[pos]; + cmov(ref t, ref table[0], equal(babs, 1)); + cmov(ref t, ref table[1], equal(babs, 2)); + cmov(ref t, ref table[2], equal(babs, 3)); + cmov(ref t, ref table[3], equal(babs, 4)); + cmov(ref t, ref table[4], equal(babs, 5)); + cmov(ref t, ref table[5], equal(babs, 6)); + cmov(ref t, ref table[6], equal(babs, 7)); + cmov(ref t, ref table[7], equal(babs, 8)); + minust.yplusx = t.yminusx; + minust.yminusx = t.yplusx; + FieldOperations.fe_neg(out minust.xy2d, ref t.xy2d); + cmov(ref t, ref minust, bnegative); + } + + /* + h = a * B + where a = a[0]+256*a[1]+...+256^31 a[31] + B is the Ed25519 base point (x,4/5) with x positive. + + Preconditions: + a[31] <= 127 + */ + + internal static void ge_scalarmult_base(out GroupElementP3 h, byte[] a, int offset) + { + // todo: Perhaps remove this allocation + sbyte[] e = new sbyte[64]; + sbyte carry; + GroupElementP1P1 r; + GroupElementP2 s; + GroupElementPreComp t; + int i; + + for (i = 0; i < 32; ++i) + { + e[2 * i + 0] = (sbyte)((a[offset + i] >> 0) & 15); + e[2 * i + 1] = (sbyte)((a[offset + i] >> 4) & 15); + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (i = 0; i < 63; ++i) + { + e[i] += carry; + carry = (sbyte)(e[i] + 8); + carry >>= 4; + e[i] -= (sbyte)(carry << 4); + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge_p3_0(out h); + for (i = 1; i < 64; i += 2) + { + select(out t, i / 2, e[i]); + ge_madd(out r, ref h, ref t); ge_p1p1_to_p3(out h, ref r); + } + + ge_p3_dbl(out r, ref h); ge_p1p1_to_p2(out s, ref r); + ge_p2_dbl(out r, ref s); ge_p1p1_to_p2(out s, ref r); + ge_p2_dbl(out r, ref s); ge_p1p1_to_p2(out s, ref r); + ge_p2_dbl(out r, ref s); ge_p1p1_to_p3(out h, ref r); + + for (i = 0; i < 64; i += 2) + { + select(out t, i / 2, e[i]); + ge_madd(out r, ref h, ref t); ge_p1p1_to_p3(out h, ref r); + } + } + + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_sub.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_sub.cs new file mode 100644 index 00000000..83cc5b27 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/ge_sub.cs @@ -0,0 +1,114 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class GroupOperations + { + /* + r = p - q + */ + + internal static void ge_sub(out GroupElementP1P1 r, ref GroupElementP3 p, ref GroupElementCached q) + { + FieldElement t0; + + /* qhasm: enter ge_sub */ + + /* qhasm: fe X1 */ + + /* qhasm: fe Y1 */ + + /* qhasm: fe Z1 */ + + /* qhasm: fe Z2 */ + + /* qhasm: fe T1 */ + + /* qhasm: fe ZZ */ + + /* qhasm: fe YpX2 */ + + /* qhasm: fe YmX2 */ + + /* qhasm: fe T2d2 */ + + /* qhasm: fe X3 */ + + /* qhasm: fe Y3 */ + + /* qhasm: fe Z3 */ + + /* qhasm: fe T3 */ + + /* qhasm: fe YpX1 */ + + /* qhasm: fe YmX1 */ + + /* qhasm: fe A */ + + /* qhasm: fe B */ + + /* qhasm: fe C */ + + /* qhasm: fe D */ + + /* qhasm: YpX1 = Y1+X1 */ + /* asm 1: fe_add(>YpX1=fe#1,YpX1=r.X,YmX1=fe#2,YmX1=r.Y,A=fe#3,A=r.Z,B=fe#2,B=r.Y,C=fe#4,C=r.T,ZZ=fe#1,ZZ=r.X,D=fe#5,D=t0,X3=fe#1,X3=r.X,Y3=fe#2,Y3=r.Y,Z3=fe#3,Z3=r.Z,T3=fe#4,T3=r.T,> 5); + Int64 a2 = 2097151 & (load_3(a, 5) >> 2); + Int64 a3 = 2097151 & (load_4(a, 7) >> 7); + Int64 a4 = 2097151 & (load_4(a, 10) >> 4); + Int64 a5 = 2097151 & (load_3(a, 13) >> 1); + Int64 a6 = 2097151 & (load_4(a, 15) >> 6); + Int64 a7 = 2097151 & (load_3(a, 18) >> 3); + Int64 a8 = 2097151 & load_3(a, 21); + Int64 a9 = 2097151 & (load_4(a, 23) >> 5); + Int64 a10 = 2097151 & (load_3(a, 26) >> 2); + Int64 a11 = (load_4(a, 28) >> 7); + Int64 b0 = 2097151 & load_3(b, 0); + Int64 b1 = 2097151 & (load_4(b, 2) >> 5); + Int64 b2 = 2097151 & (load_3(b, 5) >> 2); + Int64 b3 = 2097151 & (load_4(b, 7) >> 7); + Int64 b4 = 2097151 & (load_4(b, 10) >> 4); + Int64 b5 = 2097151 & (load_3(b, 13) >> 1); + Int64 b6 = 2097151 & (load_4(b, 15) >> 6); + Int64 b7 = 2097151 & (load_3(b, 18) >> 3); + Int64 b8 = 2097151 & load_3(b, 21); + Int64 b9 = 2097151 & (load_4(b, 23) >> 5); + Int64 b10 = 2097151 & (load_3(b, 26) >> 2); + Int64 b11 = (load_4(b, 28) >> 7); + Int64 c0 = 2097151 & load_3(c, 0); + Int64 c1 = 2097151 & (load_4(c, 2) >> 5); + Int64 c2 = 2097151 & (load_3(c, 5) >> 2); + Int64 c3 = 2097151 & (load_4(c, 7) >> 7); + Int64 c4 = 2097151 & (load_4(c, 10) >> 4); + Int64 c5 = 2097151 & (load_3(c, 13) >> 1); + Int64 c6 = 2097151 & (load_4(c, 15) >> 6); + Int64 c7 = 2097151 & (load_3(c, 18) >> 3); + Int64 c8 = 2097151 & load_3(c, 21); + Int64 c9 = 2097151 & (load_4(c, 23) >> 5); + Int64 c10 = 2097151 & (load_3(c, 26) >> 2); + Int64 c11 = (load_4(c, 28) >> 7); + Int64 s0; + Int64 s1; + Int64 s2; + Int64 s3; + Int64 s4; + Int64 s5; + Int64 s6; + Int64 s7; + Int64 s8; + Int64 s9; + Int64 s10; + Int64 s11; + Int64 s12; + Int64 s13; + Int64 s14; + Int64 s15; + Int64 s16; + Int64 s17; + Int64 s18; + Int64 s19; + Int64 s20; + Int64 s21; + Int64 s22; + Int64 s23; + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + Int64 carry10; + Int64 carry11; + Int64 carry12; + Int64 carry13; + Int64 carry14; + Int64 carry15; + Int64 carry16; + Int64 carry17; + Int64 carry18; + Int64 carry19; + Int64 carry20; + Int64 carry21; + Int64 carry22; + + s0 = c0 + a0 * b0; + s1 = c1 + a0 * b1 + a1 * b0; + s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0; + s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; + s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; + s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; + s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0; + s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0; + s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; + s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; + s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0; + s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1; + s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2; + s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3; + s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4; + s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5; + s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6; + s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7; + s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8; + s20 = a9 * b11 + a10 * b10 + a11 * b9; + s21 = a10 * b11 + a11 * b10; + s22 = a11 * b11; + s23 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + carry18 = (s18 + (1 << 20)) >> 21; s19 += carry18; s18 -= carry18 << 21; + carry20 = (s20 + (1 << 20)) >> 21; s21 += carry20; s20 -= carry20 << 21; + carry22 = (s22 + (1 << 20)) >> 21; s23 += carry22; s22 -= carry22 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + carry17 = (s17 + (1 << 20)) >> 21; s18 += carry17; s17 -= carry17 << 21; + carry19 = (s19 + (1 << 20)) >> 21; s20 += carry19; s19 -= carry19 << 21; + carry21 = (s21 + (1 << 20)) >> 21; s22 += carry21; s21 -= carry21 << 21; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s23 = 0; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s22 = 0; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s21 = 0; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s20 = 0; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s19 = 0; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + s18 = 0; + + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s17 = 0; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s16 = 0; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s15 = 0; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s14 = 0; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s13 = 0; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + unchecked + { + s[0] = (byte)(s0 >> 0); + s[1] = (byte)(s0 >> 8); + s[2] = (byte)((s0 >> 16) | (s1 << 5)); + s[3] = (byte)(s1 >> 3); + s[4] = (byte)(s1 >> 11); + s[5] = (byte)((s1 >> 19) | (s2 << 2)); + s[6] = (byte)(s2 >> 6); + s[7] = (byte)((s2 >> 14) | (s3 << 7)); + s[8] = (byte)(s3 >> 1); + s[9] = (byte)(s3 >> 9); + s[10] = (byte)((s3 >> 17) | (s4 << 4)); + s[11] = (byte)(s4 >> 4); + s[12] = (byte)(s4 >> 12); + s[13] = (byte)((s4 >> 20) | (s5 << 1)); + s[14] = (byte)(s5 >> 7); + s[15] = (byte)((s5 >> 15) | (s6 << 6)); + s[16] = (byte)(s6 >> 2); + s[17] = (byte)(s6 >> 10); + s[18] = (byte)((s6 >> 18) | (s7 << 3)); + s[19] = (byte)(s7 >> 5); + s[20] = (byte)(s7 >> 13); + s[21] = (byte)(s8 >> 0); + s[22] = (byte)(s8 >> 8); + s[23] = (byte)((s8 >> 16) | (s9 << 5)); + s[24] = (byte)(s9 >> 3); + s[25] = (byte)(s9 >> 11); + s[26] = (byte)((s9 >> 19) | (s10 << 2)); + s[27] = (byte)(s10 >> 6); + s[28] = (byte)((s10 >> 14) | (s11 << 7)); + s[29] = (byte)(s11 >> 1); + s[30] = (byte)(s11 >> 9); + s[31] = (byte)(s11 >> 17); + } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/sc_reduce.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/sc_reduce.cs new file mode 100644 index 00000000..e310331f --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/sc_reduce.cs @@ -0,0 +1,263 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static partial class ScalarOperations + { + /* + Input: + s[0]+256*s[1]+...+256^63*s[63] = s + + Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. + */ + + internal static void sc_reduce(byte[] s) + { + Int64 s0 = 2097151 & load_3(s, 0); + Int64 s1 = 2097151 & (load_4(s, 2) >> 5); + Int64 s2 = 2097151 & (load_3(s, 5) >> 2); + Int64 s3 = 2097151 & (load_4(s, 7) >> 7); + Int64 s4 = 2097151 & (load_4(s, 10) >> 4); + Int64 s5 = 2097151 & (load_3(s, 13) >> 1); + Int64 s6 = 2097151 & (load_4(s, 15) >> 6); + Int64 s7 = 2097151 & (load_3(s, 18) >> 3); + Int64 s8 = 2097151 & load_3(s, 21); + Int64 s9 = 2097151 & (load_4(s, 23) >> 5); + Int64 s10 = 2097151 & (load_3(s, 26) >> 2); + Int64 s11 = 2097151 & (load_4(s, 28) >> 7); + Int64 s12 = 2097151 & (load_4(s, 31) >> 4); + Int64 s13 = 2097151 & (load_3(s, 34) >> 1); + Int64 s14 = 2097151 & (load_4(s, 36) >> 6); + Int64 s15 = 2097151 & (load_3(s, 39) >> 3); + Int64 s16 = 2097151 & load_3(s, 42); + Int64 s17 = 2097151 & (load_4(s, 44) >> 5); + Int64 s18 = 2097151 & (load_3(s, 47) >> 2); + Int64 s19 = 2097151 & (load_4(s, 49) >> 7); + Int64 s20 = 2097151 & (load_4(s, 52) >> 4); + Int64 s21 = 2097151 & (load_3(s, 55) >> 1); + Int64 s22 = 2097151 & (load_4(s, 57) >> 6); + Int64 s23 = (load_4(s, 60) >> 3); + Int64 carry0; + Int64 carry1; + Int64 carry2; + Int64 carry3; + Int64 carry4; + Int64 carry5; + Int64 carry6; + Int64 carry7; + Int64 carry8; + Int64 carry9; + Int64 carry10; + Int64 carry11; + Int64 carry12; + Int64 carry13; + Int64 carry14; + Int64 carry15; + Int64 carry16; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s23 = 0; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s22 = 0; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s21 = 0; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s20 = 0; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s19 = 0; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + s18 = 0; + + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; s13 += carry12; s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; s15 += carry14; s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; s17 += carry16; s16 -= carry16 << 21; + + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; s14 += carry13; s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; s16 += carry15; s15 -= carry15 << 21; + + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s17 = 0; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s16 = 0; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s15 = 0; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s14 = 0; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s13 = 0; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = (s0 + (1 << 20)) >> 21; s1 += carry0; s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; s3 += carry2; s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; s5 += carry4; s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; s7 += carry6; s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; s9 += carry8; s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; s11 += carry10; s10 -= carry10 << 21; + + carry1 = (s1 + (1 << 20)) >> 21; s2 += carry1; s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; s4 += carry3; s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; s6 += carry5; s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; s8 += carry7; s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; s10 += carry9; s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21; + carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21; + carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21; + carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21; + carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21; + carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21; + carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21; + carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21; + carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21; + carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21; + carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21; + + unchecked + { + s[0] = (byte)(s0 >> 0); + s[1] = (byte)(s0 >> 8); + s[2] = (byte)((s0 >> 16) | (s1 << 5)); + s[3] = (byte)(s1 >> 3); + s[4] = (byte)(s1 >> 11); + s[5] = (byte)((s1 >> 19) | (s2 << 2)); + s[6] = (byte)(s2 >> 6); + s[7] = (byte)((s2 >> 14) | (s3 << 7)); + s[8] = (byte)(s3 >> 1); + s[9] = (byte)(s3 >> 9); + s[10] = (byte)((s3 >> 17) | (s4 << 4)); + s[11] = (byte)(s4 >> 4); + s[12] = (byte)(s4 >> 12); + s[13] = (byte)((s4 >> 20) | (s5 << 1)); + s[14] = (byte)(s5 >> 7); + s[15] = (byte)((s5 >> 15) | (s6 << 6)); + s[16] = (byte)(s6 >> 2); + s[17] = (byte)(s6 >> 10); + s[18] = (byte)((s6 >> 18) | (s7 << 3)); + s[19] = (byte)(s7 >> 5); + s[20] = (byte)(s7 >> 13); + s[21] = (byte)(s8 >> 0); + s[22] = (byte)(s8 >> 8); + s[23] = (byte)((s8 >> 16) | (s9 << 5)); + s[24] = (byte)(s9 >> 3); + s[25] = (byte)(s9 >> 11); + s[26] = (byte)((s9 >> 19) | (s10 << 2)); + s[27] = (byte)(s10 >> 6); + s[28] = (byte)((s10 >> 14) | (s11 << 7)); + s[29] = (byte)(s11 >> 1); + s[30] = (byte)(s11 >> 9); + s[31] = (byte)(s11 >> 17); + } + } + + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/scalarmult.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/scalarmult.cs new file mode 100644 index 00000000..5c439da7 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Ed25519Ref10/scalarmult.cs @@ -0,0 +1,205 @@ +using System; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10 +{ + internal static class MontgomeryOperations + { + internal static void scalarmult( + byte[] q, int qoffset, + byte[] n, int noffset, + byte[] p, int poffset) + { + FieldElement p0; + FieldElement q0; + FieldOperations.fe_frombytes2(out p0, p, poffset); + scalarmult(out q0, n, noffset, ref p0); + FieldOperations.fe_tobytes(q, qoffset, ref q0); + } + + internal static void scalarmult( + out FieldElement q, + byte[] n, int noffset, + ref FieldElement p) + { + byte[] e = new byte[32];//ToDo: remove allocation + UInt32 i; + FieldElement x1; + FieldElement x2; + FieldElement z2; + FieldElement x3; + FieldElement z3; + FieldElement tmp0; + FieldElement tmp1; + int pos; + UInt32 swap; + UInt32 b; + + for (i = 0; i < 32; ++i) + e[i] = n[noffset + i]; + ScalarOperations.sc_clamp(e, 0); + x1 = p; + FieldOperations.fe_1(out x2); + FieldOperations.fe_0(out z2); + x3 = x1; + FieldOperations.fe_1(out z3); + + swap = 0; + for (pos = 254; pos >= 0; --pos) + { + b = (uint)(e[pos / 8] >> (pos & 7)); + b &= 1; + swap ^= b; + FieldOperations.fe_cswap(ref x2, ref x3, swap); + FieldOperations.fe_cswap(ref z2, ref z3, swap); + swap = b; + /* qhasm: fe X2 */ + + /* qhasm: fe Z2 */ + + /* qhasm: fe X3 */ + + /* qhasm: fe Z3 */ + + /* qhasm: fe X4 */ + + /* qhasm: fe Z4 */ + + /* qhasm: fe X5 */ + + /* qhasm: fe Z5 */ + + /* qhasm: fe A */ + + /* qhasm: fe B */ + + /* qhasm: fe C */ + + /* qhasm: fe D */ + + /* qhasm: fe E */ + + /* qhasm: fe AA */ + + /* qhasm: fe BB */ + + /* qhasm: fe DA */ + + /* qhasm: fe CB */ + + /* qhasm: fe t0 */ + + /* qhasm: fe t1 */ + + /* qhasm: fe t2 */ + + /* qhasm: fe t3 */ + + /* qhasm: fe t4 */ + + /* qhasm: enter ladder */ + + /* qhasm: D = X3-Z3 */ + /* asm 1: fe_sub(>D=fe#5,D=tmp0,B=fe#6,B=tmp1,A=fe#1,A=x2,C=fe#2,C=z2,DA=fe#4,DA=z3,CB=fe#2,CB=z2,BB=fe#5,BB=tmp0,AA=fe#6,AA=tmp1,t0=fe#3,t0=x3,t1=fe#2,t1=z2,X4=fe#1,X4=x2,E=fe#6,E=tmp1,t2=fe#2,t2=z2,t3=fe#4,t3=z3,X5=fe#3,X5=x3,t4=fe#5,t4=tmp0,Z5=fe#4,x1,Z5=z3,x1,Z4=fe#2,Z4=z2, key) + { + UInt32 t0, t1, t2, t3; + UInt32 h0, h1, h2, h3, h4; + UInt32 r0, r1, r2, r3, r4; + UInt32 s1, s2, s3, s4; + UInt32 b, nb; + int j; + UInt64 tt0, tt1, tt2, tt3, tt4; + UInt64 f0, f1, f2, f3; + UInt32 g0, g1, g2, g3, g4; + UInt64 c; + + /* clamp key */ + t0 = key.x0; + t1 = key.x1; + t2 = key.x2; + t3 = key.x3; + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; t0 >>= 26; t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; t1 >>= 20; t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; t2 >>= 14; t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if (mLength < 16) + goto poly1305_donna_atmost15bytes; + + poly1305_donna_16bytes: + mStart += 16; + mLength -= 16; + + t0 = ByteIntegerConverter.LoadLittleEndian32(m, mStart - 16); + t1 = ByteIntegerConverter.LoadLittleEndian32(m, mStart - 12); + t2 = ByteIntegerConverter.LoadLittleEndian32(m, mStart - 8); + t3 = ByteIntegerConverter.LoadLittleEndian32(m, mStart - 4); + + //todo: looks like these can be simplified a bit + h0 += t0 & 0x3ffffff; + h1 += (uint)(((((UInt64)t1 << 32) | t0) >> 26) & 0x3ffffff); + h2 += (uint)(((((UInt64)t2 << 32) | t1) >> 20) & 0x3ffffff); + h3 += (uint)(((((UInt64)t3 << 32) | t2) >> 14) & 0x3ffffff); + h4 += (t3 >> 8) | (1 << 24); + + + poly1305_donna_mul: + tt0 = (ulong)h0 * r0 + (ulong)h1 * s4 + (ulong)h2 * s3 + (ulong)h3 * s2 + (ulong)h4 * s1; + tt1 = (ulong)h0 * r1 + (ulong)h1 * r0 + (ulong)h2 * s4 + (ulong)h3 * s3 + (ulong)h4 * s2; + tt2 = (ulong)h0 * r2 + (ulong)h1 * r1 + (ulong)h2 * r0 + (ulong)h3 * s4 + (ulong)h4 * s3; + tt3 = (ulong)h0 * r3 + (ulong)h1 * r2 + (ulong)h2 * r1 + (ulong)h3 * r0 + (ulong)h4 * s4; + tt4 = (ulong)h0 * r4 + (ulong)h1 * r3 + (ulong)h2 * r2 + (ulong)h3 * r1 + (ulong)h4 * r0; + + unchecked + { + h0 = (UInt32)tt0 & 0x3ffffff; c = (tt0 >> 26); + tt1 += c; h1 = (UInt32)tt1 & 0x3ffffff; b = (UInt32)(tt1 >> 26); + tt2 += b; h2 = (UInt32)tt2 & 0x3ffffff; b = (UInt32)(tt2 >> 26); + tt3 += b; h3 = (UInt32)tt3 & 0x3ffffff; b = (UInt32)(tt3 >> 26); + tt4 += b; h4 = (UInt32)tt4 & 0x3ffffff; b = (UInt32)(tt4 >> 26); + } + h0 += b * 5; + + if (mLength >= 16) + goto poly1305_donna_16bytes; + + /* final bytes */ + poly1305_donna_atmost15bytes: + if (mLength == 0) + goto poly1305_donna_finish; + + byte[] mp = new byte[16];//todo remove allocation + + for (j = 0; j < mLength; j++) + mp[j] = m[mStart + j]; + mp[j++] = 1; + for (; j < 16; j++) + mp[j] = 0; + mLength = 0; + + t0 = ByteIntegerConverter.LoadLittleEndian32(mp, 0); + t1 = ByteIntegerConverter.LoadLittleEndian32(mp, 4); + t2 = ByteIntegerConverter.LoadLittleEndian32(mp, 8); + t3 = ByteIntegerConverter.LoadLittleEndian32(mp, 12); + CryptoBytes.Wipe(mp); + + h0 += t0 & 0x3ffffff; + h1 += (uint)(((((UInt64)t1 << 32) | t0) >> 26) & 0x3ffffff); + h2 += (uint)(((((UInt64)t2 << 32) | t1) >> 20) & 0x3ffffff); + h3 += (uint)(((((UInt64)t3 << 32) | t2) >> 14) & 0x3ffffff); + h4 += t3 >> 8; + + goto poly1305_donna_mul; + + poly1305_donna_finish: + b = h0 >> 26; h0 = h0 & 0x3ffffff; + h1 += b; b = h1 >> 26; h1 = h1 & 0x3ffffff; + h2 += b; b = h2 >> 26; h2 = h2 & 0x3ffffff; + h3 += b; b = h3 >> 26; h3 = h3 & 0x3ffffff; + h4 += b; b = h4 >> 26; h4 = h4 & 0x3ffffff; + h0 += b * 5; + + g0 = h0 + 5; b = g0 >> 26; g0 &= 0x3ffffff; + g1 = h1 + b; b = g1 >> 26; g1 &= 0x3ffffff; + g2 = h2 + b; b = g2 >> 26; g2 &= 0x3ffffff; + g3 = h3 + b; b = g3 >> 26; g3 &= 0x3ffffff; + g4 = unchecked(h4 + b - (1 << 26)); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0) | (h1 << 26)) + (UInt64)key.x4; + f1 = ((h1 >> 6) | (h2 << 20)) + (UInt64)key.x5; + f2 = ((h2 >> 12) | (h3 << 14)) + (UInt64)key.x6; + f3 = ((h3 >> 18) | (h4 << 8)) + (UInt64)key.x7; + + unchecked + { + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 0, (uint)f0); f1 += (f0 >> 32); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 4, (uint)f1); f2 += (f1 >> 32); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 8, (uint)f2); f3 += (f2 >> 32); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 12, (uint)f3); + } + } + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/Salsa20.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/Salsa20.cs new file mode 100644 index 00000000..4b74ad0c --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/Salsa20.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Salsa +{ + internal class Salsa20 + { + public const uint SalsaConst0 = 0x61707865; + public const uint SalsaConst1 = 0x3320646e; + public const uint SalsaConst2 = 0x79622d32; + public const uint SalsaConst3 = 0x6b206574; + + internal static void HSalsa20(byte[] output, int outputOffset, byte[] key, int keyOffset, byte[] nonce, int nonceOffset) + { + Array16 state; + state.x0 = SalsaConst0; + state.x1 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 0); + state.x2 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 4); + state.x3 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 8); + state.x4 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 12); + state.x5 = SalsaConst1; + state.x6 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 0); + state.x7 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 4); + state.x8 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 8); + state.x9 = ByteIntegerConverter.LoadLittleEndian32(nonce, nonceOffset + 12); + state.x10 = SalsaConst2; + state.x11 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 16); + state.x12 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 20); + state.x13 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 24); + state.x14 = ByteIntegerConverter.LoadLittleEndian32(key, keyOffset + 28); + state.x15 = SalsaConst3; + + SalsaCore.HSalsa(out state, ref state, 20); + + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 0, state.x0); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 4, state.x5); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 8, state.x10); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 12, state.x15); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 16, state.x6); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 20, state.x7); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 24, state.x8); + ByteIntegerConverter.StoreLittleEndian32(output, outputOffset + 28, state.x9); + } + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/SalsaCore.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/SalsaCore.cs new file mode 100644 index 00000000..e539d668 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/SalsaCore.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal.Salsa +{ + internal static class SalsaCore + { + internal static void HSalsa(out Array16 output, ref Array16 input, int rounds) + { + InternalAssert.Assert(rounds % 2 == 0, "Number of salsa rounds must be even"); + + int doubleRounds = rounds / 2; + + UInt32 x0 = input.x0; + UInt32 x1 = input.x1; + UInt32 x2 = input.x2; + UInt32 x3 = input.x3; + UInt32 x4 = input.x4; + UInt32 x5 = input.x5; + UInt32 x6 = input.x6; + UInt32 x7 = input.x7; + UInt32 x8 = input.x8; + UInt32 x9 = input.x9; + UInt32 x10 = input.x10; + UInt32 x11 = input.x11; + UInt32 x12 = input.x12; + UInt32 x13 = input.x13; + UInt32 x14 = input.x14; + UInt32 x15 = input.x15; + + unchecked + { + for (int i = 0; i < doubleRounds; i++) + { + UInt32 y; + + // row 0 + y = x0 + x12; + x4 ^= (y << 7) | (y >> (32 - 7)); + y = x4 + x0; + x8 ^= (y << 9) | (y >> (32 - 9)); + y = x8 + x4; + x12 ^= (y << 13) | (y >> (32 - 13)); + y = x12 + x8; + x0 ^= (y << 18) | (y >> (32 - 18)); + + // row 1 + y = x5 + x1; + x9 ^= (y << 7) | (y >> (32 - 7)); + y = x9 + x5; + x13 ^= (y << 9) | (y >> (32 - 9)); + y = x13 + x9; + x1 ^= (y << 13) | (y >> (32 - 13)); + y = x1 + x13; + x5 ^= (y << 18) | (y >> (32 - 18)); + + // row 2 + y = x10 + x6; + x14 ^= (y << 7) | (y >> (32 - 7)); + y = x14 + x10; + x2 ^= (y << 9) | (y >> (32 - 9)); + y = x2 + x14; + x6 ^= (y << 13) | (y >> (32 - 13)); + y = x6 + x2; + x10 ^= (y << 18) | (y >> (32 - 18)); + + // row 3 + y = x15 + x11; + x3 ^= (y << 7) | (y >> (32 - 7)); + y = x3 + x15; + x7 ^= (y << 9) | (y >> (32 - 9)); + y = x7 + x3; + x11 ^= (y << 13) | (y >> (32 - 13)); + y = x11 + x7; + x15 ^= (y << 18) | (y >> (32 - 18)); + + // column 0 + y = x0 + x3; + x1 ^= (y << 7) | (y >> (32 - 7)); + y = x1 + x0; + x2 ^= (y << 9) | (y >> (32 - 9)); + y = x2 + x1; + x3 ^= (y << 13) | (y >> (32 - 13)); + y = x3 + x2; + x0 ^= (y << 18) | (y >> (32 - 18)); + + // column 1 + y = x5 + x4; + x6 ^= (y << 7) | (y >> (32 - 7)); + y = x6 + x5; + x7 ^= (y << 9) | (y >> (32 - 9)); + y = x7 + x6; + x4 ^= (y << 13) | (y >> (32 - 13)); + y = x4 + x7; + x5 ^= (y << 18) | (y >> (32 - 18)); + + // column 2 + y = x10 + x9; + x11 ^= (y << 7) | (y >> (32 - 7)); + y = x11 + x10; + x8 ^= (y << 9) | (y >> (32 - 9)); + y = x8 + x11; + x9 ^= (y << 13) | (y >> (32 - 13)); + y = x9 + x8; + x10 ^= (y << 18) | (y >> (32 - 18)); + + // column 3 + y = x15 + x14; + x12 ^= (y << 7) | (y >> (32 - 7)); + y = x12 + x15; + x13 ^= (y << 9) | (y >> (32 - 9)); + y = x13 + x12; + x14 ^= (y << 13) | (y >> (32 - 13)); + y = x14 + x13; + x15 ^= (y << 18) | (y >> (32 - 18)); + } + } + + output.x0 = x0; + output.x1 = x1; + output.x2 = x2; + output.x3 = x3; + output.x4 = x4; + output.x5 = x5; + output.x6 = x6; + output.x7 = x7; + output.x8 = x8; + output.x9 = x9; + output.x10 = x10; + output.x11 = x11; + output.x12 = x12; + output.x13 = x13; + output.x14 = x14; + output.x15 = x15; + } + + internal static void Salsa(out Array16 output, ref Array16 input, int rounds) + { + Array16 temp; + HSalsa(out temp, ref input, rounds); + unchecked + { + output.x0 = temp.x0 + input.x0; + output.x1 = temp.x1 + input.x1; + output.x2 = temp.x2 + input.x2; + output.x3 = temp.x3 + input.x3; + output.x4 = temp.x4 + input.x4; + output.x5 = temp.x5 + input.x5; + output.x6 = temp.x6 + input.x6; + output.x7 = temp.x7 + input.x7; + output.x8 = temp.x8 + input.x8; + output.x9 = temp.x9 + input.x9; + output.x10 = temp.x10 + input.x10; + output.x11 = temp.x11 + input.x11; + output.x12 = temp.x12 + input.x12; + output.x13 = temp.x13 + input.x13; + output.x14 = temp.x14 + input.x14; + output.x15 = temp.x15 + input.x15; + } + } + + /*internal static void SalsaCore(int[] output, int outputOffset, int[] input, int inputOffset, int rounds) + { + if (rounds % 2 != 0) + throw new ArgumentException("rounds must be even"); + } + + +static void store_littleendian(unsigned char *x,uint32 u) +{ + x[0] = u; u >>= 8; + x[1] = u; u >>= 8; + x[2] = u; u >>= 8; + x[3] = u; +} + + internal static void HSalsaCore(int[] output, int outputOffset, int[] input, int inputOffset, int rounds) + { + if (rounds % 2 != 0) + throw new ArgumentException("rounds must be even"); + static uint32 rotate(uint32 u,int c) +{ + return (u << c) | (u >> (32 - c)); +} + + + +int crypto_core( + unsigned char *out, + const unsigned char *in, + const unsigned char *k, + const unsigned char *c +) +{ + uint32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15; + int i; + + x0 = load_littleendian(c + 0); + x1 = load_littleendian(k + 0); + x2 = load_littleendian(k + 4); + x3 = load_littleendian(k + 8); + x4 = load_littleendian(k + 12); + x5 = load_littleendian(c + 4); + x6 = load_littleendian(in + 0); + x7 = load_littleendian(in + 4); + x8 = load_littleendian(in + 8); + x9 = load_littleendian(in + 12); + x10 = load_littleendian(c + 8); + x11 = load_littleendian(k + 16); + x12 = load_littleendian(k + 20); + x13 = load_littleendian(k + 24); + x14 = load_littleendian(k + 28); + x15 = load_littleendian(c + 12); + + for (i = ROUNDS;i > 0;i -= 2) { + x4 ^= rotate( x0+x12, 7); + x8 ^= rotate( x4+ x0, 9); + x12 ^= rotate( x8+ x4,13); + x0 ^= rotate(x12+ x8,18); + x9 ^= rotate( x5+ x1, 7); + x13 ^= rotate( x9+ x5, 9); + x1 ^= rotate(x13+ x9,13); + x5 ^= rotate( x1+x13,18); + x14 ^= rotate(x10+ x6, 7); + x2 ^= rotate(x14+x10, 9); + x6 ^= rotate( x2+x14,13); + x10 ^= rotate( x6+ x2,18); + x3 ^= rotate(x15+x11, 7); + x7 ^= rotate( x3+x15, 9); + x11 ^= rotate( x7+ x3,13); + x15 ^= rotate(x11+ x7,18); + x1 ^= rotate( x0+ x3, 7); + x2 ^= rotate( x1+ x0, 9); + x3 ^= rotate( x2+ x1,13); + x0 ^= rotate( x3+ x2,18); + x6 ^= rotate( x5+ x4, 7); + x7 ^= rotate( x6+ x5, 9); + x4 ^= rotate( x7+ x6,13); + x5 ^= rotate( x4+ x7,18); + x11 ^= rotate(x10+ x9, 7); + x8 ^= rotate(x11+x10, 9); + x9 ^= rotate( x8+x11,13); + x10 ^= rotate( x9+ x8,18); + x12 ^= rotate(x15+x14, 7); + x13 ^= rotate(x12+x15, 9); + x14 ^= rotate(x13+x12,13); + x15 ^= rotate(x14+x13,18); + } + + store_littleendian(out + 0,x0); + store_littleendian(out + 4,x5); + store_littleendian(out + 8,x10); + store_littleendian(out + 12,x15); + store_littleendian(out + 16,x6); + store_littleendian(out + 20,x7); + store_littleendian(out + 24,x8); + store_littleendian(out + 28,x9); + + return 0; +}*/ + + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/replace regex.txt b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/replace regex.txt new file mode 100644 index 00000000..f4856899 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Salsa/replace regex.txt @@ -0,0 +1,2 @@ +x(\d+) ^= rotate\((.+), (\d+)\); +y = \2;\r\nx\1 ^= (y << \3) | (y >> (32 - \3)); \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Sha512Internal.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Sha512Internal.cs new file mode 100644 index 00000000..0f05d5ed --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Internal/Sha512Internal.cs @@ -0,0 +1,447 @@ +using System; +using System.Collections.Generic; + +namespace Renci.SshNet.Security.Chaos.NaCl.Internal +{ + internal static class Sha512Internal + { + private static readonly UInt64[] K = new UInt64[] + { + 0x428a2f98d728ae22,0x7137449123ef65cd,0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc, + 0x3956c25bf348b538,0x59f111f1b605d019,0x923f82a4af194f9b,0xab1c5ed5da6d8118, + 0xd807aa98a3030242,0x12835b0145706fbe,0x243185be4ee4b28c,0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f,0x80deb1fe3b1696b1,0x9bdc06a725c71235,0xc19bf174cf692694, + 0xe49b69c19ef14ad2,0xefbe4786384f25e3,0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65, + 0x2de92c6f592b0275,0x4a7484aa6ea6e483,0x5cb0a9dcbd41fbd4,0x76f988da831153b5, + 0x983e5152ee66dfab,0xa831c66d2db43210,0xb00327c898fb213f,0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2,0xd5a79147930aa725,0x06ca6351e003826f,0x142929670a0e6e70, + 0x27b70a8546d22ffc,0x2e1b21385c26c926,0x4d2c6dfc5ac42aed,0x53380d139d95b3df, + 0x650a73548baf63de,0x766a0abb3c77b2a8,0x81c2c92e47edaee6,0x92722c851482353b, + 0xa2bfe8a14cf10364,0xa81a664bbc423001,0xc24b8b70d0f89791,0xc76c51a30654be30, + 0xd192e819d6ef5218,0xd69906245565a910,0xf40e35855771202a,0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8,0x1e376c085141ab53,0x2748774cdf8eeb99,0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb,0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc,0x78a5636f43172f60,0x84c87814a1f0ab72,0x8cc702081a6439ec, + 0x90befffa23631e28,0xa4506cebde82bde9,0xbef9a3f7b2c67915,0xc67178f2e372532b, + 0xca273eceea26619c,0xd186b8c721c0c207,0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178, + 0x06f067aa72176fba,0x0a637dc5a2c898a6,0x113f9804bef90dae,0x1b710b35131c471b, + 0x28db77f523047d84,0x32caab7b40c72493,0x3c9ebe0a15c9bebc,0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6,0x597f299cfc657e2a,0x5fcb6fab3ad6faec,0x6c44198c4a475817 + }; + + internal static void Sha512Init(out Array8 state) + { + state.x0 = 0x6a09e667f3bcc908; + state.x1 = 0xbb67ae8584caa73b; + state.x2 = 0x3c6ef372fe94f82b; + state.x3 = 0xa54ff53a5f1d36f1; + state.x4 = 0x510e527fade682d1; + state.x5 = 0x9b05688c2b3e6c1f; + state.x6 = 0x1f83d9abfb41bd6b; + state.x7 = 0x5be0cd19137e2179; + } + + internal static void Core(out Array8 outputState, ref Array8 inputState, ref Array16 input) + { + unchecked + { + UInt64 a = inputState.x0; + UInt64 b = inputState.x1; + UInt64 c = inputState.x2; + UInt64 d = inputState.x3; + UInt64 e = inputState.x4; + UInt64 f = inputState.x5; + UInt64 g = inputState.x6; + UInt64 h = inputState.x7; + + UInt64 w0 = input.x0; + UInt64 w1 = input.x1; + UInt64 w2 = input.x2; + UInt64 w3 = input.x3; + UInt64 w4 = input.x4; + UInt64 w5 = input.x5; + UInt64 w6 = input.x6; + UInt64 w7 = input.x7; + UInt64 w8 = input.x8; + UInt64 w9 = input.x9; + UInt64 w10 = input.x10; + UInt64 w11 = input.x11; + UInt64 w12 = input.x12; + UInt64 w13 = input.x13; + UInt64 w14 = input.x14; + UInt64 w15 = input.x15; + + int t = 0; + while (true) + { + ulong t1, t2; + + {//0 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w0; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//1 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w1; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//2 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w2; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//3 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w3; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//4 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w4; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//5 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w5; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//6 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w6; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//7 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w7; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//8 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w8; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//9 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w9; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//10 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w10; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//11 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w11; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//12 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w12; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//13 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w13; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//14 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w14; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + {//15 + t1 = h + + ((e >> 14) ^ (e << (64 - 14)) ^ (e >> 18) ^ (e << (64 - 18)) ^ (e >> 41) ^ (e << (64 - 41))) + + //Sigma1(e) + ((e & f) ^ (~e & g)) + //Ch(e,f,g) + K[t] + w15; + t2 = ((a >> 28) ^ (a << (64 - 28)) ^ (a >> 34) ^ (a << (64 - 34)) ^ (a >> 39) ^ (a << (64 - 39))) + + //Sigma0(a) + ((a & b) ^ (a & c) ^ (b & c)); //Maj(a,b,c) + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + t++; + } + if (t == 80) + break; + + w0 += ((w14 >> 19) ^ (w14 << (64 - 19)) ^ (w14 >> 61) ^ (w14 << (64 - 61)) ^ (w14 >> 6)) + + w9 + + ((w1 >> 1) ^ (w1 << (64 - 1)) ^ (w1 >> 8) ^ (w1 << (64 - 8)) ^ (w1 >> 7)); + w1 += ((w15 >> 19) ^ (w15 << (64 - 19)) ^ (w15 >> 61) ^ (w15 << (64 - 61)) ^ (w15 >> 6)) + + w10 + + ((w2 >> 1) ^ (w2 << (64 - 1)) ^ (w2 >> 8) ^ (w2 << (64 - 8)) ^ (w2 >> 7)); + w2 += ((w0 >> 19) ^ (w0 << (64 - 19)) ^ (w0 >> 61) ^ (w0 << (64 - 61)) ^ (w0 >> 6)) + + w11 + + ((w3 >> 1) ^ (w3 << (64 - 1)) ^ (w3 >> 8) ^ (w3 << (64 - 8)) ^ (w3 >> 7)); + w3 += ((w1 >> 19) ^ (w1 << (64 - 19)) ^ (w1 >> 61) ^ (w1 << (64 - 61)) ^ (w1 >> 6)) + + w12 + + ((w4 >> 1) ^ (w4 << (64 - 1)) ^ (w4 >> 8) ^ (w4 << (64 - 8)) ^ (w4 >> 7)); + w4 += ((w2 >> 19) ^ (w2 << (64 - 19)) ^ (w2 >> 61) ^ (w2 << (64 - 61)) ^ (w2 >> 6)) + + w13 + + ((w5 >> 1) ^ (w5 << (64 - 1)) ^ (w5 >> 8) ^ (w5 << (64 - 8)) ^ (w5 >> 7)); + w5 += ((w3 >> 19) ^ (w3 << (64 - 19)) ^ (w3 >> 61) ^ (w3 << (64 - 61)) ^ (w3 >> 6)) + + w14 + + ((w6 >> 1) ^ (w6 << (64 - 1)) ^ (w6 >> 8) ^ (w6 << (64 - 8)) ^ (w6 >> 7)); + w6 += ((w4 >> 19) ^ (w4 << (64 - 19)) ^ (w4 >> 61) ^ (w4 << (64 - 61)) ^ (w4 >> 6)) + + w15 + + ((w7 >> 1) ^ (w7 << (64 - 1)) ^ (w7 >> 8) ^ (w7 << (64 - 8)) ^ (w7 >> 7)); + w7 += ((w5 >> 19) ^ (w5 << (64 - 19)) ^ (w5 >> 61) ^ (w5 << (64 - 61)) ^ (w5 >> 6)) + + w0 + + ((w8 >> 1) ^ (w8 << (64 - 1)) ^ (w8 >> 8) ^ (w8 << (64 - 8)) ^ (w8 >> 7)); + w8 += ((w6 >> 19) ^ (w6 << (64 - 19)) ^ (w6 >> 61) ^ (w6 << (64 - 61)) ^ (w6 >> 6)) + + w1 + + ((w9 >> 1) ^ (w9 << (64 - 1)) ^ (w9 >> 8) ^ (w9 << (64 - 8)) ^ (w9 >> 7)); + w9 += ((w7 >> 19) ^ (w7 << (64 - 19)) ^ (w7 >> 61) ^ (w7 << (64 - 61)) ^ (w7 >> 6)) + + w2 + + ((w10 >> 1) ^ (w10 << (64 - 1)) ^ (w10 >> 8) ^ (w10 << (64 - 8)) ^ (w10 >> 7)); + w10 += ((w8 >> 19) ^ (w8 << (64 - 19)) ^ (w8 >> 61) ^ (w8 << (64 - 61)) ^ (w8 >> 6)) + + w3 + + ((w11 >> 1) ^ (w11 << (64 - 1)) ^ (w11 >> 8) ^ (w11 << (64 - 8)) ^ (w11 >> 7)); + w11 += ((w9 >> 19) ^ (w9 << (64 - 19)) ^ (w9 >> 61) ^ (w9 << (64 - 61)) ^ (w9 >> 6)) + + w4 + + ((w12 >> 1) ^ (w12 << (64 - 1)) ^ (w12 >> 8) ^ (w12 << (64 - 8)) ^ (w12 >> 7)); + w12 += ((w10 >> 19) ^ (w10 << (64 - 19)) ^ (w10 >> 61) ^ (w10 << (64 - 61)) ^ (w10 >> 6)) + + w5 + + ((w13 >> 1) ^ (w13 << (64 - 1)) ^ (w13 >> 8) ^ (w13 << (64 - 8)) ^ (w13 >> 7)); + w13 += ((w11 >> 19) ^ (w11 << (64 - 19)) ^ (w11 >> 61) ^ (w11 << (64 - 61)) ^ (w11 >> 6)) + + w6 + + ((w14 >> 1) ^ (w14 << (64 - 1)) ^ (w14 >> 8) ^ (w14 << (64 - 8)) ^ (w14 >> 7)); + w14 += ((w12 >> 19) ^ (w12 << (64 - 19)) ^ (w12 >> 61) ^ (w12 << (64 - 61)) ^ (w12 >> 6)) + + w7 + + ((w15 >> 1) ^ (w15 << (64 - 1)) ^ (w15 >> 8) ^ (w15 << (64 - 8)) ^ (w15 >> 7)); + w15 += ((w13 >> 19) ^ (w13 << (64 - 19)) ^ (w13 >> 61) ^ (w13 << (64 - 61)) ^ (w13 >> 6)) + + w8 + + ((w0 >> 1) ^ (w0 << (64 - 1)) ^ (w0 >> 8) ^ (w0 << (64 - 8)) ^ (w0 >> 7)); + } + + outputState.x0 = inputState.x0 + a; + outputState.x1 = inputState.x1 + b; + outputState.x2 = inputState.x2 + c; + outputState.x3 = inputState.x3 + d; + outputState.x4 = inputState.x4 + e; + outputState.x5 = inputState.x5 + f; + outputState.x6 = inputState.x6 + g; + outputState.x7 = inputState.x7 + h; + } + } + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/License.txt b/src/Renci.SshNet/Security/Chaos.NaCl/License.txt new file mode 100644 index 00000000..fa608d14 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/License.txt @@ -0,0 +1,23 @@ +Public domain + +C# port + code by Christian Winnerlein (CodesInChaos) + +Poly1305 in c + written by Andrew M. (floodyberry) + original license: MIT or PUBLIC DOMAIN + https://github.com/floodyberry/poly1305-donna/blob/master/poly1305-donna-unrolled.c + +Curve25519 and Ed25519 in c + written by Dan Bernstein (djb) + public domain + from Ref10 in SUPERCOP http://bench.cr.yp.to/supercop.html + +(H)Salsa20 in c + written by Dan Bernstein (djb) + public domain + from SUPERCOP http://bench.cr.yp.to/supercop.html + +SHA512 + written by Christian Winnerlein (CodesInChaos) + public domain + directly from the specification \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/MontgomeryCurve25519.cs b/src/Renci.SshNet/Security/Chaos.NaCl/MontgomeryCurve25519.cs new file mode 100644 index 00000000..2b99ce55 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/MontgomeryCurve25519.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using Renci.SshNet.Security.Chaos.NaCl.Internal; +using Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10; +using Renci.SshNet.Security.Chaos.NaCl.Internal.Salsa; + +namespace Renci.SshNet.Security.Chaos.NaCl +{ + // This class is mainly for compatibility with NaCl's Curve25519 implementation + // If you don't need that compatibility, use Ed25519.KeyExchange + internal static class MontgomeryCurve25519 + { + internal static readonly int PublicKeySizeInBytes = 32; + internal static readonly int PrivateKeySizeInBytes = 32; + internal static readonly int SharedKeySizeInBytes = 32; + + internal static byte[] GetPublicKey(byte[] privateKey) + { + if (privateKey == null) + throw new ArgumentNullException("privateKey"); + if (privateKey.Length != PrivateKeySizeInBytes) + throw new ArgumentException("privateKey.Length must be 32"); + var publicKey = new byte[32]; + GetPublicKey(new ArraySegment(publicKey), new ArraySegment(privateKey)); + return publicKey; + } + + static readonly byte[] _basePoint = new byte[32] + { + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 ,0, 0, 0, 0, 0, + 0, 0, 0 ,0, 0, 0, 0, 0, + 0, 0, 0 ,0, 0, 0, 0, 0 + }; + + internal static void GetPublicKey(ArraySegment publicKey, ArraySegment privateKey) + { + if (publicKey.Array == null) + throw new ArgumentNullException("publicKey.Array"); + if (privateKey.Array == null) + throw new ArgumentNullException("privateKey.Array"); + if (publicKey.Count != PublicKeySizeInBytes) + throw new ArgumentException("privateKey.Count must be 32"); + if (privateKey.Count != PrivateKeySizeInBytes) + throw new ArgumentException("privateKey.Count must be 32"); + + // hack: abusing publicKey as temporary storage + // todo: remove hack + for (int i = 0; i < 32; i++) + { + publicKey.Array[publicKey.Offset + i] = privateKey.Array[privateKey.Offset + i]; + } + ScalarOperations.sc_clamp(publicKey.Array, publicKey.Offset); + + GroupElementP3 A; + GroupOperations.ge_scalarmult_base(out A, publicKey.Array, publicKey.Offset); + FieldElement publicKeyFE; + EdwardsToMontgomeryX(out publicKeyFE, ref A.Y, ref A.Z); + FieldOperations.fe_tobytes(publicKey.Array, publicKey.Offset, ref publicKeyFE); + } + + // hashes like the Curve25519 paper says + internal static void KeyExchangeOutputHashCurve25519Paper(byte[] sharedKey, int offset) + { + //c = Curve25519output + const UInt32 c0 = 'C' | 'u' << 8 | 'r' << 16 | (UInt32)'v' << 24; + const UInt32 c1 = 'e' | '2' << 8 | '5' << 16 | (UInt32)'5' << 24; + const UInt32 c2 = '1' | '9' << 8 | 'o' << 16 | (UInt32)'u' << 24; + const UInt32 c3 = 't' | 'p' << 8 | 'u' << 16 | (UInt32)'t' << 24; + + Array16 salsaState; + salsaState.x0 = c0; + salsaState.x1 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 0); + salsaState.x2 = 0; + salsaState.x3 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 4); + salsaState.x4 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 8); + salsaState.x5 = c1; + salsaState.x6 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 12); + salsaState.x7 = 0; + salsaState.x8 = 0; + salsaState.x9 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 16); + salsaState.x10 = c2; + salsaState.x11 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 20); + salsaState.x12 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 24); + salsaState.x13 = 0; + salsaState.x14 = ByteIntegerConverter.LoadLittleEndian32(sharedKey, offset + 28); + salsaState.x15 = c3; + SalsaCore.Salsa(out salsaState, ref salsaState, 20); + + ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 0, salsaState.x0); + ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 4, salsaState.x1); + ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 8, salsaState.x2); + ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 12, salsaState.x3); + ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 16, salsaState.x4); + ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 20, salsaState.x5); + ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 24, salsaState.x6); + ByteIntegerConverter.StoreLittleEndian32(sharedKey, offset + 28, salsaState.x7); + } + + private static readonly byte[] _zero16 = new byte[16]; + + // hashes like the NaCl paper says instead i.e. HSalsa(x,0) + internal static void KeyExchangeOutputHashNaCl(byte[] sharedKey, int offset) + { + Salsa20.HSalsa20(sharedKey, offset, sharedKey, offset, _zero16, 0); + } + + internal static byte[] KeyExchange(byte[] publicKey, byte[] privateKey) + { + var sharedKey = new byte[SharedKeySizeInBytes]; + KeyExchange(new ArraySegment(sharedKey), new ArraySegment(publicKey), new ArraySegment(privateKey)); + return sharedKey; + } + + internal static void KeyExchange(ArraySegment sharedKey, ArraySegment publicKey, ArraySegment privateKey) + { + if (sharedKey.Array == null) + throw new ArgumentNullException("sharedKey.Array"); + if (publicKey.Array == null) + throw new ArgumentNullException("publicKey.Array"); + if (privateKey.Array == null) + throw new ArgumentNullException("privateKey"); + if (sharedKey.Count != 32) + throw new ArgumentException("sharedKey.Count != 32"); + if (publicKey.Count != 32) + throw new ArgumentException("publicKey.Count != 32"); + if (privateKey.Count != 32) + throw new ArgumentException("privateKey.Count != 32"); + MontgomeryOperations.scalarmult(sharedKey.Array, sharedKey.Offset, privateKey.Array, privateKey.Offset, publicKey.Array, publicKey.Offset); + KeyExchangeOutputHashNaCl(sharedKey.Array, sharedKey.Offset); + } + + internal static void EdwardsToMontgomeryX(out FieldElement montgomeryX, ref FieldElement edwardsY, ref FieldElement edwardsZ) + { + FieldElement tempX, tempZ; + FieldOperations.fe_add(out tempX, ref edwardsZ, ref edwardsY); + FieldOperations.fe_sub(out tempZ, ref edwardsZ, ref edwardsY); + FieldOperations.fe_invert(out tempZ, ref tempZ); + FieldOperations.fe_mul(out montgomeryX, ref tempX, ref tempZ); + } + } +} diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/Sha512.cs b/src/Renci.SshNet/Security/Chaos.NaCl/Sha512.cs new file mode 100644 index 00000000..f68d6ab8 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/Sha512.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using Renci.SshNet.Security.Chaos.NaCl.Internal; + +namespace Renci.SshNet.Security.Chaos.NaCl +{ + internal class Sha512 + { + private Array8 _state; + private readonly byte[] _buffer; + private ulong _totalBytes; + public const int BlockSize = 128; + private static readonly byte[] _padding = new byte[] { 0x80 }; + + public Sha512() + { + _buffer = new byte[BlockSize];//todo: remove allocation + Init(); + } + + public void Init() + { + Sha512Internal.Sha512Init(out _state); + _totalBytes = 0; + } + + public void Update(ArraySegment data) + { + if (data.Array == null) + throw new ArgumentNullException("data.Array"); + Update(data.Array, data.Offset, data.Count); + } + + public void Update(byte[] data, int offset, int count) + { + if (data == null) + throw new ArgumentNullException("data"); + if (offset < 0) + throw new ArgumentOutOfRangeException("offset"); + if (count < 0) + throw new ArgumentOutOfRangeException("count"); + if (data.Length - offset < count) + throw new ArgumentException("Requires offset + count <= data.Length"); + + Array16 block; + int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); + _totalBytes += (uint)count; + + if (_totalBytes >= ulong.MaxValue / 8) + throw new InvalidOperationException("Too much data"); + // Fill existing buffer + if (bytesInBuffer != 0) + { + var toCopy = Math.Min(BlockSize - bytesInBuffer, count); + Buffer.BlockCopy(data, offset, _buffer, bytesInBuffer, toCopy); + offset += toCopy; + count -= toCopy; + bytesInBuffer += toCopy; + if (bytesInBuffer == BlockSize) + { + ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer, 0); + Sha512Internal.Core(out _state, ref _state, ref block); + CryptoBytes.InternalWipe(_buffer, 0, _buffer.Length); + bytesInBuffer = 0; + } + } + // Hash complete blocks without copying + while (count >= BlockSize) + { + ByteIntegerConverter.Array16LoadBigEndian64(out block, data, offset); + Sha512Internal.Core(out _state, ref _state, ref block); + offset += BlockSize; + count -= BlockSize; + } + // Copy remainder into buffer + if (count > 0) + { + Buffer.BlockCopy(data, offset, _buffer, bytesInBuffer, count); + } + } + + public void Finish(ArraySegment output) + { + if (output.Array == null) + throw new ArgumentNullException("output.Array"); + if (output.Count != 64) + throw new ArgumentException("output.Count must be 64"); + + Update(_padding, 0, _padding.Length); + Array16 block; + ByteIntegerConverter.Array16LoadBigEndian64(out block, _buffer, 0); + CryptoBytes.InternalWipe(_buffer, 0, _buffer.Length); + int bytesInBuffer = (int)_totalBytes & (BlockSize - 1); + if (bytesInBuffer > BlockSize - 16) + { + Sha512Internal.Core(out _state, ref _state, ref block); + block = default(Array16); + } + block.x15 = (_totalBytes - 1) * 8; + Sha512Internal.Core(out _state, ref _state, ref block); + + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 0, _state.x0); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 8, _state.x1); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 16, _state.x2); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 24, _state.x3); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 32, _state.x4); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 40, _state.x5); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 48, _state.x6); + ByteIntegerConverter.StoreBigEndian64(output.Array, output.Offset + 56, _state.x7); + _state = default(Array8); + } + + public byte[] Finish() + { + var result = new byte[64]; + Finish(new ArraySegment(result)); + return result; + } + + internal static byte[] Hash(byte[] data) + { + return Hash(data, 0, data.Length); + } + + internal static byte[] Hash(byte[] data, int offset, int count) + { + var hasher = new Sha512(); + hasher.Update(data, offset, count); + return hasher.Finish(); + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs b/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs new file mode 100644 index 00000000..837d0031 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs @@ -0,0 +1,956 @@ +// +// Copyright (c) 2006 Damien Miller +// Copyright (c) 2010 Ryan D. Emerle +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +using Renci.SshNet.Abstractions; +using System; +using System.Diagnostics; +using System.Security.Cryptography; +using System.Text; + +namespace Renci.SshNet.Security.Cryptography +{ + /// BCrypt implementation. + /// + /// + /// BCrypt implements OpenBSD-style Blowfish password hashing using the scheme described in + /// "A Future- + /// Adaptable Password Scheme" by Niels Provos and David Mazieres. + /// + /// + /// This password hashing system tries to thwart off-line password cracking using a + /// computationally-intensive hashing algorithm, based on Bruce Schneier's Blowfish cipher. + /// The work factor of the algorithm is parameterised, so it can be increased as computers + /// get faster. + /// + /// + /// Usage is really simple. To hash a password for the first time, call the method with a random salt, like this: + /// + /// string pw_hash = BCrypt.HashPassword(plain_password); + /// + /// To check whether a plaintext password matches one that has been hashed previously, + /// use the method: + /// + /// + /// if (BCrypt.Verify(candidate_password, stored_hash)) + /// Console.WriteLine("It matches"); + /// else + /// Console.WriteLine("It does not match"); + /// + /// + /// The method takes an optional parameter (workFactor) that + /// determines the computational complexity of the hashing: + /// + /// + /// string strong_salt = BCrypt.GenerateSalt(10); + /// string stronger_salt = BCrypt.GenerateSalt(12); + /// + /// + /// The amount of work increases exponentially (2^workFactor), so each increment is twice + /// as much work. The default workFactor is 10, and the valid range is 4 to 31. + /// + /// + internal sealed class BCrypt + { + // BCrypt parameters + private const int GENSALT_DEFAULT_LOG2_ROUNDS = 10; + private const int BCRYPT_SALT_LEN = 16; + + // Blowfish parameters + private const int BLOWFISH_NUM_ROUNDS = 16; + + // Initial contents of key schedule + private static readonly uint[] _POrig = { + 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, + 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, + 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, + 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, + 0x9216d5d9, 0x8979fb1b + }; + + private static readonly uint[] _SOrig = { + 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, + 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, + 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, + 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, + 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, + 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, + 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, + 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, + 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, + 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, + 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, + 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, + 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, + 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, + 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, + 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, + 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, + 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, + 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, + 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, + 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, + 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, + 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, + 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, + 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, + 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, + 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, + 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, + 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, + 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, + 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, + 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, + 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, + 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, + 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, + 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, + 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, + 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, + 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, + 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, + 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, + 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, + 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, + 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, + 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, + 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, + 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, + 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, + 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, + 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, + 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, + 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, + 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, + 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, + 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, + 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, + 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, + 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, + 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, + 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, + 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, + 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, + 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, + 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a, + 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, + 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, + 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, + 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, + 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, + 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, + 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, + 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, + 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, + 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, + 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, + 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, + 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, + 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, + 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, + 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, + 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, + 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, + 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, + 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, + 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, + 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, + 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, + 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, + 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, + 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, + 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, + 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, + 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, + 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, + 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, + 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, + 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, + 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, + 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, + 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, + 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, + 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, + 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, + 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, + 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, + 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, + 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, + 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, + 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, + 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, + 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, + 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, + 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, + 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, + 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, + 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, + 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, + 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, + 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, + 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, + 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, + 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, + 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, + 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, + 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, + 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, + 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, + 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7, + 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, + 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, + 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, + 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, + 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, + 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, + 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, + 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, + 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, + 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, + 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, + 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, + 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, + 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, + 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, + 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, + 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, + 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, + 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, + 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, + 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, + 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, + 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, + 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, + 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, + 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, + 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, + 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, + 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, + 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, + 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, + 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, + 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, + 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, + 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, + 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, + 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, + 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, + 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, + 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, + 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, + 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, + 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, + 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, + 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, + 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, + 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, + 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, + 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, + 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, + 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, + 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, + 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, + 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, + 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, + 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, + 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, + 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, + 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, + 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, + 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, + 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, + 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, + 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0, + 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, + 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, + 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, + 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, + 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, + 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, + 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, + 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, + 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, + 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, + 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, + 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, + 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, + 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, + 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, + 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, + 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, + 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, + 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, + 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, + 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, + 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, + 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, + 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, + 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, + 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, + 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, + 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, + 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, + 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, + 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, + 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, + 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, + 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, + 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, + 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, + 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, + 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, + 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, + 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, + 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, + 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, + 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, + 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, + 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, + 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, + 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, + 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, + 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, + 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, + 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, + 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, + 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, + 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, + 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, + 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, + 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, + 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, + 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, + 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, + 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, + 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, + 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, + 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 + }; + + // OpenBSD IV: "OxychromaticBlowfishSwatDynamite" in big endian + private static readonly uint[] _OpenBsdIv = new uint[] { + 0x4f787963, 0x68726f6d, 0x61746963, 0x426c6f77, + 0x66697368, 0x53776174, 0x44796e61, 0x6d697465, + }; + + // bcrypt IV: "OrpheanBeholderScryDoubt" + private static readonly uint[] _BfCryptCiphertext = { + 0x4f727068, 0x65616e42, 0x65686f6c, + 0x64657253, 0x63727944, 0x6f756274 + }; + + // Table for Base64 encoding + private static readonly char[] _Base64Code = { + '.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', + '6', '7', '8', '9' + }; + + // Table for Base64 decoding + private static readonly int[] _Index64 = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, -1, -1, + -1, -1, -1, -1, -1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + -1, -1, -1, -1, -1, -1, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, -1, -1, -1, -1, -1 + }; + + // Expanded Blowfish key + private uint[] _P; + private uint[] _S; + + /// + /// Hash a string using the OpenBSD bcrypt scheme and a salt generated by . + /// + /// Just an alias for HashPassword. + /// The string to hash. + /// The hashed string. + public static string HashString(string source) + { + return HashPassword(source); + } + + /// + /// Hash a string using the OpenBSD bcrypt scheme and a salt generated by . + /// + /// Just an alias for HashPassword. + /// The string to hash. + /// The log2 of the number of rounds of hashing to apply - the work + /// factor therefore increases as 2^workFactor. + /// The hashed string. + public static string HashString(string source, int workFactor) + { + return HashPassword(source, GenerateSalt(workFactor)); + } + + /// + /// Hash a password using the OpenBSD bcrypt scheme and a salt generated by . + /// + /// The password to hash. + /// The hashed password. + public static string HashPassword(string input) + { + return HashPassword(input, GenerateSalt()); + } + + /// + /// Hash a password using the OpenBSD bcrypt scheme and a salt generated by using the given . + /// + /// The password to hash. + /// The log2 of the number of rounds of hashing to apply - the work + /// factor therefore increases as 2^workFactor. + /// The hashed password. + public static string HashPassword(string input, int workFactor) + { + return HashPassword(input, GenerateSalt(workFactor)); + } + + /// Hash a password using the OpenBSD bcrypt scheme. + /// Thrown when one or more arguments have unsupported or + /// illegal values. + /// The password to hash. + /// the salt to hash with (perhaps generated using BCrypt.gensalt). + /// The hashed password + public static string HashPassword(string input, string salt) + { + if (input == null) + throw new ArgumentNullException("input"); + + if (string.IsNullOrEmpty(salt)) + throw new ArgumentException("Invalid salt", "salt"); + + // Determinthe starting offset and validate the salt + int startingOffset; + char minor = (char)0; + if (salt[0] != '$' || salt[1] != '2') + throw new SaltParseException("Invalid salt version"); + if (salt[2] == '$') + startingOffset = 3; + else + { + minor = salt[2]; + if (minor != 'a' || salt[3] != '$') + throw new SaltParseException("Invalid salt revision"); + startingOffset = 4; + } + + // Extract number of rounds + if (salt[startingOffset + 2] > '$') + throw new SaltParseException("Missing salt rounds"); + + // Extract details from salt + int logRounds = Convert.ToInt32(salt.Substring(startingOffset, 2)); + string extractedSalt = salt.Substring(startingOffset + 3, 22); + + byte[] inputBytes = Encoding.UTF8.GetBytes((input + (minor >= 'a' ? "\0" : ""))); + byte[] saltBytes = DecodeBase64(extractedSalt, BCRYPT_SALT_LEN); + + BCrypt bCrypt = new BCrypt(); + byte[] hashed = bCrypt.CryptRaw(inputBytes, saltBytes, logRounds); + + // Generate result string + StringBuilder result = new StringBuilder(); + result.Append("$2"); + if (minor >= 'a') + result.Append(minor); + result.AppendFormat("${0:00}$", logRounds); + result.Append(EncodeBase64(saltBytes, saltBytes.Length)); + result.Append(EncodeBase64(hashed, (_BfCryptCiphertext.Length * 4) - 1)); + return result.ToString(); + } + + /// + /// Generate a salt for use with the method. + /// + /// The log2 of the number of rounds of hashing to apply - the work + /// factor therefore increases as 2**workFactor. + /// A base64 encoded salt value. + public static string GenerateSalt(int workFactor) + { + if (workFactor < 4 || workFactor > 31) + throw new ArgumentOutOfRangeException("workFactor", "The work factor must be between 4 and 31 (inclusive)"); + + byte[] rnd = new byte[BCRYPT_SALT_LEN]; +#if FEATURE_RNG_CREATE + RandomNumberGenerator rng = RandomNumberGenerator.Create(); +#elif FEATURE_RNG_CSP + RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); +#endif +#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP + rng.GetBytes(rnd); +#endif + + StringBuilder rs = new StringBuilder(); + rs.AppendFormat("$2a${0:00}$", workFactor); + rs.Append(EncodeBase64(rnd, rnd.Length)); + return rs.ToString(); + } + + /// + /// Generate a salt for use with the method + /// selecting a reasonable default for the number of hashing rounds to apply. + /// + /// A base64 encoded salt value. + public static string GenerateSalt() + { + return GenerateSalt(GENSALT_DEFAULT_LOG2_ROUNDS); + } + + /// + /// Verifies that the hash of the given matches the provided + /// + /// + /// The text to verify. + /// The previously-hashed password. + /// true if the passwords match, false otherwise. + public static bool Verify(string text, string hash) + { + return hash == HashPassword(text, hash); + } + + /// + /// Encode a byte array using bcrypt's slightly-modified base64 encoding scheme. Note that this + /// is *not* compatible with the standard MIME-base64 encoding. + /// + /// Thrown when one or more arguments have unsupported or + /// illegal values. + /// The byte array to encode. + /// The number of bytes to encode. + /// Base64-encoded string. + private static string EncodeBase64(byte[] byteArray, int length) + { + if (length <= 0 || length > byteArray.Length) + throw new ArgumentException("Invalid length", "length"); + + int off = 0; + StringBuilder rs = new StringBuilder(); + while (off < length) + { + int c1 = byteArray[off++] & 0xff; + rs.Append(_Base64Code[(c1 >> 2) & 0x3f]); + c1 = (c1 & 0x03) << 4; + if (off >= length) + { + rs.Append(_Base64Code[c1 & 0x3f]); + break; + } + int c2 = byteArray[off++] & 0xff; + c1 |= (c2 >> 4) & 0x0f; + rs.Append(_Base64Code[c1 & 0x3f]); + c1 = (c2 & 0x0f) << 2; + if (off >= length) + { + rs.Append(_Base64Code[c1 & 0x3f]); + break; + } + c2 = byteArray[off++] & 0xff; + c1 |= (c2 >> 6) & 0x03; + rs.Append(_Base64Code[c1 & 0x3f]); + rs.Append(_Base64Code[c2 & 0x3f]); + } + return rs.ToString(); + } + + /// + /// Decode a string encoded using bcrypt's base64 scheme to a byte array. Note that this is *not* + /// compatible with the standard MIME-base64 encoding. + /// + /// Thrown when one or more arguments have unsupported or + /// illegal values. + /// The string to decode. + /// The maximum bytes to decode. + /// The decoded byte array. + private static byte[] DecodeBase64(string encodedstring, int maximumBytes) + { + int position = 0, + sourceLength = encodedstring.Length, + outputLength = 0; + + if (maximumBytes <= 0) + throw new ArgumentException("Invalid maximum bytes value", "maximumBytes"); + + // TODO: update to use a List - it's only ever 16 bytes, so it's not a big deal + StringBuilder rs = new StringBuilder(); + while (position < sourceLength - 1 && outputLength < maximumBytes) + { + int c1 = Char64(encodedstring[position++]); + int c2 = Char64(encodedstring[position++]); + if (c1 == -1 || c2 == -1) + break; + + rs.Append((char)((c1 << 2) | ((c2 & 0x30) >> 4))); + if (++outputLength >= maximumBytes || position >= sourceLength) + break; + + int c3 = Char64(encodedstring[position++]); + if (c3 == -1) + break; + + rs.Append((char)(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2))); + if (++outputLength >= maximumBytes || position >= sourceLength) + break; + + int c4 = Char64(encodedstring[position++]); + rs.Append((char)(((c3 & 0x03) << 6) | c4)); + + ++outputLength; + } + + byte[] ret = new byte[outputLength]; + for (position = 0; position < outputLength; position++) + ret[position] = (byte)rs[position]; + return ret; + } + + /// + /// Look up the 3 bits base64-encoded by the specified character, range-checking against + /// conversion table. + /// + /// The base64-encoded value. + /// The decoded value of x. + private static int Char64(char character) + { + if (character < 0 || character > _Index64.Length) + return -1; + return _Index64[character]; + } + + /// Blowfish encipher a single 64-bit block encoded as two 32-bit halves. + /// An array containing the two 32-bit half blocks. + /// The position in the array of the blocks. + private void Encipher(uint[] blockArray, int offset) + { + uint round, + n, + block = blockArray[offset], + r = blockArray[offset + 1]; + + block ^= _P[0]; + for (round = 0; round <= BLOWFISH_NUM_ROUNDS - 2;) + { + // Feistel substitution on left word + n = _S[(block >> 24) & 0xff]; + n += _S[0x100 | ((block >> 16) & 0xff)]; + n ^= _S[0x200 | ((block >> 8) & 0xff)]; + n += _S[0x300 | (block & 0xff)]; + r ^= n ^ _P[++round]; + + // Feistel substitution on right word + n = _S[(r >> 24) & 0xff]; + n += _S[0x100 | ((r >> 16) & 0xff)]; + n ^= _S[0x200 | ((r >> 8) & 0xff)]; + n += _S[0x300 | (r & 0xff)]; + block ^= n ^ _P[++round]; + } + blockArray[offset] = r ^ _P[BLOWFISH_NUM_ROUNDS + 1]; + blockArray[offset + 1] = block; + } + + /// Cycically extract a word of key material. + /// The string to extract the data from. + /// [in,out] The current offset. + /// The next word of material from data. + private static uint StreamToWord(byte[] data, ref int offset) + { + int i; + uint word = 0; + + for (i = 0; i < 4; i++) + { + word = (word << 8) | (uint)(data[offset] & 0xff); + offset = (offset + 1) % data.Length; + } + return word; + } + + /// Initializes the Blowfish key schedule. + private void InitializeKey() + { + _P = new uint[_POrig.Length]; + _S = new uint[_SOrig.Length]; + Array.Copy(_POrig, _P, _POrig.Length); + Array.Copy(_SOrig, _S, _SOrig.Length); + } + + /// Key the Blowfish cipher. + /// The key byte array. + private void Key(byte[] keyBytes) + { + int i; + int koffp = 0; + uint[] lr = { 0, 0 }; + int plen = _P.Length, slen = _S.Length; + + for (i = 0; i < plen; i++) + _P[i] = _P[i] ^ StreamToWord(keyBytes, ref koffp); + + for (i = 0; i < plen; i += 2) + { + Encipher(lr, 0); + _P[i] = lr[0]; + _P[i + 1] = lr[1]; + } + + for (i = 0; i < slen; i += 2) + { + Encipher(lr, 0); + _S[i] = lr[0]; + _S[i + 1] = lr[1]; + } + } + + /// + /// Perform the "enhanced key schedule" step described by Provos and Mazieres in "A Future- + /// Adaptable Password Scheme" http://www.openbsd.org/papers/bcrypt-paper.ps. + /// + /// Salt byte array. + /// Input byte array. + private void EKSKey(byte[] saltBytes, byte[] inputBytes) + { + int i; + int passwordOffset = 0, + saltOffset = 0; + uint[] lr = { 0, 0 }; + int plen = _P.Length, slen = _S.Length; + + for (i = 0; i < plen; i++) + _P[i] = _P[i] ^ StreamToWord(inputBytes, ref passwordOffset); + + for (i = 0; i < plen; i += 2) + { + lr[0] ^= StreamToWord(saltBytes, ref saltOffset); + lr[1] ^= StreamToWord(saltBytes, ref saltOffset); + Encipher(lr, 0); + _P[i] = lr[0]; + _P[i + 1] = lr[1]; + } + + for (i = 0; i < slen; i += 2) + { + lr[0] ^= StreamToWord(saltBytes, ref saltOffset); + lr[1] ^= StreamToWord(saltBytes, ref saltOffset); + Encipher(lr, 0); + _S[i] = lr[0]; + _S[i + 1] = lr[1]; + } + } + + /// Perform the central hashing step in the bcrypt scheme. + /// Thrown when one or more arguments have unsupported or + /// illegal values. + /// The input byte array to hash. + /// The salt byte array to hash with. + /// The binary logarithm of the number of rounds of hashing to apply. + /// A byte array containing the hashed result. + private byte[] CryptRaw(byte[] inputBytes, byte[] saltBytes, int logRounds) + { + uint[] cdata = new uint[_BfCryptCiphertext.Length]; + Array.Copy(_BfCryptCiphertext, cdata, _BfCryptCiphertext.Length); + int clen = cdata.Length; + + if (logRounds < 4 || logRounds > 31) + throw new ArgumentException("Bad number of rounds", "logRounds"); + + if (saltBytes.Length != BCRYPT_SALT_LEN) + throw new ArgumentException("Bad salt Length", "saltBytes"); + + uint rounds = 1u << logRounds; + Debug.Assert(rounds > 0, "Rounds must be > 0"); // We overflowed rounds at 31 - added safety check + + InitializeKey(); + EKSKey(saltBytes, inputBytes); + + for (int i = 0; i < rounds; i++) + { + Key(inputBytes); + Key(saltBytes); + } + + for (int i = 0; i < 64; i++) + { + for (int j = 0; j < (clen >> 1); j++) + Encipher(cdata, j << 1); + } + + byte[] ret = new byte[clen * 4]; + for (int i = 0, j = 0; i < clen; i++) + { + ret[j++] = (byte)((cdata[i] >> 24) & 0xff); + ret[j++] = (byte)((cdata[i] >> 16) & 0xff); + ret[j++] = (byte)((cdata[i] >> 8) & 0xff); + ret[j++] = (byte)(cdata[i] & 0xff); + } + return ret; + } + + /** + * Compatibility with new OpenBSD function. + * Ported from SSHJ library (https://github.com/hierynomus/sshj) + */ + public void Hash(byte[] hpass, byte[] hsalt, byte[] output) + { + InitializeKey(); + EKSKey(hsalt, hpass); + for (int i = 0; i < 64; i++) + { + Key(hsalt); + Key(hpass); + } + + uint[] buf = new uint[_OpenBsdIv.Length]; + Array.Copy(_OpenBsdIv, 0, buf, 0, _OpenBsdIv.Length); + for (int i = 0; i < 8; i += 2) + { + for (int j = 0; j < 64; j++) + { + Encipher(buf, i); + } + } + + for (int i = 0, j = 0; i < buf.Length; i++) + { + // Output of this is little endian + output[j++] = (byte)(buf[i] & 0xff); + output[j++] = (byte)((buf[i] >> 8) & 0xff); + output[j++] = (byte)((buf[i] >> 16) & 0xff); + output[j++] = (byte)((buf[i] >> 24) & 0xff); + } + } + + /// + /// Applies the Bcrypt kdf to derive a key and iv from the passphrase, + /// the key/iv are returned in the output variable. + /// Ported from the SSHJ library. https://github.com/hierynomus/sshj + /// + /// + /// + /// + /// + public void Pbkdf(byte[] password, byte[] salt, int rounds, byte[] output) + { + using (var sha512 = CryptoAbstraction.CreateSHA512()) + { + int nblocks = (output.Length + 31) / 32; + byte[] hpass = sha512.ComputeHash(password); + + byte[] hsalt = new byte[64]; + byte[] block_b = new byte[4]; + byte[] outBytes = new byte[32]; + byte[] tmp = new byte[32]; + for (int block = 1; block <= nblocks; block++) + { + // Block count is in big endian + block_b[0] = (byte)((block >> 24) & 0xFF); + block_b[1] = (byte)((block >> 16) & 0xFF); + block_b[2] = (byte)((block >> 8) & 0xFF); + block_b[3] = (byte)(block & 0xFF); + + hsalt = sha512.ComputeHash(AppendArrays(salt, block_b)); + Hash(hpass, hsalt, outBytes); + Array.Copy(outBytes, 0, tmp, 0, outBytes.Length); + + for (int round = 1; round < rounds; round++) + { + hsalt = sha512.ComputeHash(tmp); + Hash(hpass, hsalt, tmp); + + for (int i = 0; i < tmp.Length; i++) + { + outBytes[i] ^= tmp[i]; + } + } + + for (int i = 0; i < outBytes.Length; i++) + { + int idx = i * nblocks + (block - 1); + if (idx < output.Length) + { + output[idx] = outBytes[i]; + } + } + } + } + } + + /// + /// Appends multiple byte arrays into one array. + /// + /// + /// + /// + private byte[] AppendArrays(byte[] b1, params byte[][] others) + { + //from https://stackoverflow.com/questions/46534429/how-to-convert-java-messagedigest-with-two-update-statements-to-c-sharp + int n = b1.Length; + foreach (var other in others) + { + n += other.Length; + } + + var result = new byte[n]; + + n = 0; + Array.Copy(b1, 0, result, n, b1.Length); + n += b1.Length; + foreach (var other in others) + { + Array.Copy(other, 0, result, n, other.Length); + n += other.Length; + } + + return result; + } + + /// Exception for signalling parse errors. + public class SaltParseException : Exception + { + /// Default constructor. + public SaltParseException() + { + } + + /// Initializes a new instance of . + /// The message. + public SaltParseException(string message) + : base(message) + { + } + + /// Initializes a new instance of . + /// The message. + /// The inner exception. + public SaltParseException(string message, Exception innerException) + : base(message, innerException) + { + } + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs index 81bb13f2..e7577f39 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs @@ -8,9 +8,9 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers /// public sealed class CastCipher : BlockCipher { - internal static readonly int MAX_ROUNDS = 16; + private static readonly int MaxRounds = 16; - internal static readonly int RED_ROUNDS = 12; + private static readonly int RedRounds = 12; /// /// The rotating round key @@ -22,7 +22,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers /// private readonly uint[] _km = new uint[17]; - private int _rounds = MAX_ROUNDS; + private int _rounds = MaxRounds; /// /// Initializes a new instance of the class. @@ -60,11 +60,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers // batch the units up into a 32 bit chunk and go for it // the array is in bytes, the increment is 8x8 bits = 64 - var L0 = Pack.BigEndianToUInt32(inputBuffer, inputOffset); - var R0 = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); + var l0 = Pack.BigEndianToUInt32(inputBuffer, inputOffset); + var r0 = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); var result = new uint[2]; - CastEncipher(L0, R0, result); + CastEncipher(l0, r0, result); // now stuff them into the destination block Pack.UInt32ToBigEndian(result[0], outputBuffer, outputOffset); @@ -89,11 +89,11 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers // 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 - var L16 = Pack.BigEndianToUInt32(inputBuffer, inputOffset); - var R16 = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); + var l16 = Pack.BigEndianToUInt32(inputBuffer, inputOffset); + var r16 = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); var result = new uint[2]; - CastDecipher(L16, R16, result); + CastDecipher(l16, r16, result); // now stuff them into the destination block Pack.UInt32ToBigEndian(result[0], outputBuffer, outputOffset); @@ -105,285 +105,292 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers #region Static Definition Tables internal static readonly uint[] S1 = - { - 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, - 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, - 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, - 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, - 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, - 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, - 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, - 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, - 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, - 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, - 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, - 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, - 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, - 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, - 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, - 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, - 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, - 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, - 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, - 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, - 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, - 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, - 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, - 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, - 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, - 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, - 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, - 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, - 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, - 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, - 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, - 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf - }, - S2 = - { - 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, - 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, - 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, - 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, - 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, - 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, - 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, - 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, - 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, - 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, - 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, - 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, - 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, - 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, - 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, - 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, - 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, - 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, - 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, - 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, - 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, - 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, - 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, - 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, - 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, - 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, - 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, - 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, - 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, - 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, - 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, - 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 - }, - S3 = - { - 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, - 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, - 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, - 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, - 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, - 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, - 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, - 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, - 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, - 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, - 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, - 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, - 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, - 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, - 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, - 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, - 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, - 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, - 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, - 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, - 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, - 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, - 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, - 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, - 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, - 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, - 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, - 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, - 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, - 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, - 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, - 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 - }, - S4 = - { - 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, - 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, - 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, - 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, - 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, - 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, - 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, - 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, - 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, - 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, - 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, - 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, - 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, - 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, - 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, - 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, - 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, - 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, - 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, - 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, - 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, - 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, - 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, - 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, - 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, - 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, - 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, - 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, - 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, - 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, - 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, - 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 - }, - S5 = - { - 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, - 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, - 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, - 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, - 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, - 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, - 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, - 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, - 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, - 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, - 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, - 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, - 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, - 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, - 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, - 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, - 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, - 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, - 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, - 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, - 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, - 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, - 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, - 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, - 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, - 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, - 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, - 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, - 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, - 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, - 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, - 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4 - }, - S6 = - { - 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, - 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, - 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, - 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, - 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, - 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, - 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, - 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, - 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, - 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, - 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, - 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, - 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, - 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, - 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, - 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, - 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, - 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, - 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, - 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, - 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, - 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, - 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, - 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, - 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, - 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, - 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, - 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, - 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, - 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, - 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, - 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f - }, - S7 = - { - 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, - 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, - 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, - 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, - 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, - 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, - 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, - 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, - 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, - 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, - 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, - 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, - 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, - 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, - 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, - 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, - 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, - 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, - 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, - 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, - 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, - 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, - 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, - 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, - 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, - 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, - 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, - 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, - 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, - 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, - 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, - 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3 - }, - S8 = - { - 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, - 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, - 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, - 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, - 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, - 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, - 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, - 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, - 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, - 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, - 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, - 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, - 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, - 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, - 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, - 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, - 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, - 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, - 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, - 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, - 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, - 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, - 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, - 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, - 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, - 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, - 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, - 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, - 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, - 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, - 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, - 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e - }; + { + 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, + 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, + 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, + 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0, + 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7, + 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935, + 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d, + 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, + 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe, + 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3, + 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167, + 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291, + 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, + 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2, + 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511, + 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d, + 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5, + 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, + 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c, + 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc, + 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d, + 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96, + 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, + 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d, + 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd, + 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6, + 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9, + 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, + 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c, + 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e, + 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9, + 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf + }; + + internal static readonly uint[] S2 = + { + 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651, + 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3, + 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, + 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806, + 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b, + 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359, + 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b, + 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, + 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34, + 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb, + 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd, + 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860, + 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, + 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304, + 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b, + 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, + 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c, + 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, + 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f, + 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6, + 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6, + 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58, + 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, + 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d, + 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6, + 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4, + 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6, + 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, + 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249, + 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa, + 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9, + 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1 + }; + + internal static readonly uint[] S3 = + { + 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90, + 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5, + 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, + 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240, + 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5, + 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, + 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71, + 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, + 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82, + 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15, + 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2, + 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176, + 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, + 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc, + 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341, + 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e, + 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51, + 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, + 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a, + 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b, + 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, + 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5, + 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, + 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536, + 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc, + 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0, + 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69, + 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, + 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49, + 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d, + 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a, + 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783 + }; + + internal static readonly uint[] S4 = + { + 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1, + 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf, + 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, + 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121, + 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25, + 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, + 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb, + 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, + 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d, + 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6, + 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23, + 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003, + 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, + 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119, + 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24, + 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a, + 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79, + 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, + 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26, + 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab, + 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7, + 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417, + 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, + 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2, + 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a, + 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919, + 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef, + 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, + 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab, + 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04, + 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282, + 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2 + }; + + internal static readonly uint[] S5 = + { + 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f, + 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a, + 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, + 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02, + 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a, + 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7, + 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9, + 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, + 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774, + 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655, + 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2, + 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910, + 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, + 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da, + 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049, + 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f, + 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba, + 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, + 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3, + 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840, + 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4, + 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2, + 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, + 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5, + 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e, + 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e, + 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801, + 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, + 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0, + 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20, + 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8, + 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4 + }; + + internal static readonly uint[] S6 = + { + 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac, + 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138, + 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, + 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98, + 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072, + 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3, + 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd, + 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, + 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9, + 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54, + 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387, + 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc, + 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, + 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf, + 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f, + 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289, + 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950, + 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, + 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b, + 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be, + 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13, + 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976, + 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, + 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891, + 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da, + 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc, + 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084, + 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, + 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121, + 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5, + 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd, + 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f + }; + + internal static readonly uint[] S7 = + { + 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f, + 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de, + 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, + 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19, + 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2, + 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516, + 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88, + 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, + 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756, + 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a, + 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264, + 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688, + 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, + 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3, + 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7, + 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, + 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033, + 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, + 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566, + 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509, + 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962, + 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e, + 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, + 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c, + 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285, + 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301, + 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be, + 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, + 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647, + 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914, + 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c, + 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3 + }; + + internal static readonly uint[] S8 = + { + 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5, + 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc, + 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, + 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d, + 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2, + 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862, + 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc, + 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, + 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e, + 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039, + 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8, + 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42, + 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, + 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472, + 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225, + 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c, + 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb, + 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, + 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70, + 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc, + 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c, + 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3, + 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, + 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101, + 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f, + 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e, + 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a, + 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, + 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384, + 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c, + 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82, + 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e + }; #endregion @@ -404,16 +411,16 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers if (key.Length < 11) { - _rounds = RED_ROUNDS; + _rounds = RedRounds; } var z = new int[16]; var x = new int[16]; /* copy the key into x */ - for (int i = 0; i < key.Length; i++) + for (var i = 0; i < key.Length; i++) { - x[i] = (int)(key[i] & 0xff); + x[i] = key[i] & 0xff; } /* @@ -421,139 +428,139 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers * bytes from the input key I've already chosen the * correct int. */ - var x03 = IntsTo32bits(x, 0x0); - var x47 = IntsTo32bits(x, 0x4); - var x8B = IntsTo32bits(x, 0x8); - var xCF = IntsTo32bits(x, 0xC); + var x03 = IntsTo32Bits(x, 0x0); + var x47 = IntsTo32Bits(x, 0x4); + var x8B = IntsTo32Bits(x, 0x8); + var xCf = IntsTo32Bits(x, 0xC); var z03 = x03 ^ S5[x[0xD]] ^ S6[x[0xF]] ^ S7[x[0xC]] ^ S8[x[0xE]] ^ S7[x[0x8]]; Bits32ToInts(z03, z, 0x0); var z47 = x8B ^ S5[z[0x0]] ^ S6[z[0x2]] ^ S7[z[0x1]] ^ S8[z[0x3]] ^ S8[x[0xA]]; Bits32ToInts(z47, z, 0x4); - var z8B = xCF ^ S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S5[x[0x9]]; + var z8B = xCf ^ S5[z[0x7]] ^ S6[z[0x6]] ^ S7[z[0x5]] ^ S8[z[0x4]] ^ S5[x[0x9]]; Bits32ToInts(z8B, z, 0x8); - var zCF = x47 ^ S5[z[0xA]] ^ S6[z[0x9]] ^ S7[z[0xB]] ^ S8[z[0x8]] ^ S6[x[0xB]]; - Bits32ToInts(zCF, z, 0xC); + var 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]]; - z03 = IntsTo32bits(z, 0x0); - z47 = IntsTo32bits(z, 0x4); - z8B = IntsTo32bits(z, 0x8); - zCF = IntsTo32bits(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]]; Bits32ToInts(x03, x, 0x0); 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]]; Bits32ToInts(x8B, x, 0x8); - xCF = zCF ^ S5[x[0xA]] ^ S6[x[0x9]] ^ S7[x[0xB]] ^ S8[x[0x8]] ^ S6[z[0x3]]; - Bits32ToInts(xCF, x, 0xC); + 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]]; - x03 = IntsTo32bits(x, 0x0); - x47 = IntsTo32bits(x, 0x4); - x8B = IntsTo32bits(x, 0x8); - xCF = IntsTo32bits(x, 0xC); + 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]]; Bits32ToInts(z03, z, 0x0); 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]]; - Bits32ToInts(zCF, z, 0xC); + 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]]; - z03 = IntsTo32bits(z, 0x0); - z47 = IntsTo32bits(z, 0x4); - z8B = IntsTo32bits(z, 0x8); - zCF = IntsTo32bits(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]]; Bits32ToInts(x03, x, 0x0); 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]]; Bits32ToInts(x8B, x, 0x8); - xCF = zCF ^ S5[x[0xA]] ^ S6[x[0x9]] ^ S7[x[0xB]] ^ S8[x[0x8]] ^ S6[z[0x3]]; - Bits32ToInts(xCF, x, 0xC); + 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]]; - x03 = IntsTo32bits(x, 0x0); - x47 = IntsTo32bits(x, 0x4); - x8B = IntsTo32bits(x, 0x8); - xCF = IntsTo32bits(x, 0xC); + 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]]; Bits32ToInts(z03, z, 0x0); 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]]; - Bits32ToInts(zCF, z, 0xC); + 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); - z03 = IntsTo32bits(z, 0x0); - z47 = IntsTo32bits(z, 0x4); - z8B = IntsTo32bits(z, 0x8); - zCF = IntsTo32bits(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]]; Bits32ToInts(x03, x, 0x0); 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]]; Bits32ToInts(x8B, x, 0x8); - xCF = zCF ^ S5[x[0xA]] ^ S6[x[0x9]] ^ S7[x[0xB]] ^ S8[x[0x8]] ^ S6[z[0x3]]; - Bits32ToInts(xCF, x, 0xC); + 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); - x03 = IntsTo32bits(x, 0x0); - x47 = IntsTo32bits(x, 0x4); - x8B = IntsTo32bits(x, 0x8); - xCF = IntsTo32bits(x, 0xC); + 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]]; Bits32ToInts(z03, z, 0x0); 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]]; - Bits32ToInts(zCF, z, 0xC); + 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); - z03 = IntsTo32bits(z, 0x0); - z47 = IntsTo32bits(z, 0x4); - z8B = IntsTo32bits(z, 0x8); - zCF = IntsTo32bits(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]]; Bits32ToInts(x03, x, 0x0); 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]]; Bits32ToInts(x8B, x, 0x8); - xCF = zCF ^ S5[x[0xA]] ^ S6[x[0x9]] ^ S7[x[0xB]] ^ S8[x[0x8]] ^ S6[z[0x3]]; - Bits32ToInts(xCF, x, 0xC); + 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); @@ -563,68 +570,61 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers /// /// The first of the three processing functions for the encryption and decryption. /// - /// The input to be processed. - /// The mask to be used from Km[n]. - /// The rotation value to be used. + /// The input to be processed. + /// The mask to be used from Km[n]. + /// The rotation value to be used. /// - private 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)); + var 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]; } /// /// The second of the three processing functions for the encryption and decryption. /// - /// The input to be processed. - /// The mask to be used from Km[n]. - /// The rotation value to be used. + /// The input to be processed. + /// The mask to be used from Km[n]. + /// The rotation value to be used. /// - private 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)); + var 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]; } /// /// The third of the three processing functions for the encryption and decryption. /// - /// The input to be processed. - /// The mask to be used from Km[n]. - /// The rotation value to be used. + /// The input to be processed. + /// The mask to be used from Km[n]. + /// The rotation value to be used. /// - private 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)); + var 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]; } /// /// Does the 16 rounds to encrypt the block. /// - /// The LH-32bits of the plaintext block. - /// The RH-32bits of the plaintext block. + /// The LH-32bits of the plaintext block. + /// The RH-32bits of the plaintext block. /// The result. - private void CastEncipher(uint L0, uint R0, uint[] result) + private void CastEncipher(uint l0, uint r0, uint[] result) { - var Lp = L0; // the previous value, equiv to L[i-1] - var Rp = R0; // equivalent to R[i-1] + uint li = l0, ri = r0; - /* - * numbering consistent with paper to make - * checking and validating easier - */ - uint Li = L0, Ri = R0; - - for (int i = 1; i <= _rounds; i++) + for (var i = 1; i <= _rounds; i++) { - Lp = Li; - Rp = Ri; + var lp = li; // the previous value, equiv to L[i-1] + var rp = ri; // equivalent to R[i-1] - Li = Rp; + li = rp; switch (i) { case 1: @@ -633,46 +633,39 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers case 10: case 13: case 16: - Ri = Lp ^ F1(Rp, _km[i], _kr[i]); + ri = lp ^ F1(rp, _km[i], _kr[i]); break; case 2: case 5: case 8: case 11: case 14: - Ri = Lp ^ F2(Rp, _km[i], _kr[i]); + ri = lp ^ F2(rp, _km[i], _kr[i]); break; case 3: case 6: case 9: case 12: case 15: - Ri = Lp ^ F3(Rp, _km[i], _kr[i]); + ri = lp ^ F3(rp, _km[i], _kr[i]); break; } } - result[0] = Ri; - result[1] = Li; + result[0] = ri; + result[1] = li; } - private void CastDecipher(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] + uint li = l16, ri = r16; - /* - * numbering consistent with paper to make - * checking and validating easier - */ - uint Li = L16, Ri = R16; - - for (int i = _rounds; i > 0; i--) + for (var i = _rounds; i > 0; i--) { - Lp = Li; - Rp = Ri; + var lp = li; // the previous value, equiv to L[i-1] + var rp = ri; // equivalent to R[i-1] - Li = Rp; + li = rp; switch (i) { case 1: @@ -681,44 +674,43 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers case 10: case 13: case 16: - Ri = Lp ^ F1(Rp, _km[i], _kr[i]); + ri = lp ^ F1(rp, _km[i], _kr[i]); break; case 2: case 5: case 8: case 11: case 14: - Ri = Lp ^ F2(Rp, _km[i], _kr[i]); + ri = lp ^ F2(rp, _km[i], _kr[i]); break; case 3: case 6: case 9: case 12: case 15: - Ri = Lp ^ F3(Rp, _km[i], _kr[i]); + ri = lp ^ F3(rp, _km[i], _kr[i]); break; } } - result[0] = Ri; - result[1] = Li; + result[0] = ri; + result[1] = li; } 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); } - private 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)); } - } } diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs new file mode 100644 index 00000000..be68fd48 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs @@ -0,0 +1,93 @@ +using System; +using Renci.SshNet.Common; +using Renci.SshNet.Security.Chaos.NaCl; + +namespace Renci.SshNet.Security.Cryptography +{ + /// + /// Implements ECDSA digital signature algorithm. + /// + public class ED25519DigitalSignature : DigitalSignature, IDisposable + { + private readonly ED25519Key _key; + + /// + /// Initializes a new instance of the class. + /// + /// The ED25519Key key. + /// is null. + public ED25519DigitalSignature(ED25519Key key) + { + if (key == null) + throw new ArgumentNullException("key"); + + _key = key; + } + + /// + /// Verifies the signature. + /// + /// The input. + /// The signature. + /// + /// true if signature was successfully verified; otherwise false. + /// + /// Invalid signature. + public override bool Verify(byte[] input, byte[] signature) + { + return Ed25519.Verify(signature, input, _key.PublicKey); + } + + /// + /// Creates the signature. + /// + /// The input. + /// + /// Signed input data. + /// + /// Invalid ED25519Key key. + public override byte[] Sign(byte[] input) + { + return Ed25519.Sign(input, _key.PrivateKey); + } + + #region IDisposable Members + + private bool _isDisposed; + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_isDisposed) + return; + + if (disposing) + { + _isDisposed = true; + } + } + + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~ED25519DigitalSignature() + { + Dispose(false); + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs new file mode 100644 index 00000000..83ac1c8c --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -0,0 +1,154 @@ +using System; +using Renci.SshNet.Common; +using Renci.SshNet.Security.Cryptography; +using Renci.SshNet.Security.Chaos.NaCl; + +namespace Renci.SshNet.Security +{ + /// + /// Contains ED25519 private and public key + /// + public class ED25519Key : Key, IDisposable + { + private ED25519DigitalSignature _digitalSignature; + + private byte[] publicKey = new byte[Ed25519.PublicKeySizeInBytes]; + private byte[] privateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes]; + + /// + /// Gets the Key String. + /// + public override string ToString() + { + return "ssh-ed25519"; + } + + /// + /// Gets or sets the public. + /// + /// + /// The public. + /// + public override BigInteger[] Public + { + get + { + return new BigInteger[] { publicKey.ToBigInteger() }; + } + set + { + publicKey = value[0].ToByteArray().Reverse().TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + } + } + + /// + /// Gets the length of the key. + /// + /// + /// The length of the key. + /// + public override int KeyLength + { + get + { + return PublicKey.Length; + } + } + + /// + /// Gets the digital signature. + /// + protected override DigitalSignature DigitalSignature + { + get + { + if (_digitalSignature == null) + { + _digitalSignature = new ED25519DigitalSignature(this); + } + return _digitalSignature; + } + } + + /// + /// Gets the PublicKey Bytes + /// + public byte[] PublicKey + { + get + { + return publicKey; + } + } + + /// + /// Gets the PrivateKey Bytes + /// + public byte[] PrivateKey + { + get + { + return privateKey; + } + } + + /// + /// Initializes a new instance of the class. + /// + public ED25519Key() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// pk data. + /// sk data. + public ED25519Key(byte[] pk, byte[] sk) + { + publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + var seed = new byte[Ed25519.PrivateKeySeedSizeInBytes]; + Buffer.BlockCopy(sk, 0, seed, 0, seed.Length); + Ed25519.KeyPairFromSeed(out publicKey, out privateKey, seed); + } + + #region IDisposable Members + + private bool _isDisposed; + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_isDisposed) + return; + + if (disposing) + { + _isDisposed = true; + } + } + + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~ED25519Key() + { + Dispose(false); + } + + #endregion + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs new file mode 100644 index 00000000..38d60966 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs @@ -0,0 +1,189 @@ +#if FEATURE_ECDSA +using System; +using Renci.SshNet.Common; +using System.Globalization; +using System.Security.Cryptography; + +namespace Renci.SshNet.Security.Cryptography +{ + /// + /// Implements ECDSA digital signature algorithm. + /// + public class EcdsaDigitalSignature : DigitalSignature, IDisposable + { + private readonly EcdsaKey _key; + + /// + /// Initializes a new instance of the class. + /// + /// The ECDSA key. + /// is null. + public EcdsaDigitalSignature(EcdsaKey key) + { + if (key == null) + throw new ArgumentNullException("key"); + + _key = key; + } + + /// + /// Verifies the signature. + /// + /// The input. + /// The signature. + /// + /// true if signature was successfully verified; otherwise false. + /// + public override bool Verify(byte[] input, byte[] signature) + { + // for 521 sig_size is 132 + var sig_size = _key.KeyLength == 521 ? 132 : _key.KeyLength / 4; + var ssh_data = new SshDataSignature(signature, sig_size); +#if NETSTANDARD2_0 + return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm); +#else + var ecdsa = (ECDsaCng)_key.Ecdsa; + ecdsa.HashAlgorithm = _key.HashAlgorithm; + return ecdsa.VerifyData(input, ssh_data.Signature); +#endif + } + + /// + /// Creates the signature. + /// + /// The input. + /// + /// Signed input data. + /// + public override byte[] Sign(byte[] input) + { +#if NETSTANDARD2_0 + var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm); +#else + var ecdsa = (ECDsaCng)_key.Ecdsa; + ecdsa.HashAlgorithm = _key.HashAlgorithm; + var signed = ecdsa.SignData(input); +#endif + var ssh_data = new SshDataSignature(signed.Length); + ssh_data.Signature = signed; + return ssh_data.GetBytes(); + } + + #region IDisposable Members + + private bool _isDisposed; + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_isDisposed) + return; + + if (disposing) + { + _isDisposed = true; + } + } + + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~EcdsaDigitalSignature() + { + Dispose(false); + } + + #endregion + } + + class SshDataSignature : SshData + { + private int _signature_size; + + private byte[] _signature_r; + private byte[] _signature_s; + + public byte[] Signature + { + get + { + var signature = new byte[_signature_size]; + Buffer.BlockCopy(_signature_r, 0, signature, 0, _signature_r.Length); + Buffer.BlockCopy(_signature_s, 0, signature, _signature_r.Length, _signature_s.Length); + return signature; + } + set + { + var signed_r = new byte[_signature_size / 2]; + Buffer.BlockCopy(value, 0, signed_r, 0, signed_r.Length); + _signature_r = signed_r.ToBigInteger2().ToByteArray().Reverse(); + + var signed_s = new byte[_signature_size / 2]; + Buffer.BlockCopy(value, signed_r.Length, signed_s, 0, signed_s.Length); + _signature_s = signed_s.ToBigInteger2().ToByteArray().Reverse(); + } + } + + public SshDataSignature(int sig_size) + { + _signature_size = sig_size; + } + + public SshDataSignature(byte[] data, int sig_size) + { + _signature_size = sig_size; + Load(data); + } + + protected override void LoadData() + { + _signature_r = ReadBinary().TrimLeadingZeros().Pad(_signature_size / 2); + _signature_s = ReadBinary().TrimLeadingZeros().Pad(_signature_size / 2); + } + + protected override void SaveData() + { + WriteBinaryString(_signature_r.ToBigInteger2().ToByteArray().Reverse()); + WriteBinaryString(_signature_s.ToBigInteger2().ToByteArray().Reverse()); + } + + public new byte[] ReadBinary() + { + var length = ReadUInt32(); + + if (length > int.MaxValue) + { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Strings longer than {0} is not supported.", int.MaxValue)); + } + + return ReadBytes((int)length); + } + + protected override int BufferCapacity + { + get + { + var capacity = base.BufferCapacity; + capacity += 4; // r length + capacity += _signature_r.Length; // signature r + capacity += 4; // s length + capacity += _signature_s.Length; // signature s + return capacity; + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs new file mode 100644 index 00000000..58861f02 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -0,0 +1,459 @@ +#if FEATURE_ECDSA +using System; +using System.IO; +using System.Text; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using Renci.SshNet.Common; +using Renci.SshNet.Security.Cryptography; + +namespace Renci.SshNet.Security +{ + /// + /// Contains ECDSA (ecdsa-sha2-nistp{256,384,521}) private and public key + /// + public class EcdsaKey : Key, IDisposable + { + internal const string ECDSA_P256_OID_VALUE = "1.2.840.10045.3.1.7"; // Also called nistP256 or secP256r1 + internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1 + internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1 + +#if !NETSTANDARD2_0 + internal enum KeyBlobMagicNumber : int + { + BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345, + BCRYPT_ECDSA_PRIVATE_P256_MAGIC = 0x32534345, + BCRYPT_ECDSA_PUBLIC_P384_MAGIC = 0x33534345, + BCRYPT_ECDSA_PRIVATE_P384_MAGIC = 0x34534345, + BCRYPT_ECDSA_PUBLIC_P521_MAGIC = 0x35534345, + BCRYPT_ECDSA_PRIVATE_P521_MAGIC = 0x36534345, + + BCRYPT_ECDH_PUBLIC_P256_MAGIC = 0x314B4345, + BCRYPT_ECDH_PRIVATE_P256_MAGIC = 0x324B4345, + BCRYPT_ECDH_PUBLIC_P384_MAGIC = 0x334B4345, + BCRYPT_ECDH_PRIVATE_P384_MAGIC = 0x344B4345, + BCRYPT_ECDH_PUBLIC_P521_MAGIC = 0x354B4345, + BCRYPT_ECDH_PRIVATE_P521_MAGIC = 0x364B4345, + + BCRYPT_ECDH_PUBLIC_GENERIC_MAGIC = 0x504B4345, + BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC = 0x564B4345, + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BCRYPT_ECCKEY_BLOB + { + internal KeyBlobMagicNumber Magic; + internal int cbKey; + } + + private CngKey key; +#endif + + /// + /// Gets the SSH name of the ECDSA Key + /// + public override string ToString() + { + return string.Format("ecdsa-sha2-nistp{0}", KeyLength); + } + +#if NETSTANDARD2_0 + /// + /// Gets the HashAlgorithm to use + /// + public HashAlgorithmName HashAlgorithm + { + get + { + switch (KeyLength) + { + case 256: + return HashAlgorithmName.SHA256; + case 384: + return HashAlgorithmName.SHA384; + case 521: + return HashAlgorithmName.SHA512; + } + return HashAlgorithmName.SHA256; + } + } +#else + /// + /// Gets the HashAlgorithm to use + /// + public CngAlgorithm HashAlgorithm + { + get + { + switch (Ecdsa.KeySize) + { + case 256: + return CngAlgorithm.Sha256; + case 384: + return CngAlgorithm.Sha384; + case 521: + return CngAlgorithm.Sha512; + default: + throw new SshException("Unknown KeySize: " + Ecdsa.KeySize); + } + } + } +#endif + + /// + /// Gets the length of the key. + /// + /// + /// The length of the key. + /// + public override int KeyLength + { + get + { + return Ecdsa.KeySize; + } + } + + private EcdsaDigitalSignature _digitalSignature; + + /// + /// Gets the digital signature. + /// + protected override DigitalSignature DigitalSignature + { + get + { + if (_digitalSignature == null) + { + _digitalSignature = new EcdsaDigitalSignature(this); + } + return _digitalSignature; + } + } + + /// + /// Gets or sets the public. + /// + /// + /// The public. + /// + public override BigInteger[] Public + { + get + { + byte[] curve; + byte[] qx; + byte[] qy; +#if NETSTANDARD2_0 + var parameter = Ecdsa.ExportParameters(false); + qx = parameter.Q.X; + qy = parameter.Q.Y; + switch (parameter.Curve.Oid.FriendlyName) + { + case "ECDSA_P256": + case "nistP256": + curve = Encoding.ASCII.GetBytes("nistp256"); + break; + case "ECDSA_P384": + case "nistP384": + curve = Encoding.ASCII.GetBytes("nistp384"); + break; + case "ECDSA_P521": + case "nistP521": + curve = Encoding.ASCII.GetBytes("nistp521"); + break; + default: + throw new SshException("Unexpected Curve Name: " + parameter.Curve.Oid.FriendlyName); + } +#else + var blob = key.Export(CngKeyBlobFormat.EccPublicBlob); + + KeyBlobMagicNumber magic; + using (var br = new BinaryReader(new MemoryStream(blob))) + { + magic = (KeyBlobMagicNumber)br.ReadInt32(); + int cbKey = br.ReadInt32(); + qx = br.ReadBytes(cbKey); + qy = br.ReadBytes(cbKey); + } + + switch (magic) + { + case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P256_MAGIC: + curve = Encoding.ASCII.GetBytes("nistp256"); + break; + case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC: + curve = Encoding.ASCII.GetBytes("nistp384"); + break; + case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC: + curve = Encoding.ASCII.GetBytes("nistp521"); + break; + default: + throw new SshException("Unexpected Curve Magic: " + magic); + } +#endif + // Make ECPoint from x and y + // Prepend 04 (uncompressed format) + qx-bytes + qy-bytes + var q = new byte[1 + qx.Length + qy.Length]; + Buffer.SetByte(q, 0, 4); + Buffer.BlockCopy(qx, 0, q, 1, qx.Length); + Buffer.BlockCopy(qy, 0, q, qx.Length + 1, qy.Length); + + // returns Curve-Name and x/y as ECPoint + return new[] { new BigInteger(curve.Reverse()), new BigInteger(q.Reverse()) }; + } + set + { + var curve_s = Encoding.ASCII.GetString(value[0].ToByteArray().Reverse()); + string curve_oid = GetCurveOid(curve_s); + + var publickey = value[1].ToByteArray().Reverse(); + Import(curve_oid, publickey, null); + } + } + + /// + /// Gets ECDsa Object + /// + public ECDsa Ecdsa { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + public EcdsaKey() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The curve name + /// Value of publickey + /// Value of privatekey + public EcdsaKey(string curve, byte[] publickey, byte[] privatekey) + { + Import(GetCurveOid(curve), publickey, privatekey); + } + + /// + /// Initializes a new instance of the class. + /// + /// DER encoded private key data. + public EcdsaKey(byte[] data) + { + var der = new DerData(data); + var version = der.ReadBigInteger(); // skip version + + // PrivateKey + var privatekey = der.ReadOctetString().TrimLeadingZeros(); + + // Construct + var s0 = der.ReadByte(); + if ((s0 & 0xe0) != 0xa0) + throw new SshException(string.Format("UnexpectedDER: wanted constructed tag (0xa0-0xbf), got: {0:X}", s0)); + var tag = s0 & 0x1f; + if (tag != 0) + throw new SshException(string.Format("expected tag 0 in DER privkey, got: {0}", tag)); + var construct = der.ReadBytes(der.ReadLength()); // object length + + // curve OID + var curve_der = new DerData(construct, true); + var curve = curve_der.ReadObject(); + + // Construct + s0 = der.ReadByte(); + if ((s0 & 0xe0) != 0xa0) + throw new SshException(string.Format("UnexpectedDER: wanted constructed tag (0xa0-0xbf), got: {0:X}", s0)); + tag = s0 & 0x1f; + if (tag != 1) + throw new SshException(string.Format("expected tag 1 in DER privkey, got: {0}", tag)); + construct = der.ReadBytes(der.ReadLength()); // object length + + // PublicKey + var pubkey_der = new DerData(construct, true); + var pubkey = pubkey_der.ReadBitString().TrimLeadingZeros(); + + Import(OidByteArrayToString(curve), pubkey, privatekey); + } + + private void Import(string curve_oid, byte[] publickey, byte[] privatekey) + { +#if NETSTANDARD2_0 + var curve = ECCurve.CreateFromValue(curve_oid); + var parameter = new ECParameters + { + Curve = curve + }; + + // ECPoint as BigInteger(2) + var cord_size = (publickey.Length - 1) / 2; + var qx = new byte[cord_size]; + Buffer.BlockCopy(publickey, 1, qx, 0, qx.Length); + + var qy = new byte[cord_size]; + Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length); + + parameter.Q.X = qx; + parameter.Q.Y = qy; + + if (privatekey != null) + parameter.D = privatekey.TrimLeadingZeros().Pad(cord_size); + + Ecdsa = ECDsa.Create(parameter); +#else + var curve_magic = KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC; + switch (GetCurveName(curve_oid)) + { + case "nistp256": + if (privatekey != null) + curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P256_MAGIC; + else + curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P256_MAGIC; + break; + case "nistp384": + if (privatekey != null) + curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P384_MAGIC; + else + curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC; + break; + case "nistp521": + if (privatekey != null) + curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P521_MAGIC; + else + curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC; + break; + default: + throw new SshException("Unknown: " + curve_oid); + } + + // ECPoint as BigInteger(2) + var cord_size = (publickey.Length - 1) / 2; + var qx = new byte[cord_size]; + Buffer.BlockCopy(publickey, 1, qx, 0, qx.Length); + + var qy = new byte[cord_size]; + Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length); + + if (privatekey != null) + privatekey = privatekey.Pad(cord_size); + + int headerSize = Marshal.SizeOf(typeof(BCRYPT_ECCKEY_BLOB)); + int blobSize = headerSize + qx.Length + qy.Length; + if (privatekey != null) + blobSize += privatekey.Length; + + byte[] blob = new byte[blobSize]; + using (var bw = new BinaryWriter(new MemoryStream(blob))) + { + bw.Write((int)curve_magic); + bw.Write(cord_size); + bw.Write(qx); // q.x + bw.Write(qy); // q.y + if (privatekey != null) + bw.Write(privatekey); // d + } + key = CngKey.Import(blob, privatekey == null ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob); + + Ecdsa = new ECDsaCng(key); +#endif + } + + private string GetCurveOid(string curve_s) + { + switch (curve_s.ToLower()) + { + case "nistp256": + return ECDSA_P256_OID_VALUE; + case "nistp384": + return ECDSA_P384_OID_VALUE; + case "nistp521": + return ECDSA_P521_OID_VALUE; + default: + throw new SshException("Unexpected Curve Name: " + curve_s); + } + } + + private string GetCurveName(string oid) + { + switch (oid) + { + case ECDSA_P256_OID_VALUE: + return "nistp256"; + case ECDSA_P384_OID_VALUE: + return "nistp384"; + case ECDSA_P521_OID_VALUE: + return "nistp521"; + default: + throw new SshException("Unexpected OID: " + oid); + } + } + + private string OidByteArrayToString(byte[] oid) + { + StringBuilder retVal = new StringBuilder(); + + for (int i = 0; i < oid.Length; i++) + { + if (i == 0) + { + int b = oid[0] % 40; + int a = (oid[0] - b) / 40; + retVal.AppendFormat("{0}.{1}", a, b); + } + else + { + if (oid[i] < 128) + retVal.AppendFormat(".{0}", oid[i]); + else + { + retVal.AppendFormat(".{0}", + ((oid[i] - 128) * 128) + oid[i + 1]); + i++; + } + } + } + + return retVal.ToString(); + } + + #region IDisposable Members + + private bool _isDisposed; + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_isDisposed) + return; + + if (disposing) + { + _isDisposed = true; + } + } + + /// + /// Releases unmanaged resources and performs other cleanup operations before the + /// is reclaimed by garbage collection. + /// + ~EcdsaKey() + { + Dispose(false); + } + + #endregion + } +} +#endif \ No newline at end of file diff --git a/src/Renci.SshNet/Security/GroupExchangeHashData.cs b/src/Renci.SshNet/Security/GroupExchangeHashData.cs index 992df4ae..12b5fbf1 100644 --- a/src/Renci.SshNet/Security/GroupExchangeHashData.cs +++ b/src/Renci.SshNet/Security/GroupExchangeHashData.cs @@ -9,9 +9,6 @@ namespace Renci.SshNet.Security private byte[] _clientVersion; private byte[] _prime; private byte[] _subGroup; - private byte[] _clientExchangeValue; - private byte[] _serverExchangeValue; - private byte[] _sharedKey; public string ServerVersion { @@ -50,23 +47,11 @@ namespace Renci.SshNet.Security set { _subGroup = value.ToByteArray().Reverse(); } } - public BigInteger ClientExchangeValue - { - private get { return _clientExchangeValue.ToBigInteger(); } - set { _clientExchangeValue = value.ToByteArray().Reverse(); } - } + public byte[] ClientExchangeValue { get; set; } - public BigInteger ServerExchangeValue - { - private get { return _serverExchangeValue.ToBigInteger(); } - set { _serverExchangeValue = value.ToByteArray().Reverse(); } - } + public byte[] ServerExchangeValue { get; set; } - public BigInteger SharedKey - { - private get { return _sharedKey.ToBigInteger(); } - set { _sharedKey = value.ToByteArray().Reverse(); } - } + public byte[] SharedKey { get; set; } /// /// Gets the size of the message in bytes. @@ -97,11 +82,11 @@ namespace Renci.SshNet.Security capacity += 4; // SubGroup length capacity += _subGroup.Length; // SubGroup capacity += 4; // ClientExchangeValue length - capacity += _clientExchangeValue.Length; // ClientExchangeValue + capacity += ClientExchangeValue.Length; // ClientExchangeValue capacity += 4; // ServerExchangeValue length - capacity += _serverExchangeValue.Length; // ServerExchangeValue + capacity += ServerExchangeValue.Length; // ServerExchangeValue capacity += 4; // SharedKey length - capacity += _sharedKey.Length; // SharedKey + capacity += SharedKey.Length; // SharedKey return capacity; } } @@ -123,9 +108,9 @@ namespace Renci.SshNet.Security Write(MaximumGroupSize); WriteBinaryString(_prime); WriteBinaryString(_subGroup); - WriteBinaryString(_clientExchangeValue); - WriteBinaryString(_serverExchangeValue); - WriteBinaryString(_sharedKey); + WriteBinaryString(ClientExchangeValue); + WriteBinaryString(ServerExchangeValue); + WriteBinaryString(SharedKey); } } } diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index 75e3517a..a13c272a 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -37,7 +37,7 @@ namespace Renci.SshNet.Security /// /// The shared key. /// - public BigInteger SharedKey { get; protected set; } + public byte[] SharedKey { get; protected set; } private byte[] _exchangeHash; @@ -323,13 +323,7 @@ namespace Renci.SshNet.Security /// /// Hashed bytes /// - protected virtual byte[] Hash(byte[] hashData) - { - using (var sha1 = CryptoAbstraction.CreateSHA1()) - { - return sha1.ComputeHash(hashData, 0, hashData.Length); - } - } + protected abstract byte[] Hash(byte[] hashData); /// /// Sends SSH message to the server @@ -348,17 +342,20 @@ namespace Renci.SshNet.Security /// The key. /// The size. /// - private byte[] GenerateSessionKey(BigInteger sharedKey, byte[] exchangeHash, byte[] key, int size) + private byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, byte[] key, int size) { var result = new List(key); + while (size > result.Count) { - result.AddRange(Hash(new _SessionKeyAdjustment - { - SharedKey = sharedKey, - ExchangeHash = exchangeHash, - Key = key, - }.GetBytes())); + var sessionKeyAdjustment = new SessionKeyAdjustment + { + SharedKey = sharedKey, + ExchangeHash = exchangeHash, + Key = key, + }; + + result.AddRange(Hash(sessionKeyAdjustment.GetBytes())); } return result.ToArray(); @@ -372,28 +369,26 @@ namespace Renci.SshNet.Security /// The p. /// The session id. /// - private static byte[] GenerateSessionKey(BigInteger sharedKey, byte[] exchangeHash, char p, byte[] sessionId) + private static byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, char p, byte[] sessionId) { - return new _SessionKeyGeneration - { - SharedKey = sharedKey, - ExchangeHash = exchangeHash, - Char = p, - SessionId = sessionId, - }.GetBytes(); + var sessionKeyGeneration = new SessionKeyGeneration + { + SharedKey = sharedKey, + ExchangeHash = exchangeHash, + Char = p, + SessionId = sessionId + }; + return sessionKeyGeneration.GetBytes(); } - private class _SessionKeyGeneration : SshData + private class SessionKeyGeneration : SshData { - private byte[] _sharedKey; + public byte[] SharedKey { get; set; } - public BigInteger SharedKey - { - private get { return _sharedKey.ToBigInteger(); } - set { _sharedKey = value.ToByteArray().Reverse(); } - } public byte[] ExchangeHash { get; set; } + public char Char { get; set; } + public byte[] SessionId { get; set; } /// @@ -408,7 +403,7 @@ namespace Renci.SshNet.Security { var capacity = base.BufferCapacity; capacity += 4; // SharedKey length - capacity += _sharedKey.Length; // SharedKey + capacity += SharedKey.Length; // SharedKey capacity += ExchangeHash.Length; // ExchangeHash capacity += 1; // Char capacity += SessionId.Length; // SessionId @@ -423,23 +418,19 @@ namespace Renci.SshNet.Security protected override void SaveData() { - WriteBinaryString(_sharedKey); + WriteBinaryString(SharedKey); Write(ExchangeHash); Write((byte) Char); Write(SessionId); } } - private class _SessionKeyAdjustment : SshData + private class SessionKeyAdjustment : SshData { - private byte[] _sharedKey; + public byte[] SharedKey { get; set; } - public BigInteger SharedKey - { - private get { return _sharedKey.ToBigInteger(); } - set { _sharedKey = value.ToByteArray().Reverse(); } - } public byte[] ExchangeHash { get; set; } + public byte[] Key { get; set; } /// @@ -454,7 +445,7 @@ namespace Renci.SshNet.Security { var capacity = base.BufferCapacity; capacity += 4; // SharedKey length - capacity += _sharedKey.Length; // SharedKey + capacity += SharedKey.Length; // SharedKey capacity += ExchangeHash.Length; // ExchangeHash capacity += Key.Length; // Key return capacity; @@ -468,7 +459,7 @@ namespace Renci.SshNet.Security protected override void SaveData() { - WriteBinaryString(_sharedKey); + WriteBinaryString(SharedKey); Write(ExchangeHash); Write(Key); } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs index 29223a2e..375c3a59 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs @@ -33,12 +33,12 @@ namespace Renci.SshNet.Security /// /// Specifies client exchange number. /// - protected BigInteger _clientExchangeValue; + protected byte[] _clientExchangeValue; /// /// Specifies server exchange number. /// - protected BigInteger _serverExchangeValue; + protected byte[] _serverExchangeValue; /// /// Specifies random generated number. @@ -114,13 +114,17 @@ namespace Renci.SshNet.Security // of 1024 bits (whatever is less) var privateExponentSize = Math.Max(HashSize * 2, 1024); + BigInteger clientExchangeValue; + do { // create private component _privateExponent = BigInteger.Random(privateExponentSize); // generate public component - _clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime); - } while (_clientExchangeValue < 1 || _clientExchangeValue > (_prime - 1)); + clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime); + } while (clientExchangeValue < 1 || clientExchangeValue > (_prime - 1)); + + _clientExchangeValue = clientExchangeValue.ToByteArray().Reverse(); } /// @@ -129,11 +133,11 @@ namespace Renci.SshNet.Security /// The host key. /// The server exchange value. /// The signature. - protected virtual void HandleServerDhReply(byte[] hostKey, BigInteger serverExchangeValue, byte[] signature) + protected virtual void HandleServerDhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature) { _serverExchangeValue = serverExchangeValue; _hostKey = hostKey; - SharedKey = BigInteger.ModPow(serverExchangeValue, _privateExponent, _prime); + SharedKey = BigInteger.ModPow(serverExchangeValue.ToBigInteger(), _privateExponent, _prime).ToByteArray().Reverse(); _signature = signature; } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs new file mode 100644 index 00000000..276077a0 --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs @@ -0,0 +1,62 @@ +using Renci.SshNet.Common; + +namespace Renci.SshNet.Security +{ + /// + /// Represents "diffie-hellman-group14-sha256" algorithm implementation. + /// + internal class KeyExchangeDiffieHellmanGroup14Sha256 : KeyExchangeDiffieHellmanGroupSha256 + { + /// + /// https://tools.ietf.org/html/rfc2409#section-6.2 + /// + private static readonly byte[] SecondOkleyGroupReversed = + { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x68, 0xaa, 0xac, 0x8a, + 0x5a, 0x8e, 0x72, 0x15, 0x10, 0x05, 0xfa, 0x98, 0x18, 0x26, 0xd2, 0x15, + 0xe5, 0x6a, 0x95, 0xea, 0x7c, 0x49, 0x95, 0x39, 0x18, 0x17, 0x58, 0x95, + 0xf6, 0xcb, 0x2b, 0xde, 0xc9, 0x52, 0x4c, 0x6f, 0xf0, 0x5d, 0xc5, 0xb5, + 0x8f, 0xa2, 0x07, 0xec, 0xa2, 0x83, 0x27, 0x9b, 0x03, 0x86, 0x0e, 0x18, + 0x2c, 0x77, 0x9e, 0xe3, 0x3b, 0xce, 0x36, 0x2e, 0x46, 0x5e, 0x90, 0x32, + 0x7c, 0x21, 0x18, 0xca, 0x08, 0x6c, 0x74, 0xf1, 0x04, 0x98, 0xbc, 0x4a, + 0x4e, 0x35, 0x0c, 0x67, 0x6d, 0x96, 0x96, 0x70, 0x07, 0x29, 0xd5, 0x9e, + 0xbb, 0x52, 0x85, 0x20, 0x56, 0xf3, 0x62, 0x1c, 0x96, 0xad, 0xa3, 0xdc, + 0x23, 0x5d, 0x65, 0x83, 0x5f, 0xcf, 0x24, 0xfd, 0xa8, 0x3f, 0x16, 0x69, + 0x9a, 0xd3, 0x55, 0x1c, 0x36, 0x48, 0xda, 0x98, 0x05, 0xbf, 0x63, 0xa1, + 0xb8, 0x7c, 0x00, 0xc2, 0x3d, 0x5b, 0xe4, 0xec, 0x51, 0x66, 0x28, 0x49, + 0xe6, 0x1f, 0x4b, 0x7c, 0x11, 0x24, 0x9f, 0xae, 0xa5, 0x9f, 0x89, 0x5a, + 0xfb, 0x6b, 0x38, 0xee, 0xed, 0xb7, 0x06, 0xf4, 0xb6, 0x5c, 0xff, 0x0b, + 0x6b, 0xed, 0x37, 0xa6, 0xe9, 0x42, 0x4c, 0xf4, 0xc6, 0x7e, 0x5e, 0x62, + 0x76, 0xb5, 0x85, 0xe4, 0x45, 0xc2, 0x51, 0x6d, 0x6d, 0x35, 0xe1, 0x4f, + 0x37, 0x14, 0x5f, 0xf2, 0x6d, 0x0a, 0x2b, 0x30, 0x1b, 0x43, 0x3a, 0xcd, + 0xb3, 0x19, 0x95, 0xef, 0xdd, 0x04, 0x34, 0x8e, 0x79, 0x08, 0x4a, 0x51, + 0x22, 0x9b, 0x13, 0x3b, 0xa6, 0xbe, 0x0b, 0x02, 0x74, 0xcc, 0x67, 0x8a, + 0x08, 0x4e, 0x02, 0x29, 0xd1, 0x1c, 0xdc, 0x80, 0x8b, 0x62, 0xc6, 0xc4, + 0x34, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, + 0x00 + }; + + /// + /// Gets algorithm name. + /// + public override string Name + { + get { return "diffie-hellman-group14-sha256"; } + } + + /// + /// Gets the group prime. + /// + /// + /// The group prime. + /// + public override BigInteger GroupPrime + { + get + { + return new BigInteger(SecondOkleyGroupReversed); + } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs new file mode 100644 index 00000000..48f7e178 --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs @@ -0,0 +1,66 @@ +using Renci.SshNet.Common; + +namespace Renci.SshNet.Security +{ + /// + /// Represents "diffie-hellman-group16-sha512" algorithm implementation. + /// + internal class KeyExchangeDiffieHellmanGroup16Sha512 : KeyExchangeDiffieHellmanGroupSha512 + { + /// + /// https://tools.ietf.org/html/rfc3526#section-5 + /// + private static readonly byte[] MoreModularExponentialGroup16Reversed = + { + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x99,0x31,0x06,0x34,0xc9,0x35,0xf4,0x4d, + 0x8f,0xc0,0xa6,0x90,0xdc,0xb7,0xff,0x86,0xc1,0xdd,0x8f,0x8d,0x98,0xea,0xb4,0x93, + 0xa9,0x5a,0xb0,0xd5,0x27,0x91,0x06,0xd0,0x1c,0x48,0x70,0x21,0x76,0xdd,0x1b,0xb8, + 0xaf,0xd7,0xe2,0xce,0x70,0x29,0x61,0x1f,0xed,0xe7,0x5b,0x51,0x86,0xa1,0x3b,0x23, + 0xa2,0xc3,0x90,0xa0,0x4f,0x96,0xb2,0x99,0x5d,0xc0,0x6b,0x4e,0x47,0x59,0x7c,0x28, + 0xa6,0xca,0xbe,0x1f,0x14,0xfc,0x8e,0x2e,0xf9,0x8e,0xde,0x04,0xdb,0xc2,0xbb,0xdb, + 0xe8,0x4c,0xd4,0x2a,0xca,0xe9,0x83,0x25,0xda,0x0b,0x15,0xb6,0x34,0x68,0x94,0x1a, + 0x3c,0xe2,0xf4,0x6a,0x18,0x27,0xc3,0x99,0x26,0x5b,0xba,0xbd,0x10,0x9a,0x71,0x88, + 0xd7,0xe6,0x87,0xa7,0x12,0x3c,0x72,0x1a,0x01,0x08,0x21,0xa9,0x20,0xd1,0x82,0x4b, + 0x8e,0x10,0xfd,0xe0,0xfc,0x5b,0xdb,0x43,0x31,0xab,0xe5,0x74,0xa0,0x4f,0xe2,0x08, + 0xe2,0x46,0xd9,0xba,0xc0,0x88,0x09,0x77,0x6c,0x5d,0x61,0x7a,0x57,0x17,0xe1,0xbb, + 0x0c,0x20,0x7b,0x17,0x18,0x2b,0x1f,0x52,0x64,0x6a,0xc8,0x3e,0x73,0x02,0x76,0xd8, + 0x64,0x08,0x8a,0xd9,0x06,0xfa,0x2f,0xf1,0x6b,0xee,0xd2,0x1a,0x26,0xd2,0xe3,0xce, + 0x9d,0x61,0x25,0x4a,0xe0,0x94,0x8c,0x1e,0xd7,0x33,0x09,0xdb,0x8c,0xae,0xf5,0xab, + 0xc7,0xe4,0xe1,0xa6,0x85,0x0f,0x97,0xb3,0x7d,0x0c,0x06,0x5d,0x57,0x71,0xea,0x8a, + 0x0a,0xef,0xdb,0x58,0x04,0x85,0xfb,0xec,0x64,0xba,0x1c,0xdf,0xab,0x21,0x55,0xa8, + 0x33,0x7a,0x50,0x04,0x0d,0x17,0x33,0xad,0x2d,0xc4,0xaa,0x8a,0x5a,0x8e,0x72,0x15, + 0x10,0x05,0xfa,0x98,0x18,0x26,0xd2,0x15,0xe5,0x6a,0x95,0xea,0x7c,0x49,0x95,0x39, + 0x18,0x17,0x58,0x95,0xf6,0xcb,0x2b,0xde,0xc9,0x52,0x4c,0x6f,0xf0,0x5d,0xc5,0xb5, + 0x8f,0xa2,0x07,0xec,0xa2,0x83,0x27,0x9b,0x03,0x86,0x0e,0x18,0x2c,0x77,0x9e,0xe3, + 0x3b,0xce,0x36,0x2e,0x46,0x5e,0x90,0x32,0x7c,0x21,0x18,0xca,0x08,0x6c,0x74,0xf1, + 0x04,0x98,0xbc,0x4a,0x4e,0x35,0x0c,0x67,0x6d,0x96,0x96,0x70,0x07,0x29,0xd5,0x9e, + 0xbb,0x52,0x85,0x20,0x56,0xf3,0x62,0x1c,0x96,0xad,0xa3,0xdc,0x23,0x5d,0x65,0x83, + 0x5f,0xcf,0x24,0xfd,0xa8,0x3f,0x16,0x69,0x9a,0xd3,0x55,0x1c,0x36,0x48,0xda,0x98, + 0x05,0xbf,0x63,0xa1,0xb8,0x7c,0x00,0xc2,0x3d,0x5b,0xe4,0xec,0x51,0x66,0x28,0x49, + 0xe6,0x1f,0x4b,0x7c,0x11,0x24,0x9f,0xae,0xa5,0x9f,0x89,0x5a,0xfb,0x6b,0x38,0xee, + 0xed,0xb7,0x06,0xf4,0xb6,0x5c,0xff,0x0b,0x6b,0xed,0x37,0xa6,0xe9,0x42,0x4c,0xf4, + 0xc6,0x7e,0x5e,0x62,0x76,0xb5,0x85,0xe4,0x45,0xc2,0x51,0x6d,0x6d,0x35,0xe1,0x4f, + 0x37,0x14,0x5f,0xf2,0x6d,0x0a,0x2b,0x30,0x1b,0x43,0x3a,0xcd,0xb3,0x19,0x95,0xef, + 0xdd,0x04,0x34,0x8e,0x79,0x08,0x4a,0x51,0x22,0x9b,0x13,0x3b,0xa6,0xbe,0x0b,0x02, + 0x74,0xcc,0x67,0x8a,0x08,0x4e,0x02,0x29,0xd1,0x1c,0xdc,0x80,0x8b,0x62,0xc6,0xc4, + 0x34,0xc2,0x68,0x21,0xa2,0xda,0x0f,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0x00 + }; + + public override BigInteger GroupPrime + { + get + { + return new BigInteger(MoreModularExponentialGroup16Reversed); + } + } + + /// + /// Gets algorithm name. + /// + public override string Name + { + get { return "diffie-hellman-group16-sha512"; } + } + } +} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs index fc1a18a6..a7f1b742 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs @@ -1,4 +1,6 @@ -namespace Renci.SshNet.Security +using Renci.SshNet.Abstractions; + +namespace Renci.SshNet.Security { /// /// Represents "diffie-hellman-group-exchange-sha1" algorithm implementation. @@ -23,5 +25,20 @@ { get { return 160; } } + + /// + /// Hashes the specified data bytes. + /// + /// The hash data. + /// + /// Hashed bytes + /// + protected override byte[] Hash(byte[] hashData) + { + using (var sha1 = CryptoAbstraction.CreateSHA1()) + { + return sha1.ComputeHash(hashData, 0, hashData.Length); + } + } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs index 2ccdf731..755f77f2 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs @@ -19,7 +19,7 @@ namespace Renci.SshNet.Security /// protected override byte[] CalculateHash() { - var hashData = new GroupExchangeHashData + var groupExchangeHashData = new GroupExchangeHashData { ClientVersion = Session.ClientVersion, ServerVersion = Session.ServerVersion, @@ -34,9 +34,9 @@ namespace Renci.SshNet.Security ClientExchangeValue = _clientExchangeValue, ServerExchangeValue = _serverExchangeValue, SharedKey = SharedKey, - }.GetBytes(); + }; - return Hash(hashData); + return Hash(groupExchangeHashData.GetBytes()); } /// @@ -54,8 +54,7 @@ namespace Renci.SshNet.Security Session.KeyExchangeDhGroupExchangeGroupReceived += Session_KeyExchangeDhGroupExchangeGroupReceived; // 1. client sends SSH_MSG_KEY_DH_GEX_REQUEST - SendMessage(new KeyExchangeDhGroupExchangeRequest(MinimumGroupSize, PreferredGroupSize, - MaximumProupSize)); + SendMessage(new KeyExchangeDhGroupExchangeRequest(MinimumGroupSize, PreferredGroupSize, MaximumProupSize)); } /// diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs index eb2a0cb1..675ee2cf 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs @@ -1,22 +1,12 @@ -using System; -using Renci.SshNet.Common; -using Renci.SshNet.Messages.Transport; +using Renci.SshNet.Abstractions; namespace Renci.SshNet.Security { /// /// Represents "diffie-hellman-group1-sha1" algorithm implementation. /// - internal abstract class KeyExchangeDiffieHellmanGroupSha1 : KeyExchangeDiffieHellman + internal abstract class KeyExchangeDiffieHellmanGroupSha1 : KeyExchangeDiffieHellmanGroupShaBase { - /// - /// Gets the group prime. - /// - /// - /// The group prime. - /// - public abstract BigInteger GroupPrime { get; } - /// /// Gets the size, in bits, of the computed hash code. /// @@ -29,162 +19,17 @@ namespace Renci.SshNet.Security } /// - /// Calculates key exchange hash value. + /// Hashes the specified data bytes. /// + /// The hash data. /// - /// Key exchange hash. + /// Hashed bytes /// - protected override byte[] CalculateHash() + protected override byte[] Hash(byte[] hashData) { - var hashData = new _ExchangeHashData - { - ClientVersion = Session.ClientVersion, - ServerVersion = Session.ServerVersion, - ClientPayload = _clientPayload, - ServerPayload = _serverPayload, - HostKey = _hostKey, - ClientExchangeValue = _clientExchangeValue, - ServerExchangeValue = _serverExchangeValue, - SharedKey = SharedKey, - }.GetBytes(); - - return Hash(hashData); - } - - /// - /// Starts key exchange algorithm - /// - /// The session. - /// Key exchange init message. - public override void Start(Session session, KeyExchangeInitMessage message) - { - base.Start(session, message); - - Session.RegisterMessage("SSH_MSG_KEXDH_REPLY"); - - Session.KeyExchangeDhReplyMessageReceived += Session_KeyExchangeDhReplyMessageReceived; - - _prime = GroupPrime; - _group = new BigInteger(new byte[] { 2 }); - - PopulateClientExchangeValue(); - - SendMessage(new KeyExchangeDhInitMessage(_clientExchangeValue)); - } - - /// - /// Finishes key exchange algorithm. - /// - public override void Finish() - { - base.Finish(); - - Session.KeyExchangeDhReplyMessageReceived -= Session_KeyExchangeDhReplyMessageReceived; - } - - private void Session_KeyExchangeDhReplyMessageReceived(object sender, MessageEventArgs e) - { - var message = e.Message; - - // Unregister message once received - Session.UnRegisterMessage("SSH_MSG_KEXDH_REPLY"); - - HandleServerDhReply(message.HostKey, message.F, message.Signature); - - // When SSH_MSG_KEXDH_REPLY received key exchange is completed - Finish(); - } - - private class _ExchangeHashData : SshData - { - private byte[] _serverVersion; - private byte[] _clientVersion; - private byte[] _clientExchangeValue; - private byte[] _serverExchangeValue; - private byte[] _sharedKey; - - public string ServerVersion + using (var sha1 = CryptoAbstraction.CreateSHA1()) { - private get { return Utf8.GetString(_serverVersion, 0, _serverVersion.Length); } - set { _serverVersion = Utf8.GetBytes(value); } - } - - public string ClientVersion - { - private get { return Utf8.GetString(_clientVersion, 0, _clientVersion.Length); } - set { _clientVersion = Utf8.GetBytes(value); } - } - - public byte[] ClientPayload { get; set; } - - public byte[] ServerPayload { get; set; } - - public byte[] HostKey { get; set; } - - public BigInteger ClientExchangeValue - { - private get { return _clientExchangeValue.ToBigInteger(); } - set { _clientExchangeValue = value.ToByteArray().Reverse(); } - } - - public BigInteger ServerExchangeValue - { - private get { return _serverExchangeValue.ToBigInteger(); } - set { _serverExchangeValue = value.ToByteArray().Reverse(); } - } - - public BigInteger SharedKey - { - private get { return _sharedKey.ToBigInteger(); } - set { _sharedKey = value.ToByteArray().Reverse(); } - } - - /// - /// Gets the size of the message in bytes. - /// - /// - /// The size of the messages in bytes. - /// - protected override int BufferCapacity - { - get - { - var capacity = base.BufferCapacity; - capacity += 4; // ClientVersion length - capacity += _clientVersion.Length; // ClientVersion - capacity += 4; // ServerVersion length - capacity += _serverVersion.Length; // ServerVersion - capacity += 4; // ClientPayload length - capacity += ClientPayload.Length; // ClientPayload - capacity += 4; // ServerPayload length - capacity += ServerPayload.Length; // ServerPayload - capacity += 4; // HostKey length - capacity += HostKey.Length; // HostKey - capacity += 4; // ClientExchangeValue length - capacity += _clientExchangeValue.Length; // ClientExchangeValue - capacity += 4; // ServerExchangeValue length - capacity += _serverExchangeValue.Length; // ServerExchangeValue - capacity += 4; // SharedKey length - capacity += _sharedKey.Length; // SharedKey - return capacity; - } - } - - protected override void LoadData() - { - throw new NotImplementedException(); - } - - protected override void SaveData() - { - WriteBinaryString(_clientVersion); - WriteBinaryString(_serverVersion); - WriteBinaryString(ClientPayload); - WriteBinaryString(ServerPayload); - WriteBinaryString(HostKey); - WriteBinaryString(_clientExchangeValue); - WriteBinaryString(_serverExchangeValue); - WriteBinaryString(_sharedKey); + return sha1.ComputeHash(hashData, 0, hashData.Length); } } } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs new file mode 100644 index 00000000..6cb67460 --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs @@ -0,0 +1,36 @@ +using Renci.SshNet.Abstractions; + +namespace Renci.SshNet.Security +{ + /// + /// Base class for "diffie-hellman" SHA-256 group algorithm implementations. + /// + internal abstract class KeyExchangeDiffieHellmanGroupSha256 : KeyExchangeDiffieHellmanGroupShaBase + { + /// + /// Gets the size, in bits, of the computed hash code. + /// + /// + /// The size, in bits, of the computed hash code. + /// + protected override int HashSize + { + get { return 256; } + } + + /// + /// Hashes the specified data bytes. + /// + /// The hash data. + /// + /// Hashed bytes + /// + protected override byte[] Hash(byte[] hashData) + { + using (var sha256 = CryptoAbstraction.CreateSHA256()) + { + return sha256.ComputeHash(hashData); + } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs new file mode 100644 index 00000000..54369b84 --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs @@ -0,0 +1,36 @@ +using Renci.SshNet.Abstractions; + +namespace Renci.SshNet.Security +{ + /// + /// Base class for "diffie-hellman" SHA-512 group algorithm implementations. + /// + internal abstract class KeyExchangeDiffieHellmanGroupSha512 : KeyExchangeDiffieHellmanGroupShaBase + { + /// + /// Gets the size, in bits, of the computed hash code. + /// + /// + /// The size, in bits, of the computed hash code. + /// + protected override int HashSize + { + get { return 512; } + } + + /// + /// Hashes the specified data bytes. + /// + /// The hash data. + /// + /// Hashed bytes + /// + protected override byte[] Hash(byte[] hashData) + { + using (var sha512 = CryptoAbstraction.CreateSHA512()) + { + return sha512.ComputeHash(hashData); + } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs new file mode 100644 index 00000000..2618b63a --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs @@ -0,0 +1,83 @@ +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Security +{ + internal abstract class KeyExchangeDiffieHellmanGroupShaBase : KeyExchangeDiffieHellman + { + /// + /// Gets the group prime. + /// + /// + /// The group prime. + /// + public abstract BigInteger GroupPrime { get; } + + /// + /// Calculates key exchange hash value. + /// + /// + /// Key exchange hash. + /// + protected override byte[] CalculateHash() + { + var keyExchangeHashData = new KeyExchangeHashData + { + ClientVersion = Session.ClientVersion, + ServerVersion = Session.ServerVersion, + ClientPayload = _clientPayload, + ServerPayload = _serverPayload, + HostKey = _hostKey, + ClientExchangeValue = _clientExchangeValue, + ServerExchangeValue = _serverExchangeValue, + SharedKey = SharedKey, + }; + + return Hash(keyExchangeHashData.GetBytes()); + } + + /// + /// Starts key exchange algorithm + /// + /// The session. + /// Key exchange init message. + public override void Start(Session session, KeyExchangeInitMessage message) + { + base.Start(session, message); + + Session.RegisterMessage("SSH_MSG_KEXDH_REPLY"); + + Session.KeyExchangeDhReplyMessageReceived += Session_KeyExchangeDhReplyMessageReceived; + + _prime = GroupPrime; + _group = new BigInteger(new byte[] { 2 }); + + PopulateClientExchangeValue(); + + SendMessage(new KeyExchangeDhInitMessage(_clientExchangeValue)); + } + + /// + /// Finishes key exchange algorithm. + /// + public override void Finish() + { + base.Finish(); + + Session.KeyExchangeDhReplyMessageReceived -= Session_KeyExchangeDhReplyMessageReceived; + } + + private void Session_KeyExchangeDhReplyMessageReceived(object sender, MessageEventArgs e) + { + var message = e.Message; + + // Unregister message once received + Session.UnRegisterMessage("SSH_MSG_KEXDH_REPLY"); + + HandleServerDhReply(message.HostKey, message.F, message.Signature); + + // When SSH_MSG_KEXDH_REPLY received key exchange is completed + Finish(); + } + } +} diff --git a/src/Renci.SshNet/Security/KeyExchangeEC.cs b/src/Renci.SshNet/Security/KeyExchangeEC.cs new file mode 100644 index 00000000..79cdf5be --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeEC.cs @@ -0,0 +1,106 @@ +using System.Text; +using Renci.SshNet.Messages.Transport; +using Renci.SshNet.Common; + +namespace Renci.SshNet.Security +{ + internal abstract class KeyExchangeEC : KeyExchange + { + /// + /// Specifies client payload + /// + protected byte[] _clientPayload; + + /// + /// Specifies server payload + /// + protected byte[] _serverPayload; + + /// + /// Specifies client exchange. + /// + protected byte[] _clientExchangeValue; + + /// + /// Specifies server exchange. + /// + protected byte[] _serverExchangeValue; + + /// + /// Specifies host key data. + /// + protected byte[] _hostKey; + + /// + /// Specifies signature data. + /// + protected byte[] _signature; + + /// + /// Gets the size, in bits, of the computed hash code. + /// + /// + /// The size, in bits, of the computed hash code. + /// + protected abstract int HashSize { get; } + + /// + /// Calculates key exchange hash value. + /// + /// + /// Key exchange hash. + /// + protected override byte[] CalculateHash() + { + var hashData = new KeyExchangeHashData + { + ClientVersion = Session.ClientVersion, + ServerVersion = Session.ServerVersion, + ClientPayload = _clientPayload, + ServerPayload = _serverPayload, + HostKey = _hostKey, + ClientExchangeValue = _clientExchangeValue, + ServerExchangeValue = _serverExchangeValue, + SharedKey = SharedKey, + }; + + return Hash(hashData.GetBytes()); + } + + /// + /// Validates the exchange hash. + /// + /// + /// true if exchange hash is valid; otherwise false. + /// + protected override bool ValidateExchangeHash() + { + var exchangeHash = CalculateHash(); + + var length = Pack.BigEndianToUInt32(_hostKey); + var algorithmName = Encoding.UTF8.GetString(_hostKey, 4, (int)length); + var key = Session.ConnectionInfo.HostKeyAlgorithms[algorithmName](_hostKey); + + Session.ConnectionInfo.CurrentHostKeyAlgorithm = algorithmName; + + if (CanTrustHostKey(key)) + { + return key.VerifySignature(exchangeHash, _signature); + } + return false; + } + + /// + /// Starts key exchange algorithm + /// + /// The session. + /// Key exchange init message. + public override void Start(Session session, KeyExchangeInitMessage message) + { + base.Start(session, message); + + _serverPayload = message.GetBytes(); + _clientPayload = Session.ClientInitMessage.GetBytes(); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs new file mode 100644 index 00000000..9de7af8f --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs @@ -0,0 +1,114 @@ +using System; +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; +using Renci.SshNet.Security.Chaos.NaCl; +using Renci.SshNet.Security.Chaos.NaCl.Internal.Ed25519Ref10; + +namespace Renci.SshNet.Security +{ + internal class KeyExchangeECCurve25519 : KeyExchangeEC + { + private byte[] _privateKey; + + /// + /// Gets algorithm name. + /// + public override string Name + { + get { return "curve25519-sha256"; } + } + + /// + /// Gets the size, in bits, of the computed hash code. + /// + /// + /// The size, in bits, of the computed hash code. + /// + protected override int HashSize + { + get { return 256; } + } + + /// + /// Starts key exchange algorithm + /// + /// The session. + /// Key exchange init message. + public override void Start(Session session, KeyExchangeInitMessage message) + { + base.Start(session, message); + + Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); + + Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived; + + var basepoint = new byte[MontgomeryCurve25519.PublicKeySizeInBytes]; + basepoint[0] = 9; + + var rnd = new Random(); + _privateKey = new byte[MontgomeryCurve25519.PrivateKeySizeInBytes]; + rnd.NextBytes(_privateKey); + + _clientExchangeValue = new byte[MontgomeryCurve25519.PublicKeySizeInBytes]; + MontgomeryOperations.scalarmult(_clientExchangeValue, 0, _privateKey, 0, basepoint, 0); + + SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue)); + } + + /// + /// Finishes key exchange algorithm. + /// + public override void Finish() + { + base.Finish(); + + Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived; + } + + /// + /// Hashes the specified data bytes. + /// + /// The hash data. + /// + /// Hashed bytes + /// + protected override byte[] Hash(byte[] hashData) + { + using (var sha256 = CryptoAbstraction.CreateSHA256()) + { + return sha256.ComputeHash(hashData, 0, hashData.Length); + } + } + + private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs e) + { + var message = e.Message; + + // Unregister message once received + Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); + + HandleServerEcdhReply(message.KS, message.QS, message.Signature); + + // When SSH_MSG_KEXDH_REPLY received key exchange is completed + Finish(); + } + + /// + /// Handles the server DH reply message. + /// + /// The host key. + /// The server exchange value. + /// The signature. + private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature) + { + _serverExchangeValue = serverExchangeValue; + _hostKey = hostKey; + _signature = signature; + + var sharedKey = new byte[MontgomeryCurve25519.PublicKeySizeInBytes]; + MontgomeryOperations.scalarmult(sharedKey, 0, _privateKey, 0, serverExchangeValue, 0); + SharedKey = sharedKey.ToBigInteger2().ToByteArray().Reverse(); + } + } +} diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH.cs b/src/Renci.SshNet/Security/KeyExchangeECDH.cs new file mode 100644 index 00000000..f87a5c7e --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeECDH.cs @@ -0,0 +1,106 @@ +using System; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; + +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Generators; +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters; +using Renci.SshNet.Security.Org.BouncyCastle.Security; +using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9; +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Agreement; + +namespace Renci.SshNet.Security +{ + internal abstract class KeyExchangeECDH : KeyExchangeEC + { + /// + /// Gets the parameter of the curve. + /// + /// + /// The parameter of the curve. + /// + protected abstract X9ECParameters CurveParameter { get; } + + protected ECDHCBasicAgreement KeyAgreement; + protected ECDomainParameters DomainParameters; + + /// + /// Starts key exchange algorithm + /// + /// The session. + /// Key exchange init message. + public override void Start(Session session, KeyExchangeInitMessage message) + { + base.Start(session, message); + + Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); + + Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived; + + DomainParameters = new ECDomainParameters(CurveParameter.Curve, + CurveParameter.G, + CurveParameter.N, + CurveParameter.H, + CurveParameter.GetSeed()); + + var g = new ECKeyPairGenerator(); + g.Init(new ECKeyGenerationParameters(DomainParameters, new SecureRandom())); + + var aKeyPair = g.GenerateKeyPair(); + KeyAgreement = new ECDHCBasicAgreement(); + KeyAgreement.Init(aKeyPair.Private); + _clientExchangeValue = ((ECPublicKeyParameters)aKeyPair.Public).Q.GetEncoded(); + + SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue)); + } + + /// + /// Finishes key exchange algorithm. + /// + public override void Finish() + { + base.Finish(); + + Session.KeyExchangeEcdhReplyMessageReceived -= Session_KeyExchangeEcdhReplyMessageReceived; + } + + private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageEventArgs e) + { + var message = e.Message; + + // Unregister message once received + Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); + + HandleServerEcdhReply(message.KS, message.QS, message.Signature); + + // When SSH_MSG_KEXDH_REPLY received key exchange is completed + Finish(); + } + + /// + /// Handles the server DH reply message. + /// + /// The host key. + /// The server exchange value. + /// The signature. + private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, byte[] signature) + { + _serverExchangeValue = serverExchangeValue; + _hostKey = hostKey; + _signature = signature; + + var cordSize = (serverExchangeValue.Length - 1) / 2; + var x = new byte[cordSize]; + Buffer.BlockCopy(serverExchangeValue, 1, x, 0, x.Length); // first byte is format. should be checked and passed to bouncy castle? + var y = new byte[cordSize]; + Buffer.BlockCopy(serverExchangeValue, cordSize + 1, y, 0, y.Length); + + var c = (FpCurve)DomainParameters.Curve; + var q = c.CreatePoint(new Org.BouncyCastle.Math.BigInteger(1, x), new Org.BouncyCastle.Math.BigInteger(1, y)); + var publicKey = new ECPublicKeyParameters("ECDH", q, DomainParameters); + + var k1 = KeyAgreement.CalculateAgreement(publicKey); + SharedKey = k1.ToByteArray().ToBigInteger2().ToByteArray().Reverse(); + } + } +} diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH256.cs b/src/Renci.SshNet/Security/KeyExchangeECDH256.cs new file mode 100644 index 00000000..8f14d9bd --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeECDH256.cs @@ -0,0 +1,54 @@ +using Renci.SshNet.Abstractions; +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.Sec; +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9; + +namespace Renci.SshNet.Security +{ + internal class KeyExchangeECDH256 : KeyExchangeECDH + { + /// + /// Gets algorithm name. + /// + public override string Name + { + get { return "ecdh-sha2-nistp256"; } + } + + /// + /// Gets Curve Parameter. + /// + protected override X9ECParameters CurveParameter + { + get + { + return SecNamedCurves.GetByName("P-256"); + } + } + + /// + /// Gets the size, in bits, of the computed hash code. + /// + /// + /// The size, in bits, of the computed hash code. + /// + protected override int HashSize + { + get { return 256; } + } + + /// + /// Hashes the specified data bytes. + /// + /// The hash data. + /// + /// Hashed bytes + /// + protected override byte[] Hash(byte[] hashData) + { + using (var sha256 = CryptoAbstraction.CreateSHA256()) + { + return sha256.ComputeHash(hashData, 0, hashData.Length); + } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH384.cs b/src/Renci.SshNet/Security/KeyExchangeECDH384.cs new file mode 100644 index 00000000..bbd7ced5 --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeECDH384.cs @@ -0,0 +1,54 @@ +using Renci.SshNet.Abstractions; +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.Sec; +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9; + +namespace Renci.SshNet.Security +{ + internal class KeyExchangeECDH384 : KeyExchangeECDH + { + /// + /// Gets algorithm name. + /// + public override string Name + { + get { return "ecdh-sha2-nistp384"; } + } + + /// + /// Gets Curve Parameter. + /// + protected override X9ECParameters CurveParameter + { + get + { + return SecNamedCurves.GetByName("P-384"); + } + } + + /// + /// Gets the size, in bits, of the computed hash code. + /// + /// + /// The size, in bits, of the computed hash code. + /// + protected override int HashSize + { + get { return 384; } + } + + /// + /// Hashes the specified data bytes. + /// + /// The hash data. + /// + /// Hashed bytes + /// + protected override byte[] Hash(byte[] hashData) + { + using (var sha384 = CryptoAbstraction.CreateSHA384()) + { + return sha384.ComputeHash(hashData, 0, hashData.Length); + } + } + } +} diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH521.cs b/src/Renci.SshNet/Security/KeyExchangeECDH521.cs new file mode 100644 index 00000000..920089c0 --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeECDH521.cs @@ -0,0 +1,54 @@ +using Renci.SshNet.Abstractions; +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.Sec; +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9; + +namespace Renci.SshNet.Security +{ + internal class KeyExchangeECDH521 : KeyExchangeECDH + { + /// + /// Gets algorithm name. + /// + public override string Name + { + get { return "ecdh-sha2-nistp521"; } + } + + /// + /// Gets Curve Parameter. + /// + protected override X9ECParameters CurveParameter + { + get + { + return SecNamedCurves.GetByName("P-521"); + } + } + + /// + /// Gets the size, in bits, of the computed hash code. + /// + /// + /// The size, in bits, of the computed hash code. + /// + protected override int HashSize + { + get { return 512; } + } + + /// + /// Hashes the specified data bytes. + /// + /// The hash data. + /// + /// Hashed bytes + /// + protected override byte[] Hash(byte[] hashData) + { + using (var sha512 = CryptoAbstraction.CreateSHA512()) + { + return sha512.ComputeHash(hashData, 0, hashData.Length); + } + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/KeyExchangeHash.cs b/src/Renci.SshNet/Security/KeyExchangeHash.cs new file mode 100644 index 00000000..e33cb14c --- /dev/null +++ b/src/Renci.SshNet/Security/KeyExchangeHash.cs @@ -0,0 +1,83 @@ +using Renci.SshNet.Common; +using System; + +namespace Renci.SshNet.Security +{ + internal class KeyExchangeHashData : SshData + { + private byte[] _serverVersion; + private byte[] _clientVersion; + + public string ServerVersion + { + private get { return Utf8.GetString(_serverVersion, 0, _serverVersion.Length); } + set { _serverVersion = Utf8.GetBytes(value); } + } + + public string ClientVersion + { + private get { return Utf8.GetString(_clientVersion, 0, _clientVersion.Length); } + set { _clientVersion = Utf8.GetBytes(value); } + } + + public byte[] ClientPayload { get; set; } + + public byte[] ServerPayload { get; set; } + + public byte[] HostKey { get; set; } + + public byte[] ClientExchangeValue { get; set; } + + public byte[] ServerExchangeValue { get; set; } + + public byte[] SharedKey { get; set; } + + /// + /// Gets the size of the message in bytes. + /// + /// + /// The size of the messages in bytes. + /// + protected override int BufferCapacity + { + get + { + var capacity = base.BufferCapacity; + capacity += 4; // ClientVersion length + capacity += _clientVersion.Length; // ClientVersion + capacity += 4; // ServerVersion length + capacity += _serverVersion.Length; // ServerVersion + capacity += 4; // ClientPayload length + capacity += ClientPayload.Length; // ClientPayload + capacity += 4; // ServerPayload length + capacity += ServerPayload.Length; // ServerPayload + capacity += 4; // HostKey length + capacity += HostKey.Length; // HostKey + capacity += 4; // ClientExchangeValue length + capacity += ClientExchangeValue.Length; // ClientExchangeValue + capacity += 4; // ServerExchangeValue length + capacity += ServerExchangeValue.Length; // ServerExchangeValue + capacity += 4; // SharedKey length + capacity += SharedKey.Length; // SharedKey + return capacity; + } + } + + protected override void LoadData() + { + throw new NotImplementedException(); + } + + protected override void SaveData() + { + WriteBinaryString(_clientVersion); + WriteBinaryString(_serverVersion); + WriteBinaryString(ClientPayload); + WriteBinaryString(ServerPayload); + WriteBinaryString(HostKey); + WriteBinaryString(ClientExchangeValue); + WriteBinaryString(ServerExchangeValue); + WriteBinaryString(SharedKey); + } + } +} diff --git a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs index 619bfc92..ca94fa70 100644 --- a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs +++ b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs @@ -82,7 +82,7 @@ namespace Renci.SshNet.Security private class SshKeyData : SshData { private byte[] _name; - private IList _keys; + private List _keys; public BigInteger[] Keys { @@ -92,7 +92,7 @@ namespace Renci.SshNet.Security for (var i = 0; i < _keys.Count; i++) { var key = _keys[i]; - keys[i] = key.ToBigInteger(); + keys[i] = key.ToBigInteger2(); } return keys; } diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 1f5f4eb2..9edcb687 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -34,7 +34,7 @@ namespace Renci.SshNet /// Specifies an infinite waiting period. /// /// - /// The value of this field is -1 millisecond. + /// The value of this field is -1 millisecond. /// internal static readonly TimeSpan InfiniteTimeSpan = new TimeSpan(0, 0, 0, 0, -1); @@ -268,7 +268,7 @@ namespace Renci.SshNet /// The is disposed. /// /// - /// The SSH_MSG_DISCONNECT message - which is used to disconnect from the server - has been sent. + /// The SSH_MSG_DISCONNECT message - which is used to disconnect from the server - has been sent. /// /// /// The client has not been authenticated successfully. @@ -439,6 +439,11 @@ namespace Renci.SshNet /// internal event EventHandler> KeyExchangeDhReplyMessageReceived; + /// + /// Occurs when a message is received from the SSH server. + /// + internal event EventHandler> KeyExchangeEcdhReplyMessageReceived; + /// /// Occurs when message received /// @@ -798,6 +803,82 @@ namespace Renci.SshNet WaitOnHandle(waitHandle, ConnectionInfo.Timeout); } + /// + /// Waits for the specified to receive a signal, using a + /// to specify the time interval. + /// + /// The that should be signaled. + /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. + /// + /// A . + /// + WaitResult ISession.TryWait(WaitHandle waitHandle, TimeSpan timeout) + { + Exception exception; + return TryWait(waitHandle, timeout, out exception); + } + + /// + /// Waits for the specified to receive a signal, using a + /// to specify the time interval. + /// + /// The that should be signaled. + /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. + /// When this method returns , contains the . + /// + /// A . + /// + WaitResult ISession.TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exception exception) + { + return TryWait(waitHandle, timeout, out exception); + } + + /// + /// Waits for the specified to receive a signal, using a + /// to specify the time interval. + /// + /// The that should be signaled. + /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. + /// When this method returns , contains the . + /// + /// A . + /// + private WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exception exception) + { + if (waitHandle == null) + throw new ArgumentNullException("waitHandle"); + + var waitHandles = new[] + { + _exceptionWaitHandle, + _messageListenerCompleted, + waitHandle + }; + + switch (WaitHandle.WaitAny(waitHandles, timeout)) + { + case 0: + if (_exception is SshConnectionException) + { + exception = null; + return WaitResult.Disconnected; + } + exception = _exception; + return WaitResult.Failed; + case 1: + exception = null; + return WaitResult.Disconnected; + case 2: + exception = null; + return WaitResult.Success; + case WaitHandle.WaitTimeout: + exception = null; + return WaitResult.TimedOut; + default: + throw new InvalidOperationException("Unexpected result."); + } + } + /// /// Waits for the specified handle or the exception handle for the receive thread /// to signal within the specified timeout. @@ -878,7 +959,7 @@ namespace Renci.SshNet hash = _clientMac.ComputeHash(packetData); } - // Encrypt packet data + // Encrypt packet data if (_clientCipher != null) { packetData = _clientCipher.Encrypt(packetData, packetDataOffset, (packetData.Length - packetDataOffset)); @@ -1077,7 +1158,7 @@ namespace Renci.SshNet var serverHash = data.Take(data.Length - serverMacLength, serverMacLength); // TODO add IsEqualTo overload that takes left+right index and number of bytes to compare; - // TODO that way we can eliminate the extrate allocation of the Take above + // TODO that way we can eliminate the extra allocation of the Take above if (!serverHash.IsEqualTo(clientHash)) { throw new SshConnectionException("MAC error", DisconnectReason.MacError); @@ -1110,7 +1191,7 @@ namespace Renci.SshNet _isDisconnectMessageSent = true; } -#region Handle received message events + #region Handle received message events /// /// Called when received. @@ -1225,7 +1306,7 @@ namespace Renci.SshNet _sshMessageFactory.DisableNonKeyExchangeMessages(); _keyExchange = _serviceFactory.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, - message.KeyExchangeAlgorithms); + message.KeyExchangeAlgorithms); ConnectionInfo.CurrentKeyExchangeAlgorithm = _keyExchange.Name; @@ -1246,6 +1327,13 @@ namespace Renci.SshNet handlers(this, new MessageEventArgs(message)); } + internal void OnKeyExchangeEcdhReplyMessageReceived(KeyExchangeEcdhReplyMessage message) + { + var handlers = KeyExchangeEcdhReplyMessageReceived; + if (handlers != null) + handlers(this, new MessageEventArgs(message)); + } + /// /// Called when message received. /// @@ -1532,7 +1620,7 @@ namespace Renci.SshNet handlers(this, new MessageEventArgs(message)); } -#endregion + #endregion private void KeyExchange_HostKeyReceived(object sender, HostKeyEventArgs e) { @@ -1541,7 +1629,7 @@ namespace Renci.SshNet handlers(this, e); } -#region Message loading functions + #region Message loading functions /// /// Registers SSH message with the session. @@ -1606,7 +1694,7 @@ namespace Renci.SshNet return ToHex(bytes, 0); } -#endregion + #endregion /// /// Establishes a socket connection to the specified host and port. @@ -1650,7 +1738,7 @@ namespace Renci.SshNet // SshConnectionException will interrupt the message listener loop (if not already interrupted) // and the exception itself will be ignored (in RaiseError) throw new SshConnectionException("An established connection was aborted by the server.", - DisconnectReason.ConnectionLost); + DisconnectReason.ConnectionLost); } return bytesRead; } @@ -1832,16 +1920,23 @@ namespace Renci.SshNet /// private void MessageListener() { -#if FEATURE_SOCKET_SELECT - var readSockets = new List { _socket }; -#endif // FEATURE_SOCKET_SELECT - try { // remain in message loop until socket is shut down or until we're disconnecting while (_socket.IsConnected()) { -#if FEATURE_SOCKET_SELECT +#if FEATURE_SOCKET_POLL + // Block until either data is available or the socket is closed + var connectionClosedOrDataAvailable = _socket.Poll(-1, SelectMode.SelectRead); + if (connectionClosedOrDataAvailable && _socket.Available == 0) + { + // connection with SSH server was closed or socket was disposed; + // break out of the message loop + break; + } +#elif FEATURE_SOCKET_SELECT + var readSockets = new List { _socket }; + // if the socket is already disposed when Select is invoked, then a SocketException // stating "An operation was attempted on something that is not a socket" is thrown; // we attempt to avoid this exception by having an IsConnected() that can break the @@ -1875,18 +1970,9 @@ namespace Renci.SshNet // break out of the message loop break; } -#elif FEATURE_SOCKET_POLL - // when Socket.Select(IList, IList, IList, Int32) is not available or is buggy, we use - // Socket.Poll(Int, SelectMode) to block until either data is available or the socket - // is closed - _socket.Poll(-1, SelectMode.SelectRead); - - if (!_socket.IsConnected()) - { - // connection with SSH server was closed or socket was disposed; - // break out of the message loop - break; - } +#else + #error Blocking wait on either socket data to become available or connection to be + #error closed is not implemented. #endif // FEATURE_SOCKET_SELECT var message = ReceiveMessage(); @@ -1926,33 +2012,12 @@ namespace Renci.SshNet return buffer[0]; } - private void SocketWriteByte(byte data) - { - SocketAbstraction.Send(_socket, new[] {data}); - } - private void ConnectSocks4() { - // Send socks version number - SocketWriteByte(0x04); + var connectionRequest = CreateSocks4ConnectionRequest(ConnectionInfo.Host, (ushort) ConnectionInfo.Port, ConnectionInfo.ProxyUsername); + SocketAbstraction.Send(_socket, connectionRequest); - // Send command code - SocketWriteByte(0x01); - - // Send port - SocketWriteByte((byte)(ConnectionInfo.Port / 0xFF)); - SocketWriteByte((byte)(ConnectionInfo.Port % 0xFF)); - - // Send IP - var ipAddress = DnsAbstraction.GetHostAddresses(ConnectionInfo.Host)[0]; - SocketAbstraction.Send(_socket, ipAddress.GetAddressBytes()); - - // Send username - var username = SshData.Ascii.GetBytes(ConnectionInfo.ProxyUsername); - SocketAbstraction.Send(_socket, username); - SocketWriteByte(0x00); - - // Read 0 + // Read null byte if (SocketReadByte() != 0) { throw new ProxyException("SOCKS4: Null is expected."); @@ -1981,15 +2046,18 @@ namespace Renci.SshNet private void ConnectSocks5() { - // Send socks version number - SocketWriteByte(0x05); - - // Send number of supported authentication methods - SocketWriteByte(0x02); - - // Send supported authentication methods - SocketWriteByte(0x00); // No authentication - SocketWriteByte(0x02); // Username/Password + var greeting = new byte[] + { + // SOCKS version number + 0x05, + // Number of supported authentication methods + 0x02, + // No authentication + 0x00, + // Username/Password authentication + 0x02 + }; + SocketAbstraction.Send(_socket, greeting); var socksVersion = SocketReadByte(); if (socksVersion != 0x05) @@ -2001,78 +2069,24 @@ namespace Renci.SshNet case 0x00: break; case 0x02: + // Create username/password authentication request + var authenticationRequest = CreateSocks5UserNameAndPasswordAuthenticationRequest(ConnectionInfo.ProxyUsername, ConnectionInfo.ProxyPassword); + // Send authentication request + SocketAbstraction.Send(_socket, authenticationRequest); + // Read authentication result + var authenticationResult = SocketAbstraction.Read(_socket, 2, ConnectionInfo.Timeout); - // Send version - SocketWriteByte(0x01); - - var username = SshData.Ascii.GetBytes(ConnectionInfo.ProxyUsername); - - if (username.Length > byte.MaxValue) - throw new ProxyException("Proxy username is too long."); - - // Send username length - SocketWriteByte((byte)username.Length); - - // Send username - SocketAbstraction.Send(_socket, username); - - var password = SshData.Ascii.GetBytes(ConnectionInfo.ProxyPassword); - - if (password.Length > byte.MaxValue) - throw new ProxyException("Proxy password is too long."); - - // Send username length - SocketWriteByte((byte)password.Length); - - // Send username - SocketAbstraction.Send(_socket, password); - - var serverVersion = SocketReadByte(); - - if (serverVersion != 1) + if (authenticationResult[0] != 0x01) throw new ProxyException("SOCKS5: Server authentication version is not valid."); - - var statusCode = SocketReadByte(); - if (statusCode != 0) + if (authenticationResult[1] != 0x00) throw new ProxyException("SOCKS5: Username/Password authentication failed."); - break; case 0xFF: throw new ProxyException("SOCKS5: No acceptable authentication methods were offered."); } - // Send socks version number - SocketWriteByte(0x05); - - // Send command code - SocketWriteByte(0x01); // establish a TCP/IP stream connection - - // Send reserved, must be 0x00 - SocketWriteByte(0x00); - - var ip = DnsAbstraction.GetHostAddresses(ConnectionInfo.Host)[0]; - - // Send address type and address - if (ip.AddressFamily == AddressFamily.InterNetwork) - { - SocketWriteByte(0x01); - var address = ip.GetAddressBytes(); - SocketAbstraction.Send(_socket, address); - } - else if (ip.AddressFamily == AddressFamily.InterNetworkV6) - { - SocketWriteByte(0x04); - var address = ip.GetAddressBytes(); - SocketAbstraction.Send(_socket, address); - } - else - { - throw new ProxyException(string.Format("SOCKS5: IP address '{0}' is not supported.", ip)); - } - - // Send port - SocketWriteByte((byte)(ConnectionInfo.Port / 0xFF)); - SocketWriteByte((byte)(ConnectionInfo.Port % 0xFF)); + var connectionRequest = CreateSocks5ConnectionRequest(ConnectionInfo.Host, (ushort) ConnectionInfo.Port); + SocketAbstraction.Send(_socket, connectionRequest); // Read Server SOCKS5 version if (SocketReadByte() != 5) @@ -2107,22 +2121,22 @@ namespace Renci.SshNet throw new ProxyException("SOCKS5: Not valid response."); } - // Read 0 + // Read reserved byte if (SocketReadByte() != 0) { throw new ProxyException("SOCKS5: 0 byte is expected."); } var addressType = SocketReadByte(); - var responseIp = new byte[16]; - switch (addressType) { case 0x01: - SocketRead(responseIp, 0, 4); + var ipv4 = new byte[4]; + SocketRead(ipv4, 0, 4); break; case 0x04: - SocketRead(responseIp, 0, 16); + var ipv6 = new byte[16]; + SocketRead(ipv6, 0, 16); break; default: throw new ProxyException(string.Format("Address type '{0}' is not supported.", addressType)); @@ -2134,6 +2148,174 @@ namespace Renci.SshNet SocketRead(port, 0, 2); } + /// + /// https://tools.ietf.org/html/rfc1929 + /// + private static byte[] CreateSocks5UserNameAndPasswordAuthenticationRequest(string username, string password) + { + if (username.Length > byte.MaxValue) + throw new ProxyException("Proxy username is too long."); + if (password.Length > byte.MaxValue) + throw new ProxyException("Proxy password is too long."); + + var authenticationRequest = new byte + [ + // Version of the negotiation + 1 + + // Length of the username + 1 + + // Username + username.Length + + // Length of the password + 1 + + // Password + password.Length + ]; + + var index = 0; + + // Version of the negiotiation + authenticationRequest[index++] = 0x01; + + // Length of the username + authenticationRequest[index++] = (byte) username.Length; + + // Username + SshData.Ascii.GetBytes(username, 0, username.Length, authenticationRequest, index); + index += username.Length; + + // Length of the password + authenticationRequest[index++] = (byte) password.Length; + + // Password + SshData.Ascii.GetBytes(password, 0, password.Length, authenticationRequest, index); + + return authenticationRequest; + } + + private static byte[] CreateSocks4ConnectionRequest(string hostname, ushort port, string username) + { + var addressBytes = GetSocks4DestinationAddress(hostname); + + var connectionRequest = new byte + [ + // SOCKS version number + 1 + + // Command code + 1 + + // Port number + 2 + + // IP address + addressBytes.Length + + // Username + username.Length + + // Null terminator + 1 + ]; + + var index = 0; + + // SOCKS version number + connectionRequest[index++] = 0x04; + + // Command code + connectionRequest[index++] = 0x01; // establish a TCP/IP stream connection + + // Port number + Pack.UInt16ToBigEndian(port, connectionRequest, index); + index += 2; + + // Address + Buffer.BlockCopy(addressBytes, 0, connectionRequest, index, addressBytes.Length); + index += addressBytes.Length; + + connectionRequest[index] = 0x00; + + return connectionRequest; + } + + private static byte[] CreateSocks5ConnectionRequest(string hostname, ushort port) + { + byte addressType; + var addressBytes = GetSocks5DestinationAddress(hostname, out addressType); + + var connectionRequest = new byte + [ + // SOCKS version number + 1 + + // Command code + 1 + + // Reserved + 1 + + // Address type + 1 + + // Address + addressBytes.Length + + // Port number + 2 + ]; + + var index = 0; + + // SOCKS version number + connectionRequest[index++] = 0x05; + + // Command code + connectionRequest[index++] = 0x01; // establish a TCP/IP stream connection + + // Reserved + connectionRequest[index++] = 0x00; + + // Address type + connectionRequest[index++] = addressType; + + // Address + Buffer.BlockCopy(addressBytes, 0, connectionRequest, index, addressBytes.Length); + index += addressBytes.Length; + + // Port number + Pack.UInt16ToBigEndian(port, connectionRequest, index); + + return connectionRequest; + } + + private static byte[] GetSocks4DestinationAddress(string hostname) + { + var addresses = DnsAbstraction.GetHostAddresses(hostname); + + for (var i = 0; i < addresses.Length; i++) + { + var address = addresses[i]; + if (address.AddressFamily == AddressFamily.InterNetwork) + return address.GetAddressBytes(); + } + + throw new ProxyException(string.Format("SOCKS4 only supports IPv4. No such address found for '{0}'.", hostname)); + } + + private static byte[] GetSocks5DestinationAddress(string hostname, out byte addressType) + { + var ip = DnsAbstraction.GetHostAddresses(hostname)[0]; + + byte[] address; + + switch (ip.AddressFamily) + { + case AddressFamily.InterNetwork: + addressType = 0x01; // IPv4 + address = ip.GetAddressBytes(); + break; + case AddressFamily.InterNetworkV6: + addressType = 0x04; // IPv6 + address = ip.GetAddressBytes(); + break; + default: + throw new ProxyException(string.Format("SOCKS5: IP address '{0}' is not supported.", ip)); + } + + return address; + } + private void ConnectHttp() { var httpResponseRe = new Regex(@"HTTP/(?\d[.]\d) (?\d{3}) (?.+)$"); @@ -2272,7 +2454,7 @@ namespace Renci.SshNet private static SshConnectionException CreateConnectionAbortedByServerException() { return new SshConnectionException("An established connection was aborted by the server.", - DisconnectReason.ConnectionLost); + DisconnectReason.ConnectionLost); } #region IDisposable implementation @@ -2412,8 +2594,9 @@ namespace Renci.SshNet /// /// A new "forwarded-tcpip" SSH channel. /// - IChannelForwardedTcpip ISession.CreateChannelForwardedTcpip(uint remoteChannelNumber, uint remoteWindowSize, - uint remoteChannelDataPacketSize) + IChannelForwardedTcpip ISession.CreateChannelForwardedTcpip(uint remoteChannelNumber, + uint remoteWindowSize, + uint remoteChannelDataPacketSize) { return new ChannelForwardedTcpip(this, NextChannelNumber, @@ -2455,4 +2638,30 @@ namespace Renci.SshNet #endregion ISession implementation } + + /// + /// Represents the result of a wait operations. + /// + internal enum WaitResult + { + /// + /// The was signaled within the specified interval. + /// + Success = 1, + + /// + /// The was not signaled within the specified interval. + /// + TimedOut = 2, + + /// + /// The session is in a disconnected state. + /// + Disconnected = 3, + + /// + /// The session is in a failed state. + /// + Failed = 4 + } } \ No newline at end of file diff --git a/src/Renci.SshNet/Sftp/ISftpFileReader.cs b/src/Renci.SshNet/Sftp/ISftpFileReader.cs index bab6151c..684cc418 100644 --- a/src/Renci.SshNet/Sftp/ISftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/ISftpFileReader.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace Renci.SshNet.Sftp { diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 6403ce88..5a099300 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -44,6 +44,7 @@ namespace Renci.SshNet /// one (-1) milliseconds, which indicates an infinite timeout period. /// /// The method was called after the client was disposed. + /// represents a value that is less than -1 or greater than milliseconds. public TimeSpan OperationTimeout { get @@ -58,7 +59,7 @@ namespace Renci.SshNet var timeoutInMilliseconds = value.TotalMilliseconds; if (timeoutInMilliseconds < -1d || timeoutInMilliseconds > int.MaxValue) - throw new ArgumentOutOfRangeException("timeout", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + throw new ArgumentOutOfRangeException("value", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); _operationTimeout = (int) timeoutInMilliseconds; } @@ -141,6 +142,17 @@ namespace Renci.SshNet } } + /// + /// Gets the current SFTP session. + /// + /// + /// The current SFTP session. + /// + internal ISftpSession SftpSession + { + get { return _sftpSession; } + } + #region Constructors /// @@ -2151,11 +2163,7 @@ namespace Renci.SshNet { base.OnConnected(); - _sftpSession = ServiceFactory.CreateSftpSession(Session, - _operationTimeout, - ConnectionInfo.Encoding, - ServiceFactory.CreateSftpResponseFactory()); - _sftpSession.Connect(); + _sftpSession = CreateAndConnectToSftpSession(); } /// @@ -2193,5 +2201,23 @@ namespace Renci.SshNet } } } + + private ISftpSession CreateAndConnectToSftpSession() + { + var sftpSession = ServiceFactory.CreateSftpSession(Session, + _operationTimeout, + ConnectionInfo.Encoding, + ServiceFactory.CreateSftpResponseFactory()); + try + { + sftpSession.Connect(); + return sftpSession; + } + catch + { + sftpSession.Dispose(); + throw; + } + } } } diff --git a/src/Renci.SshNet/Shell.cs b/src/Renci.SshNet/Shell.cs index e2e2b558..c508be89 100644 --- a/src/Renci.SshNet/Shell.cs +++ b/src/Renci.SshNet/Shell.cs @@ -135,7 +135,7 @@ namespace Renci.SshNet if (WaitHandle.WaitAny(new[] {readWaitHandle, _channelClosedWaitHandle}) == 0) { - var read = readTask.Result; + var read = readTask.GetAwaiter().GetResult(); _channel.SendData(buffer, 0, read); continue; } diff --git a/src/Renci.SshNet/ShellStream.cs b/src/Renci.SshNet/ShellStream.cs index 72ced02c..3274fe19 100644 --- a/src/Renci.SshNet/ShellStream.cs +++ b/src/Renci.SshNet/ShellStream.cs @@ -64,7 +64,6 @@ namespace Renci.SshNet get { return _bufferSize; } } - /// /// Initializes a new instance. /// @@ -76,6 +75,9 @@ namespace Renci.SshNet /// The terminal height in pixels. /// The terminal mode values. /// The size of the buffer. + /// The channel could not be opened. + /// The pseudo-terminal request was not accepted by the server. + /// The request to start a shell was not accepted by the server. internal ShellStream(ISession session, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModeValues, int bufferSize) { _encoding = session.ConnectionInfo.Encoding; @@ -90,9 +92,24 @@ namespace Renci.SshNet _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; - _channel.Open(); - _channel.SendPseudoTerminalRequest(terminalName, columns, rows, width, height, terminalModeValues); - _channel.SendShellRequest(); + try + { + _channel.Open(); + if (!_channel.SendPseudoTerminalRequest(terminalName, columns, rows, width, height, terminalModeValues)) + { + throw new SshException("The pseudo-terminal request was not accepted by the server. Consult the server log for more information."); + } + if (!_channel.SendShellRequest()) + { + throw new SshException("The request to start a shell was not accepted by the server. Consult the server log for more information."); + } + } + catch + { + UnsubscribeFromSessionEvents(session); + _channel.Dispose(); + throw; + } } #region Stream overide methods diff --git a/src/Renci.SshNet/SshMessageFactory.cs b/src/Renci.SshNet/SshMessageFactory.cs index 9041ea34..153024db 100644 --- a/src/Renci.SshNet/SshMessageFactory.cs +++ b/src/Renci.SshNet/SshMessageFactory.cs @@ -25,7 +25,7 @@ namespace Renci.SshNet /// /// Defines the total number of supported messages. /// - internal const int TotalMessageCount = 31; + internal const int TotalMessageCount = 32; static SshMessageFactory() { @@ -61,7 +61,8 @@ namespace Renci.SshNet new MessageMetadata (27, "SSH_MSG_SERVICE_ACCEPT", 6), new MessageMetadata (28, "SSH_MSG_KEX_DH_GEX_GROUP", 31), new MessageMetadata (29, "SSH_MSG_KEXDH_REPLY", 31), - new MessageMetadata (30, "SSH_MSG_KEX_DH_GEX_REPLY", 33) + new MessageMetadata (30, "SSH_MSG_KEX_DH_GEX_REPLY", 33), + new MessageMetadata (31, "SSH_MSG_KEX_ECDH_REPLY", 31) }; MessagesByName = new Dictionary(AllMessages.Length); diff --git a/src/Renci.SshNet/SubsystemSession.cs b/src/Renci.SshNet/SubsystemSession.cs index 4aa52d5c..943a2db9 100644 --- a/src/Renci.SshNet/SubsystemSession.cs +++ b/src/Renci.SshNet/SubsystemSession.cs @@ -95,6 +95,7 @@ namespace Renci.SshNet /// /// The session is already connected. /// The method was called after the session was disposed. + /// The channel session could not be opened, or the subsystem could not be executed. public void Connect() { EnsureNotDisposed(); @@ -116,7 +117,16 @@ namespace Renci.SshNet _channel.Exception += Channel_Exception; _channel.Closed += Channel_Closed; _channel.Open(); - _channel.SendSubsystemRequest(_subsystemName); + + if (!_channel.SendSubsystemRequest(_subsystemName)) + { + // close channel session + Disconnect(); + // signal subsystem failure + throw new SshException(string.Format(CultureInfo.InvariantCulture, + "Subsystem '{0}' could not be executed.", + _subsystemName)); + } OnChannelOpen(); }