Subversion Repositories Applications.framework

Rev

Rev 299 | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php

/**
 * Classe utilitaire proposant des fonctions permettant la réalisation d'un 
 * échange de clé Diffie Hellman
 * 
 * "En cryptographie, l'échange de clés Diffie-Hellman, du nom de ses auteurs 
 *  Whitfield Diffie et Martin Hellman, est une méthode par laquelle deux 
 *  personnes peuvent se mettre d'accord sur un nombre (qu'ils peuvent utiliser 
 *  comme clé pour chiffrer la conversation suivante) sans qu'une troisième 
 *  personne appelée Ève puisse découvrir le nombre, même en ayant écouté tous 
 *  leurs échanges."
 *  
 *  Voir http://fr.wikipedia.org/wiki/%C3%89change_de_cl%C3%A9s_Diffie-Hellman
 * 
 * */
class DiffieHellmanUtil {
        
        // 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';

    
        
        
        /**
     * 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
     */
    public static 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(self::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
     */
    public static 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'];
        }
    }
    
    
    
// Depuis OpenId.php, les fonctions de Diffie-Hellman
    // TODO : voir si ça peut être externaliser pour être réutilisé ? => dans utilitaires
        /**
     * 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
     */
    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);*/
        
        trigger_error('Le système ne gère pas les nombre de taille arbitraire', E_STRICT);
    }
    
        /**
     * 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
     */
    public function btwoc($str)
    {
        if (ord($str[0]) > 127) {
            return "\0" . $str;
        }
        return $str;
    }
    
        
    
        /**
     * Produces string of random byte of given length.
     *
     * @param integer $len length of requested string
     * @return string RAW random binary string
     */
    public function randomBytes($len)
    {
        $key = '';
        for($i=0; $i < $len; $i++) {
            $key .= chr(mt_rand(0, 255));
        }
        return $key;
    }
    
        /**
     * 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);
        }
    }
    
    
        /**
     * 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
     */
    protected function binToBigNum($bin)
    {
        if (extension_loaded('gmp')) {
            return gmp_init(bin2hex($bin), 16);
        } else if (extension_loaded('bcmath')) {
            $bn = 0;
            $len = self::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);*/
        
        trigger_error('Le système ne gère pas les nombre de taille arbitraire', E_STRICT);
    }
    
}
?>