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
- RowUpdatedEventArgs.cs
- EmbossBitmapEffect.cs
- ToolStripDropDownClosedEventArgs.cs
- Misc.cs
- ByValueEqualityComparer.cs
- WinInetCache.cs
- TextTreeText.cs
- IDispatchConstantAttribute.cs
- HebrewCalendar.cs
- LabelDesigner.cs
- RegexTree.cs
- CodeFieldReferenceExpression.cs
- ToolStripItemDesigner.cs
- EntityDataSourceChangedEventArgs.cs
- SemanticResolver.cs
- EncodedStreamFactory.cs
- TiffBitmapEncoder.cs
- TableDetailsRow.cs
- JsonServiceDocumentSerializer.cs
- FacetDescription.cs
- ChtmlTextBoxAdapter.cs
- PropertyGridCommands.cs
- KeyGestureValueSerializer.cs
- MsmqInputChannel.cs
- Rect.cs
- NavigateUrlConverter.cs
- SiteMap.cs
- TextEditorDragDrop.cs
- SoapReflectionImporter.cs
- InternalConfigConfigurationFactory.cs
- GeometryCollection.cs
- WebPartMenuStyle.cs
- SystemWebCachingSectionGroup.cs
- ErrorStyle.cs
- FontInfo.cs
- PropertyTabAttribute.cs
- BinaryFormatter.cs
- TextRange.cs
- AspNetSynchronizationContext.cs
- RootAction.cs
- AttributeCollection.cs
- objectquery_tresulttype.cs
- SplitContainer.cs
- PropertyRef.cs
- ComAdminWrapper.cs
- Control.cs
- IRCollection.cs
- FontUnitConverter.cs
- XmlAttributeAttribute.cs
- XmlEventCache.cs
- AssemblyHash.cs
- InputMethodStateChangeEventArgs.cs
- DependencyPropertyDescriptor.cs
- SimplePropertyEntry.cs
- NativeMethods.cs
- PrintPreviewGraphics.cs
- BamlResourceDeserializer.cs
- MeasurementDCInfo.cs
- ReadContentAsBinaryHelper.cs
- DispatcherTimer.cs
- BaseResourcesBuildProvider.cs
- HashMembershipCondition.cs
- ZeroOpNode.cs
- TriState.cs
- Misc.cs
- ColorContext.cs
- RowUpdatingEventArgs.cs
- DataContractAttribute.cs
- RoleManagerEventArgs.cs
- ListViewGroupConverter.cs
- QuaternionAnimationUsingKeyFrames.cs
- Mappings.cs
- CanExecuteRoutedEventArgs.cs
- Vector3DIndependentAnimationStorage.cs
- GlyphRunDrawing.cs
- ContractCodeDomInfo.cs
- ObjectSet.cs
- CodeDelegateCreateExpression.cs
- CommonDialog.cs
- MediaElement.cs
- SqlTransaction.cs
- MenuItem.cs
- UserControlParser.cs
- smtpconnection.cs
- WebPartMinimizeVerb.cs
- XmlCharCheckingWriter.cs
- CacheOutputQuery.cs
- HyperLink.cs
- SqlNamer.cs
- RegistryKey.cs
- UpdatePanel.cs
- XmlUTF8TextReader.cs
- SqlRecordBuffer.cs
- BufferedGraphicsManager.cs
- DataGridViewLinkCell.cs
- FieldBuilder.cs
- RtfControlWordInfo.cs
- BindingWorker.cs
- ScrollItemProviderWrapper.cs
- CLSCompliantAttribute.cs