/* * Mentalis.org Security Library * * Copyright © 2002-2005, The KPD-Team * All rights reserved. * http://www.mentalis.org/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Neither the name of the KPD-Team, nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Security.Cryptography; using System.Runtime.InteropServices; using Org.Mentalis.Security; namespace Org.Mentalis.Security.Cryptography { /// /// Defines a wrapper object to access the cryptographic service provider (CSP) version of the RC4 algorithm. This class cannot be inherited. /// public sealed class RC4CryptoServiceProvider : RC4 { /// /// Initializes a new instance of the class. /// public RC4CryptoServiceProvider() { // acquire an RC4 context m_Provider = CAPIProvider.Handle; /* if (SspiProvider.CryptAcquireContext(ref m_Provider, IntPtr.Zero, null, SecurityConstants.PROV_RSA_FULL, 0) == 0) { if (Marshal.GetLastWin32Error() == SecurityConstants.NTE_BAD_KEYSET) SspiProvider.CryptAcquireContext(ref m_Provider, IntPtr.Zero, null, SecurityConstants.PROV_RSA_FULL, SecurityConstants.CRYPT_NEWKEYSET); }*/ if (m_Provider != 0) { int dwFlags = SecurityConstants.CRYPT_FIRST; bool found = false; IntPtr provEnum = Marshal.AllocHGlobal(100); int dwSize; do { dwSize = 100; if (SspiProvider.CryptGetProvParam(m_Provider, SecurityConstants.PP_ENUMALGS_EX, provEnum, ref dwSize, dwFlags) == 0) break; dwFlags = 0; PROV_ENUMALGS_EX eax = (PROV_ENUMALGS_EX)Marshal.PtrToStructure(provEnum, typeof(PROV_ENUMALGS_EX)); if (eax.aiAlgid == SecurityConstants.CALG_RC4) { found = true; m_MinLen = eax.dwMinLen; m_MaxLen = eax.dwMaxLen; } } while (!found); Marshal.FreeHGlobal(provEnum); /* if (!found) { SspiProvider.CryptReleaseContext(m_Provider, 0); m_Provider = 0; }*/ } m_Managed = new ARCFourManaged(); } /// /// Gets or sets the block size of the cryptographic operation in bits. /// /// The block size of RC4 is always 8 bits. /// The block size is invalid. public override int BlockSize { get { return m_Managed.BlockSize; } set { m_Managed.BlockSize = value; } } /// /// Gets or sets the feedback size of the cryptographic operation in bits. /// /// This property always throws a . /// This exception is always thrown. /// RC4 doesn't use the FeedbackSize property. public override int FeedbackSize { get { return m_Managed.FeedbackSize; } set { m_Managed.FeedbackSize = value; } } /// /// Gets or sets the initialization vector (IV) for the symmetric algorithm. /// /// This property always returns a byte array of length one. The value of the byte in the array is always set to zero. /// An attempt is made to set the IV to an invalid instance. /// RC4 doesn't use the IV property, however the property accepts IV's of up to one byte (RC4's ) in order to interoperate with software that has been written with the use of block ciphers in mind. public override byte[] IV { get { return m_Managed.IV; } set { m_Managed.IV = value; } } /// /// Gets or sets the secret key for the symmetric algorithm. /// /// The secret key to be used for the symmetric algorithm. /// An attempt is made to set the key to a null reference (Nothing in Visual Basic). public override byte[] Key { get { return m_Managed.Key; } set { m_Managed.Key = value; } } /// /// Gets or sets the size of the secret key used by the symmetric algorithm in bits. /// /// The size of the secret key used by the symmetric algorithm. /// The key size is not valid. public override int KeySize { get { return m_Managed.KeySize; } set { m_Managed.KeySize = value; } } /// /// Gets the block sizes that are supported by the symmetric algorithm. /// /// An array containing the block sizes supported by the algorithm. /// Only a block size of one byte is supported by the RC4 algorithm. public override KeySizes[] LegalBlockSizes { get { return m_Managed.LegalBlockSizes; } } /// /// Gets the key sizes that are supported by the symmetric algorithm. /// /// An array containing the key sizes supported by the algorithm. /// Only key sizes that match an entry in this array are supported by the symmetric algorithm. public override KeySizes[] LegalKeySizes { get { return m_Managed.LegalKeySizes; } } /// /// Gets or sets the mode for operation of the symmetric algorithm. /// /// The mode for operation of the symmetric algorithm. /// RC4 only supports the OFB cipher mode. See for a description of this mode. /// The cipher mode is not OFB. public override CipherMode Mode { get { return m_Managed.Mode; } set { m_Managed.Mode = value; } } /// /// Gets or sets the padding mode used in the symmetric algorithm. /// /// The padding mode used in the symmetric algorithm. This property always returns PaddingMode.None. /// The padding mode is set to a padding mode other than PaddingMode.None. public override PaddingMode Padding { get { return m_Managed.Padding; } set { m_Managed.Padding = value; } } /// /// This is a stub method. /// /// Since the RC4 cipher doesn't use an Initialization Vector, this method will not do anything. public override void GenerateIV() { m_Managed.GenerateIV(); } /// /// Generates a random Key to be used for the algorithm. /// /// Use this method to generate a random key when none is specified. public override void GenerateKey() { m_Managed.GenerateKey(); } /// /// Creates a symmetric decryptor object with the specified Key. /// /// The secret key to be used for the symmetric algorithm. /// Not used in RC4. It can be a null reference or a byte array with a length less than 2. /// A symmetric decryptor object. /// This method decrypts an encrypted message created using the overload with the same parameters. /// The object is disposed. /// is a null reference (Nothing in Visual Basic). /// public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) { if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); if (rgbKey == null) throw new ArgumentNullException("Key is a null reference."); if (rgbKey.Length == 0 || rgbKey.Length > 256) throw new CryptographicException("Invalid Key."); if (rgbIV != null && rgbIV.Length > 1) throw new CryptographicException("Invalid Initialization Vector."); try { if (CanUseUnmanaged(rgbKey.Length * 8)) return new RC4UnmanagedTransform(rgbKey); } catch {} return m_Managed.CreateDecryptor(rgbKey, rgbIV); } /// /// Creates a symmetric encryptor object with the specified Key. /// /// The secret key to be used for the symmetric algorithm. /// Not used in RC4. It can be a null reference or a byte array with a length less than 2. /// A symmetric encryptor object. /// Use the overload with the same parameters to decrypt the result of this method. /// The object is disposed. /// is a null reference (Nothing in Visual Basic). /// public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) { return this.CreateDecryptor(rgbKey, rgbIV); } /// /// Returns a boolean that indicates whether the unmanaged CSP can be used or not. /// /// The size of the required key (in bits). /// true if the unmanaged CSP can be used to encrypt and decrypt data, false otherwise. private bool CanUseUnmanaged(int keySize) { return (m_Provider != 0) && // make sure the unmanaged CSP is available keySize >= m_MinLen && // keysize is a value between the minimum keySize <= m_MaxLen; // and the maximum size the CSP supports } /// /// Releases all managed and unmanaged resources used by this class. /// private void Dispose() { if (!m_Disposed) { m_Disposed = true; if (m_Managed != null) { m_Managed.Clear(); m_Managed = null; } /* if (m_Provider != 0) { SspiProvider.CryptReleaseContext(m_Provider, 0); m_Provider = 0; }*/ try { GC.SuppressFinalize(this); } catch {} } } /// /// Finalizes the RC4CryptoServiceProvider. /// ~RC4CryptoServiceProvider() { Dispose(); } /// Holds a managed instance. private ARCFourManaged m_Managed; /// Handle of the unmanaged RC4 CSP. private int m_Provider; /// Minimal supported key length by the acquired provider. private int m_MinLen; /// Maximal supported key length by the acquired provider. private int m_MaxLen; /// true if the class is disposed, false otherwise. private bool m_Disposed; } }