//
// System.Security.Cryptography SymmetricAlgorithm Class implementation
//
// Authors:
// Thomas Neidhart (tome@sbox.tugraz.at)
//
using System;
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 () {
return Rijndael.Create();
}
///
/// 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 algorithm instance
return null;
}
}
}