using System;
using System.Xml;
using System.Security.Cryptography;
using System.IO;
using System.Text;
using System.Configuration.Provider;
using System.Configuration;
using System.Windows.Forms;
namespace EncryptConfigurationFile
{
/// <summary>
/// Enumeration : Helps to choose the right algorithm to use
/// </summary>
enum CryptAlgorythmToUse
{
RijndaelManaged,TripleDES
}
/// <summary>
/// Enumeration : Helps to choose the key and IV generation mode
/// </summary>
enum Generate
{
Auto,Manual
}
/// <summary>
/// Class that inherits form the abstract class ProtectedConfigurationProvider
/// </summary>
sealed class CustomProtectionProvider : ProtectedConfigurationProvider, EncryptConfigurationFile.ICustomProtectionProvider
{
//Used to precise the name of the current provider
private string CustomProviderName;
//Used to precise the configuration file path
private string _ConfigFilePath;
//Used to precise the configuration section to Encrypt/Decrypt
private string _SectionName;
//The key
private byte[] _Key;
//The initial vector
private byte[] _IV;
/// <summary>
/// The first class constructor
/// </summary>
/// <param name="CustomProviderName">String: The provider name</param>
/// <param name="Algorithm">Enum: The symmetric algorithm to use </param>
/// <param name="Generate">Enum: Precise if the key and the initial vector
/// are auto generated or given by the class user
///</param>
public CustomProtectionProvider(string CustomProviderName, CryptAlgorythmToUse Algorithm, Generate Generate)
{
//Set the provider name
this.CustomProviderName = CustomProviderName;
//In this case the rijndael is selected
if (Algorithm == CryptAlgorythmToUse.RijndaelManaged)
{
Algo = new RijndaelManaged();
//If the generation mode is auto means that algo generates the key and IV automatically
if (Generate == Generate.Auto)
{
Algo.GenerateKey();
_Key = Algo.Key;
Algo.GenerateIV();
_IV = Algo.IV;
}
}
//In this case the TripleDES is selected
if (Algorithm == CryptAlgorythmToUse.TripleDES)
{
Algo = new TripleDESCryptoServiceProvider();
if (Generate == Generate.Auto)
{
Algo.GenerateKey();
_Key = Algo.Key;
Algo.GenerateIV();
_IV = Algo.IV;
}
}
}
/// <summary>
/// The second class constructor
/// </summary>
/// <param name="CustomProviderName">String: The provider name</param>
/// <param name="ConfigFilePath">String: The configuration file path</param>
/// <param name="Algorithm">Enum: The symmetric algorithm to use</param>
/// <param name="Generate">Enum: Precise if the key and the initial vector
/// are auto generated or given by the class user</param>
public CustomProtectionProvider(string CustomProviderName, string ConfigFilePath, CryptAlgorythmToUse Algorithm, Generate Generate)
{
//Set the provider name
this.CustomProviderName = CustomProviderName;
//Set the configuration path
this.ConfigFilePath = ConfigFilePath;
if (Algorithm == CryptAlgorythmToUse.RijndaelManaged)
{
Algo = new RijndaelManaged();
if (Generate == Generate.Auto)
{
Algo.GenerateKey();
_Key = Algo.Key;
Algo.GenerateIV();
_IV = Algo.IV;
}
}
if (Algorithm == CryptAlgorythmToUse.TripleDES)
{
Algo = new TripleDESCryptoServiceProvider();
if (Generate == Generate.Auto)
{
Algo.GenerateKey();
_Key = Algo.Key;
Algo.GenerateIV();
_IV = Algo.IV;
}
}
}
/// <summary>
/// String: Get and set the configuration file path
/// </summary>
public string ConfigFilePath
{
get { return _ConfigFilePath; }
set { _ConfigFilePath = value; }
}
/// <summary>
/// String : Get the custom provider name
/// </summary>
public override string Name
{
get
{
return "EncryptConfigurationFile.CustomProtectionProvider: " + CustomProviderName;
}
}
/// <summary>
/// String : Get the custom provider description
/// </summary>
public override string Description
{
get
{
return "This is a customized protection provider to encrypt/decrypt configurations sections";
}
}
/// <summary>
/// Byte array : Get and set the algorithm key
/// </summary>
public byte[] Key
{
get
{return _Key;}
set
{_Key = value;}
}
/// <summary>
/// Byte array : Get and set the algorithm initial vector
/// </summary>
public byte[] IV
{
get { return _IV; }
set { _IV = value; }
}
/// <summary>
/// String : Get and set the configuration section name
/// </summary>
public string SectionName
{
get { return _SectionName; }
set { _SectionName = value; }
}
/// <summary>
/// XmlNode : Function that returns an encrypted xml node
/// </summary>
/// <param name="node">XmlNode : Xml node that could be null</param>
/// <returns></returns>
public override XmlNode Encrypt(XmlNode node)
{
//Create a new xml document
XmlDocument myDoc = new XmlDocument();
//Then load it, the configuration file path has to be precised
myDoc.Load(ConfigFilePath);
//If you leave the argument as null you have toprecise at least the configuration section name
if (node == null)
{
XmlNodeList myXmlNodeList = myDoc.GetElementsByTagName(SectionName);
node = myXmlNodeList[0] as XmlNode;
}
//This option lets you precise the xml node to encrypt outside the class scoop
if (node != null)
{
XmlNodeList myXmlNodeList = myDoc.GetElementsByTagName(node.Name);
node = myXmlNodeList[0] as XmlNode;
}
//Encode the configuration section contents to bytes
byte[] nodeContentInByte = Encoding.Unicode.GetBytes(node.InnerXml);
//This byte array is used to contain the output after encryption
byte[] outPutContentInByte = new byte[nodeContentInByte.Length];
//I choose the file stream instead of the memory stream
using (FileStream oStream = new FileStream(@"C:\temp\inout.txt", FileMode.Create,FileAccess.Write))
{
//Create an encryptor
using (ICryptoTransform oTransform = Algo.CreateEncryptor(Algo.Key, Algo.IV))
{
using (CryptoStream crStream = new CryptoStream(oStream, oTransform, CryptoStreamMode.Write))
{
try
{
crStream.Write(nodeContentInByte, 0, nodeContentInByte.Length);
crStream.Flush();
}
catch (ArgumentException caught) { MessageBox.Show(caught.Message); }
}
}
}
//The ouput as string
string output = Convert.ToBase64String(outPutContentInByte);
//Set the new node content
node.InnerXml = AddTags(output);
MessageBox.Show(node.InnerXml);
//Update the configuration file
myDoc.Save(ConfigFilePath);
return node;
}
public override XmlNode Decrypt(XmlNode node)
{
XmlDocument myDoc = new XmlDocument();
myDoc.Load(ConfigFilePath);
string output ="";
if (node == null)
{
XmlNodeList myXmlNodeList = myDoc.GetElementsByTagName(SectionName);
node = myXmlNodeList[0] as XmlNode;
}
if (node != null)
{
XmlNodeList myXmlNodeList = myDoc.GetElementsByTagName(node.Name);
node = myXmlNodeList[0] as XmlNode;
}
using (FileStream oStream = new FileStream(@"C:\temp\inout.txt", FileMode.Open, FileAccess.Read))
{
using (BinaryReader oBinaryReader = new BinaryReader(oStream))
{
long Max = oBinaryReader.BaseStream.Length;
//Put the file content into an array of bytes
byte[] ContentToByte = oBinaryReader.ReadBytes(Convert.ToInt32(Max));
//Encode the bytes to chars
char[] ContentToChar = Encoding.Unicode.GetChars(ContentToByte);
//Transform the char array to string
string inputstring = new string(ContentToChar);
//Set the current position of this stream
oStream.Seek(0, SeekOrigin.Begin);
using (ICryptoTransform oTransform = Algo.CreateDecryptor(Key, IV))
{
using(CryptoStream crStream = new CryptoStream(oStream,oTransform, CryptoStreamMode.Read))
{
//Read the data within the crypto stream using a stream reader instance
using(StreamReader oReader = new StreamReader(crStream,new UnicodeEncoding()))
{
output = oReader.ReadToEnd();
}
crStream.Flush();
}
}
}
}
//Update the node conetent
node.InnerXml = output;
MessageBox.Show(node.InnerXml);
//Update the configuration file
myDoc.Save(ConfigFilePath);
return node;
}
/// <summary>
/// int: Get the hash code
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return base.GetHashCode();
}
/// <summary>
/// String : Adds tags to indicate that the current string is a ecrypted
/// </summary>
/// <param name="input">String: The string going to be tagged</param>
/// <returns>String : Tagged encrypted string</returns>
private string AddTags(string input)
{
return "<EncryptedData>" + input + "</EncryptedData>";
}
}
}
|