File: System\Security\Cryptography\ECDiffieHellmanCngPublicKey.cs
Web Access
Project: src\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.Runtime.Versioning;

namespace System.Security.Cryptography
{
    /// <summary>
    /// Public key used to do key exchange with the ECDiffieHellmanCng algorithm
    /// </summary>
    public sealed partial class ECDiffieHellmanCngPublicKey : ECDiffieHellmanPublicKey
    {
        private readonly CngKeyBlobFormat _format;
        private readonly string? _curveName;
        private bool _disposed;

        /// <summary>
        /// Wrap a CNG key
        /// </summary>
#pragma warning disable SYSLIB0043 // byte[] constructor on ECDiffieHellmanPublicKey is obsolete
        internal ECDiffieHellmanCngPublicKey(byte[] keyBlob, string? curveName, CngKeyBlobFormat format) : base(keyBlob)
#pragma warning restore SYSLIB0043
        {
            _format = format;
            // Can be null for P256, P384, P521, or an explicit blob
            _curveName = curveName;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _disposed = true;
            }

            base.Dispose(disposing);
        }

        [Obsolete(Obsoletions.EccXmlExportImportMessage, DiagnosticId = Obsoletions.EccXmlExportImportDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        public override string ToXmlString()
        {
            throw new PlatformNotSupportedException();
        }

        [Obsolete(Obsoletions.EccXmlExportImportMessage, DiagnosticId = Obsoletions.EccXmlExportImportDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
        public static ECDiffieHellmanCngPublicKey FromXmlString(string xml)
        {
            throw new PlatformNotSupportedException();
        }

        /// <summary>
        /// Format the key blob is expressed in
        /// </summary>
        public CngKeyBlobFormat BlobFormat
        {
            get
            {
                return _format;
            }
        }

        /// <summary>
        /// Hydrate a public key from a blob
        /// </summary>
        [SupportedOSPlatform("windows")]
        public static ECDiffieHellmanPublicKey FromByteArray(byte[] publicKeyBlob, CngKeyBlobFormat format)
        {
            ArgumentNullException.ThrowIfNull(publicKeyBlob);
            ArgumentNullException.ThrowIfNull(format);

            // Verify that the key can import successfully, because we did in the past.
            using (CngKey imported = CngKey.Import(publicKeyBlob, format))
            {
                if (imported.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman)
                {
                    throw new ArgumentException(SR.Cryptography_ArgECDHRequiresECDHKey);
                }

                return new ECDiffieHellmanCngPublicKey(publicKeyBlob, null, format);
            }
        }

        internal static ECDiffieHellmanCngPublicKey FromKey(CngKey key)
        {
            CngKeyBlobFormat format;
            string? curveName;
            byte[] blob = ECCng.ExportKeyBlob(key, false, out format, out curveName);
            return new ECDiffieHellmanCngPublicKey(blob, curveName, format);
        }

        /// <summary>
        /// Import the public key into CNG
        /// </summary>
        /// <returns></returns>
        public CngKey Import()
        {
            ObjectDisposedException.ThrowIf(_disposed, this);

#pragma warning disable SYSLIB0043 // ToByteArray is obsolete.
            return CngKey.Import(ToByteArray(), _curveName, BlobFormat);
#pragma warning restore SYSLIB0043
        }

        /// <summary>
        ///  Exports the key and explicit curve parameters used by the ECC object into an <see cref="ECParameters"/> object.
        /// </summary>
        /// <exception cref="CryptographicException">
        ///  if there was an issue obtaining the curve values.
        /// </exception>
        /// <exception cref="PlatformNotSupportedException">
        ///  if explicit export is not supported by this platform. Windows 10 or higher is required.
        /// </exception>
        /// <returns>The key and explicit curve parameters used by the ECC object.</returns>
        public override ECParameters ExportExplicitParameters()
        {
            using (CngKey key = Import())
            {
                ECParameters ecparams = default;
                byte[] blob = ECCng.ExportFullKeyBlob(key, includePrivateParameters: false);
                ECCng.ExportPrimeCurveParameters(ref ecparams, blob, includePrivateParameters: false);
                return ecparams;
            }
        }

        /// <summary>
        ///  Exports the key used by the ECC object into an <see cref="ECParameters"/> object.
        ///  If the key was created as a named curve, the Curve property will contain named curve parameters
        ///  otherwise it will contain explicit parameters.
        /// </summary>
        /// <exception cref="CryptographicException">
        ///  if there was an issue obtaining the curve values.
        /// </exception>
        /// <returns>The key and named curve parameters used by the ECC object.</returns>
        public override ECParameters ExportParameters()
        {
            using (CngKey key = Import())
            {
                ECParameters ecparams = default;
                string? curveName = key.GetCurveName(out _);

                if (string.IsNullOrEmpty(curveName))
                {
                    byte[] fullKeyBlob = ECCng.ExportFullKeyBlob(key, includePrivateParameters: false);
                    ECCng.ExportPrimeCurveParameters(ref ecparams, fullKeyBlob, includePrivateParameters: false);
                }
                else
                {
                    byte[] keyBlob = ECCng.ExportKeyBlob(key, includePrivateParameters: false);
                    ECCng.ExportNamedCurveParameters(ref ecparams, keyBlob, includePrivateParameters: false);
                    ecparams.Curve = ECCurve.CreateFromFriendlyName(curveName);
                }

                return ecparams;
            }
        }
    }
}