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
- AttachedPropertyInfo.cs
- ImageBrush.cs
- DispatcherOperation.cs
- HttpRuntime.cs
- SQLUtility.cs
- LineUtil.cs
- XmlBoundElement.cs
- TextPointer.cs
- ComponentCollection.cs
- TypefaceMetricsCache.cs
- PackageProperties.cs
- UshortList2.cs
- BindingRestrictions.cs
- CacheEntry.cs
- KnownTypesHelper.cs
- FocusChangedEventArgs.cs
- ListItemCollection.cs
- SerializationEventsCache.cs
- XmlUtil.cs
- AutomationElementIdentifiers.cs
- PermissionSet.cs
- IdleTimeoutMonitor.cs
- PenThread.cs
- ScriptResourceInfo.cs
- TypeInformation.cs
- InteropBitmapSource.cs
- DynamicControl.cs
- Base64Decoder.cs
- StorageBasedPackageProperties.cs
- LinkDescriptor.cs
- BamlWriter.cs
- FileNotFoundException.cs
- BasicExpandProvider.cs
- SqlCaseSimplifier.cs
- GetPageNumberCompletedEventArgs.cs
- DateTimeValueSerializer.cs
- Columns.cs
- MobileControlsSection.cs
- GeneratedContractType.cs
- WorkItem.cs
- X509PeerCertificateAuthenticationElement.cs
- StateChangeEvent.cs
- UnsafeNativeMethodsTablet.cs
- OleDbDataAdapter.cs
- DataGridViewCellCancelEventArgs.cs
- GeneratedContractType.cs
- ClientScriptManager.cs
- ExpressionLexer.cs
- FormDesigner.cs
- ApplicationDirectoryMembershipCondition.cs
- TableLayoutPanel.cs
- GroupBox.cs
- SynchronizedDispatch.cs
- DocumentScope.cs
- GridViewAutomationPeer.cs
- ShortcutKeysEditor.cs
- TaskFactory.cs
- ClientProxyGenerator.cs
- GraphicsPath.cs
- ExitEventArgs.cs
- IdentitySection.cs
- RouteCollection.cs
- TemplatePropertyEntry.cs
- PeerContact.cs
- StrokeCollectionDefaultValueFactory.cs
- XmlReaderDelegator.cs
- PropertyEntry.cs
- DocumentPageView.cs
- CompilationLock.cs
- SqlUtils.cs
- TreeNodeStyleCollectionEditor.cs
- MenuScrollingVisibilityConverter.cs
- Set.cs
- ServiceContractViewControl.cs
- NamespaceList.cs
- Parser.cs
- serverconfig.cs
- ProxyGenerationError.cs
- TdsParser.cs
- Script.cs
- Predicate.cs
- StringCollection.cs
- UrlMappingCollection.cs
- CodeIndexerExpression.cs
- IDispatchConstantAttribute.cs
- AdapterUtil.cs
- ComponentResourceKeyConverter.cs
- Vector3DKeyFrameCollection.cs
- ZipIOCentralDirectoryBlock.cs
- FormViewPagerRow.cs
- OdbcHandle.cs
- _ReceiveMessageOverlappedAsyncResult.cs
- CounterCreationDataCollection.cs
- CounterCreationDataCollection.cs
- BrushMappingModeValidation.cs
- SelectedDatesCollection.cs
- PauseStoryboard.cs
- StrokeNode.cs
- DesignerEditorPartChrome.cs
- WorkflowDefinitionContext.cs