| File: System\Security\Cryptography\ECDiffieHellmanCng.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 System.Runtime.Versioning; namespace System.Security.Cryptography { /// <summary> /// Wrapper for CNG's implementation of elliptic curve Diffie-Hellman key exchange /// </summary> public sealed partial class ECDiffieHellmanCng : ECDiffieHellman { private CngAlgorithmCore _core = new CngAlgorithmCore(typeof(ECDiffieHellmanCng)) { DefaultKeyType = CngAlgorithm.ECDiffieHellman }; private CngAlgorithm _hashAlgorithm = CngAlgorithm.Sha256; private ECDiffieHellmanKeyDerivationFunction _kdf = ECDiffieHellmanKeyDerivationFunction.Hash; private byte[]? _hmacKey; private byte[]? _label; private byte[]? _secretAppend; private byte[]? _secretPrepend; private byte[]? _seed; [SupportedOSPlatform("windows")] public ECDiffieHellmanCng(CngKey key) { ArgumentNullException.ThrowIfNull(key); if (key.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman) throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey, nameof(key)); Key = CngAlgorithmCore.Duplicate(key); } [SupportedOSPlatform("windows")] internal ECDiffieHellmanCng(CngKey key, bool transferOwnership) { Debug.Assert(key is not null); Debug.Assert(key.AlgorithmGroup == CngAlgorithmGroup.ECDiffieHellman); Debug.Assert(transferOwnership); Key = key; } /// <summary> /// Hash algorithm used with the Hash and HMAC KDFs /// </summary> public CngAlgorithm HashAlgorithm { get { return _hashAlgorithm; } set { ArgumentNullException.ThrowIfNull(value); _hashAlgorithm = value; } } /// <summary> /// KDF used to transform the secret agreement into key material /// </summary> public ECDiffieHellmanKeyDerivationFunction KeyDerivationFunction { get { return _kdf; } set { if (value < ECDiffieHellmanKeyDerivationFunction.Hash || value > ECDiffieHellmanKeyDerivationFunction.Tls) { throw new ArgumentOutOfRangeException(nameof(value)); } _kdf = value; } } /// <summary> /// Key used with the HMAC KDF /// </summary> public byte[]? HmacKey { get { return _hmacKey; } set { _hmacKey = value; } } /// <summary> /// Label bytes used for the TLS KDF /// </summary> public byte[]? Label { get { return _label; } set { _label = value; } } /// <summary> /// Bytes to append to the raw secret agreement before processing by the KDF /// </summary> public byte[]? SecretAppend { get { return _secretAppend; } set { _secretAppend = value; } } /// <summary> /// Bytes to prepend to the raw secret agreement before processing by the KDF /// </summary> public byte[]? SecretPrepend { get { return _secretPrepend; } set { _secretPrepend = value; } } /// <summary> /// Seed bytes used for the TLS KDF /// </summary> public byte[]? Seed { get { return _seed; } set { _seed = value; } } /// <summary> /// Use the secret agreement as the HMAC key rather than supplying a separate one /// </summary> public bool UseSecretAgreementAsHmacKey { get { return HmacKey == null; } } protected override void Dispose(bool disposing) { _core.Dispose(); } private void ThrowIfDisposed() { _core.ThrowIfDisposed(); } private void DisposeKey() { _core.DisposeKey(); } internal string? GetCurveName(out string? oidValue) { return Key.GetCurveName(out oidValue); } private void ImportFullKeyBlob(byte[] ecfullKeyBlob, bool includePrivateParameters) { CngKey newKey = ECCng.ImportFullKeyBlob(ecfullKeyBlob, includePrivateParameters); try { Key = newKey; } catch { newKey.Dispose(); throw; } } private void ImportKeyBlob(byte[] ecfullKeyBlob, string curveName, bool includePrivateParameters) { CngKey newKey = ECCng.ImportKeyBlob(ecfullKeyBlob, curveName, includePrivateParameters); try { Key = newKey; } catch { newKey.Dispose(); throw; } } private byte[] ExportKeyBlob(bool includePrivateParameters) { return ECCng.ExportKeyBlob(Key, includePrivateParameters); } private byte[] ExportFullKeyBlob(bool includePrivateParameters) { return ECCng.ExportFullKeyBlob(Key, includePrivateParameters); } private void AcceptImport(CngPkcs8.Pkcs8Response response) { try { Key = response.Key; } catch { response.FreeKey(); throw; } } public override bool TryExportPkcs8PrivateKey(Span<byte> destination, out int bytesWritten) { bool encryptedOnlyExport = CngPkcs8.AllowsOnlyEncryptedExport(Key); if (encryptedOnlyExport) { const string TemporaryExportPassword = "DotnetExportPhrase"; byte[] exported = ExportEncryptedPkcs8(TemporaryExportPassword, 1); EccKeyFormatHelper.ReadEncryptedPkcs8( exported, TemporaryExportPassword, out _, out ECParameters ecParameters); return EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters).TryEncode(destination, out bytesWritten); } return Key.TryExportKeyBlob( Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB, destination, out bytesWritten); } private byte[] ExportEncryptedPkcs8(ReadOnlySpan<char> pkcs8Password, int kdfCount) { return Key.ExportPkcs8KeyBlob(pkcs8Password, kdfCount); } private bool TryExportEncryptedPkcs8( ReadOnlySpan<char> pkcs8Password, int kdfCount, Span<byte> destination, out int bytesWritten) { return Key.TryExportPkcs8KeyBlob( pkcs8Password, kdfCount, destination, out bytesWritten); } } }