Xbase++ Requires Chilkat v11.0.0+
Xbase++
Decrypt a SAML Response
See more Encryption Examples
Demonstrates how to decrypt a SAML response.Chilkat Xbase++ Downloads
LOCAL nSuccess
LOCAL oHttp
LOCAL oSbSamlResponse
LOCAL oSbPrivateKeyPem
LOCAL oXml
LOCAL oPrivkey
LOCAL oRsa
LOCAL cEncryptedAesKey
LOCAL oBdAesKey
LOCAL oSbRsaAlg
LOCAL cEncrypted64
LOCAL oBdEncrypted
LOCAL oCrypt
LOCAL oSbAlg
LOCAL cDecryptedXml
LOCAL oXmlAssertion
LOCAL oXmlEncryptedAssertion
nSuccess := 0
// This example requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
// This example decrypts this SAML response:
// <?xml version="1.0" encoding="UTF-8" ?>
// <saml2p:Response Destination="https://deskflow-asp2.com/ubc/ubcdfe.dll/cwlacs" ID="_e4585eaeedbcaf7c24dff7f1ee2499f5" IssueInstant="2018-10-11T17:46:20.727Z" Version="2.0" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
// <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://authentication.stg.id.ubc.ca</saml2:Issuer>
// <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
// <ds:SignedInfo>
// <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
// <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
// <ds:Reference URI="#_e4585eaeedbcaf7c24dff7f1ee2499f5">
// <ds:Transforms>
// <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
// <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
// </ds:Transforms>
// <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
// <ds:DigestValue>1ui22tqFyYEOoWI19CMwz4n+ynxNjLDGdTeRMdi60EU=</ds:DigestValue>
// </ds:Reference>
// </ds:SignedInfo>
// <ds:SignatureValue>ROg7FXV6vsp8socVhdo76/i7cRHGGKIveAiScKdujZT0QrHVqIvvbZ/RnwvEMJ9H9i/kJFAQA171
// Eo2kDjSdvNFQ/YcKaJUwMtAwT05yVatGV42RZKEf7ME+vpcCTR1LWZdrhat1FWCg1MNQwNWB0EL5
// fEP2a4jAcSTB8tFbjTAHsv7IWC39E5RVv99mACYXLa7iGZLtORANZxgYu5qQgmH6pUkI6Z1cpmf+
// m9mIjKM6LF0EvLfWOBWL6udZ+GsHPOLjVTJg+1S0xb9FQCYDVW1QhbjSS0icKHKTNNbrsaxllVDY
// m4q27YQjRh+XxugPgvsZ61Pxlto8Jbg+6jUlMQ==</ds:SignatureValue>
// <ds:KeyInfo>
// <ds:X509Data>
// <ds:X509Certificate>MIIDTTCCAjWgAwIBAgIVAJccYyIV6wly8XyddumpgnHMJ2JLMA0GCSqGSIb3DQEBCwUAMCcxJTAj
// BgNVBAMMHGF1dGhlbnRpY2F0aW9uLnN0Zy5pZC51YmMuY2EwHhcNMTcwMzAxMTk1NDM0WhcNMzcw
// ...
// xUuh6HuHKIwQqHBz7udxbH3Zbb6jXGDJjiDHt1LRJ8xbVisFIcDlIwsGQQi0HeEJfx4P</ds:X509Certificate>
// </ds:X509Data>
// </ds:KeyInfo>
// </ds:Signature>
// <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 Id="_314d80b9cf02d8eda8d686a6ffd626cf" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
// <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="_d7b6da6fb59a627ebb4a96928441ab79" Recipient="https://ubcdfe.deskflow-asp2.com" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
// <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
// <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"/>
// </xenc:EncryptionMethod>
// <ds:KeyInfo>
// <ds:X509Data>
// <ds:X509Certificate>MIICuzCCAiQCCQD3bpigRnKMSzANBgkqhkiG9w0BAQsFADCBoTELMAkGA1UEBhMCQ0ExEDAOBgNV
// BAgMB09udGFyaW8xEDAOBgNVBAcMB1Rvcm9udG8xJjAkBgNVBAoMHVRhY3RpY2FsIEJ1c2luZXNz
// ...
// kVRcHd1UK3q7G8FoykWjdQz/0EoMTfEZ+Md56mLOe48eMUZV2ONZuL1kDCEKw1UwkaDQI4Pf8pzx
// 82b9rgw9wBDtvu5eFPlUGEGIBw==</ds:X509Certificate>
// </ds:X509Data>
// </ds:KeyInfo>
// <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
// <xenc:CipherValue>BNHfUOpgdPE5BgpN2VIZIDthMAv1rxk91qVnWyCZOG9bmUKChJtTUqMpndot7VJwYuyKFshkAdnT
// D79KGdlSA1xHKcVeZXXzDWglqSyYjzhDCsyOhPaI4HelMFgCLwyFz89uEpUpqlvfl8ol3Am/XnzQ
// Vp7V7oS76hocjUI51Qs=</xenc:CipherValue>
// </xenc:CipherData>
// </xenc:EncryptedKey>
// </ds:KeyInfo>
// <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
// <xenc:CipherValue>R6l7tmbnXrOfBgB8lA3KnwLYsLH5ZO5omQ7Hp5K05atzw2o55xmCXVMYhNneFxMtxUh6raEyHeZX
// PTZNgWrvdqc4GYND/R7MhRrJzk9OAq1WyoOXwbtRpwNDwWA4N2IuprPQJbvjVxaw/PesZMZwZqlp
// ...
// zm9zAxahyu8Ooe8M4r3HN2cY0JxxxkZtDiulbnyA+rRtXfBRJtangvFQ4iFAnzM/Yg9hMyW9jcu0
// S7FzuRB9ONMxi+nh0IFWgqp+</xenc:CipherValue>
// </xenc:CipherData>
// </xenc:EncryptedData>
// </saml2:EncryptedAssertion>
// </saml2p:Response>
// The sample encrypted SAML response and RSA private key are available online:
oHttp := CreateObject("Chilkat.Http")
oSbSamlResponse := CreateObject("Chilkat.StringBuilder")
oSbPrivateKeyPem := CreateObject("Chilkat.StringBuilder")
nSuccess := oHttp:QuickGetSb("https://chilkatdownload.com/data/samlresponse.xml", oSbSamlResponse)
IF (nSuccess == 1)
nSuccess := oHttp:QuickGetSb("https://chilkatdownload.com/data/samlresponse_privkey.pem", oSbPrivateKeyPem)
ENDIF
IF (nSuccess == 0)
? oHttp:LastErrorText
oHttp:destroy()
oSbSamlResponse:destroy()
oSbPrivateKeyPem:destroy()
RETURN
ENDIF
oXml := CreateObject("Chilkat.Xml")
oXml:LoadSb(oSbSamlResponse, 1)
// Load the RSA private key..
oPrivkey := CreateObject("Chilkat.PrivateKey")
nSuccess := oPrivkey:LoadPem(oSbPrivateKeyPem:GetAsString())
IF (nSuccess == 0)
? oPrivkey:LastErrorText
oHttp:destroy()
oSbSamlResponse:destroy()
oSbPrivateKeyPem:destroy()
oXml:destroy()
oPrivkey:destroy()
RETURN
ENDIF
// Prepare an RSA object w/ the private key...
oRsa := CreateObject("Chilkat.Rsa")
nSuccess := oRsa:UsePrivateKey(oPrivkey)
IF (nSuccess == 0)
? oRsa:LastErrorText
oHttp:destroy()
oSbSamlResponse:destroy()
oSbPrivateKeyPem:destroy()
oXml:destroy()
oPrivkey:destroy()
oRsa:destroy()
RETURN
ENDIF
// RSA will be used to decrypt the xenc:EncryptedKey
// The bytes to be decrypted are in xenc:CipherValue (in base64 format)
cEncryptedAesKey := oXml:GetChildContent("saml2:EncryptedAssertion|xenc:EncryptedData|ds:KeyInfo|xenc:EncryptedKey|xenc:CipherData|xenc:CipherValue")
IF (oXml:LastMethodSuccess != 1)
? "Encrypted AES key not found."
oHttp:destroy()
oSbSamlResponse:destroy()
oSbPrivateKeyPem:destroy()
oXml:destroy()
oPrivkey:destroy()
oRsa:destroy()
RETURN
ENDIF
? "Encrypted AES key (base64) = " + cEncryptedAesKey
oBdAesKey := CreateObject("Chilkat.BinData")
oBdAesKey:AppendEncoded(cEncryptedAesKey, "base64")
oSbRsaAlg := CreateObject("Chilkat.StringBuilder")
oSbRsaAlg:Append(oXml:ChilkatPath("saml2:EncryptedAssertion|xenc:EncryptedData|ds:KeyInfo|xenc:EncryptedKey|xenc:EncryptionMethod|(Algorithm)"))
? "sbRsaAlg contains: " + oSbRsaAlg:GetAsString()
IF (oSbRsaAlg:Contains("rsa-oaep", 1) == 1)
oRsa:PkcsPadding := 0
ENDIF
nSuccess := oRsa:DecryptBd(oBdAesKey, 1)
IF (nSuccess == 0)
? oRsa:LastErrorText
oHttp:destroy()
oSbSamlResponse:destroy()
oSbPrivateKeyPem:destroy()
oXml:destroy()
oPrivkey:destroy()
oRsa:destroy()
oBdAesKey:destroy()
oSbRsaAlg:destroy()
RETURN
ENDIF
? "Decrypted AES key (hex) = " + oBdAesKey:GetEncoded("hex")
// Get the encrypted XML (in base64) to be decrypted w/ the AES key.
cEncrypted64 := oXml:GetChildContent("saml2:EncryptedAssertion|xenc:EncryptedData|xenc:CipherData|xenc:CipherValue")
IF (oXml:LastMethodSuccess != 1)
? "Encrypted data not found."
oHttp:destroy()
oSbSamlResponse:destroy()
oSbPrivateKeyPem:destroy()
oXml:destroy()
oPrivkey:destroy()
oRsa:destroy()
oBdAesKey:destroy()
oSbRsaAlg:destroy()
RETURN
ENDIF
oBdEncrypted := CreateObject("Chilkat.BinData")
oBdEncrypted:AppendEncoded(cEncrypted64, "base64")
// Get the symmetric algorithm: "http://www.w3.org/2001/04/xmlenc#aes128-cbc"
// and set the symmetric decrypt properties.
oCrypt := CreateObject("Chilkat.Crypt2")
oSbAlg := CreateObject("Chilkat.StringBuilder")
oSbAlg:Append(oXml:ChilkatPath("saml2:EncryptedAssertion|xenc:EncryptedData|xenc:EncryptionMethod|(Algorithm)"))
IF (oSbAlg:Contains("aes128-cbc", 1) == 1)
oCrypt:CryptAlgorithm := "aes"
oCrypt:KeyLength := 128
oCrypt:CipherMode := "cbc"
// The 1st 16 bytes of the encrypted data are the AES IV.
oCrypt:SetEncodedIV(oBdEncrypted:GetEncodedChunk(0, 16, "hex"), "hex")
oBdEncrypted:RemoveChunk(0, 16)
ENDIF
// Other algorithms, key lengths, etc, can be supported by checking for different Algorithm attribute values..
oCrypt:SetEncodedKey(oBdAesKey:GetEncoded("hex"), "hex")
// AES decrypt...
nSuccess := oCrypt:DecryptBd(oBdEncrypted)
IF (nSuccess == 0)
? oCrypt:LastErrorText
oHttp:destroy()
oSbSamlResponse:destroy()
oSbPrivateKeyPem:destroy()
oXml:destroy()
oPrivkey:destroy()
oRsa:destroy()
oBdAesKey:destroy()
oSbRsaAlg:destroy()
oBdEncrypted:destroy()
oCrypt:destroy()
oSbAlg:destroy()
RETURN
ENDIF
// Get the decrypted XML
cDecryptedXml := oBdEncrypted:GetString("utf-8")
? "Decrypted XML:"
? cDecryptedXml
// The decrypted XML looks like this:
// <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_226e565c548db7986d165d7d969b48b4" IssueInstant="2018-10-11T17:46:20.727Z" Version="2.0">
// ...
// ...
// ...
// </saml2:Assertion>
oXmlAssertion := CreateObject("Chilkat.Xml")
oXmlAssertion:LoadXml(cDecryptedXml)
// Replace the saml2:EncryptedAssertion XML subtree with the saml2:Assertion XML.
oXmlEncryptedAssertion := oXml:FindChild("saml2:EncryptedAssertion")
oXmlEncryptedAssertion:SwapTree(oXmlAssertion)
oXmlEncryptedAssertion:destroy()
// The decrypted XML assertion has now replaced the encrypted XML assertion.
// Examine the fully decrypted XML document:
? "Full XML SAML document with decrypted assertion:"
? oXml:GetXml()
oHttp:destroy()
oSbSamlResponse:destroy()
oSbPrivateKeyPem:destroy()
oXml:destroy()
oPrivkey:destroy()
oRsa:destroy()
oBdAesKey:destroy()
oSbRsaAlg:destroy()
oBdEncrypted:destroy()
oCrypt:destroy()
oSbAlg:destroy()
oXmlAssertion:destroy()