--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/Zend/OpenId.php Mon Dec 13 18:29:26 2010 +0100
@@ -0,0 +1,753 @@
+<?php
+
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_OpenId
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @version $Id: OpenId.php 22653 2010-07-22 18:41:39Z mabe $
+ */
+
+/**
+ * @see Zend_Controller_Response_Abstract
+ */
+require_once "Zend/Controller/Response/Abstract.php";
+
+/**
+ * Static class that contains common utility functions for
+ * {@link Zend_OpenId_Consumer} and {@link Zend_OpenId_Provider}.
+ *
+ * This class implements common utility functions that are used by both
+ * Consumer and Provider. They include functions for Diffie-Hellman keys
+ * generation and exchange, URL normalization, HTTP redirection and some others.
+ *
+ * @category Zend
+ * @package Zend_OpenId
+ * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_OpenId
+{
+ /**
+ * Default Diffie-Hellman key generator (1024 bit)
+ */
+ const DH_P = 'dcf93a0b883972ec0e19989ac5a2ce310e1d37717e8d9571bb7623731866e61ef75a2e27898b057f9891c2e27a639c3f29b60814581cd3b2ca3986d2683705577d45c2e7e52dc81c7a171876e5cea74b1448bfdfaf18828efd2519f14e45e3826634af1949e5b535cc829a483b8a76223e5d490a257f05bdff16f2fb22c583ab';
+
+ /**
+ * Default Diffie-Hellman prime number (should be 2 or 5)
+ */
+ const DH_G = '02';
+
+ /**
+ * OpenID 2.0 namespace. All OpenID 2.0 messages MUST contain variable
+ * openid.ns with its value.
+ */
+ const NS_2_0 = 'http://specs.openid.net/auth/2.0';
+
+ /**
+ * Allows enable/disable stoping execution of PHP script after redirect()
+ */
+ static public $exitOnRedirect = true;
+
+ /**
+ * Alternative request URL that can be used to override the default
+ * selfUrl() response
+ */
+ static public $selfUrl = null;
+
+ /**
+ * Sets alternative request URL that can be used to override the default
+ * selfUrl() response
+ *
+ * @param string $selfUrl the URL to be set
+ * @return string the old value of overriding URL
+ */
+ static public function setSelfUrl($selfUrl = null)
+ {
+ $ret = self::$selfUrl;
+ self::$selfUrl = $selfUrl;
+ return $ret;
+ }
+
+ /**
+ * Returns a full URL that was requested on current HTTP request.
+ *
+ * @return string
+ */
+ static public function selfUrl()
+ {
+ if (self::$selfUrl !== null) {
+ return self::$selfUrl;
+ } if (isset($_SERVER['SCRIPT_URI'])) {
+ return $_SERVER['SCRIPT_URI'];
+ }
+ $url = '';
+ $port = '';
+ if (isset($_SERVER['HTTP_HOST'])) {
+ if (($pos = strpos($_SERVER['HTTP_HOST'], ':')) === false) {
+ if (isset($_SERVER['SERVER_PORT'])) {
+ $port = ':' . $_SERVER['SERVER_PORT'];
+ }
+ $url = $_SERVER['HTTP_HOST'];
+ } else {
+ $url = substr($_SERVER['HTTP_HOST'], 0, $pos);
+ $port = substr($_SERVER['HTTP_HOST'], $pos);
+ }
+ } else if (isset($_SERVER['SERVER_NAME'])) {
+ $url = $_SERVER['SERVER_NAME'];
+ if (isset($_SERVER['SERVER_PORT'])) {
+ $port = ':' . $_SERVER['SERVER_PORT'];
+ }
+ }
+ if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
+ $url = 'https://' . $url;
+ if ($port == ':443') {
+ $port = '';
+ }
+ } else {
+ $url = 'http://' . $url;
+ if ($port == ':80') {
+ $port = '';
+ }
+ }
+
+ $url .= $port;
+ if (isset($_SERVER['HTTP_X_REWRITE_URL'])) {
+ $url .= $_SERVER['HTTP_X_REWRITE_URL'];
+ } elseif (isset($_SERVER['REQUEST_URI'])) {
+ $query = strpos($_SERVER['REQUEST_URI'], '?');
+ if ($query === false) {
+ $url .= $_SERVER['REQUEST_URI'];
+ } else {
+ $url .= substr($_SERVER['REQUEST_URI'], 0, $query);
+ }
+ } else if (isset($_SERVER['SCRIPT_URL'])) {
+ $url .= $_SERVER['SCRIPT_URL'];
+ } else if (isset($_SERVER['REDIRECT_URL'])) {
+ $url .= $_SERVER['REDIRECT_URL'];
+ } else if (isset($_SERVER['PHP_SELF'])) {
+ $url .= $_SERVER['PHP_SELF'];
+ } else if (isset($_SERVER['SCRIPT_NAME'])) {
+ $url .= $_SERVER['SCRIPT_NAME'];
+ if (isset($_SERVER['PATH_INFO'])) {
+ $url .= $_SERVER['PATH_INFO'];
+ }
+ }
+ return $url;
+ }
+
+ /**
+ * Returns an absolute URL for the given one
+ *
+ * @param string $url absilute or relative URL
+ * @return string
+ */
+ static public function absoluteUrl($url)
+ {
+ if (empty($url)) {
+ return Zend_OpenId::selfUrl();
+ } else if (!preg_match('|^([^:]+)://|', $url)) {
+ if (preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?]*)?((?:[?](?:[^#]*))?(?:#.*)?)$|', Zend_OpenId::selfUrl(), $reg)) {
+ $scheme = $reg[1];
+ $auth = $reg[2];
+ $host = $reg[3];
+ $port = $reg[4];
+ $path = $reg[5];
+ $query = $reg[6];
+ if ($url[0] == '/') {
+ return $scheme
+ . '://'
+ . $auth
+ . $host
+ . (empty($port) ? '' : (':' . $port))
+ . $url;
+ } else {
+ $dir = dirname($path);
+ return $scheme
+ . '://'
+ . $auth
+ . $host
+ . (empty($port) ? '' : (':' . $port))
+ . (strlen($dir) > 1 ? $dir : '')
+ . '/'
+ . $url;
+ }
+ }
+ }
+ return $url;
+ }
+
+ /**
+ * Converts variable/value pairs into URL encoded query string
+ *
+ * @param array $params variable/value pairs
+ * @return string URL encoded query string
+ */
+ static public function paramsToQuery($params)
+ {
+ foreach($params as $key => $value) {
+ if (isset($query)) {
+ $query .= '&' . $key . '=' . urlencode($value);
+ } else {
+ $query = $key . '=' . urlencode($value);
+ }
+ }
+ return isset($query) ? $query : '';
+ }
+
+ /**
+ * Normalizes URL according to RFC 3986 to use it in comparison operations.
+ * The function gets URL argument by reference and modifies it.
+ * It returns true on success and false of failure.
+ *
+ * @param string &$id url to be normalized
+ * @return bool
+ */
+ static public function normalizeUrl(&$id)
+ {
+ // RFC 3986, 6.2.2. Syntax-Based Normalization
+
+ // RFC 3986, 6.2.2.2 Percent-Encoding Normalization
+ $i = 0;
+ $n = strlen($id);
+ $res = '';
+ while ($i < $n) {
+ if ($id[$i] == '%') {
+ if ($i + 2 >= $n) {
+ return false;
+ }
+ ++$i;
+ if ($id[$i] >= '0' && $id[$i] <= '9') {
+ $c = ord($id[$i]) - ord('0');
+ } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
+ $c = ord($id[$i]) - ord('A') + 10;
+ } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
+ $c = ord($id[$i]) - ord('a') + 10;
+ } else {
+ return false;
+ }
+ ++$i;
+ if ($id[$i] >= '0' && $id[$i] <= '9') {
+ $c = ($c << 4) | (ord($id[$i]) - ord('0'));
+ } else if ($id[$i] >= 'A' && $id[$i] <= 'F') {
+ $c = ($c << 4) | (ord($id[$i]) - ord('A') + 10);
+ } else if ($id[$i] >= 'a' && $id[$i] <= 'f') {
+ $c = ($c << 4) | (ord($id[$i]) - ord('a') + 10);
+ } else {
+ return false;
+ }
+ ++$i;
+ $ch = chr($c);
+ if (($ch >= 'A' && $ch <= 'Z') ||
+ ($ch >= 'a' && $ch <= 'z') ||
+ $ch == '-' ||
+ $ch == '.' ||
+ $ch == '_' ||
+ $ch == '~') {
+ $res .= $ch;
+ } else {
+ $res .= '%';
+ if (($c >> 4) < 10) {
+ $res .= chr(($c >> 4) + ord('0'));
+ } else {
+ $res .= chr(($c >> 4) - 10 + ord('A'));
+ }
+ $c = $c & 0xf;
+ if ($c < 10) {
+ $res .= chr($c + ord('0'));
+ } else {
+ $res .= chr($c - 10 + ord('A'));
+ }
+ }
+ } else {
+ $res .= $id[$i++];
+ }
+ }
+
+ if (!preg_match('|^([^:]+)://([^:@]*(?:[:][^@]*)?@)?([^/:@?#]*)(?:[:]([^/?#]*))?(/[^?#]*)?((?:[?](?:[^#]*))?)((?:#.*)?)$|', $res, $reg)) {
+ return false;
+ }
+ $scheme = $reg[1];
+ $auth = $reg[2];
+ $host = $reg[3];
+ $port = $reg[4];
+ $path = $reg[5];
+ $query = $reg[6];
+ $fragment = $reg[7]; /* strip it */
+
+ if (empty($scheme) || empty($host)) {
+ return false;
+ }
+
+ // RFC 3986, 6.2.2.1. Case Normalization
+ $scheme = strtolower($scheme);
+ $host = strtolower($host);
+
+ // RFC 3986, 6.2.2.3. Path Segment Normalization
+ if (!empty($path)) {
+ $i = 0;
+ $n = strlen($path);
+ $res = "";
+ while ($i < $n) {
+ if ($path[$i] == '/') {
+ ++$i;
+ while ($i < $n && $path[$i] == '/') {
+ ++$i;
+ }
+ if ($i < $n && $path[$i] == '.') {
+ ++$i;
+ if ($i < $n && $path[$i] == '.') {
+ ++$i;
+ if ($i == $n || $path[$i] == '/') {
+ if (($pos = strrpos($res, '/')) !== false) {
+ $res = substr($res, 0, $pos);
+ }
+ } else {
+ $res .= '/..';
+ }
+ } else if ($i != $n && $path[$i] != '/') {
+ $res .= '/.';
+ }
+ } else {
+ $res .= '/';
+ }
+ } else {
+ $res .= $path[$i++];
+ }
+ }
+ $path = $res;
+ }
+
+ // RFC 3986,6.2.3. Scheme-Based Normalization
+ if ($scheme == 'http') {
+ if ($port == 80) {
+ $port = '';
+ }
+ } else if ($scheme == 'https') {
+ if ($port == 443) {
+ $port = '';
+ }
+ }
+ if (empty($path)) {
+ $path = '/';
+ }
+
+ $id = $scheme
+ . '://'
+ . $auth
+ . $host
+ . (empty($port) ? '' : (':' . $port))
+ . $path
+ . $query;
+ return true;
+ }
+
+ /**
+ * Normalizes OpenID identifier that can be URL or XRI name.
+ * Returns true on success and false of failure.
+ *
+ * Normalization is performed according to the following rules:
+ * 1. If the user's input starts with one of the "xri://", "xri://$ip*",
+ * or "xri://$dns*" prefixes, they MUST be stripped off, so that XRIs
+ * are used in the canonical form, and URI-authority XRIs are further
+ * considered URL identifiers.
+ * 2. If the first character of the resulting string is an XRI Global
+ * Context Symbol ("=", "@", "+", "$", "!"), then the input SHOULD be
+ * treated as an XRI.
+ * 3. Otherwise, the input SHOULD be treated as an http URL; if it does
+ * not include a "http" or "https" scheme, the Identifier MUST be
+ * prefixed with the string "http://".
+ * 4. URL identifiers MUST then be further normalized by both following
+ * redirects when retrieving their content and finally applying the
+ * rules in Section 6 of [RFC3986] to the final destination URL.
+ * @param string &$id identifier to be normalized
+ * @return bool
+ */
+ static public function normalize(&$id)
+ {
+ $id = trim($id);
+ if (strlen($id) === 0) {
+ return true;
+ }
+
+ // 7.2.1
+ if (strpos($id, 'xri://$ip*') === 0) {
+ $id = substr($id, strlen('xri://$ip*'));
+ } else if (strpos($id, 'xri://$dns*') === 0) {
+ $id = substr($id, strlen('xri://$dns*'));
+ } else if (strpos($id, 'xri://') === 0) {
+ $id = substr($id, strlen('xri://'));
+ }
+
+ // 7.2.2
+ if ($id[0] == '=' ||
+ $id[0] == '@' ||
+ $id[0] == '+' ||
+ $id[0] == '$' ||
+ $id[0] == '!') {
+ return true;
+ }
+
+ // 7.2.3
+ if (strpos($id, "://") === false) {
+ $id = 'http://' . $id;
+ }
+
+ // 7.2.4
+ return self::normalizeURL($id);
+ }
+
+ /**
+ * Performs a HTTP redirection to specified URL with additional data.
+ * It may generate redirected request using GET or POST HTTP method.
+ * The function never returns.
+ *
+ * @param string $url URL to redirect to
+ * @param array $params additional variable/value pairs to send
+ * @param Zend_Controller_Response_Abstract $response
+ * @param string $method redirection method ('GET' or 'POST')
+ */
+ static public function redirect($url, $params = null,
+ Zend_Controller_Response_Abstract $response = null, $method = 'GET')
+ {
+ $url = Zend_OpenId::absoluteUrl($url);
+ $body = "";
+ if (null === $response) {
+ require_once "Zend/Controller/Response/Http.php";
+ $response = new Zend_Controller_Response_Http();
+ }
+
+ if ($method == 'POST') {
+ $body = "<html><body onLoad=\"document.forms[0].submit();\">\n";
+ $body .= "<form method=\"POST\" action=\"$url\">\n";
+ if (is_array($params) && count($params) > 0) {
+ foreach($params as $key => $value) {
+ $body .= '<input type="hidden" name="' . $key . '" value="' . $value . "\">\n";
+ }
+ }
+ $body .= "<input type=\"submit\" value=\"Continue OpenID transaction\">\n";
+ $body .= "</form></body></html>\n";
+ } else if (is_array($params) && count($params) > 0) {
+ if (strpos($url, '?') === false) {
+ $url .= '?' . self::paramsToQuery($params);
+ } else {
+ $url .= '&' . self::paramsToQuery($params);
+ }
+ }
+ if (!empty($body)) {
+ $response->setBody($body);
+ } else if (!$response->canSendHeaders()) {
+ $response->setBody("<script language=\"JavaScript\"" .
+ " type=\"text/javascript\">window.location='$url';" .
+ "</script>");
+ } else {
+ $response->setRedirect($url);
+ }
+ $response->sendResponse();
+ if (self::$exitOnRedirect) {
+ exit();
+ }
+ }
+
+ /**
+ * Produces string of random byte of given length.
+ *
+ * @param integer $len length of requested string
+ * @return string RAW random binary string
+ */
+ static public function randomBytes($len)
+ {
+ $key = '';
+ for($i=0; $i < $len; $i++) {
+ $key .= chr(mt_rand(0, 255));
+ }
+ return $key;
+ }
+
+ /**
+ * Generates a hash value (message digest) according to given algorithm.
+ * It returns RAW binary string.
+ *
+ * This is a wrapper function that uses one of available internal function
+ * dependent on given PHP configuration. It may use various functions from
+ * ext/openssl, ext/hash, ext/mhash or ext/standard.
+ *
+ * @param string $func digest algorithm
+ * @param string $data data to sign
+ * @return string RAW digital signature
+ * @throws Zend_OpenId_Exception
+ */
+ static public function digest($func, $data)
+ {
+ if (function_exists('openssl_digest')) {
+ return openssl_digest($data, $func, true);
+ } else if (function_exists('hash')) {
+ return hash($func, $data, true);
+ } else if ($func === 'sha1') {
+ return sha1($data, true);
+ } else if ($func === 'sha256') {
+ if (function_exists('mhash')) {
+ return mhash(MHASH_SHA256 , $data);
+ }
+ }
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'Unsupported digest algorithm "' . $func . '".',
+ Zend_OpenId_Exception::UNSUPPORTED_DIGEST);
+ }
+
+ /**
+ * Generates a keyed hash value using the HMAC method. It uses ext/hash
+ * if available or user-level PHP implementation, that is not significantly
+ * slower.
+ *
+ * @param string $macFunc name of selected hashing algorithm (sha1, sha256)
+ * @param string $data data to sign
+ * @param string $secret shared secret key used for generating the HMAC
+ * variant of the message digest
+ * @return string RAW HMAC value
+ */
+ static public function hashHmac($macFunc, $data, $secret)
+ {
+// require_once "Zend/Crypt/Hmac.php";
+// return Zend_Crypt_Hmac::compute($secret, $macFunc, $data, Zend_Crypt_Hmac::BINARY);
+ if (function_exists('hash_hmac')) {
+ return hash_hmac($macFunc, $data, $secret, 1);
+ } else {
+ if (Zend_OpenId::strlen($secret) > 64) {
+ $secret = self::digest($macFunc, $secret);
+ }
+ $secret = str_pad($secret, 64, chr(0x00));
+ $ipad = str_repeat(chr(0x36), 64);
+ $opad = str_repeat(chr(0x5c), 64);
+ $hash1 = self::digest($macFunc, ($secret ^ $ipad) . $data);
+ return self::digest($macFunc, ($secret ^ $opad) . $hash1);
+ }
+ }
+
+ /**
+ * Converts binary representation into ext/gmp or ext/bcmath big integer
+ * representation.
+ *
+ * @param string $bin binary representation of big number
+ * @return mixed
+ * @throws Zend_OpenId_Exception
+ */
+ static protected function binToBigNum($bin)
+ {
+ if (extension_loaded('gmp')) {
+ return gmp_init(bin2hex($bin), 16);
+ } else if (extension_loaded('bcmath')) {
+ $bn = 0;
+ $len = Zend_OpenId::strlen($bin);
+ for ($i = 0; $i < $len; $i++) {
+ $bn = bcmul($bn, 256);
+ $bn = bcadd($bn, ord($bin[$i]));
+ }
+ return $bn;
+ }
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'The system doesn\'t have proper big integer extension',
+ Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+ }
+
+ /**
+ * Converts internal ext/gmp or ext/bcmath big integer representation into
+ * binary string.
+ *
+ * @param mixed $bn big number
+ * @return string
+ * @throws Zend_OpenId_Exception
+ */
+ static protected function bigNumToBin($bn)
+ {
+ if (extension_loaded('gmp')) {
+ $s = gmp_strval($bn, 16);
+ if (strlen($s) % 2 != 0) {
+ $s = '0' . $s;
+ } else if ($s[0] > '7') {
+ $s = '00' . $s;
+ }
+ return pack("H*", $s);
+ } else if (extension_loaded('bcmath')) {
+ $cmp = bccomp($bn, 0);
+ if ($cmp == 0) {
+ return "\0";
+ } else if ($cmp < 0) {
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'Big integer arithmetic error',
+ Zend_OpenId_Exception::ERROR_LONG_MATH);
+ }
+ $bin = "";
+ while (bccomp($bn, 0) > 0) {
+ $bin = chr(bcmod($bn, 256)) . $bin;
+ $bn = bcdiv($bn, 256);
+ }
+ if (ord($bin[0]) > 127) {
+ $bin = "\0" . $bin;
+ }
+ return $bin;
+ }
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'The system doesn\'t have proper big integer extension',
+ Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+ }
+
+ /**
+ * Performs the first step of a Diffie-Hellman key exchange by generating
+ * private and public DH values based on given prime number $p and
+ * generator $g. Both sides of key exchange MUST have the same prime number
+ * and generator. In this case they will able to create a random shared
+ * secret that is never send from one to the other.
+ *
+ * @param string $p prime number in binary representation
+ * @param string $g generator in binary representation
+ * @param string $priv_key private key in binary representation
+ * @return mixed
+ */
+ static public function createDhKey($p, $g, $priv_key = null)
+ {
+ if (function_exists('openssl_dh_compute_key')) {
+ $dh_details = array(
+ 'p' => $p,
+ 'g' => $g
+ );
+ if ($priv_key !== null) {
+ $dh_details['priv_key'] = $priv_key;
+ }
+ return openssl_pkey_new(array('dh'=>$dh_details));
+ } else {
+ $bn_p = self::binToBigNum($p);
+ $bn_g = self::binToBigNum($g);
+ if ($priv_key === null) {
+ $priv_key = self::randomBytes(Zend_OpenId::strlen($p));
+ }
+ $bn_priv_key = self::binToBigNum($priv_key);
+ if (extension_loaded('gmp')) {
+ $bn_pub_key = gmp_powm($bn_g, $bn_priv_key, $bn_p);
+ } else if (extension_loaded('bcmath')) {
+ $bn_pub_key = bcpowmod($bn_g, $bn_priv_key, $bn_p);
+ }
+ $pub_key = self::bigNumToBin($bn_pub_key);
+
+ return array(
+ 'p' => $bn_p,
+ 'g' => $bn_g,
+ 'priv_key' => $bn_priv_key,
+ 'pub_key' => $bn_pub_key,
+ 'details' => array(
+ 'p' => $p,
+ 'g' => $g,
+ 'priv_key' => $priv_key,
+ 'pub_key' => $pub_key));
+ }
+ }
+
+ /**
+ * Returns an associative array with Diffie-Hellman key components in
+ * binary representation. The array includes original prime number 'p' and
+ * generator 'g', random private key 'priv_key' and corresponding public
+ * key 'pub_key'.
+ *
+ * @param mixed $dh Diffie-Hellman key
+ * @return array
+ */
+ static public function getDhKeyDetails($dh)
+ {
+ if (function_exists('openssl_dh_compute_key')) {
+ $details = openssl_pkey_get_details($dh);
+ if (isset($details['dh'])) {
+ return $details['dh'];
+ }
+ } else {
+ return $dh['details'];
+ }
+ }
+
+ /**
+ * Computes the shared secret from the private DH value $dh and the other
+ * party's public value in $pub_key
+ *
+ * @param string $pub_key other party's public value
+ * @param mixed $dh Diffie-Hellman key
+ * @return string
+ * @throws Zend_OpenId_Exception
+ */
+ static public function computeDhSecret($pub_key, $dh)
+ {
+ if (function_exists('openssl_dh_compute_key')) {
+ $ret = openssl_dh_compute_key($pub_key, $dh);
+ if (ord($ret[0]) > 127) {
+ $ret = "\0" . $ret;
+ }
+ return $ret;
+ } else if (extension_loaded('gmp')) {
+ $bn_pub_key = self::binToBigNum($pub_key);
+ $bn_secret = gmp_powm($bn_pub_key, $dh['priv_key'], $dh['p']);
+ return self::bigNumToBin($bn_secret);
+ } else if (extension_loaded('bcmath')) {
+ $bn_pub_key = self::binToBigNum($pub_key);
+ $bn_secret = bcpowmod($bn_pub_key, $dh['priv_key'], $dh['p']);
+ return self::bigNumToBin($bn_secret);
+ }
+ require_once "Zend/OpenId/Exception.php";
+ throw new Zend_OpenId_Exception(
+ 'The system doesn\'t have proper big integer extension',
+ Zend_OpenId_Exception::UNSUPPORTED_LONG_MATH);
+ }
+
+ /**
+ * Takes an arbitrary precision integer and returns its shortest big-endian
+ * two's complement representation.
+ *
+ * Arbitrary precision integers MUST be encoded as big-endian signed two's
+ * complement binary strings. Henceforth, "btwoc" is a function that takes
+ * an arbitrary precision integer and returns its shortest big-endian two's
+ * complement representation. All integers that are used with
+ * Diffie-Hellman Key Exchange are positive. This means that the left-most
+ * bit of the two's complement representation MUST be zero. If it is not,
+ * implementations MUST add a zero byte at the front of the string.
+ *
+ * @param string $str binary representation of arbitrary precision integer
+ * @return string big-endian signed representation
+ */
+ static public function btwoc($str)
+ {
+ if (ord($str[0]) > 127) {
+ return "\0" . $str;
+ }
+ return $str;
+ }
+
+ /**
+ * Returns lenght of binary string in bytes
+ *
+ * @param string $str
+ * @return int the string lenght
+ */
+ static public function strlen($str)
+ {
+ if (extension_loaded('mbstring') &&
+ (((int)ini_get('mbstring.func_overload')) & 2)) {
+ return mb_strlen($str, 'latin1');
+ } else {
+ return strlen($str);
+ }
+ }
+
+}