Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Security / Cryptography / AesCryptoServiceProvider.cs / 1305376 / AesCryptoServiceProvider.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== using System; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Diagnostics.Contracts; using Microsoft.Win32.SafeHandles; namespace System.Security.Cryptography { ////// AES wrapper around the CAPI implementation. /// [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] public sealed class AesCryptoServiceProvider : Aes { private static KeySizes[] s_supportedKeySizes; private static int s_defaultKeySize; private SafeCspHandle m_cspHandle; // Note that keys are stored in CAPI rather than directly in the KeyValue property, which should not // be used to retrieve the key value directly. private SafeCapiKeyHandle m_key; //// [System.Security.SecurityCritical] public AesCryptoServiceProvider () { Contract.Ensures(m_cspHandle != null && !m_cspHandle.IsInvalid && !m_cspHandle.IsClosed); // On Windows XP the AES CSP has the prototype name, but on newer operating systems it has the // standard name string providerName = CapiNative.ProviderNames.MicrosoftEnhancedRsaAes; if (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1) { providerName = CapiNative.ProviderNames.MicrosoftEnhancedRsaAesPrototype; } m_cspHandle = CapiNative.AcquireCsp(null, providerName, CapiNative.ProviderType.RsaAes, CapiNative.CryptAcquireContextFlags.VerifyContext, true); // CAPI will not allow feedback sizes greater than 64 bits FeedbackSizeValue = 8; // Get the different AES key sizes supported by this platform, raising an error if there are no // supported key sizes. int defaultKeySize = 0; KeySizes[] keySizes = FindSupportedKeySizes(m_cspHandle, out defaultKeySize); if (keySizes.Length != 0) { Debug.Assert(defaultKeySize > 0, "defaultKeySize > 0"); KeySizeValue = defaultKeySize; } else { throw new PlatformNotSupportedException(SR.GetString(SR.Cryptography_PlatformNotSupported)); } } ///// // // // // /// Value of the symmetric key used for encryption / decryption /// public override byte[] Key { //// [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] get { Contract.Ensures(m_key != null && !m_key.IsInvalid && !m_key.IsClosed); Contract.Ensures(Contract.Result// // // // () != null && Contract.Result ().Length == KeySizeValue / 8); if (m_key == null || m_key.IsInvalid || m_key.IsClosed) { GenerateKey(); } // We don't hold onto a key value directly, so we need to export it from CAPI when the user // wants a byte array representation. byte[] keyValue = CapiNative.ExportSymmetricKey(m_key); return keyValue; } // // [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] set { Contract.Ensures(m_key != null && !m_key.IsInvalid && !m_key.IsClosed); if (value == null) { throw new ArgumentNullException("value"); } byte[] keyValue = (byte[])value.Clone(); if (!ValidKeySize(keyValue.Length * 8)) { throw new CryptographicException(SR.GetString(SR.Cryptography_InvalidKeySize)); } // Import the key, then close any current key and replace with the new one. We need to make // sure the import is successful before closing the current key to avoid having an algorithm // with no valid keys. SafeCapiKeyHandle importedKey = CapiNative.ImportSymmetricKey(m_cspHandle, GetAlgorithmId(keyValue.Length * 8), keyValue); if (m_key != null) { m_key.Dispose(); } m_key = importedKey; KeySizeValue = keyValue.Length * 8; } } ///// // // // // // // /// Size, in bits, of the key /// public override int KeySize { get { return base.KeySize; } //// [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] set { base.KeySize = value; // Since the key size is being reset, we need to reset the key itself as well if (m_key != null) { m_key.Dispose(); } } } ///// // /// Create an object to perform AES decryption with the current key and IV /// ///// // [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] public override ICryptoTransform CreateDecryptor() { Contract.Ensures(Contract.Result// // // // () != null); if (m_key == null || m_key.IsInvalid || m_key.IsClosed) { throw new CryptographicException(SR.GetString(SR.Cryptography_DecryptWithNoKey)); } return CreateDecryptor(m_key, IVValue); } /// /// Create an object to perform AES decryption with the given key and IV /// //// [System.Security.SecurityCritical] public override ICryptoTransform CreateDecryptor(byte[] key, byte[] iv) { Contract.Ensures(Contract.Result// // // // () != null); if (key == null) { throw new ArgumentNullException("key"); } if (!ValidKeySize(key.Length * 8)) { throw new ArgumentException(SR.GetString(SR.Cryptography_InvalidKeySize), "key"); } if (iv != null && iv.Length * 8 != BlockSizeValue) { throw new ArgumentException(SR.GetString(SR.Cryptography_InvalidIVSize), "iv"); } byte[] keyCopy = (byte[])key.Clone(); byte[] ivCopy = null; if (iv != null) { ivCopy = (byte[])iv.Clone(); } using (SafeCapiKeyHandle importedKey = CapiNative.ImportSymmetricKey(m_cspHandle, GetAlgorithmId(keyCopy.Length * 8), keyCopy)) { return CreateDecryptor(importedKey, ivCopy); } } /// /// Create an object to perform AES decryption /// //// [System.Security.SecurityCritical] private ICryptoTransform CreateDecryptor(SafeCapiKeyHandle key, byte[] iv) { Contract.Requires(key != null); Contract.Ensures(Contract.Result// // // () != null); return new CapiSymmetricAlgorithm(BlockSizeValue, FeedbackSizeValue, m_cspHandle, key, iv, Mode, PaddingValue, EncryptionMode.Decrypt); } /// /// Create an object to do AES encryption with the current key and IV /// //// [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] public override ICryptoTransform CreateEncryptor() { Contract.Ensures(Contract.Result// // // // () != null); if (m_key == null || m_key.IsInvalid || m_key.IsClosed) { GenerateKey(); } // ECB is the only mode which does not require an IV -- generate one here if we don't have one yet. if (Mode != CipherMode.ECB && IVValue == null) { GenerateIV(); } return CreateEncryptor(m_key, IVValue); } /// /// Create an object to do AES encryption with the given key and IV /// //// [System.Security.SecurityCritical] public override ICryptoTransform CreateEncryptor(byte[] key, byte[] iv) { Contract.Ensures(Contract.Result// // // // () != null); if (key == null) { throw new ArgumentNullException("key"); } if (!ValidKeySize(key.Length * 8)) { throw new ArgumentException(SR.GetString(SR.Cryptography_InvalidKeySize), "key"); } if (iv != null && iv.Length * 8 != BlockSizeValue) { throw new ArgumentException(SR.GetString(SR.Cryptography_InvalidIVSize), "iv"); } byte[] keyCopy = (byte[])key.Clone(); byte[] ivCopy = null; if (iv != null) { ivCopy = (byte[])iv.Clone(); } using (SafeCapiKeyHandle importedKey = CapiNative.ImportSymmetricKey(m_cspHandle, GetAlgorithmId(keyCopy.Length * 8), keyCopy)) { return CreateEncryptor(importedKey, ivCopy); } } /// /// Create an object to perform AES encryption /// //// [System.Security.SecurityCritical] private ICryptoTransform CreateEncryptor(SafeCapiKeyHandle key, byte[] iv) { Contract.Requires(key != null); Contract.Ensures(Contract.Result// // // () != null); return new CapiSymmetricAlgorithm(BlockSizeValue, FeedbackSizeValue, m_cspHandle, key, iv, Mode, PaddingValue, EncryptionMode.Encrypt); } /// /// Release any CAPI handles we're holding onto /// //// [System.Security.SecurityCritical] protected override void Dispose(bool disposing) { Contract.Ensures(!disposing || m_key == null || m_key.IsClosed); Contract.Ensures(!disposing || m_cspHandle == null || m_cspHandle.IsClosed); try { if (disposing) { if (m_key != null) { m_key.Dispose(); } if (m_cspHandle != null) { m_cspHandle.Dispose(); } } } finally { base.Dispose(disposing); } } ///// // // // /// Get the size of AES keys supported by the given CSP, and which size should be used by default. /// /// We assume that the same CSP will always be used by all instances of the AesCryptoServiceProvider /// in the current AppDomain. If we add the ability for users to choose which CSP to use on a /// per-instance basis, we need to update the code to account for the CSP when checking the cached /// key size values. /// //// [System.Security.SecurityCritical] private static KeySizes[] FindSupportedKeySizes(SafeCspHandle csp, out int defaultKeySize) { Contract.Requires(csp != null); Contract.Ensures(Contract.Result// // () != null); // If this platform has any supported algorithm sizes, then the default key size should be set to a // reasonable value. Contract.Ensures(Contract.Result ().Length == 0 || (Contract.ValueAtReturn (out defaultKeySize) > 0 && Contract.ValueAtReturn (out defaultKeySize) % 8 == 0)); if (s_supportedKeySizes == null) { List keySizes = new List (); int maxKeySize = 0; // // Enumerate the CSP's supported algorithms to see what key sizes it supports for AES // CapiNative.PROV_ENUMALGS algorithm = CapiNative.GetProviderParameterStruct (csp, CapiNative.ProviderParameter.EnumerateAlgorithms, CapiNative.ProviderParameterFlags.RestartEnumeration); // Translate between CAPI AES algorithm IDs and supported key sizes while (algorithm.aiAlgId != CapiNative.AlgorithmId.None) { switch (algorithm.aiAlgId) { case CapiNative.AlgorithmId.Aes128: keySizes.Add(new KeySizes(128, 128, 0)); if (128 > maxKeySize) { maxKeySize = 128; } break; case CapiNative.AlgorithmId.Aes192: keySizes.Add(new KeySizes(192, 192, 0)); if (192 > maxKeySize) { maxKeySize = 192; } break; case CapiNative.AlgorithmId.Aes256: keySizes.Add(new KeySizes(256, 256, 0)); if (256 > maxKeySize) { maxKeySize = 256; } break; default: break; } algorithm = CapiNative.GetProviderParameterStruct (csp, CapiNative.ProviderParameter.EnumerateAlgorithms, CapiNative.ProviderParameterFlags.None); } s_supportedKeySizes = keySizes.ToArray(); s_defaultKeySize = maxKeySize; } defaultKeySize = s_defaultKeySize; return s_supportedKeySizes; } /// /// Generate a new random key /// //// [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] public override void GenerateKey() { Contract.Ensures(m_key != null && !m_key.IsInvalid & !m_key.IsClosed); Contract.Assert(m_cspHandle != null); SafeCapiKeyHandle key = null; if (!CapiNative.UnsafeNativeMethods.CryptGenKey(m_cspHandle, GetAlgorithmId(KeySizeValue), CapiNative.KeyFlags.Exportable, out key)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } if (m_key != null) { m_key.Dispose(); } m_key = key; } ///// // // // // // // // /// Generate a random initialization vector /// //// [System.Security.SecurityCritical] [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] public override void GenerateIV() { Contract.Ensures(IVValue != null && IVValue.Length == BlockSizeValue / 8); Contract.Assert(m_cspHandle != null); Contract.Assert(BlockSizeValue % 8 == 0); byte[] iv = new byte[BlockSizeValue / 8]; if (!CapiNative.UnsafeNativeMethods.CryptGenRandom(m_cspHandle, iv.Length, iv)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } IVValue = iv; } ///// // // /// Map an AES key size to the corresponding CAPI algorithm ID /// private static CapiNative.AlgorithmId GetAlgorithmId(int keySize) { // We should always return either a data encryption algorithm ID or None if we don't recognize the key size Contract.Ensures( ((((int)Contract.Result()) & (int)CapiNative.AlgorithmClass.DataEncryption) == (int)CapiNative.AlgorithmClass.DataEncryption) || Contract.Result () == CapiNative.AlgorithmId.None); switch (keySize) { case 128: return CapiNative.AlgorithmId.Aes128; case 192: return CapiNative.AlgorithmId.Aes192; case 256: return CapiNative.AlgorithmId.Aes256; default: return CapiNative.AlgorithmId.None; } } } } // 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
- ShaperBuffers.cs
- OptimalBreakSession.cs
- ImageSource.cs
- AnnotationComponentManager.cs
- NameValueFileSectionHandler.cs
- BackgroundWorker.cs
- ReadOnlyDataSourceView.cs
- DeclarativeCatalogPart.cs
- RightsManagementUser.cs
- MergeLocalizationDirectives.cs
- SmiMetaData.cs
- ToolStripItemDataObject.cs
- Rule.cs
- BindUriHelper.cs
- DSACryptoServiceProvider.cs
- WorkflowRuntimeServiceElementCollection.cs
- CachedFontFamily.cs
- DataGridViewCellStateChangedEventArgs.cs
- InvokeProviderWrapper.cs
- Math.cs
- IndexingContentUnit.cs
- FileUtil.cs
- SharedStatics.cs
- Header.cs
- XPathParser.cs
- AppDomainManager.cs
- NamespaceEmitter.cs
- SystemInfo.cs
- Message.cs
- ScriptResourceHandler.cs
- Cursors.cs
- FileSystemWatcher.cs
- BadImageFormatException.cs
- GridViewDeletedEventArgs.cs
- FamilyMap.cs
- SqlDataSourceCache.cs
- LoginUtil.cs
- OciLobLocator.cs
- MetadataArtifactLoaderFile.cs
- SmtpLoginAuthenticationModule.cs
- PeerCollaborationPermission.cs
- NumberSubstitution.cs
- XPathParser.cs
- DbMetaDataFactory.cs
- Utils.cs
- ContextMenuAutomationPeer.cs
- GridViewDeleteEventArgs.cs
- Latin1Encoding.cs
- ColumnCollection.cs
- HandleCollector.cs
- AnnotationResourceCollection.cs
- TypedTableBaseExtensions.cs
- CompressionTracing.cs
- NavigationPropertyEmitter.cs
- RelationshipManager.cs
- hresults.cs
- SynchronizedDispatch.cs
- SmtpReplyReaderFactory.cs
- Vector.cs
- DataViewListener.cs
- URLAttribute.cs
- SiteMapDataSourceView.cs
- EraserBehavior.cs
- MachineKeyConverter.cs
- BuilderPropertyEntry.cs
- ButtonPopupAdapter.cs
- SystemFonts.cs
- SslStreamSecurityUpgradeProvider.cs
- WriteFileContext.cs
- recordstate.cs
- BufferedStream.cs
- InternalMappingException.cs
- SessionSymmetricMessageSecurityProtocolFactory.cs
- GC.cs
- StoreAnnotationsMap.cs
- WebPartConnectionsCancelEventArgs.cs
- CompositeKey.cs
- PageThemeCodeDomTreeGenerator.cs
- DetailsViewInsertedEventArgs.cs
- PrintPageEvent.cs
- SystemDiagnosticsSection.cs
- ColorConvertedBitmapExtension.cs
- Vector3DCollectionConverter.cs
- BitmapImage.cs
- DataColumn.cs
- PagedDataSource.cs
- BitmapImage.cs
- ComponentEditorPage.cs
- AttachmentService.cs
- XmlILStorageConverter.cs
- InheritanceContextHelper.cs
- WebServiceHost.cs
- Process.cs
- LayoutTable.cs
- InkSerializer.cs
- PropertyChangeTracker.cs
- CssClassPropertyAttribute.cs
- OletxCommittableTransaction.cs
- SaveFileDialog.cs
- ChameleonKey.cs