Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Core / System / Security / Cryptography / ECDiffieHellmanCngPublicKey.cs
index 67232bb0e90c03ea4ee44f913d12de93975384b3..0417c4fcc7189e6753a99cb1c142f5428046fe3c 100644 (file)
@@ -18,35 +18,20 @@ namespace System.Security.Cryptography {
     [Serializable]
     [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
     public sealed class ECDiffieHellmanCngPublicKey : ECDiffieHellmanPublicKey {
-        [NonSerialized]
-        private CngKey m_key;
         private CngKeyBlobFormat m_format;
+        [OptionalField] private string m_curveName;
 
         /// <summary>
         ///     Wrap a CNG key
         /// </summary>
         [SecuritySafeCritical]
-        internal ECDiffieHellmanCngPublicKey(CngKey key) : base(key.Export(CngKeyBlobFormat.EccPublicBlob)) {
-            Contract.Requires(key != null && key.AlgorithmGroup == CngAlgorithmGroup.ECDiffieHellman);
+        internal ECDiffieHellmanCngPublicKey(byte[] keyBlob, string curveName, CngKeyBlobFormat format) : base(keyBlob) {
+            Contract.Requires(format != null);
             Contract.Ensures(m_format != null);
 
-            m_format = CngKeyBlobFormat.EccPublicBlob;
-
-            //
-            // We need to make a copy of the key to prevent the situation where the ECDiffieHellmanCng algorithm
-            // object is disposed (this disposing its key) before the ECDiffieHellmanCngPublic key is disposed.
-            //
-            // Accessing the handle in partial trust is safe because we're not exposing it back out to user code
-            //
-
-            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
-
-            // This looks odd, but .Handle returns a duplicate, so we need to dispose it
-            using (SafeNCryptKeyHandle importKey = key.Handle) {
-                m_key = CngKey.Open(importKey, key.IsEphemeral ? CngKeyHandleOpenOptions.EphemeralKey : CngKeyHandleOpenOptions.None);
-            }
-
-            CodeAccessPermission.RevertAssert();
+            m_format = format;
+            // Can be null for P256, P384, P521, or an explicit blob
+            m_curveName = curveName;
         }
 
         /// <summary>
@@ -65,16 +50,7 @@ namespace System.Security.Cryptography {
         ///     Clean up the key
         /// </summary>
         protected override void Dispose(bool disposing) {
-            try {
-                if (disposing) {
-                    if (m_key != null) {
-                        m_key.Dispose();
-                    }
-                }
-            }
-            finally {
-                base.Dispose(disposing);
-            }
+            base.Dispose(disposing);
         }
 
         /// <summary>
@@ -89,15 +65,26 @@ namespace System.Security.Cryptography {
                 throw new ArgumentNullException("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.GetString(SR.Cryptography_ArgECDHRequiresECDHKey));
                 }
 
-                return new ECDiffieHellmanCngPublicKey(imported);
+                return new ECDiffieHellmanCngPublicKey(publicKeyBlob, null, format);
             }
         }
 
+        internal static ECDiffieHellmanCngPublicKey FromKey(CngKey key) {
+            Contract.Requires(key != null && key.AlgorithmGroup == CngAlgorithmGroup.ECDiffieHellman);
+            Contract.Ensures(Contract.Result<ECDiffieHellmanCngPublicKey>() != null);
+
+            CngKeyBlobFormat format;
+            string curveName;
+            byte[] blob = ECCng.ExportKeyBlob(key, false, out format, out curveName);
+            return new ECDiffieHellmanCngPublicKey(blob, curveName, format);
+        }
+
         /// <summary>
         ///     Hydrate a public key from XML
         /// 
@@ -110,13 +97,17 @@ namespace System.Security.Cryptography {
                 throw new ArgumentNullException("xml");
             }
 
-            using (CngKey imported = Rfc4050KeyFormatter.FromXml(xml)) {
-                if (imported.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman) {
-                    throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHRequiresECDHKey), "xml");
-                }
+            bool isEcdh;
+            ECParameters parameters = Rfc4050KeyFormatter.FromXml(xml, out isEcdh);
 
-                return new ECDiffieHellmanCngPublicKey(imported);
+            if (!isEcdh) {
+                throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHRequiresECDHKey), "xml");
             }
+
+            CngKeyBlobFormat format;
+            string curveName;
+            byte[] blob = ECCng.EcdhParametersToBlob(ref parameters, out format, out curveName);
+            return new ECDiffieHellmanCngPublicKey(blob, curveName, format);
         }
 
         /// <summary>
@@ -127,7 +118,7 @@ namespace System.Security.Cryptography {
             Contract.Ensures(Contract.Result<CngKey>() != null);
             Contract.Assert(m_format != null);
 
-            return CngKey.Import(ToByteArray(), BlobFormat);
+            return CngKey.Import(ToByteArray(), m_curveName, BlobFormat);
         }
 
         /// <summary>
@@ -139,11 +130,39 @@ namespace System.Security.Cryptography {
         public override string ToXmlString() {
             Contract.Ensures(!String.IsNullOrEmpty(Contract.Result<string>()));
 
-            if (m_key == null) {
-                m_key = Import();
+            ECParameters ecParams = ExportParameters();
+            return Rfc4050KeyFormatter.ToXml(ecParams, isEcdh: true);
+        }
+
+        /// <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()) {
+                return ECCng.ExportExplicitParameters(key, includePrivateParameters: false);
             }
+        }
 
-            return Rfc4050KeyFormatter.ToXml(m_key);
+        /// <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()) {
+                return ECCng.ExportParameters(key, includePrivateParameters: false);
+            }
         }
     }
 }