diff --git a/Corlib.Extensions/System/Security/Cryptography/Adler.cs b/Corlib.Extensions/System/Security/Cryptography/Adler.cs index a7fc9992..a1b04fcb 100644 --- a/Corlib.Extensions/System/Security/Cryptography/Adler.cs +++ b/Corlib.Extensions/System/Security/Cryptography/Adler.cs @@ -102,36 +102,13 @@ void Reset() { void Core(byte[] array, int index, int count) { for (count += index; index < count; ++index) { - state = (state + array[index]) % PRIME; - sum = (sum + state) % PRIME; + state = (uint)(((ulong)state + array[index]) % PRIME); + sum = (uint)(((ulong)sum + state) % PRIME); } } byte[] Final() => new[] { (byte)(sum >> 24), (byte)(sum >> 16), (byte)(sum >> 8), (byte)sum, (byte)(state >> 24), (byte)(state >> 16), (byte)(state >> 8), (byte)state }; } - case 128: { - const ulong PRIME = 18446744073709551557; - ulong state = default, sum = default; - - this._reset = Reset; - this._core = Core; - this._final = Final; - break; - - void Reset() { - state = 1; - sum = 0; - } - - void Core(byte[] array, int index, int count) { - for (count += index; index < count; ++index) { - state = (state + array[index]) % PRIME; - sum = (sum + state) % PRIME; - } - } - - byte[] Final() => new[] { (byte)(sum >> 56), (byte)(sum >> 48), (byte)(sum >> 40), (byte)(sum >> 32), (byte)(sum >> 24), (byte)(sum >> 16), (byte)(sum >> 8), (byte)sum, (byte)(state >> 56), (byte)(state >> 48), (byte)(state >> 40), (byte)(state >> 32), (byte)(state >> 24), (byte)(state >> 16), (byte)(state >> 8), (byte)state }; - } default: throw new NotSupportedException(); } @@ -164,9 +141,9 @@ public byte[] IV { set => throw new NotSupportedException(); } - public static int MinOutputBits => 16; - public static int MaxOutputBits => 128; - public static int[] SupportedOutputBits => new[] { 16, 32, 64, 128 }; + public static int MinOutputBits => SupportedOutputBits[0]; + public static int MaxOutputBits => SupportedOutputBits[^1]; + public static int[] SupportedOutputBits => new[] { 16, 32, 64 }; public static bool SupportsIV => false; public static int MinIVBits => 0; diff --git a/Corlib.Extensions/System/Security/Cryptography/Fletcher.cs b/Corlib.Extensions/System/Security/Cryptography/Fletcher.cs index 0a5e91f2..1459927e 100644 --- a/Corlib.Extensions/System/Security/Cryptography/Fletcher.cs +++ b/Corlib.Extensions/System/Security/Cryptography/Fletcher.cs @@ -19,6 +19,8 @@ along with Hawkynt's .NET Framework extensions. */ #endregion +using System.Collections.Generic; + namespace System.Security.Cryptography; public sealed class Fletcher : HashAlgorithm, IAdvancedHashAlgorithm { @@ -40,33 +42,8 @@ public Fletcher(int outputBits) { public override void Initialize() { switch (this.OutputBits) { - case 4: { - byte state = 0; - byte sum = 0; - - this._reset = Reset; - this._core = Core; - this._final = Final; - break; - - void Reset() { - state = 0; - sum = 0; - } - - void Core(byte[] array, int index, int count) { - for (count += index; index < count; ++index) { - state = (byte)((state + array[index]) % 3); - sum = (byte)((sum + state) % 3); - } - } - - byte[] Final() => new[] { (byte)(sum << 2 | state) }; - - } case 8: { - byte state = 0; - byte sum = 0; + byte state = default, sum = default; this._reset = Reset; this._core = Core; @@ -86,11 +63,9 @@ void Core(byte[] array, int index, int count) { } byte[] Final() => new[] { (byte)(sum << 4 | state) }; - } case 16: { - byte state = 0; - byte sum = 0; + byte state = default, sum = default; this._reset = Reset; this._core = Core; @@ -109,83 +84,125 @@ void Core(byte[] array, int index, int count) { } } - byte[] Final() => new[] { state, sum }; - + byte[] Final() => new[] { sum, state }; } case 32: { - ushort state = 0; - ushort sum = 0; + ushort state = default, sum = default; + List carry = new(2); this._reset = Reset; this._core = Core; this._final = Final; break; + ushort ConvertFrom(byte b0, byte b1) => (ushort)((b0) | (b1 << 8)); + + void Round(ushort value) { + state = (ushort)(((uint)state + value) % ushort.MaxValue); + sum = (ushort)(((uint)sum + state) % ushort.MaxValue); + } + void Reset() { state = 0; sum = 0; + carry.Clear(); } void Core(byte[] array, int index, int count) { - for (count += index; index < count; ++index) { - state = (ushort)((state + array[index]) % ushort.MaxValue); - sum = (ushort)((sum + state) % ushort.MaxValue); + var end = index + count; + + while (carry.Count > 0) { + if (index >= end) + return; + + carry.Add(array[index++]); + if (carry.Count != 2) + continue; + + Round(ConvertFrom(carry[0], carry[1])); + carry.Clear(); + break; } + + while (index + 1 < end) + Round(ConvertFrom(array[index++], array[index++])); + + while (index < end) + carry.Add(array[index++]); } - byte[] Final() => BitConverter.GetBytes((uint)sum << 16 | state); + byte[] Final() { + if (carry.Count == 1) + Round(ConvertFrom(carry[0], 0)); + return new[] { + (byte)(sum >> 8), (byte)sum, + (byte)(state >> 8), (byte)state + }; + } } case 64: { - uint state = 0; - uint sum = 0; + uint state = default, sum = default; + List carry = new(4); this._reset = Reset; this._core = Core; this._final = Final; break; + uint ConvertFrom(byte b0, byte b1, byte b2, byte b3) => (uint)((b0) | (b1 << 8) | (b2 << 16) | (b3 << 24)); + + void Round(uint value) { + state = (uint)(((ulong)state + value) % uint.MaxValue); + sum = (uint)(((ulong)sum + state) % uint.MaxValue); + } + void Reset() { state = 0; sum = 0; + carry.Clear(); } void Core(byte[] array, int index, int count) { - for (count += index; index < count; ++index) { - state = (state + array[index]) % uint.MaxValue; - sum = (sum + state) % uint.MaxValue; - } - } + var end = index + count; - byte[] Final() => BitConverter.GetBytes((ulong)sum << 32 | state); + while (carry.Count > 0) { + if (index >= end) + return; - } - case 128: { - ulong state = 0; - ulong sum = 0; + carry.Add(array[index++]); + if (carry.Count != 4) + continue; - this._reset = Reset; - this._core = Core; - this._final = Final; - break; + Round(ConvertFrom(carry[0], carry[1], carry[2], carry[3])); + carry.Clear(); + break; + } - void Reset() { - state = 0; - sum = 0; - } + while (index + 3 < end) + Round(ConvertFrom(array[index++], array[index++], array[index++], array[index++])); - void Core(byte[] array, int index, int count) { - for (count += index; index < count; ++index) { - state = (state + array[index]) % ulong.MaxValue; - sum = (sum + state) % ulong.MaxValue; - } + while (index < end) + carry.Add(array[index++]); } byte[] Final() { - var result = new byte[16]; - Array.Copy(BitConverter.GetBytes(state),0,result,0,8); - Array.Copy(BitConverter.GetBytes(sum), 0, result, 8, 8); - return result; + switch (carry.Count) { + case 1: + Round(ConvertFrom(carry[0], 0, 0, 0)); + break; + case 2: + Round(ConvertFrom(carry[0], carry[1], 0, 0)); + break; + case 3: + Round(ConvertFrom(carry[0], carry[1], carry[2], 0)); + break; + } + + return new[] { + (byte)(sum >> 24), (byte)(sum >> 16), (byte)(sum >> 8), (byte)sum, + (byte)(state >> 24), (byte)(state >> 16), (byte)(state >> 8), (byte)state + }; } } default: @@ -220,9 +237,9 @@ public byte[] IV { set => throw new NotSupportedException(); } - public static int MinOutputBits => 4; - public static int MaxOutputBits => 128; - public static int[] SupportedOutputBits => new[]{ 4, 8, 16, 32, 64, 128 }; + public static int MinOutputBits => SupportedOutputBits[0]; + public static int MaxOutputBits => SupportedOutputBits[^1]; + public static int[] SupportedOutputBits => new[]{ 8, 16, 32, 64 }; public static bool SupportsIV => false; public static int MinIVBits => 0; diff --git a/Corlib.Extensions/System/Security/Cryptography/JavaHash.cs b/Corlib.Extensions/System/Security/Cryptography/JavaHash.cs index 84f55a6a..1b608ed3 100644 --- a/Corlib.Extensions/System/Security/Cryptography/JavaHash.cs +++ b/Corlib.Extensions/System/Security/Cryptography/JavaHash.cs @@ -109,18 +109,12 @@ public byte[] IV { set => throw new NotImplementedException(); } - public static int MinOutputBits => 32; - - public static int MaxOutputBits => 64; - - public static int[] SupportedOutputBits => new[] { MinOutputBits, MaxOutputBits }; - + public static int MinOutputBits => SupportedOutputBits[0]; + public static int MaxOutputBits => SupportedOutputBits[^1]; + public static int[] SupportedOutputBits => new[] { 32, 64 }; public static bool SupportsIV => false; - public static int MinIVBits => 0; - public static int MaxIVBits => MinIVBits; - public static int[] SupportedIVBits => Utilities.Array.Empty(); #endregion diff --git a/Tests/Corlib.Tests/System/Security/Cryptography/HashAlgorithmsTests.cs b/Tests/Corlib.Tests/System/Security/Cryptography/HashAlgorithmsTests.cs new file mode 100644 index 00000000..e8dccca6 --- /dev/null +++ b/Tests/Corlib.Tests/System/Security/Cryptography/HashAlgorithmsTests.cs @@ -0,0 +1,102 @@ +#region (c)2010-2042 Hawkynt +/* + This file is part of Hawkynt's .NET Framework extensions. + + Hawkynt's .NET Framework extensions are free software: + you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Hawkynt's .NET Framework extensions is distributed in the hope that + it will be useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Hawkynt's .NET Framework extensions. + If not, see . +*/ +#endregion + +using NUnit.Framework; +using static Corlib.Tests.NUnit.TestUtilities; + +namespace System.Security.Cryptography; + +[TestFixture] +public class HashAlgorithmsTests { + + [Test] + [TestCase(32, "", "00000001")] + [TestCase(32, "a", "00620062")] + [TestCase(32, "abc", "024d0127")] + [TestCase(32, "Wikipedia", "11e60398")] + [TestCase(32, "message digest", "29750586")] + [TestCase(32, "abcdefghijklmnopqrstuvwxyz", "90860b20")] + [TestCase(32, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "8adb150c")] + [TestCase(32, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "c4062ac7")] + public void Adler32(int numberOfBits, string input, string expected) + => ExecuteTest(() => input.ComputeHash(new Adler(numberOfBits)), expected, null); + + [Test] + [TestCase(8, "", "00")] + [TestCase(8, "a", "77")] + [TestCase(8, "abc", "19")] + [TestCase(8, "message digest", "93")] + [TestCase(8, "abcdefghijklmnopqrstuvwxyz", "cc")] + [TestCase(8, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "c2")] + [TestCase(8, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "90")] + [TestCase(16, "", "0000")] + [TestCase(16, "a", "6161")] + [TestCase(16, "abc", "4c27")] + [TestCase(16, "message digest", "908a")] + [TestCase(16, "abcdefghijklmnopqrstuvwxyz", "fc2a")] + [TestCase(16, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "0c20")] + [TestCase(16, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "bdf0")] + [TestCase(32, "", "00000000")] + [TestCase(32, "a", "00610061")] + [TestCase(32, "ab", "62616261")] + [TestCase(32, "abc", "c52562c4")] + [TestCase(32, "abcd", "2926c6c4")] + [TestCase(32, "abcde", "f04fc729")] + [TestCase(32, "abcdefgh", "ebe19591")] + [TestCase(32, "message digest", "7c9da3e6")] + [TestCase(32, "abcdefghijklmnopqrstuvwxyz", "d3789b8e")] + [TestCase(32, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "e1f39f80")] + [TestCase(32, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "f2b89957")] + [TestCase(64, "", "0000000000000000")] + [TestCase(64, "a", "0000006100000061")] + [TestCase(64, "ab", "0000626100006261")] + [TestCase(64, "abc", "0063626100636261")] + [TestCase(64, "abcd", "6463626164636261")] + [TestCase(64, "abcde", "c8c6c527646362c6")] + [TestCase(64, "abcdefgh", "312e2b28cccac8c6")] + [TestCase(64, "message digest", "f9cd1314f940aaa5")] + [TestCase(64, "abcdefghijklmnopqrstuvwxyz", "5f44a387969104fd")] + [TestCase(64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "3ab328a245365a4a")] + [TestCase(64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "f5d1f5ebe4c2b494")] + public void Fletcher(int numberOfBits, string input, string expected) + => ExecuteTest(() => input.ComputeHash(new Fletcher(numberOfBits)), expected, null); + + [Test] + [TestCase(192, "", "3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3")] + [TestCase(192, "abc", "2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93")] + [TestCase(192, "Tiger", "dd00230799f5009fec6debc838bb6a27df2b9d6f110c7937")] + [TestCase(192, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "f71c8583902afb879edfe610f82c0d4786a3a534504486b5")] + [TestCase(192, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "c54034e5b43eb8005848a7e0ae6aac76e4ff590ae715fd25")] + [TestCase(160, "", "3293ac630c13f0245f92bbb1766e16167a4e5849")] + [TestCase(160, "abc", "2aab1484e8c158f2bfb8c5ff41b57a525129131c")] + [TestCase(160, "Tiger", "dd00230799f5009fec6debc838bb6a27df2b9d6f")] + [TestCase(160, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "f71c8583902afb879edfe610f82c0d4786a3a534")] + [TestCase(160, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "c54034e5b43eb8005848a7e0ae6aac76e4ff590a")] + [TestCase(128, "", "3293ac630c13f0245f92bbb1766e1616")] + [TestCase(128, "abc", "2aab1484e8c158f2bfb8c5ff41b57a52")] + [TestCase(128, "Tiger", "dd00230799f5009fec6debc838bb6a27")] + [TestCase(128, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "f71c8583902afb879edfe610f82c0d47")] + [TestCase(128, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "c54034e5b43eb8005848a7e0ae6aac76")] + public void Tiger(int numberOfBits, string input, string expected) + => ExecuteTest(() => input.ComputeHash(new Tiger(numberOfBits)), expected, null); + +} + diff --git a/Tests/Corlib.Tests/System/Security/Cryptography/TigerTests.cs b/Tests/Corlib.Tests/System/Security/Cryptography/TigerTests.cs deleted file mode 100644 index a4100b4d..00000000 --- a/Tests/Corlib.Tests/System/Security/Cryptography/TigerTests.cs +++ /dev/null @@ -1,53 +0,0 @@ -#region (c)2010-2042 Hawkynt -/* - This file is part of Hawkynt's .NET Framework extensions. - - Hawkynt's .NET Framework extensions are free software: - you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Hawkynt's .NET Framework extensions is distributed in the hope that - it will be useful, but WITHOUT ANY WARRANTY; without even the implied - warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Hawkynt's .NET Framework extensions. - If not, see . -*/ -#endregion - -using System.Text; -using NUnit.Framework; -using static Corlib.Tests.NUnit.TestUtilities; - -namespace System.Security.Cryptography; - -using Collections.Generic; - -[TestFixture] -public class TigerTests { - - [Test] - [TestCase(192, "", "3293ac630c13f0245f92bbb1766e16167a4e58492dde73f3")] - [TestCase(192, "abc", "2aab1484e8c158f2bfb8c5ff41b57a525129131c957b5f93")] - [TestCase(192, "Tiger", "dd00230799f5009fec6debc838bb6a27df2b9d6f110c7937")] - [TestCase(192, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "f71c8583902afb879edfe610f82c0d4786a3a534504486b5")] - [TestCase(192, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "c54034e5b43eb8005848a7e0ae6aac76e4ff590ae715fd25")] - [TestCase(160, "", "3293ac630c13f0245f92bbb1766e16167a4e5849")] - [TestCase(160, "abc", "2aab1484e8c158f2bfb8c5ff41b57a525129131c")] - [TestCase(160, "Tiger", "dd00230799f5009fec6debc838bb6a27df2b9d6f")] - [TestCase(160, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "f71c8583902afb879edfe610f82c0d4786a3a534")] - [TestCase(160, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "c54034e5b43eb8005848a7e0ae6aac76e4ff590a")] - [TestCase(128, "", "3293ac630c13f0245f92bbb1766e1616")] - [TestCase(128, "abc", "2aab1484e8c158f2bfb8c5ff41b57a52")] - [TestCase(128, "Tiger", "dd00230799f5009fec6debc838bb6a27")] - [TestCase(128, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "f71c8583902afb879edfe610f82c0d47")] - [TestCase(128, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", "c54034e5b43eb8005848a7e0ae6aac76")] - public void Tiger(int numberOfBits, string input, string expected) - => ExecuteTest(() => new Tiger(numberOfBits).ComputeHash(Encoding.ASCII.GetBytes(input)).Select(b => b.ToString("x2")).Join(string.Empty), expected, null); - -} -