Skip to content
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

Fix seed initialization in Microsoft.Bcl.Hashcode #42808

Closed
fabricefou opened this issue Sep 28, 2020 · 20 comments
Closed

Fix seed initialization in Microsoft.Bcl.Hashcode #42808

fabricefou opened this issue Sep 28, 2020 · 20 comments
Assignees
Milestone

Comments

@fabricefou
Copy link

Description

Private field s_seed is always set to 0 due to a bug in method GetRandomBytes.
In this method the parameter byte* buffer is always overwritten, so random value is lost.

We can easily reproduce the problem with this code.

var seed = typeof(HashCode).GetField("s_seed", BindingFlags.NonPublic | BindingFlags.Statics);

This problem don't existe in .NET Core implementation.

Configuration

.NET Framework

Regression?

It's not really a regression but not the expected behavior.
People using this package want the same behavior than in .NET core.

And if it's not fixed, I think this package should be mark as deprecated.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-Serialization untriaged New issue has not been triaged by the area owner labels Sep 28, 2020
@stephentoub stephentoub added area-System.Runtime bug and removed area-Serialization untriaged New issue has not been triaged by the area owner labels Sep 28, 2020
@stephentoub stephentoub added this to the 6.0.0 milestone Sep 28, 2020
@stephentoub stephentoub changed the title Fix seed initialization in Microsoft.Blc.Hascode Fix seed initialization in Microsoft.Bcl.Hashcode Sep 28, 2020
@fabricefou
Copy link
Author

Thanks to be so reactive !
Any idea if this bug will be fix and when ?
(I can of course copy paste implementation and fix the random seed problem, but if you release the nuget package with the fix it's better 😀.)

@stephentoub
Copy link
Member

cc: @ericstj

@danmoseley
Copy link
Member

It's interesting, given our recent conversations about Guid, that this code is generating a Guid purely as a source of random bytes. Isn't there a more canonical way to fill a buffer with cryptographically random bytes? Or perhaps it isn't available in .NET Standard?

@ericstj
Copy link
Member

ericstj commented Sep 29, 2020

IIRC @bartonjs usually recommends to only use crypto when you need it. If all you need is random, then other methods are more efficient. Not sure if crytpo is needed here, I would imagine no since in net5.0 this uses

Sys.GetNonCryptographicallySecureRandomBytes(buffer, length);

As far as fixing this, it would need to be done in 3.1 servicing. @danmosemsft what's your feeling for this meeting servicing bar? Related discussion: #39895 (comment)

@bartonjs
Copy link
Member

Because this is used for things like avoiding dictionary collision attacks, it's important to use good random in the static seed generation (dotnet/corefx#25013 (comment) was the original discussion).

If this is OOB@NS2.0, then (if we're keeping the signature on the GetRandomBytes call for code sharing reasons):

    internal static unsafe void GetRandomBytes(byte* buffer, int length)
    {
        byte[] tmp = new byte[length];

        using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(tmp);
        }

        Marshal.Copy(tmp, 0, (IntPtr)buffer, length);
    }

Since it's only ever used once, it shouldn't be too big of a deal.

It's probably cleaner to make GenerateGlobalSeed() just have a different implementation in the package built variant

        private static unsafe uint GenerateGlobalSeed()
        {
            byte[] tmp = new byte[sizeof(uint));
             
            using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(tmp);
            }

            fixed (byte* pTmp = tmp)
            {
                return *((uint*)pTmp);
            }
        }

@fabricefou
Copy link
Author

Thanks to be so reactive !
Any idea if this bug will be fix and when ?
(I can of course copy paste implementation and fix the random seed problem, but if you release the nuget package with the fix it's better 😀.)

Any idea of the schedule for the fix? Week(s)? Month(s)?

Thanks

@ericstj
Copy link
Member

ericstj commented Oct 1, 2020

Since this is servicing, at the very earliest it would be November. We'll need to discuss it per the bar, as mentioned above.

@fabricefou
Copy link
Author

Since this is servicing, at the very earliest it would be November. We'll need to discuss it per the bar, as mentioned above.

Thanks

@ericstj
Copy link
Member

ericstj commented Oct 7, 2020

Current thinking is to propose this for release/3.1 with an AppContext switch to go back to non-randomized in case someone is broken by the non-stable hash ordering (this has cause compat issues in the past).

@fabricefou
Copy link
Author

Current thinking is to propose this for release/3.1 with an AppContext switch to go back to non-randomized in case someone is broken by the non-stable hash ordering (this has cause compat issues in the past).

If I understand well, default value for switch will be random seed activated ?

@joperezr
Copy link
Member

If I understand well, default value for switch will be random seed activated ?

@ericstj please correct me if I'm wrong but I think the idea would be to keep the existing behavior in .NETStandard as we have it today ( so as to not break people depending on this today) but have an appcontext switch that allows you to get the .NET Core behavior if you want to. That would be an opt-in fix so that we don't break existing consumers.

@ericstj
Copy link
Member

ericstj commented Oct 14, 2020

The opposite actually, we need to make the behavior consistent. We have the AppContext switch to go back to the broken behavior if someone happened to depend on it.

@joperezr joperezr added the Servicing-consider Issue for next servicing release review label Nov 12, 2020
@joperezr joperezr modified the milestones: 6.0.0, 3.1.x Nov 12, 2020
@danmoseley danmoseley removed the Servicing-consider Issue for next servicing release review label Nov 12, 2020
@leecow leecow modified the milestones: 3.1.x, 3.1.11 Nov 12, 2020
@fabricefou
Copy link
Author

Thanks for the fix 👍 .
Any idea when the fix will be available as nuget package?

@joperezr
Copy link
Member

Yes, as you can see we set the milestone to be 3.1.11 which is our next servicing for 3.1 for which we don't have exact dates but should be in NuGet within the next two months.

@fabricefou
Copy link
Author

Yes, as you can see we set the milestone to be 3.1.11 which is our next servicing for 3.1 for which we don't have exact dates but should be in NuGet within the next two months.

Thanks

@fabricefou
Copy link
Author

Hello any news for a NuGet release date?
Thanks

@KalleOlaviNiemitalo
Copy link

@fabricefou, Microsoft.Bcl.HashCode 1.1.1 was released last week. version.txt in that package refers to commit dotnet/corefx@59d2f36, which is on the release/3.1 branch and includes the fix dotnet/corefx#43004.

I don't know why this issue is still open.

@fabricefou
Copy link
Author

@fabricefou, Microsoft.Bcl.HashCode 1.1.1 was released last week. version.txt in that package refers to commit dotnet/corefx@59d2f36, which is on the release/3.1 branch and includes the fix dotnet/corefx#43004.

I don't know why this issue is still open.

Thanks 👍

@joperezr
Copy link
Member

I don't know why this issue is still open.

Seems like we just forgot to close it 😆. Closing now.

@ghost ghost locked as resolved and limited conversation to collaborators Feb 19, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

9 participants