Sample code for 30+ languages & platforms
Xbase++ Requires Chilkat v11.0.0+

Decrypt a SAML Response

See more Encryption Examples

Demonstrates how to decrypt a SAML response.

Chilkat Xbase++ Downloads

Xbase++
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()