// // System.Security.Cryptography SymmetricAlgorithm Class implementation // // Authors: // Thomas Neidhart (tome@sbox.tugraz.at) // using System; using System.Security.Cryptography; namespace System.Security.Cryptography { /// /// Abstract base class for all cryptographic symmetric algorithms. /// Available algorithms include: /// DES, RC2, Rijndael, TripleDES /// public abstract class SymmetricAlgorithm { protected int BlockSizeValue; // The block size of the cryptographic operation in bits. protected int FeedbackSizeValue; // The feedback size of the cryptographic operation in bits. protected byte[] IVValue; // The initialization vector ( IV) for the symmetric algorithm. protected int KeySizeValue; // The size of the secret key used by the symmetric algorithm in bits. protected byte[] KeyValue; // The secret key for the symmetric algorithm. protected KeySizes[] LegalBlockSizesValue; // Specifies the block sizes that are supported by the symmetric algorithm. protected KeySizes[] LegalKeySizesValue; // Specifies the key sizes that are supported by the symmetric algorithm. protected CipherMode ModeValue; // Represents the cipher mode used in the symmetric algorithm. protected PaddingMode PaddingValue; // Represents the padding mode used in the symmetric algorithm. /// /// Called from constructor of derived class. /// public SymmetricAlgorithm () { throw new CryptographicException(); } /// /// Called from constructor of derived class. /// ~SymmetricAlgorithm () { if (KeyValue != null) { Array.Clear(KeyValue, 0, KeyValue.Length); KeyValue = null; } } /// /// Gets or sets the actual BlockSize /// public virtual int BlockSize { get { return this.BlockSizeValue; } set { if (IsLegalKeySize(this.LegalBlockSizesValue, value)) this.BlockSizeValue = value; else throw new CryptographicException("block size not supported by algorithm"); } } /// /// Gets or sets the actual FeedbackSize /// public virtual int FeedbackSize { get { return this.FeedbackSizeValue; } set { if (value > this.BlockSizeValue) throw new CryptographicException("feedback size larger than block size"); else this.FeedbackSizeValue = value; } } /// /// Gets or sets the actual Initial Vector /// public virtual byte[] IV { get { if (this.IVValue == null) GenerateIV(); return this.IVValue; } set { if (value == null) throw new ArgumentNullException("tried setting initial vector to null"); // FIXME: dont know if to compare with block or key size if (value.Length != this.KeySizeValue) throw new CryptographicException("tried setting initial vector with illegal size"); this.IVValue = new byte [value.Length]; System.Array.Copy (value, 0, this.IVValue, 0, value.Length); } } /// /// Gets or sets the actual key /// public virtual byte[] Key { get { if (this.KeyValue == null) GenerateKey(); return this.KeyValue; } set { if (value == null) throw new ArgumentNullException("tried setting key to null"); if (!IsLegalKeySize(this.LegalKeySizesValue, value.Length)) throw new CryptographicException("key size not supported by algorithm"); this.KeySizeValue = value.Length; this.KeyValue = new byte [this.KeySizeValue]; System.Array.Copy (value, 0, this.KeyValue, 0, this.KeySizeValue); } } /// /// Gets or sets the actual key size /// public virtual int KeySize { get { return this.KeySizeValue; } set { if (!IsLegalKeySize(this.LegalKeySizesValue, value)) throw new CryptographicException("key size not supported by algorithm"); this.KeyValue = null; this.KeySizeValue = value; } } /// /// Gets all legal block sizes /// public virtual KeySizes[] LegalBlockSizes { get { return this.LegalBlockSizesValue; } } /// /// Gets all legal key sizes /// public virtual KeySizes[] LegalKeySizes { get { return this.LegalKeySizesValue; } } /// /// Gets or sets the actual cipher mode /// public virtual CipherMode Mode { get { return this.ModeValue; } set { if (Enum.IsDefined(ModeValue.GetType(), value)) this.ModeValue = value; else throw new CryptographicException("padding mode not available"); } } /// /// Gets or sets the actual padding /// public virtual PaddingMode Padding { get { return this.PaddingValue; } set { if (Enum.IsDefined(PaddingValue.GetType(), value)) this.PaddingValue = value; else throw new CryptographicException("padding mode not available"); } } /// /// Gets an Decryptor transform object to work with a CryptoStream /// public virtual ICryptoTransform CreateDecryptor() { return CreateDecryptor(Key, IV); } /// /// Gets an Decryptor transform object to work with a CryptoStream /// public abstract ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV); /// /// Gets an Encryptor transform object to work with a CryptoStream /// public virtual ICryptoTransform CreateEncryptor() { return CreateEncryptor(Key, IV); } /// /// Gets an Encryptor transform object to work with a CryptoStream /// public abstract ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV); /// /// used to generate an inital vector if none is specified /// public abstract void GenerateIV(); /// /// used to generate a random key if none is specified /// public abstract void GenerateKey(); internal bool IsLegalKeySize(KeySizes[] LegalKeys, int Size) { foreach (KeySizes LegalKeySize in LegalKeys) { for (int i=LegalKeySize.MinSize; i<=LegalKeySize.MaxSize; i+=LegalKeySize.SkipSize) { if (i == Size) return true; } } return false; } /// /// Checks wether the given keyLength is valid for the current algorithm /// /// the given keyLength public bool ValidKeySize(int bitLength) { return IsLegalKeySize(LegalKeySizesValue, bitLength); } /// /// Creates the default implementation of the default symmetric algorithm (RC2). /// public static SymmetricAlgorithm Create () { // TODO: default algorithm is RijndaelManaged return null; } /// /// Creates a specific implementation of the given symmetric algorithm. /// /// the given algorithm public static SymmetricAlgorithm Create (string algName) { // TODO: use reflection to create a new instance of the given algorithm return null; } } }