diff --git a/README.md b/README.md index f63e1bb..c53b486 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,37 @@ # acryptohashnet -A pure C# implementation of well-known cryptographic hash functions for .Net Standard 2.0 compatible platforms (.Net Framework, .Net Core, Mono, Xamarin, UWP, Unity). +A pure C# implementation of cryptographic hash functions for .Net Standard 2.0 compatible platforms (.Net Framework, .Net Core, Mono, Xamarin, UWP, Unity). # Features - * Pure managed implementations, - * Compatible with System.Security.Cryptography.HashAlgorithm and can be used everywhere as a simple replacement of the target hash algorithm, - * Fast and has low memory footprint (less GC). + +* Pure managed C# implementation, +* Compatible with System.Security.Cryptography.HashAlgorithm and can be used everywhere as a simple drop replacement for the target hash algorithm, +* Extremely fast, highly optimized with low memory footprint (less GC time). # Usage examples -## MD5 of file +## MD5 + ``` csharp using System; -using System.IO; using System.Linq; +using System.Text; static class Program { - static void Main(string[] args) - { - var hashAlgorithm = new acryptohashnet.MD5(); - - using(var stream = File.OpenRead(@"C:\Windows\System32\explorer.exe")) + static void Main(string[] args) { - var hashBytes = hashAlgorithm.ComputeHash(stream); - Console.WriteLine("Hash: {0}", hashBytes.ToHexString()); + var message = "Test Message"; + + var hashAlgorithm = new acryptohashnet.MD5(); + Console.WriteLine("MD5: {0}", hashAlgorithm.ComputeHash(message.ToUtf8Bytes()).ToHexString()); } - } - static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); + static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); } ``` -## SHA512 of string +## SHA256 (SHA2-256 bits) ``` csharp using System; @@ -40,19 +40,77 @@ using System.Text; static class Program { - static void Main(string[] args) - { - var hashAlgorithm = new acryptohashnet.SHA512(); - var hashBytes = hashAlgorithm.ComputeHash("message digest".ToUtf8Bytes()); - Console.WriteLine("Hash: {0}", hashBytes.ToHexString()); - } - - static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); - static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); + static void Main(string[] args) + { + var message = "Test Message"; + + var hashAlgorithm = new acryptohashnet.Sha2_256(); + Console.WriteLine("SHA256: {0}", hashAlgorithm.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + } + + static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); +} +``` + +## Compute string message hash via HashAlgorithm interface (MD5, SHA1, SHA256, SHA3-512) + +``` csharp +static class Program +{ + static void Main(string[] args) + { + var md5 = new acryptohashnet.MD5(); + var sha1 = new acryptohashnet.SHA1(); + var sha2_256 = new acryptohashnet.Sha2_256(); + var sha3_512 = new acryptohashnet.Sha3_512(); + + var message = "Lorem ipsum is placeholder text commonly used in the graphic, " + + "print, and publishing industries for previewing layouts and visual mockups."; + + Console.WriteLine("MD5: {0}", md5.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + Console.WriteLine("SHA1: {0}", sha1.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + Console.WriteLine("SHA256: {0}", sha2_256.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + Console.WriteLine("SHA3-512: {0}", sha3_512.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + } + + static byte[] ToUtf8Bytes(this string input) => System.Text.Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); +} +``` + +## Compute hash of file via HashAlgorithm interface (MD5, SHA1, SHA256, SHA3-512) + +``` csharp +static class Program +{ + static void Main(string[] args) + { + var md5 = new acryptohashnet.MD5(); + var sha1 = new acryptohashnet.SHA1(); + var sha2_256 = new acryptohashnet.Sha2_256(); + var sha3_512 = new acryptohashnet.Sha3_512(); + + using (var file = File.OpenRead(@"C:\Windows\explorer.exe")) + { + Console.WriteLine("MD5: {0}", md5.ComputeHash(file).ToHexString()); + + file.Position = 0; // Rewind stream to beginning + Console.WriteLine("SHA1: {0}", sha1.ComputeHash(file).ToHexString()); + + file.Position = 0; // Rewind stream to beginning + Console.WriteLine("SHA256: {0}", sha2_256.ComputeHash(file).ToHexString()); + + file.Position = 0; // Rewind stream to beginning + Console.WriteLine("SHA3-512: {0}", sha3_512.ComputeHash(file).ToHexString()); + } + } + + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); } ``` -# Implemented hash functions +# Implemented hash algorithms ## MD Family All functions designed and specified by [Ron Rivest](https://en.wikipedia.org/wiki/Ron_Rivest). @@ -60,16 +118,30 @@ All functions designed and specified by [Ron Rivest](https://en.wikipedia.org/wi * MD4, specification: [RFC 1320](docs/rfc1320.txt). * MD5, specification: [RFC 1321](docs/rfc1320.txt). -## SHA Family -Secure Hash Standard [[pdf]](docs/fips180-3_final.pdf) +## SHA0 & SHA1 +Secure Hash Standard [[pdf]](docs/NIST.FIPS.180-4.pdf) + +## SHA2 Family +Secure Hash Standard [[pdf]](docs/NIST.FIPS.180-4.pdf) Published as standard by "National Institute of Standards and Technology". * SHA-0, * SHA-1, -* SHA-256, -* SHA-384, -* SHA-512 +* SHA2-224 (also known as SHA224), +* SHA2-256 (also known as SHA256), +* SHA2-384 (also known as SHA384), +* SHA2-512 (also known as SHA512) + +## SHA3 Family +SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions [[pdf]](docs/NIST.FIPS.202.pdf) + +Published as standard by "National Institute of Standards and Technology". + +* SHA3-224, +* SHA3-256, +* SHA3-384, +* SHA3-512 ## RIPEMD RIPEMD-160: A Strengthened Version of RIPEMD [[pdf]](docs/AB-9601.pdf) diff --git a/build/build.sh b/build/build.sh new file mode 100644 index 0000000..b2faeb6 --- /dev/null +++ b/build/build.sh @@ -0,0 +1 @@ +pwsh -ExecutionPolicy ByPass -NoProfile -file ./build.ps1 \ No newline at end of file diff --git a/docs/Damgaard_DesignPrincipleForHashFunctions.pdf b/docs/Damgaard_DesignPrincipleForHashFunctions.pdf new file mode 100644 index 0000000..c1ae4bb Binary files /dev/null and b/docs/Damgaard_DesignPrincipleForHashFunctions.pdf differ diff --git a/docs/Keccak-implementation-3.2.pdf b/docs/Keccak-implementation-3.2.pdf new file mode 100644 index 0000000..03dc36b Binary files /dev/null and b/docs/Keccak-implementation-3.2.pdf differ diff --git a/docs/Keccak-submission-3.pdf b/docs/Keccak-submission-3.pdf new file mode 100644 index 0000000..e25cedf Binary files /dev/null and b/docs/Keccak-submission-3.pdf differ diff --git a/docs/Merkle_Thesis1979.pdf b/docs/Merkle_Thesis1979.pdf new file mode 100644 index 0000000..b305030 Binary files /dev/null and b/docs/Merkle_Thesis1979.pdf differ diff --git a/docs/NIST.FIPS.180-4.pdf b/docs/NIST.FIPS.180-4.pdf new file mode 100644 index 0000000..5462a6a Binary files /dev/null and b/docs/NIST.FIPS.180-4.pdf differ diff --git a/docs/NIST.FIPS.202.pdf b/docs/NIST.FIPS.202.pdf new file mode 100644 index 0000000..08dc113 Binary files /dev/null and b/docs/NIST.FIPS.202.pdf differ diff --git a/docs/S.Lucks_DesignPrincipleForHashFunctions.pdf b/docs/S.Lucks_DesignPrincipleForHashFunctions.pdf new file mode 100644 index 0000000..d84f4ec Binary files /dev/null and b/docs/S.Lucks_DesignPrincipleForHashFunctions.pdf differ diff --git a/docs/Sakura.pdf b/docs/Sakura.pdf new file mode 100644 index 0000000..ff51c4f Binary files /dev/null and b/docs/Sakura.pdf differ diff --git a/docs/fips180-3_final.pdf b/docs/fips180-3_final.pdf deleted file mode 100644 index 72c10ce..0000000 Binary files a/docs/fips180-3_final.pdf and /dev/null differ diff --git a/docs/merkle_ADigitalSignatureBasedOnAConventionalEncryptionFunction.pdf b/docs/merkle_ADigitalSignatureBasedOnAConventionalEncryptionFunction.pdf new file mode 100644 index 0000000..b51b924 Binary files /dev/null and b/docs/merkle_ADigitalSignatureBasedOnAConventionalEncryptionFunction.pdf differ diff --git a/readme.txt b/readme.txt deleted file mode 100644 index 4c075d4..0000000 --- a/readme.txt +++ /dev/null @@ -1,17 +0,0 @@ -AcryptoHash.Net Project - -This project is subproject for project Acrypto.Net. - -Targets -Implementation of well-known cryptographic hash functions for .Net Framework. - -Requirements -Crossplatforms for .Net Framework implementations (No depends from operational systems). Implementation in managed code followed from requirement above. - -Tools -All algorithms from open sources, standards and request for comments (rfc). -For Testing purpose used NUnit (nunit.org). - -Authors -Idea and implementation: Andrey Rusyaev (mailto:andir@it-project.ru) -Company: It-Project (http://it-project.ru/) diff --git a/src/acryptohashnet.Benchmarks/Program.cs b/src/acryptohashnet.Benchmarks/Program.cs index 9d42bb9..2113482 100644 --- a/src/acryptohashnet.Benchmarks/Program.cs +++ b/src/acryptohashnet.Benchmarks/Program.cs @@ -1,13 +1,5 @@ -using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Jobs; -using BenchmarkDotNet.Running; +using BenchmarkDotNet.Running; -namespace acryptohashnet.Benchmarks -{ - internal static class Program - { - static void Main(string[] args) => BenchmarkSwitcher - .FromAssembly(typeof(Program).Assembly) - .Run(args); - } -} +BenchmarkSwitcher + .FromAssembly(typeof(Program).Assembly) + .Run(args); diff --git a/src/acryptohashnet.Benchmarks/SHA256Benchmark.cs b/src/acryptohashnet.Benchmarks/SHA256Benchmark.cs index 638a6d9..cc23dce 100644 --- a/src/acryptohashnet.Benchmarks/SHA256Benchmark.cs +++ b/src/acryptohashnet.Benchmarks/SHA256Benchmark.cs @@ -12,7 +12,7 @@ public class SHA256Benchmark private System.Security.Cryptography.SHA256Managed systemManagedImpl = new System.Security.Cryptography.SHA256Managed(); - private global::acryptohashnet.SHA256 acryptohashnetImpl = new global::acryptohashnet.SHA256(); + private global::acryptohashnet.Sha2_256 acryptohashnetImpl = new global::acryptohashnet.Sha2_256(); [ParamsSource(nameof(InputSource))] public byte[] Input { get; set; } diff --git a/src/acryptohashnet.Benchmarks/SHA384Benchmark.cs b/src/acryptohashnet.Benchmarks/SHA384Benchmark.cs index c22c162..d0ffb14 100644 --- a/src/acryptohashnet.Benchmarks/SHA384Benchmark.cs +++ b/src/acryptohashnet.Benchmarks/SHA384Benchmark.cs @@ -11,7 +11,7 @@ public class SHA384Benchmark private System.Security.Cryptography.SHA384Managed systemManagedImpl = new System.Security.Cryptography.SHA384Managed(); - private global::acryptohashnet.SHA384 acryptohashnetImpl = new global::acryptohashnet.SHA384(); + private global::acryptohashnet.Sha2_384 acryptohashnetImpl = new global::acryptohashnet.Sha2_384(); [ParamsSource(nameof(InputSource))] public byte[] Input { get; set; } diff --git a/src/acryptohashnet.Benchmarks/SHA512Benchmark.cs b/src/acryptohashnet.Benchmarks/SHA512Benchmark.cs index 838be10..cae7c33 100644 --- a/src/acryptohashnet.Benchmarks/SHA512Benchmark.cs +++ b/src/acryptohashnet.Benchmarks/SHA512Benchmark.cs @@ -11,7 +11,7 @@ public class SHA512Benchmark private System.Security.Cryptography.SHA512Managed systemManagedImpl = new System.Security.Cryptography.SHA512Managed(); - private global::acryptohashnet.SHA512 acryptohashnetImpl = new global::acryptohashnet.SHA512(); + private global::acryptohashnet.Sha2_512 acryptohashnetImpl = new global::acryptohashnet.Sha2_512(); [ParamsSource(nameof(InputSource))] public byte[] Input { get; set; } diff --git a/src/acryptohashnet.Benchmarks/SHAFamilyBenchmark.cs b/src/acryptohashnet.Benchmarks/SHAFamilyBenchmark.cs index 27ece8e..3b50eb5 100644 --- a/src/acryptohashnet.Benchmarks/SHAFamilyBenchmark.cs +++ b/src/acryptohashnet.Benchmarks/SHAFamilyBenchmark.cs @@ -12,11 +12,21 @@ public class SHAFamilyBenchmark private global::acryptohashnet.SHA1 sha1Impl = new global::acryptohashnet.SHA1(); - private global::acryptohashnet.SHA256 sha256Impl = new global::acryptohashnet.SHA256(); + private global::acryptohashnet.Sha2_224 sha2_224Impl = new global::acryptohashnet.Sha2_224(); - private global::acryptohashnet.SHA384 sha384Impl = new global::acryptohashnet.SHA384(); + private global::acryptohashnet.Sha2_256 sha2_256Impl = new global::acryptohashnet.Sha2_256(); - private global::acryptohashnet.SHA512 sha512Impl = new global::acryptohashnet.SHA512(); + private global::acryptohashnet.Sha2_384 sha2_384Impl = new global::acryptohashnet.Sha2_384(); + + private global::acryptohashnet.Sha2_512 sha2_512Impl = new global::acryptohashnet.Sha2_512(); + + private global::acryptohashnet.Sha3_224 sha3_224Impl = new global::acryptohashnet.Sha3_224(); + + private global::acryptohashnet.Sha3_256 sha3_256Impl = new global::acryptohashnet.Sha3_256(); + + private global::acryptohashnet.Sha3_384 sha3_384Impl = new global::acryptohashnet.Sha3_384(); + + private global::acryptohashnet.Sha3_512 sha3_512Impl = new global::acryptohashnet.Sha3_512(); [ParamsSource(nameof(InputSource))] public byte[] Input { get; set; } @@ -30,12 +40,27 @@ public class SHAFamilyBenchmark public byte[] Sha1Impl() => sha1Impl.ComputeHash(Input); [Benchmark] - public byte[] Sha256Impl() => sha256Impl.ComputeHash(Input); + public byte[] Sha2_224Impl() => sha2_224Impl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_256Impl() => sha2_256Impl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_384Impl() => sha2_384Impl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_512Impl() => sha2_512Impl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha3_224Impl() => sha3_224Impl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha3_256Impl() => sha3_256Impl.ComputeHash(Input); [Benchmark] - public byte[] Sha384Impl() => sha384Impl.ComputeHash(Input); + public byte[] Sha3_384Impl() => sha3_384Impl.ComputeHash(Input); [Benchmark] - public byte[] Sha512Impl() => sha512Impl.ComputeHash(Input); + public byte[] Sha3_512Impl() => sha3_512Impl.ComputeHash(Input); } } diff --git a/src/acryptohashnet.Benchmarks/Sha3_224Benchmark.cs b/src/acryptohashnet.Benchmarks/Sha3_224Benchmark.cs new file mode 100644 index 0000000..6c14163 --- /dev/null +++ b/src/acryptohashnet.Benchmarks/Sha3_224Benchmark.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +using BenchmarkDotNet.Attributes; + +namespace acryptohashnet.Benchmarks +{ + [MemoryDiagnoser] + public class Sha3_224Benchmark + { + private System.Security.Cryptography.SHA256 cryptoProviderImpl = System.Security.Cryptography.SHA256.Create(); + + private System.Security.Cryptography.SHA256Managed systemManagedImpl = new System.Security.Cryptography.SHA256Managed(); + + private global::acryptohashnet.Sha2_224 sha2_224AcryptohashnetImpl = new global::acryptohashnet.Sha2_224(); + + private global::acryptohashnet.Sha3_224 sha3_224AcryptohashnetImpl = new global::acryptohashnet.Sha3_224(); + + [ParamsSource(nameof(InputSource))] + public byte[] Input { get; set; } + + public IEnumerable InputSource { get; } = TestSuite.BinaryMessages; + + [Benchmark] + public byte[] Sha256CryptoProvider() => cryptoProviderImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha256SystemManaged() => systemManagedImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_224AcryptoHashNet() => sha2_224AcryptohashnetImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha3_224AcryptoHashNet() => sha3_224AcryptohashnetImpl.ComputeHash(Input); + } +} diff --git a/src/acryptohashnet.Benchmarks/Sha3_256Benchmark.cs b/src/acryptohashnet.Benchmarks/Sha3_256Benchmark.cs new file mode 100644 index 0000000..c32206f --- /dev/null +++ b/src/acryptohashnet.Benchmarks/Sha3_256Benchmark.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +using BenchmarkDotNet.Attributes; + +namespace acryptohashnet.Benchmarks +{ + [MemoryDiagnoser] + public class Sha3_256Benchmark + { + private System.Security.Cryptography.SHA256 cryptoProviderImpl = System.Security.Cryptography.SHA256.Create(); + + private System.Security.Cryptography.SHA256Managed systemManagedImpl = new System.Security.Cryptography.SHA256Managed(); + + private global::acryptohashnet.Sha2_256 sha2_256AcryptohashnetImpl = new global::acryptohashnet.Sha2_256(); + + private global::acryptohashnet.Sha3_256 sha3_256AcryptohashnetImpl = new global::acryptohashnet.Sha3_256(); + + [ParamsSource(nameof(InputSource))] + public byte[] Input { get; set; } + + public IEnumerable InputSource { get; } = TestSuite.BinaryMessages; + + [Benchmark] + public byte[] Sha2_256CryptoProvider() => cryptoProviderImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_256SystemManaged() => systemManagedImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_256AcryptoHashNet() => sha2_256AcryptohashnetImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha3_256AcryptoHashNet() => sha3_256AcryptohashnetImpl.ComputeHash(Input); + } +} diff --git a/src/acryptohashnet.Benchmarks/Sha3_384Benchmark.cs b/src/acryptohashnet.Benchmarks/Sha3_384Benchmark.cs new file mode 100644 index 0000000..86043eb --- /dev/null +++ b/src/acryptohashnet.Benchmarks/Sha3_384Benchmark.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +using BenchmarkDotNet.Attributes; + +namespace acryptohashnet.Benchmarks +{ + [MemoryDiagnoser] + public class Sha3_384Benchmark + { + private System.Security.Cryptography.SHA384 cryptoProviderImpl = System.Security.Cryptography.SHA384.Create(); + + private System.Security.Cryptography.SHA384Managed systemManagedImpl = new System.Security.Cryptography.SHA384Managed(); + + private global::acryptohashnet.Sha2_384 sha2_384AcryptohashnetImpl = new global::acryptohashnet.Sha2_384(); + + private global::acryptohashnet.Sha3_384 sha3_384AcryptohashnetImpl = new global::acryptohashnet.Sha3_384(); + + [ParamsSource(nameof(InputSource))] + public byte[] Input { get; set; } + + public IEnumerable InputSource { get; } = TestSuite.BinaryMessages; + + [Benchmark] + public byte[] Sha2_384CryptoProvider() => cryptoProviderImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_384SystemManaged() => systemManagedImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_384AcryptoHashNet() => sha2_384AcryptohashnetImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha3_384AcryptoHashNet() => sha3_384AcryptohashnetImpl.ComputeHash(Input); + } +} diff --git a/src/acryptohashnet.Benchmarks/Sha3_512Benchmark.cs b/src/acryptohashnet.Benchmarks/Sha3_512Benchmark.cs new file mode 100644 index 0000000..037c886 --- /dev/null +++ b/src/acryptohashnet.Benchmarks/Sha3_512Benchmark.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +using BenchmarkDotNet.Attributes; + +namespace acryptohashnet.Benchmarks +{ + [MemoryDiagnoser] + public class Sha3_512Benchmark + { + private System.Security.Cryptography.SHA512 cryptoProviderImpl = System.Security.Cryptography.SHA512.Create(); + + private System.Security.Cryptography.SHA512Managed systemManagedImpl = new System.Security.Cryptography.SHA512Managed(); + + private global::acryptohashnet.Sha2_512 sha2_512AcryptohashnetImpl = new global::acryptohashnet.Sha2_512(); + + private global::acryptohashnet.Sha3_512 sha3_512AcryptohashnetImpl = new global::acryptohashnet.Sha3_512(); + + [ParamsSource(nameof(InputSource))] + public byte[] Input { get; set; } + + public IEnumerable InputSource { get; } = TestSuite.BinaryMessages; + + [Benchmark] + public byte[] Sha2_512CryptoProvider() => cryptoProviderImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_512SystemManaged() => systemManagedImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha2_512AcryptoHashNet() => sha2_512AcryptohashnetImpl.ComputeHash(Input); + + [Benchmark] + public byte[] Sha3_512AcryptoHashNet() => sha3_512AcryptohashnetImpl.ComputeHash(Input); + } +} diff --git a/src/acryptohashnet.Benchmarks/acryptohashnet.Benchmarks.csproj b/src/acryptohashnet.Benchmarks/acryptohashnet.Benchmarks.csproj index dc5b1f1..deafc9c 100644 --- a/src/acryptohashnet.Benchmarks/acryptohashnet.Benchmarks.csproj +++ b/src/acryptohashnet.Benchmarks/acryptohashnet.Benchmarks.csproj @@ -2,12 +2,12 @@ Exe - net6.0 + net8.0 Major - + diff --git a/src/acryptohashnet.UnitTests/BigEndianTests.cs b/src/acryptohashnet.UnitTests/BigEndianTests.cs index 77cf2e4..750c9ea 100644 --- a/src/acryptohashnet.UnitTests/BigEndianTests.cs +++ b/src/acryptohashnet.UnitTests/BigEndianTests.cs @@ -14,9 +14,9 @@ public void CopyBytesToUintsTest() BigEndian.Copy(input, output); - CollectionAssert.AreEqual( - new uint[] { 0x12345678, 0x78563412 }, - output); + Assert.That( + output, + Is.EqualTo(new uint[] { 0x12345678, 0x78563412 })); } [Test] @@ -28,9 +28,9 @@ public void CopyUintsToBytesTest() BigEndian.Copy(input, output); - CollectionAssert.AreEqual( - new byte[] { 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 }, - output); + Assert.That( + output, + Is.EqualTo(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x78, 0x56, 0x34, 0x12 })); } [Test] @@ -42,9 +42,9 @@ public void CopyBytesToUlongsTest() BigEndian.Copy(input, output); - CollectionAssert.AreEqual( - new ulong[] { 0x123456789ABCDEF1, 0x1FEDCBA978563412 }, - output); + Assert.That( + output, + Is.EqualTo(new ulong[] { 0x123456789ABCDEF1, 0x1FEDCBA978563412 })); } [Test] @@ -56,9 +56,9 @@ public void CopyUlongsToBytesTest() BigEndian.Copy(input, output); - CollectionAssert.AreEqual( - new byte[] { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, 0x1F, 0xED, 0xCB, 0xA9, 0x78, 0x56, 0x34, 0x12 }, - output); + Assert.That( + output, + Is.EqualTo(new byte[] { 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, 0x1F, 0xED, 0xCB, 0xA9, 0x78, 0x56, 0x34, 0x12 })); } } } diff --git a/src/acryptohashnet.UnitTests/HashAlgorithmTests.cs b/src/acryptohashnet.UnitTests/HashAlgorithmTests.cs index 4bffa92..eeea46b 100644 --- a/src/acryptohashnet.UnitTests/HashAlgorithmTests.cs +++ b/src/acryptohashnet.UnitTests/HashAlgorithmTests.cs @@ -38,9 +38,16 @@ public static IEnumerable HashAlgorithms new SHA0(), new SHA1(), - new SHA256(), - new SHA256(), - new SHA512(), + + new Sha2_224(), + new Sha2_256(), + new Sha2_384(), + new Sha2_512(), + + new Sha3_224(), + new Sha3_256(), + new Sha3_384(), + new Sha3_512(), new Snefru(), new Snefru256(), @@ -60,7 +67,7 @@ public void HashAlgorithmCanBeReused(HashAlgorithm hashAlgorithm) var hash1 = hashAlgorithm.ComputeHash(input); var hash2 = hashAlgorithm.ComputeHash(input); - Assert.AreEqual(hash1.ToHexString(), hash2.ToHexString()); + Assert.That(hash1.ToHexString(), Is.EqualTo(hash2.ToHexString())); } [Test] @@ -78,7 +85,9 @@ public void TransformByTwoBlocksShouldHaveSameResult(HashAlgorithm hashAlgorithm hashAlgorithm.TransformBlock(b1, 0, b1.Length, null, 0); hashAlgorithm.TransformFinalBlock(b2, 0, b2.Length); - Assert.AreEqual(expected, hashAlgorithm.Hash?.ToHexString()); + Assert.That( + hashAlgorithm.Hash?.ToHexString(), + Is.EqualTo(expected)); } [Test] @@ -97,7 +106,9 @@ public void TransformByTwoBlocksAndEmptyFinalBlockShouldHaveSameResult(HashAlgor hashAlgorithm.TransformBlock(b2, 0, b2.Length, null, 0); hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0); - Assert.AreEqual(expected, hashAlgorithm.Hash?.ToHexString()); + Assert.That( + hashAlgorithm.Hash?.ToHexString(), + Is.EqualTo(expected)); } [Test] @@ -116,7 +127,9 @@ public void TransformByBytesShouldHaveSameResult(HashAlgorithm hashAlgorithm) hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0); - Assert.AreEqual(expected, hashAlgorithm.Hash?.ToHexString()); + Assert.That( + hashAlgorithm.Hash?.ToHexString(), + Is.EqualTo(expected)); } [Test] @@ -129,7 +142,9 @@ public void TransformOnlyFinalBlockShouldHaveSameResult(HashAlgorithm hashAlgori hashAlgorithm.Initialize(); hashAlgorithm.TransformFinalBlock(binaryMessage, 0, binaryMessage.Length); - Assert.AreEqual(expected, hashAlgorithm.Hash?.ToHexString()); + Assert.That( + hashAlgorithm.Hash?.ToHexString(), + Is.EqualTo(expected)); } @@ -144,7 +159,9 @@ public void TransformEmptyFinalBlockShouldHaveSameResult(HashAlgorithm hashAlgor hashAlgorithm.TransformBlock(binaryMessage, 0, binaryMessage.Length, null, 0); hashAlgorithm.TransformFinalBlock(new byte[0], 0, 0); - Assert.AreEqual(expected, hashAlgorithm.Hash?.ToHexString()); + Assert.That( + hashAlgorithm.Hash?.ToHexString(), + Is.EqualTo(expected)); } [Test] @@ -165,7 +182,9 @@ public void TransformByBlockSizeOffByOneMinusBlockShouldHaveSameResult(HashAlgor } hashAlgorithm.TransformFinalBlock(binaryMessage, binaryMessage.Length - remainingBytes, remainingBytes); - Assert.AreEqual(expected, hashAlgorithm.Hash?.ToHexString()); + Assert.That( + hashAlgorithm.Hash?.ToHexString(), + Is.EqualTo(expected)); } [Test] @@ -186,7 +205,9 @@ public void TransformByExactlyByBlockSizeBlockShouldHaveSameResult(HashAlgorithm } hashAlgorithm.TransformFinalBlock(binaryMessage, binaryMessage.Length - remainingBytes, remainingBytes); - Assert.AreEqual(expected, hashAlgorithm.Hash?.ToHexString()); + Assert.That( + hashAlgorithm.Hash?.ToHexString(), + Is.EqualTo(expected)); } [Test] @@ -207,7 +228,9 @@ public void TransformByBlockSizeOffByOnePlusBlockShouldHaveSameResult(HashAlgori } hashAlgorithm.TransformFinalBlock(binaryMessage, binaryMessage.Length - remainingBytes, remainingBytes); - Assert.AreEqual(expected, hashAlgorithm.Hash?.ToHexString()); + Assert.That( + hashAlgorithm.Hash?.ToHexString(), + Is.EqualTo(expected)); } private static string GenerateMessageWithAtLeastBlocks(HashAlgorithm hashAlgorithm, int minimumBlocksRequired) diff --git a/src/acryptohashnet.UnitTests/LittleEndianTests.cs b/src/acryptohashnet.UnitTests/LittleEndianTests.cs index d48f2a5..7f4a531 100644 --- a/src/acryptohashnet.UnitTests/LittleEndianTests.cs +++ b/src/acryptohashnet.UnitTests/LittleEndianTests.cs @@ -14,9 +14,9 @@ public void CopyBytesToUintsTest() LittleEndian.Copy(input, output); - CollectionAssert.AreEqual( - new uint[] { 0x78563412, 0x12345678 }, - output); + Assert.That( + output, + Is.EqualTo(new uint[] { 0x78563412, 0x12345678 })); } [Test] @@ -28,9 +28,9 @@ public void CopyUintsToBytesTest() LittleEndian.Copy(input, output); - CollectionAssert.AreEqual( - new byte[] { 0x78, 0x56, 0x34, 0x12, 0x12, 0x34, 0x56, 0x78 }, - output); + Assert.That( + output, + Is.EqualTo(new byte[] { 0x78, 0x56, 0x34, 0x12, 0x12, 0x34, 0x56, 0x78 })); } [Test] @@ -42,9 +42,9 @@ public void CopyBytesToUlongsTest() LittleEndian.Copy(input, output); - CollectionAssert.AreEqual( - new ulong[] { 0xF1DEBC9A78563412, 0x12345678A9CBED1F }, - output); + Assert.That( + output, + Is.EqualTo(new ulong[] { 0xF1DEBC9A78563412, 0x12345678A9CBED1F })); } [Test] @@ -56,9 +56,9 @@ public void CopyUlongsToBytesTest() LittleEndian.Copy(input, output); - CollectionAssert.AreEqual( - new byte[] { 0xF1, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, 0x12, 0x34, 0x56, 0x78, 0xA9, 0xCB, 0xED, 0x1F }, - output); + Assert.That( + output, + Is.EqualTo(new byte[] { 0xF1, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, 0x12, 0x34, 0x56, 0x78, 0xA9, 0xCB, 0xED, 0x1F })); } } } diff --git a/src/acryptohashnet.UnitTests/SHA/SHA0Tests.cs b/src/acryptohashnet.UnitTests/SHA/SHA0Tests.cs index caae403..b912b6f 100644 --- a/src/acryptohashnet.UnitTests/SHA/SHA0Tests.cs +++ b/src/acryptohashnet.UnitTests/SHA/SHA0Tests.cs @@ -1,25 +1,25 @@ -using NUnit.Framework; using System.Collections.Generic; using System.Linq; -using System.Text; + +using NUnit.Framework; namespace acryptohashnet.UnitTests { [TestFixture] public class SHA0Tests { - [TestCaseSource(nameof(TestCases))] - public void HashOfString(string input, string expected) + [TestCaseSource(nameof(Sha0TestCases))] + public void Sha0(string input, string expected) { - var actual = new SHA0().ComputeHash(Encoding.UTF8.GetBytes(input)).ToHexString(); + var actual = new SHA0().ComputeHash(input.GetUtf8Bytes()).ToHexString(); Assert.That(actual, Is.EqualTo(expected)); } - public static IEnumerable TestCases + public static IEnumerable Sha0TestCases { get { - return SHAFamilyTestCases.All().Select(x => new object[] { x.Input, x.Sha0 }); + return SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha0 }); } } } diff --git a/src/acryptohashnet.UnitTests/SHA/SHA1Tests.cs b/src/acryptohashnet.UnitTests/SHA/SHA1Tests.cs index b6907eb..6151dda 100644 --- a/src/acryptohashnet.UnitTests/SHA/SHA1Tests.cs +++ b/src/acryptohashnet.UnitTests/SHA/SHA1Tests.cs @@ -1,25 +1,25 @@ -using NUnit.Framework; using System.Collections.Generic; using System.Linq; -using System.Text; + +using NUnit.Framework; namespace acryptohashnet.UnitTests { [TestFixture] public class SHA1Tests { - [TestCaseSource(nameof(TestCases))] - public void HashOfString(string input, string expected) + [TestCaseSource(nameof(Sha1TestCases))] + public void Sha1(string input, string expected) { - var actual = new SHA1().ComputeHash(Encoding.UTF8.GetBytes(input)).ToHexString(); + var actual = new SHA1().ComputeHash(input.GetUtf8Bytes()).ToHexString(); Assert.That(actual, Is.EqualTo(expected)); } - public static IEnumerable TestCases + public static IEnumerable Sha1TestCases { get { - return SHAFamilyTestCases.All().Select(x => new object[] { x.Input, x.Sha1 }); + return SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha1 }); } } } diff --git a/src/acryptohashnet.UnitTests/SHA/SHA256Tests.cs b/src/acryptohashnet.UnitTests/SHA/SHA256Tests.cs deleted file mode 100644 index 4b3b21c..0000000 --- a/src/acryptohashnet.UnitTests/SHA/SHA256Tests.cs +++ /dev/null @@ -1,26 +0,0 @@ -using NUnit.Framework; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace acryptohashnet.UnitTests -{ - [TestFixture] - public class SHA256Tests - { - [TestCaseSource(nameof(TestCases))] - public void HashOfString(string input, string expected) - { - var actual = new SHA256().ComputeHash(Encoding.UTF8.GetBytes(input)).ToHexString(); - Assert.That(actual, Is.EqualTo(expected)); - } - - public static IEnumerable TestCases - { - get - { - return SHAFamilyTestCases.All().Select(x => new object[] { x.Input, x.Sha256 }); - } - } - } -} diff --git a/src/acryptohashnet.UnitTests/SHA/SHA384Tests.cs b/src/acryptohashnet.UnitTests/SHA/SHA384Tests.cs deleted file mode 100644 index 8c49db4..0000000 --- a/src/acryptohashnet.UnitTests/SHA/SHA384Tests.cs +++ /dev/null @@ -1,26 +0,0 @@ -using NUnit.Framework; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace acryptohashnet.UnitTests -{ - [TestFixture] - public class SHA384Tests - { - [TestCaseSource(nameof(TestCases))] - public void HashOfString(string input, string expected) - { - var actual = new SHA384().ComputeHash(Encoding.UTF8.GetBytes(input)).ToHexString(); - Assert.That(actual, Is.EqualTo(expected)); - } - - public static IEnumerable TestCases - { - get - { - return SHAFamilyTestCases.All().Select(x => new object[] { x.Input, x.Sha384 }); - } - } - } -} diff --git a/src/acryptohashnet.UnitTests/SHA/SHA512Tests.cs b/src/acryptohashnet.UnitTests/SHA/SHA512Tests.cs deleted file mode 100644 index d2c2d96..0000000 --- a/src/acryptohashnet.UnitTests/SHA/SHA512Tests.cs +++ /dev/null @@ -1,26 +0,0 @@ -using NUnit.Framework; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace acryptohashnet.UnitTests -{ - [TestFixture] - public class SHA512Tests - { - [TestCaseSource(nameof(TestCases))] - public void HashOfString(string input, string expected) - { - var actual = new SHA512().ComputeHash(Encoding.UTF8.GetBytes(input)).ToHexString(); - Assert.That(actual, Is.EqualTo(expected)); - } - - public static IEnumerable TestCases - { - get - { - return SHAFamilyTestCases.All().Select(x => new object[] { x.Input, x.Sha512 }); - } - } - } -} diff --git a/src/acryptohashnet.UnitTests/SHA/SHAFamilyTestCases.cs b/src/acryptohashnet.UnitTests/SHA/SHAFamilyTestCases.cs index 458739b..dd17003 100644 --- a/src/acryptohashnet.UnitTests/SHA/SHAFamilyTestCases.cs +++ b/src/acryptohashnet.UnitTests/SHA/SHAFamilyTestCases.cs @@ -10,149 +10,269 @@ public static IEnumerable All() { new HashTestCase { - Input = "", + Message = "", + Md2 = "8350e5a3e24c153df2275c9f80692773", + Md4 = "31d6cfe0d16ae931b73c59d7e0c089c0", + Md5 = "d41d8cd98f00b204e9800998ecf8427e", Sha0 = "f96cea198ad1dd5617ac084a3d92c6107708c0ef", Sha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709", - Sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - Sha384 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", - Sha512 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + Sha2_224 = "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + Sha2_256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + Sha2_384 = "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", + Sha2_512 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + Sha3_224 = "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", + Sha3_256 = "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", + Sha3_384 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004", + Sha3_512 = "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26" }, new HashTestCase { - Input = "a", + Message = "a", + Md2 = "32ec01ec4a6dac72c0ab96fb34c0b5d1", + Md4 = "bde52cb31de33e46245e05fbdbd6fb24", + Md5 = "0cc175b9c0f1b6a831c399e269772661", Sha0 = "37f297772fae4cb1ba39b6cf9cf0381180bd62f2", Sha1 = "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", - Sha256 = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", - Sha384 = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", - Sha512 = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" + Sha2_224 = "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", + Sha2_256 = "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", + Sha2_384 = "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", + Sha2_512 = "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", + Sha3_224 = "9e86ff69557ca95f405f081269685b38e3a819b309ee942f482b6a8b", + Sha3_256 = "80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", + Sha3_384 = "1815f774f320491b48569efec794d249eeb59aae46d22bf77dafe25c5edc28d7ea44f93ee1234aa88f61c91912a4ccd9", + Sha3_512 = "697f2d856172cb8309d6b8b97dac4de344b549d4dee61edfb4962d8698b7fa803f4f93ff24393586e28b5b957ac3d1d369420ce53332712f997bd336d09ab02a" }, new HashTestCase { - Input = "abc", + Message = "abc", + Md2 = "da853b0d3f88d99b30283a69e6ded6bb", + Md4 = "a448017aaf21d8525fc10ae87aa6729d", + Md5 = "900150983cd24fb0d6963f7d28e17f72", Sha0 = "0164b8a914cd2a5e74c4f7ff082c4d97f1edf880", Sha1 = "a9993e364706816aba3e25717850c26c9cd0d89d", - Sha256 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - Sha384 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", - Sha512 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" + Sha2_224 = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", + Sha2_256 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + Sha2_384 = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", + Sha2_512 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + Sha3_224 = "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", + Sha3_256 = "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", + Sha3_384 = "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25", + Sha3_512 = "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0" }, new HashTestCase { - Input = "message digest", + Message = "message digest", + Md2 = "ab4f496bfb2a530b219ff33031fe06b0", + Md4 = "d9130a8164549fe818874806e1c7014b", + Md5 = "f96b697d7cb7938d525a2f31aaf161d0", Sha0 = "c1b0f222d150ebb9aa36a40cafdc8bcbed830b14", Sha1 = "c12252ceda8be8994d5fa0290a47231c1d16aae3", - Sha256 = "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650", - Sha384 = "473ed35167ec1f5d8e550368a3db39be54639f828868e9454c239fc8b52e3c61dbd0d8b4de1390c256dcbb5d5fd99cd5", - Sha512 = "107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c" + Sha2_224 = "2cb21c83ae2f004de7e81c3c7019cbcb65b71ab656b22d6d0c39b8eb", + Sha2_256 = "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650", + Sha2_384 = "473ed35167ec1f5d8e550368a3db39be54639f828868e9454c239fc8b52e3c61dbd0d8b4de1390c256dcbb5d5fd99cd5", + Sha2_512 = "107dbf389d9e9f71a3a95f6c055b9251bc5268c2be16d6c13492ea45b0199f3309e16455ab1e96118e8a905d5597b72038ddb372a89826046de66687bb420e7c", + Sha3_224 = "18768bb4c48eb7fc88e5ddb17efcf2964abd7798a39d86a4b4a1e4c8", + Sha3_256 = "edcdb2069366e75243860c18c3a11465eca34bce6143d30c8665cefcfd32bffd", + Sha3_384 = "d9519709f44af73e2c8e291109a979de3d61dc02bf69def7fbffdfffe662751513f19ad57e17d4b93ba1e484fc1980d5", + Sha3_512 = "3444e155881fa15511f57726c7d7cfe80302a7433067b29d59a71415ca9dd141ac892d310bc4d78128c98fda839d18d7f0556f2fe7acb3c0cda4bff3a25f5f59" }, new HashTestCase { - Input = "abcdefghijklmnopqrstuvwxyz", + Message = "abcdefghijklmnopqrstuvwxyz", + Md2 = "4e8ddff3650292ab5a4108c3aa47940b", + Md4 = "d79e1c308aa5bbcdeea8ed63df412da9", + Md5 = "c3fcd3d76192e4007dfb496cca67e13b", Sha0 = "b40ce07a430cfd3c033039b9fe9afec95dc1bdcd", Sha1 = "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", - Sha256 = "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73", - Sha384 = "feb67349df3db6f5924815d6c3dc133f091809213731fe5c7b5f4999e463479ff2877f5f2936fa63bb43784b12f3ebb4", - Sha512 = "4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1" + Sha2_224 = "45a5f72c39c5cff2522eb3429799e49e5f44b356ef926bcf390dccc2", + Sha2_256 = "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73", + Sha2_384 = "feb67349df3db6f5924815d6c3dc133f091809213731fe5c7b5f4999e463479ff2877f5f2936fa63bb43784b12f3ebb4", + Sha2_512 = "4dbff86cc2ca1bae1e16468a05cb9881c97f1753bce3619034898faa1aabe429955a1bf8ec483d7421fe3c1646613a59ed5441fb0f321389f77f48a879c7b1f1", + Sha3_224 = "5cdeca81e123f87cad96b9cba999f16f6d41549608d4e0f4681b8239", + Sha3_256 = "7cab2dc765e21b241dbc1c255ce620b29f527c6d5e7f5f843e56288f0d707521", + Sha3_384 = "fed399d2217aaf4c717ad0c5102c15589e1c990cc2b9a5029056a7f7485888d6ab65db2370077a5cadb53fc9280d278f", + Sha3_512 = "af328d17fa28753a3c9f5cb72e376b90440b96f0289e5703b729324a975ab384eda565fc92aaded143669900d761861687acdc0a5ffa358bd0571aaad80aca68" }, new HashTestCase { - Input = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + Message = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + Md2 = "da33def2a42df13975352846c30338cd", + Md4 = "043f8582f241db351ce627e153e7f0e4", + Md5 = "d174ab98d277d9f5a5611c2c9f419d9f", Sha0 = "79e966f7a3a990df33e40e3d7f8f18d2caebadfa", Sha1 = "761c457bf73b14d27e9e9265c46f4b4dda11f940", - Sha256 = "db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0", - Sha384 = "1761336e3f7cbfe51deb137f026f89e01a448e3b1fafa64039c1464ee8732f11a5341a6f41e0c202294736ed64db1a84", - Sha512 = "1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894" + Sha2_224 = "bff72b4fcb7d75e5632900ac5f90d219e05e97a7bde72e740db393d9", + Sha2_256 = "db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0", + Sha2_384 = "1761336e3f7cbfe51deb137f026f89e01a448e3b1fafa64039c1464ee8732f11a5341a6f41e0c202294736ed64db1a84", + Sha2_512 = "1e07be23c26a86ea37ea810c8ec7809352515a970e9253c26f536cfc7a9996c45c8370583e0a78fa4a90041d71a4ceab7423f19c71b9d5a3e01249f0bebd5894", + Sha3_224 = "a67c289b8250a6f437a20137985d605589a8c163d45261b15419556e", + Sha3_256 = "a79d6a9da47f04a3b9a9323ec9991f2105d4c78a7bc7beeb103855a7a11dfb9f", + Sha3_384 = "d5b972302f5080d0830e0de7b6b2cf383665a008f4c4f386a61112652c742d20cb45aa51bd4f542fc733e2719e999291", + Sha3_512 = "d1db17b4745b255e5eb159f66593cc9c143850979fc7a3951796aba80165aab536b46174ce19e3f707f0e5c6487f5f03084bc0ec9461691ef20113e42ad28163" }, new HashTestCase { - Input = "For this sample, this 63-byte string will be used as input data", + Message = "For this sample, this 63-byte string will be used as input data", + Md2 = "4d2b317fb976ad61b23eaf8fe8592bcf", + Md4 = "0b501fa8881a5caa0d83fe7a3d2d186d", + Md5 = "b02752d13a05fa8d7d04aabd158ff9d1", Sha0 = "dda99bb3c3376907131166db9597040cd0f63ea5", Sha1 = "4f0ea5cd0585a23d028abdc1a6684e5a8094dc49", - Sha256 = "f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342", - Sha384 = "37b49ef3d08de53e9bd018b0630067bd43d09c427d06b05812f48531bce7d2a698ee2d1ed1ffed46fd4c3b9f38a8a557", - Sha512 = "b3de4afbc516d2478fe9b518d063bda6c8dd65fc38402dd81d1eb7364e72fb6e6663cf6d2771c8f5a6da09601712fb3d2a36c6ffea3e28b0818b05b0a8660766" + Sha2_224 = "0873433e1c8749dad0e34f92aff11c4b2ca310356283817747aa6940", + Sha2_256 = "f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342", + Sha2_384 = "37b49ef3d08de53e9bd018b0630067bd43d09c427d06b05812f48531bce7d2a698ee2d1ed1ffed46fd4c3b9f38a8a557", + Sha2_512 = "b3de4afbc516d2478fe9b518d063bda6c8dd65fc38402dd81d1eb7364e72fb6e6663cf6d2771c8f5a6da09601712fb3d2a36c6ffea3e28b0818b05b0a8660766", + Sha3_224 = "24ca73a54f94fb66634e7a975e0ccdf9411446a6e6125564dc409085", + Sha3_256 = "66c3646740ff4c95eb5db97cfae97f954340f54dc22e0f1eb169b7ce0f611881", + Sha3_384 = "ea135c8672638075a3f7e772b4b5620f60168e95d7e8b4f8e37740f96753fac8f9f929d25356b7dc59f0c8c53f58701b", + Sha3_512 = "4d26f437b17e35b2c8c352c813b3fc387cd69b6f9bf3dcfdba281ad35e76c8b731f6394e1c9694984eeb4d8bd6e368989162928c1f9d9ab7a3f3681102c944fd" }, new HashTestCase { - Input = "This is exactly 64 bytes long, not counting the terminating byte", + Message = "This is exactly 64 bytes long, not counting the terminating byte", + Md2 = "6caa9cd8554a2152f201f9705d7027a6", + Md4 = "572c146781d8abc6d5f827844cf4d94b", + Md5 = "debcb70bf9c8e83659ef1d85aa51c5e9", Sha0 = "922f7783393e8f2ee8b948c8dd7b6d542b19be4c", Sha1 = "fb679f23e7d1ce053313e66e127ab1b444397057", - Sha256 = "ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8", - Sha384 = "e28e35e25a1874908bf0958bb088b69f3d742a753c86993e9f4b1c4c21988f958bd1fe0315b195aca7b061213ac2a9bd", - Sha512 = "70aefeaa0e7ac4f8fe17532d7185a289bee3b428d950c14fa8b713ca09814a387d245870e007a80ad97c369d193e41701aa07f3221d15f0e65a1ff970cedf030" + Sha2_224 = "d92622d56f83d869a884f6cc0763e90c4520a21e1cc429841e4584d2", + Sha2_256 = "ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8", + Sha2_384 = "e28e35e25a1874908bf0958bb088b69f3d742a753c86993e9f4b1c4c21988f958bd1fe0315b195aca7b061213ac2a9bd", + Sha2_512 = "70aefeaa0e7ac4f8fe17532d7185a289bee3b428d950c14fa8b713ca09814a387d245870e007a80ad97c369d193e41701aa07f3221d15f0e65a1ff970cedf030", + Sha3_224 = "7590bf3e5bb176529c30679448bfe63bb489ca27b44e5e30784a85e1", + Sha3_256 = "d7fcb87d155ffdeb4a9f154a6b241631038cad064e3d4cffc46900fbfb557d4d", + Sha3_384 = "2cc2687e269bded5e3fc2cf0b4170b625a011535e0cef7e6ef3f5b3f26490f4caad6fe72b1705a30c8c2572dfdf1b968", + Sha3_512 = "cfb955003293d477b2189e8a6f3f9cee83906b5bcca3db59c2853ad0e85350c52636685d99aa01c55e34412a6ef40ab6fc16119f45509c73e9e1e47cd7da2090" }, new HashTestCase { - Input = "By hashing data that is one byte less than a multiple of a hash block length (like this 127-byte string), bugs may be revealed.", + Message = "By hashing data that is one byte less than a multiple of a hash block length (like this 127-byte string), bugs may be revealed.", + Md2 = "303a4941ba2a3fb01430289503d074ee", + Md4 = "0c1d5450ebdf236aceee8b0b66cdfa72", + Md5 = "50c757c2522680444582b8f4572b32f2", Sha0 = "a66bc4b1b05eb0a0c22625ea87e05363f1ca19d2", Sha1 = "69e8e40e4a20b17a8de35505e2fe6ff1fe63cc96", - Sha256 = "e4326d0459653d7d3514674d713e74dc3df11ed4d30b4013fd327fdb9e394c26", - Sha384 = "1ca650f38480fa9dfb5729636bec4a935ebc1cd4c0055ee50cad2aa627e066871044fd8e6fdb80edf10b85df15ba7aab", - Sha512 = "d399507bbf5f2d0da51db1ff1fc51c1c9ff1de0937e00d01693b240e84fcc3400601429f45c297acc6e8fcf1e4e4abe9ff21a54a0d3d88888f298971bd206cd5" + Sha2_224 = "49e54148d21d457f2ffe28532543d91da98724c9883e67682301dec4", + Sha2_256 = "e4326d0459653d7d3514674d713e74dc3df11ed4d30b4013fd327fdb9e394c26", + Sha2_384 = "1ca650f38480fa9dfb5729636bec4a935ebc1cd4c0055ee50cad2aa627e066871044fd8e6fdb80edf10b85df15ba7aab", + Sha2_512 = "d399507bbf5f2d0da51db1ff1fc51c1c9ff1de0937e00d01693b240e84fcc3400601429f45c297acc6e8fcf1e4e4abe9ff21a54a0d3d88888f298971bd206cd5", + Sha3_224 = "d1e3c1f63938eed5a5f0f950882a0e4815005f092955360fd95df961", + Sha3_256 = "c790addecbb54333aa90e6325d7173069982aee4763fd1d85f5816501b741058", + Sha3_384 = "bf28930432e04820a983171bf03567c291eee90a4a4d44ede97718c59bdd219ea541031cdfba4d7a4b047a862a406fde", + Sha3_512 = "be7f09cef9492217dd3e822d0221cb94c91941a187d75171907a80ae4d0e3d925126596a8da3111d7937c97eba794c9be22eb8ef1d5be9e647c29259119a1148" }, new HashTestCase { - Input = "And this textual data, astonishing as it may appear, is exactly 128 bytes in length, as are both SHA-384 and SHA-512 block sizes", + Message = "And this textual data, astonishing as it may appear, is exactly 128 bytes in length, as are both SHA-384 and SHA-512 block sizes", + Md2 = "0b4e8940897149509fd7bc5078032578", + Md4 = "dadc76e37d7b36b2e313a13657ac5f9f", + Md5 = "268dc47e6b6f19a86481374b2ced6f18", Sha0 = "b1b8de4c612ea852c9e55ac6fdae3f7ee8bf56c0", Sha1 = "7e9fb243f2cb25eab54b1217ab104d72ddec1c6a", - Sha256 = "0ab803344830f92089494fb635ad00d76164ad6e57012b237722df0d7ad26896", - Sha384 = "e3e3602f4d90c935321d788f722071a8809f4f09366f2825cd85da97ccd2955eb6b8245974402aa64789ed45293e94ba", - Sha512 = "97fb4ec472f3cb698b9c3c12a12768483e5b62bcdad934280750b4fa4701e5e0550a80bb0828342c19631ba55a55e1cee5de2fda91fc5d40e7bee1d4e6d415b3" + Sha2_224 = "5a69ccca0b5e7f84efda7c026d010fa46569c03f97b4440eba32b941", + Sha2_256 = "0ab803344830f92089494fb635ad00d76164ad6e57012b237722df0d7ad26896", + Sha2_384 = "e3e3602f4d90c935321d788f722071a8809f4f09366f2825cd85da97ccd2955eb6b8245974402aa64789ed45293e94ba", + Sha2_512 = "97fb4ec472f3cb698b9c3c12a12768483e5b62bcdad934280750b4fa4701e5e0550a80bb0828342c19631ba55a55e1cee5de2fda91fc5d40e7bee1d4e6d415b3", + Sha3_224 = "d2f7704e038f5be195c3fd2e7de433749e585ebb0b29cf18d479b8b3", + Sha3_256 = "f420ebf4fcd128355fe703154acb085c6178bc8d415adf3b29485ba21e133d37", + Sha3_384 = "4dce6c4657b749c680e95e98f83bd60162ed07713dc8a39bd6cb72efb72bb58831006dc3bc16d6e9000825d3417b8e56", + Sha3_512 = "758c72814a27e32aabfdf49d421a67a2281cdcc0d9f5ac77482161f5b042bd6f3d251065373647d59f393ac3818760784db6cf9ae263a3bd3e167fe9a6e8a503" }, new HashTestCase { - Input = "Exactly 1000 bytes: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX", + Message = "Exactly 1000 bytes: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX", + Md2 = "cbede9d6080aea700605ad4565a9e3af", + Md4 = "0fc4c9f881efddbd5712c8a52d4f5271", + Md5 = "8552d46f34d75f4f770ea10227d73cb9", Sha0 = "98b59f2c2e9b87473f685d2339bbc839d84065ff", Sha1 = "a26ab5cb975a0ebad8fde68cb157a05ad169b632", - Sha256 = "629730eb261524c260ac8135936f3593ed01d3ebc361ae265385ba44529935d9", - Sha384 = "530338f9e56c1c3c872df925468eae047f48fb8955d5da37b81e0879fff53927cbc64fb7f1b65316b203207c8a72b5bc", - Sha512 = "7635d618e14800a3c2c27b614c446baf09ea08ae64a087cd8218fc72b385d99d59a8940c7cacd67bafc0ef9e4da964e0626c5e3c30e83df7d9577198b61111d2" + Sha2_224 = "9ca47d8b16589c19fe4f40545ecc0c6b106bf9e8f30f914136e11d30", + Sha2_256 = "629730eb261524c260ac8135936f3593ed01d3ebc361ae265385ba44529935d9", + Sha2_384 = "530338f9e56c1c3c872df925468eae047f48fb8955d5da37b81e0879fff53927cbc64fb7f1b65316b203207c8a72b5bc", + Sha2_512 = "7635d618e14800a3c2c27b614c446baf09ea08ae64a087cd8218fc72b385d99d59a8940c7cacd67bafc0ef9e4da964e0626c5e3c30e83df7d9577198b61111d2", + Sha3_224 = "b5b7b2369667f84128c345ce1e6c275e5a1ab13a5b3f6e3ee3518c8a", + Sha3_256 = "182a8bf1ec6e1f733b021fdce87be2b95b1b092673c0513f3219e1fb4a78210c", + Sha3_384 = "bd70cb9ffd007619e812e6fe58a2936f9feb9c437ccd18c41985c10c3b19ba70c6b4b0a1ed6f5fe029bebfa2d8bcfc0d", + Sha3_512 = "ae3a6eecb8b93e93e7406a4758717b2745575be72a7f5ce5ca66d6816d2cbea7bb3cb41d6746a1a6aef2887aa8ffa1d2bf68b11ccd4645d23dfd55c53683e567" }, new HashTestCase { - Input = "Exactly 4000 bytes: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijkl", + Message = "Exactly 4000 bytes: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijkl", + Md2 = "518453006c8c5a4f389d722322186099", + Md4 = "a273308cf00e3b57839733972abeefd3", + Md5 = "2f5d1fb0a5a7281d92333b1012719965", Sha0 = "52412e546d2a96d55e619c3a80d436e4a2fd5482", Sha1 = "e8b1acd9e623d51b9d4fbc84bd35e81bd2d617fa", - Sha256 = "f86ede611091b7762241505eb71ebb0bc614e022ceae2a78172cb93c4921d25d", - Sha384 = "6fd286c643d5c59b65d03633f44936e024bf65bfc39c92083467472eecc685f2f036b591226e6cb72b2569d5770f343b", - Sha512 = "09ce524502636f4e13dfe80f94192842682ed695d3c0745b3379fc67390ad87f30e551cdcdf5cfab2958442fb8f540e73f540cb1f778cbd88569ab75983f7bd6" + Sha2_224 = "71472f8c256039f6387368edfcd5d252d67424619b6591a91bf57431", + Sha2_256 = "f86ede611091b7762241505eb71ebb0bc614e022ceae2a78172cb93c4921d25d", + Sha2_384 = "6fd286c643d5c59b65d03633f44936e024bf65bfc39c92083467472eecc685f2f036b591226e6cb72b2569d5770f343b", + Sha2_512 = "09ce524502636f4e13dfe80f94192842682ed695d3c0745b3379fc67390ad87f30e551cdcdf5cfab2958442fb8f540e73f540cb1f778cbd88569ab75983f7bd6", + Sha3_224 = "5fd5544120471c3b9835be4c0ae8907013519037b3610829d8c52e46", + Sha3_256 = "9a009840759539dacecaa8d2663ecedc2ce32f0a6e3799131d5a04fcb390814e", + Sha3_384 = "074b44ee6e3bd3ec395a7dfc312685d697db43c74dde92ff746487e10846eae10081281074230f9606c0adb6337223bd", + Sha3_512 = "088af132aebab984dc4d0c978faff16a987cedd52f0059ba9a87c9c92cfbac41b6d7c5cee0c91e16d800a65d55bbc2a8d6ba52ad1a166e31e905aaf0a040e7dc" }, new HashTestCase { - Input = "Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battlefield of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we can not dedicate--we can not consecrate--we can not hallow--this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us--that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion--that we here highly resolve that these dead shall not have died in vain--that this nation, under God, shall have a new birth of freedom--and that government of the people, by the people, for the people, shall not perish from the earth. -- President Abraham Lincoln, November 19, 1863", + Message = "Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battlefield of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we can not dedicate--we can not consecrate--we can not hallow--this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us--that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion--that we here highly resolve that these dead shall not have died in vain--that this nation, under God, shall have a new birth of freedom--and that government of the people, by the people, for the people, shall not perish from the earth. -- President Abraham Lincoln, November 19, 1863", + Md2 = "58bacf68f1f8ed5a3515ae0607b3b511", + Md4 = "50385e2a1f0b9869040a289eff3abff2", + Md5 = "43696c3abe0610e776cde9bf4c052421", Sha0 = "54a84ee72093c6265e264cdb0127a5b2334f19c8", Sha1 = "3728b3fd827fe2bfd0900e0586a03ffd3394e647", - Sha256 = "4d25fccf8752ce470a58cd21d90939b7eb25f3fa418dd2da4c38288ea561e600", - Sha384 = "69cc75b95280bdd9e154e743903e37b1205aa382e92e051b1f48a6db9d0203f8a17c1762d46887037275606932d3381e", - Sha512 = "23450737795d2f6a13aa61adcca0df5eef6df8d8db2b42cd2ca8f783734217a73e9cabc3c9b8a8602f8aeaeb34562b6b1286846060f9809b90286b3555751f09" + Sha2_224 = "62a41ab0961bcdd22db70b896db3955c1d04096af6de47f5aaad1226", + Sha2_256 = "4d25fccf8752ce470a58cd21d90939b7eb25f3fa418dd2da4c38288ea561e600", + Sha2_384 = "69cc75b95280bdd9e154e743903e37b1205aa382e92e051b1f48a6db9d0203f8a17c1762d46887037275606932d3381e", + Sha2_512 = "23450737795d2f6a13aa61adcca0df5eef6df8d8db2b42cd2ca8f783734217a73e9cabc3c9b8a8602f8aeaeb34562b6b1286846060f9809b90286b3555751f09", + Sha3_224 = "6ac187368fc334e8c774c89f7e5f34eda94e921e2ac021a48dae9fca", + Sha3_256 = "9b50251ac0a8cbadc9aaf2596932443cc2f33f11d79c3ef2a67dd7c867c0e71b", + Sha3_384 = "6ca40c91ca4f4ba8bc530cc7dcd69d9bcc891fa58692a0e0700f4a7e3945d8c9940f1071d2f8b4ad47c5c8cb9f304e1d", + Sha3_512 = "d889af1035efe42795a971a2d4da562574b0e00353179086a0d8d21fa65517def799a19f2d4d9dbd810cb7969fe73fe4ab8597fef7d04e98b3ab64b3bee4237c" } }; } internal record HashTestCase { - public string Input { get; init; } = default!; + public string Message { get; init; } = default!; + + public string Md2 { get; init; } = default!; + + public string Md4 { get; init; } = default!; + + public string Md5 { get; init; } = default!; public string Sha0 { get; init; } = default!; public string Sha1 { get; init; } = default!; - public string Sha256 { get; init; } = default!; + public string Sha2_224 { get; init; } = default!; + + public string Sha2_256 { get; init; } = default!; + + public string Sha2_384 { get; init; } = default!; + + public string Sha2_512 { get; init; } = default!; + + public string Sha3_224 { get; init; } = default!; + + public string Sha3_256 { get; init; } = default!; - public string Sha384 { get; init; } = default!; + public string Sha3_384 { get; init; } = default!; - public string Sha512 { get; init; } = default!; + public string Sha3_512 { get; init; } = default!; } } } diff --git a/src/acryptohashnet.UnitTests/SHA/Sha2FamilyTests.cs b/src/acryptohashnet.UnitTests/SHA/Sha2FamilyTests.cs new file mode 100644 index 0000000..73b842f --- /dev/null +++ b/src/acryptohashnet.UnitTests/SHA/Sha2FamilyTests.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using System.Linq; + +using NUnit.Framework; + +namespace acryptohashnet.UnitTests +{ + [TestFixture] + internal class Sha2FamilyTests + { + [TestCaseSource(nameof(Sha2_224Cases))] + public void SHA224(string input, string expected) + { + var actual = new SHA224().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha2_224Cases))] + public void Sha2_224(string input, string expected) + { + var actual = new Sha2_224().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha2_256Cases))] + public void SHA256(string input, string expected) + { + var actual = new SHA256().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha2_256Cases))] + public void Sha2_256(string input, string expected) + { + var actual = new Sha2_256().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha2_384Cases))] + public void SHA384(string input, string expected) + { + var actual = new SHA384().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha2_384Cases))] + public void Sha2_384(string input, string expected) + { + var actual = new Sha2_384().ComputeHash(input.GetUtf8Bytes()).ToHexString(); ; + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha2_512Cases))] + public void SHA512(string input, string expected) + { + var actual = new SHA512().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha2_512Cases))] + public void Sha2_512(string input, string expected) + { + var actual = new Sha2_512().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + + static IEnumerable Sha2_224Cases = SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha2_224 }); + + static IEnumerable Sha2_256Cases = SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha2_256 }); + + static IEnumerable Sha2_384Cases = SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha2_384 }); + + static IEnumerable Sha2_512Cases = SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha2_512 }); + } +} diff --git a/src/acryptohashnet.UnitTests/SHA/Sha3FamilyTests.cs b/src/acryptohashnet.UnitTests/SHA/Sha3FamilyTests.cs new file mode 100644 index 0000000..1d49ef1 --- /dev/null +++ b/src/acryptohashnet.UnitTests/SHA/Sha3FamilyTests.cs @@ -0,0 +1,48 @@ +using NUnit.Framework; + +using System.Collections.Generic; +using System.Linq; + +namespace acryptohashnet.UnitTests +{ + [TestFixture] + public class Sha3FamilyTests + { + [TestCaseSource(nameof(Sha3_224Cases))] + public void Sha3_224(string input, string expected) + { + var actual = new Sha3_224().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha3_256Cases))] + public void Sha3_256(string input, string expected) + { + var actual = new Sha3_256().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha3_384Cases))] + public void Sha3_384(string input, string expected) + { + var actual = new Sha3_384().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + [TestCaseSource(nameof(Sha3_512Cases))] + public void Sha3_512(string input, string expected) + { + var actual = new Sha3_512().ComputeHash(input.GetUtf8Bytes()).ToHexString(); + Assert.That(actual, Is.EqualTo(expected)); + } + + + static IEnumerable Sha3_224Cases = SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha3_224 }); + + static IEnumerable Sha3_256Cases = SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha3_256 }); + + static IEnumerable Sha3_384Cases = SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha3_384 }); + + static IEnumerable Sha3_512Cases = SHAFamilyTestCases.All().Select(x => new object[] { x.Message, x.Sha3_512 }); + } +} diff --git a/src/acryptohashnet.UnitTests/StringUtils.cs b/src/acryptohashnet.UnitTests/StringUtils.cs index 22e9d66..3b472d7 100644 --- a/src/acryptohashnet.UnitTests/StringUtils.cs +++ b/src/acryptohashnet.UnitTests/StringUtils.cs @@ -1,13 +1,13 @@ using System; using System.Linq; +using System.Text; namespace acryptohashnet.UnitTests { internal static class StringUtils { - public static string ToHexString(this byte[] bytes) - { - return string.Join("", bytes.Select(x => x.ToString("x2"))); - } + public static byte[] GetUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); + + public static string ToHexString(this byte[] bytes) => string.Join("", bytes.Select(x => x.ToString("x2"))); } } diff --git a/src/acryptohashnet.UnitTests/Tiger/Tiger2Tests.cs b/src/acryptohashnet.UnitTests/Tiger/Tiger2Tests.cs index cf1a66d..9521416 100644 --- a/src/acryptohashnet.UnitTests/Tiger/Tiger2Tests.cs +++ b/src/acryptohashnet.UnitTests/Tiger/Tiger2Tests.cs @@ -34,9 +34,9 @@ public void TestCase_1_million_times_a() message[ii] = (byte)'a'; } - Assert.AreEqual( - "e068281f060f551628cc5715b9d0226796914d45f7717cf4", - new Tiger2().ComputeHash(message).ToHexString()); + Assert.That( + new Tiger2().ComputeHash(message).ToHexString(), + Is.EqualTo("e068281f060f551628cc5715b9d0226796914d45f7717cf4")); } } } diff --git a/src/acryptohashnet.UnitTests/Tiger/TigerTests.cs b/src/acryptohashnet.UnitTests/Tiger/TigerTests.cs index be37c1e..ef7fd85 100644 --- a/src/acryptohashnet.UnitTests/Tiger/TigerTests.cs +++ b/src/acryptohashnet.UnitTests/Tiger/TigerTests.cs @@ -34,9 +34,9 @@ public void TestCase_1_million_times_a() message[ii] = (byte)'a'; } - Assert.AreEqual( - "6db0e2729cbead93d715c6a7d36302e9b3cee0d2bc314b41", - new Tiger().ComputeHash(message).ToHexString()); + Assert.That( + new Tiger().ComputeHash(message).ToHexString(), + Is.EqualTo("6db0e2729cbead93d715c6a7d36302e9b3cee0d2bc314b41")); } [Test] @@ -49,9 +49,9 @@ public void TestString_64Kb() message[ii] = (byte)(ii & 0xff); } - Assert.AreEqual( - "fdf4f5b35139f48e710e421be5af411de1a8aac333f26204", - new Tiger().ComputeHash(message).ToHexString()); + Assert.That( + new Tiger().ComputeHash(message).ToHexString(), + Is.EqualTo("fdf4f5b35139f48e710e421be5af411de1a8aac333f26204")); } } } diff --git a/src/acryptohashnet.UnitTests/acryptohashnet.UnitTests.csproj b/src/acryptohashnet.UnitTests/acryptohashnet.UnitTests.csproj index 4bd8c9b..6663b8d 100644 --- a/src/acryptohashnet.UnitTests/acryptohashnet.UnitTests.csproj +++ b/src/acryptohashnet.UnitTests/acryptohashnet.UnitTests.csproj @@ -1,15 +1,15 @@  - net6.0 + net8.0 enable Major - - - + + + diff --git a/src/acryptohashnet/SHA/Keccak.cs b/src/acryptohashnet/SHA/Keccak.cs new file mode 100644 index 0000000..f9259d0 --- /dev/null +++ b/src/acryptohashnet/SHA/Keccak.cs @@ -0,0 +1,174 @@ +using System; + +namespace acryptohashnet +{ + internal static class Keccak + { + private static readonly ulong[] RoundConstants = new ulong[24] + { + 0x0000_0000_0000_0001, 0x0000_0000_0000_8082, 0x8000_0000_0000_808a, 0x8000_0000_8000_8000, + 0x0000_0000_0000_808b, 0x0000_0000_8000_0001, 0x8000_0000_8000_8081, 0x8000_0000_0000_8009, + 0x0000_0000_0000_008a, 0x0000_0000_0000_0088, 0x0000_0000_8000_8009, 0x0000_0000_8000_000a, + 0x0000_0000_8000_808b, 0x8000_0000_0000_008b, 0x8000_0000_0000_8089, 0x8000_0000_0000_8003, + 0x8000_0000_0000_8002, 0x8000_0000_0000_0080, 0x0000_0000_0000_800a, 0x8000_0000_8000_000a, + 0x8000_0000_8000_8081, 0x8000_0000_0000_8080, 0x0000_0000_8000_0001, 0x8000_0000_8000_8008 + }; + public static void Permute(Span state) + { + if (state.Length < 25) + { + throw new InvalidOperationException("State should be exactly 25 elements."); + } + + // w is 64 == sizeof(ulong) + // 0 <= x < 5, 0 <= y < 5, 0 <= z < w + // A is [5 x 5 x w] + // A[x, y, z] = State[ w * (5y + x) + z ] + + ulong temp0; + ulong temp1; + ulong temp2; + ulong temp3; + ulong temp4; + + for (int round = 0; round < RoundConstants.Length; round += 1) + { + // ### Theta + + { + // For all pairs (x, z) such that 0 ≤ x < 5 and 0 ≤ z < w, let + // C[x, z] = A[x, 0, z] ^ A[x, 1, z] ^ A[x, 2, z] ^ A[x, 3, z] ^ A[x, 4, z]. + + temp0 = state[0] ^ state[5] ^ state[10] ^ state[15] ^ state[20]; + temp1 = state[1] ^ state[6] ^ state[11] ^ state[16] ^ state[21]; + temp2 = state[2] ^ state[7] ^ state[12] ^ state[17] ^ state[22]; + temp3 = state[3] ^ state[8] ^ state[13] ^ state[18] ^ state[23]; + temp4 = state[4] ^ state[9] ^ state[14] ^ state[19] ^ state[24]; + + // For all triples (x, y, z) such that 0 ≤ x < 5, 0 ≤ y < 5, and 0 ≤ z < w, let + // A′[x, y, z] = A[x, y, z] ^ D[x, z]. + + // For all pairs (x, z) such that 0 ≤ x < 5 and 0 ≤ z < w let + // D[x, z] = C[(x - 1) mod 5, z] ^ C[(x + 1) mod 5, (z – 1) mod w]. + + // For all triples (x, y, z) such that 0 ≤ x < 5, 0 ≤ y < 5, and 0 ≤ z < w, let + // A′[x, y, z] = A[x, y, z] ^ D[x, z]. + ulong d; + + d = temp4 ^ temp1.RotateLeft(1); + state[0] ^= d; state[5] ^= d; state[10] ^= d; state[15] ^= d; state[20] ^= d; + + d = temp0 ^ temp2.RotateLeft(1); + state[1] ^= d; state[6] ^= d; state[11] ^= d; state[16] ^= d; state[21] ^= d; + + d = temp1 ^ temp3.RotateLeft(1); + state[2] ^= d; state[7] ^= d; state[12] ^= d; state[17] ^= d; state[22] ^= d; + + d = temp2 ^ temp4.RotateLeft(1); + state[3] ^= d; state[8] ^= d; state[13] ^= d; state[18] ^= d; state[23] ^= d; + + d = temp3 ^ temp0.RotateLeft(1); + state[4] ^= d; state[9] ^= d; state[14] ^= d; state[19] ^= d; state[24] ^= d; + } + + // ### Rho + Pi (combined steps with predcalculated indexes) + + // Rho: + // For all z such that 0 ≤ z < w, let A′ [0, 0, z] = A[0, 0, z]. + // Let (x, y) = (1, 0). + // For t from 0 to 23: + // for all z such that 0 ≤ z < w, let A′[x, y, z] = A[x, y, (z – (t + 1)(t + 2)/2) mod w]; + // let (x, y) = (y, (2x + 3y) mod 5). + // End For + + // Pi: + // For all triples (x, y, z) such that 0 ≤ x < 5, 0 ≤ y < 5, and 0 ≤ z < w, let + // A′[x, y, z] = A[(x + 3y) mod 5, x, z]. + { + // Precalculated indexes are + // piExchanges: + // 10, 07, 11, 17, 18, 03, 05, 16, 08, 21, 24, 04, 15, 23, 19, 13, 12, 02, 20, 14, 22, 09, 06, 01 + // RhoRotations: + // 01, 03, 06, 10, 15, 21, 28, 36, 45, 55, 02, 14, 27, 41, 56, 08, 25, 43, 62, 18, 39, 61, 20, 44 + + ulong nextState = state[1]; + temp0 = state[10]; state[10] = nextState.RotateLeft(01); nextState = temp0; + temp0 = state[07]; state[07] = nextState.RotateLeft(03); nextState = temp0; + temp0 = state[11]; state[11] = nextState.RotateLeft(06); nextState = temp0; + temp0 = state[17]; state[17] = nextState.RotateLeft(10); nextState = temp0; + temp0 = state[18]; state[18] = nextState.RotateLeft(15); nextState = temp0; + temp0 = state[03]; state[03] = nextState.RotateLeft(21); nextState = temp0; + temp0 = state[05]; state[05] = nextState.RotateLeft(28); nextState = temp0; + temp0 = state[16]; state[16] = nextState.RotateLeft(36); nextState = temp0; + temp0 = state[08]; state[08] = nextState.RotateLeft(45); nextState = temp0; + temp0 = state[21]; state[21] = nextState.RotateLeft(55); nextState = temp0; + temp0 = state[24]; state[24] = nextState.RotateLeft(02); nextState = temp0; + temp0 = state[04]; state[04] = nextState.RotateLeft(14); nextState = temp0; + temp0 = state[15]; state[15] = nextState.RotateLeft(27); nextState = temp0; + temp0 = state[23]; state[23] = nextState.RotateLeft(41); nextState = temp0; + temp0 = state[19]; state[19] = nextState.RotateLeft(56); nextState = temp0; + temp0 = state[13]; state[13] = nextState.RotateLeft(08); nextState = temp0; + temp0 = state[12]; state[12] = nextState.RotateLeft(25); nextState = temp0; + temp0 = state[02]; state[02] = nextState.RotateLeft(43); nextState = temp0; + temp0 = state[20]; state[20] = nextState.RotateLeft(62); nextState = temp0; + temp0 = state[14]; state[14] = nextState.RotateLeft(18); nextState = temp0; + temp0 = state[22]; state[22] = nextState.RotateLeft(39); nextState = temp0; + temp0 = state[09]; state[09] = nextState.RotateLeft(61); nextState = temp0; + temp0 = state[06]; state[06] = nextState.RotateLeft(20); nextState = temp0; + temp0 = state[01]; state[01] = nextState.RotateLeft(44); nextState = temp0; + } + + // ### Chi + + // For all triples (x, y, z) such that 0 ≤ x < 5, 0 ≤ y < 5, and 0 ≤ z < w, let + // A′ [x, y, z] = A[x, y, z] ^ ( ~A[(x + 1) mod 5, y, z] & A[(x + 2) mod 5, y, z] ). + { + temp0 = state[0]; temp1 = state[1]; temp2 = state[2]; temp3 = state[3]; temp4 = state[4]; + + state[0] ^= ~temp1 & temp2; + state[1] ^= ~temp2 & temp3; + state[2] ^= ~temp3 & temp4; + state[3] ^= ~temp4 & temp0; + state[4] ^= ~temp0 & temp1; + + temp0 = state[5]; temp1 = state[6]; temp2 = state[7]; temp3 = state[8]; temp4 = state[9]; + + state[5] ^= ~temp1 & temp2; + state[6] ^= ~temp2 & temp3; + state[7] ^= ~temp3 & temp4; + state[8] ^= ~temp4 & temp0; + state[9] ^= ~temp0 & temp1; + + temp0 = state[10]; temp1 = state[11]; temp2 = state[12]; temp3 = state[13]; temp4 = state[14]; + + state[10] ^= ~temp1 & temp2; + state[11] ^= ~temp2 & temp3; + state[12] ^= ~temp3 & temp4; + state[13] ^= ~temp4 & temp0; + state[14] ^= ~temp0 & temp1; + + temp0 = state[15]; temp1 = state[16]; temp2 = state[17]; temp3 = state[18]; temp4 = state[19]; + + state[15] ^= ~temp1 & temp2; + state[16] ^= ~temp2 & temp3; + state[17] ^= ~temp3 & temp4; + state[18] ^= ~temp4 & temp0; + state[19] ^= ~temp0 & temp1; + + temp0 = state[20]; temp1 = state[21]; temp2 = state[22]; temp3 = state[23]; temp4 = state[24]; + + state[20] ^= ~temp1 & temp2; + state[21] ^= ~temp2 & temp3; + state[22] ^= ~temp3 & temp4; + state[23] ^= ~temp4 & temp0; + state[24] ^= ~temp0 & temp1; + } + + // ### Iota + + // For all z such that 0 ≤ z < w, let A′ [0, 0, z] = A′ [0, 0, z] ^ RC[z]. + state[0] ^= RoundConstants[round]; + } + } + } +} diff --git a/src/acryptohashnet/SHA/SHA1.cs b/src/acryptohashnet/SHA/SHA1.cs index 15662ad..49c6134 100644 --- a/src/acryptohashnet/SHA/SHA1.cs +++ b/src/acryptohashnet/SHA/SHA1.cs @@ -46,7 +46,7 @@ protected override void ProcessBlock(ReadOnlySpan block) { uint x = buffer[ii - 3] ^ buffer[ii - 8] ^ buffer[ii - 14] ^ buffer[ii - 16]; // added in sha-1 - buffer[ii] = x << 1 | x >> 31; + buffer[ii] = x.RotateLeft(1); } uint a = state.A; diff --git a/src/acryptohashnet/SHA/SHA224.cs b/src/acryptohashnet/SHA/SHA224.cs new file mode 100644 index 0000000..813bdad --- /dev/null +++ b/src/acryptohashnet/SHA/SHA224.cs @@ -0,0 +1,171 @@ +using System; +using System.Runtime.CompilerServices; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS 180-4: Secure Hash Standard (SHS) + /// This is an alias of . + /// It's provided only for backward compatibility with acryptohashnet < 3.0 and .Net Framework naming scheme. + /// + public sealed class SHA224 : BlockHashAlgorithm + { + private static readonly uint[] Constants = new uint[64] + { + // round 1 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + // round 2 + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + // round 3 + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + // round 4 + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + // round 5 + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + // round 6 + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + // round 7 + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + // round 8 + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + private readonly HashState state = new HashState(); + + private readonly uint[] buffer = new uint[64]; + + public SHA224() : base(64) + { + PaddingType = PaddingType.OneZeroFillAnd8BytesMessageLengthBigEndian; + } + + public override void Initialize() + { + base.Initialize(); + state.Initialize(); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + // Fill buffer for transformation + BigEndian.Copy(block, buffer.AsSpan(0, 16)); + + for (int ii = 16; ii < buffer.Length; ii++) + { + buffer[ii] = SHAFunctions32.Ro1(buffer[ii - 2]) + buffer[ii - 7] + SHAFunctions32.Ro0(buffer[ii - 15]) + buffer[ii - 16]; + } + + uint a = state.A; + uint b = state.B; + uint c = state.C; + uint d = state.D; + uint e = state.E; + uint f = state.F; + uint g = state.G; + uint h = state.H; + + for (int ii = 0; ii < buffer.Length - 7; ii += 8) + { + // step 1 + h += buffer[ii + 0] + Constants[ii + 0] + SHAFunctions32.Ch(e, f, g) + SHAFunctions32.Sig1(e); + d += h; + h += SHAFunctions32.Maj(a, b, c) + SHAFunctions32.Sig0(a); + + // step 2 + g += buffer[ii + 1] + Constants[ii + 1] + SHAFunctions32.Ch(d, e, f) + SHAFunctions32.Sig1(d); + c += g; + g += SHAFunctions32.Maj(h, a, b) + SHAFunctions32.Sig0(h); + + // step 3 + f += buffer[ii + 2] + Constants[ii + 2] + SHAFunctions32.Ch(c, d, e) + SHAFunctions32.Sig1(c); + b += f; + f += SHAFunctions32.Maj(g, h, a) + SHAFunctions32.Sig0(g); + + // step 4 + e += buffer[ii + 3] + Constants[ii + 3] + SHAFunctions32.Ch(b, c, d) + SHAFunctions32.Sig1(b); + a += e; + e += SHAFunctions32.Maj(f, g, h) + SHAFunctions32.Sig0(f); + + // step 5 + d += buffer[ii + 4] + Constants[ii + 4] + SHAFunctions32.Ch(a, b, c) + SHAFunctions32.Sig1(a); + h += d; + d += SHAFunctions32.Maj(e, f, g) + SHAFunctions32.Sig0(e); + + // step 6 + c += buffer[ii + 5] + Constants[ii + 5] + SHAFunctions32.Ch(h, a, b) + SHAFunctions32.Sig1(h); + g += c; + c += SHAFunctions32.Maj(d, e, f) + SHAFunctions32.Sig0(d); + + // step 7 + b += buffer[ii + 6] + Constants[ii + 6] + SHAFunctions32.Ch(g, h, a) + SHAFunctions32.Sig1(g); + f += b; + b += SHAFunctions32.Maj(c, d, e) + SHAFunctions32.Sig0(c); + + // step 8 + a += buffer[ii + 7] + Constants[ii + 7] + SHAFunctions32.Ch(f, g, h) + SHAFunctions32.Sig1(f); + e += a; + a += SHAFunctions32.Maj(b, c, d) + SHAFunctions32.Sig0(b); + } + + state.A += a; + state.B += b; + state.C += c; + state.D += d; + state.E += e; + state.F += f; + state.G += g; + state.H += h; + } + + protected override byte[] ProcessFinalBlock() + { + return state.ToByteArray(); + } + + private sealed class HashState + { + public uint A; + public uint B; + public uint C; + public uint D; + public uint E; + public uint F; + public uint G; + public uint H; + + public HashState() + { + Initialize(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize() + { + A = 0xc1059ed8; + B = 0x367cd507; + C = 0x3070dd17; + D = 0xf70e5939; + E = 0xffc00b31; + F = 0x68581511; + G = 0x64f98fa7; + H = 0xbefa4fa4; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte[] ToByteArray() + { + var result = new byte[28]; + + BigEndian.Copy(A, result); + BigEndian.Copy(B, result.AsSpan(4)); + BigEndian.Copy(C, result.AsSpan(8)); + BigEndian.Copy(D, result.AsSpan(12)); + BigEndian.Copy(E, result.AsSpan(16)); + BigEndian.Copy(F, result.AsSpan(20)); + BigEndian.Copy(G, result.AsSpan(24)); + + return result; + } + } + } +} diff --git a/src/acryptohashnet/SHA/SHA256.cs b/src/acryptohashnet/SHA/SHA256.cs index e861bc6..31bdc21 100644 --- a/src/acryptohashnet/SHA/SHA256.cs +++ b/src/acryptohashnet/SHA/SHA256.cs @@ -5,6 +5,8 @@ namespace acryptohashnet { /// /// Defined by FIPS 180-4: Secure Hash Standard (SHS) + /// This is an alias of . + /// It's provided only for backward compatibility with acryptohashnet < 3.0 and .Net Framework naming scheme. /// public sealed class SHA256 : BlockHashAlgorithm { diff --git a/src/acryptohashnet/SHA/SHA384.cs b/src/acryptohashnet/SHA/SHA384.cs index 4708e12..9354c16 100644 --- a/src/acryptohashnet/SHA/SHA384.cs +++ b/src/acryptohashnet/SHA/SHA384.cs @@ -5,6 +5,8 @@ namespace acryptohashnet { /// /// Defined by FIPS 180-4: Secure Hash Standard (SHS) + /// This is an alias of . + /// It's provided only for backward compatibility with acryptohashnet < 3.0 and .Net Framework naming scheme. /// public sealed class SHA384 : BlockHashAlgorithm { @@ -41,7 +43,7 @@ public sealed class SHA384 : BlockHashAlgorithm 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 }; - + private readonly HashState state = new HashState(); private readonly ulong[] buffer = new ulong[80]; @@ -176,8 +178,6 @@ public byte[] ToByteArray() BigEndian.Copy(D, result.AsSpan(24)); BigEndian.Copy(E, result.AsSpan(32)); BigEndian.Copy(F, result.AsSpan(40)); - // BigEndian.Copy(G, result.AsSpan(48)); - // BigEndian.Copy(H, result.AsSpan(56)); return result; } diff --git a/src/acryptohashnet/SHA/SHA512.cs b/src/acryptohashnet/SHA/SHA512.cs index 89a87fa..42ccd3e 100644 --- a/src/acryptohashnet/SHA/SHA512.cs +++ b/src/acryptohashnet/SHA/SHA512.cs @@ -5,6 +5,8 @@ namespace acryptohashnet { /// /// Defined by FIPS 180-4: Secure Hash Standard (SHS) + /// This is an alias of . + /// It's provided only for backward compatibility with acryptohashnet < 3.0 and .Net Framework naming scheme. /// public sealed class SHA512 : BlockHashAlgorithm { diff --git a/src/acryptohashnet/SHA/Sha2_224.cs b/src/acryptohashnet/SHA/Sha2_224.cs new file mode 100644 index 0000000..308445f --- /dev/null +++ b/src/acryptohashnet/SHA/Sha2_224.cs @@ -0,0 +1,169 @@ +using System; +using System.Runtime.CompilerServices; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS 180-4: Secure Hash Standard (SHS) + /// + public sealed class Sha2_224 : BlockHashAlgorithm + { + private static readonly uint[] Constants = new uint[64] + { + // round 1 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + // round 2 + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + // round 3 + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + // round 4 + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + // round 5 + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + // round 6 + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + // round 7 + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + // round 8 + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + private readonly HashState state = new HashState(); + + private readonly uint[] buffer = new uint[64]; + + public Sha2_224() : base(64) + { + PaddingType = PaddingType.OneZeroFillAnd8BytesMessageLengthBigEndian; + } + + public override void Initialize() + { + base.Initialize(); + state.Initialize(); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + // Fill buffer for transformation + BigEndian.Copy(block, buffer.AsSpan(0, 16)); + + for (int ii = 16; ii < buffer.Length; ii++) + { + buffer[ii] = SHAFunctions32.Ro1(buffer[ii - 2]) + buffer[ii - 7] + SHAFunctions32.Ro0(buffer[ii - 15]) + buffer[ii - 16]; + } + + uint a = state.A; + uint b = state.B; + uint c = state.C; + uint d = state.D; + uint e = state.E; + uint f = state.F; + uint g = state.G; + uint h = state.H; + + for (int ii = 0; ii < buffer.Length - 7; ii += 8) + { + // step 1 + h += buffer[ii + 0] + Constants[ii + 0] + SHAFunctions32.Ch(e, f, g) + SHAFunctions32.Sig1(e); + d += h; + h += SHAFunctions32.Maj(a, b, c) + SHAFunctions32.Sig0(a); + + // step 2 + g += buffer[ii + 1] + Constants[ii + 1] + SHAFunctions32.Ch(d, e, f) + SHAFunctions32.Sig1(d); + c += g; + g += SHAFunctions32.Maj(h, a, b) + SHAFunctions32.Sig0(h); + + // step 3 + f += buffer[ii + 2] + Constants[ii + 2] + SHAFunctions32.Ch(c, d, e) + SHAFunctions32.Sig1(c); + b += f; + f += SHAFunctions32.Maj(g, h, a) + SHAFunctions32.Sig0(g); + + // step 4 + e += buffer[ii + 3] + Constants[ii + 3] + SHAFunctions32.Ch(b, c, d) + SHAFunctions32.Sig1(b); + a += e; + e += SHAFunctions32.Maj(f, g, h) + SHAFunctions32.Sig0(f); + + // step 5 + d += buffer[ii + 4] + Constants[ii + 4] + SHAFunctions32.Ch(a, b, c) + SHAFunctions32.Sig1(a); + h += d; + d += SHAFunctions32.Maj(e, f, g) + SHAFunctions32.Sig0(e); + + // step 6 + c += buffer[ii + 5] + Constants[ii + 5] + SHAFunctions32.Ch(h, a, b) + SHAFunctions32.Sig1(h); + g += c; + c += SHAFunctions32.Maj(d, e, f) + SHAFunctions32.Sig0(d); + + // step 7 + b += buffer[ii + 6] + Constants[ii + 6] + SHAFunctions32.Ch(g, h, a) + SHAFunctions32.Sig1(g); + f += b; + b += SHAFunctions32.Maj(c, d, e) + SHAFunctions32.Sig0(c); + + // step 8 + a += buffer[ii + 7] + Constants[ii + 7] + SHAFunctions32.Ch(f, g, h) + SHAFunctions32.Sig1(f); + e += a; + a += SHAFunctions32.Maj(b, c, d) + SHAFunctions32.Sig0(b); + } + + state.A += a; + state.B += b; + state.C += c; + state.D += d; + state.E += e; + state.F += f; + state.G += g; + state.H += h; + } + + protected override byte[] ProcessFinalBlock() + { + return state.ToByteArray(); + } + + private sealed class HashState + { + public uint A; + public uint B; + public uint C; + public uint D; + public uint E; + public uint F; + public uint G; + public uint H; + + public HashState() + { + Initialize(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize() + { + A = 0xc1059ed8; + B = 0x367cd507; + C = 0x3070dd17; + D = 0xf70e5939; + E = 0xffc00b31; + F = 0x68581511; + G = 0x64f98fa7; + H = 0xbefa4fa4; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte[] ToByteArray() + { + var result = new byte[28]; + + BigEndian.Copy(A, result); + BigEndian.Copy(B, result.AsSpan(4)); + BigEndian.Copy(C, result.AsSpan(8)); + BigEndian.Copy(D, result.AsSpan(12)); + BigEndian.Copy(E, result.AsSpan(16)); + BigEndian.Copy(F, result.AsSpan(20)); + BigEndian.Copy(G, result.AsSpan(24)); + + return result; + } + } + } +} diff --git a/src/acryptohashnet/SHA/Sha2_256.cs b/src/acryptohashnet/SHA/Sha2_256.cs new file mode 100644 index 0000000..2038188 --- /dev/null +++ b/src/acryptohashnet/SHA/Sha2_256.cs @@ -0,0 +1,170 @@ +using System; +using System.Runtime.CompilerServices; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS 180-4: Secure Hash Standard (SHS) + /// + public sealed class Sha2_256 : BlockHashAlgorithm + { + private static readonly uint[] Constants = new uint[64] + { + // round 1 + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + // round 2 + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + // round 3 + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + // round 4 + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + // round 5 + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + // round 6 + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + // round 7 + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + // round 8 + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + private readonly HashState state = new HashState(); + + private readonly uint[] buffer = new uint[64]; + + public Sha2_256() : base(64) + { + PaddingType = PaddingType.OneZeroFillAnd8BytesMessageLengthBigEndian; + } + + public override void Initialize() + { + base.Initialize(); + state.Initialize(); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + // Fill buffer for transformation + BigEndian.Copy(block, buffer.AsSpan(0, 16)); + + for (int ii = 16; ii < buffer.Length; ii++) + { + buffer[ii] = SHAFunctions32.Ro1(buffer[ii - 2]) + buffer[ii - 7] + SHAFunctions32.Ro0(buffer[ii - 15]) + buffer[ii - 16]; + } + + uint a = state.A; + uint b = state.B; + uint c = state.C; + uint d = state.D; + uint e = state.E; + uint f = state.F; + uint g = state.G; + uint h = state.H; + + for (int ii = 0; ii < buffer.Length - 7; ii += 8) + { + // step 1 + h += buffer[ii + 0] + Constants[ii + 0] + SHAFunctions32.Ch(e, f, g) + SHAFunctions32.Sig1(e); + d += h; + h += SHAFunctions32.Maj(a, b, c) + SHAFunctions32.Sig0(a); + + // step 2 + g += buffer[ii + 1] + Constants[ii + 1] + SHAFunctions32.Ch(d, e, f) + SHAFunctions32.Sig1(d); + c += g; + g += SHAFunctions32.Maj(h, a, b) + SHAFunctions32.Sig0(h); + + // step 3 + f += buffer[ii + 2] + Constants[ii + 2] + SHAFunctions32.Ch(c, d, e) + SHAFunctions32.Sig1(c); + b += f; + f += SHAFunctions32.Maj(g, h, a) + SHAFunctions32.Sig0(g); + + // step 4 + e += buffer[ii + 3] + Constants[ii + 3] + SHAFunctions32.Ch(b, c, d) + SHAFunctions32.Sig1(b); + a += e; + e += SHAFunctions32.Maj(f, g, h) + SHAFunctions32.Sig0(f); + + // step 5 + d += buffer[ii + 4] + Constants[ii + 4] + SHAFunctions32.Ch(a, b, c) + SHAFunctions32.Sig1(a); + h += d; + d += SHAFunctions32.Maj(e, f, g) + SHAFunctions32.Sig0(e); + + // step 6 + c += buffer[ii + 5] + Constants[ii + 5] + SHAFunctions32.Ch(h, a, b) + SHAFunctions32.Sig1(h); + g += c; + c += SHAFunctions32.Maj(d, e, f) + SHAFunctions32.Sig0(d); + + // step 7 + b += buffer[ii + 6] + Constants[ii + 6] + SHAFunctions32.Ch(g, h, a) + SHAFunctions32.Sig1(g); + f += b; + b += SHAFunctions32.Maj(c, d, e) + SHAFunctions32.Sig0(c); + + // step 8 + a += buffer[ii + 7] + Constants[ii + 7] + SHAFunctions32.Ch(f, g, h) + SHAFunctions32.Sig1(f); + e += a; + a += SHAFunctions32.Maj(b, c, d) + SHAFunctions32.Sig0(b); + } + + state.A += a; + state.B += b; + state.C += c; + state.D += d; + state.E += e; + state.F += f; + state.G += g; + state.H += h; + } + + protected override byte[] ProcessFinalBlock() + { + return state.ToByteArray(); + } + + private sealed class HashState + { + public uint A; + public uint B; + public uint C; + public uint D; + public uint E; + public uint F; + public uint G; + public uint H; + + public HashState() + { + Initialize(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize() + { + A = 0x6a09e667; + B = 0xbb67ae85; + C = 0x3c6ef372; + D = 0xa54ff53a; + E = 0x510e527f; + F = 0x9b05688c; + G = 0x1f83d9ab; + H = 0x5be0cd19; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte[] ToByteArray() + { + var result = new byte[32]; + + BigEndian.Copy(A, result); + BigEndian.Copy(B, result.AsSpan(4)); + BigEndian.Copy(C, result.AsSpan(8)); + BigEndian.Copy(D, result.AsSpan(12)); + BigEndian.Copy(E, result.AsSpan(16)); + BigEndian.Copy(F, result.AsSpan(20)); + BigEndian.Copy(G, result.AsSpan(24)); + BigEndian.Copy(H, result.AsSpan(28)); + + return result; + } + } + } +} diff --git a/src/acryptohashnet/SHA/Sha2_384.cs b/src/acryptohashnet/SHA/Sha2_384.cs new file mode 100644 index 0000000..a3d6ec4 --- /dev/null +++ b/src/acryptohashnet/SHA/Sha2_384.cs @@ -0,0 +1,184 @@ +using System; +using System.Runtime.CompilerServices; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS 180-4: Secure Hash Standard (SHS) + /// + public sealed class Sha2_384 : BlockHashAlgorithm + { + private static readonly ulong[] Constants = new ulong[] + { + // round 1 + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + // round 2 + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + // round 3 + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + // round 4 + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + // round 5 + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + // round 6 + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + // round 7 + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + // round 8 + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + // round 9 + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + // round 10 + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 + }; + + private readonly HashState state = new HashState(); + + private readonly ulong[] buffer = new ulong[80]; + + public Sha2_384() : base(128) + { + HashSizeValue = 384; + PaddingType = PaddingType.OneZeroFillAnd16BytesMessageLengthBigEndian; + } + + public override void Initialize() + { + base.Initialize(); + state.Initialize(); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + // Fill buffer for transformation + BigEndian.Copy(block, buffer.AsSpan(0, 16)); + + // Expand buffer + for (int ii = 16; ii < buffer.Length; ii++) + { + buffer[ii] = SHAFunctions64.Ro1(buffer[ii - 2]) + buffer[ii - 7] + SHAFunctions64.Ro0(buffer[ii - 15]) + buffer[ii - 16]; + } + + ulong a = state.A; + ulong b = state.B; + ulong c = state.C; + ulong d = state.D; + ulong e = state.E; + ulong f = state.F; + ulong g = state.G; + ulong h = state.H; + + for (int ii = 0; ii < buffer.Length - 7 && ii < Constants.Length - 7; ii += 8) + { + // step 1 + h += buffer[ii + 0] + Constants[ii + 0] + SHAFunctions64.Ch(e, f, g) + SHAFunctions64.Sig1(e); + d += h; + h += SHAFunctions64.Maj(a, b, c) + SHAFunctions64.Sig0(a); + + // step 2 + g += buffer[ii + 1] + Constants[ii + 1] + SHAFunctions64.Ch(d, e, f) + SHAFunctions64.Sig1(d); + c += g; + g += SHAFunctions64.Maj(h, a, b) + SHAFunctions64.Sig0(h); + + // step 3 + f += buffer[ii + 2] + Constants[ii + 2] + SHAFunctions64.Ch(c, d, e) + SHAFunctions64.Sig1(c); + b += f; + f += SHAFunctions64.Maj(g, h, a) + SHAFunctions64.Sig0(g); + + // step 4 + e += buffer[ii + 3] + Constants[ii + 3] + SHAFunctions64.Ch(b, c, d) + SHAFunctions64.Sig1(b); + a += e; + e += SHAFunctions64.Maj(f, g, h) + SHAFunctions64.Sig0(f); + + // step 5 + d += buffer[ii + 4] + Constants[ii + 4] + SHAFunctions64.Ch(a, b, c) + SHAFunctions64.Sig1(a); + h += d; + d += SHAFunctions64.Maj(e, f, g) + SHAFunctions64.Sig0(e); + + // step 6 + c += buffer[ii + 5] + Constants[ii + 5] + SHAFunctions64.Ch(h, a, b) + SHAFunctions64.Sig1(h); + g += c; + c += SHAFunctions64.Maj(d, e, f) + SHAFunctions64.Sig0(d); + + // step 7 + b += buffer[ii + 6] + Constants[ii + 6] + SHAFunctions64.Ch(g, h, a) + SHAFunctions64.Sig1(g); + f += b; + b += SHAFunctions64.Maj(c, d, e) + SHAFunctions64.Sig0(c); + + // step 8 + a += buffer[ii + 7] + Constants[ii + 7] + SHAFunctions64.Ch(f, g, h) + SHAFunctions64.Sig1(f); + e += a; + a += SHAFunctions64.Maj(b, c, d) + SHAFunctions64.Sig0(b); + } + + state.A += a; + state.B += b; + state.C += c; + state.D += d; + state.E += e; + state.F += f; + state.G += g; + state.H += h; + } + + protected override byte[] ProcessFinalBlock() + { + return state.ToByteArray(); + } + + private sealed class HashState + { + public ulong A; + public ulong B; + public ulong C; + public ulong D; + public ulong E; + public ulong F; + public ulong G; + public ulong H; + + public HashState() + { + Initialize(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize() + { + A = 0xcbbb9d5dc1059ed8; + B = 0x629a292a367cd507; + C = 0x9159015a3070dd17; + D = 0x152fecd8f70e5939; + E = 0x67332667ffc00b31; + F = 0x8eb44a8768581511; + G = 0xdb0c2e0d64f98fa7; + H = 0x47b5481dbefa4fa4; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte[] ToByteArray() + { + var result = new byte[48]; + + BigEndian.Copy(A, result); + BigEndian.Copy(B, result.AsSpan(8)); + BigEndian.Copy(C, result.AsSpan(16)); + BigEndian.Copy(D, result.AsSpan(24)); + BigEndian.Copy(E, result.AsSpan(32)); + BigEndian.Copy(F, result.AsSpan(40)); + + return result; + } + } + } +} diff --git a/src/acryptohashnet/SHA/Sha2_512.cs b/src/acryptohashnet/SHA/Sha2_512.cs new file mode 100644 index 0000000..d1c7f73 --- /dev/null +++ b/src/acryptohashnet/SHA/Sha2_512.cs @@ -0,0 +1,191 @@ +using System; +using System.Runtime.CompilerServices; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS 180-4: Secure Hash Standard (SHS) + /// + public sealed class Sha2_512 : BlockHashAlgorithm + { + private static readonly ulong[] Constants = new ulong[] + { + // round 1 + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + // round 2 + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + // round 3 + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + // round 4 + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + // round 5 + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + // round 6 + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + // round 7 + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + // round 8 + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + // round 9 + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + // round 10 + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 + }; + + private readonly HashState state = new HashState(); + + private readonly ulong[] buffer = new ulong[80]; + + public Sha2_512() : base(128) + { + PaddingType = PaddingType.OneZeroFillAnd16BytesMessageLengthBigEndian; + } + + public override void Initialize() + { + base.Initialize(); + state.Initialize(); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + BigEndian.Copy(block, buffer.AsSpan(0, 16)); + + // Extend buffer + for (int ii = 16; ii < buffer.Length - 7; ii += 8) + { + buffer[ii + 0] = SHAFunctions64.Ro1(buffer[ii - 2]) + buffer[ii - 7] + SHAFunctions64.Ro0(buffer[ii - 15]) + buffer[ii - 16]; + buffer[ii + 1] = SHAFunctions64.Ro1(buffer[ii - 1]) + buffer[ii - 6] + SHAFunctions64.Ro0(buffer[ii - 14]) + buffer[ii - 15]; + buffer[ii + 2] = SHAFunctions64.Ro1(buffer[ii - 0]) + buffer[ii - 5] + SHAFunctions64.Ro0(buffer[ii - 13]) + buffer[ii - 14]; + buffer[ii + 3] = SHAFunctions64.Ro1(buffer[ii + 1]) + buffer[ii - 4] + SHAFunctions64.Ro0(buffer[ii - 12]) + buffer[ii - 13]; + buffer[ii + 4] = SHAFunctions64.Ro1(buffer[ii + 2]) + buffer[ii - 3] + SHAFunctions64.Ro0(buffer[ii - 11]) + buffer[ii - 12]; + buffer[ii + 5] = SHAFunctions64.Ro1(buffer[ii + 3]) + buffer[ii - 2] + SHAFunctions64.Ro0(buffer[ii - 10]) + buffer[ii - 11]; + buffer[ii + 6] = SHAFunctions64.Ro1(buffer[ii + 4]) + buffer[ii - 1] + SHAFunctions64.Ro0(buffer[ii - 09]) + buffer[ii - 10]; + buffer[ii + 7] = SHAFunctions64.Ro1(buffer[ii + 5]) + buffer[ii - 0] + SHAFunctions64.Ro0(buffer[ii - 08]) + buffer[ii - 09]; + } + + ulong a = state.A; + ulong b = state.B; + ulong c = state.C; + ulong d = state.D; + ulong e = state.E; + ulong f = state.F; + ulong g = state.G; + ulong h = state.H; + + for (int ii = 0; ii < buffer.Length - 7; ii += 8) + { + // step 1 + h += buffer[ii + 0] + Constants[ii + 0] + SHAFunctions64.Ch(e, f, g) + SHAFunctions64.Sig1(e); + d += h; + h += SHAFunctions64.Maj(a, b, c) + SHAFunctions64.Sig0(a); + + // step 2 + g += buffer[ii + 1] + Constants[ii + 1] + SHAFunctions64.Ch(d, e, f) + SHAFunctions64.Sig1(d); + c += g; + g += SHAFunctions64.Maj(h, a, b) + SHAFunctions64.Sig0(h); + + // step 3 + f += buffer[ii + 2] + Constants[ii + 2] + SHAFunctions64.Ch(c, d, e) + SHAFunctions64.Sig1(c); + b += f; + f += SHAFunctions64.Maj(g, h, a) + SHAFunctions64.Sig0(g); + + // step 4 + e += buffer[ii + 3] + Constants[ii + 3] + SHAFunctions64.Ch(b, c, d) + SHAFunctions64.Sig1(b); + a += e; + e += SHAFunctions64.Maj(f, g, h) + SHAFunctions64.Sig0(f); + + // step 5 + d += buffer[ii + 4] + Constants[ii + 4] + SHAFunctions64.Ch(a, b, c) + SHAFunctions64.Sig1(a); + h += d; + d += SHAFunctions64.Maj(e, f, g) + SHAFunctions64.Sig0(e); + + // step 6 + c += buffer[ii + 5] + Constants[ii + 5] + SHAFunctions64.Ch(h, a, b) + SHAFunctions64.Sig1(h); + g += c; + c += SHAFunctions64.Maj(d, e, f) + SHAFunctions64.Sig0(d); + + // step 7 + b += buffer[ii + 6] + Constants[ii + 6] + SHAFunctions64.Ch(g, h, a) + SHAFunctions64.Sig1(g); + f += b; + b += SHAFunctions64.Maj(c, d, e) + SHAFunctions64.Sig0(c); + + // step 8 + a += buffer[ii + 7] + Constants[ii + 7] + SHAFunctions64.Ch(f, g, h) + SHAFunctions64.Sig1(f); + e += a; + a += SHAFunctions64.Maj(b, c, d) + SHAFunctions64.Sig0(b); + } + + state.A += a; + state.B += b; + state.C += c; + state.D += d; + state.E += e; + state.F += f; + state.G += g; + state.H += h; + } + + protected override byte[] ProcessFinalBlock() + { + return state.ToByteArray(); + } + + private sealed class HashState + { + public ulong A; + public ulong B; + public ulong C; + public ulong D; + public ulong E; + public ulong F; + public ulong G; + public ulong H; + + public HashState() + { + Initialize(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize() + { + A = 0x6a09e667f3bcc908; + B = 0xbb67ae8584caa73b; + C = 0x3c6ef372fe94f82b; + D = 0xa54ff53a5f1d36f1; + E = 0x510e527fade682d1; + F = 0x9b05688c2b3e6c1f; + G = 0x1f83d9abfb41bd6b; + H = 0x5be0cd19137e2179; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte[] ToByteArray() + { + var result = new byte[64]; + + BigEndian.Copy(A, result); + BigEndian.Copy(B, result.AsSpan(8)); + BigEndian.Copy(C, result.AsSpan(16)); + BigEndian.Copy(D, result.AsSpan(24)); + BigEndian.Copy(E, result.AsSpan(32)); + BigEndian.Copy(F, result.AsSpan(40)); + BigEndian.Copy(G, result.AsSpan(48)); + BigEndian.Copy(H, result.AsSpan(56)); + + return result; + } + } + } +} diff --git a/src/acryptohashnet/SHA/Sha3_224.cs b/src/acryptohashnet/SHA/Sha3_224.cs new file mode 100644 index 0000000..e4f772d --- /dev/null +++ b/src/acryptohashnet/SHA/Sha3_224.cs @@ -0,0 +1,50 @@ +using System; +using System.Numerics; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions + /// + public sealed class Sha3_224 : BlockHashAlgorithm + { + private readonly ulong[] state = new ulong[25]; + + public Sha3_224() : base(144) + { + HashSizeValue = 224; + } + + public override void Initialize() + { + base.Initialize(); + state.AsSpan().Fill(0); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + for (int ii = 0; ii < BlockSize / 8; ii += 1) + { + state[ii] ^= LittleEndian.ToUInt64(block.Slice(ii * 8, 8)); + } + + Keccak.Permute(state); + } + + protected override byte[] ProcessFinalBlock() + { + return LittleEndian.ToByteArray(state.AsSpan(0, 4)).AsSpan(0, 28).ToArray(); + } + + protected override byte[] GeneratePaddingBlocks(ReadOnlySpan lastBlock, BigInteger messageLength) + { + var padding = new byte[BlockSize]; + lastBlock.CopyTo(padding); + + padding[lastBlock.Length] = 0x06; // 0000 0110 + padding[padding.Length - 1] |= 0x80; // 1000 0000 + + return padding; + } + } +} diff --git a/src/acryptohashnet/SHA/Sha3_256.cs b/src/acryptohashnet/SHA/Sha3_256.cs new file mode 100644 index 0000000..be70634 --- /dev/null +++ b/src/acryptohashnet/SHA/Sha3_256.cs @@ -0,0 +1,50 @@ +using System; +using System.Numerics; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions + /// + public sealed class Sha3_256 : BlockHashAlgorithm + { + private readonly ulong[] state = new ulong[25]; + + public Sha3_256() : base(136) + { + HashSizeValue = 256; + } + + public override void Initialize() + { + base.Initialize(); + state.AsSpan().Fill(0); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + for (int ii = 0; ii < BlockSize / 8; ii += 1) + { + state[ii] ^= LittleEndian.ToUInt64(block.Slice(ii * 8, 8)); + } + + Keccak.Permute(state); + } + + protected override byte[] ProcessFinalBlock() + { + return LittleEndian.ToByteArray(state.AsSpan(0, 4)); + } + + protected override byte[] GeneratePaddingBlocks(ReadOnlySpan lastBlock, BigInteger messageLength) + { + var padding = new byte[BlockSize]; + lastBlock.CopyTo(padding); + + padding[lastBlock.Length] = 0x06; // 0000 0110 + padding[padding.Length - 1] |= 0x80; // 1000 0000 + + return padding; + } + } +} diff --git a/src/acryptohashnet/SHA/Sha3_384.cs b/src/acryptohashnet/SHA/Sha3_384.cs new file mode 100644 index 0000000..3fa2a41 --- /dev/null +++ b/src/acryptohashnet/SHA/Sha3_384.cs @@ -0,0 +1,50 @@ +using System; +using System.Numerics; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions + /// + public sealed class Sha3_384 : BlockHashAlgorithm + { + private readonly ulong[] state = new ulong[25]; + + public Sha3_384() : base(104) + { + HashSizeValue = 384; + } + + public override void Initialize() + { + base.Initialize(); + state.AsSpan().Fill(0); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + for (int ii = 0; ii < BlockSize / 8; ii += 1) + { + state[ii] ^= LittleEndian.ToUInt64(block.Slice(ii * 8, 8)); + } + + Keccak.Permute(state); + } + + protected override byte[] ProcessFinalBlock() + { + return LittleEndian.ToByteArray(state.AsSpan(0, 6)); + } + + protected override byte[] GeneratePaddingBlocks(ReadOnlySpan lastBlock, BigInteger messageLength) + { + var padding = new byte[BlockSize]; + lastBlock.CopyTo(padding); + + padding[lastBlock.Length] = 0x06; // 0000 0110 + padding[padding.Length - 1] |= 0x80; // 1000 0000 + + return padding; + } + } +} diff --git a/src/acryptohashnet/SHA/Sha3_512.cs b/src/acryptohashnet/SHA/Sha3_512.cs new file mode 100644 index 0000000..4056937 --- /dev/null +++ b/src/acryptohashnet/SHA/Sha3_512.cs @@ -0,0 +1,50 @@ +using System; +using System.Numerics; + +namespace acryptohashnet +{ + /// + /// Defined by FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions + /// + public sealed class Sha3_512 : BlockHashAlgorithm + { + private readonly ulong[] state = new ulong[25]; + + public Sha3_512() : base(72) + { + HashSizeValue = 512; + } + + public override void Initialize() + { + base.Initialize(); + state.AsSpan().Fill(0); + } + + protected override void ProcessBlock(ReadOnlySpan block) + { + for (int ii = 0; ii < BlockSize / 8; ii += 1) + { + state[ii] ^= LittleEndian.ToUInt64(block.Slice(ii * 8, 8)); + } + + Keccak.Permute(state); + } + + protected override byte[] ProcessFinalBlock() + { + return LittleEndian.ToByteArray(state.AsSpan(0, 8)); + } + + protected override byte[] GeneratePaddingBlocks(ReadOnlySpan lastBlock, BigInteger messageLength) + { + var padding = new byte[BlockSize]; + lastBlock.CopyTo(padding); + + padding[lastBlock.Length] = 0x06; // 0000 0110 + padding[padding.Length - 1] |= 0x80; // 1000 0000 + + return padding; + } + } +} diff --git a/src/acryptohashnet/acryptohashnet.csproj b/src/acryptohashnet/acryptohashnet.csproj index efe758c..36a04c4 100644 --- a/src/acryptohashnet/acryptohashnet.csproj +++ b/src/acryptohashnet/acryptohashnet.csproj @@ -1,9 +1,9 @@  - netstandard2.0; netstandard2.1; net6.0 + netstandard2.0; netstandard2.1; net6.0; net8.0 enable - 2.0.0 + 3.0.0 A pure managed C# implementation of well-known cryptographic hash functions such as SHA-family (SHA0, SHA1, SHA2, SHA256, SHA384, SHA512), MD-family (MD2, MD4, MD5), RIPEMD, Tiger, Haval, Snefru and others. Andrey Rusyaev Andrey Rusyaev diff --git a/src/acryptohashnet/readme.md b/src/acryptohashnet/readme.md index 0187197..145f306 100644 --- a/src/acryptohashnet/readme.md +++ b/src/acryptohashnet/readme.md @@ -1,11 +1,18 @@ # Overview -A pure C# implementation of well-known cryptographic hash functions for .Net Standard 2.0 compatible platforms (.Net Framework, .Net Core, Mono, Xamarin, UWP, Unity). +A pure C# implementation of cryptographic hash functions for .Net Standard 2.0 compatible platforms (.Net Framework, .Net Core, Mono, Xamarin, UWP, Unity). -# Included hash functions +# Features + +* Pure managed C# implementation, +* Compatible with System.Security.Cryptography.HashAlgorithm and can be used everywhere as a simple drop replacement for the target hash algorithm, +* Extremely fast, highly optimized with low memory footprint (less GC time). + +# Implemented hash functions * MD family: MD2, MD4, MD5, * SHA family: SHA0, SHA1, -* SHA2 family: SHA256, SHA384, SHA512, +* SHA2 family: SHA224, SHA256, SHA384, SHA512, +* SHA3 family: SHA3-224, SHA3-256, SHA3-384, SHA3-512, * RIPEMD family: RIPEMD128, RIPEMD160, * Haval family: Haval128, Haval160, Haval192, Haval224, Haval256, * Snefru, Snefru256, @@ -22,19 +29,21 @@ using System.Text; static class Program { - static void Main(string[] args) - { - var hashAlgorithm = new acryptohashnet.MD5(); - var hashBytes = hashAlgorithm.ComputeHash("message digest".ToUtf8Bytes()); - Console.WriteLine("Hash: {0}", hashBytes.ToHexString()); - } - - static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); - static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); + static void Main(string[] args) + { + var message = "Lorem ipsum is placeholder text commonly used in the graphic, " + + "print, and publishing industries for previewing layouts and visual mockups."; + + var hashAlgorithm = new acryptohashnet.MD5(); + Console.WriteLine("MD5: {0}", hashAlgorithm.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + } + + static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); } ``` -## SHA256 +## SHA256 (SHA2-256 bits) ``` csharp using System; @@ -43,19 +52,21 @@ using System.Text; static class Program { - static void Main(string[] args) - { - var hashAlgorithm = new acryptohashnet.SHA256(); - var hashBytes = hashAlgorithm.ComputeHash("message digest".ToUtf8Bytes()); - Console.WriteLine("Hash: {0}", hashBytes.ToHexString()); - } - - static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); - static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); + static void Main(string[] args) + { + var message = "Lorem ipsum is placeholder text commonly used in the graphic, " + + "print, and publishing industries for previewing layouts and visual mockups."; + + var hashAlgorithm = new acryptohashnet.Sha2_256(); + Console.WriteLine("SHA256: {0}", hashAlgorithm.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + } + + static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); } ``` -## SHA512 +## SHA512 (SHA2-512 bits) ``` csharp using System; @@ -64,15 +75,40 @@ using System.Text; static class Program { - static void Main(string[] args) - { - var hashAlgorithm = new acryptohashnet.SHA512(); - var hashBytes = hashAlgorithm.ComputeHash("message digest".ToUtf8Bytes()); - Console.WriteLine("Hash: {0}", hashBytes.ToHexString()); - } - - static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); - static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); + static void Main(string[] args) + { + var message = "Lorem ipsum is placeholder text commonly used in the graphic, " + + "print, and publishing industries for previewing layouts and visual mockups."; + + var hashAlgorithm = new acryptohashnet.Sha2_512(); + Console.WriteLine("SHA512: {0}", hashAlgorithm.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + } + + static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); +} +``` + +## SHA3-512 + +``` csharp +using System; +using System.Linq; +using System.Text; + +static class Program +{ + static void Main(string[] args) + { + var message = "Lorem ipsum is placeholder text commonly used in the graphic, " + + "print, and publishing industries for previewing layouts and visual mockups."; + + var hashAlgorithm = new acryptohashnet.Sha3_512(); + Console.WriteLine("SHA3-512: {0}", hashAlgorithm.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + } + + static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); } ``` @@ -85,14 +121,56 @@ using System.Text; static class Program { - static void Main(string[] args) - { - var hashAlgorithm = new acryptohashnet.Snefru256(); - var hashBytes = hashAlgorithm.ComputeHash("message digest".ToUtf8Bytes()); - Console.WriteLine("Hash: {0}", hashBytes.ToHexString()); - } - - static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); - static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); + static void Main(string[] args) + { + var message = "Lorem ipsum is placeholder text commonly used in the graphic, " + + "print, and publishing industries for previewing layouts and visual mockups."; + + var hashAlgorithm = new acryptohashnet.Snefru256(); + Console.WriteLine("Snefru256: {0}", hashAlgorithm.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + } + + static byte[] ToUtf8Bytes(this string input) => Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); +} +``` + +## Compute hashes with different algorithms and use of System.Security.Cryptography.HashAlgorithm + +``` csharp +static class Program +{ + static void Main(string[] args) + { + var message = "Lorem ipsum is placeholder text commonly used in the graphic, " + + "print, and publishing industries for previewing layouts and visual mockups."; + + var md5 = new acryptohashnet.MD5(); + var sha1 = new acryptohashnet.SHA1(); + var sha2_256 = new acryptohashnet.Sha2_256(); + var sha3_512 = new acryptohashnet.Sha3_512(); + + Console.WriteLine("message MD5: {0}", md5.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + Console.WriteLine("message SHA1: {0}", sha1.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + Console.WriteLine("message SHA256: {0}", sha2_256.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + Console.WriteLine("message SHA3-512: {0}", sha3_512.ComputeHash(message.ToUtf8Bytes()).ToHexString()); + + using (var file = File.OpenRead(@"C:\Windows\explorer.exe")) + { + Console.WriteLine("explorer.exe MD5: {0}", md5.ComputeHash(file).ToHexString()); + + file.Position = 0; // Rewind stream + Console.WriteLine("explorer.exe SHA1: {0}", sha1.ComputeHash(file).ToHexString()); + + file.Position = 0; // Rewind stream + Console.WriteLine("explorer.exe SHA256: {0}", sha2_256.ComputeHash(file).ToHexString()); + + file.Position = 0; // Rewind stream + Console.WriteLine("explorer.exe SHA3-512: {0}", sha3_512.ComputeHash(file).ToHexString()); + } + } + + static byte[] ToUtf8Bytes(this string input) => System.Text.Encoding.UTF8.GetBytes(input); + static string ToHexString(this byte[] input) => string.Join("", input.Select(x => x.ToString("x2"))); } ``` \ No newline at end of file