[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>
/// 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>
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
///
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>
Contract.Ensures(Contract.Result<CngKey>() != null);
Contract.Assert(m_format != null);
- return CngKey.Import(ToByteArray(), BlobFormat);
+ return CngKey.Import(ToByteArray(), m_curveName, BlobFormat);
}
/// <summary>
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);
+ }
}
}
}