kreta/Kreta.EESZTInterface/STS/EncryptHelper.cs
2024-03-13 00:33:46 +01:00

237 lines
9.7 KiB
C#

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Xml;
using Kreta.Resources;
namespace Kreta.EESZTInterface.STS
{
class EncryptHelper
{
public static RSA TransportKey { get; set; }
private static SymmetricAlgorithm _sessionKey;
private static string _sessionKeyAlgorithm = EncryptedXml.XmlEncAES128Url;
private static SymmetricAlgorithm SessionKey
{
get
{
if (_sessionKey == null)
{
_sessionKey = GetKeyInstance(_sessionKeyAlgorithm);
_sessionKey.GenerateKey();
}
return _sessionKey;
}
}
public static string SessionKeyAlgorithm
{
get { return _sessionKeyAlgorithm; }
set
{
// Validate that the URI used to identify the algorithm of the session key is probably correct. Not a complete validation, but should catch most obvious mistakes.
if (!value.StartsWith(Namespaces.xencNs))
{
throw new ArgumentException(EESZTInterfaceResource.SessionKeyAlgorithmMustBeSpecified);
}
_sessionKeyAlgorithm = value;
}
}
public static XmlDocument EncryptMessage(XmlDocument mySoap, X509Certificate2 oamcert, string IdBody, string IdTs,
string idOamCert)
{
string encKId = "EK-" + Guid.NewGuid().ToString().Replace("-", "");
string encDId = "ED-" + Guid.NewGuid().ToString().Replace("-", "");
// Create a symmetric key.
SessionKeyAlgorithm = EncryptedXml.XmlEncAES128Url;
TransportKey = (RSA)oamcert.PublicKey.Key;
var encryptedData = new EncryptedData
{
Type = EncryptedXml.XmlEncElementContentUrl,
EncryptionMethod = new EncryptionMethod(_sessionKeyAlgorithm),
Id = encDId
};
var body = XmlHelper.GetElement(XmlHelper.BodyElementName, Namespaces.soap12Ns, mySoap.DocumentElement);
var requestSecurityToken = XmlHelper.GetElement(XmlHelper.RequestSecurityTokenElementName, Namespaces.nsNs, body);
var encryptedXml = new EncryptedXml();
var encryptedElement = encryptedXml.EncryptData(requestSecurityToken, SessionKey, false);
encryptedData.CipherData.CipherValue = encryptedElement;
encryptedData.KeyInfo = new KeyInfo();
var encryptedKey = new EncryptedKey
{
EncryptionMethod = new EncryptionMethod(EncryptedXml.XmlEncRSAOAEPUrl),
CipherData = new CipherData(EncryptedXml.EncryptKey(SessionKey.Key, TransportKey, true)),
Id = encKId
};
var kInfo = new KeyInfo();
kInfo.Id = "KI-" + Guid.NewGuid().ToString().Replace("-", "");
XmlElement securityTokenReference = mySoap.CreateElement("wsse", "SecurityTokenReference", Namespaces.wsseNs);
securityTokenReference.SetAttribute("Id", Namespaces.wsuNs, "STR-" + Guid.NewGuid().ToString().Replace("-", ""));
XmlElement reference = mySoap.CreateElement("wsse", "Reference", Namespaces.wsseNs);
reference.SetAttribute("ValueType", STSValues.x509v3Value);
reference.SetAttribute("URI", idOamCert);
securityTokenReference.AppendChild(reference);
KeyInfoNode kInfoNode = new KeyInfoNode();
kInfoNode.Value = securityTokenReference;
kInfo.AddClause(kInfoNode);
encryptedKey.KeyInfo = kInfo;
DataReference dRef = new DataReference();
dRef.Uri = "#" + encDId;
encryptedKey.AddReference(dRef);
var headerSec = XmlHelper.GetElement(XmlHelper.SecurityElementName, Namespaces.wsseNs, mySoap.DocumentElement);
var enc = encryptedKey.GetXml();
XmlElement encKeyElement = headerSec.OwnerDocument.ImportNode(encryptedKey.GetXml(), true) as XmlElement;
SetEncPrefix(encKeyElement);
headerSec.InsertAfter(encKeyElement, XmlHelper.GetElementId(mySoap, idOamCert.Replace("#", "")));
kInfo = new KeyInfo();
securityTokenReference = mySoap.CreateElement("wsse", "SecurityTokenReference", Namespaces.wsseNs);
securityTokenReference.SetAttribute("xmlns:wsse11", Namespaces.wsse11Ns);
securityTokenReference.SetAttribute("TokenType", Namespaces.wsse11Ns, STSValues.encryptedKeyValue);
reference = mySoap.CreateElement("wsse", "Reference", Namespaces.wsseNs);
reference.SetAttribute("URI", "#" + encKId);
securityTokenReference.AppendChild(reference);
kInfoNode = new KeyInfoNode();
kInfoNode.Value = securityTokenReference;
kInfo.AddClause(kInfoNode);
encryptedData.KeyInfo = kInfo;
EncryptedXml.ReplaceElement(body, encryptedData, true);
SetEncPrefix(body);
return mySoap;
}
public static XmlDocument DecryptMessageAll(XmlDocument mySoap, X509Certificate2 userCert)
{
RSA publicKeyRSA = userCert.PrivateKey as RSA;
TransportKey = publicKeyRSA;
var bodyElement = XmlHelper.GetElement(XmlHelper.BodyElementName, Namespaces.soap12Ns, mySoap.DocumentElement);
var encryptedDataElement = XmlHelper.GetElement(XmlHelper.EncryptedDataElementName, Namespaces.xencNs, bodyElement);
var securityElement = XmlHelper.GetElement(XmlHelper.SecurityElementName, Namespaces.wsseNs, mySoap.DocumentElement);
var encryptedData = new EncryptedData();
encryptedData.LoadXml(encryptedDataElement);
string _sessionKeyAlgorithm;
SymmetricAlgorithm sessionKey;
if (encryptedData.EncryptionMethod != null)
{
_sessionKeyAlgorithm = encryptedData.EncryptionMethod.KeyAlgorithm;
sessionKey = ExtractSessionKey(securityElement, encryptedDataElement, _sessionKeyAlgorithm);
}
else
{
sessionKey = ExtractSessionKey(securityElement, encryptedDataElement, string.Empty);
}
var encryptedXml = new EncryptedXml(mySoap);
encryptedXml.ReplaceData(encryptedDataElement, encryptedXml.DecryptData(encryptedData, sessionKey));
return mySoap;
}
private static SymmetricAlgorithm ExtractSessionKey(XmlElement securityElement, XmlElement encryptedData, string keyAlgorithm)
{
// Check if there are any <EncryptedKey> elements immediately below the EncryptedAssertion element.
foreach (XmlNode node in securityElement.ChildNodes)
{
if (node.LocalName == XmlHelper.EncryptedKeyElementName && node.NamespaceURI == Namespaces.xencNs)
{
return ToSymmetricKey((XmlElement)node, keyAlgorithm);
}
}
// Check if the key is embedded in the <EncryptedData> element.
if (encryptedData != null)
{
var encryptedKeyElement = XmlHelper.GetElement(XmlHelper.EncryptedKeyElementName, Namespaces.xencNs, encryptedData);
if (encryptedKeyElement != null)
{
return ToSymmetricKey(encryptedKeyElement, keyAlgorithm);
}
}
throw new Exception(EESZTInterfaceResource.EncryptedKeyNemTalalhato);
}
private static SymmetricAlgorithm ToSymmetricKey(XmlElement encryptedKeyElement, string keyAlgorithm)
{
var encryptedKey = new EncryptedKey();
encryptedKey.LoadXml(encryptedKeyElement);
var useOaep = true;
if (encryptedKey.EncryptionMethod != null)
{
useOaep = encryptedKey.EncryptionMethod.KeyAlgorithm == EncryptedXml.XmlEncRSAOAEPUrl;
}
if (encryptedKey.CipherData.CipherValue != null)
{
var key = GetKeyInstance(keyAlgorithm);
key.Key = EncryptedXml.DecryptKey(encryptedKey.CipherData.CipherValue, TransportKey, useOaep);
return key;
}
throw new NotImplementedException(EESZTInterfaceResource.UnableToDecodeCipherData);
}
private static SymmetricAlgorithm GetKeyInstance(string algorithm)
{
SymmetricAlgorithm result;
switch (algorithm)
{
case EncryptedXml.XmlEncTripleDESUrl:
result = TripleDES.Create();
break;
case EncryptedXml.XmlEncAES128Url:
result = new RijndaelManaged { KeySize = 128 };
break;
case EncryptedXml.XmlEncAES192Url:
result = new RijndaelManaged { KeySize = 192 };
break;
case EncryptedXml.XmlEncAES256Url:
default:
result = new RijndaelManaged { KeySize = 256 };
break;
}
return result;
}
private static void SetEncPrefix(XmlElement encKeyElement)
{
foreach (XmlNode xnode in encKeyElement.SelectNodes($"descendant-or-self::*[namespace-uri()='{Namespaces.dsNs}']"))
{
xnode.Prefix = "ds";
}
foreach (XmlNode xnode in encKeyElement.SelectNodes($"descendant-or-self::*[namespace-uri()='{Namespaces.xencNs}']"))
{
xnode.Prefix = "xenc";
}
}
}
}