using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Xml;
namespace EduNetworkBuilder
{
///
/// Copied from https://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.encryptedxml(v=vs.110).aspx
///
class TrippleDESDocumentEncryption
{
protected XmlDocument docValue;
protected TripleDES algValue;
///
/// The characters we use for passwords and salts.
///
protected const string PWChars = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ234567890_.!#$^*";
public TrippleDESDocumentEncryption(XmlDocument Doc, TripleDES Key)
{
if (Doc != null)
{
docValue = Doc;
}
else
{
throw new ArgumentNullException("Doc");
}
if (Key != null)
{
algValue = Key;
}
else
{
throw new ArgumentNullException("Key");
}
}
public XmlDocument Doc { set { docValue = value; } get { return docValue; } }
public TripleDES Alg { set { algValue = value; } get { return algValue; } }
public void Clear()
{
if (algValue != null)
{
algValue.Clear();
}
else
{
throw new Exception("No TripleDES key was found to clear.");
}
}
public void Encrypt(string Element)
{
// Find the element by name and create a new
// XmlElement object.
XmlElement inputElement = docValue.GetElementsByTagName(Element)[0] as XmlElement;
// If the element was not found, throw an exception.
if (inputElement == null)
{
throw new Exception("The element was not found.");
}
// Create a new EncryptedXml object.
EncryptedXml exml = new EncryptedXml(docValue);
// Encrypt the element using the symmetric key.
byte[] rgbOutput = exml.EncryptData(inputElement, algValue, false);
// Create an EncryptedData object and populate it.
EncryptedData ed = new EncryptedData();
// Specify the namespace URI for XML encryption elements.
ed.Type = Element + " " + EncryptedXml.XmlEncElementUrl;
// Specify the namespace URI for the TrippleDES algorithm.
ed.EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncTripleDESUrl);
// Create a CipherData element.
ed.CipherData = new CipherData();
// Set the CipherData element to the value of the encrypted XML element.
ed.CipherData.CipherValue = rgbOutput;
// Replace the plaintext XML elemnt with an EncryptedData element.
EncryptedXml.ReplaceElement(inputElement, ed, false);
}
XmlElement ChooseBestElement(string preferType)
{
XmlNodeList xnl = docValue.GetElementsByTagName("EncryptedData");
foreach (XmlElement one in xnl.OfType())
{
string TypeAttr = one.GetAttribute("Type");
if (TypeAttr != null && TypeAttr.StartsWith(preferType))
return one;
}
return xnl[0] as XmlElement;
}
public void Decrypt(string preferType)
{
// XmlElement object.
XmlElement encryptedElement = ChooseBestElement(preferType);
// If the EncryptedData element was not found, throw an exception.
if (encryptedElement == null)
{
throw new Exception("The EncryptedData element was not found.");
}
// Create an EncryptedData object and populate it.
EncryptedData ed = new EncryptedData();
ed.LoadXml(encryptedElement);
// Create a new EncryptedXml object.
EncryptedXml exml = new EncryptedXml();
// Decrypt the element using the symmetric key.
try
{
//Do the decryption
byte[] rgbOutput = exml.DecryptData(ed, algValue);
// Replace the encryptedData element with the plaintext XML elemnt.
exml.ReplaceData(encryptedElement, rgbOutput);
}
catch
{
//The decryption failed.
throw new LoginException("Key/Salt unable to decrypt.");
}
}
protected static string GenCharString(Random RanGen, int length)
{
int next;
string result = "";
for(int i=0; i< length; i++)
{
next = RanGen.Next(PWChars.Length);
result += PWChars[next];
}
return result;
}
public static string GenSalt(Random RanGen)
{
return GenSalt(RanGen, NB.DefaultSaltLen);
}
public static string GenSalt(Random RanGen, int length)
{
return GenCharString(RanGen, length);
}
public static string GenUserPW(Random RanGen)
{
return GenUserPW(RanGen, NB.DefaultPasswordLen);
}
public static string GenMachinePW(Random RanGen)
{
return GenUserPW(RanGen, NB.DefaultMachinePasswordLen);
}
public static string GenUserPW(Random RanGen, int length)
{
return GenCharString(RanGen, length);
}
public static TripleDES GenKey(string password, string salt)
{
TripleDESCryptoServiceProvider tDESkey = new TripleDESCryptoServiceProvider();
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
var p = new Rfc2898DeriveBytes(password, saltBytes);
tDESkey.IV = p.GetBytes(tDESkey.BlockSize / 8);
tDESkey.Key = p.GetBytes(tDESkey.KeySize / 8);
return tDESkey;
}
public void SetKey(string password, string salt)
{
algValue = GenKey(password, salt);
}
}
///
/// Create a simple login exception that we can throw when we try to decrypt and it fails
///
public class LoginException : System.Exception
{
public LoginException() : base()
{ }
public LoginException(String message) : base(message)
{ }
public LoginException(String message, Exception innerException) : base(message, innerException)
{ }
}
}