Skip to content
Open
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 @@ -15,7 +15,7 @@ private static unsafe partial NTSTATUS BCryptDeriveKey(
SafeBCryptSecretHandle hSharedSecret,
string pwszKDF,
ref readonly BCryptBufferDesc pParameterList,
Span<byte> pbDerivedKey,
byte* pbDerivedKey,
uint cbDerivedKey,
out uint pcbResult,
uint dwFlags);
Expand All @@ -27,21 +27,24 @@ internal static unsafe void BCryptDeriveKey(
Span<byte> destination,
out int written)
{
NTSTATUS status = BCryptDeriveKey(
hSharedSecret,
pwszKDF,
in parameterList,
destination,
(uint)destination.Length,
out uint pcbResult,
0);

if (status != NTSTATUS.STATUS_SUCCESS)
fixed (byte* pDestination = destination)
{
throw CreateCryptographicException(status);
}
NTSTATUS status = BCryptDeriveKey(
hSharedSecret,
pwszKDF,
in parameterList,
pDestination,
(uint)destination.Length,
out uint pcbResult,
0);

written = checked((int)pcbResult);
if (status != NTSTATUS.STATUS_SUCCESS)
{
throw CreateCryptographicException(status);
}

written = checked((int)pcbResult);
}
}
}
}
10 changes: 9 additions & 1 deletion src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Keys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,15 @@ internal static partial class NCrypt
internal static partial ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, IntPtr pParameterList, ref byte pbOutput, int cbOutput, out int pcbResult, int dwFlags);

[LibraryImport(Interop.Libraries.NCrypt, StringMarshalling = StringMarshalling.Utf16)]
internal static partial ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, IntPtr pParameterList, Span<byte> pbOutput, int cbOutput, out int pcbResult, int dwFlags);
private static unsafe partial ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, IntPtr pParameterList, byte* pbOutput, int cbOutput, out int pcbResult, int dwFlags);

internal static unsafe ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, IntPtr pParameterList, Span<byte> pbOutput, int cbOutput, out int pcbResult, int dwFlags)
{
fixed (byte* pOutput = pbOutput)
{
return NCryptExportKey(hKey, hExportKey, pszBlobType, pParameterList, pOutput, cbOutput, out pcbResult, dwFlags);
}
}

[LibraryImport(Interop.Libraries.NCrypt, StringMarshalling = StringMarshalling.Utf16)]
internal static partial ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, ref NCryptBufferDesc pParameterList, ref byte pbOutput, int cbOutput, out int pcbResult, int dwFlags);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ private static partial ErrorCode NCryptDeriveKey(
SafeNCryptSecretHandle hSharedSecret,
string pwszKDF,
IntPtr pParameterList,
Span<byte> pbDerivedKey,
byte* pbDerivedKey,
int cbDerivedKey,
out int pcbResult,
SecretAgreementFlags dwFlags);
Expand Down Expand Up @@ -252,7 +252,7 @@ internal static byte[] DeriveKeyMaterialTruncate(
SafeNCryptSecretHandle secretAgreement,
SecretAgreementFlags flags)
{
if (!OperatingSystem.IsWindowsVersionAtLeast(10))
if (!IsWindows10OrGreater())
{
throw new PlatformNotSupportedException();
}
Comment thread
vcsjones marked this conversation as resolved.
Expand All @@ -268,20 +268,42 @@ internal static byte[] DeriveKeyMaterialTruncate(
return result;
}

private static bool IsWindows10OrGreater()
{
#if NET
return OperatingSystem.IsWindowsVersionAtLeast(10);
#elif NETSTANDARD
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && Environment.OSVersion.Version.Major >= 10;
#elif NETFRAMEWORK
return Environment.OSVersion.Version.Major >= 10;
#else
#error Unhandled platform target
#endif
}

internal static bool TryDeriveKeyMaterialTruncate(
SafeNCryptSecretHandle secretAgreement,
SecretAgreementFlags flags,
Span<byte> destination,
out int bytesWritten)
{
ErrorCode error = NCryptDeriveKey(
secretAgreement,
BCryptNative.KeyDerivationFunction.Raw,
IntPtr.Zero,
destination,
destination.Length,
out int localWritten,
flags);
ErrorCode error;
int localWritten;

unsafe
{
fixed (byte* pDestination = destination)
{
error = NCryptDeriveKey(
secretAgreement,
BCryptNative.KeyDerivationFunction.Raw,
IntPtr.Zero,
pDestination,
destination.Length,
out localWritten,
flags);
}
}

switch (error)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using Internal.Cryptography;
using Microsoft.Win32.SafeHandles;

internal static partial class Interop
Expand All @@ -29,7 +28,6 @@ internal static unsafe partial ErrorCode NCryptSetProperty(
int cbInput,
CngPropertyOptions dwFlags);

[SupportedOSPlatform("windows")]
internal static unsafe ErrorCode NCryptGetByteProperty(SafeNCryptHandle hObject, string pszProperty, ref byte result, CngPropertyOptions options = CngPropertyOptions.None)
{
fixed (byte* pResult = &result)
Expand All @@ -55,8 +53,6 @@ internal static unsafe ErrorCode NCryptGetIntProperty(SafeNCryptHandle hObject,
{
fixed (int* pResult = &result)
{
Debug.Assert(Helpers.IsOSPlatformWindows);

ErrorCode errorCode = Interop.NCrypt.NCryptGetProperty(
hObject,
pszProperty,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ internal static unsafe bool ExportPkcs8KeyBlob(

Interop.NCrypt.PBE_PARAMS pbeParams = default;
Span<byte> salt = new Span<byte>(pbeParams.rgbSalt, Interop.NCrypt.PBE_PARAMS.RgbSaltSize);
RandomNumberGenerator.Fill(salt);
RngFill(salt);
pbeParams.Params.cbSalt = salt.Length;
pbeParams.Params.iIterations = kdfCount;

Expand Down Expand Up @@ -338,10 +338,48 @@ ref MemoryMarshal.GetReference(destination),
}
}

[SupportedOSPlatform("windows")]
internal static CngKey Duplicate(this SafeNCryptKeyHandle keyHandle, bool isEphemeral)
{
#pragma warning disable CA1416 // only supported on: 'windows'
return CngKey.Open(keyHandle, isEphemeral ? CngKeyHandleOpenOptions.EphemeralKey : CngKeyHandleOpenOptions.None);
#pragma warning restore CA1416 // only supported on: 'windows'
}

internal static CngKey Duplicate(this CngKey key)
{
#if SYSTEM_SECURITY_CRYPTOGRAPHY
return Duplicate(key.HandleNoDuplicate, key.IsEphemeral);
#else
#pragma warning disable CA1416 // only supported on: 'windows'
using (SafeNCryptKeyHandle handle = key.Handle)
{
return Duplicate(handle, key.IsEphemeral);
}
#pragma warning restore CA1416 // only supported on: 'windows'
#endif
}

private static void RngFill(Span<byte> destination)
{
#if NET
RandomNumberGenerator.Fill(destination);
Comment thread
vcsjones marked this conversation as resolved.
#else
byte[] tmp = new byte[destination.Length];

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

tmp.AsSpan().CopyTo(destination);
}
finally
{
CryptographicOperations.ZeroMemory(tmp);
}
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1877,9 +1877,7 @@ private AsnWriter WriteSubjectPublicKeyToAsnWriter()
return writer;
}

private delegate TResult ProcessExportedContent<TResult>(ReadOnlySpan<byte> exportedContent);

private TResult ExportPkcs8PrivateKeyCallback<TResult>(ProcessExportedContent<TResult> func)
private TResult ExportPkcs8PrivateKeyCallback<TResult>(ExportPkcs8PrivateKeyFunc<TResult> func)
{
int size = Algorithm.MaxPrivateKeySizeInBytes;
byte[] buffer = CryptoPool.Rent(size);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@

namespace System.Security.Cryptography
{
internal delegate TResult ExportPkcs8PrivateKeyFunc<TResult>(ReadOnlySpan<byte> pkcs8);

internal delegate AsnWriter WriteEncryptedPkcs8Func<TChar>(
ReadOnlySpan<TChar> password,
AsnWriter writer,
PbeParameters pbeParameters);

internal static partial class KeyFormatHelper
{
internal delegate void KeyReader<TRet>(ReadOnlySpan<byte> key, in ValueAlgorithmIdentifierAsn algId, out TRet ret);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2335,6 +2335,5 @@ internal static void ThrowIfNotSupported()
return hashAlgorithmIdentifier;
}

private delegate TResult ExportPkcs8PrivateKeyFunc<TResult>(ReadOnlySpan<byte> pkcs8);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,7 @@ private static partial MLDsaAlgorithm AlgorithmFromHandle(CngKey key, out CngKey

MLDsaAlgorithm algorithm = AlgorithmFromHandleImpl(key);

#if SYSTEM_SECURITY_CRYPTOGRAPHY
duplicateKey = CngHelpers.Duplicate(key.HandleNoDuplicate, key.IsEphemeral);
#else
duplicateKey = key.Duplicate();
#endif

return algorithm;
}
Expand Down Expand Up @@ -98,13 +94,7 @@ public partial CngKey GetKey()
{
ThrowIfDisposed();

#if SYSTEM_SECURITY_CRYPTOGRAPHY
return CngHelpers.Duplicate(_key.HandleNoDuplicate, _key.IsEphemeral);
#else
#pragma warning disable CA1416 // only supported on: 'windows'
return _key.Duplicate();
#pragma warning restore CA1416 // only supported on: 'windows'
#endif
}

internal CngKey KeyNoDuplicate => _key;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1838,11 +1838,5 @@ private protected static void ThrowIfNoDecapsulationKey(bool hasDecapsulationKey
}
}

private delegate TResult ExportPkcs8PrivateKeyFunc<TResult>(ReadOnlySpan<byte> pkcs8);

private delegate AsnWriter WriteEncryptedPkcs8Func<TChar>(
ReadOnlySpan<TChar> password,
AsnWriter writer,
PbeParameters pbeParameters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,7 @@ private static partial MLKemAlgorithm AlgorithmFromHandle(CngKey key, out CngKey

MLKemAlgorithm algorithm = AlgorithmFromHandleImpl(key);

#if SYSTEM_SECURITY_CRYPTOGRAPHY
duplicateKey = CngHelpers.Duplicate(key.HandleNoDuplicate, key.IsEphemeral);
#else
duplicateKey = key.Duplicate();
#endif

return algorithm;
}
Expand Down Expand Up @@ -90,13 +86,7 @@ public partial CngKey GetKey()
{
ThrowIfDisposed();

#if SYSTEM_SECURITY_CRYPTOGRAPHY
return CngHelpers.Duplicate(_key.HandleNoDuplicate, _key.IsEphemeral);
#else
#pragma warning disable CA1416 // only supported on: 'windows'
return _key.Duplicate();
#pragma warning restore CA1416 // only supported on: 'windows'
#endif
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2003,6 +2003,5 @@ private static void ThrowIfNotSupported()
}
}

private delegate TResult ExportPkcs8PrivateKeyFunc<TResult>(ReadOnlySpan<byte> pkcs8);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace System.Security.Cryptography
/// cryptographic libraries.
/// </para>
/// </remarks>
public abstract class X25519DiffieHellman : IDisposable
public abstract partial class X25519DiffieHellman : IDisposable
{
private protected static readonly string[] s_knownOids = [Oids.X25519];

Expand Down Expand Up @@ -1433,9 +1433,11 @@ protected virtual void Dispose(bool disposing)
private protected static bool TryWriteSubjectPublicKeyInfo<TState>(
Span<byte> destination,
TState state,
Action<TState, Span<byte>> writer,
WriteKeyFunc<TState> writer,
out int bytesWritten)
#if NET
where TState : allows ref struct
#endif
{
// Pre-encoded SubjectPublicKeyInfo for X25519 (RFC 8410):
ReadOnlySpan<byte> spkiPreamble =
Expand Down Expand Up @@ -1468,7 +1470,7 @@ private bool TryExportSubjectPublicKeyInfoCore(Span<byte> destination, out int b
out bytesWritten);
}

private TResult ExportPkcs8PrivateKeyCallback<TResult>(Func<ReadOnlySpan<byte>, TResult> func)
private TResult ExportPkcs8PrivateKeyCallback<TResult>(ExportPkcs8PrivateKeyFunc<TResult> func)
{
// A PKCS#8 X25519 PrivateKeyInfo has an ASN.1 overhead of 16 bytes, assuming no attributes.
// Make it an even 32 and that should give a good starting point for a buffer size.
Expand Down Expand Up @@ -1507,9 +1509,11 @@ private protected bool TryExportPkcs8PrivateKeyImpl(Span<byte> destination, out
private protected static bool TryWritePkcs8PrivateKey<TState>(
Span<byte> destination,
TState state,
Action<TState, Span<byte>> writer,
WriteKeyFunc<TState> writer,
out int bytesWritten)
#if NET
where TState : allows ref struct
#endif
{
// Pre-encoded PKCS#8 PrivateKeyInfo for X25519 (RFC 8410):
ReadOnlySpan<byte> pkcs8Preamble =
Expand Down Expand Up @@ -1548,7 +1552,7 @@ private protected static bool TryWritePkcs8PrivateKey<TState>(
private AsnWriter ExportEncryptedPkcs8PrivateKeyCore<TChar>(
ReadOnlySpan<TChar> password,
PbeParameters pbeParameters,
Func<ReadOnlySpan<TChar>, AsnWriter, PbeParameters, AsnWriter> encryptor)
WriteEncryptedPkcs8Func<TChar> encryptor)
{
// A PKCS#8 X25519 PrivateKeyInfo has an ASN.1 overhead of 16 bytes, assuming no attributes.
// Make it an even 32 and that should give a good starting point for a buffer size.
Expand Down Expand Up @@ -1618,5 +1622,13 @@ private protected static void ThrowIfNotSupported()
nameof(X25519DiffieHellman)));
}
}

private protected delegate void WriteKeyFunc<TState>(TState state, Span<byte> destination)
#if NET
where TState : allows ref struct;
#else
;
#endif

}
}
Loading
Loading