File: System\Security\Cryptography\SP800108HmacCounterKdfImplementationOpenSsl.cs
Web Access
Project: src\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using Microsoft.Win32.SafeHandles;
 
namespace System.Security.Cryptography
{
    internal sealed class SP800108HmacCounterKdfImplementationOpenSsl : SP800108HmacCounterKdfImplementationBase
    {
        private const int CharToBytesStackBufferSize = 256;
 
        private readonly HashAlgorithmName _hashAlgorithm;
        private readonly FixedMemoryKeyBox _keyBox;
 
        internal unsafe SP800108HmacCounterKdfImplementationOpenSsl(ReadOnlySpan<byte> key, HashAlgorithmName hashAlgorithm)
        {
            _hashAlgorithm = hashAlgorithm;
            _keyBox = new FixedMemoryKeyBox(key);
        }
 
        public override void Dispose()
        {
            _keyBox.Dispose();
        }
 
        internal override unsafe void DeriveBytes(ReadOnlySpan<byte> label, ReadOnlySpan<byte> context, Span<byte> destination)
        {
            Debug.Assert(Interop.Crypto.EvpKdfAlgs.Kbkdf is { IsInvalid: false });
 
            if (destination.IsEmpty)
            {
                return;
            }
 
            bool acquired = false;
 
            try
            {
                _keyBox.DangerousAddRef(ref acquired);
                Interop.Crypto.KbkdfHmacOneShot(
                    Interop.Crypto.EvpKdfAlgs.Kbkdf,
                    _keyBox.DangerousKeySpan,
                    _hashAlgorithm.Name!,
                    label,
                    context,
                    destination);
            }
            finally
            {
                if (acquired)
                {
                    _keyBox.DangerousRelease();
                }
            }
        }
 
        internal override void DeriveBytes(byte[] label, byte[] context, Span<byte> destination)
        {
            DeriveBytes(new ReadOnlySpan<byte>(label), new ReadOnlySpan<byte>(context), destination);
        }
 
        internal override void DeriveBytes(ReadOnlySpan<char> label, ReadOnlySpan<char> context, Span<byte> destination)
        {
            using (Utf8DataEncoding labelData = new Utf8DataEncoding(label, stackalloc byte[CharToBytesStackBufferSize]))
            using (Utf8DataEncoding contextData = new Utf8DataEncoding(context, stackalloc byte[CharToBytesStackBufferSize]))
            {
                DeriveBytes(labelData.Utf8Bytes, contextData.Utf8Bytes, destination);
            }
        }
 
        internal static void DeriveBytesOneShot(
            ReadOnlySpan<byte> key,
            HashAlgorithmName hashAlgorithm,
            ReadOnlySpan<byte> label,
            ReadOnlySpan<byte> context,
            Span<byte> destination)
        {
            Debug.Assert(Interop.Crypto.EvpKdfAlgs.Kbkdf is { IsInvalid: false });
 
            if (destination.IsEmpty)
            {
                return;
            }
 
            Interop.Crypto.KbkdfHmacOneShot(
                Interop.Crypto.EvpKdfAlgs.Kbkdf,
                key,
                hashAlgorithm.Name!,
                label,
                context,
                destination);
        }
 
        internal static void DeriveBytesOneShot(
            ReadOnlySpan<byte> key,
            HashAlgorithmName hashAlgorithm,
            ReadOnlySpan<char> label,
            ReadOnlySpan<char> context,
            Span<byte> destination)
        {
            if (destination.Length == 0)
            {
                return;
            }
 
            using (Utf8DataEncoding labelData = new Utf8DataEncoding(label, stackalloc byte[CharToBytesStackBufferSize]))
            using (Utf8DataEncoding contextData = new Utf8DataEncoding(context, stackalloc byte[CharToBytesStackBufferSize]))
            {
                DeriveBytesOneShot(key, hashAlgorithm, labelData.Utf8Bytes, contextData.Utf8Bytes, destination);
            }
        }
    }
}