212 lines
6.7 KiB
C#
212 lines
6.7 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Copied from https://msdn.microsoft.com/en-us/library/system.security.cryptography.xml.encryptedxml(v=vs.110).aspx
|
|
/// </summary>
|
|
class TrippleDESDocumentEncryption
|
|
{
|
|
protected XmlDocument docValue;
|
|
protected TripleDES algValue;
|
|
|
|
/// <summary>
|
|
/// The characters we use for passwords and salts.
|
|
/// </summary>
|
|
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<XmlElement>())
|
|
{
|
|
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);
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a simple login exception that we can throw when we try to decrypt and it fails
|
|
/// </summary>
|
|
public class LoginException : System.Exception
|
|
{
|
|
public LoginException() : base()
|
|
{ }
|
|
|
|
public LoginException(String message) : base(message)
|
|
{ }
|
|
|
|
public LoginException(String message, Exception innerException) : base(message, innerException)
|
|
{ }
|
|
}
|
|
}
|