<?php

require_once('../html/classes/jCryption-1.0.1.php');

/**
 * RSAKeyImport
 *
 * PHP versions 4 and 5
 *
 * LICENSE: This source file is subject to version 3.0 of the PHP license
 * that is available through the world-wide-web at the following URI:
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
 * the PHP License and are unable to obtain it through the web, please
 * send a note to license@php.net so we can mail you a copy immediately.
 *
 * Many of the functions in this class are from the PEAR Crypt_RSA package ...
 * So most of the credits goes to the original creator of this package Alexander Valyalkin
 * you can get the package under http://pear.php.net/package/Crypt_RSA
 *
 * This is just a simplified extraction for the PEM key import functionality and requires bcmath.
 *
 * @author     Lite Speed Technologies <info@litespeedtech.com>
 * @copyright  2009 Lite Speed Technologies
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
 * @version    1.0.0
 */

class RSAKeyImport
{
    function bin2int($str)
    {
        $result = '0';
        $n = strlen($str);
        do {
            $result = bcadd(bcmul($result, '256'), ord($str{--$n}));
        } while ($n > 0);
        return $result;
    }

    function fromPEMString($str)
    {
        // search for base64-encoded private key
        if (!preg_match('/-----BEGIN RSA PRIVATE KEY-----([^-]+)-----END RSA PRIVATE KEY-----/', $str, $matches)) {
            echo ("can't find RSA private key in the string [{$str}]");
            return false;
        }

        // parse private key. It is ASN.1-encoded
        $str = base64_decode($matches[1]);
        $pos = 0;
        $tmp = RSAKeyImport::_ASN1Parse($str, $pos);
        if ($tmp == false) 
            return false;
    
        if ($tmp['tag'] != 0x10) {
            echo "Expected 0x10 (SEQUENCE) wrong ASN tag value: " .  $tmp['tag'];
	    return false;
        }

        // parse ASN.1 SEQUENCE for RSA private key
        $attr_names = array('version', 'n', 'e', 'd', 'p', 'q', 'dmp1', 'dmq1', 'iqmp');
        $n = sizeof($attr_names);
        $rsa_attrs = array();
        for ($i = 0; $i < $n; $i++) {
            $tmp = RSAKeyImport::_ASN1ParseInt($str, $pos);
            if ($tmp === false) {
		echo "fail to parse int";
                return false;
            }
            $attr = $attr_names[$i];
            $rsa_attrs[$attr] = $tmp;
        }
	return $rsa_attrs;

        // create Crypt_RSA_KeyPair object.
	$keypair = &new KeyPair($rsa_attrs);
        if ($keypair == false) {
            return false;
        }
        return $keypair; 
    }

    function _ASN1Parse($str, &$pos)
    {
        $max_pos = strlen($str);
        if ($max_pos < 2) {
            echo ("ASN.1 string too short");
            return false;
        }

        // get ASN.1 tag value
        $tag = ord($str[$pos++]) & 0x1f;
        if ($tag == 0x1f) {
            $tag = 0;
            do {
                $n = ord($str[$pos++]);
                $tag <<= 7;
                $tag |= $n & 0x7f;
            } while (($n & 0x80) && $pos < $max_pos);
        }
        if ($pos >= $max_pos) {
            echo("ASN.1 string too short");
            return false;
        }

        // get ASN.1 object length
        $len = ord($str[$pos++]);
        if ($len & 0x80) {
            $n = $len & 0x1f;
            $len = 0;
            while ($n-- && $pos < $max_pos) {
                $len <<= 8;
                $len |= ord($str[$pos++]);
            }
        }
        if ($pos >= $max_pos || $len > $max_pos - $pos) {
            echo ("ASN.1 string too short");
            return false;
        }

        // get string value of ASN.1 object
        $str = substr($str, $pos, $len);

        return array(
            'tag' => $tag,
            'str' => $str,
	    );
    }

    function _ASN1ParseInt($str, &$pos)
    {
        $tmp = RSAKeyImport::_ASN1Parse($str, $pos);
        if ($tmp == false) {
            return false;
        }
        if ($tmp['tag'] != 0x02) {
            echo "Expected 0x02 (INTEGER) wrong ASN tag value: " . $tmp['tag'];
            return false;
        }
        $pos += strlen($tmp['str']);

        return strrev($tmp['str']);
    }

    function dec2string($decimal, $base) {

	$string = null;

	$base = (int) $base;
	if ($base < 2 | $base > 36 | $base == 10) {
	    echo 'BASE must be in the range 2-9 or 11-36';
	    exit;
	}

	$charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';

	$charset = substr($charset, 0, $base);

	do {
	    $remainder = bcmod($decimal, $base);
	    $char = substr($charset, $remainder, 1);
	    $string = "$char$string";
	    $decimal = bcdiv(bcsub($decimal, $remainder), $base);
	} while ($decimal > 0);

	return strtolower($string);
    }

    function import_and_convert($pem_filename)
    {
	$str1 = file_get_contents($pem_filename);
	if ($str1 == false) {
	    echo "failed to open file $pem_filename";
	    return false;
	}

	$attrs = RSAKeyImport::fromPEMString($str1);
	if ($attrs == false) {
	    echo "failed to parse $pem_filename";
	    return false;
	}

	$n_int = RSAKeyImport::bin2int($attrs['n']);
	$d_int = RSAKeyImport::bin2int($attrs['d']);
	$e_int = RSAKeyImport::bin2int($attrs['e']);
	$e_hex = RSAKeyImport::dec2string($e_int,16);
	$n_hex = RSAKeyImport::dec2string($n_int,16);
	$mykeys = array( 'e_hex' => $e_hex, 'n_hex' => $n_hex, 'd_int' => $d_int, 'n_int' => $n_int);

	return $mykeys;
    }

}

## main
# openssl genrsa -out key.pem 512

function my_file_put_contents($filename, $contents) 
{ 	// file_put_contents in php5 only
	if (!$handle = fopen($filename,'w')) {
		return FALSE;
	}
	if (fwrite($handle,$contents) === FALSE) {
		return FALSE;
	}
	fclose($handle);
	return TRUE;
}
		
## main

$mykeys = NULL;

if ( isset($argv[1]) ) {
    $pemfile = $argv[1];
    $mykeys = RSAKeyImport::import_and_convert($pemfile);
}

if ($mykeys == FALSE) {
    echo "Using php to generate keys, please be patient ... \n";

    $keyLength = 512;
    $jCryption = new jCryption();
    $keys = $jCryption->generateKeypair($keyLength);
    $e_hex = $jCryption->dec2string($keys['e'],16);
    $n_hex = $jCryption->dec2string($keys['n'],16);
    $mykeys = array( 'e_hex' => $e_hex, 'n_hex' => $n_hex, 'd_int' => $keys['d'], 'n_int' => $keys['n']);
}

$keyfile = '../conf/jcryption_keypair';
$serialized_str = serialize($mykeys);
$result = my_file_put_contents($keyfile, $serialized_str);
chmod($keyfile, 0600);

if ($result == TRUE)
    exit(0);
else
    exit(1);

?>
