private static function Utilities::doDecryptElement in SAML SP 2.0 Single Sign On (SSO) - SAML Service Provider 7
Decrypt an encrypted element.
This is an internal helper function.
Parameters
DOMElement $encryptedData The encrypted data.:
XMLSecurityKey $inputKey The decryption key.:
array &$blacklist Blacklisted decryption algorithms.:
Return value
DOMElement The decrypted element.
Throws
Exception
1 call to Utilities::doDecryptElement()
- Utilities::decryptElement in includes/
Utilities.php - Decrypt an encrypted element.
File
- includes/
Utilities.php, line 1063
Class
- Utilities
- This file is part of miniOrange SAML plugin.
Code
private static function doDecryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey, array &$blacklist) {
$enc = new XMLSecEnc();
$enc
->setNode($encryptedData);
$enc->type = $encryptedData
->getAttribute("Type");
$symmetricKey = $enc
->locateKey($encryptedData);
if (!$symmetricKey) {
echo sprintf('Could not locate key algorithm in encrypted data.');
exit;
}
$symmetricKeyInfo = $enc
->locateKeyInfo($symmetricKey);
if (!$symmetricKeyInfo) {
echo sprintf('Could not locate <dsig:KeyInfo> for the encrypted key.');
exit;
}
$inputKeyAlgo = $inputKey
->getAlgorith();
if ($symmetricKeyInfo->isEncrypted) {
$symKeyInfoAlgo = $symmetricKeyInfo
->getAlgorith();
if (in_array($symKeyInfoAlgo, $blacklist, TRUE)) {
echo sprintf('Algorithm disabled: ' . var_export($symKeyInfoAlgo, TRUE));
exit;
}
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) {
echo sprintf('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));
exit;
}
/** @var XMLSecEnc $encKey */
$encKey = $symmetricKeyInfo->encryptedCtx;
$symmetricKeyInfo->key = $inputKey->key;
$keySize = $symmetricKey
->getSymmetricKeySize();
if ($keySize === NULL) {
/* To protect against "key oracle" attacks, we need to be able to create a
* symmetric key, and for that we need to know the key size.
*/
echo sprintf('Unknown key size for encryption algorithm: ' . var_export($symmetricKey->type, TRUE));
exit;
}
try {
$key = $encKey
->decryptKey($symmetricKeyInfo);
if (strlen($key) != $keySize) {
echo sprintf('Unexpected key size (' . strlen($key) * 8 . 'bits) for encryption algorithm: ' . var_export($symmetricKey->type, TRUE));
exit;
}
} catch (Exception $e) {
/* We failed to decrypt this key. Log it, and substitute a "random" key. */
/* Create a replacement key, so that it looks like we fail in the same way as if the key was correctly padded. */
/* We base the symmetric key on the encrypted key and private key, so that we always behave the
* same way for a given input key.
*/
$encryptedKey = $encKey
->getCipherValue();
$pkey = openssl_pkey_get_details($symmetricKeyInfo->key);
$pkey = sha1(serialize($pkey), TRUE);
$key = sha1($encryptedKey . $pkey, TRUE);
/* Make sure that the key has the correct length. */
if (strlen($key) > $keySize) {
$key = substr($key, 0, $keySize);
}
elseif (strlen($key) < $keySize) {
$key = str_pad($key, $keySize);
}
}
$symmetricKey
->loadkey($key);
}
else {
$symKeyAlgo = $symmetricKey
->getAlgorith();
/* Make sure that the input key has the correct format. */
if ($inputKeyAlgo !== $symKeyAlgo) {
echo sprintf('Algorithm mismatch between input key and key in message. ' . 'Key was: ' . var_export($inputKeyAlgo, TRUE) . '; message was: ' . var_export($symKeyAlgo, TRUE));
exit;
}
$symmetricKey = $inputKey;
}
$algorithm = $symmetricKey
->getAlgorith();
if (in_array($algorithm, $blacklist, TRUE)) {
echo sprintf('Algorithm disabled: ' . var_export($algorithm, TRUE));
exit;
}
/** @var string $decrypted */
$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) {
echo sprintf('Missing encrypted element.');
throw new Exception('Missing encrypted element.');
}
if (!$decryptedElement instanceof DOMElement) {
echo sprintf('Decrypted element was not actually a DOMElement.');
}
return $decryptedElement;
}