Skip to content

Clone for IncrementalHash and KMAC #103479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,8 @@ internal static unsafe int EvpDigestCurrentXOF(SafeEvpMdCtxHandle ctx, Span<byte
throw new UnreachableException();
}

internal static SafeEvpMdCtxHandle EvpMdCtxCopyEx(SafeEvpMdCtxHandle ctx)
{
_ = ctx;
Debug.Fail("Should have validated that XOF is not supported before getting here.");
throw new UnreachableException();
}
[LibraryImport(Libraries.AndroidCryptoNative, EntryPoint = "CryptoNative_EvpMdCtxCopyEx")]
internal static partial SafeEvpMdCtxHandle EvpMdCtxCopyEx(SafeEvpMdCtxHandle ctx);

internal static int EvpDigestSqueeze(SafeEvpMdCtxHandle ctx, Span<byte> destination)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ internal static partial class Crypto
[LibraryImport(Libraries.AndroidCryptoNative, EntryPoint = "CryptoNative_HmacOneShot")]
private static unsafe partial int HmacOneShot(IntPtr type, byte* key, int keySize, byte* source, int sourceSize, byte* md, ref int mdSize);

internal static SafeHmacCtxHandle HmacCopy(SafeHmacCtxHandle ctx) => throw new PlatformNotSupportedException();

internal static unsafe int HmacOneShot(IntPtr type, ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
{
int size = destination.Length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ internal static int DigestCurrent(SafeDigestCtxHandle ctx, Span<byte> output) =>

[LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestReset")]
internal static partial int DigestReset(SafeDigestCtxHandle ctx);

[LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestClone")]
internal static partial SafeDigestCtxHandle DigestClone(SafeDigestCtxHandle ctx);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ internal static unsafe partial int HmacOneShot(
byte* pOutput,
int cbOutput,
int* cbDigest);

[LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacClone")]
internal static partial SafeHmacHandle HmacClone(SafeHmacHandle ctx);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ private static partial int CryptoNative_EvpMacInit(
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpMacCurrent")]
private static partial int CryptoNative_EvpMacCurrent(SafeEvpMacCtxHandle ctx, Span<byte> mac, int macLength);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpMacCtxDup")]
private static partial SafeEvpMacCtxHandle CryptoNative_EvpMacCtxDup(SafeEvpMacCtxHandle ctx);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpMacOneShot", StringMarshalling = StringMarshalling.Utf8)]
private static partial int CryptoNative_EvpMacOneShot(
SafeEvpMacHandle mac,
Expand Down Expand Up @@ -158,5 +161,18 @@ internal static void EvpMacReset(SafeEvpMacCtxHandle ctx)
throw CreateOpenSslCryptographicException();
}
}

internal static SafeEvpMacCtxHandle EvpMacCtxDup(SafeEvpMacCtxHandle ctx)
{
SafeEvpMacCtxHandle clone = CryptoNative_EvpMacCtxDup(ctx);

if (clone.IsInvalid)
{
clone.Dispose();
throw CreateOpenSslCryptographicException();
}

return clone;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ internal static partial class Crypto
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HmacOneShot")]
private static unsafe partial int HmacOneShot(IntPtr type, byte* key, int keySize, byte* source, int sourceSize, byte* md, int* mdSize);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HmacCopy")]
internal static partial SafeHmacCtxHandle HmacCopy(SafeHmacCtxHandle ctx);

internal static unsafe int HmacOneShot(IntPtr type, ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
{
int size = destination.Length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1616,6 +1616,7 @@ internal IncrementalHash() { }
public void AppendData(byte[] data) { }
public void AppendData(byte[] data, int offset, int count) { }
public void AppendData(System.ReadOnlySpan<byte> data) { }
public System.Security.Cryptography.IncrementalHash Clone() { throw null; }
public static System.Security.Cryptography.IncrementalHash CreateHash(System.Security.Cryptography.HashAlgorithmName hashAlgorithm) { throw null; }
public static System.Security.Cryptography.IncrementalHash CreateHMAC(System.Security.Cryptography.HashAlgorithmName hashAlgorithm, byte[] key) { throw null; }
public static System.Security.Cryptography.IncrementalHash CreateHMAC(System.Security.Cryptography.HashAlgorithmName hashAlgorithm, System.ReadOnlySpan<byte> key) { throw null; }
Expand Down Expand Up @@ -1658,6 +1659,7 @@ public Kmac128(byte[] key, byte[]? customizationString = null) { }
public static bool IsSupported { get { throw null; } }
public void AppendData(byte[] data) { }
public void AppendData(System.ReadOnlySpan<byte> data) { }
public System.Security.Cryptography.Kmac128 Clone() { throw null; }
public void Dispose() { }
public byte[] GetCurrentHash(int outputLength) { throw null; }
public void GetCurrentHash(System.Span<byte> destination) { }
Expand All @@ -1680,6 +1682,7 @@ public Kmac256(byte[] key, byte[]? customizationString = null) { }
public static bool IsSupported { get { throw null; } }
public void AppendData(byte[] data) { }
public void AppendData(System.ReadOnlySpan<byte> data) { }
public System.Security.Cryptography.Kmac256 Clone() { throw null; }
public void Dispose() { }
public byte[] GetCurrentHash(int outputLength) { throw null; }
public void GetCurrentHash(System.Span<byte> destination) { }
Expand All @@ -1702,6 +1705,7 @@ public KmacXof128(byte[] key, byte[]? customizationString = null) { }
public static bool IsSupported { get { throw null; } }
public void AppendData(byte[] data) { }
public void AppendData(System.ReadOnlySpan<byte> data) { }
public System.Security.Cryptography.KmacXof128 Clone() { throw null; }
public void Dispose() { }
public byte[] GetCurrentHash(int outputLength) { throw null; }
public void GetCurrentHash(System.Span<byte> destination) { }
Expand All @@ -1724,6 +1728,7 @@ public KmacXof256(byte[] key, byte[]? customizationString = null) { }
public static bool IsSupported { get { throw null; } }
public void AppendData(byte[] data) { }
public void AppendData(System.ReadOnlySpan<byte> data) { }
public System.Security.Cryptography.KmacXof256 Clone() { throw null; }
public void Dispose() { }
public byte[] GetCurrentHash(int outputLength) { throw null; }
public void GetCurrentHash(System.Span<byte> destination) { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ internal ConcurrentSafeKmac(string algorithmId, ReadOnlySpan<byte> key, ReadOnly
_liteKmac = LiteHashProvider.CreateKmac(algorithmId, key, customizationString, xof);
}

private ConcurrentSafeKmac(LiteKmac liteKmac)
{
_liteKmac = liteKmac;
}

public void Append(ReadOnlySpan<byte> data)
{
using (ConcurrencyBlock.Enter(ref _block))
Expand Down Expand Up @@ -47,6 +52,14 @@ public void Reset()
}
}

public ConcurrentSafeKmac Clone()
{
using (ConcurrencyBlock.Enter(ref _block))
{
return new ConcurrentSafeKmac(_liteKmac.Clone());
}
}

public void Dispose() => _liteKmac.Dispose();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ internal HMACCommon(string hashAlgorithmId, ReadOnlySpan<byte> key, int blockSiz
ActualKey = ChangeKeyImpl(key);
}

private HMACCommon(string hashAlgorithmId, HashProvider hmacProvider, int blockSize, byte[]? actualKey)
{
Debug.Assert(!string.IsNullOrEmpty(hashAlgorithmId));
Debug.Assert(blockSize is > 0 or -1);

_hashAlgorithmId = hashAlgorithmId;
_hMacProvider = hmacProvider;
_blockSize = blockSize;
ActualKey = Helpers.CloneByteArray(actualKey);
}

public int HashSizeInBits => _hMacProvider.HashSizeInBytes * 8;
public int HashSizeInBytes => _hMacProvider.HashSizeInBytes;

Expand Down Expand Up @@ -125,6 +136,11 @@ public int GetCurrentHash(Span<byte> destination) =>

public void Reset() => _hMacProvider.Reset();

public HMACCommon Clone()
{
return new HMACCommon(_hashAlgorithmId, _hMacProvider.Clone(), _blockSize, ActualKey);
}

public void Dispose(bool disposing)
{
if (disposing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,27 @@ public HMACManagedHashProvider(string hashAlgorithmId, ReadOnlySpan<byte> key)
_key = InitializeKey(key);
}

private HMACManagedHashProvider(HashProvider hash1, HashProvider hash2, byte[] key, int blockSize, int hashSize, bool hashing)
{
_hash1 = hash1;
_hash2 = hash2;
_key = key;
_blockSizeValue = blockSize;
_hashSizeValue = hashSize;
_hashing = hashing;

// This constructor is used for cloning so the key should be pre-adjusted.
Debug.Assert(_key.Length <= _blockSizeValue);
}

public override HashProvider Clone()
{
HashProvider hash1Clone = _hash1.Clone();
HashProvider hash2Clone = _hash2.Clone();
byte[] keyClone = _key.AsSpan().ToArray();
return new HMACManagedHashProvider(hash1Clone, hash2Clone, keyClone, _blockSizeValue, _hashSizeValue, _hashing);
}

private byte[] InitializeKey(ReadOnlySpan<byte> key)
{
if (key.Length > _blockSizeValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public void AppendHashData(byte[] data, int offset, int count)
}

public abstract void AppendHashData(ReadOnlySpan<byte> data);
public abstract HashProvider Clone();

// Compute the hash based on the appended data and resets the HashProvider for more hashing.
public abstract int FinalizeHashAndReset(Span<byte> destination);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.Win32.SafeHandles;
using Internal.Cryptography;
using BCryptCreateHashFlags = Interop.BCrypt.BCryptCreateHashFlags;
using BCryptOpenAlgorithmProviderFlags = Interop.BCrypt.BCryptOpenAlgorithmProviderFlags;
using NTSTATUS = Interop.BCrypt.NTSTATUS;
Expand Down Expand Up @@ -62,6 +63,22 @@ internal HashProviderCng(string hashAlgId, ReadOnlySpan<byte> key, bool isHmac)
}
}

private HashProviderCng(
SafeBCryptAlgorithmHandle algorithmHandle,
SafeBCryptHashHandle hashHandle,
byte[]? key,
bool reusable,
int hashSize,
bool running)
{
_hAlgorithm = algorithmHandle;
_hHash = hashHandle;
_key = key.CloneByteArray();
_reusable = reusable;
_hashSize = hashSize;
_running = running;
}

public sealed override unsafe void AppendHashData(ReadOnlySpan<byte> source)
{
Debug.Assert(_hHash != null);
Expand Down Expand Up @@ -119,6 +136,15 @@ public override int GetCurrentHash(Span<byte> destination)
}
}

public override HashProviderCng Clone()
{
using (ConcurrencyBlock.Enter(ref _block))
{
SafeBCryptHashHandle clone = Interop.BCrypt.BCryptDuplicateHash(_hHash);
return new HashProviderCng(_hAlgorithm, clone, _key, _reusable, _hashSize, _running);
}
}

public sealed override void Dispose(bool disposing)
{
if (disposing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ public AppleDigestProvider(string hashAlgorithmId)
_liteHash = LiteHashProvider.CreateHash(hashAlgorithmId);
}

private AppleDigestProvider(LiteHash liteHash, bool running)
{
_liteHash = liteHash;
_running = running;
}

public override void AppendHashData(ReadOnlySpan<byte> data)
{
using (ConcurrencyBlock.Enter(ref _block))
Expand All @@ -157,6 +163,14 @@ public override void AppendHashData(ReadOnlySpan<byte> data)
}
}

public override AppleDigestProvider Clone()
{
using (ConcurrencyBlock.Enter(ref _block))
{
return new AppleDigestProvider(_liteHash.Clone(), _running);
}
}

public override int FinalizeHashAndReset(Span<byte> destination)
{
using (ConcurrencyBlock.Enter(ref _block))
Expand Down Expand Up @@ -213,6 +227,13 @@ public AppleHmacProvider(string hashAlgorithmId, ReadOnlySpan<byte> key)
_key = key.ToArray();
}

private AppleHmacProvider(LiteHmac liteHmac, ReadOnlySpan<byte> key, bool running)
{
_liteHmac = liteHmac;
_running = running;
_key = key.ToArray();
}

public override void AppendHashData(ReadOnlySpan<byte> data)
{
using (ConcurrencyBlock.Enter(ref _block))
Expand Down Expand Up @@ -256,6 +277,14 @@ public override int GetCurrentHash(Span<byte> destination)
}
}

public override AppleHmacProvider Clone()
{
using (ConcurrencyBlock.Enter(ref _block))
{
return new AppleHmacProvider(_liteHmac.Clone(), _key, _running);
}
}

public override int HashSizeInBytes => _liteHmac.HashSizeInBytes;

public override void Dispose(bool disposing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ public EvpHashProvider(string hashAlgorithmId)
_liteHash = LiteHashProvider.CreateHash(hashAlgorithmId);
}

private EvpHashProvider(LiteHash hash, bool running)
{
_liteHash = hash;
_running = running;
}

public override EvpHashProvider Clone()
{
using (ConcurrencyBlock.Enter(ref _block))
{
return new EvpHashProvider(_liteHash.Clone(), _running);
}
}

public override void AppendHashData(ReadOnlySpan<byte> data)
{
using (ConcurrencyBlock.Enter(ref _block))
Expand Down Expand Up @@ -156,6 +170,20 @@ public HmacHashProvider(string hashAlgorithmId, ReadOnlySpan<byte> key)
_liteHmac = LiteHashProvider.CreateHmac(hashAlgorithmId, key);
}

private HmacHashProvider(LiteHmac liteHmac, bool running)
{
_liteHmac = liteHmac;
_running = running;
}

public override HmacHashProvider Clone()
{
using (ConcurrencyBlock.Enter(ref _block))
{
return new HmacHashProvider(_liteHmac.Clone(), _running);
}
}

public override void AppendHashData(ReadOnlySpan<byte> data)
{
using (ConcurrencyBlock.Enter(ref _block))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,22 @@ private int GetCurrentHashCore(Span<byte> destination)
_hmac!.GetCurrentHash(destination);
}

/// <summary>
/// Creates a new instance of <see cref="IncrementalHash" /> with the existing appended data preserved.
/// </summary>
/// <returns>A clone of the current instance.</returns>
/// <exception cref="CryptographicException">An error has occurred during the operation.</exception>
/// <exception cref="ObjectDisposedException">The object has already been disposed.</exception>
public IncrementalHash Clone()
{
ObjectDisposedException.ThrowIf(_disposed, this);
Debug.Assert((_hash != null) ^ (_hmac != null));

return _hash is not null ?
new IncrementalHash(_algorithmName, _hash.Clone()) :
new IncrementalHash(_algorithmName, _hmac!.Clone());
}

/// <summary>
/// Release all resources used by the current instance of the
/// <see cref="IncrementalHash"/> class.
Expand Down
Loading
Loading