function test_cryptrand() { // It's possible, but HIGHLY unlikely that a correct // implementation will fail by returning the same number twice $s = Auth_OpenID_CryptUtil::getBytes(32); $t = Auth_OpenID_CryptUtil::getBytes(32); $this->assertEquals(Auth_OpenID::bytes($s), 32); $this->assertEquals(Auth_OpenID::bytes($t), 32); $this->assertFalse($s == $t); }
function xorSecret($composite, $secret, $hash_func) { $dh_shared = $this->getSharedSecret($composite); $dh_shared_str = $this->lib->longToBinary($dh_shared); $hash_dh_shared = $hash_func($dh_shared_str); $xsecret = ""; for ($i = 0; $i < Auth_OpenID::bytes($secret); $i++) { $xsecret .= chr(ord($secret[$i]) ^ ord($hash_dh_shared[$i])); } return $xsecret; }
/** * Compute an HMAC/SHA1 hash. * * @access private * @param string $key The HMAC key * @param string $text The message text to hash * @return string $mac The MAC */ function Auth_OpenID_HMACSHA1($key, $text) { if (Auth_OpenID::bytes($key) > Auth_OpenID_SHA1_BLOCKSIZE) { $key = Auth_OpenID_SHA1($key, true); } $key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x0)); $ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE); $opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE); $hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text, true); $hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1, true); return $hmac; }
/** * Compute an HMAC/SHA1 hash. * * @access private * @param string $key The HMAC key * @param string $text The message text to hash * @return string $mac The MAC */ function Auth_OpenID_HMACSHA1($key, $text) { if (Auth_OpenID::bytes($key) > Auth_OpenID_SHA1_BLOCKSIZE) { $key = Auth_OpenID_SHA1($key, true); } if (function_exists('hash_hmac') && function_exists('hash_algos') && in_array('sha1', hash_algos())) { return hash_hmac('sha1', $text, $key, true); } // Home-made solution $key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x0)); $ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE); $opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE); $hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text, true); $hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1, true); return $hmac; }
/** * "Octifies" a binary string by returning a string with escaped * octal bytes. This is used for preparing binary data for * PostgreSQL BYTEA fields. * * @access private */ function _octify($str) { $result = ""; for ($i = 0; $i < Auth_OpenID::bytes($str); $i++) { $ch = substr($str, $i, 1); if ($ch == "\\") { $result .= "\\\\\\\\"; } else { if (ord($ch) == 0) { $result .= "\\\\000"; } else { $result .= "\\" . strval(decoct(ord($ch))); } } } return $result; }
/** * Returns a random number in the specified range. This function * accepts $start, $stop, and $step values of arbitrary magnitude * and will utilize the local large-number math library when * available. * * @param integer $start The start of the range, or the minimum * random number to return * @param integer $stop The end of the range, or the maximum * random number to return * @param integer $step The step size, such that $result - ($step * * N) = $start for some N * @return integer $result The resulting randomly-generated number */ function rand($stop) { static $duplicate_cache = array(); // Used as the key for the duplicate cache $rbytes = $this->longToBinary($stop); if (array_key_exists($rbytes, $duplicate_cache)) { list($duplicate, $nbytes) = $duplicate_cache[$rbytes]; } else { if ($rbytes[0] == "") { $nbytes = Auth_OpenID::bytes($rbytes) - 1; } else { $nbytes = Auth_OpenID::bytes($rbytes); } $mxrand = $this->pow(256, $nbytes); // If we get a number less than this, then it is in the // duplicated range. $duplicate = $this->mod($mxrand, $stop); if (count($duplicate_cache) > 10) { $duplicate_cache = array(); } $duplicate_cache[$rbytes] = array($duplicate, $nbytes); } do { $bytes = "" . Auth_OpenID_CryptUtil::getBytes($nbytes); $n = $this->binaryToLong($bytes); // Keep looping if this value is in the low duplicated range } while ($this->cmp($n, $duplicate) < 0); return $this->mod($n, $stop); }
function detect_random($r, &$out) { $out .= $r->h2('Cryptographic-quality randomness source'); if (Auth_OpenID_RAND_SOURCE === null) { $out .= $r->p('Using (insecure) pseudorandom number source, because ' . 'Auth_OpenID_RAND_SOURCE has been defined as null.'); return false; } $msg = 'The library will try to access ' . Auth_OpenID_RAND_SOURCE . ' as a source of random data. '; $numbytes = 6; $f = @fopen(Auth_OpenID_RAND_SOURCE, 'r'); if ($f !== false) { $data = fread($f, $numbytes); $stat = fstat($f); $size = $stat['size']; fclose($f); } else { $data = null; $size = true; } if ($f !== false) { $dataok = Auth_OpenID::bytes($data) == $numbytes; $ok = $dataok && !$size; $msg .= 'It seems to exist '; if ($dataok) { $msg .= 'and be readable. Here is some hex data: ' . bin2hex($data) . '.'; } else { $msg .= 'but reading data failed.'; } if ($size) { $msg .= ' This is a ' . $size . ' byte file. Unless you know ' . 'what you are doing, it is likely that you are making a ' . 'mistake by using a regular file as a randomness source.'; } } else { $msg .= Auth_OpenID_RAND_SOURCE . ' could not be opened. This could be because of restrictions on' . ' your PHP environment or that randomness source may not exist' . ' on this platform.'; if (IS_WINDOWS) { $msg .= ' You seem to be running Windows. This library does not' . ' have access to a good source of randomness on Windows.'; } $ok = false; } $out .= $r->p($msg); if (!$ok) { $out .= $r->p('To set a source of randomness, define Auth_OpenID_RAND_SOURCE ' . 'to the path to the randomness source. If your platform does ' . 'not provide a secure randomness source, the library can' . 'operate in pseudorandom mode, but it is then vulnerable to ' . 'theoretical attacks. If you wish to operate in pseudorandom ' . 'mode, define Auth_OpenID_RAND_SOURCE to null.'); $out .= $r->p('You are running on:'); $out .= $r->pre(php_uname()); $out .= $r->p('There does not seem to be an available source ' . 'of randomness. On a Unix-like platform ' . '(including MacOS X), try /dev/random and ' . '/dev/urandom.'); } return $ok; }
function _readTestCases($test_file_name, $digest_len) { $lines = Tests_Auth_OpenID_readlines($test_file_name); $cases = array(); $case = array(); foreach ($lines as $line) { if ($line[0] == "#") { continue; } // Blank line separates test cases if ($line == "\n") { $cases[] = $case; $case = array(); } else { $match = array(); $pat = '/^([a-z0-9_-]+) =\\s+(.*?)\\n$/'; if (!preg_match($pat, $line, $match)) { trigger_error("Bad test input: {$line}", E_USER_ERROR); } $c = count($match); if ($c != 3) { trigger_error("Wrong number of elements in parsed case: {$c}", E_USER_ERROR); return false; } $key = $match[1]; $value = $match[2]; $case[$key] = $value; } } if (count($case)) { $cases[] = $case; } $final = array(); // Normalize strings and check data integrity foreach ($cases as $case) { $clean = array(); $clean["key"] = Tests_Auth_OpenID_HMAC::_strConvert($case["key"]); if (defined(@$case["key_len"])) { if (Auth_OpenID::bytes($clean["key"]) != $case["key_len"]) { trigger_error("Bad key length", E_USER_ERROR); } } $clean["data"] = Tests_Auth_OpenID_HMAC::_strConvert($case["data"]); if (defined(@$case["data_len"])) { if (Auth_OpenID::bytes($clean["data"]) != $case["data_len"]) { trigger_error("Bad data length", E_USER_ERROR); } } $clean["digest"] = Tests_Auth_OpenID_HMAC::_strConvert($case["digest"]); if (Auth_OpenID::bytes($clean["digest"]) != $digest_len) { $l = Auth_OpenID::bytes($clean["digest"]); trigger_error("Bad digest length: {$l}", E_USER_ERROR); } $clean['test_case'] = $case['test_case']; $final[] = $clean; } return $final; }