PHP version of PGP

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: PHP version of PGP

Post by Benjamin »

Ambush Commander wrote:Meh... (Can't be bothered to digout his login for PHP classes)
I know I never login to that site. I don't even know why they require a login.

Code: Select all

 
<?php
 
DEFINE('ENCRYPTION_PACKET_SIZE', 40);
 
class RSA{
    /*
    * Function for generating keys. Return array where
    * $array[0] -> modulo N
    * $array[1] -> public key E
    * $array[2] -> private key D
    * Public key pair is N and E
    * Private key pair is N and D
    */
    public function generate_keys ($p, $q, $show_debug=0){
        $n = bcmul($p, $q);
      
        //m (we need it to calculate D and E) 
        $m = bcmul(bcsub($p, 1), bcsub($q, 1));
      
        // Public key  E 
        $e = $this->findE($m);
      
        // Private key D
        $d = $this->extend($e,$m);
      
        $keys = array ($n, $e, $d); // $n = modulu, $e = public key, $d = private key
 
        if ($show_debug) {
                echo "P = $p<br>Q = $q<br><b>N = $n</b> - modulo<br>M = $m<br><b>E = $e</b> - public key<br><b>D = $d</b> - private key<p>";
        }
      
        return $keys;
    }
 
    /* 
    * Standard method of calculating D
    * D = E-1 (mod N)
    * It's presumed D will be found in less then 16 iterations 
    */
    private function extend ($Ee,$Em) {
        $u1 = '1';
        $u2 = '0';
        $u3 = $Em;
        $v1 = '0';
        $v2 = '1';
        $v3 = $Ee;
 
        while (bccomp($v3, 0) != 0) {
                $qq = bcdiv($u3, $v3, 0);
                $t1 = bcsub($u1, bcmul($qq, $v1));
                $t2 = bcsub($u2, bcmul($qq, $v2));
                $t3 = bcsub($u3, bcmul($qq, $v3));
                $u1 = $v1;
                $u2 = $v2;
                $u3 = $v3;
                $v1 = $t1;
                $v2 = $t2;
                $v3 = $t3;
                $z  = '1';
        }
 
        $uu = $u1;
        $vv = $u2;
 
        if (bccomp($vv, 0) == -1) {
                $inverse = bcadd($vv, $Em);
        } else {
                $inverse = $vv;
        }
 
        return $inverse;
    }
 
    /* 
    * This function return Greatest Common Divisor for $e and $m numbers 
    */
    private function GCD($e,$m) {
        $y = $e;
        $x = $m;
 
        while (bccomp($y, 0) != 0) {
                // modulus function
            $w = bcsub($x, bcmul($y, bcdiv($x, $y, 0)));;
                $x = $y;
                $y = $w;
        }
 
        return $x;
    }
 
    /*
    * Calculating E under conditions:
    * GCD(N,E) = 1 and 1<E<N
    */
    private function findE($m){
        $e = '3';
        if(bccomp($this->GCD($e, $m), '1') != 0){
            $e = '5';
            $step = '2';
 
            while(bccomp($this->GCD($e, $m), '1') != 0){
                $e = bcadd($e, $step);
 
                if($step == '2'){
                    $step = '4';
                }else{
                    $step = '2';
                }
            }
        }
 
        return $e;
    }
 
    /*
    * ENCRYPT function returns
    * X = M^E (mod N)
    */
    public function encrypt ($m, $e, $n) {
        $coded   = '';
        $max     = strlen($m);
        $packets = ceil($max/ENCRYPTION_PACKET_SIZE);
        
        for($i=0; $i<$packets; $i++){
            $packet = substr($m, $i*ENCRYPTION_PACKET_SIZE, ENCRYPTION_PACKET_SIZE);
            $code   = '0';
 
            for($j=0; $j<ENCRYPTION_PACKET_SIZE; $j++){
                $pdata = (isset($packet[$j])) ? $packet[$j] : null;
                $code = bcadd($code, bcmul(ord($pdata), bcpow('256',$j)));
            }
 
            $code   = bcpowmod($code, $e, $n);
            $coded .= $code.' ';
        }
 
        return trim($coded);
    }
 
    /*
    ENCRYPT function returns
    M = X^D (mod N)
    */
    public function decrypt ($c, $d, $n) {
        $coded   = split(' ', $c);
        $message = '';
        $max     = count($coded);
 
        for($i=0; $i<$max; $i++){
            $code = bcpowmod($coded[$i], $d, $n);
 
            while(bccomp($code, '0') != 0){
                $ascii    = bcmod($code, '256');
                $code     = bcdiv($code, '256', 0);
                $message .= chr($ascii);
            }
        }
 
        return $message;
    }
    
    // Digital Signature
    public function sign($message, $d, $n){
        $messageDigest = md5($message);
        $signature = $this->encrypt($messageDigest, $d, $n, ENCRYPTION_PACKET_SIZE);
        return $signature;
    }
    
    public function prove($message, $signature, $e, $n){
        $messageDigest = $this->decrypt($signature, $e, $n);
        if($messageDigest == md5($message)){
            return true;
        }else{
            return false;
        }
    }
 
    public function signFile($file, $d, $n){
        $messageDigest = md5_file($file);
        $signature = $this->encrypt($messageDigest, $d, $n, ENCRYPTION_PACKET_SIZE);
        return $signature;
    }
    
    public function proveFile($file, $signature, $e, $n){
        $messageDigest = $this->decrypt($signature, $e, $n);
        if($messageDigest == md5_file($file)){
            return true;
        }else{
            return false;
        }
    }
}
?>
 
 

Code: Select all

 
<pre>
<?php
include 'rsa.class.php';
 
/*
The keys are:
0:99812541893017455179 - modulo
1:5 - public key
2:19962508374607241957 - private key
*/
 
error_reporting(0);
 
$RSA = new RSA();
 
$message = 'RSA Encryption Test';
 
$private_key = '19962508374607241957';
$modulo      = '99812541893017455179';
$public_key  = '5';
 
echo "Testing with public key to encrypt, private key to decrypt:\n";
$encoded = $RSA->encrypt ($message, $public_key, $modulo);
$decoded = $RSA->decrypt ($encoded, $private_key, $modulo);
echo "Encrypted: $encoded\nDecrypted: $decoded\n"; 
 
echo "Testing with private key to encrypt, public key to decrypt:\n";
$encoded = $RSA->encrypt ($message, $private_key, $modulo);
$decoded = $RSA->decrypt ($encoded, $public_key, $modulo);
echo "Encrypted: $encoded\nDecrypted: $decoded\n"; 
 
echo "Testing with private key to encrypt, private key to decrypt:\n";
$encoded = $RSA->encrypt ($message, $private_key, $modulo);
$decoded = $RSA->decrypt ($encoded, $private_key, $modulo);
echo "Encrypted: $encoded\nDecrypted: $decoded\n"; 
 
echo "Testing with public key to encrypt, public key to decrypt:\n";
$encoded = $RSA->encrypt ($message, $public_key, $modulo);
$decoded = $RSA->decrypt ($encoded, $public_key, $modulo);
echo "Encrypted: $encoded\nDecrypted: $decoded\n"; 
 
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Re: PHP version of PGP

Post by Ambush Commander »

The class makes me really leery. It looks like it's been made without any regard to real-world usage, and is still using the insecure MD5 (it should be using SHA-1 at least).

Can I know a little more about why you need this (i.e. real-world need) so I can give an alternative?
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: PHP version of PGP

Post by Benjamin »

I need a way to digitally sign modules and license keys for a public web application. The end user can validate the signatures and/or decrypt data but a malicous user would not be able to create them.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Re: PHP version of PGP

Post by Ambush Commander »

Why not just do it by hand?
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: PHP version of PGP

Post by Benjamin »

In this instance it's not possible I'm afraid.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Re: PHP version of PGP

Post by Ambush Commander »

How much automation is required, then?

Remember: signing things mean that you're vouching for it, so you should be doing auditing or something. Also, how many secret keys will this system need to manage?
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: PHP version of PGP

Post by Benjamin »

Without getting into too much detail, this will be used to do quite a few things. The main purpose is to protect a closed source application. I want to digitally sign the license keys so that even if someone creates a keygenerator they won't work.

We sometimes distribute updates via e-mail so it's important that the software can recognize genuine updates. We do not provide download links for the software.

There are a few other things this will be used for (for) anti piracy measures that I can't really talk about publicly.

We currently have a few idiots trying to decode the script. So far they have not been successful, but they were able to get access to encryption keys.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Re: PHP version of PGP

Post by Ambush Commander »

The main purpose is to protect a closed source application. I want to digitally sign the license keys so that even if someone creates a keygenerator they won't work.

We sometimes distribute updates via e-mail so it's important that the software can recognize genuine updates. We do not provide download links for the software.

There are a few other things this will be used for (for) anti piracy measures that I can't really talk about publicly.
It really sounds like it should be done by hand. Can you elaborate on why that's not possible?
We currently have a few idiots trying to decode the script. So far they have not been successful, but they were able to get access to encryption keys.
What do you mean by encryption key? If you mean the private key, that's a big problem.

I should also point out that it would be easy for a hacker to alter the public key the software uses to check its authenticity (or excise the check completely).
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: PHP version of PGP

Post by Benjamin »

How am I supposed to digitally sign license keys manually?
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Re: PHP version of PGP

Post by Ambush Commander »

Touché!

Next question: how much control do you have over the server that issues license keys?
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: PHP version of PGP

Post by Benjamin »

root
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Re: PHP version of PGP

Post by Ambush Commander »

My recommendation is install the gnupg extension and use that. An example of clearsigning something can be found here.
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: PHP version of PGP

Post by Benjamin »

That isn't doable because it would need to be installed on all the client servers as well.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Re: PHP version of PGP

Post by Ambush Commander »

I'm out of ideas, then. Sorry; I was never much good at cooking up DRM schemes ;-)
User avatar
Benjamin
Site Administrator
Posts: 6935
Joined: Sun May 19, 2002 10:24 pm

Re: PHP version of PGP

Post by Benjamin »

Maybe I can convert the MD5 to sha-1 or something. I think this will be secure enough for what I need it for.
Post Reply