25    private static function _aesDecrypt($ciphertext, $secret)
 
   27        if (!is_string($ciphertext)) {
 
   28            throw new \InvalidArgumentException(
 
   29                'Input parameter "$ciphertext" must be a string with more than 48 characters.' 
   33        $len = mb_strlen($ciphertext, 
'8bit');
 
   35            throw new \InvalidArgumentException(
 
   36                'Input parameter "$ciphertext" must be a string with more than 48 characters.' 
   39        if (!function_exists(
"openssl_decrypt")) {
 
   40            throw new \SimpleSAML_Error_Exception(
"The openssl PHP module is not loaded.");
 
   44        $key  = openssl_digest($secret, 
'sha512');
 
   46        $hmac = mb_substr($ciphertext, 0, 32, 
'8bit');
 
   47        $iv   = mb_substr($ciphertext, 32, 16, 
'8bit');
 
   48        $msg  = mb_substr($ciphertext, 48, $len - 48, 
'8bit');
 
   51        if (self::secureCompare(hash_hmac(
'sha256', $iv.$msg, substr(
$key, 64, 64), 
true), $hmac)) {
 
   52            $plaintext = openssl_decrypt(
 
   56                defined(
'OPENSSL_RAW_DATA') ? OPENSSL_RAW_DATA : 1,
 
   60            if ($plaintext !== 
false) {
 
   65        throw new \SimpleSAML_Error_Exception(
"Failed to decrypt ciphertext.");
 
   99    private static function _aesEncrypt(
$data, $secret)
 
  101        if (!is_string(
$data)) {
 
  102            throw new \InvalidArgumentException(
'Input parameter "$data" must be a string.');
 
  105        if (!function_exists(
"openssl_encrypt")) {
 
  106            throw new \SimpleSAML_Error_Exception(
'The openssl PHP module is not loaded.');
 
  110        $key = openssl_digest($secret, 
'sha512');
 
  113        $iv = openssl_random_pseudo_bytes(16);
 
  117        $ciphertext = openssl_encrypt(
 
  121            defined(
'OPENSSL_RAW_DATA') ? OPENSSL_RAW_DATA : 1,
 
  125        if ($ciphertext === 
false) {
 
  126            throw new \SimpleSAML_Error_Exception(
"Failed to encrypt plaintext.");
 
  130        return hash_hmac(
'sha256', $iv.$ciphertext, substr(
$key, 64, 64), 
true).$iv.$ciphertext;
 
  162        return "-----BEGIN ".$type.
"-----\n".
 
  163               chunk_split(base64_encode($der), 64, 
"\n").
 
  164               "-----END ".$type.
"-----\n";
 
  197        if (!is_bool($required) || !is_string($prefix) || !is_bool($full_path)) {
 
  198            throw new \InvalidArgumentException(
'Invalid input parameters.');
 
  201        $file = 
$metadata->getString($prefix.
'privatekey', 
null);
 
  202        if ($file === 
null) {
 
  205                throw new \SimpleSAML_Error_Exception(
'No private key found in metadata.');
 
  215        $data = @file_get_contents($file);
 
  216        if (
$data === 
false) {
 
  217            throw new \SimpleSAML_Error_Exception(
'Unable to load private key from file "'.$file.
'"');
 
  224        if (
$metadata->hasValue($prefix.
'privatekey_pass')) {
 
  225            $ret[
'password'] = 
$metadata->getString($prefix.
'privatekey_pass');
 
  267        if (!is_bool($required) || !is_string($prefix)) {
 
  268            throw new \InvalidArgumentException(
'Invalid input parameters.');
 
  274                if (
$key[
'type'] !== 
'X509Certificate') {
 
  277                if (
$key[
'signing'] !== 
true) {
 
  280                $certData = 
$key[
'X509Certificate'];
 
  281                $pem = 
"-----BEGIN CERTIFICATE-----\n".
 
  282                    chunk_split($certData, 64).
 
  283                    "-----END CERTIFICATE-----\n";
 
  284                $certFingerprint = strtolower(sha1(base64_decode($certData)));
 
  287                    'certData'        => $certData,
 
  289                    'certFingerprint' => array($certFingerprint),
 
  293        } elseif (
$metadata->hasValue($prefix.
'certFingerprint')) {
 
  295            $fps = 
$metadata->getArrayizeString($prefix.
'certFingerprint');
 
  298            foreach ($fps as &$fp) {
 
  299                assert(is_string($fp));
 
  300                $fp = strtolower(str_replace(
':', 
'', $fp));
 
  307            return array(
'certFingerprint' => $fps);
 
  312            throw new \SimpleSAML_Error_Exception(
'No public key / certificate found in metadata.');
 
  330        $begin = 
"-----BEGIN ";
 
  332        $lines = explode(
"\n", $pem);
 
  333        $last  = count($lines) - 1;
 
  335        if (strpos($lines[0], $begin) !== 0) {
 
  336            throw new \InvalidArgumentException(
"pem2der: input is not encoded in PEM format.");
 
  339        if (strpos($lines[$last], 
$end) !== 0) {
 
  340            throw new \InvalidArgumentException(
"pem2der: input is not encoded in PEM format.");
 
  342        unset($lines[$last]);
 
  344        return base64_decode(implode($lines));
 
  367        if (!is_string($algorithm) || !is_string(
$password)) {
 
  368            throw new \InvalidArgumentException(
'Invalid input parameters.');
 
  372        if (in_array(strtolower($algorithm), hash_algos(), 
true)) {
 
  373            $alg_str = 
'{'.str_replace(
'SHA1', 
'SHA', $algorithm).
'}'; 
 
  375            return $alg_str.base64_encode($hash);
 
  379        if ($salt === 
null) { 
 
  381            $bytes = ($algorithm == 
'SSHA1') ? 4 : 8;
 
  382            $salt = openssl_random_pseudo_bytes($bytes);
 
  385        if ($algorithm[0] == 
'S' && in_array(substr(strtolower($algorithm), 1), hash_algos(), 
true)) {
 
  386            $alg = substr(strtolower($algorithm), 1); 
 
  387            $alg_str = 
'{'.str_replace(
'SSHA1', 
'SSHA', $algorithm).
'}'; 
 
  389            return $alg_str.base64_encode($hash.$salt);
 
  392        throw new \SimpleSAML_Error_Exception(
'Hashing algorithm \''.strtolower($algorithm).
'\' is not supported
'); 
  407    public static function secureCompare($known, $user) 
  409        if (function_exists('hash_equals
')) { 
  410            // use hash_equals() if available (PHP >= 5.6) 
  411            return hash_equals($known, $user); 
  414        // compare manually in constant time 
  415        $len = mb_strlen($known, '8bit
'); // see mbstring.func_overload 
  416        if ($len !== mb_strlen($user, '8bit
')) { 
  417            return false; // length differs 
  420        for ($i = 0; $i < $len; $i++) { 
  421            $diff |= ord($known[$i]) ^ ord($user[$i]); 
  423        // if all the bytes in $a and $b are identical, $diff should be equal to 0 
  440    public static function pwValid($hash, $password) 
  442        if (!is_string($hash) || !is_string($password)) { 
  443            throw new \InvalidArgumentException('Invalid 
input parameters.
'); 
  446        // match algorithm string (e.g. '{SSHA256}
', '{MD5}
') 
  447        if (preg_match('/^{(.*?)}(.*)$/
', $hash, $matches)) { 
  448            // LDAP compatibility 
  449            $alg = preg_replace('/^(S?SHA)$/
', '${1}1
', $matches[1]); 
  452            if (in_array(strtolower($alg), hash_algos(), true)) { 
  453                return self::secureCompare($hash, self::pwHash($password, $alg)); 
  457            if ($alg[0] === 'S
' && in_array(substr(strtolower($alg), 1), hash_algos(), true)) { 
  458                $php_alg = substr(strtolower($alg), 1); 
  460                // get hash length of this algorithm to learn how long the salt is 
  461                $hash_length = strlen(hash($php_alg, '', true)); 
  462                $salt = substr(base64_decode($matches[2]), $hash_length); 
  463                return self::secureCompare($hash, self::pwHash($password, $alg, $salt)); 
  466            return $hash === $password; 
  469        throw new \SimpleSAML_Error_Exception('Hashing algorithm \
''.strtolower($alg).
'\' is not supported
'); 
$metadata['__DYNAMIC:1__']
An exception for terminatinating execution or to throw for unit testing.
static getSecretSalt()
Retrieve the secret salt.
static getCertPath($path)
Resolves a path that may be relative to the cert-directory.
static pwHash($password, $algorithm, $salt=null)
This function hashes a password with a given algorithm.
static loadPublicKey(\SimpleSAML_Configuration $metadata, $required=false, $prefix='')
Get public key or certificate from metadata.
static der2pem($der, $type='CERTIFICATE')
Convert data from DER to PEM encoding.
static aesEncrypt($data)
Encrypt data using AES-256-CBC and the system-wide secret salt as key.
static loadPrivateKey(\SimpleSAML_Configuration $metadata, $required=false, $prefix='', $full_path=false)
Load a private key from metadata.
static aesDecrypt($ciphertext)
Decrypt data using AES-256-CBC and the system-wide secret salt as key.
static pem2der($pem)
Convert from PEM to DER encoding.
hash(StreamInterface $stream, $algo, $rawOutput=false)
Calculate a hash of a Stream.