diff --git a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptDeriveKey.cs b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptDeriveKey.cs index 0ac167f36debaf..01b8b0a989df3e 100644 --- a/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptDeriveKey.cs +++ b/src/libraries/Common/src/Interop/Windows/BCrypt/Interop.BCryptDeriveKey.cs @@ -15,7 +15,7 @@ private static unsafe partial NTSTATUS BCryptDeriveKey( SafeBCryptSecretHandle hSharedSecret, string pwszKDF, ref readonly BCryptBufferDesc pParameterList, - Span pbDerivedKey, + byte* pbDerivedKey, uint cbDerivedKey, out uint pcbResult, uint dwFlags); @@ -27,21 +27,24 @@ internal static unsafe void BCryptDeriveKey( Span 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); + } } } } diff --git a/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Keys.cs b/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Keys.cs index 4cd779d627aeba..a6eca535c0fade 100644 --- a/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Keys.cs +++ b/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Keys.cs @@ -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 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 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); diff --git a/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveKeyMaterial.cs b/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveKeyMaterial.cs index e0c1ada8a4c9f7..36ab5473f932e5 100644 --- a/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveKeyMaterial.cs +++ b/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.NCryptDeriveKeyMaterial.cs @@ -30,7 +30,7 @@ private static partial ErrorCode NCryptDeriveKey( SafeNCryptSecretHandle hSharedSecret, string pwszKDF, IntPtr pParameterList, - Span pbDerivedKey, + byte* pbDerivedKey, int cbDerivedKey, out int pcbResult, SecretAgreementFlags dwFlags); @@ -252,7 +252,7 @@ internal static byte[] DeriveKeyMaterialTruncate( SafeNCryptSecretHandle secretAgreement, SecretAgreementFlags flags) { - if (!OperatingSystem.IsWindowsVersionAtLeast(10)) + if (!IsWindows10OrGreater()) { throw new PlatformNotSupportedException(); } @@ -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 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) { diff --git a/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Properties.cs b/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Properties.cs index 377924f386948f..22bb2a145a914d 100644 --- a/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Properties.cs +++ b/src/libraries/Common/src/Interop/Windows/NCrypt/Interop.Properties.cs @@ -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 @@ -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) @@ -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, diff --git a/src/libraries/Common/src/System/Security/Cryptography/CngHelpers.cs b/src/libraries/Common/src/System/Security/Cryptography/CngHelpers.cs index 1c781f653ce425..cf89fa27bc73d5 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CngHelpers.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CngHelpers.cs @@ -242,7 +242,7 @@ internal static unsafe bool ExportPkcs8KeyBlob( Interop.NCrypt.PBE_PARAMS pbeParams = default; Span salt = new Span(pbeParams.rgbSalt, Interop.NCrypt.PBE_PARAMS.RgbSaltSize); - RandomNumberGenerator.Fill(salt); + RngFill(salt); pbeParams.Params.cbSalt = salt.Length; pbeParams.Params.iIterations = kdfCount; @@ -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 destination) + { +#if NET + RandomNumberGenerator.Fill(destination); +#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 } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs index 8145cdcdcd6e4a..1c90be70113613 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs @@ -1877,9 +1877,7 @@ private AsnWriter WriteSubjectPublicKeyToAsnWriter() return writer; } - private delegate TResult ProcessExportedContent(ReadOnlySpan exportedContent); - - private TResult ExportPkcs8PrivateKeyCallback(ProcessExportedContent func) + private TResult ExportPkcs8PrivateKeyCallback(ExportPkcs8PrivateKeyFunc func) { int size = Algorithm.MaxPrivateKeySizeInBytes; byte[] buffer = CryptoPool.Rent(size); diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs index 31f1a3ffbbc205..7104308a4f1492 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs @@ -9,6 +9,13 @@ namespace System.Security.Cryptography { + internal delegate TResult ExportPkcs8PrivateKeyFunc(ReadOnlySpan pkcs8); + + internal delegate AsnWriter WriteEncryptedPkcs8Func( + ReadOnlySpan password, + AsnWriter writer, + PbeParameters pbeParameters); + internal static partial class KeyFormatHelper { internal delegate void KeyReader(ReadOnlySpan key, in ValueAlgorithmIdentifierAsn algId, out TRet ret); diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs index ccf270bf419833..b51046d7dd279b 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs @@ -2335,6 +2335,5 @@ internal static void ThrowIfNotSupported() return hashAlgorithmIdentifier; } - private delegate TResult ExportPkcs8PrivateKeyFunc(ReadOnlySpan pkcs8); } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLDsaCng.Windows.cs b/src/libraries/Common/src/System/Security/Cryptography/MLDsaCng.Windows.cs index a2ec3aaf4dab37..1addab31a360be 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLDsaCng.Windows.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLDsaCng.Windows.cs @@ -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; } @@ -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; diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs b/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs index 7a8c377cfb77cc..a83ea5ddd71576 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs @@ -1838,11 +1838,5 @@ private protected static void ThrowIfNoDecapsulationKey(bool hasDecapsulationKey } } - private delegate TResult ExportPkcs8PrivateKeyFunc(ReadOnlySpan pkcs8); - - private delegate AsnWriter WriteEncryptedPkcs8Func( - ReadOnlySpan password, - AsnWriter writer, - PbeParameters pbeParameters); } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLKemCng.Windows.cs b/src/libraries/Common/src/System/Security/Cryptography/MLKemCng.Windows.cs index df238d5c28ab17..64a84cf0ee5bd4 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLKemCng.Windows.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLKemCng.Windows.cs @@ -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; } @@ -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 } /// diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs index c22659afdb3cc3..bcc2ee4d13a0a9 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs @@ -2003,6 +2003,5 @@ private static void ThrowIfNotSupported() } } - private delegate TResult ExportPkcs8PrivateKeyFunc(ReadOnlySpan pkcs8); } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellman.cs b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellman.cs similarity index 99% rename from src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellman.cs rename to src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellman.cs index 32fa23d7d46df9..390fb964a1b832 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellman.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellman.cs @@ -20,7 +20,7 @@ namespace System.Security.Cryptography /// cryptographic libraries. /// /// - public abstract class X25519DiffieHellman : IDisposable + public abstract partial class X25519DiffieHellman : IDisposable { private protected static readonly string[] s_knownOids = [Oids.X25519]; @@ -1433,9 +1433,11 @@ protected virtual void Dispose(bool disposing) private protected static bool TryWriteSubjectPublicKeyInfo( Span destination, TState state, - Action> writer, + WriteKeyFunc writer, out int bytesWritten) +#if NET where TState : allows ref struct +#endif { // Pre-encoded SubjectPublicKeyInfo for X25519 (RFC 8410): ReadOnlySpan spkiPreamble = @@ -1468,7 +1470,7 @@ private bool TryExportSubjectPublicKeyInfoCore(Span destination, out int b out bytesWritten); } - private TResult ExportPkcs8PrivateKeyCallback(Func, TResult> func) + private TResult ExportPkcs8PrivateKeyCallback(ExportPkcs8PrivateKeyFunc 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. @@ -1507,9 +1509,11 @@ private protected bool TryExportPkcs8PrivateKeyImpl(Span destination, out private protected static bool TryWritePkcs8PrivateKey( Span destination, TState state, - Action> writer, + WriteKeyFunc writer, out int bytesWritten) +#if NET where TState : allows ref struct +#endif { // Pre-encoded PKCS#8 PrivateKeyInfo for X25519 (RFC 8410): ReadOnlySpan pkcs8Preamble = @@ -1548,7 +1552,7 @@ private protected static bool TryWritePkcs8PrivateKey( private AsnWriter ExportEncryptedPkcs8PrivateKeyCore( ReadOnlySpan password, PbeParameters pbeParameters, - Func, AsnWriter, PbeParameters, AsnWriter> encryptor) + WriteEncryptedPkcs8Func 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. @@ -1618,5 +1622,13 @@ private protected static void ThrowIfNotSupported() nameof(X25519DiffieHellman))); } } + + private protected delegate void WriteKeyFunc(TState state, Span destination) +#if NET + where TState : allows ref struct; +#else + ; +#endif + } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanCng.Windows.cs b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanCng.Windows.cs similarity index 86% rename from src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanCng.Windows.cs rename to src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanCng.Windows.cs index 398c6a5e92c3e9..4bdeafdbfdac0c 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanCng.Windows.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanCng.Windows.cs @@ -4,8 +4,8 @@ using System.Diagnostics; using System.Formats.Asn1; using System.Security.Cryptography.Asn1; -using Microsoft.Win32.SafeHandles; using Internal.Cryptography; +using Microsoft.Win32.SafeHandles; using ErrorCode = Interop.NCrypt.ErrorCode; @@ -18,23 +18,26 @@ public sealed partial class X25519DiffieHellmanCng : X25519DiffieHellman public partial X25519DiffieHellmanCng(CngKey key) { - Debug.Assert(Helpers.IsOSPlatformWindows); + if (!Helpers.IsOSPlatformWindows) + { + throw new PlatformNotSupportedException(); + } + ArgumentNullException.ThrowIfNull(key); ThrowIfNotSupported(); - if (key.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman || - key.GetCurveName(out _) != X25519WindowsHelpers.BCRYPT_ECC_CURVE_25519) + if (key.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman || !IsX25519Key(key)) { throw new ArgumentException(SR.Cryptography_ArgX25519RequiresX25519Key, nameof(key)); } - _key = CngHelpers.Duplicate(key.HandleNoDuplicate, key.IsEphemeral); + _key = key.Duplicate(); } public partial CngKey GetKey() { ThrowIfDisposed(); - return CngHelpers.Duplicate(_key.HandleNoDuplicate, _key.IsEphemeral); + return _key.Duplicate(); } protected override unsafe partial void DeriveRawSecretAgreementCore(X25519DiffieHellman otherParty, Span destination) @@ -87,9 +90,16 @@ private void DeriveRawSecretAgreementWithPublicKey(ReadOnlySpan otherParty flags); using (keyHandle) +#if SYSTEM_SECURITY_CRYPTOGRAPHY using (SafeNCryptSecretHandle secretAgreement = Interop.NCrypt.DeriveSecretAgreement( _key.HandleNoDuplicate, keyHandle)) +#else + using (SafeNCryptKeyHandle currentKeyHandle = _key.Handle) + using (SafeNCryptSecretHandle secretAgreement = Interop.NCrypt.DeriveSecretAgreement( + currentKeyHandle, + keyHandle)) +#endif { bool success = Interop.NCrypt.TryDeriveKeyMaterialTruncate( secretAgreement, @@ -163,8 +173,14 @@ private static void ExportKeyFromBlob(CngKey key, bool privateKey, Span de CngKeyBlobFormat.EccPrivateBlob.Format : CngKeyBlobFormat.EccPublicBlob.Format; +#if SYSTEM_SECURITY_CRYPTOGRAPHY + SafeNCryptKeyHandle keyHandle = key.HandleNoDuplicate; +#else + using SafeNCryptKeyHandle keyHandle = key.Handle; +#endif + ErrorCode errorCode = Interop.NCrypt.NCryptExportKey( - key.HandleNoDuplicate, + keyHandle, IntPtr.Zero, format, IntPtr.Zero, @@ -181,7 +197,7 @@ private static void ExportKeyFromBlob(CngKey key, bool privateKey, Span de using (CryptoPoolLease lease = CryptoPoolLease.Rent(numBytesNeeded, skipClear: !privateKey)) { errorCode = Interop.NCrypt.NCryptExportKey( - key.HandleNoDuplicate, + keyHandle, IntPtr.Zero, format, IntPtr.Zero, @@ -199,19 +215,30 @@ private static void ExportKeyFromBlob(CngKey key, bool privateKey, Span de } } + private static bool IsX25519Key(CngKey key) + { +#if SYSTEM_SECURITY_CRYPTOGRAPHY + return key.GetCurveName(out _) == X25519WindowsHelpers.BCRYPT_ECC_CURVE_25519; +#else + return key.GetPropertyAsString(KeyPropertyName.ECCCurveName) == X25519WindowsHelpers.BCRYPT_ECC_CURVE_25519; +#endif + } + private void ExportPrivateKeyFromEncryptedPkcs8(Span destination) { const string TemporaryExportPassword = "DotnetExportPhrase"; byte[] exported = _key.ExportPkcs8KeyBlob(TemporaryExportPassword, 1); + byte[] privateKey = new byte[PrivateKeySizeInBytes]; using (PinAndClear.Track(exported)) + using (PinAndClear.Track(privateKey)) { KeyFormatHelper.ReadEncryptedPkcs8( s_eccKeyOid, exported, TemporaryExportPassword, - destination, - static (ReadOnlySpan key, Span destination, in ValueAlgorithmIdentifierAsn algId, out object? ret) => + privateKey, + static (ReadOnlySpan key, byte[] privateKey, in ValueAlgorithmIdentifierAsn algId, out object? ret) => { if (algId.Algorithm != Oids.EcPublicKey) { @@ -228,11 +255,13 @@ private void ExportPrivateKeyFromEncryptedPkcs8(Span destination) throw new CryptographicException(SR.Cryptography_NotValidPrivateKey); } - ecKey.PrivateKey.CopyTo(destination); + ecKey.PrivateKey.CopyTo(privateKey); ret = (object?)null; }, out _, out _); + + privateKey.CopyTo(destination); } } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanCng.cs b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanCng.cs similarity index 100% rename from src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanCng.cs rename to src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanCng.cs diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.NotSupported.cs b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.NotSupported.cs similarity index 96% rename from src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.NotSupported.cs rename to src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.NotSupported.cs index 067db596082deb..67c2751e654952 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.NotSupported.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.NotSupported.cs @@ -5,7 +5,7 @@ namespace System.Security.Cryptography { - internal sealed class X25519DiffieHellmanImplementation : X25519DiffieHellman + internal sealed partial class X25519DiffieHellmanImplementation : X25519DiffieHellman { internal static new bool IsSupported => false; diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.Windows.cs b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.Windows.cs similarity index 97% rename from src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.Windows.cs rename to src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.Windows.cs index 4dcb4357b4b6f1..9a9e8f95a7b172 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.Windows.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/X25519DiffieHellmanImplementation.Windows.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using Internal.Cryptography; using Internal.NativeCrypto; using Microsoft.Win32.SafeHandles; @@ -11,7 +12,7 @@ namespace System.Security.Cryptography { - internal sealed class X25519DiffieHellmanImplementation : X25519DiffieHellman + internal sealed partial class X25519DiffieHellmanImplementation : X25519DiffieHellman { private static readonly SafeBCryptAlgorithmHandle? s_algHandle = OpenAlgorithmHandle(); @@ -106,6 +107,7 @@ private void DeriveRawSecretAgreementWithKey(SafeBCryptKeyHandle otherPartyKey, protected override void ExportPrivateKeyCore(Span destination) { + ThrowIfPrivateNeeded(); ExportKey(true, destination); X25519WindowsHelpers.RefixPrivateScalar(destination, _privatePreservation); } @@ -234,6 +236,11 @@ private static SafeBCryptKeyHandle ImportKey(bool privateKey, ReadOnlySpan private static SafeBCryptAlgorithmHandle? OpenAlgorithmHandle() { + if (!Helpers.IsOSPlatformWindows) + { + return null; + } + NTSTATUS status = Interop.BCrypt.BCryptOpenAlgorithmProvider( out SafeBCryptAlgorithmHandle hAlgorithm, BCryptNative.AlgorithmName.ECDH, diff --git a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanBaseTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanBaseTests.cs similarity index 70% rename from src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanBaseTests.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanBaseTests.cs index 34b326624458e3..ac939e83c58bb1 100644 --- a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanBaseTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanBaseTests.cs @@ -84,8 +84,8 @@ public void ExportPrivateKey_PublicKeyOnly_Throws() using X25519DiffieHellman xdh = GenerateKey(); using X25519DiffieHellman publicOnly = ImportPublicKey(xdh.ExportPublicKey()); - Assert.Throws(() => publicOnly.ExportPrivateKey()); - Assert.Throws(() => publicOnly.ExportPrivateKey(new byte[X25519DiffieHellman.PrivateKeySizeInBytes])); + Assert.ThrowsAny(() => publicOnly.ExportPrivateKey()); + Assert.ThrowsAny(() => publicOnly.ExportPrivateKey(new byte[X25519DiffieHellman.PrivateKeySizeInBytes])); } [Fact] @@ -264,8 +264,8 @@ public void DeriveRawSecretAgreement_ZeroSharedSecret_Throws() { // Wycheproof tcId 64: peer public key is a low-order point on Curve25519. // This low-order point produces a shared secret that is all zeros. - byte[] privateKey = Convert.FromHexString("387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579"); - byte[] peerPublicKey = Convert.FromHexString("5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157"); + byte[] privateKey = "387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579".HexToByteArray(); + byte[] peerPublicKey = "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157".HexToByteArray(); using X25519DiffieHellman key = ImportPrivateKey(privateKey); using X25519DiffieHellman peer = ImportPublicKey(peerPublicKey); @@ -278,8 +278,8 @@ public void DeriveRawSecretAgreement_ExactBuffers_ZeroSharedSecret_Throws() { // Wycheproof tcId 64: peer public key is a low-order point on Curve25519. // This low-order point produces a shared secret that is all zeros. - byte[] privateKey = Convert.FromHexString("387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579"); - byte[] peerPublicKey = Convert.FromHexString("5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157"); + byte[] privateKey = "387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579".HexToByteArray(); + byte[] peerPublicKey = "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157".HexToByteArray(); using X25519DiffieHellman key = ImportPrivateKey(privateKey); using X25519DiffieHellman peer = ImportPublicKey(peerPublicKey); @@ -293,8 +293,8 @@ public void DeriveRawSecretAgreement_Bytes_ZeroSharedSecret_Throws() { // Wycheproof tcId 64: peer public key is a low-order point on Curve25519. // This low-order point produces a shared secret that is all zeros. - byte[] privateKey = Convert.FromHexString("387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579"); - byte[] peerPublicKey = Convert.FromHexString("5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157"); + byte[] privateKey = "387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579".HexToByteArray(); + byte[] peerPublicKey = "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157".HexToByteArray(); using X25519DiffieHellman key = ImportPrivateKey(privateKey); @@ -309,8 +309,8 @@ public void DeriveRawSecretAgreement_Bytes_ExactBuffers_ZeroSharedSecret_Throws( { // Wycheproof tcId 64: peer public key is a low-order point on Curve25519. // This low-order point produces a shared secret that is all zeros. - byte[] privateKey = Convert.FromHexString("387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579"); - byte[] peerPublicKey = Convert.FromHexString("5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157"); + byte[] privateKey = "387355d995616090503aafad49da01fb3dc3eda962704eaee6b86f9e20c92579".HexToByteArray(); + byte[] peerPublicKey = "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157".HexToByteArray(); using X25519DiffieHellman key = ImportPrivateKey(privateKey); @@ -381,8 +381,8 @@ public void ExportPkcs8PrivateKey_Roundtrip() public void ExportPkcs8PrivateKey_PublicKeyOnly_Fails() { using X25519DiffieHellman xdh = ImportPublicKey(X25519DiffieHellmanTestData.AlicePublicKey); - Assert.Throws(() => DoTryUntilDone(xdh.TryExportPkcs8PrivateKey)); - Assert.Throws(() => xdh.ExportPkcs8PrivateKey()); + Assert.ThrowsAny(() => DoTryUntilDone(xdh.TryExportPkcs8PrivateKey)); + Assert.ThrowsAny(() => xdh.ExportPkcs8PrivateKey()); } [Fact] @@ -410,36 +410,36 @@ public void ExportEncryptedPkcs8PrivateKey_PublicKeyOnly_Fails() { using X25519DiffieHellman xdh = ImportPublicKey(X25519DiffieHellmanTestData.AlicePublicKey); - Assert.Throws(() => DoTryUntilDone((Span destination, out int bytesWritten) => + Assert.ThrowsAny(() => DoTryUntilDone((Span destination, out int bytesWritten) => xdh.TryExportEncryptedPkcs8PrivateKey( X25519DiffieHellmanTestData.EncryptedPrivateKeyPassword.AsSpan(), s_aes128Pbe, destination, out bytesWritten))); - Assert.Throws(() => DoTryUntilDone((Span destination, out int bytesWritten) => + Assert.ThrowsAny(() => DoTryUntilDone((Span destination, out int bytesWritten) => xdh.TryExportEncryptedPkcs8PrivateKey( X25519DiffieHellmanTestData.EncryptedPrivateKeyPasswordBytes, s_aes128Pbe, destination, out bytesWritten))); - Assert.Throws(() => xdh.ExportEncryptedPkcs8PrivateKey( + Assert.ThrowsAny(() => xdh.ExportEncryptedPkcs8PrivateKey( X25519DiffieHellmanTestData.EncryptedPrivateKeyPassword, s_aes128Pbe)); - Assert.Throws(() => xdh.ExportEncryptedPkcs8PrivateKey( + Assert.ThrowsAny(() => xdh.ExportEncryptedPkcs8PrivateKey( X25519DiffieHellmanTestData.EncryptedPrivateKeyPassword.AsSpan(), s_aes128Pbe)); - Assert.Throws(() => xdh.ExportEncryptedPkcs8PrivateKey( + Assert.ThrowsAny(() => xdh.ExportEncryptedPkcs8PrivateKey( X25519DiffieHellmanTestData.EncryptedPrivateKeyPasswordBytes, s_aes128Pbe)); - Assert.Throws(() => xdh.ExportEncryptedPkcs8PrivateKeyPem( + Assert.ThrowsAny(() => xdh.ExportEncryptedPkcs8PrivateKeyPem( X25519DiffieHellmanTestData.EncryptedPrivateKeyPasswordBytes, s_aes128Pbe)); - Assert.Throws(() => xdh.ExportEncryptedPkcs8PrivateKeyPem( + Assert.ThrowsAny(() => xdh.ExportEncryptedPkcs8PrivateKeyPem( X25519DiffieHellmanTestData.EncryptedPrivateKeyPassword, s_aes128Pbe)); - Assert.Throws(() => xdh.ExportEncryptedPkcs8PrivateKeyPem( + Assert.ThrowsAny(() => xdh.ExportEncryptedPkcs8PrivateKeyPem( X25519DiffieHellmanTestData.EncryptedPrivateKeyPassword.AsSpan(), s_aes128Pbe)); } @@ -733,7 +733,7 @@ public static IEnumerable DeriveSecretAgreementVect { // Wycheproof Cases 2-4: low-order shared secret results (same private key) byte[] wycheproofPrivate2 = - Convert.FromHexString("a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63"); + "a0a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a976bf63".HexToByteArray(); // RFC 7748 Section 6.1 yield return new("RFC7748_Alice", @@ -764,212 +764,212 @@ public static IEnumerable DeriveSecretAgreementVect // platforms reject the non-canonical encoding. yield return new("NonCanonical_BasePoint_PPlus9", X25519DiffieHellmanTestData.AlicePrivateKey, - Convert.FromHexString("f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), + "f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f".HexToByteArray(), X25519DiffieHellmanTestData.AlicePublicKey, RequiresLenientValidation: true); // Wycheproof Case 0: near-max public key (0xF0FF...FF7F) yield return new("Wycheproof_0", - Convert.FromHexString("288796bc5aff4b81a37501757bc0753a3c21964790d38699308debc17a6eaf8d"), - Convert.FromHexString("f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), - Convert.FromHexString("b4e0dd76da7b071728b61f856771aa356e57eda78a5b1655cc3820fb5f854c5c"), + "288796bc5aff4b81a37501757bc0753a3c21964790d38699308debc17a6eaf8d".HexToByteArray(), + "f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f".HexToByteArray(), + "b4e0dd76da7b071728b61f856771aa356e57eda78a5b1655cc3820fb5f854c5c".HexToByteArray(), RequiresLenientValidation: true); // Wycheproof Case 1: all-bits-set public key (0xF0FF...FFFF) yield return new("Wycheproof_1", - Convert.FromHexString("60887b3dc72443026ebedbbbb70665f42b87add1440e7768fbd7e8e2ce5f639d"), - Convert.FromHexString("f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - Convert.FromHexString("38d6304c4a7e6d9f7959334fb5245bd2c754525d4c91db950206926234c1f633"), + "60887b3dc72443026ebedbbbb70665f42b87add1440e7768fbd7e8e2ce5f639d".HexToByteArray(), + "f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToByteArray(), + "38d6304c4a7e6d9f7959334fb5245bd2c754525d4c91db950206926234c1f633".HexToByteArray(), RequiresLenientValidation: true); yield return new("Wycheproof_2_LowOrder", wycheproofPrivate2, - Convert.FromHexString("0ab4e76380d84dde4f6833c58f2a9fb8f83bb0169b172be4b6e0592887741a36"), - Convert.FromHexString("0200000000000000000000000000000000000000000000000000000000000000"), + "0ab4e76380d84dde4f6833c58f2a9fb8f83bb0169b172be4b6e0592887741a36".HexToByteArray(), + "0200000000000000000000000000000000000000000000000000000000000000".HexToByteArray(), RequiresLenientValidation: true); yield return new("Wycheproof_3_LowOrder", wycheproofPrivate2, - Convert.FromHexString("89e10d5701b4337d2d032181538b1064bd4084401ceca1fd12663a1959388000"), - Convert.FromHexString("0900000000000000000000000000000000000000000000000000000000000000")); + "89e10d5701b4337d2d032181538b1064bd4084401ceca1fd12663a1959388000".HexToByteArray(), + "0900000000000000000000000000000000000000000000000000000000000000".HexToByteArray()); yield return new("Wycheproof_4_LowOrder", wycheproofPrivate2, - Convert.FromHexString("2b55d3aa4a8f80c8c0b2ae5f933e85af49beac36c2fa7394bab76c8933f8f81d"), - Convert.FromHexString("1000000000000000000000000000000000000000000000000000000000000000")); + "2b55d3aa4a8f80c8c0b2ae5f933e85af49beac36c2fa7394bab76c8933f8f81d".HexToByteArray(), + "1000000000000000000000000000000000000000000000000000000000000000".HexToByteArray()); // Select Wycheproof X25519 test vectors for edge cases. yield return new("WycheproofTcId_1", // Normal - Convert.FromHexString("c8a9d5a91091ad851c668b0736c1c9a02936c0d3ad62670858088047ba057475"), - Convert.FromHexString("504a36999f489cd2fdbc08baff3d88fa00569ba986cba22548ffde80f9806829"), - Convert.FromHexString("436a2c040cf45fea9b29a0cb81b1f41458f863d0d61b453d0a982720d6d61320")); + "c8a9d5a91091ad851c668b0736c1c9a02936c0d3ad62670858088047ba057475".HexToByteArray(), + "504a36999f489cd2fdbc08baff3d88fa00569ba986cba22548ffde80f9806829".HexToByteArray(), + "436a2c040cf45fea9b29a0cb81b1f41458f863d0d61b453d0a982720d6d61320".HexToByteArray()); yield return new("WycheproofTcId_2", // Twist - Convert.FromHexString("d85d8c061a50804ac488ad774ac716c3f5ba714b2712e048491379a500211958"), - Convert.FromHexString("63aa40c6e38346c5caf23a6df0a5e6c80889a08647e551b3563449befcfc9733"), - Convert.FromHexString("279df67a7c4611db4708a0e8282b195e5ac0ed6f4b2f292c6fbd0acac30d1332"), + "d85d8c061a50804ac488ad774ac716c3f5ba714b2712e048491379a500211958".HexToByteArray(), + "63aa40c6e38346c5caf23a6df0a5e6c80889a08647e551b3563449befcfc9733".HexToByteArray(), + "279df67a7c4611db4708a0e8282b195e5ac0ed6f4b2f292c6fbd0acac30d1332".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_4", // Twist - Convert.FromHexString("f876e34bcbe1f47fbc0fddfd7c1e1aa53d57bfe0f66d243067b424bb6210be51"), - Convert.FromHexString("0b8211a2b6049097f6871c6c052d3c5fc1ba17da9e32ae458403b05bb283092a"), - Convert.FromHexString("119d37ed4b109cbd6418b1f28dea83c836c844715cdf98a3a8c362191debd514"), + "f876e34bcbe1f47fbc0fddfd7c1e1aa53d57bfe0f66d243067b424bb6210be51".HexToByteArray(), + "0b8211a2b6049097f6871c6c052d3c5fc1ba17da9e32ae458403b05bb283092a".HexToByteArray(), + "119d37ed4b109cbd6418b1f28dea83c836c844715cdf98a3a8c362191debd514".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_7", // SpecialPublicKey,Twist - Convert.FromHexString("d03edde9f3e7b799045f9ac3793d4a9277dadeadc41bec0290f81f744f73775f"), - Convert.FromHexString("0200000000000000000000000000000000000000000000000000000000000000"), - Convert.FromHexString("b87a1722cc6c1e2feecb54e97abd5a22acc27616f78f6e315fd2b73d9f221e57"), + "d03edde9f3e7b799045f9ac3793d4a9277dadeadc41bec0290f81f744f73775f".HexToByteArray(), + "0200000000000000000000000000000000000000000000000000000000000000".HexToByteArray(), + "b87a1722cc6c1e2feecb54e97abd5a22acc27616f78f6e315fd2b73d9f221e57".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_19", // SpecialPublicKey,Twist - Convert.FromHexString("105d621e1ef339c3d99245cfb77cd3a5bd0c4427a0e4d8752c3b51f045889b4f"), - Convert.FromHexString("ffffff030000f8ffff1f0000c0ffffff000000feffff070000f0ffff3f000000"), - Convert.FromHexString("61eace52da5f5ecefafa4f199b077ff64f2e3d2a6ece6f8ec0497826b212ef5f"), + "105d621e1ef339c3d99245cfb77cd3a5bd0c4427a0e4d8752c3b51f045889b4f".HexToByteArray(), + "ffffff030000f8ffff1f0000c0ffffff000000feffff070000f0ffff3f000000".HexToByteArray(), + "61eace52da5f5ecefafa4f199b077ff64f2e3d2a6ece6f8ec0497826b212ef5f".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_31", // SpecialPublicKey,Twist - Convert.FromHexString("d02456e456911d3c6cd054933199807732dfdc958642ad1aebe900c793bef24a"), - Convert.FromHexString("eaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), - Convert.FromHexString("07ba5fcbda21a9a17845c401492b10e6de0a168d5c94b606694c11bac39bea41"), + "d02456e456911d3c6cd054933199807732dfdc958642ad1aebe900c793bef24a".HexToByteArray(), + "eaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f".HexToByteArray(), + "07ba5fcbda21a9a17845c401492b10e6de0a168d5c94b606694c11bac39bea41".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_34", // SpecialPublicKey - Convert.FromHexString("a8386f7f16c50731d64f82e6a170b142a4e34f31fd7768fcb8902925e7d1e25a"), - Convert.FromHexString("0400000000000000000000000000000000000000000000000000000000000000"), - Convert.FromHexString("34b7e4fa53264420d9f943d15513902342b386b172a0b0b7c8b8f2dd3d669f59"), + "a8386f7f16c50731d64f82e6a170b142a4e34f31fd7768fcb8902925e7d1e25a".HexToByteArray(), + "0400000000000000000000000000000000000000000000000000000000000000".HexToByteArray(), + "34b7e4fa53264420d9f943d15513902342b386b172a0b0b7c8b8f2dd3d669f59".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_48", // SpecialPublicKey - Convert.FromHexString("182191b7052e9cd630ef08007fc6b43bc7652913be6774e2fd271b71b962a641"), - Convert.FromHexString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03"), - Convert.FromHexString("a0e0315175788362d4ebe05e6ac76d52d40187bd687492af05abc7ba7c70197d")); + "182191b7052e9cd630ef08007fc6b43bc7652913be6774e2fd271b71b962a641".HexToByteArray(), + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03".HexToByteArray(), + "a0e0315175788362d4ebe05e6ac76d52d40187bd687492af05abc7ba7c70197d".HexToByteArray()); yield return new("WycheproofTcId_62", // SpecialPublicKey - Convert.FromHexString("40bd4e1caf39d9def7663823502dad3e7d30eb6eb01e9b89516d4f2f45b7cd7f"), - Convert.FromHexString("ebffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), - Convert.FromHexString("2cf6974b0c070e3707bf92e721d3ea9de3db6f61ed810e0a23d72d433365f631"), + "40bd4e1caf39d9def7663823502dad3e7d30eb6eb01e9b89516d4f2f45b7cd7f".HexToByteArray(), + "ebffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f".HexToByteArray(), + "2cf6974b0c070e3707bf92e721d3ea9de3db6f61ed810e0a23d72d433365f631".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_87", // NonCanonicalPublic,SpecialPublicKey,Twist - Convert.FromHexString("0016b62af5cabde8c40938ebf2108e05d27fa0533ed85d70015ad4ad39762d54"), - Convert.FromHexString("efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), - Convert.FromHexString("b4d10e832714972f96bd3382e4d082a21a8333a16315b3ffb536061d2482360d"), + "0016b62af5cabde8c40938ebf2108e05d27fa0533ed85d70015ad4ad39762d54".HexToByteArray(), + "efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f".HexToByteArray(), + "b4d10e832714972f96bd3382e4d082a21a8333a16315b3ffb536061d2482360d".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_89", // NonCanonicalPublic,SpecialPublicKey - Convert.FromHexString("88dd14e2711ebd0b0026c651264ca965e7e3da5082789fbab7e24425e7b4377e"), - Convert.FromHexString("f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), - Convert.FromHexString("6919992d6a591e77b3f2bacbd74caf3aea4be4802b18b2bc07eb09ade3ad6662"), + "88dd14e2711ebd0b0026c651264ca965e7e3da5082789fbab7e24425e7b4377e".HexToByteArray(), + "f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f".HexToByteArray(), + "6919992d6a591e77b3f2bacbd74caf3aea4be4802b18b2bc07eb09ade3ad6662".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_91", // NonCanonicalPublic,SpecialPublicKey,Twist - Convert.FromHexString("c0697b6f05e0f3433b44ea352f20508eb0623098a7770853af5ca09727340c4e"), - Convert.FromHexString("0200000000000000000000000000000000000000000000000000000000000080"), - Convert.FromHexString("ed18b06da512cab63f22d2d51d77d99facd3c4502e4abf4e97b094c20a9ddf10"), + "c0697b6f05e0f3433b44ea352f20508eb0623098a7770853af5ca09727340c4e".HexToByteArray(), + "0200000000000000000000000000000000000000000000000000000000000080".HexToByteArray(), + "ed18b06da512cab63f22d2d51d77d99facd3c4502e4abf4e97b094c20a9ddf10".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_94", // NonCanonicalPublic,SpecialPublicKey - Convert.FromHexString("285a6a7ceeb7122f2c78d99c53b2a902b490892f7dff326f89d12673c3101b53"), - Convert.FromHexString("daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - Convert.FromHexString("9b01287717d72f4cfb583ec85f8f936849b17d978dbae7b837db56a62f100a68"), + "285a6a7ceeb7122f2c78d99c53b2a902b490892f7dff326f89d12673c3101b53".HexToByteArray(), + "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToByteArray(), + "9b01287717d72f4cfb583ec85f8f936849b17d978dbae7b837db56a62f100a68".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_97", // NonCanonicalPublic,SpecialPublicKey,Twist - Convert.FromHexString("9041c6e044a277df8466275ca8b5ee0da7bc028648054ade5c592add3057474e"), - Convert.FromHexString("eaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - Convert.FromHexString("13da5695a4c206115409b5277a934782fe985fa050bc902cba5616f9156fe277"), + "9041c6e044a277df8466275ca8b5ee0da7bc028648054ade5c592add3057474e".HexToByteArray(), + "eaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToByteArray(), + "13da5695a4c206115409b5277a934782fe985fa050bc902cba5616f9156fe277".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_99", // NonCanonicalPublic,SpecialPublicKey - Convert.FromHexString("c85f08e60c845f82099141a66dc4583d2b1040462c544d33d0453b20b1a6377e"), - Convert.FromHexString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), - Convert.FromHexString("e9db74bc88d0d9bf046ddd13f943bccbe6dbb47d49323f8dfeedc4a694991a3c"), + "c85f08e60c845f82099141a66dc4583d2b1040462c544d33d0453b20b1a6377e".HexToByteArray(), + "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff".HexToByteArray(), + "e9db74bc88d0d9bf046ddd13f943bccbe6dbb47d49323f8dfeedc4a694991a3c".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_100", // Ktv - Convert.FromHexString("a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44"), - Convert.FromHexString("e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c"), - Convert.FromHexString("c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552"), + "a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44".HexToByteArray(), + "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c".HexToByteArray(), + "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_101", // Ktv,Twist - Convert.FromHexString("4866e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba4d"), - Convert.FromHexString("e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a413"), - Convert.FromHexString("95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957"), + "4866e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba4d".HexToByteArray(), + "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a413".HexToByteArray(), + "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_102", // Ktv - Convert.FromHexString("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a"), - Convert.FromHexString("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f"), - Convert.FromHexString("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742")); + "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a".HexToByteArray(), + "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f".HexToByteArray(), + "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742".HexToByteArray()); yield return new("WycheproofTcId_103", // EdgeCaseShared,Twist - Convert.FromHexString("60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f"), - Convert.FromHexString("b7b6d39c765cb60c0c8542f4f3952ffb51d3002d4aeb9f8ff988b192043e6d0a"), - Convert.FromHexString("0200000000000000000000000000000000000000000000000000000000000000"), + "60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f".HexToByteArray(), + "b7b6d39c765cb60c0c8542f4f3952ffb51d3002d4aeb9f8ff988b192043e6d0a".HexToByteArray(), + "0200000000000000000000000000000000000000000000000000000000000000".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_104", // EdgeCaseShared - Convert.FromHexString("60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f"), - Convert.FromHexString("3b18df1e50b899ebd588c3161cbd3bf98ebcc2c1f7df53b811bd0e91b4d5153d"), - Convert.FromHexString("0900000000000000000000000000000000000000000000000000000000000000")); + "60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f".HexToByteArray(), + "3b18df1e50b899ebd588c3161cbd3bf98ebcc2c1f7df53b811bd0e91b4d5153d".HexToByteArray(), + "0900000000000000000000000000000000000000000000000000000000000000".HexToByteArray()); yield return new("WycheproofTcId_107", // EdgeCaseShared - Convert.FromHexString("60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f"), - Convert.FromHexString("98730bc03e29e8b057fb1d20ef8c0bffc822485d3db7f45f4e3cc2c3c6d1d14c"), - Convert.FromHexString("fcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f")); + "60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f".HexToByteArray(), + "98730bc03e29e8b057fb1d20ef8c0bffc822485d3db7f45f4e3cc2c3c6d1d14c".HexToByteArray(), + "fcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f".HexToByteArray()); yield return new("WycheproofTcId_112", // EdgeCaseShared,Twist - Convert.FromHexString("60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f"), - Convert.FromHexString("8d612c5831aa64b057300e7e310f3aa332af34066fefcab2b089c9592878f832"), - Convert.FromHexString("e3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"), + "60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f".HexToByteArray(), + "8d612c5831aa64b057300e7e310f3aa332af34066fefcab2b089c9592878f832".HexToByteArray(), + "e3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_113", // EdgeCaseShared - Convert.FromHexString("60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f"), - Convert.FromHexString("8d44108d05d940d3dfe5647ea7a87be24d0d036c9f0a95a2386b839e7b7bf145"), - Convert.FromHexString("ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f")); + "60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f".HexToByteArray(), + "8d44108d05d940d3dfe5647ea7a87be24d0d036c9f0a95a2386b839e7b7bf145".HexToByteArray(), + "ddffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f".HexToByteArray()); yield return new("WycheproofTcId_116", // EdgeCaseShared,Twist - Convert.FromHexString("60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f"), - Convert.FromHexString("8e41f05ea3c76572be104ad8788e970863c6e2ca3daae64d1c2f46decfffa571"), - Convert.FromHexString("0000000000000000000000000000000000000000000000000000000000008000"), + "60a3a4f130b98a5be4b1cedb7cb85584a3520e142d474dc9ccb909a073a9767f".HexToByteArray(), + "8e41f05ea3c76572be104ad8788e970863c6e2ca3daae64d1c2f46decfffa571".HexToByteArray(), + "0000000000000000000000000000000000000000000000000000000000008000".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_119", // EdgeCaseMultiplication,Twist - Convert.FromHexString("e0a8be63315c4f0f0a3fee607f44d30a55be63f09561d9af93e0a1c9cf0ed751"), - Convert.FromHexString("0200000000000000000000000000000000000000000000000000000000000000"), - Convert.FromHexString("0c50ac2bfb6815b47d0734c5981379882a24a2de6166853c735329d978baee4d"), + "e0a8be63315c4f0f0a3fee607f44d30a55be63f09561d9af93e0a1c9cf0ed751".HexToByteArray(), + "0200000000000000000000000000000000000000000000000000000000000000".HexToByteArray(), + "0c50ac2bfb6815b47d0734c5981379882a24a2de6166853c735329d978baee4d".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_120", // EdgeCaseMultiplication - Convert.FromHexString("0840a8af5bc4c48da8850e973d7e14220f45c192cea4020d377eecd25c7c3643"), - Convert.FromHexString("1200000000000000000000000000000000000000000000000000000000000000"), - Convert.FromHexString("77557137a2a2a651c49627a9b239ac1f2bf78b8a3e72168ccecc10a51fc5ae66"), + "0840a8af5bc4c48da8850e973d7e14220f45c192cea4020d377eecd25c7c3643".HexToByteArray(), + "1200000000000000000000000000000000000000000000000000000000000000".HexToByteArray(), + "77557137a2a2a651c49627a9b239ac1f2bf78b8a3e72168ccecc10a51fc5ae66".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_249", // EdgeCaseMultiplication - Convert.FromHexString("4028802030d8a8221a7160eebbf1846116c1c253abc467d6e43cb850f1459860"), - Convert.FromHexString("0f13955978b93d7b9f9a2e70d96df922850a8ffd8412e236fb074aef99d37d54"), - Convert.FromHexString("e23d63a46be67c7443c07b9371ff6a06afcd7a5794bf2537926074b88190307a"), + "4028802030d8a8221a7160eebbf1846116c1c253abc467d6e43cb850f1459860".HexToByteArray(), + "0f13955978b93d7b9f9a2e70d96df922850a8ffd8412e236fb074aef99d37d54".HexToByteArray(), + "e23d63a46be67c7443c07b9371ff6a06afcd7a5794bf2537926074b88190307a".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_256", // EdgeCaseMultiplication,Twist - Convert.FromHexString("d0e67f68183a4c1aed9c56864b36278bb7bb75d57a78321bc7c24ff61636607a"), - Convert.FromHexString("d8c8e2c6f33a98525df3767d1d04430dab0bda41f1f904c95bc61cc122caca74"), - Convert.FromHexString("ef7612c156078dae3a81e50ef33951cab661fb07731d8f419bc0105c4d6d6050"), + "d0e67f68183a4c1aed9c56864b36278bb7bb75d57a78321bc7c24ff61636607a".HexToByteArray(), + "d8c8e2c6f33a98525df3767d1d04430dab0bda41f1f904c95bc61cc122caca74".HexToByteArray(), + "ef7612c156078dae3a81e50ef33951cab661fb07731d8f419bc0105c4d6d6050".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_377", // EdgeCaseMultiplication - Convert.FromHexString("c01f66cb094289d728421dd46c6f9718412e1c546dad70e586851be4da58bf67"), - Convert.FromHexString("4e056b317a31dd96f8ec14b48474af587d195efcc2a70f01f052ef882d7b3a45"), - Convert.FromHexString("bad9f7b27dac64b0fc980a41f1cefa50c5ca40c714296c0c4042095c2db60e11"), + "c01f66cb094289d728421dd46c6f9718412e1c546dad70e586851be4da58bf67".HexToByteArray(), + "4e056b317a31dd96f8ec14b48474af587d195efcc2a70f01f052ef882d7b3a45".HexToByteArray(), + "bad9f7b27dac64b0fc980a41f1cefa50c5ca40c714296c0c4042095c2db60e11".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_387", // EdgeCaseMultiplication,Twist - Convert.FromHexString("204a3b5652854ff48e25cd385cabe6360f64ce44fea5621db1fa2f6e219f3063"), - Convert.FromHexString("ed1c82082b74cc2aaebf3dc772ba09557c0fc14139a8814fc5f9370bb8e98858"), - Convert.FromHexString("e0a82f313046024b3cea93b98e2f8ecf228cbfab8ae10b10292c32feccff1603"), + "204a3b5652854ff48e25cd385cabe6360f64ce44fea5621db1fa2f6e219f3063".HexToByteArray(), + "ed1c82082b74cc2aaebf3dc772ba09557c0fc14139a8814fc5f9370bb8e98858".HexToByteArray(), + "e0a82f313046024b3cea93b98e2f8ecf228cbfab8ae10b10292c32feccff1603".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_506", // EdgeCaseMultiplication,Twist - Convert.FromHexString("707ee81f113a244c9d87608b12158c50f9ac1f2c8948d170ad16ab0ad866d74b"), - Convert.FromHexString("dcffc4c1e1fba5fda9d5c98421d99c257afa90921bc212a046d90f6683e8a467"), - Convert.FromHexString("7ecdd54c5e15f7b4061be2c30b5a4884a0256581f87df60d579a3345653eb641"), + "707ee81f113a244c9d87608b12158c50f9ac1f2c8948d170ad16ab0ad866d74b".HexToByteArray(), + "dcffc4c1e1fba5fda9d5c98421d99c257afa90921bc212a046d90f6683e8a467".HexToByteArray(), + "7ecdd54c5e15f7b4061be2c30b5a4884a0256581f87df60d579a3345653eb641".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_510", // EdgeCaseMultiplication - Convert.FromHexString("78ed4c9bf9f44db8d93388985191ecf59226b9c1205fe7e762c327581c75884e"), - Convert.FromHexString("ce7295d1227c9062aab9cf02fc5671fb81632e725367f131d4122824a6132d68"), - Convert.FromHexString("3740de297ff0122067951e8985247123440e0f27171da99e263d5b4450f59f3d"), + "78ed4c9bf9f44db8d93388985191ecf59226b9c1205fe7e762c327581c75884e".HexToByteArray(), + "ce7295d1227c9062aab9cf02fc5671fb81632e725367f131d4122824a6132d68".HexToByteArray(), + "3740de297ff0122067951e8985247123440e0f27171da99e263d5b4450f59f3d".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_511", // EdgeCasePrivateKey - Convert.FromHexString("a023cdd083ef5bb82f10d62e59e15a6800000000000000000000000000000050"), - Convert.FromHexString("6c05871352a451dbe182ed5e6ba554f2034456ffe041a054ff9cc56b8e946376"), - Convert.FromHexString("6c05871352a451dbe182ed5e6ba554f2034456ffe041a054ff9cc56b8e946376")); + "a023cdd083ef5bb82f10d62e59e15a6800000000000000000000000000000050".HexToByteArray(), + "6c05871352a451dbe182ed5e6ba554f2034456ffe041a054ff9cc56b8e946376".HexToByteArray(), + "6c05871352a451dbe182ed5e6ba554f2034456ffe041a054ff9cc56b8e946376".HexToByteArray()); yield return new("WycheproofTcId_512", // Twist - Convert.FromHexString("58083dd261ad91eff952322ec824c682ffffffffffffffffffffffffffffff5f"), - Convert.FromHexString("2eae5ec3dd494e9f2d37d258f873a8e6e9d0dbd1e383ef64d98bb91b3e0be035"), - Convert.FromHexString("2eae5ec3dd494e9f2d37d258f873a8e6e9d0dbd1e383ef64d98bb91b3e0be035"), + "58083dd261ad91eff952322ec824c682ffffffffffffffffffffffffffffff5f".HexToByteArray(), + "2eae5ec3dd494e9f2d37d258f873a8e6e9d0dbd1e383ef64d98bb91b3e0be035".HexToByteArray(), + "2eae5ec3dd494e9f2d37d258f873a8e6e9d0dbd1e383ef64d98bb91b3e0be035".HexToByteArray(), RequiresLenientValidation: true); yield return new("WycheproofTcId_515", // EdgeCasePrivateKey - Convert.FromHexString("4855555555555555555555555555555555555555555555555555555555555555"), - Convert.FromHexString("be3b3edeffaf83c54ae526379b23dd79f1cb41446e3687fef347eb9b5f0dc308"), - Convert.FromHexString("cfa83e098829fe82fd4c14355f70829015219942c01e2b85bdd9ac4889ec2921")); + "4855555555555555555555555555555555555555555555555555555555555555".HexToByteArray(), + "be3b3edeffaf83c54ae526379b23dd79f1cb41446e3687fef347eb9b5f0dc308".HexToByteArray(), + "cfa83e098829fe82fd4c14355f70829015219942c01e2b85bdd9ac4889ec2921".HexToByteArray()); yield return new("WycheproofTcId_518", // EdgeCasePrivateKey - Convert.FromHexString("b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa6a"), - Convert.FromHexString("be3b3edeffaf83c54ae526379b23dd79f1cb41446e3687fef347eb9b5f0dc308"), - Convert.FromHexString("e3c649beae7cc4a0698d519a0a61932ee5493cbb590dbe14db0274cc8611f914")); + "b8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa6a".HexToByteArray(), + "be3b3edeffaf83c54ae526379b23dd79f1cb41446e3687fef347eb9b5f0dc308".HexToByteArray(), + "e3c649beae7cc4a0698d519a0a61932ee5493cbb590dbe14db0274cc8611f914".HexToByteArray()); } } diff --git a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanCngTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanCngTests.Windows.cs similarity index 93% rename from src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanCngTests.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanCngTests.Windows.cs index b50adbbffac1b0..7863ccfa341b7f 100644 --- a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanCngTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanCngTests.Windows.cs @@ -9,12 +9,14 @@ namespace System.Security.Cryptography.Tests { [ConditionalClass(typeof(X25519DiffieHellman), nameof(X25519DiffieHellman.IsSupported))] + [PlatformSpecific(TestPlatforms.Windows)] public sealed class X25519DiffieHellmanExportableCngTests : X25519DiffieHellmanCngTests { protected override CngExportPolicies ExportPolicy => CngExportPolicies.AllowExport; } [ConditionalClass(typeof(X25519DiffieHellman), nameof(X25519DiffieHellman.IsSupported))] + [PlatformSpecific(TestPlatforms.Windows)] public sealed class X25519DiffieHellmanPlaintextExportableCngTests : X25519DiffieHellmanCngTests { protected override CngExportPolicies ExportPolicy => @@ -23,6 +25,7 @@ public sealed class X25519DiffieHellmanPlaintextExportableCngTests : X25519Diffi } [ConditionalClass(typeof(X25519DiffieHellman), nameof(X25519DiffieHellman.IsSupported))] + [PlatformSpecific(TestPlatforms.Windows)] public static class X25519DiffieHellmanCngContractTests { [Fact] @@ -75,6 +78,7 @@ public static void GetKey_Disposed() } [ConditionalClass(typeof(X25519DiffieHellman), nameof(X25519DiffieHellman.IsSupported))] + [PlatformSpecific(TestPlatforms.Windows)] public static class X25519DiffieHellmanCngNonExportableTests { [Fact] @@ -82,7 +86,7 @@ public static void X25519DiffieHellmanCng_NonExportable_ExportPrivateKeyThrows() { using CngKey key = X25519DiffieHellmanCngTests.GenerateCngKey(exportPolicy: CngExportPolicies.None); using X25519DiffieHellmanCng xdh = new(key); - Assert.Throws(() => xdh.ExportPrivateKey()); + Assert.ThrowsAny(() => xdh.ExportPrivateKey()); } [Fact] @@ -109,13 +113,13 @@ public abstract class X25519DiffieHellmanCngTests : X25519DiffieHellmanBaseTests protected abstract CngExportPolicies ExportPolicy { get; } - public override X25519DiffieHellmanCng GenerateKey() + public override X25519DiffieHellman GenerateKey() { using CngKey key = GenerateCngKey(exportPolicy: ExportPolicy); return new X25519DiffieHellmanCng(key); } - public override X25519DiffieHellmanCng ImportPrivateKey(ReadOnlySpan source) + public override X25519DiffieHellman ImportPrivateKey(ReadOnlySpan source) { using CryptoPoolLease lease = X25519WindowsHelpers.CreateCngBlob(source, true, out _); using SafeNCryptKeyHandle keyHandle = ECCng.ImportKeyBlob( @@ -136,7 +140,7 @@ public override X25519DiffieHellmanCng ImportPrivateKey(ReadOnlySpan sourc return new X25519DiffieHellmanCng(cngKey); } - public override X25519DiffieHellmanCng ImportPublicKey(ReadOnlySpan source) + public override X25519DiffieHellman ImportPublicKey(ReadOnlySpan source) { Span reducedPublicKey = stackalloc byte[X25519DiffieHellman.PublicKeySizeInBytes]; X25519WindowsHelpers.ReducePublicKey(source, reducedPublicKey); diff --git a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanContractTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanContractTests.cs similarity index 99% rename from src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanContractTests.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanContractTests.cs index 74a20a5f780021..dae20fc024c2d9 100644 --- a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanContractTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanContractTests.cs @@ -463,8 +463,9 @@ public static void TryExportPkcs8PrivateKey() // Test with various inputs of different sizes from TryExportPkcs8PrivateKeyCore that it reports // as-is to the public APIs. Invalid behavior like reporting more byte written than possible is handled // elsewhere. - int bufferSize = Random.Shared.Next(50, 1024); - int writtenSize = Random.Shared.Next(48, bufferSize); + Random random = new(); + int bufferSize = random.Next(50, 1024); + int writtenSize = random.Next(48, bufferSize); bool success = (writtenSize & 1) == 1; byte[] buffer = new byte[bufferSize]; X25519DiffieHellmanContract xdh = new() diff --git a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanImplementationTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanImplementationTests.cs similarity index 98% rename from src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanImplementationTests.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanImplementationTests.cs index b0cac751d4367e..147e4d973143fe 100644 --- a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanImplementationTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanImplementationTests.cs @@ -25,7 +25,9 @@ public static void IsSupported_AgreesWithPlatform() bool expectedSupported = PlatformDetection.IsWindows10OrLater || PlatformDetection.IsApplePlatform || +#if NET OperatingSystem.IsAndroidVersionAtLeast(33) || +#endif PlatformDetection.IsOpenSslSupported; // X25519 is in OpenSSL 1.1.0 and .NET's floor is 1.1.1. Assert.Equal(expectedSupported, X25519DiffieHellman.IsSupported); diff --git a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanKeyTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanKeyTests.cs similarity index 100% rename from src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanKeyTests.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanKeyTests.cs diff --git a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanNotSupportedTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanNotSupportedTests.cs similarity index 94% rename from src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanNotSupportedTests.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanNotSupportedTests.cs index 03e2711dbb0a8a..88a638093063d7 100644 --- a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanNotSupportedTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanNotSupportedTests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Xunit; +using Test.Cryptography; namespace System.Security.Cryptography.Tests { @@ -40,9 +41,9 @@ public static void ImportPublicKey_NotSupported() public static void ImportSubjectPublicKeyInfo_NotSupported() { // A minimal valid SPKI for X25519 - byte[] spki = Convert.FromHexString( + byte[] spki = ( "302a300506032b656e032100" + - "0000000000000000000000000000000000000000000000000000000000000000"); + "0000000000000000000000000000000000000000000000000000000000000000").HexToByteArray(); Assert.Throws(() => X25519DiffieHellman.ImportSubjectPublicKeyInfo(spki)); @@ -55,9 +56,9 @@ public static void ImportSubjectPublicKeyInfo_NotSupported() public static void ImportPkcs8PrivateKey_NotSupported() { // A minimal valid PKCS#8 for X25519 - byte[] pkcs8 = Convert.FromHexString( + byte[] pkcs8 = ( "302e020100300506032b656e04220420" + - "0000000000000000000000000000000000000000000000000000000000000000"); + "0000000000000000000000000000000000000000000000000000000000000000").HexToByteArray(); Assert.Throws(() => X25519DiffieHellman.ImportPkcs8PrivateKey(pkcs8)); @@ -71,9 +72,9 @@ public static void ImportEncryptedPkcs8PrivateKey_NotSupported() { // Use an encrypted PKCS#8 blob. The implementation should throw PlatformNotSupportedException // before attempting decryption. - byte[] pkcs8 = Convert.FromHexString( + byte[] pkcs8 = ( "302e020100300506032b656e04220420" + - "0000000000000000000000000000000000000000000000000000000000000000"); + "0000000000000000000000000000000000000000000000000000000000000000").HexToByteArray(); Assert.Throws(() => X25519DiffieHellman.ImportEncryptedPkcs8PrivateKey("password", pkcs8)); diff --git a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanTestData.cs b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanTestData.cs similarity index 100% rename from src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanTestData.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanTestData.cs diff --git a/src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanTests.cs similarity index 100% rename from src/libraries/System.Security.Cryptography/tests/X25519DiffieHellmanTests.cs rename to src/libraries/Common/tests/System/Security/Cryptography/X25519DiffieHellmanTests.cs diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.Forwards.cs b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.Forwards.cs index 85c7ddfdc2e14e..395d2aa62dc5b2 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.Forwards.cs +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.Forwards.cs @@ -20,6 +20,10 @@ [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.SlhDsa))] [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.SlhDsaAlgorithm))] [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.SlhDsaCng))] +#if NET11_0_OR_GREATER +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.X25519DiffieHellman))] +[assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.X25519DiffieHellmanCng))] +#endif #endif #if NET || NETSTANDARD2_1_OR_GREATER [assembly: System.Runtime.CompilerServices.TypeForwardedTo(typeof(System.Security.Cryptography.PbeEncryptionAlgorithm))] diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj index 6670adf751a160..997ff87a57e39b 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/Microsoft.Bcl.Cryptography.csproj @@ -17,11 +17,13 @@ true true - true + + true + true - - + + - + - + + + + @@ -90,7 +95,7 @@ Link="Common\System\Security\Cryptography\PbeParameters.cs" /> - + Common\System\Security\Cryptography\Asn1\AlgorithmIdentifierAsn.xml @@ -348,7 +353,7 @@ - + @@ -373,11 +378,56 @@ Link="Common\System\Security\Cryptography\ECCng.ImportExport.NamedCurve.cs" /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + System\Security\Cryptography\Asn1\MLKemPrivateKeyAsn.xml @@ -393,28 +443,10 @@ System\Security\Cryptography\Asn1\MLKemPrivateKeyBothAsn.xml.cs System\Security\Cryptography\Asn1\MLKemPrivateKeyBothAsn.xml - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + @@ -488,20 +544,12 @@ Link="Common\Microsoft\Win32\SafeHandles\SafeCryptMsgHandle.cs" /> - - - - - - - - - - + + + + + diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/Resources/Strings.resx b/src/libraries/Microsoft.Bcl.Cryptography/src/Resources/Strings.resx index 065d4467e23e9e..e8dba523496f6e 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/Resources/Strings.resx +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/Resources/Strings.resx @@ -147,6 +147,9 @@ Keys used with the MLKemCng algorithm must have an algorithm group of MLKem. + + Keys used with the X25519DiffieHellmanCng algorithm must have an algorithm group of ECDiffieHellman using curve25519. + The computed authentication tag did not match the input authentication tag. @@ -156,6 +159,9 @@ Composite signature generation failed due to an error in one or both of the components. + + Object contains only the public half of a key pair. A private key must also be provided. + The specified curve '{0}' or its parameters are not valid for this platform. diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/CngExtensions.cs b/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/CngExtensions.cs index 8a2f2c1ded858b..5b42c1a3b3eeed 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/CngExtensions.cs +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/CngExtensions.cs @@ -2,22 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; -using System.Runtime.Versioning; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography { internal static class CngKeyExtensions { - [SupportedOSPlatform("windows")] - internal static CngKey Duplicate(this CngKey key) - { - using (SafeNCryptKeyHandle handle = key.Handle) - { - return CngHelpers.Duplicate(handle, key.IsEphemeral); - } - } - internal static void SetExportPolicy(this CngKey key, CngExportPolicies exportPolicy) { using (SafeNCryptKeyHandle keyHandle = key.Handle) diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/Helpers.cs b/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/Helpers.cs index 2d50b4bd4b445c..3ed31067629db3 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/Helpers.cs +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/Helpers.cs @@ -99,21 +99,6 @@ internal static int GetHashLengthInBytes(this IncrementalHash hash) } } - extension (RandomNumberGenerator) - { - internal static unsafe void Fill(Span buffer) - { - if (buffer.Length > 0) - { - fixed (byte* pbBuffer = buffer) - { - Interop.BCrypt.NTSTATUS status = Interop.BCrypt.BCryptGenRandom(IntPtr.Zero, pbBuffer, buffer.Length, Interop.BCrypt.BCRYPT_USE_SYSTEM_PREFERRED_RNG); - if (status != Interop.BCrypt.NTSTATUS.STATUS_SUCCESS) - throw Interop.BCrypt.CreateCryptographicException(status); - } - } - } - } #endif } } diff --git a/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/NetStandardShims.cs b/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/NetStandardShims.cs index 344ff4878ca9eb..4f8c96ceacae60 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/NetStandardShims.cs +++ b/src/libraries/Microsoft.Bcl.Cryptography/src/System/Security/Cryptography/NetStandardShims.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; @@ -8,6 +9,25 @@ namespace System.Security.Cryptography { internal static class NetStandardShims { +#if !NET + extension(ReadOnlySpan source) where T : IEquatable? + { + internal int IndexOfAnyExcept(T value) + { + for (int i = 0; i < source.Length; i++) + { + if (!EqualityComparer.Default.Equals(source[i], value)) + { + return i; + } + } + + return -1; + } + } + +#endif + internal static void ReadExactly(this Stream stream, Span buffer) => ReadAtLeast(stream, buffer, buffer.Length, throwOnEndOfStream: true); @@ -86,7 +106,34 @@ internal static bool TryGetHashAndReset( } } -#if !NETSTANDARD2_1_OR_GREATER +#if !NET11_0_OR_GREATER && (NET || NETSTANDARD) + internal static class CryptographicOperationsExtensions + { + extension(CryptographicOperations) + { + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] + internal static bool FixedTimeEquals(ReadOnlySpan left, byte right) + { + // NoOptimization because we want this method to be exactly as non-short-circuiting + // as written. + // + // NoInlining because the NoOptimization would get lost if the method got inlined. + + int length = left.Length; + int accum = 0; + + for (int i = 0; i < length; i++) + { + accum |= left[i] - right; + } + + return accum == 0; + } + } + } +#endif + +#if NETFRAMEWORK || NETSTANDARD2_0 internal static class CryptographicOperations { [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] @@ -118,6 +165,27 @@ internal static bool FixedTimeEquals(ReadOnlySpan left, ReadOnlySpan return accum == 0; } + +#if NETFRAMEWORK + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] + internal static bool FixedTimeEquals(ReadOnlySpan left, byte right) + { + // NoOptimization because we want this method to be exactly as non-short-circuiting + // as written. + // + // NoInlining because the NoOptimization would get lost if the method got inlined. + + int length = left.Length; + int accum = 0; + + for (int i = 0; i < length; i++) + { + accum |= left[i] - right; + } + + return accum == 0; + } +#endif } #endif } diff --git a/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj b/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj index 616f3521063d97..021673e2d2a7be 100644 --- a/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj +++ b/src/libraries/Microsoft.Bcl.Cryptography/tests/Microsoft.Bcl.Cryptography.Tests.csproj @@ -147,12 +147,55 @@ Link="CommonTest\System\Security\Cryptography\MLKemCngTests.Windows.cs" /> + + + + + + + + + + + + + + + + + + + + + + + + - - @@ -887,7 +889,8 @@ - + @@ -2040,8 +2043,10 @@ - - + + diff --git a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj index 56ed338c3f9b1a..901cc08e329c4d 100644 --- a/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj +++ b/src/libraries/System.Security.Cryptography/tests/System.Security.Cryptography.Tests.csproj @@ -246,6 +246,20 @@ Link="CommonTest\System\Security\Cryptography\MLKemTests.cs" /> + + + + + + + - - - - - - - @@ -726,7 +733,8 @@ Link="Common\System\Security\Cryptography\CryptoThrowHelper.Windows.cs" /> - +