dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.95k stars 4.65k forks source link

Add support for SHA3 (Keccak) #20342

Closed ghost closed 1 year ago

ghost commented 7 years ago

Since SHA1 has been known as an "unsafe" algorithm, but now a safer algorithm called "SHA3" is created. So this algorithm should also be included here. Any plans or options for Microsoft now? As far as we see, SHA3 is a little faster than SHA2 and what's more——It's SAFER.

API Proposal v2

The original proposal was outfitted with many annotations for [SupportedOSPlatform{Guard}]. We discussed this in the original review and made it a point to revisit this topic. The current thinking now is that we should simply omit the attributes.

We have IsSupported properties that folks should be using to determine if the platform is supported or not.

The platform support may change over time. None of these APIs are inherently OS-specific. If macOS gives us SHA3 APIs we can use later, then we will do so, and the IsSupported is the source of truth for this information, not the platform name.

The API below is the new proposal. It is the same as the previously approved API, but [SupportedOSPlatform("XYZ")] and [SupportedOSPlatformGuard("XYZ")] have been removed.

namespace System.Security.Cryptography;

public partial struct HashAlgorithmName {
    public static HashAlgorithmName SHA3_256 { get; }
    public static HashAlgorithmName SHA3_384 { get; }
    public static HashAlgorithmName SHA3_512 { get; }
}

public sealed partial class RSAEncryptionPadding {
    public static RSAEncryptionPadding OaepSHA3_256 { get; }
    public static RSAEncryptionPadding OaepSHA3_384 { get; }
    public static RSAEncryptionPadding OaepSHA3_512 { get; }
}

public abstract partial class SHA3_256 : HashAlgorithm {
    public const int HashSizeInBits = 256;
    public const int HashSizeInBytes = 32;

    protected SHA3_256();

    public static bool IsSupported { get; }

    public static new SHA3_256 Create();

    public static byte[] HashData(byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    public static byte[] HashData(Stream source);
    public static int HashData(Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public abstract partial class SHA3_384 : HashAlgorithm {
    public const int HashSizeInBits = 384;
    public const int HashSizeInBytes = 48;

    protected SHA3_384();

    public static bool IsSupported { get; }

    public static new SHA3_384 Create();

    public static byte[] HashData(byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    public static byte[] HashData(Stream source);
    public static int HashData(Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public abstract partial class SHA3_512 : HashAlgorithm {
    public const int HashSizeInBits = 512;
    public const int HashSizeInBytes = 64;

    protected SHA3_512();

    public static bool IsSupported { get; }

    public static new SHA3_512 Create();

    public static byte[] HashData(byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    public static byte[] HashData(Stream source);
    public static int HashData(Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_256 : HMAC {
    public const int HashSizeInBits = 256;
    public const int HashSizeInBytes = 32;

    public HMACSHA3_256();
    public HMACSHA3_256(byte[] key);

    public static bool IsSupported { get; } // New

    public static byte[] HashData(byte[] key, byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);

    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    public static byte[] HashData(byte[] key, Stream source);
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_384 : HMAC {
    public const int HashSizeInBits = 384;
    public const int HashSizeInBytes = 48;

    public HMACSHA3_384();
    public HMACSHA3_384(byte[] key);

    public static bool IsSupported { get; } // New

    public static byte[] HashData(byte[] key, byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    public static byte[] HashData(byte[] key, Stream source);
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_512 : HMAC {
    public const int HashSizeInBits = 512;
    public const int HashSizeInBytes = 64;

    public HMACSHA3_512();
    public HMACSHA3_512(byte[] key);

    public static bool IsSupported { get; } // New

    public static byte[] HashData(byte[] key, byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    public static byte[] HashData(byte[] key, Stream source);
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public sealed partial class Shake128 : IDisposable {

    public Shake128();

    public static bool IsSupported { get; }

    public void AppendData(byte[] data);
    public void AppendData(ReadOnlySpan<byte> data);
    public byte[] GetCurrentHash(int outputLength);
    public void GetCurrentHash(Span<byte> destination);
    public byte[] GetHashAndReset(int outputLength);
    public void GetHashAndReset(Span<byte> destination);
    public void Dispose();

    public static byte[] HashData(byte[] source, int outputLength);
    public static byte[] HashData(ReadOnlySpan<byte> source, int outputLength);
    public static void HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    public static byte[] HashData(Stream source, int outputLength);
    public static void HashData(Stream source, Span<byte> destination);
    public static ValueTask HashDataAsync(Stream source, Memory<byte> destination, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(Stream source, int outputLength, CancellationToken cancellationToken = default);
}

public sealed partial class Shake256 : IDisposable {

    public Shake256();

    public static bool IsSupported { get; }

    public void AppendData(byte[] data);
    public void AppendData(ReadOnlySpan<byte> data);
    public byte[] GetCurrentHash(int outputLength);
    public void GetCurrentHash(Span<byte> destination);
    public byte[] GetHashAndReset(int outputLength);
    public void GetHashAndReset(Span<byte> destination);
    public void Dispose();

    public static byte[] HashData(byte[] source, int outputLength);
    public static byte[] HashData(ReadOnlySpan<byte> source, int outputLength);
    public static void HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    public static byte[] HashData(Stream source, int outputLength);
    public static void HashData(Stream source, Span<byte> destination);
    public static ValueTask HashDataAsync(Stream source, Memory<byte> destination, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(Stream source, int outputLength, CancellationToken cancellationToken = default);
}
Old proposal ## API Proposal ```C# namespace System.Security.Cryptography; public partial struct HashAlgorithmName { public static HashAlgorithmName SHA3_256 { get; } public static HashAlgorithmName SHA3_384 { get; } public static HashAlgorithmName SHA3_512 { get; } } public sealed partial class RSAEncryptionPadding { public static RSAEncryptionPadding OaepSHA3_256 { get; } public static RSAEncryptionPadding OaepSHA3_384 { get; } public static RSAEncryptionPadding OaepSHA3_512 { get; } } public abstract partial class SHA3_256 : HashAlgorithm { public const int HashSizeInBits = 256; public const int HashSizeInBytes = 32; protected SHA3_256(); [UnsupportedOSPlatformGuard("ios")] [UnsupportedOSPlatformGuard("tvos")] [UnsupportedOSPlatformGuard("android")] [UnsupportedOSPlatformGuard("browser")] [UnsupportedOSPlatformGuard("osx")] public static bool IsSupported { get; } [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static new SHA3_256 Create(); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static bool TryHashData(ReadOnlySpan source, Span destination, out int bytesWritten); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(Stream source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync( Stream source, Memory destination, CancellationToken cancellationToken = default); } public abstract partial class SHA3_384 : HashAlgorithm { public const int HashSizeInBits = 384; public const int HashSizeInBytes = 48; protected SHA3_384(); [UnsupportedOSPlatformGuard("ios")] [UnsupportedOSPlatformGuard("tvos")] [UnsupportedOSPlatformGuard("android")] [UnsupportedOSPlatformGuard("browser")] [UnsupportedOSPlatformGuard("osx")] public static bool IsSupported { get; } [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static new SHA3_384 Create(); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static bool TryHashData(ReadOnlySpan source, Span destination, out int bytesWritten); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(Stream source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync( Stream source, Memory destination, CancellationToken cancellationToken = default); } public abstract partial class SHA3_512 : HashAlgorithm { public const int HashSizeInBits = 512; public const int HashSizeInBytes = 64; protected SHA3_512(); [UnsupportedOSPlatformGuard("ios")] [UnsupportedOSPlatformGuard("tvos")] [UnsupportedOSPlatformGuard("android")] [UnsupportedOSPlatformGuard("browser")] [UnsupportedOSPlatformGuard("osx")] public static bool IsSupported { get; } [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static new SHA3_512 Create(); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static bool TryHashData(ReadOnlySpan source, Span destination, out int bytesWritten); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(Stream source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync( Stream source, Memory destination, CancellationToken cancellationToken = default); } public partial class HMACSHA3_256 : HMAC { public const int HashSizeInBits = 256; public const int HashSizeInBytes = 32; [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public HMACSHA3_256(); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public HMACSHA3_256(byte[] key); [UnsupportedOSPlatformGuard("ios")] [UnsupportedOSPlatformGuard("tvos")] [UnsupportedOSPlatformGuard("android")] [UnsupportedOSPlatformGuard("browser")] [UnsupportedOSPlatformGuard("osx")] public static bool IsSupported { get; } // New [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] key, byte[] source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan key, ReadOnlySpan source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan key, ReadOnlySpan source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static bool TryHashData( ReadOnlySpan key, ReadOnlySpan source, Span destination, out int bytesWritten); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] key, Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan key, Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan key, Stream source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync( ReadOnlyMemory key, Stream source, Memory destination, CancellationToken cancellationToken = default); } public partial class HMACSHA3_384 : HMAC { public const int HashSizeInBits = 384; public const int HashSizeInBytes = 48; [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public HMACSHA3_384(); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public HMACSHA3_384(byte[] key); [UnsupportedOSPlatformGuard("ios")] [UnsupportedOSPlatformGuard("tvos")] [UnsupportedOSPlatformGuard("android")] [UnsupportedOSPlatformGuard("browser")] [UnsupportedOSPlatformGuard("osx")] public static bool IsSupported { get; } // New [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] key, byte[] source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan key, ReadOnlySpan source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan key, ReadOnlySpan source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static bool TryHashData( ReadOnlySpan key, ReadOnlySpan source, Span destination, out int bytesWritten); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] key, Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan key, Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan key, Stream source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync( ReadOnlyMemory key, Stream source, Memory destination, CancellationToken cancellationToken = default); } public partial class HMACSHA3_512 : HMAC { public const int HashSizeInBits = 512; public const int HashSizeInBytes = 64; [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public HMACSHA3_512(); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public HMACSHA3_512(byte[] key); [UnsupportedOSPlatformGuard("ios")] [UnsupportedOSPlatformGuard("tvos")] [UnsupportedOSPlatformGuard("android")] [UnsupportedOSPlatformGuard("browser")] [UnsupportedOSPlatformGuard("osx")] public static bool IsSupported { get; } // New [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] key, byte[] source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan key, ReadOnlySpan source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan key, ReadOnlySpan source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static bool TryHashData( ReadOnlySpan key, ReadOnlySpan source, Span destination, out int bytesWritten); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(byte[] key, Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static byte[] HashData(ReadOnlySpan key, Stream source); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static int HashData(ReadOnlySpan key, Stream source, Span destination); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync(ReadOnlyMemory key, Stream source, CancellationToken cancellationToken = default); [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public static ValueTask HashDataAsync( ReadOnlyMemory key, Stream source, Memory destination, CancellationToken cancellationToken = default); } public abstract partial class Shake : IDisposable { internal Shake(); // Will not be subclassable by developers. public void AppendData(byte[] data); public void AppendData(ReadOnlySpan data); protected abstract void AppendDataCore(ReadOnlySpan data); public byte[] GetCurrentHash(int outputLength); public void GetCurrentHash(Span destination); protected abstract void GetCurrentHashCore(Span destination); public byte[] GetHashAndReset(int outputLength); public void GetHashAndReset(Span destination); protected abstract void GetHashAndResetCore(Span destination); public void Dispose(); protected virtual void Dispose(bool disposing); } [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public sealed partial class Shake128 : Shake { public Shake128(); [UnsupportedOSPlatformGuard("ios")] [UnsupportedOSPlatformGuard("tvos")] [UnsupportedOSPlatformGuard("android")] [UnsupportedOSPlatformGuard("browser")] [UnsupportedOSPlatformGuard("osx")] public static bool IsSupported { get; } public static byte[] HashData(byte[] source, int outputLength); public static byte[] HashData(ReadOnlySpan source, int outputLength); public static void HashData(ReadOnlySpan source, Span destination); public static byte[] HashData(Stream source, int outputLength); public static void HashData(Stream source, Span destination); public static ValueTask HashDataAsync(Stream source, Memory destination, CancellationToken cancellationToken = default); public static ValueTask HashDataAsync(Stream source, int outputLength, CancellationToken cancellationToken = default); } [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("osx")] public sealed partial class Shake256 : Shake { public Shake256(); [UnsupportedOSPlatformGuard("ios")] [UnsupportedOSPlatformGuard("tvos")] [UnsupportedOSPlatformGuard("android")] [UnsupportedOSPlatformGuard("browser")] [UnsupportedOSPlatformGuard("osx")] public static bool IsSupported { get; } public static byte[] HashData(byte[] source, int outputLength); public static byte[] HashData(ReadOnlySpan source, int outputLength); public static void HashData(ReadOnlySpan source, Span destination); public static byte[] HashData(Stream source, int outputLength); public static void HashData(Stream source, Span destination); public static ValueTask HashDataAsync(Stream source, Memory destination, CancellationToken cancellationToken = default); public static ValueTask HashDataAsync(Stream source, int outputLength, CancellationToken cancellationToken = default); } ```
bartonjs commented 7 years ago

It's been on the watch list since it was announced. Since we don't implement cryptographic algorithms within .NET we're waiting on support from the underlying platforms (Windows CNG, Apple Security.framework, and OpenSSL).

As far as speed, I'm given to understand that SHA-3 can never be as fast as SHA-2, due to an inability to hardware optimize it.

ghost commented 7 years ago

Hello @bartonjs:

Thanks for your quick reply, and I get the complete code from here: http://keccak.noekeon.org/KeccakReferenceAndOptimized-3.2.zip.

For more about speed and other things, please read here:http://www.drdobbs.com/security/keccak-the-new-sha-3-encryption-standard/240154037?pgno=1

bartonjs commented 7 years ago

Yeah, Keccak is (per your linked article) 12.5 cycles/byte. SHA-2-512 with 64-bit instructions on an Intel processor is 8.5 cycles/byte.

That said, we're just at the mercy of 1) Our underlying providers supporting it. 2) Figuring out what to name the classes. Since SHA-3 also supports a 256, 384, and 512-bit mode, we can't go with "SHA256", etc. And "SHA3256" is a bit weird.... "SHA3_256" violates our naming rules, "SHA3-256" is an invalid identifier.

ghost commented 7 years ago

Well……I think you can rename it as "Keccak256,384 or 512", because Keccak is just the algorithm of SHA3 as the standard one.

A persudo code may look like this following:

var keccak = Keccak256.Create().……;

Also something like for these providers:

Keccak256CrytoServiceProvider Keccak384CrytoServiceProvider Keccak512CrytoServiceProvider

gvanas commented 7 years ago

Sorry to jump in the thread, but I would suggest to consider the SHAKE extendable-output functions (XOF) from FIPS 202, or the cSHAKE from SP 800-185. They are more flexible than the plain SHA-3 hash functions and have about the same speed as SHA-2.

For higher speed, there is ParallelHash [SP 800-185] or KangarooTwelve. https://twitter.com/KeccakTeam/status/834789451708628995

Kind regards, Gilles (a Keccak co-designer)

JonHanna commented 7 years ago

SHA3_256 seems a reasonable enough reason to bend the rules.

morganbr commented 7 years ago

Based on @gvanas 's points, I'd be interested to see an API design that keeps those other functions in mind. Maybe that would even affect the naming question.

ghost commented 7 years ago

@JonHanna:Agree. The name is something like the inner class that isn't publicly published to the public to be used, it's really a bit strange for us. Maybe this can be used as a wrapper or something else like this dynamically generated. And for us, the published one can be something like what I've mentioned above in my post.

vanillajonathan commented 6 years ago

The naming SHA3 violates the Microsoft naming guidelines which dictate that three-letter algorithms should not be uppercase. https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions

The proper name according to the capitalization convention would be Sha3.

jdluzen commented 6 years ago

My port of Keccak (including both original and FIPS 202 SHA3 padding) integrates with HashAlgorithm as the others in that namespace. I would be happy to contribute it.

gvanas commented 6 years ago

@jdluzen Nice! Ideally, your code should also support the SHAKE and cSHAKE functions. Not much extra work, the underlying function is the same.

morganbr commented 6 years ago

@jdluzen, we appreciate the offer, but we have a strict policy of only using cryptographic algorithms provided by underlying platforms (CNG on Windows, OpenSSL on Linux, Apple Crypto on Mac). That ensures we don't have to worry about provable correctness or avoiding side channels. Right now, I think OpenSSL has SHA3, but not the other two platforms.

Spacefish commented 4 years ago

Well, we could implement the SHA3 API and just throw a "PlatformNotSupportedException" exception, when running on Mac or Windows.

danmoseley commented 4 years ago

Well, we could implement the SHA3 API and just throw a "PlatformNotSupportedException" exception, when running on Mac or Windows.

@Spacefish we generally try to avoid this, as it makes it harder to write cross platform libraries if an API that seems relevant to all platforms only works on some.

markusschaber commented 4 years ago

As far as I can see, there are several free implementations (at least BouncyCastle and the one by @jdluzen mentioned above), so users have alternatives as long as it's not supported in the Framework.

GrabYourPitchforks commented 4 years ago

@bartonjs Is SHA3 realistically something that we're going to be able to support in the near-to-intermediate future? Should we resolve this issue for now and reopen it once there's a critical mass of support?

TYoung86 commented 4 years ago

(Just a heads up; I don't feel as strongly as the wording I've written here implies, this one's a little cynical.)

You might also want to consider the impact on driving adoption in the direction opposite vendor support to encourage vendor support by creating adopters by creating the API.

When SHA3 is suggested and no implementation is present the framework, at present (emphasis on it's 2020) many architects opt for SHA2 and concrete their architectures around it. The lifespan of SHA2 is shortening, and as SHA3 was standardized in late 2015, given that now we're looking for post-quantum solutions like SPHINCS+ and others - the NIST began officially requesting post-quantum solutions in 2017, and now we're on round 2 of PQC standardization - the ball appears dropped.

Those that do opt to use SHA3 end up using OpenSSL/BouncyCastle/etc. or rolling their own, which is perfectly fine, and 'demand' is met and none is perceived by the OS vendors or framework.

OS vendor implementation appears to be driven by demand, of which dependent frameworks are the prime mover. So then .NET and Windows CNG are both waiting on each other. (Or do you think there are relatively many that use Windows CNG directly instead of as a supplment or fallback?)

Microsoft has their own PQC initiative, sans hashing algo at present. Wait much longer, the question won't be "Where's SHA3?" it'll be "Where's PQSHA1?"

Microsoft added XTS mode for AES in Windows 10, though I honestly have no idea if you can use it via System.Security.Cryptography. :shrug:

I think the general consensus of those still using SHA2 is vaguely "the world didn’t move to SHA3 because almost none of the world’s software or hardware supported it" ... which isn't true in the technical sense of software and hardware, only true in the business sense of software and hardware. The .NET framework, Java, and other language-level frameworks are what the business sense is going to refer to. Many of the crypto-kids went to Rust, Go, JS, back to C/C++ (but not to Windows CNG, obviously) and even OCaml - but you don't want to count that as demand though you probably should.

Since you're both (OS vendor and framework) waiting on demand that isn't measured by uses of the algo. in general or whether the algo. should be used, or as some sort of leading example w.r.t ASP.NET Core, you may as well do the industry a favor just declare the whole namespace legacy support and encourage the use of some 3rd party solutions for legitimate up-to-date solutions or create a 1st party .NET crypto lib solution, but you probably can't for some reason that involves recursion.

We'll call it the SHA3 pickle.

edit: So no Keccak256Managed/SHA3b256Managed then?

Neustradamus commented 3 years ago

.NET 5.0 is here!

SHA3 has been added?

Linked to:

MrMatthewLayton commented 3 years ago

If anyone is interested, I have implemented SHA3 + SHAKE variants here...

https://github.com/MrMatthewLayton/CORE/tree/master/Core/Security/Cryptography

Spacefish commented 3 years ago

@Xyncgas srsly, stop spamming, it is helping no-one.. SHA3 will come to .NET sooner or later.

GrabYourPitchforks commented 3 years ago

@Xyncgas Disparaging remarks about other contributors are not welcome. Please review our code of conduct (https://dotnetfoundation.org/about/code-of-conduct) for more information.

danmoseley commented 3 years ago

@Xyncgas is a 3rd party implementation such as the ones linked above sufficient for you? If not, why not? (I recognize the leadership argument above made by another contributor, but that's philosphical: not blocking.)

bartonjs commented 3 years ago

if that's the only problem stopping you from putting it in .NET

The biggest problem stopping us from putting it in .NET is that it's not supported on macOS or Windows, and by policy .NET doesn't have implementations of cryptographic algorithms that are subject to CAVP testing / FIPS certification.

Maybe our Linux numbers are high enough that we can justify adding it with only one supported platform, but the notion that we'd do it without universal (or, at least, those 3) support is itself a fairly recent change.

TourajOstovari commented 3 years ago

We would have SHA3 hash function with witch algorithms? ~> Shake, keccak, Blake?

markusschaber commented 3 years ago

The biggest problem stopping us from putting it in .NET is that it's not supported on macOS or Windows, and by policy .NET doesn't have implementations of cryptographic algorithms that are subject to CAVP testing / FIPS certification.

Maybe our Linux numbers are high enough that we can justify adding it with only one supported platform, but the notion that we'd do it without universal (or, at least, those 3) support is itself a fairly recent change.

Maybe it could be in form of a platform specific API, but maintained by the core team? In the spirit of the Support for Windows Forms/WPF which only comes with the -win TFM, or the already existing platform extensions packages?

This way, it could still be "promoted" to main .NET later, when more platforms support it.

GrabYourPitchforks commented 3 years ago

There are no plans at the current time for .NET to include a SHA-3 implementation inbox in .NET 6. As Dan mentioned previously, the best bet right now is to pull in your own trusted third-party implementation.

If SHA-3 support is added in a future release, this issue will definitely be updated to reflect that.

Continuing to spam this issue / antagonize the product team will not make SHA-3 support come any faster.

MrMatthewLayton commented 3 years ago

would you prefer using someone's library that doesn't have a name on the battle field in your production code?

As you gain experience in the software development field, you get a feel for what works and what doesn't. Usually if something is implemented well, has good documentation and covered in unit tests, it's relatively speaking, trustworthy. Whether the software is written by Joe Bloggs, me, or the team at Microsoft, it's still ultimately written by fallible human beings.

Especially we are talking about algorithm and SHA3 in specific has several implementations I think

Correct. Last time I was researching SHA-3, the competition version was known as Keccak, and the standardized version was known (or standardized) as FIPS-202. There may be some other implementations that I don't know about.

so I want my stuff to standardize on .NET's version, and I am literally waiting for you to do it.

Well then be prepared to wait. The only other option you have is to use a 3rd party implementation. Complaining isn't helping.

Because honestly the reason I am still using whatever instead of someone's SHA-3 library is that, I don't want my SHA-3 hash to be a different result than .NET

Why? If you have a dependency on a 3rd party implementation, then just leave it that way! I would hedge my bets that .NET will implement the FIPS-202 version anyway, so if you can find a 3rd party implementation of that (which I've written by the way), then you can use that.

it doesn't make sense in business and I am depending on .NET I would RATHER do this than having dependency on someone's library so it's gonna get discontinued in 2 years n I am screwed.

Well if the library is hosted on nuget then you're not screwed because you can't delete nuget packages (only hide them), and if the source code exists as open source on GitHub (and I can assure you it does), then fork or clone the repository and maintain it yourself.

FYI, I had exactly the same problem as you, probably around the release of .NET Core 2.0 I was wondering whether SHA-3 would make it to .NET...sadly no (not yet anyway), so I implemented it myself. First step was research into Keccak vs FIPS-202 - I opted for FIPS-202. Second step was to find unit tested implementations in other languages; Go, C, C++, Java, Python, etc. Eventually I found one written in Managed C++, so it was really easy to port to C#.

The final implementation is here. If you really want SHA-3 (FIPS-202) in .NET, feel free to copy as required. https://github.com/MrMatthewLayton/CORE/tree/master/Core/Security/Cryptography

markusschaber commented 3 years ago

Just as an additional hint: The mature bouncy castle library, implemented by a charity, also has an implementation: https://www.bouncycastle.org/csharp/index.html

TYoung86 commented 3 years ago

I wrote the rant above specifically about this scenario. Everyone here has likely run into it, the SHA3 pickle.

I proposed deprecating System.Security and officially recommending a 3rd party library (I endorse Bouncy Castle and OpenSSL wrappers) so that people can move on with their projects and lives. "Business" isn't always (sanely) supportive of extra-institutional or 3rd party (NIH) implementations of standards given some core framework, especially when it appears standards at least partially exist; IMO that's why implementations today still get concreted around SHA2 instead of SHA3.

In summary, just use Bouncy Castle and pretend there are no hashes built into the .NET framework.

MrMatthewLayton commented 3 years ago

This was absolutely fantastic! I honestly can't remember the last time I enjoyed reading something so much. Rest assured, the next time I go for a job interview and they ask me about myself, I'm going to describe myself as a "fishy, chinese communist!" :rofl::rofl::rofl:

I think u are the guy that created the repository for SHA-3 (the one that shows up on google when I searched for it)

Who knows? I just googled "SHA-3 .NET C#" but I didn't find my implementation anywhere on the first two pages at least, but I did find this as the top result:

https://www.nuget.org/packages/SHA3.Net/

https://github.com/griffo-io/sha3.net

For starters...

Now, here's why I decided to implement it myself rather than using something that already existed...

Essentially what I wanted (which isn't a million miles from what you're asking for) was a FIPS 202 implementation of SHA-3 with no underlying dependencies, except for .NET itself (respectfully System.Security.Cryptography.HashAlgorithm). In actual fact, I only wanted the SHAKE-256 variant of SHA-3 for a quantum cryptography research project, but for completeness I decided to build the whole suite of FIPS 202 SHA-3 implementation variants anyway.

I forgot to mention and I will say it here, the repository that you own, seemingly stopped maintaining 2 years ago, that's a big red flag and so I stopped there the first time I saw it, and I think people should be alerted of this, because it's what looks like a personal project that's decorated as some kinds of influencing program with seemingly legit documentations, so you mean to say that you just so conveniently to have this repository sitting over here for two years, and now all the sudden you just showed up to everyone and advertising it, it's almost like you knew the virus was coming and created this repository according to your lords' plan.

Well, here I will grant you your dues; yes, the repository has not been maintained for a long time and is actually in dire need of retiring or updating. Hmmm, maybe I should add that to my ever-growing todo list?

The reason for this was that I moved professionally from being a C# developer to a Kotlin developer, specifically working in Blockchain and DLT (an area of computer science which is notably steeped in cryptography).

Acknowledgements and excuses aside, FIPS 202 is FIPS 202, regardless of whether it was implemented 2 years ago or an hour ago. Even if I were to actively maintain this repository, the only things I could improve are performance, and importantly adding useful unit tests to prove that the algorithm continues to work as expected. I cannot change the algorithm because then it's not FIPS 202 anymore. So yes, it's a piece of legacy code, but it's a piece of legacy code that works according to the FIPS 202 specification.

Somehow I don't think that the Lord has any plans for SHA-3.

Why encourage people to use your own library, when we can use the official product

You CAN'T use the official product (yet). What other choices do people have? As I stated before, complaining isn't helping! Throwing your toys out of the pram just because you want something isn't going to make Microsoft deliver this any faster! So, if you really want/need SHA-3 in .NET, use a 3rd party implementation whether it's mine or someone elses!

In general it is undesirable to drive people away from products made from for example Microsoft and have a dependency on some no body's code, it's creditable, reputable, and if anything goes wrong microsoft is going to fix it (in general, microsoft is like a mom to me, that take cares of my everything, and disciplines me, through windows updates to remind me who's the alpha here), when clearly you are just one man on the internet it doesn't make sense usually for people to use you library when you may be gone in two years and people's issues aren't getting replied in your repository...

"In general" you don't seem to have grapsed the point of "open-source" (something that Microsoft has enbraced in recent years). Much less do you understand the potential of individuals in this field...

All of these nobodys, became somebody!

Notably and with respect to this debate, JSON.NET and Automapper are free, open-source products that have MASSIVE adoption in the .NET community (JSON.NET ranks as the most downloaded NuGet package). The community is welcome to contribute to them, but hey, they're not part of .NET and are maintained by "some nobody" rather than by Microsoft, so...not trustworthy, right?

For full transparency to the above, James Newton-King was invited to, and now works for Microsoft, due to his personal successes with JSON.NET.

...and now we have to hire new people to study the codes u've written or actually it's more likely that people wouldn't be bothered with this authoritarian cliché that this world requires you to learn something...

...I don't think you should be responsible for the mistakes at work when you are working under a billion dollar company.

I'm sorry to be blunt but if there was ever an argument for laziness, ignorance and lack of responsibility, this is it!

...it's the policy and namely the "naming - policy" whatever that was...

The existing SHA implementations in .NET are called SHA1, SHA256, SHA384 and SHA512. Aside from SHA1 being a special case, the 1 indicating the first version of SHA, the remaining 256, 384 and 512 indicate the number of bits that the algorithm implements.

According to .NET's naming conventions, they should be called Sha1, Sha256, Sha384 and Sha512.

The dispute is not that Microsoft made a mistake. The implementations were probably created before the naming conventions were standardized and there's nothing that can be done about it now.

The dispute is what to call SHA3 variant implementations:

There are only two hard things in Computer Science: cache invalidation and naming things.

Phil Karlton

As if naming wasn't hard enough, the other things that Microsoft will have to consider...

But hey, they're a multi-billion dollar company, they can just do it faster...right?

CyrusNajmabadi commented 3 years ago

@Xyncgas i've hidden your message for multiple fairly extreme violations of the .NET Code of Conduct. In particular, but not limited to:

a. Being respectful of differing opinions, viewpoints, and experiences b. Giving and gracefully accepting constructive feedback c. Trolling, insulting or derogatory comments, and personal or political attacks d. Other conduct which could reasonably be considered inappropriate in a professional setting

For now, I'm just starting with a warning that such behavior is not acceptable here. Further similar behavior will lead to necessary action, including either temporary or permanent bans.


To @MrMatthewLayton and others, i ask that you not respond to that post (or any referenced parts of it in the post that followed), and keep the discussion purely on topic about the main issue's subject. Thanks!

huoyaoyuan commented 3 years ago

I would appreciate if there are news about underlying providers. Search for "Windows CNG SHA-3" gets nothing for me. You internal ones may contact Windows cryptography folks about their plan.

Xyncgas commented 3 years ago

You can use bouncy castle.

  1. Install BouncyCatle package
  2. use these codes as examples, try other packages like BouncyCatle.portable if you want
       public static string GET512(string input)
        {
            var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(512);
            byte[] byte_array = System.Text.Encoding.UTF8.GetBytes(input);
            hashAlgorithm.BlockUpdate(byte_array, 0, byte_array.Length);
            byte[] result = new byte[64]; // 512 / 8 = 64
            hashAlgorithm.DoFinal(result, 0);
            string hashString = BitConverter.ToString(result);
            hashString = hashString.Replace("-", "").ToUpperInvariant();
            return hashString;
        }
        public static string GET512(byte[] input)
        {
            var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(512);
            hashAlgorithm.BlockUpdate(input, 0, input.Length);
            byte[] result = new byte[64]; // 512 / 8 = 64
            hashAlgorithm.DoFinal(result, 0);
            string hashString = BitConverter.ToString(result);
            hashString = hashString.Replace("-", "").ToUpperInvariant();
            return hashString;
        }
        public static string GET256(string input)
        {
            var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(256);
            byte[] byte_array = System.Text.Encoding.UTF8.GetBytes(input);
            hashAlgorithm.BlockUpdate(byte_array, 0, byte_array.Length);
            byte[] result = new byte[32]; // 256 / 8 = 32
            hashAlgorithm.DoFinal(result, 0);
            string hashString = BitConverter.ToString(result);
            hashString = hashString.Replace("-", "").ToUpperInvariant();
            return hashString;
        }
        public static string GET256(byte[] input)
        {
            var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(256);
            hashAlgorithm.BlockUpdate(input, 0, input.Length);
            byte[] result = new byte[32]; // 256 / 8 = 32
            hashAlgorithm.DoFinal(result, 0);
            string hashString = BitConverter.ToString(result);
            hashString = hashString.Replace("-", "").ToUpperInvariant();
            return hashString;
        }
dariogriffo commented 2 years ago

You can use bouncy castle.

  1. Install BouncyCatle package
  2. use these codes as examples, try other packages like BouncyCatle.portable if you want
       public static string GET512(string input)
        {
            var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(512);
            byte[] byte_array = System.Text.Encoding.UTF8.GetBytes(input);
            hashAlgorithm.BlockUpdate(byte_array, 0, byte_array.Length);
            byte[] result = new byte[64]; // 512 / 8 = 64
            hashAlgorithm.DoFinal(result, 0);
            string hashString = BitConverter.ToString(result);
            hashString = hashString.Replace("-", "").ToUpperInvariant();
            return hashString;
        }
        public static string GET512(byte[] input)
        {
            var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(512);
            hashAlgorithm.BlockUpdate(input, 0, input.Length);
            byte[] result = new byte[64]; // 512 / 8 = 64
            hashAlgorithm.DoFinal(result, 0);
            string hashString = BitConverter.ToString(result);
            hashString = hashString.Replace("-", "").ToUpperInvariant();
            return hashString;
        }
        public static string GET256(string input)
        {
            var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(256);
            byte[] byte_array = System.Text.Encoding.UTF8.GetBytes(input);
            hashAlgorithm.BlockUpdate(byte_array, 0, byte_array.Length);
            byte[] result = new byte[32]; // 256 / 8 = 32
            hashAlgorithm.DoFinal(result, 0);
            string hashString = BitConverter.ToString(result);
            hashString = hashString.Replace("-", "").ToUpperInvariant();
            return hashString;
        }
        public static string GET256(byte[] input)
        {
            var hashAlgorithm = new Org.BouncyCastle.Crypto.Digests.Sha3Digest(256);
            hashAlgorithm.BlockUpdate(input, 0, input.Length);
            byte[] result = new byte[32]; // 256 / 8 = 32
            hashAlgorithm.DoFinal(result, 0);
            string hashString = BitConverter.ToString(result);
            hashString = hashString.Replace("-", "").ToUpperInvariant();
            return hashString;
        }

I guess I'm that guy you referred that created the library. Sorry to disappoint you but I'm argentinian living in Europe, not Asian. I have released a new version of the library that doesn't depend on bouncy castle but is the actual code of bouncy castle to perform Keccak. This new version has an execution time 10% of what it was and has no other dependencies, targeted net5 and 6. I removed any dependencies to net fwk 4.5 and 4.6. On a side note I'm happy you have you have friends. We all have, but some of us like to provide to the open source community, and open source means that, you can copy, modify and use other people's code as long as you don't break their licenses. The beauty of open source is that you can read the code and understand what is doing avoiding security issues. You can see now that waiting for Microsoft to implement this will take time, but if you do things right you can easily change implementationa on your app and try new libraries. Plenty of people here published code but not packages, just make sure your application"s quotes them and their licenses. Happy coding

Xyncgas commented 2 years ago

Is SHA3 going to be in .NET 7 ?

bartonjs commented 2 years ago

Is SHA3 going to be in .NET 7 ?

No. Windows doesn't already have it, and we're wrapping up the release.

Plus, I don't think I've seen any good naming proposals for how we can incorporate it (other than calling it Keccak, which no few will understand)

MrMatthewLayton commented 2 years ago

Now, I know I've been here before, flogging my own horse, but since SHA-3 isn't appearing in .NET any time soon, allow me to collate and be at least somewhat impartial as to the available options:

I said I've been here before...DON'T USE THIS! https://github.com/MrMatthewLayton/CORE This is my project implementing FIPS-202 however it's massively out of date and no longer supported.

Other Options https://www.nuget.org/packages/SHA3.Net/ implemented by @dariogriffo https://www.bouncycastle.org/csharp/

If you are interested in what I have been doing since I retired the codebase above, all of my open-source cryptography APIs are now released under ONIXLabs Ltd.

https://github.com/onix-labs/onixlabs-dotnet https://github.com/onix-labs/onixlabs-dotnet/tree/main/OnixLabs.Security.Cryptography

I hope this helps.

P.S. I Think I cracked the naming. It doesn't follow the ~wrong~ naming convention already in .NET...

jeffhandley commented 1 year ago

With Windows SHA-3 Support now announced, we will move forward with this proposal and include it in .NET 8.

MrMatthewLayton commented 1 year ago

@jeffhandley Excellent news! Do you know whether the same APIs may be available for Linux and macOS?

Spacefish commented 1 year ago

@jeffhandley Excellent news! Do you know whether the same APIs may be available for Linux and macOS?

One would assume that, as it would be quite trivial to support it there. The main reason new Crypto is hold back in the .NET standard libs is native platform support in windows. The .NET devs have been hesitant to support Crypto Algorithms in the .NET standard libs which would return "Plaform Not Supported" on Windows. Probably for obvious reasons..

You can always use bouncy castle and or openssl via NuGet packages on windows as well to get SHA3 today.

MrMatthewLayton commented 1 year ago

@Spacefish or, I could just use my own ;) https://github.com/dotnet/runtime/issues/20342#issuecomment-1193156664

That is, until they're provided in .NET, in which case I will probably refactor my own APIs to use the platform provided API, and fall back to my own in the event that platform not supported exceptions are thrown.

vcsjones commented 1 year ago

The top post is updated with the proposal for SHA3.

bartonjs commented 1 year ago

Video

namespace System.Security.Cryptography;

public partial struct HashAlgorithmName {
    public static HashAlgorithmName SHA3_256 { get; }
    public static HashAlgorithmName SHA3_384 { get; }
    public static HashAlgorithmName SHA3_512 { get; }
}

public sealed partial class RSAEncryptionPadding {
    public static RSAEncryptionPadding OaepSHA3_256 { get; }
    public static RSAEncryptionPadding OaepSHA3_384 { get; }
    public static RSAEncryptionPadding OaepSHA3_512 { get; }
}

public abstract partial class SHA3_256 : HashAlgorithm {
    public const int HashSizeInBits = 256;
    public const int HashSizeInBytes = 32;

    protected SHA3_256();

    [UnsupportedOSPlatformGuard("ios")]
    [UnsupportedOSPlatformGuard("tvos")]
    [UnsupportedOSPlatformGuard("android")]
    [UnsupportedOSPlatformGuard("browser")]
    [UnsupportedOSPlatformGuard("osx")]
    public static bool IsSupported { get; }

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static new SHA3_256 Create();

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(Stream source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public abstract partial class SHA3_384 : HashAlgorithm {
    public const int HashSizeInBits = 384;
    public const int HashSizeInBytes = 48;

    protected SHA3_384();

    [UnsupportedOSPlatformGuard("ios")]
    [UnsupportedOSPlatformGuard("tvos")]
    [UnsupportedOSPlatformGuard("android")]
    [UnsupportedOSPlatformGuard("browser")]
    [UnsupportedOSPlatformGuard("osx")]
    public static bool IsSupported { get; }

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static new SHA3_384 Create();

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(Stream source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public abstract partial class SHA3_512 : HashAlgorithm {
    public const int HashSizeInBits = 512;
    public const int HashSizeInBytes = 64;

    protected SHA3_512();

    [UnsupportedOSPlatformGuard("ios")]
    [UnsupportedOSPlatformGuard("tvos")]
    [UnsupportedOSPlatformGuard("android")]
    [UnsupportedOSPlatformGuard("browser")]
    [UnsupportedOSPlatformGuard("osx")]
    public static bool IsSupported { get; }

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static new SHA3_512 Create();

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(Stream source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_256 : HMAC {
    public const int HashSizeInBits = 256;
    public const int HashSizeInBytes = 32;

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public HMACSHA3_256();

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public HMACSHA3_256(byte[] key);

    [UnsupportedOSPlatformGuard("ios")]
    [UnsupportedOSPlatformGuard("tvos")]
    [UnsupportedOSPlatformGuard("android")]
    [UnsupportedOSPlatformGuard("browser")]
    [UnsupportedOSPlatformGuard("osx")]
    public static bool IsSupported { get; } // New

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] key, byte[] source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] key, Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_384 : HMAC {
    public const int HashSizeInBits = 384;
    public const int HashSizeInBytes = 48;

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public HMACSHA3_384();

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public HMACSHA3_384(byte[] key);

    [UnsupportedOSPlatformGuard("ios")]
    [UnsupportedOSPlatformGuard("tvos")]
    [UnsupportedOSPlatformGuard("android")]
    [UnsupportedOSPlatformGuard("browser")]
    [UnsupportedOSPlatformGuard("osx")]
    public static bool IsSupported { get; } // New

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] key, byte[] source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] key, Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_512 : HMAC {
    public const int HashSizeInBits = 512;
    public const int HashSizeInBytes = 64;

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public HMACSHA3_512();

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public HMACSHA3_512(byte[] key);

    [UnsupportedOSPlatformGuard("ios")]
    [UnsupportedOSPlatformGuard("tvos")]
    [UnsupportedOSPlatformGuard("android")]
    [UnsupportedOSPlatformGuard("browser")]
    [UnsupportedOSPlatformGuard("osx")]
    public static bool IsSupported { get; } // New

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] key, byte[] source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(byte[] key, Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);

    [UnsupportedOSPlatform("ios")]
    [UnsupportedOSPlatform("tvos")]
    [UnsupportedOSPlatform("android")]
    [UnsupportedOSPlatform("browser")]
    [UnsupportedOSPlatform("osx")]
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("browser")]
[UnsupportedOSPlatform("osx")]
public sealed partial class Shake128 : IDisposable {

    public Shake128();

    [UnsupportedOSPlatformGuard("ios")]
    [UnsupportedOSPlatformGuard("tvos")]
    [UnsupportedOSPlatformGuard("android")]
    [UnsupportedOSPlatformGuard("browser")]
    [UnsupportedOSPlatformGuard("osx")]
    public static bool IsSupported { get; }

    public void AppendData(byte[] data);
    public void AppendData(ReadOnlySpan<byte> data);
    public byte[] GetCurrentHash(int outputLength);
    public void GetCurrentHash(Span<byte> destination);
    public byte[] GetHashAndReset(int outputLength);
    public void GetHashAndReset(Span<byte> destination);
    public void Dispose();

    public static byte[] HashData(byte[] source, int outputLength);
    public static byte[] HashData(ReadOnlySpan<byte> source, int outputLength);
    public static void HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    public static byte[] HashData(Stream source, int outputLength);
    public static void HashData(Stream source, Span<byte> destination);
    public static ValueTask HashDataAsync(Stream source, Memory<byte> destination, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(Stream source, int outputLength, CancellationToken cancellationToken = default);
}

[UnsupportedOSPlatform("ios")]
[UnsupportedOSPlatform("tvos")]
[UnsupportedOSPlatform("android")]
[UnsupportedOSPlatform("browser")]
[UnsupportedOSPlatform("osx")]
public sealed partial class Shake256 : IDisposable {

    public Shake256();

    [UnsupportedOSPlatformGuard("ios")]
    [UnsupportedOSPlatformGuard("tvos")]
    [UnsupportedOSPlatformGuard("android")]
    [UnsupportedOSPlatformGuard("browser")]
    [UnsupportedOSPlatformGuard("osx")]
    public static bool IsSupported { get; }

    public void AppendData(byte[] data);
    public void AppendData(ReadOnlySpan<byte> data);
    public byte[] GetCurrentHash(int outputLength);
    public void GetCurrentHash(Span<byte> destination);
    public byte[] GetHashAndReset(int outputLength);
    public void GetHashAndReset(Span<byte> destination);
    public void Dispose();

    public static byte[] HashData(byte[] source, int outputLength);
    public static byte[] HashData(ReadOnlySpan<byte> source, int outputLength);
    public static void HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    public static byte[] HashData(Stream source, int outputLength);
    public static void HashData(Stream source, Span<byte> destination);
    public static ValueTask HashDataAsync(Stream source, Memory<byte> destination, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(Stream source, int outputLength, CancellationToken cancellationToken = default);
}
vcsjones commented 1 year ago

This is going back to review just to further discuss the SupportedOSPlatform attributes. The proposal in the top post has been amended.

bartonjs commented 1 year ago

Video

We discussed removing the attributes and treating it similar to how we do the intrinsics... if there's an IsSupported it's up to you to know to check it (or to not check it because you have no fallback).

We should similarly remove the OS-support attributes from Ed25519 types.

namespace System.Security.Cryptography;

public partial struct HashAlgorithmName {
    public static HashAlgorithmName SHA3_256 { get; }
    public static HashAlgorithmName SHA3_384 { get; }
    public static HashAlgorithmName SHA3_512 { get; }
}

public sealed partial class RSAEncryptionPadding {
    public static RSAEncryptionPadding OaepSHA3_256 { get; }
    public static RSAEncryptionPadding OaepSHA3_384 { get; }
    public static RSAEncryptionPadding OaepSHA3_512 { get; }
}

public abstract partial class SHA3_256 : HashAlgorithm {
    public const int HashSizeInBits = 256;
    public const int HashSizeInBytes = 32;

    protected SHA3_256();

    public static bool IsSupported { get; }

    public static new SHA3_256 Create();

    public static byte[] HashData(byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    public static byte[] HashData(Stream source);
    public static int HashData(Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public abstract partial class SHA3_384 : HashAlgorithm {
    public const int HashSizeInBits = 384;
    public const int HashSizeInBytes = 48;

    protected SHA3_384();

    public static bool IsSupported { get; }

    public static new SHA3_384 Create();

    public static byte[] HashData(byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    public static byte[] HashData(Stream source);
    public static int HashData(Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public abstract partial class SHA3_512 : HashAlgorithm {
    public const int HashSizeInBits = 512;
    public const int HashSizeInBytes = 64;

    protected SHA3_512();

    public static bool IsSupported { get; }

    public static new SHA3_512 Create();

    public static byte[] HashData(byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten);

    public static byte[] HashData(Stream source);
    public static int HashData(Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_256 : HMAC {
    public const int HashSizeInBits = 256;
    public const int HashSizeInBytes = 32;

    public HMACSHA3_256();
    public HMACSHA3_256(byte[] key);

    public static bool IsSupported { get; } // New

    public static byte[] HashData(byte[] key, byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);

    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    public static byte[] HashData(byte[] key, Stream source);
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_384 : HMAC {
    public const int HashSizeInBits = 384;
    public const int HashSizeInBytes = 48;

    public HMACSHA3_384();
    public HMACSHA3_384(byte[] key);

    public static bool IsSupported { get; } // New

    public static byte[] HashData(byte[] key, byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    public static byte[] HashData(byte[] key, Stream source);
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public partial class HMACSHA3_512 : HMAC {
    public const int HashSizeInBits = 512;
    public const int HashSizeInBytes = 64;

    public HMACSHA3_512();
    public HMACSHA3_512(byte[] key);

    public static bool IsSupported { get; } // New

    public static byte[] HashData(byte[] key, byte[] source);
    public static byte[] HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source);
    public static int HashData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination);
    public static bool TryHashData(
        ReadOnlySpan<byte> key,
        ReadOnlySpan<byte> source,
        Span<byte> destination,
        out int bytesWritten);

    public static byte[] HashData(byte[] key, Stream source);
    public static byte[] HashData(ReadOnlySpan<byte> key, Stream source);
    public static int HashData(ReadOnlySpan<byte> key, Stream source, Span<byte> destination);
    public static ValueTask<byte[]> HashDataAsync(byte[] key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(ReadOnlyMemory<byte> key, Stream source, CancellationToken cancellationToken = default);
    public static ValueTask<int> HashDataAsync(
        ReadOnlyMemory<byte> key,
        Stream source,
        Memory<byte> destination,
        CancellationToken cancellationToken = default);
}

public sealed partial class Shake128 : IDisposable {

    public Shake128();

    public static bool IsSupported { get; }

    public void AppendData(byte[] data);
    public void AppendData(ReadOnlySpan<byte> data);
    public byte[] GetCurrentHash(int outputLength);
    public void GetCurrentHash(Span<byte> destination);
    public byte[] GetHashAndReset(int outputLength);
    public void GetHashAndReset(Span<byte> destination);
    public void Dispose();

    public static byte[] HashData(byte[] source, int outputLength);
    public static byte[] HashData(ReadOnlySpan<byte> source, int outputLength);
    public static void HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    public static byte[] HashData(Stream source, int outputLength);
    public static void HashData(Stream source, Span<byte> destination);
    public static ValueTask HashDataAsync(Stream source, Memory<byte> destination, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(Stream source, int outputLength, CancellationToken cancellationToken = default);
}

public sealed partial class Shake256 : IDisposable {

    public Shake256();

    public static bool IsSupported { get; }

    public void AppendData(byte[] data);
    public void AppendData(ReadOnlySpan<byte> data);
    public byte[] GetCurrentHash(int outputLength);
    public void GetCurrentHash(Span<byte> destination);
    public byte[] GetHashAndReset(int outputLength);
    public void GetHashAndReset(Span<byte> destination);
    public void Dispose();

    public static byte[] HashData(byte[] source, int outputLength);
    public static byte[] HashData(ReadOnlySpan<byte> source, int outputLength);
    public static void HashData(ReadOnlySpan<byte> source, Span<byte> destination);

    public static byte[] HashData(Stream source, int outputLength);
    public static void HashData(Stream source, Span<byte> destination);
    public static ValueTask HashDataAsync(Stream source, Memory<byte> destination, CancellationToken cancellationToken = default);
    public static ValueTask<byte[]> HashDataAsync(Stream source, int outputLength, CancellationToken cancellationToken = default);
}
vcsjones commented 1 year ago

SHA-3 has been merged, except for SHAKE128 and SHAKE256. I hope to get a pull request open for those in the next week or two.

Neustradamus commented 1 year ago

@vcsjones: Thanks a lot for your work!

Linked to: