<?php
/**
 * Crypt_DSA
 * 
 * Crypt_DSA - DSA signature verification library
 *
 * LICENSE:
 *
 * Copyright (c) 2004-2006, TSURUOKA Naoya
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer. 
 *   - Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution. 
 *   - Neither the name of the author nor the names of its contributors
 *     may be used to endorse or promote products derived from this
 *     software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @category  Crypt
 * @package   Crypt_DSA
 * @author    TSURUOKA Naoya <tsuruoka@labs.cybozu.co.jp>
 * @copyright 2006 TSURUOKA Naoya
 * @license   http://www.opensource.org/licenses/bsd-license.php The BSD License
 * @see       http://search.cpan.org/dist/Crypt-DSA/lib/Crypt/DSA.pm
 * @version 0.0.3
 */

/**
 * uses PEAR_Exception
 */
require_once 'PEAR/Exception.php';
require_once 
'Math_BigInteger.php';

/**
 * Crypt_DSA_Exception
 *
 * This class is used in all place in the package where Exceptions
 * are raised.
 *
 * @package Crypt_DSA
 * @author  Shin OHNO <ganchiku@gmail.com>
 * @author  TSURUOKA Naoya <tsuruoka@labs.cybozu.co.jp>
 */
class Crypt_DSA_Exception extends PEAR_Exception
{
    
/**
     * errorHandlerCallback
     *
     * @param int $code
     * @param string $string
     * @param string $file
     * @param int $line
     * @param array $context
     * @static
     * @access public
     * throw Crypt_DSA_Exception
     */
    
public static function errorHandlerCallback($code$string$file$line$context)
    {
        
$e = new self($string$code);
        
$e->line $line;
        
$e->file $file;
        throw 
$e;
    }
}

/**
 * Crypt_DSA
 * 
 * example:
 * <code>
 * <?php
 * if (Crypt_DSA::verify($message, $sig, $sig_keys)) {
 *   echo 'verify success';
 * } else {
 *   echo 'verify failed';
 * }
 * ?>
 * </code>
 *
 * @package Crypt_DSA
 * @author TSURUOKA Naoya <tsuruoka@labs.cybozu.co.jp>
 * @version 0.0.3
  */
class Crypt_DSA
{
    
/**
     * Version of this package
     */
    
const VERSION '0.0.3';

    
//{{{ verify
    /**
     * DSA verify
     * 
     * @param string $message message
     * @param string $sig     signature
     * @param array $sig_keys key
     * @return bool
     * @throws Crypt_DSA_Exception
     */
    
static public function verify($message$sig$sig_keys)
    {
        
$keys = array('p','q','g','pub_key');

        foreach (
$keys as $key) {
            if (!isset(
$sig_keys[$key])) {
                throw new 
Crypt_DSA_Exception("sig_keys['{$key}'] not found");
            }
            $
$key = new Math_BigInteger($sig_keys[$key]);
        }

        list (
$r_sig$s_sig) = explode(":"$sig);

        
$s1 = new Math_BigInteger(base64_decode($r_sig), 256);
        
$s2 = new Math_BigInteger(base64_decode($s_sig), 256);

        
$w      $s2->modInverse($q);
        
$hash_m = new Math_BigInteger(sha1($message), 16);

        
$hash_m_mul $hash_m->multiply($w);
        
$u1_base    $hash_m_mul->divide($q);
        
$u1         $u1_base[1];

        
$s1_mul  $s1->multiply($w);
        
$u2_base $s1_mul->divide($q);
        
$u2      $u2_base[1];

        
$g_pow              $g->modPow($u1$p);
        
$pub_key_pow        $pub_key->modPow($u2$p);
        
$g_pow_mul          $g_pow->multiply($pub_key_pow);
        
$g_pow_mul_mod_base $g_pow_mul->divide($p);
        
$g_pow_mul_mod      $g_pow_mul_mod_base[1];

        
$v_base $g_pow_mul_mod->divide($q);
        
$v      $v_base[1];

        return (
$v->compare($s1) == 0);
    }
    
//}}}

}
/*
 * vim: set expandtab tabstop=4 shiftwidth=4 
 * vim600: foldmethod=marker
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 */
?>