首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解密SAML响应

解密SAML响应
EN

Stack Overflow用户
提问于 2021-02-16 13:36:55
回答 1查看 1K关注 0票数 0

我正在测试一些基于SAML2的登录流,使用的是与某些SAML2身份提供者集成的Keycloak。登录到服务时,我可以使用如下所示的断言生成SAML响应。我希望有一种解析/解密整个结构的通用方法,这样我就可以以解密XML的形式获得响应(这样我就可以在测试期间看到原始XML )。最好是构建一个.NET核心应用程序,或者是一个Java应用程序。我的身份代理已经将一个公钥交换给身份提供者。

  • I拥有此证书的公钥和私钥,
  • I拥有与身份提供程序对应的公钥。

我为没有成为这方面的专家而事先表示歉意。我看到了处理SAML响应的多个.NET代码片段,但在我看来,似乎有多种SAML响应格式,而且我不知道如何处理这种特定类型的SAML响应。

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://somedestination.com" ID="_8665f62b-e462-402f-88e9-2bfbbff836f4" InResponseTo="ID_d3975e20-95dc-4e08-9c75-8d611d8d92f8" IssueInstant="2021-02-16T13:10:03.619Z" Version="2.0">
    <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://someissuer.com</saml2:Issuer>
    <saml2p:Status>
        <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </saml2p:Status>
    <saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
        <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_96f98f75573fe57e6cb95d4f84a4460e" Type="http://www.w3.org/2001/04/xmlenc#Element">
            <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"
                xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/>
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <xenc:EncryptedKey Id="_f494c7faf84f0cc2cf704adc6ce7b7e4"
                    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
                    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2009/xmlenc11#rsa-oaep"
                        xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/>
                    <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
                        <xenc:CipherValue>someCipherValueElementPoppingUpHere</xenc:CipherValue>
                    </xenc:CipherData>
                </xenc:EncryptedKey>
            </ds:KeyInfo>
            <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
                <xenc:CipherValue>someOtherCipherValueElementPoppingUpHere</xenc:CipherValue>
            </xenc:CipherData>
        </xenc:EncryptedData>
    </saml2:EncryptedAssertion>
</saml2p:Response>
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-02-17 13:26:32

最后,我把这件事办好了(在这一过程中我可能会有所改进)。诀窍是首先使用RSA私钥解密第一个CipherValue,然后使用解密值作为AES密钥来解密后一个片段。我不是AES方面的专家,但在阅读了有关标准之后,我读到可以(据称)通过从AES密钥中提取前16位来确定所谓的IV密钥。由于某些原因,我遇到了一些奇怪的填充问题,我不得不通过简单的字符串替换来纠正这些问题。此外,如果使用其他加密标准,则应该修改实现。这个实现是基于.NET 5的,据我所知,.NET 5特有的特性是X509Certificate2.CreateFromPemFile方法。

代码语言:javascript
复制
namespace SAMLDecrypter
{
    class Program
    {
        static void Main(string[] args)
        {
            var certPath = "cartPath";
            var samlPath = "samlresponse.xml";
            var saml = XElement.Parse(File.ReadAllText(samlPath));
            var cert = X509Certificate2.CreateFromPemFile(certPath);
            var cipherKeys = GetCipherValues(saml);
            var privateKey = cert.GetRSAPrivateKey();
            var aeskey = privateKey.Decrypt(Convert.FromBase64String(cipherKeys[0]), RSAEncryptionPadding.OaepSHA1);
            var assertions = AesDecrypt(Convert.FromBase64String(cipherKeys[1]), aeskey);
            assertions = XElement.Parse(assertions.Substring(assertions.IndexOf("<"))).ToString();

            Console.WriteLine(assertions);
        }

        static string[] GetCipherValues(XElement saml)
        {
            var alg = XName.Get("Algorithm");
            var encryptedData = XPathSelectElements(saml, "./saml2:EncryptedAssertion/xenc:EncryptedData").First();
            var encryptionMethod = XPathSelectElements(encryptedData, "./xenc:EncryptionMethod").First().Attribute(alg).Value;
            var keyInfo = XPathSelectElements(encryptedData, "./ds:KeyInfo").First();
            var encryptionMethodKey = XPathSelectElements(keyInfo, "./xenc:EncryptedKey/xenc:EncryptionMethod").First().Attribute(alg).Value;
            var cipherValueKey = XPathSelectElements(keyInfo, "./xenc:EncryptedKey/xenc:CipherData/xenc:CipherValue").First().Value;
            var cipherValue = XPathSelectElements(encryptedData, "./xenc:CipherData/xenc:CipherValue").First().Value;
            return new[] { cipherValueKey, cipherValue };
        }

        private static Dictionary<string, string> GetDefaultDict()
        {
            return new Dictionary<string, string>
            {
                { "saml2", "urn:oasis:names:tc:SAML:2.0:assertion" },
                { "saml2p", "urn:oasis:names:tc:SAML:2.0:protocol" },
                { "xenc", "http://www.w3.org/2001/04/xmlenc#" },
                { "ds", "http://www.w3.org/2000/09/xmldsig#" }
            };
        }

        private static IEnumerable<XElement> XPathSelectElements(XNode element, string query)
        {
            return XPathSelectElements(element, query, GetDefaultDict());
        }

        private static IEnumerable<XElement> XPathSelectElements(XNode element, string query, Dictionary<string,string> namespaces)
        {
            var namespaceManager = new XmlNamespaceManager(new NameTable());
            namespaces.ToList().ForEach(entry => namespaceManager.AddNamespace(entry.Key, entry.Value));
            return element.XPathSelectElements(query, namespaceManager);
        }

        static string AesDecrypt(byte[] cipherText, byte[] aesKey)
        {
            // Check arguments.
            if (cipherText == null || cipherText.Length <= 0)
                throw new ArgumentNullException("cipherText");
            if (aesKey == null || aesKey.Length < 16)
                throw new ArgumentNullException("Key");

            var aesIV = aesKey.Take(16).ToArray();
            using (var ms = new MemoryStream())
            {
                using (var aes = new AesManaged()) {
                    aes.Key = aesKey;
                    aes.IV = aesIV;
                    aes.Padding = PaddingMode.ISO10126;
                    CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write);
                    cs.Write(cipherText, 0, cipherText.Length);
                    cs.Close();
                    var result = Encoding.UTF8.GetString(ms.ToArray());
                    return result;
                }
            }
        }

    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66225416

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档