237 lines
9.7 KiB
C#
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";
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|