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 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 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"; } } } }