| File: System\Security\Cryptography\ECDiffieHellmanCng.Derive.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography { public sealed partial class ECDiffieHellmanCng : ECDiffieHellman { public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { ArgumentNullException.ThrowIfNull(otherPartyPublicKey); if (otherPartyPublicKey is ECDiffieHellmanCngPublicKey otherKey) { using (CngKey import = otherKey.Import()) { return DeriveKeyMaterial(import); } } // This deviates from the .NET Framework behavior. .NET Framework can't handle unknown public // key types, but on .NET Core there are automatically two: the public class produced by // this class' PublicKey member, and the private class produced by ECDiffieHellman.Create().PublicKey // // So let's just work. ECParameters otherPartyParameters = otherPartyPublicKey.ExportParameters(); using (ECDiffieHellmanCng otherPartyCng = new ECDiffieHellmanCng()) { otherPartyCng.ImportParameters(otherPartyParameters); using (otherKey = (ECDiffieHellmanCngPublicKey)otherPartyCng.PublicKey) using (CngKey importedKey = otherKey.Import()) { return DeriveKeyMaterial(importedKey); } } } public byte[] DeriveKeyMaterial(CngKey otherPartyPublicKey) { ArgumentNullException.ThrowIfNull(otherPartyPublicKey); if (otherPartyPublicKey.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman) throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey, nameof(otherPartyPublicKey)); if (otherPartyPublicKey.KeySize != KeySize) throw new ArgumentException(SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey)); // Setting the flag to UseSecretAsHmacKey even when the KDF isn't HMAC, because that's what .NET Framework does. Interop.NCrypt.SecretAgreementFlags flags = UseSecretAgreementAsHmacKey ? Interop.NCrypt.SecretAgreementFlags.UseSecretAsHmacKey : Interop.NCrypt.SecretAgreementFlags.None; using (SafeNCryptSecretHandle handle = DeriveSecretAgreementHandle(otherPartyPublicKey)) { switch (KeyDerivationFunction) { case ECDiffieHellmanKeyDerivationFunction.Hash: return Interop.NCrypt.DeriveKeyMaterialHash( handle, HashAlgorithm.Algorithm, _secretPrepend, _secretAppend, flags); case ECDiffieHellmanKeyDerivationFunction.Hmac: return Interop.NCrypt.DeriveKeyMaterialHmac( handle, HashAlgorithm.Algorithm, _hmacKey, _secretPrepend, _secretAppend, flags); case ECDiffieHellmanKeyDerivationFunction.Tls: if (_label == null || _seed == null) { throw new InvalidOperationException(SR.Cryptography_TlsRequiresLabelAndSeed); } return Interop.NCrypt.DeriveKeyMaterialTls( handle, _label, _seed, flags); default: Debug.Fail($"Unknown KDF ({KeyDerivationFunction})"); // Match .NET Framework behavior goto case ECDiffieHellmanKeyDerivationFunction.Tls; } } } /// <summary> /// Get a handle to the secret agreement generated between two parties /// </summary> public SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { ArgumentNullException.ThrowIfNull(otherPartyPublicKey); if (otherPartyPublicKey is ECDiffieHellmanCngPublicKey otherKey) { using (CngKey importedKey = otherKey.Import()) { return DeriveSecretAgreementHandle(importedKey); } } ECParameters otherPartyParameters = otherPartyPublicKey.ExportParameters(); using (ECDiffieHellmanCng otherPartyCng = new ECDiffieHellmanCng()) { otherPartyCng.ImportParameters(otherPartyParameters); using (otherKey = (ECDiffieHellmanCngPublicKey)otherPartyCng.PublicKey) using (CngKey importedKey = otherKey.Import()) { return DeriveSecretAgreementHandle(importedKey); } } } /// <summary> /// Get a handle to the secret agreement between two parties /// </summary> public SafeNCryptSecretHandle DeriveSecretAgreementHandle(CngKey otherPartyPublicKey) { ArgumentNullException.ThrowIfNull(otherPartyPublicKey); if (otherPartyPublicKey.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman) throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey, nameof(otherPartyPublicKey)); if (otherPartyPublicKey.KeySize != KeySize) throw new ArgumentException(SR.Cryptography_ArgECDHKeySizeMismatch, nameof(otherPartyPublicKey)); // This looks strange, but the Handle property returns a duplicate so we need to dispose of it when we're done using (SafeNCryptKeyHandle localHandle = Key.Handle) using (SafeNCryptKeyHandle otherPartyHandle = otherPartyPublicKey.Handle) { return Interop.NCrypt.DeriveSecretAgreement(localHandle, otherPartyHandle); } } } }