Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSA signing problem, when some components of private key are zero #980

Closed
externaltemp opened this issue May 5, 2016 · 7 comments
Closed

Comments

@externaltemp
Copy link

externaltemp commented May 5, 2016

Hello!
I have 512 bit private key only with modulus and privateExponent filled.
All other fields (publicExponent, prime1, prime2, exponent1, exponent2, coef) are zero.

I can use this key in Java or Python (RSA lib) to signing something without any problem, but phpseclib fall into errors like "division by zero" etc - because it's tried to use zero components.

But by RFC on RSA - zero components is normal behavior.

@terrafrost
Copy link
Member

terrafrost commented May 6, 2016

phpseclib is designed to work with private keys that don't have those fields. None-the-less I tried to reproduce the issue and was unable to do so. eg.

<?php
include('Crypt/RSA.php');

$rsa = new Crypt_RSA();
extract($rsa->createKey(512));

$rsa->loadKey($publickey);

//$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
echo bin2hex($rsa->sign('zzz'));

I don't get a "division by zero" error or anything. I tried it with PKCS1 and without PKCS1.

I tried it in the 2.0 branch as well:

<?php
include('autoloader.php');

$loader = new \Composer\Autoload\ClassLoader();
$loader->addPsr4('phpseclib\\', __DIR__ . '/phpseclib2.0');
$loader->register();

use \phpseclib\Crypt\RSA;

$rsa = new RSA();

extract($rsa->createKey(512));

//$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);

$rsa->loadKey($publickey);

echo bin2hex($rsa->sign('zzz'));

No errors / warnings / anything. Well, except for the output hex encoded output.

It's not an issue in master either:

<?php
require __DIR__ . '/vendor/autoload.php';

use phpseclib\Crypt\RSA;

extract(RSA::createKey(512));
echo bin2hex($publickey->sign('z', RSA::PADDING_PKCS1));

So if you're getting errors you're gonna have to give me some sample code.

(I'm using $publickey because that has an exponent and a modulus; it doesn't have any of the CRT parameters you're talking about)

@externaltemp
Copy link
Author

Hello!
Thank you for answer.
No problem, this is my test case:

setPrivateKeyFormat( CRYPT_RSA_PRIVATE_FORMAT_PKCS1 ); $rsa->setSignatureMode( CRYPT_RSA_SIGNATURE_PKCS1 ); $rsa->setHash( "md5" ); $rsa->setMGFHash( "md5" ); if ( !$rsa->loadKey( $prvKey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1 ) ) die( "Private key error!" ); //if ( !$rsa->loadKey( $pubKey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ) ) die( "Public key error!" ); $result = $rsa->sign( $msg ); var_dump( $result );

@externaltemp
Copy link
Author

Python test (it works fine):

import rsa

pk = """-----BEGIN RSA PRIVATE KEY-----
MIGaAgEAAkEAt5yrcHAAjhglnCEn6yecMWPeUXcMyo0+itXrLlkpcKIIyqPw546b
GThhlb1ppX1ySX/OUA4jSakHekNP5eWPawIBAAJAW6/aVD05qbsZHMvZuS2Aa5Fp
NNj0BDlf38hOtkhDzz/hkYb+EBYLLvldhgsD0OvRNy8yhz7EjaUqLCB0juIN4QIB
AAIBAAIBAAIBAAIBAA==
-----END RSA PRIVATE KEY-----"""

pkl = rsa.PrivateKey.load_pkcs1(keyfile=pk, format='PEM')
s = "dffgdfgfdgfdg"
signature = rsa.sign(message=s.encode('utf-8'), priv_key=pkl, hash='MD5')
text_file = open("signature.txt", "wb")
text_file.write( signature )
text_file.close()

@terrafrost
Copy link
Member

Here's the asn1parse results of that key:

    0:d=0  hl=3 l= 154 cons: SEQUENCE
    3:d=1  hl=2 l=   1 prim:  INTEGER           :00
    6:d=1  hl=2 l=  65 prim:  INTEGER           :00B79CAB7070008E18259C2127EB279C3163DE51770CCA8D3E8AD5EB2E592970A208CAA3F0E78E9B19386195BD69A57D72497FCE500E2349A9077A434FE5E58F6B
   73:d=1  hl=2 l=   1 prim:  INTEGER           :00
   76:d=1  hl=2 l=  64 prim:  INTEGER           :5BAFDA543D39A9BB191CCBD9B92D806B916934D8F404395FDFC84EB64843CF3FE19186FE10160B2EF95D860B03D0EBD1372F32873EC48DA52A2C20748EE20DE1
  142:d=1  hl=2 l=   1 prim:  INTEGER           :00
  145:d=1  hl=2 l=   1 prim:  INTEGER           :00
  148:d=1  hl=2 l=   1 prim:  INTEGER           :00
  151:d=1  hl=2 l=   1 prim:  INTEGER           :00
  154:d=1  hl=2 l=   1 prim:  INTEGER           :00

So the key has the fields defined - it just has them defined as 0. phpseclib supported the keys just fine if those fields weren't present at all but since they are... that's what's causing the problems.

There are two approaches to this:

terrafrost@497d5f4

That makes it so keys of this particular format are basically loaded as public keys. So if you do echo $rsa after doing $rsa->loadKey() on a key like that the string you get back will say "public key" or something to that effect.

The other approach:

terrafrost@942d194

This approach changes the conditions under which CRT-style exponentiation is done. With this approach echo $rsa should return a private key more closely resembling the one that was loaded.

@externaltemp
Copy link
Author

The second one! It works!

Man, i have no words to thank you!
You are genius! Thank you so much!

@externaltemp
Copy link
Author

externaltemp commented May 9, 2016

It's possible to simple extends Crypt_RSA by this:

class Crypt_RSA_ZC extends Crypt_RSA {
    function _exponentiate( $x ) {
        switch (true) {
            case empty($this->primes):
            case $this->primes[1]->equals($this->zero):
            case empty($this->coefficients):
            case $this->coefficients[2]->equals($this->zero):
            case empty($this->exponents):
            case $this->exponents[1]->equals($this->zero):

            return $x->modPow($this->exponent, $this->modulus);
        }

        parent::_exponentiate( $x );
    }
}

And then, simply use new Crypt_RSA_ZC() instead new Crypt_RSA()

@terrafrost
Copy link
Member

You could do that for now. I'm gonna be merging the second branch into master as time permits but will hold off on doing a release for the time being.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants