diff --git a/lib/SAML2/Utils.php b/lib/SAML2/Utils.php
index fe83f12ab607ef60b74a5e4994cae50f704edc9c..156ab941eb82f2c1dd15215ee2bd890500a6d644 100644
--- a/lib/SAML2/Utils.php
+++ b/lib/SAML2/Utils.php
@@ -239,6 +239,89 @@ class SAML2_Utils {
$objXMLSecDSig->insertSignature($root, $insertBefore);
}
+
+
+ /**
+ * Decrypt an encrypted element.
+ *
+ * @param DOMElement $encryptedData The encrypted data.
+ * @param XMLSecurityKey $inputKey The decryption key.
+ * @return DOMElement The decrypted element.
+ */
+ public static function decryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey) {
+
+ $enc = new XMLSecEnc();
+
+ $enc->setNode($encryptedData);
+ $enc->type = $encryptedData->getAttribute("Type");
+
+ $symmetricKey = $enc->locateKey($encryptedData);
+ if (!$symmetricKey) {
+ throw new Exception('Could not locate key algorithm in encrypted data.');
+ }
+
+ $symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey);
+ if (!$symmetricKeyInfo) {
+ throw new Exception('Could not locate <dsig:KeyInfo> for the encrypted key.');
+ }
+
+ $inputKeyAlgo = $inputKey->getAlgorith();
+ if ($symmetricKeyInfo->isEncrypted) {
+ $symKeyInfoAlgo = $symmetricKeyInfo->getAlgorith();
+
+ if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) {
+ /*
+ * The RSA key formats are equal, so loading an RSA_1_5 key
+ * into an RSA_OAEP_MGF1P key can be done without problems.
+ * We therefore pretend that the input key is an
+ * RSA_OAEP_MGF1P key.
+ */
+ $inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P;
+ }
+
+ /* Make sure that the input key format is the same as the one used to encrypt the key. */
+ if ($inputKeyAlgo !== $symKeyInfoAlgo) {
+ throw new Exception('Algorithm mismatch between input key and key used to encrypt ' .
+ ' the symmetric key for the message. Key was: ' .
+ var_export($inputKeyAlgo, TRUE) . '; message was: ' .
+ var_export($symKeyInfoAlgo, TRUE));
+ }
+
+ $encKey = $symmetricKeyInfo->encryptedCtx;
+ $symmetricKeyInfo->key = $inputKey->key;
+ $key = $encKey->decryptKey($symmetricKeyInfo);
+ $symmetricKey->loadkey($key);
+ } else {
+ $symKeyAlgo = $symmetricKey->getAlgorith();
+ /* Make sure that the input key has the correct format. */
+ if ($inputKeyAlgo !== $symKeyAlgo) {
+ throw new Exception('Algorithm mismatch between input key and key in message. ' .
+ 'Key was: ' . var_export($inputKeyAlgo, TRUE) . '; message was: ' .
+ var_export($symKeyAlgo, TRUE));
+ }
+ $symmetricKey = $inputKey;
+ }
+
+ $decrypted = $enc->decryptNode($symmetricKey, FALSE);
+
+ /*
+ * This is a workaround for the case where only a subset of the XML
+ * tree was serialized for encryption. In that case, we may miss the
+ * namespaces needed to parse the XML.
+ */
+ $xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'.$decrypted.'</root>';
+ $newDoc = new DOMDocument();
+ if (!$newDoc->loadXML($xml)) {
+ throw new Exception('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?');
+ }
+ $decryptedElement = $newDoc->firstChild->firstChild;
+ if ($decryptedElement === NULL) {
+ throw new Exception('Missing encrypted element.');
+ }
+
+ return $decryptedElement;
+ }
+
}
?>
\ No newline at end of file