| File: System\Security\Cryptography\Pkcs\CmsHash.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography.Pkcs\src\System.Security.Cryptography.Pkcs.csproj (System.Security.Cryptography.Pkcs) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Internal.Cryptography; namespace System.Security.Cryptography.Pkcs { internal abstract class CmsHash : IDisposable { internal static CmsHash Create(Oid oid, bool forVerification) => oid.Value switch { #if NET Oids.Shake128 => new CmsShake128Hash(), Oids.Shake256 => new CmsShake256Hash(), #endif _ => new CmsIncrementalHash(oid, forVerification), }; public abstract void Dispose(); internal abstract void AppendData(ReadOnlySpan<byte> data); internal abstract byte[] GetHashAndReset(); #if NET || NETSTANDARD2_1 internal abstract bool TryGetHashAndReset(Span<byte> destination, out int bytesWritten); #endif #if NET private sealed class CmsShake256Hash : CmsHash { // RFC 8702 specifies SHAKE256 in CMS must use 512 bits of output. private const int OutputSizeBytes = 512 / 8; private readonly Shake256 _shake256; internal CmsShake256Hash() { _shake256 = new Shake256(); } public override void Dispose() => _shake256.Dispose(); internal override void AppendData(ReadOnlySpan<byte> data) => _shake256.AppendData(data); internal override byte[] GetHashAndReset() => _shake256.GetHashAndReset(OutputSizeBytes); internal override bool TryGetHashAndReset(Span<byte> destination, out int bytesWritten) { if (destination.Length < OutputSizeBytes) { bytesWritten = 0; return false; } _shake256.GetHashAndReset(destination.Slice(0, OutputSizeBytes)); bytesWritten = OutputSizeBytes; return true; } } private sealed class CmsShake128Hash : CmsHash { // RFC 8702 specifies SHAKE128 in CMS must use 256 bits of output. private const int OutputSizeBytes = 256 / 8; private readonly Shake128 _shake128; internal CmsShake128Hash() { _shake128 = new Shake128(); } public override void Dispose() => _shake128.Dispose(); internal override void AppendData(ReadOnlySpan<byte> data) => _shake128.AppendData(data); internal override byte[] GetHashAndReset() => _shake128.GetHashAndReset(OutputSizeBytes); internal override bool TryGetHashAndReset(Span<byte> destination, out int bytesWritten) { if (destination.Length < OutputSizeBytes) { bytesWritten = 0; return false; } _shake128.GetHashAndReset(destination.Slice(0, OutputSizeBytes)); bytesWritten = OutputSizeBytes; return true; } } #endif private sealed class CmsIncrementalHash : CmsHash { private readonly IncrementalHash _incrementalHash; internal CmsIncrementalHash(Oid oid, bool forVerification) { _incrementalHash = Helpers.CreateIncrementalHash(PkcsHelpers.GetDigestAlgorithm(oid.Value, forVerification)); } public override void Dispose() => _incrementalHash.Dispose(); internal override void AppendData(ReadOnlySpan<byte> data) => _incrementalHash.AppendData(data); internal override byte[] GetHashAndReset() => _incrementalHash.GetHashAndReset(); #if NET || NETSTANDARD2_1 internal override bool TryGetHashAndReset(Span<byte> destination, out int bytesWritten) => _incrementalHash.TryGetHashAndReset(destination, out bytesWritten); #endif } } }