Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Security / Cryptography / ECDiffieHellmanCng.cs / 1305376 / ECDiffieHellmanCng.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Diagnostics.Contracts; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography { ////// Key derivation functions used to transform the raw secret agreement into key material /// public enum ECDiffieHellmanKeyDerivationFunction { Hash, Hmac, Tls } ////// Wrapper for CNG's implementation of elliptic curve Diffie-Hellman key exchange /// [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public sealed class ECDiffieHellmanCng : ECDiffieHellman { private static KeySizes[] s_legalKeySizes = new KeySizes[] { new KeySizes(256, 384, 128), new KeySizes(521, 521, 0) }; private CngAlgorithm m_hashAlgorithm = CngAlgorithm.Sha256; private byte[] m_hmacKey; private CngKey m_key; private ECDiffieHellmanKeyDerivationFunction m_kdf = ECDiffieHellmanKeyDerivationFunction.Hash; private byte[] m_label; private byte[] m_secretAppend; private byte[] m_secretPrepend; private byte[] m_seed; // // Constructors // public ECDiffieHellmanCng() : this(521) { Contract.Ensures(LegalKeySizesValue != null); } //// [System.Security.SecurityCritical] public ECDiffieHellmanCng(int keySize) { Contract.Ensures(LegalKeySizesValue != null); if (!NCryptNative.NCryptSupported) { throw new PlatformNotSupportedException(SR.GetString(SR.Cryptography_PlatformNotSupported)); } LegalKeySizesValue = s_legalKeySizes; KeySize = keySize; } //// // [System.Security.SecurityCritical] public ECDiffieHellmanCng(CngKey key) { Contract.Ensures(LegalKeySizesValue != null); Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDiffieHellman); if (key == null) { throw new ArgumentNullException("key"); } if (key.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHRequiresECDHKey), "key"); } if (!NCryptNative.NCryptSupported) { throw new PlatformNotSupportedException(SR.GetString(SR.Cryptography_PlatformNotSupported)); } LegalKeySizesValue = s_legalKeySizes; // Make a copy of the key so that we continue to work if it gets disposed before this algorithm // // This requires an assert for UnmanagedCode since we'll need to access the raw handles of the key // and the handle constructor of CngKey. The assert is safe since ECDiffieHellmanCng will never // expose the key handles to calling code (without first demanding UnmanagedCode via the Handle // property of CngKey). new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); Key = CngKey.Open(key.Handle, key.IsEphemeral ? CngKeyHandleOpenOptions.EphemeralKey : CngKeyHandleOpenOptions.None); CodeAccessPermission.RevertAssert(); KeySize = m_key.KeySize; } ///// // /// Hash algorithm used with the Hash and HMAC KDFs /// public CngAlgorithm HashAlgorithm { get { Contract.Ensures(Contract.Result() != null); return m_hashAlgorithm; } set { Contract.Ensures(m_hashAlgorithm != null); if (m_hashAlgorithm == null) { throw new ArgumentNullException("value"); } m_hashAlgorithm = value; } } /// /// Key used with the HMAC KDF /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Reviewed API design exception since these are really setters for explicit byte arrays rather than properties that will be iterated by users")] public byte[] HmacKey { get { return m_hmacKey; } set { m_hmacKey = value; } } ////// KDF used to transform the secret agreement into key material /// public ECDiffieHellmanKeyDerivationFunction KeyDerivationFunction { get { Contract.Ensures(Contract.Result() >= ECDiffieHellmanKeyDerivationFunction.Hash && Contract.Result () <= ECDiffieHellmanKeyDerivationFunction.Tls); return m_kdf; } set { Contract.Ensures(m_kdf >= ECDiffieHellmanKeyDerivationFunction.Hash && m_kdf <= ECDiffieHellmanKeyDerivationFunction.Tls); if (value < ECDiffieHellmanKeyDerivationFunction.Hash || value > ECDiffieHellmanKeyDerivationFunction.Tls) { throw new ArgumentOutOfRangeException("value"); } m_kdf = value; } } /// /// Label bytes used for the TLS KDF /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Reviewed API design exception since these are really setters for explicit byte arrays rather than properties that will be iterated by users")] public byte[] Label { get { return m_label; } set { m_label = value; } } ////// Bytes to append to the raw secret agreement before processing by the KDF /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Reviewed API design exception since these are really setters for explicit byte arrays rather than properties that will be iterated by users")] public byte[] SecretAppend { get { return m_secretAppend; } set { m_secretAppend = value; } } ////// Bytes to prepend to the raw secret agreement before processing by the KDF /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Reviewed API design exception since these are really setters for explicit byte arrays rather than properties that will be iterated by users")] public byte[] SecretPrepend { get { return m_secretPrepend; } set { m_secretPrepend = value; } } ////// Seed bytes used for the TLS KDF /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "Reviewed API design exception since these are really setters for explicit byte arrays rather than properties that will be iterated by users")] public byte[] Seed { get { return m_seed; } set { m_seed = value; } } ////// Full key pair being used for key generation /// public CngKey Key { get { Contract.Ensures(Contract.Result() != null); Contract.Ensures(Contract.Result ().AlgorithmGroup == CngAlgorithmGroup.ECDiffieHellman); Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDiffieHellman); // If the size of the key no longer matches our stored value, then we need to replace it with // a new key of the correct size. if (m_key != null && m_key.KeySize != KeySize) { m_key.Dispose(); m_key = null; } if (m_key == null) { // Map the current key size to a CNG algorithm name CngAlgorithm algorithm = null; switch (KeySize) { case 256: algorithm = CngAlgorithm.ECDiffieHellmanP256; break; case 384: algorithm = CngAlgorithm.ECDiffieHellmanP384; break; case 521: algorithm = CngAlgorithm.ECDiffieHellmanP521; break; default: Debug.Assert(false, "Illegal key size set"); break; } m_key = CngKey.Create(algorithm); } return m_key; } private set { Contract.Requires(value != null); Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDiffieHellman); if (value.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHRequiresECDHKey)); } if (m_key != null) { m_key.Dispose(); } // // We do not duplicate the handle because the only time the user has access to the key itself // to dispose underneath us is when they construct via the CngKey constructor, which does a // duplication. Otherwise all key lifetimes are controlled directly by the ECDiffieHellmanCng // class. // m_key = value; KeySize = m_key.KeySize; } } /// /// Public key used to generate key material with the second party /// public override ECDiffieHellmanPublicKey PublicKey { //// [System.Security.SecurityCritical] get { Contract.Ensures(Contract.Result// () != null); return new ECDiffieHellmanCngPublicKey(Key); } } /// /// Use the secret agreement as the HMAC key rather than supplying a seperate one /// public bool UseSecretAgreementAsHmacKey { get { return HmacKey == null; } } ////// Given a second party's public key, derive shared key material /// public override byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) { Contract.Ensures(Contract.Result() != null); Contract.Assert(m_kdf >= ECDiffieHellmanKeyDerivationFunction.Hash && m_kdf <= ECDiffieHellmanKeyDerivationFunction.Tls); if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } // We can only work with ECDiffieHellmanCngPublicKeys ECDiffieHellmanCngPublicKey otherKey = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgExpectedECDiffieHellmanCngPublicKey)); } using (CngKey import = otherKey.Import()) { return DeriveKeyMaterial(import); } } /// /// Given a second party's public key, derive shared key material /// //// [System.Security.SecurityCritical] public byte[] DeriveKeyMaterial(CngKey otherPartyPublicKey) { Contract.Ensures(Contract.Result// // // // // () != null); Contract.Assert(m_kdf >= ECDiffieHellmanKeyDerivationFunction.Hash && m_kdf <= ECDiffieHellmanKeyDerivationFunction.Tls); if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } if (otherPartyPublicKey.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHRequiresECDHKey), "otherPartyPublicKey"); } if (otherPartyPublicKey.KeySize != KeySize) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHKeySizeMismatch), "otherPartyPublicKey"); } NCryptNative.SecretAgreementFlags flags = UseSecretAgreementAsHmacKey ? NCryptNative.SecretAgreementFlags.UseSecretAsHmacKey : NCryptNative.SecretAgreementFlags.None; // We require access to the handles for generating key material. This is safe since we will never // expose these handles to user code new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert(); SafeNCryptKeyHandle localKey = Key.Handle; SafeNCryptKeyHandle otherKey = otherPartyPublicKey.Handle; CodeAccessPermission.RevertAssert(); // // Generating key material is a two phase process. // 1. Generate the secret agreement // 2. Pass the secret agreement through a KDF to get key material // using (SafeNCryptSecretHandle secretAgreement = NCryptNative.DeriveSecretAgreement(localKey, otherKey)) { if (KeyDerivationFunction == ECDiffieHellmanKeyDerivationFunction.Hash) { byte[] secretAppend = SecretAppend == null ? null : SecretAppend.Clone() as byte[]; byte[] secretPrepend = SecretPrepend == null ? null : SecretPrepend.Clone() as byte[]; return NCryptNative.DeriveKeyMaterialHash(secretAgreement, HashAlgorithm.Algorithm, secretPrepend, secretAppend, flags); } else if (KeyDerivationFunction == ECDiffieHellmanKeyDerivationFunction.Hmac) { byte[] hmacKey = HmacKey == null ? null : HmacKey.Clone() as byte[]; byte[] secretAppend = SecretAppend == null ? null : SecretAppend.Clone() as byte[]; byte[] secretPrepend = SecretPrepend == null ? null : SecretPrepend.Clone() as byte[]; return NCryptNative.DeriveKeyMaterialHmac(secretAgreement, HashAlgorithm.Algorithm, hmacKey, secretPrepend, secretAppend, flags); } else { Debug.Assert(KeyDerivationFunction == ECDiffieHellmanKeyDerivationFunction.Tls, "Unknown KDF"); byte[] label = Label == null ? null : Label.Clone() as byte[]; byte[] seed = Seed == null ? null : Seed.Clone() as byte[]; if (label == null || seed == null) { throw new InvalidOperationException(SR.GetString(SR.Cryptography_TlsRequiresLabelAndSeed)); } return NCryptNative.DeriveKeyMaterialTls(secretAgreement, label, seed, flags); } } } /// /// Get a handle to the secret agreement generated between two parties /// public SafeNCryptSecretHandle DeriveSecretAgreementHandle(ECDiffieHellmanPublicKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } // We can only work with ECDiffieHellmanCngPublicKeys ECDiffieHellmanCngPublicKey otherKey = otherPartyPublicKey as ECDiffieHellmanCngPublicKey; if (otherPartyPublicKey == null) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgExpectedECDiffieHellmanCngPublicKey)); } using (CngKey importedKey = otherKey.Import()) { return DeriveSecretAgreementHandle(importedKey); } } ////// Get a handle to the secret agreement between two parties /// //// [System.Security.SecurityCritical] [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)] public SafeNCryptSecretHandle DeriveSecretAgreementHandle(CngKey otherPartyPublicKey) { if (otherPartyPublicKey == null) { throw new ArgumentNullException("otherPartyPublicKey"); } if (otherPartyPublicKey.AlgorithmGroup != CngAlgorithmGroup.ECDiffieHellman) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHRequiresECDHKey), "otherPartyPublicKey"); } if (otherPartyPublicKey.KeySize != KeySize) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDHKeySizeMismatch), "otherPartyPublicKey"); } return NCryptNative.DeriveSecretAgreement(Key.Handle, otherPartyPublicKey.Handle); } ///// /// Clean up the algorithm /// protected override void Dispose(bool disposing) { try { if (disposing) { if (m_key != null) { m_key.Dispose(); } } } finally { base.Dispose(disposing); } } // // XML Import // // See code:System.Security.Cryptography.ECDsaCng#ECCXMLFormat and // code:System.Security.Cryptography.Rfc4050KeyFormatter#RFC4050ECKeyFormat for information about // elliptic curve XML formats. // public override void FromXmlString(string xmlString) { throw new NotImplementedException(SR.GetString(SR.Cryptography_ECXmlSerializationFormatRequired)); } public void FromXmlString(string xml, ECKeyXmlFormat format) { if (xml == null) { throw new ArgumentNullException("xml"); } if (format != ECKeyXmlFormat.Rfc4050) { throw new ArgumentOutOfRangeException("format"); } Key = Rfc4050KeyFormatter.FromXml(xml); } // // XML Export // // See code:System.Security.Cryptography.ECDsaCng#ECCXMLFormat and // code:System.Security.Cryptography.Rfc4050KeyFormatter#RFC4050ECKeyFormat for information about // elliptic curve XML formats. // public override string ToXmlString(bool includePrivateParameters) { throw new NotImplementedException(SR.GetString(SR.Cryptography_ECXmlSerializationFormatRequired)); } public string ToXmlString(ECKeyXmlFormat format) { Contract.Ensures(Contract.Result() != null); if (format != ECKeyXmlFormat.Rfc4050) { throw new ArgumentOutOfRangeException("format"); } return Rfc4050KeyFormatter.ToXml(Key); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Activator.cs
- XpsImageSerializationService.cs
- EventLogPermissionEntryCollection.cs
- DesignTimeXamlWriter.cs
- IdnElement.cs
- MethodRental.cs
- SingleKeyFrameCollection.cs
- ClientBuildManagerCallback.cs
- SourceFileInfo.cs
- HttpHandlerAction.cs
- RegexCaptureCollection.cs
- EmptyEnumerator.cs
- BitmapMetadataEnumerator.cs
- BufferedGraphics.cs
- PageCodeDomTreeGenerator.cs
- FilterQuery.cs
- SID.cs
- XmlEntityReference.cs
- SafeArrayRankMismatchException.cs
- RtType.cs
- ArraySegment.cs
- SiteMapProvider.cs
- DynamicUpdateCommand.cs
- MenuRenderer.cs
- InputBindingCollection.cs
- DrawingImage.cs
- HostingEnvironmentException.cs
- CollaborationHelperFunctions.cs
- ExpressionList.cs
- ScriptManager.cs
- XomlSerializationHelpers.cs
- SerializationInfo.cs
- Rights.cs
- FileDialogCustomPlacesCollection.cs
- MSHTMLHostUtil.cs
- WindowsImpersonationContext.cs
- DecoderReplacementFallback.cs
- SubqueryRules.cs
- RSAPKCS1SignatureDeformatter.cs
- _SslState.cs
- BaseUriHelper.cs
- EntityParameter.cs
- ResourceDisplayNameAttribute.cs
- SizeF.cs
- LineServices.cs
- QueryStack.cs
- MessageQueuePermission.cs
- Crc32Helper.cs
- TextTreeNode.cs
- Misc.cs
- objectresult_tresulttype.cs
- RectAnimationUsingKeyFrames.cs
- StringComparer.cs
- NativeMethods.cs
- SqlMultiplexer.cs
- DateTimeConverter.cs
- StateBag.cs
- MenuTracker.cs
- PermissionSetEnumerator.cs
- MenuTracker.cs
- ClientBuildManager.cs
- Deserializer.cs
- AttachedPropertyBrowsableForTypeAttribute.cs
- CompressionTransform.cs
- AssertFilter.cs
- Font.cs
- IconConverter.cs
- metadatamappinghashervisitor.hashsourcebuilder.cs
- TextSimpleMarkerProperties.cs
- RecognizeCompletedEventArgs.cs
- Authorization.cs
- GeometryGroup.cs
- MasterPageCodeDomTreeGenerator.cs
- RegisteredArrayDeclaration.cs
- FilterElement.cs
- VectorCollection.cs
- relpropertyhelper.cs
- Buffer.cs
- StylusSystemGestureEventArgs.cs
- RegexWorker.cs
- ModelUIElement3D.cs
- BackStopAuthenticationModule.cs
- Menu.cs
- MonthChangedEventArgs.cs
- MD5.cs
- StorageAssociationSetMapping.cs
- ValueExpressions.cs
- SetMemberBinder.cs
- LookupNode.cs
- ApplicationServiceManager.cs
- AspNetHostingPermission.cs
- PageBreakRecord.cs
- ContextConfiguration.cs
- XmlSchema.cs
- TableItemPattern.cs
- XmlnsCache.cs
- WebPartDescription.cs
- WebPartConnection.cs
- ScriptResourceHandler.cs
- Control.cs