RSA: make it so you can't sign w/ public key, decrypt w/ private

This commit is contained in:
terrafrost 2018-02-15 05:29:14 -06:00
parent 63b6df29a8
commit 55384afdac
6 changed files with 190 additions and 10 deletions

View File

@ -52,6 +52,8 @@ use phpseclib\Common\Functions\Strings;
use phpseclib\File\ASN1\Maps\DigestInfo;
use phpseclib\Crypt\Common\AsymmetricKey;
use phpseclib\Exception\UnsupportedAlgorithmException;
use phpseclib\Exception\UnsupportedOperationException;
use phpseclib\Exception\NoKeyLoadedException;
/**
* Pure-PHP PKCS#1 compliant implementation of RSA.
@ -201,7 +203,6 @@ class RSA extends AsymmetricKey
*/
private $sLen;
/**
* Comment
*
@ -243,6 +244,14 @@ class RSA extends AsymmetricKey
*/
private static $defaultExponent = 65537;
/**
* Is the loaded key a public key?
*
* @var bool
* @access private
*/
private $isPublic = false;
/**
* Smallest Prime
*
@ -450,6 +459,7 @@ class RSA extends AsymmetricKey
$publickey->k = $bits >> 3;
$publickey->exponent = $e;
$publickey->publicExponent = $e;
$publickey->isPublic = true;
return compact('privatekey', 'publickey');
}
@ -475,6 +485,7 @@ class RSA extends AsymmetricKey
$this->sLen = $key->sLen;
$this->mgfHLen = $key->mgfHLen;
$this->password = $key->password;
$this->isPublic = $key->isPublic;
if (is_object($key->hash)) {
$this->hash = new Hash($key->hash->getHash());
@ -524,6 +535,7 @@ class RSA extends AsymmetricKey
return false;
}
$this->isPublic = false;
$this->modulus = $components['modulus'];
$this->k = $this->modulus->getLengthInBytes();
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
@ -669,6 +681,7 @@ class RSA extends AsymmetricKey
}
if ($key === false && !empty($this->modulus)) {
$this->isPublic = true;
$this->publicExponent = $this->exponent;
return true;
}
@ -681,6 +694,7 @@ class RSA extends AsymmetricKey
if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
$this->modulus = $components['modulus'];
$this->exponent = $this->publicExponent = $components['publicExponent'];
$this->isPublic = true;
return true;
}
@ -689,6 +703,18 @@ class RSA extends AsymmetricKey
return true;
}
/**
* Does the key self-identify as being a public key or not?
*
* @see self::isPublicKey()
* @access public
* @return bool
*/
public function isPublicKey()
{
return $this->isPublic();
}
/**
* Defines the private key
*
@ -1729,6 +1755,14 @@ class RSA extends AsymmetricKey
*/
public function encrypt($plaintext, $padding = self::PADDING_OAEP)
{
if (empty($this->modulus) || empty($this->exponent)) {
throw new NoKeyLoadedException('No key has been loaded');
}
if (!$this->isPublic) {
throw new UnsupportedOperationException('phpseclib does not allow the use of private keys to encrypt data');
}
switch ($padding) {
case self::PADDING_NONE:
return $this->raw_encrypt($plaintext);
@ -1752,6 +1786,14 @@ class RSA extends AsymmetricKey
*/
public function decrypt($ciphertext, $padding = self::PADDING_OAEP)
{
if (empty($this->modulus) || empty($this->exponent)) {
throw new NoKeyLoadedException('No key has been loaded');
}
if ($this->isPublic) {
throw new UnsupportedOperationException('phpseclib does not allow the use of public keys to decrypt data');
}
switch ($padding) {
case self::PADDING_NONE:
return $this->raw_encrypt($ciphertext);
@ -1775,7 +1817,11 @@ class RSA extends AsymmetricKey
public function sign($message, $padding = self::PADDING_PSS)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
throw new NoKeyLoadedException('No key has been loaded');
}
if ($this->isPublic) {
throw new UnsupportedOperationException('phpseclib does not allow the use of public keys to sign data');
}
switch ($padding) {
@ -1801,7 +1847,11 @@ class RSA extends AsymmetricKey
public function verify($message, $signature, $padding = self::PADDING_PSS)
{
if (empty($this->modulus) || empty($this->exponent)) {
return false;
throw new NoKeyLoadedException('No key has been loaded');
}
if (!$this->isPublic) {
throw new UnsupportedOperationException('phpseclib does not allow the use of private keys to verify data');
}
switch ($padding) {

View File

@ -0,0 +1,26 @@
<?php
/**
* NoKeyLoadedException
*
* PHP version 5
*
* @category Exception
* @package NoKeyLoadedException
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib\Exception;
/**
* NoKeyLoadedException
*
* @package NoKeyLoadedException
* @author Jim Wigginton <terrafrost@php.net>
*/
class NoKeyLoadedException extends \RuntimeException
{
}

View File

@ -0,0 +1,26 @@
<?php
/**
* UnsupportedOperationException
*
* PHP version 5
*
* @category Exception
* @package UnsupportedOperationException
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib\Exception;
/**
* UnsupportedOperationException
*
* @package UnsupportedOperationException
* @author Jim Wigginton <terrafrost@php.net>
*/
class UnsupportedOperationException extends \RuntimeException
{
}

View File

@ -518,7 +518,7 @@ class X509
switch ($algorithm) {
case 'rsaEncryption':
$cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
= Base64::encode("\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
= "\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']));
/* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
-- https://tools.ietf.org/html/rfc3279#section-2.3.1
@ -1235,6 +1235,8 @@ class X509
case 'rsaEncryption':
$rsa = new RSA();
$rsa->load($publicKey);
//zzzzz
$rsa->setPublicKey();
switch ($signatureAlgorithm) {
case 'md2WithRSAEncryption':
@ -2036,7 +2038,7 @@ class X509
switch ($algorithm) {
case 'rsaEncryption':
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
= Base64::encode("\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
= "\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']));
$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
$csr['signatureAlgorithm']['parameters'] = null;
$csr['certificationRequestInfo']['signature']['parameters'] = null;
@ -2122,7 +2124,6 @@ class X509
case 'rsaEncryption':
$this->publicKey = new RSA();
$this->publicKey->load($key);
$this->publicKey->setPublicKey();
break;
default:
$this->publicKey = null;
@ -2157,7 +2158,7 @@ class X509
switch ($algorithm) {
case 'rsaEncryption':
$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
= Base64::encode("\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
= "\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']));
}
}

View File

@ -132,4 +132,82 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
$rsa->load($rsa->getPublicKey());
$this->assertTrue($rsa->verify($plaintext, $sig));
}
/**
* @expectedException \phpseclib\Exception\UnsupportedOperationException
*/
public function testPrivateEncrypt()
{
$rsa = new RSA();
$privatekey = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
$rsa->load($privatekey);
$rsa->encrypt('hello, world!');
}
/**
* @expectedException \phpseclib\Exception\UnsupportedOperationException
*/
public function testPublicSign()
{
$rsa = new RSA();
$rsa->load('-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMuqkz8ij+ESAaNvgocVGmapjlrIldmhRo4h2NX4e6IXiCLTSxASQtY4
iqRnmyxqQSfaan2okTfQ6sP95bl8Qz8lgneW3ClC6RXG/wpJgsx7TXQ2kodlcKBF
m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE=
-----END RSA PUBLIC KEY-----');
$rsa->sign('hello, world!');
}
/**
* @expectedException \phpseclib\Exception\UnsupportedOperationException
*/
public function testPublicDecrypt()
{
$rsa = new RSA();
$rsa->load('-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMuqkz8ij+ESAaNvgocVGmapjlrIldmhRo4h2NX4e6IXiCLTSxASQtY4
iqRnmyxqQSfaan2okTfQ6sP95bl8Qz8lgneW3ClC6RXG/wpJgsx7TXQ2kodlcKBF
m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE=
-----END RSA PUBLIC KEY-----');
$rsa->decrypt('zzz');
}
/**
* @expectedException \phpseclib\Exception\UnsupportedOperationException
*/
public function testPrivateVerify()
{
$rsa = new RSA();
$privatekey = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
$rsa->load($privatekey);
$rsa->verify('hello, world!', 'dummysignature');
}
}

View File

@ -46,8 +46,7 @@ class Unit_File_X509_SPKACTest extends PhpseclibTestCase
public function testSaveSPKAC()
{
$privKey = new RSA();
extract($privKey->createKey());
extract(RSA::createKey());
$x509 = new X509();
$x509->setPrivateKey($privatekey);
@ -59,7 +58,7 @@ class Unit_File_X509_SPKACTest extends PhpseclibTestCase
$this->assertInternalType('string', $x509->saveSPKAC($spkac));
$x509 = new X509();
$x509->setPrivateKey($privKey);
$x509->setPrivateKey($privatekey);
$spkac = $x509->signSPKAC();
$this->assertInternalType('array', $spkac);