From 0a7422026a9446f646fc47f337054da37c5caa00 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 25 Nov 2020 15:08:21 -0800 Subject: [PATCH 1/5] Move Sha1ForNonSecretPurposes under Common Avoid code duplication and contribute to #45237 and #45032 --- .../src/System/Sha1ForNonSecretPurposes.cs | 168 ++++++++++++++++++ .../System.Private.CoreLib.Shared.projitems | 3 + .../System/Diagnostics/Tracing/EventSource.cs | 161 ----------------- .../Cryptography/SHAHashProvider.Browser.cs | 164 +---------------- ...em.Security.Cryptography.Algorithms.csproj | 2 + 5 files changed, 176 insertions(+), 322 deletions(-) create mode 100644 src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs diff --git a/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs b/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs new file mode 100644 index 0000000000000..7f63416e1d89d --- /dev/null +++ b/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs @@ -0,0 +1,168 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Numerics; + +namespace System +{ + /// + /// Implements the SHA1 hashing algorithm. Note that + /// implementation is for hashing public information. Do not + /// use code to hash private data, as implementation does + /// not take any steps to avoid information disclosure. + /// + internal struct Sha1ForNonSecretPurposes + { + private long _length; // Total message length in bits + private uint[] _w; // Workspace + private int _pos; // Length of current chunk in bytes + + /// + /// Call Start() to initialize the hash object. + /// + public void Start() + { + _w ??= new uint[85]; + + _length = 0; + _pos = 0; + _w[80] = 0x67452301; + _w[81] = 0xEFCDAB89; + _w[82] = 0x98BADCFE; + _w[83] = 0x10325476; + _w[84] = 0xC3D2E1F0; + } + + /// + /// Adds an input byte to the hash. + /// + /// Data to include in the hash. + public void Append(byte input) + { + _w[_pos / 4] = (_w[_pos / 4] << 8) | input; + if (64 == ++_pos) + { + Drain(); + } + } + + /// + /// Adds input bytes to the hash. + /// + /// + /// Data to include in the hash. Must not be null. + /// +#if ES_BUILD_STANDALONE + public void Append(byte[] input) +#else + public void Append(ReadOnlySpan input) +#endif + { + foreach (byte b in input) + { + Append(b); + } + } + + /// + /// Retrieves the hash value. + /// Note that after calling function, the hash object should + /// be considered uninitialized. Subsequent calls to Append or + /// Finish will produce useless results. Call Start() to + /// reinitialize. + /// + /// + /// Buffer to receive the hash value. Must not be null. + /// Up to 20 bytes of hash will be written to the output buffer. + /// If the buffer is smaller than 20 bytes, the remaining hash + /// bytes will be lost. If the buffer is larger than 20 bytes, the + /// rest of the buffer is left unmodified. + /// + public void Finish(byte[] output) + { + long l = _length + 8 * _pos; + Append(0x80); + while (_pos != 56) + { + Append(0x00); + } + + unchecked + { + Append((byte)(l >> 56)); + Append((byte)(l >> 48)); + Append((byte)(l >> 40)); + Append((byte)(l >> 32)); + Append((byte)(l >> 24)); + Append((byte)(l >> 16)); + Append((byte)(l >> 8)); + Append((byte)l); + + int end = output.Length < 20 ? output.Length : 20; + for (int i = 0; i != end; i++) + { + uint temp = _w[80 + i / 4]; + output[i] = (byte)(temp >> 24); + _w[80 + i / 4] = temp << 8; + } + } + } + + /// + /// Called when pos reaches 64. + /// + private void Drain() + { + for (int i = 16; i != 80; i++) + { + _w[i] = BitOperations.RotateLeft(_w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16], 1); + } + + unchecked + { + uint a = _w[80]; + uint b = _w[81]; + uint c = _w[82]; + uint d = _w[83]; + uint e = _w[84]; + + for (int i = 0; i != 20; i++) + { + const uint k = 0x5A827999; + uint f = (b & c) | ((~b) & d); + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + for (int i = 20; i != 40; i++) + { + uint f = b ^ c ^ d; + const uint k = 0x6ED9EBA1; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + for (int i = 40; i != 60; i++) + { + uint f = (b & c) | (b & d) | (c & d); + const uint k = 0x8F1BBCDC; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + for (int i = 60; i != 80; i++) + { + uint f = b ^ c ^ d; + const uint k = 0xCA62C1D6; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + _w[80] += a; + _w[81] += b; + _w[82] += c; + _w[83] += d; + _w[84] += e; + } + + _length += 512; // 64 bytes == 512 bits + _pos = 0; + } + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index ed4e0b619de5a..3266f4f912d53 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1112,6 +1112,9 @@ Common\System\Obsoletions.cs + + Common\System\Sha1ForNonSecretPurposes.cs + Common\System\SR.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index a5171d45a7bf4..7b5f398c71a3d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -1560,167 +1560,6 @@ private static string GetName(Type eventSourceType, EventManifestOptions flags) return eventSourceType.Name; } - /// - /// Implements the SHA1 hashing algorithm. Note that this - /// implementation is for hashing public information. Do not - /// use this code to hash private data, as this implementation does - /// not take any steps to avoid information disclosure. - /// - private struct Sha1ForNonSecretPurposes - { - private long length; // Total message length in bits - private uint[] w; // Workspace - private int pos; // Length of current chunk in bytes - - /// - /// Call Start() to initialize the hash object. - /// - public void Start() - { - this.w ??= new uint[85]; - - this.length = 0; - this.pos = 0; - this.w[80] = 0x67452301; - this.w[81] = 0xEFCDAB89; - this.w[82] = 0x98BADCFE; - this.w[83] = 0x10325476; - this.w[84] = 0xC3D2E1F0; - } - - /// - /// Adds an input byte to the hash. - /// - /// Data to include in the hash. - public void Append(byte input) - { - this.w[this.pos / 4] = (this.w[this.pos / 4] << 8) | input; - if (64 == ++this.pos) - { - this.Drain(); - } - } - - /// - /// Adds input bytes to the hash. - /// - /// - /// Data to include in the hash. Must not be null. - /// -#if ES_BUILD_STANDALONE - public void Append(byte[] input) -#else - public void Append(ReadOnlySpan input) -#endif - { - foreach (byte b in input) - { - this.Append(b); - } - } - - /// - /// Retrieves the hash value. - /// Note that after calling this function, the hash object should - /// be considered uninitialized. Subsequent calls to Append or - /// Finish will produce useless results. Call Start() to - /// reinitialize. - /// - /// - /// Buffer to receive the hash value. Must not be null. - /// Up to 20 bytes of hash will be written to the output buffer. - /// If the buffer is smaller than 20 bytes, the remaining hash - /// bytes will be lost. If the buffer is larger than 20 bytes, the - /// rest of the buffer is left unmodified. - /// - public void Finish(byte[] output) - { - long l = this.length + 8 * this.pos; - this.Append(0x80); - while (this.pos != 56) - { - this.Append(0x00); - } - - unchecked - { - this.Append((byte)(l >> 56)); - this.Append((byte)(l >> 48)); - this.Append((byte)(l >> 40)); - this.Append((byte)(l >> 32)); - this.Append((byte)(l >> 24)); - this.Append((byte)(l >> 16)); - this.Append((byte)(l >> 8)); - this.Append((byte)l); - - int end = output.Length < 20 ? output.Length : 20; - for (int i = 0; i != end; i++) - { - uint temp = this.w[80 + i / 4]; - output[i] = (byte)(temp >> 24); - this.w[80 + i / 4] = temp << 8; - } - } - } - - /// - /// Called when this.pos reaches 64. - /// - private void Drain() - { - for (int i = 16; i != 80; i++) - { - this.w[i] = BitOperations.RotateLeft(this.w[i - 3] ^ this.w[i - 8] ^ this.w[i - 14] ^ this.w[i - 16], 1); - } - - unchecked - { - uint a = this.w[80]; - uint b = this.w[81]; - uint c = this.w[82]; - uint d = this.w[83]; - uint e = this.w[84]; - - for (int i = 0; i != 20; i++) - { - const uint k = 0x5A827999; - uint f = (b & c) | ((~b) & d); - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 20; i != 40; i++) - { - uint f = b ^ c ^ d; - const uint k = 0x6ED9EBA1; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 40; i != 60; i++) - { - uint f = (b & c) | (b & d) | (c & d); - const uint k = 0x8F1BBCDC; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 60; i != 80; i++) - { - uint f = b ^ c ^ d; - const uint k = 0xCA62C1D6; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - this.w[80] += a; - this.w[81] += b; - this.w[82] += c; - this.w[83] += d; - this.w[84] += e; - } - - this.length += 512; // 64 bytes == 512 bits - this.pos = 0; - } - } - private static Guid GenerateGuidFromName(string name) { #if ES_BUILD_STANDALONE diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs index 4515b8ae75c24..c87500a56e5dd 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs @@ -85,12 +85,11 @@ private abstract class SHAManagedImplementationBase public abstract byte[] HashFinal(); } - // Ported from src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs. - // n.b. It's ok to use a "non-secret purposes" hashing implementation here, as this is only - // used in wasm scenarios, and as of the current release we don't make any security guarantees - // about our crypto primitives in wasm environments. private class SHA1ManagedImplementation : SHAManagedImplementationBase { + // It's ok to use a "non-secret purposes" hashing implementation here, as this is only + // used in wasm scenarios, and as of the current release we don't make any security guarantees + // about our crypto primitives in wasm environments. private Sha1ForNonSecretPurposes _state; // mutable struct - don't make readonly public override void Initialize() @@ -110,163 +109,6 @@ public override byte[] HashFinal() _state.Finish(output); return output; } - - /// - /// Implements the SHA1 hashing algorithm. Note that this - /// implementation is for hashing public information. Do not - /// use this code to hash private data, as this implementation does - /// not take any steps to avoid information disclosure. - /// - private struct Sha1ForNonSecretPurposes - { - private long length; // Total message length in bits - private uint[] w; // Workspace - private int pos; // Length of current chunk in bytes - - /// - /// Call Start() to initialize the hash object. - /// - public void Start() - { - this.w ??= new uint[85]; - - this.length = 0; - this.pos = 0; - this.w[80] = 0x67452301; - this.w[81] = 0xEFCDAB89; - this.w[82] = 0x98BADCFE; - this.w[83] = 0x10325476; - this.w[84] = 0xC3D2E1F0; - } - - /// - /// Adds an input byte to the hash. - /// - /// Data to include in the hash. - public void Append(byte input) - { - this.w[this.pos / 4] = (this.w[this.pos / 4] << 8) | input; - if (64 == ++this.pos) - { - this.Drain(); - } - } - - /// - /// Adds input bytes to the hash. - /// - /// - /// Data to include in the hash. Must not be null. - /// - public void Append(ReadOnlySpan input) - { - foreach (byte b in input) - { - this.Append(b); - } - } - - /// - /// Retrieves the hash value. - /// Note that after calling this function, the hash object should - /// be considered uninitialized. Subsequent calls to Append or - /// Finish will produce useless results. Call Start() to - /// reinitialize. - /// - /// - /// Buffer to receive the hash value. Must not be null. - /// Up to 20 bytes of hash will be written to the output buffer. - /// If the buffer is smaller than 20 bytes, the remaining hash - /// bytes will be lost. If the buffer is larger than 20 bytes, the - /// rest of the buffer is left unmodified. - /// - public void Finish(byte[] output) - { - long l = this.length + 8 * this.pos; - this.Append(0x80); - while (this.pos != 56) - { - this.Append(0x00); - } - - unchecked - { - this.Append((byte)(l >> 56)); - this.Append((byte)(l >> 48)); - this.Append((byte)(l >> 40)); - this.Append((byte)(l >> 32)); - this.Append((byte)(l >> 24)); - this.Append((byte)(l >> 16)); - this.Append((byte)(l >> 8)); - this.Append((byte)l); - - int end = output.Length < 20 ? output.Length : 20; - for (int i = 0; i != end; i++) - { - uint temp = this.w[80 + i / 4]; - output[i] = (byte)(temp >> 24); - this.w[80 + i / 4] = temp << 8; - } - } - } - - /// - /// Called when this.pos reaches 64. - /// - private void Drain() - { - for (int i = 16; i != 80; i++) - { - this.w[i] = BitOperations.RotateLeft(this.w[i - 3] ^ this.w[i - 8] ^ this.w[i - 14] ^ this.w[i - 16], 1); - } - - unchecked - { - uint a = this.w[80]; - uint b = this.w[81]; - uint c = this.w[82]; - uint d = this.w[83]; - uint e = this.w[84]; - - for (int i = 0; i != 20; i++) - { - const uint k = 0x5A827999; - uint f = (b & c) | ((~b) & d); - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 20; i != 40; i++) - { - uint f = b ^ c ^ d; - const uint k = 0x6ED9EBA1; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 40; i != 60; i++) - { - uint f = (b & c) | (b & d) | (c & d); - const uint k = 0x8F1BBCDC; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 60; i != 80; i++) - { - uint f = b ^ c ^ d; - const uint k = 0xCA62C1D6; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - this.w[80] += a; - this.w[81] += b; - this.w[82] += c; - this.w[83] += d; - this.w[84] += e; - } - - this.length += 512; // 64 bytes == 512 bits - this.pos = 0; - } - } } // ported from https://github.com/microsoft/referencesource/blob/a48449cb48a9a693903668a71449ac719b76867c/mscorlib/system/security/cryptography/sha256managed.cs diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj index b492b5474b83d..a34f3a2a6b4d4 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj @@ -586,6 +586,8 @@ Link="Common\Interop\Unix\System.Native\Interop.GetRandomBytes.cs" /> + From 77164196190024ef17a836e73e9cfbe8a871b4bb Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 25 Nov 2020 15:32:08 -0800 Subject: [PATCH 2/5] Fix netfx build break --- .../src/Microsoft.Diagnostics.Tracing.EventSource.Redist.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/src/Microsoft.Diagnostics.Tracing.EventSource.Redist.csproj b/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/src/Microsoft.Diagnostics.Tracing.EventSource.Redist.csproj index 4d2866dda980d..fc47c82f88ab5 100644 --- a/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/src/Microsoft.Diagnostics.Tracing.EventSource.Redist.csproj +++ b/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/src/Microsoft.Diagnostics.Tracing.EventSource.Redist.csproj @@ -24,6 +24,7 @@ + From 0cabf0c0d79d92861ff23b5092d869e0f39ddd89 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 25 Nov 2020 16:45:50 -0800 Subject: [PATCH 3/5] Fix build break --- .../Diagnostics/Tracing/StubEnvironment.cs | 3 +++ .../src/System/Numerics/BitOperations.cs | 13 +------------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/src/Microsoft/Diagnostics/Tracing/StubEnvironment.cs b/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/src/Microsoft/Diagnostics/Tracing/StubEnvironment.cs index 7d437be5f43df..0cffd88038be2 100644 --- a/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/src/Microsoft/Diagnostics/Tracing/StubEnvironment.cs +++ b/src/libraries/Microsoft.Diagnostics.Tracing.EventSource.Redist/src/Microsoft/Diagnostics/Tracing/StubEnvironment.cs @@ -20,7 +20,10 @@ private static int GetCurrentProcessId() return (int)Interop.Kernel32.GetCurrentProcessId(); } } +} +namespace System.Numerics +{ internal static class BitOperations { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs index 951f6f2aaa326..93d8974fecd6b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/BitOperations.cs @@ -7,9 +7,7 @@ using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; -#if SYSTEM_PRIVATE_CORELIB using Internal.Runtime.CompilerServices; -#endif // Some routines inspired by the Stanford Bit Twiddling Hacks by Sean Eron Anderson: // http://graphics.stanford.edu/~seander/bithacks.html @@ -21,12 +19,7 @@ namespace System.Numerics /// The methods use hardware intrinsics when available on the underlying platform, /// otherwise they use optimized software fallbacks. /// -#if SYSTEM_PRIVATE_CORELIB - public -#else - internal -#endif - static class BitOperations + public static class BitOperations { // C# no-alloc optimization that directly wraps the data section of the dll (similar to string constants) // https://github.com/dotnet/roslyn/pull/24621 @@ -227,9 +220,7 @@ ref MemoryMarshal.GetReference(Log2DeBruijn), /// Similar in behavior to the x86 instruction POPCNT. /// /// The value. -#if SYSTEM_PRIVATE_CORELIB [Intrinsic] -#endif [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] public static int PopCount(uint value) @@ -270,9 +261,7 @@ static int SoftwareFallback(uint value) /// Similar in behavior to the x86 instruction POPCNT. /// /// The value. -#if SYSTEM_PRIVATE_CORELIB [Intrinsic] -#endif [MethodImpl(MethodImplOptions.AggressiveInlining)] [CLSCompliant(false)] public static int PopCount(ulong value) From c490e3e997b9857796b659522848c7b84faf9082 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 26 Nov 2020 02:30:18 -0800 Subject: [PATCH 4/5] Update src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs --- src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs b/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs index 7f63416e1d89d..698e9da12bdec 100644 --- a/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs +++ b/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs @@ -39,7 +39,8 @@ public void Start() /// Data to include in the hash. public void Append(byte input) { - _w[_pos / 4] = (_w[_pos / 4] << 8) | input; + int idx = _pos >> 2; + _w[idx] = (_w[idx] << 8) | input; if (64 == ++_pos) { Drain(); From 918986a798d67b24189d08e406a936afaa0248fd Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 26 Nov 2020 02:43:51 -0800 Subject: [PATCH 5/5] Unnecessary unchecked scopes --- .../src/System/Sha1ForNonSecretPurposes.cs | 108 +++++++++--------- 1 file changed, 51 insertions(+), 57 deletions(-) diff --git a/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs b/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs index 698e9da12bdec..4ea03f2d995ae 100644 --- a/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs +++ b/src/libraries/Common/src/System/Sha1ForNonSecretPurposes.cs @@ -88,24 +88,21 @@ public void Finish(byte[] output) Append(0x00); } - unchecked + Append((byte)(l >> 56)); + Append((byte)(l >> 48)); + Append((byte)(l >> 40)); + Append((byte)(l >> 32)); + Append((byte)(l >> 24)); + Append((byte)(l >> 16)); + Append((byte)(l >> 8)); + Append((byte)l); + + int end = output.Length < 20 ? output.Length : 20; + for (int i = 0; i != end; i++) { - Append((byte)(l >> 56)); - Append((byte)(l >> 48)); - Append((byte)(l >> 40)); - Append((byte)(l >> 32)); - Append((byte)(l >> 24)); - Append((byte)(l >> 16)); - Append((byte)(l >> 8)); - Append((byte)l); - - int end = output.Length < 20 ? output.Length : 20; - for (int i = 0; i != end; i++) - { - uint temp = _w[80 + i / 4]; - output[i] = (byte)(temp >> 24); - _w[80 + i / 4] = temp << 8; - } + uint temp = _w[80 + i / 4]; + output[i] = (byte)(temp >> 24); + _w[80 + i / 4] = temp << 8; } } @@ -119,49 +116,46 @@ private void Drain() _w[i] = BitOperations.RotateLeft(_w[i - 3] ^ _w[i - 8] ^ _w[i - 14] ^ _w[i - 16], 1); } - unchecked + uint a = _w[80]; + uint b = _w[81]; + uint c = _w[82]; + uint d = _w[83]; + uint e = _w[84]; + + for (int i = 0; i != 20; i++) + { + const uint k = 0x5A827999; + uint f = (b & c) | ((~b) & d); + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + for (int i = 20; i != 40; i++) { - uint a = _w[80]; - uint b = _w[81]; - uint c = _w[82]; - uint d = _w[83]; - uint e = _w[84]; - - for (int i = 0; i != 20; i++) - { - const uint k = 0x5A827999; - uint f = (b & c) | ((~b) & d); - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 20; i != 40; i++) - { - uint f = b ^ c ^ d; - const uint k = 0x6ED9EBA1; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 40; i != 60; i++) - { - uint f = (b & c) | (b & d) | (c & d); - const uint k = 0x8F1BBCDC; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - for (int i = 60; i != 80; i++) - { - uint f = b ^ c ^ d; - const uint k = 0xCA62C1D6; - uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; - } - - _w[80] += a; - _w[81] += b; - _w[82] += c; - _w[83] += d; - _w[84] += e; + uint f = b ^ c ^ d; + const uint k = 0x6ED9EBA1; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; } + for (int i = 40; i != 60; i++) + { + uint f = (b & c) | (b & d) | (c & d); + const uint k = 0x8F1BBCDC; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + for (int i = 60; i != 80; i++) + { + uint f = b ^ c ^ d; + const uint k = 0xCA62C1D6; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + _w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + _w[80] += a; + _w[81] += b; + _w[82] += c; + _w[83] += d; + _w[84] += e; + _length += 512; // 64 bytes == 512 bits _pos = 0; }