-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Port MD4 managed implementation from mono/mono #62074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
3fae34d
Port MD4 managed implementation from mono/mono
MaximLipnin 8e27e96
Merge branch 'main' into port_md4_managed_impl
MaximLipnin ae9cad6
Move MD4 impl to System.Net.Security
MaximLipnin 32d479d
Fix the namespace
MaximLipnin fa5e3a5
Make some methods static
MaximLipnin 5c7c417
Port some portion of MD4 tests
MaximLipnin 4c29645
Merge branch 'main' into port_md4_managed_impl
MaximLipnin daad017
Feedback
MaximLipnin e60bbb6
Merge branch 'main' into port_md4_managed_impl
MaximLipnin b40203e
Add Android as a target framework to build S.N.Security tests
MaximLipnin 187f80a
Extract the MD4 tests to a separate test suite to not depend on Syste…
MaximLipnin 43f231c
Add MD4 tests to the smoke tests item group to avoid running all the …
MaximLipnin 173acfa
Feedback
MaximLipnin 443f608
Merge branch 'main' into port_md4_managed_impl
MaximLipnin fea9889
Merge branch 'main' into port_md4_managed_impl
MaximLipnin c4a4c5e
Transient move from the instance methods to static ones.
MaximLipnin ad4b4a2
Merge branch 'main' into port_md4_managed_impl
MaximLipnin 68b3492
Merge branch 'main' into port_md4_managed_impl
MaximLipnin 40ae039
Add the "little-endian" case when encoding
MaximLipnin 6d1fd3c
Transforming static fields to local variables
MaximLipnin 7800933
feedback
MaximLipnin fff4d49
Merge branch 'main' into port_md4_managed_impl
MaximLipnin 66b7e68
Transforming static fields to local variables
MaximLipnin b9aa97c
Merge branch 'main' into port_md4_managed_impl
MaximLipnin 2af7ceb
Get rid of HashValue static field
MaximLipnin 98a1f3d
Make HashFinal write to destination directly
MaximLipnin 99cd7d6
Eliminate redundant arrays usage
MaximLipnin 1809d0f
static field -> local
MaximLipnin 913a8d6
static field -> local
MaximLipnin cf90c33
Move up constants
MaximLipnin 2cebfdf
Rename input param
MaximLipnin 40f136c
Put a local variable in place where it's neded
MaximLipnin 956f8dd
Move the HashFinal logic to the HashData method
MaximLipnin 6462885
Clean up
MaximLipnin 002fdd0
Update the tests
MaximLipnin be92981
Merge branch 'main' into port_md4_managed_impl
MaximLipnin 1d166b8
Remove redundant parameters
MaximLipnin 980272d
Use Span's Slice+CopyTo methods
MaximLipnin 5f23083
Use BinaryPrimitives.ReadUInt32LittleEndian when decoding
MaximLipnin 9b993fb
Use BitOperations.RotateLeft instead of a custom method
MaximLipnin 31cc0b5
Remove redundant parameter
MaximLipnin bc3d647
Merge branch 'main' into port_md4_managed_impl
MaximLipnin e1071c8
Add more test cases
MaximLipnin 42afb5b
Inline/remove the BlockCopy method
MaximLipnin 133f71d
Preserve the license header from Mono implementation
MaximLipnin a42224b
Fix spaces issue
MaximLipnin 4723c99
Skip the block copying when it's unnecessary
MaximLipnin 0f0b8ec
Move the MD4 tests over to System.Net.Security.Unit.Tests project
MaximLipnin 589d3ed
Revert redundant change
MaximLipnin 2bfb2b6
Revert adding a temp test suite to the smoke tests section
MaximLipnin 9488c1a
Address Stephen's feedback
MaximLipnin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
256 changes: 256 additions & 0 deletions
256
src/libraries/System.Net.Security/src/System/Net/Security/MD4.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
// | ||
// MD4.cs - Message Digest 4 Abstract class | ||
// | ||
// Author: | ||
// Sebastien Pouliot (sebastien@xamarin.com) | ||
// | ||
// (C) 2003 Motus Technologies Inc. (http://www.motus.com) | ||
// Copyright 2013 Xamarin Inc. (http://www.xamarin.com) | ||
// | ||
|
||
// | ||
// Permission is hereby granted, free of charge, to any person obtaining | ||
// a copy of this software and associated documentation files (the | ||
// "Software"), to deal in the Software without restriction, including | ||
// without limitation the rights to use, copy, modify, merge, publish, | ||
// distribute, sublicense, and/or sell copies of the Software, and to | ||
// permit persons to whom the Software is furnished to do so, subject to | ||
// the following conditions: | ||
// | ||
// The above copyright notice and this permission notice shall be | ||
// included in all copies or substantial portions of the Software. | ||
// | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
// | ||
|
||
using System.Buffers.Binary; | ||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
MaximLipnin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
using System.Numerics; | ||
|
||
// | ||
// This class is a port of the Mono managed implementation of the MD4 algorithm | ||
// and required to support NTLM in Android only. | ||
// It's an implementation detail and is not intended to be a public API. | ||
// Assuming that NTLM would be System.Net.Security, it makes sense to put MD4 here as well. | ||
// | ||
namespace System.Net.Security | ||
{ | ||
internal sealed class MD4 | ||
{ | ||
private const int S11 = 3; | ||
private const int S12 = 7; | ||
private const int S13 = 11; | ||
private const int S14 = 19; | ||
private const int S21 = 3; | ||
private const int S22 = 5; | ||
private const int S23 = 9; | ||
private const int S24 = 13; | ||
private const int S31 = 3; | ||
private const int S32 = 9; | ||
private const int S33 = 11; | ||
private const int S34 = 15; | ||
|
||
internal static void HashData(ReadOnlySpan<byte> source, Span<byte> destination) | ||
{ | ||
Debug.Assert(destination.Length == 128 >> 3); | ||
|
||
Span<byte> buffer = stackalloc byte[64]; | ||
buffer.Clear(); | ||
// Initialize the context | ||
Span<uint> state = stackalloc uint[4] { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }; | ||
Span<uint> count = stackalloc uint[2] { 0, 0 }; | ||
|
||
HashCore(source, state, count, buffer); | ||
|
||
// Save number of bits | ||
Span<byte> bits = stackalloc byte[8]; | ||
Encode(bits, count); | ||
|
||
// Pad out to 56 mod 64 | ||
uint index = ((count[0] >> 3) & 0x3f); | ||
int padLen = (int)((index < 56) ? (56 - index) : (120 - index)); | ||
Span<byte> padding = stackalloc byte[padLen]; | ||
MaximLipnin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
padding.Clear(); | ||
padding[0] = 0x80; | ||
HashCore(padding, state, count, buffer); | ||
|
||
// Append length (before padding) | ||
HashCore(bits, state, count, buffer); | ||
|
||
// Write state to destination | ||
Encode(destination, state); | ||
} | ||
|
||
private static void HashCore(ReadOnlySpan<byte> input, Span<uint> state, Span<uint> count, Span<byte> buffer) | ||
{ | ||
// Compute number of bytes mod 64 | ||
int index = (int)((count[0] >> 3) & 0x3F); | ||
// Update number of bits | ||
count[0] += (uint)(input.Length << 3); | ||
bartonjs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (count[0] < (input.Length << 3)) | ||
{ | ||
count[1]++; | ||
MaximLipnin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
count[1] += (uint)(input.Length >> 29); | ||
|
||
int partLen = 64 - index; | ||
int i = 0; | ||
// Transform as many times as possible. | ||
if (input.Length >= partLen) | ||
{ | ||
if (index != 0) | ||
{ | ||
input.Slice(0, partLen).CopyTo(buffer.Slice(index)); | ||
MD4Transform(state, buffer); | ||
index = 0; | ||
} | ||
else | ||
{ | ||
partLen = 0; | ||
} | ||
|
||
for (i = partLen; i + 63 < input.Length; i += 64) | ||
{ | ||
MD4Transform(state, input.Slice(i)); | ||
} | ||
} | ||
|
||
// Buffer remaining input | ||
input.Slice(i).CopyTo(buffer.Slice(index)); | ||
} | ||
|
||
//--- private methods --------------------------------------------------- | ||
MaximLipnin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// F, G and H are basic MD4 functions. | ||
private static uint F(uint x, uint y, uint z) | ||
{ | ||
return (uint)(((x) & (y)) | ((~x) & (z))); | ||
} | ||
|
||
private static uint G(uint x, uint y, uint z) | ||
{ | ||
return (uint)(((x) & (y)) | ((x) & (z)) | ((y) & (z))); | ||
} | ||
|
||
private static uint H(uint x, uint y, uint z) | ||
{ | ||
return (uint)((x) ^ (y) ^ (z)); | ||
} | ||
|
||
// FF, GG and HH are transformations for rounds 1, 2 and 3. | ||
// Rotation is separate from addition to prevent recomputation. | ||
private static void FF(ref uint a, uint b, uint c, uint d, uint x, byte s) | ||
{ | ||
a += F(b, c, d) + x; | ||
a = BitOperations.RotateLeft(a, s); | ||
} | ||
|
||
private static void GG(ref uint a, uint b, uint c, uint d, uint x, byte s) | ||
{ | ||
a += G(b, c, d) + x + 0x5a827999; | ||
a = BitOperations.RotateLeft(a, s); | ||
} | ||
|
||
private static void HH(ref uint a, uint b, uint c, uint d, uint x, byte s) | ||
{ | ||
a += H(b, c, d) + x + 0x6ed9eba1; | ||
a = BitOperations.RotateLeft(a, s); | ||
} | ||
|
||
private static void Encode(Span<byte> output, Span<uint> input) | ||
{ | ||
for (int i = 0, j = 0; j < output.Length; i++, j += 4) | ||
{ | ||
BinaryPrimitives.WriteUInt32LittleEndian(output.Slice(j), input[i]); | ||
} | ||
} | ||
|
||
private static void Decode(Span<uint> output, ReadOnlySpan<byte> input) | ||
{ | ||
for (int i = 0, j = 0; i < output.Length; i++, j += 4) | ||
{ | ||
output[i] = BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(j)); | ||
} | ||
} | ||
|
||
private static void MD4Transform(Span<uint> state, ReadOnlySpan<byte> block) | ||
{ | ||
uint a = state[0]; | ||
uint b = state[1]; | ||
uint c = state[2]; | ||
uint d = state[3]; | ||
Span<uint> x = stackalloc uint[16]; | ||
|
||
Decode(x, block); | ||
|
||
// Round 1 | ||
FF(ref a, b, c, d, x[0], S11); // 1 | ||
FF(ref d, a, b, c, x[1], S12); // 2 | ||
FF(ref c, d, a, b, x[2], S13); // 3 | ||
FF(ref b, c, d, a, x[3], S14); // 4 | ||
FF(ref a, b, c, d, x[4], S11); // 5 | ||
FF(ref d, a, b, c, x[5], S12); // 6 | ||
FF(ref c, d, a, b, x[6], S13); // 7 | ||
FF(ref b, c, d, a, x[7], S14); // 8 | ||
FF(ref a, b, c, d, x[8], S11); // 9 | ||
FF(ref d, a, b, c, x[9], S12); // 10 | ||
FF(ref c, d, a, b, x[10], S13); // 11 | ||
FF(ref b, c, d, a, x[11], S14); // 12 | ||
FF(ref a, b, c, d, x[12], S11); // 13 | ||
FF(ref d, a, b, c, x[13], S12); // 14 | ||
FF(ref c, d, a, b, x[14], S13); // 15 | ||
FF(ref b, c, d, a, x[15], S14); // 16 | ||
|
||
// Round 2 | ||
GG(ref a, b, c, d, x[0], S21); // 17 | ||
GG(ref d, a, b, c, x[4], S22); // 18 | ||
GG(ref c, d, a, b, x[8], S23); // 19 | ||
GG(ref b, c, d, a, x[12], S24); // 20 | ||
GG(ref a, b, c, d, x[1], S21); // 21 | ||
GG(ref d, a, b, c, x[5], S22); // 22 | ||
GG(ref c, d, a, b, x[9], S23); // 23 | ||
GG(ref b, c, d, a, x[13], S24); // 24 | ||
GG(ref a, b, c, d, x[2], S21); // 25 | ||
GG(ref d, a, b, c, x[6], S22); // 26 | ||
GG(ref c, d, a, b, x[10], S23); // 27 | ||
GG(ref b, c, d, a, x[14], S24); // 28 | ||
GG(ref a, b, c, d, x[3], S21); // 29 | ||
GG(ref d, a, b, c, x[7], S22); // 30 | ||
GG(ref c, d, a, b, x[11], S23); // 31 | ||
GG(ref b, c, d, a, x[15], S24); // 32 | ||
|
||
HH(ref a, b, c, d, x[0], S31); // 33 | ||
HH(ref d, a, b, c, x[8], S32); // 34 | ||
HH(ref c, d, a, b, x[4], S33); // 35 | ||
HH(ref b, c, d, a, x[12], S34); // 36 | ||
HH(ref a, b, c, d, x[2], S31); // 37 | ||
HH(ref d, a, b, c, x[10], S32); // 38 | ||
HH(ref c, d, a, b, x[6], S33); // 39 | ||
HH(ref b, c, d, a, x[14], S34); // 40 | ||
HH(ref a, b, c, d, x[1], S31); // 41 | ||
HH(ref d, a, b, c, x[9], S32); // 42 | ||
HH(ref c, d, a, b, x[5], S33); // 43 | ||
HH(ref b, c, d, a, x[13], S34); // 44 | ||
HH(ref a, b, c, d, x[3], S31); // 45 | ||
HH(ref d, a, b, c, x[11], S32); // 46 | ||
HH(ref c, d, a, b, x[7], S33); // 47 | ||
HH(ref b, c, d, a, x[15], S34); // 48 | ||
|
||
state[0] += a; | ||
state[1] += b; | ||
state[2] += c; | ||
state[3] += d; | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.