mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-12-26 03:27:31 +00:00
RSA: refactor PKCS1/PKCS8 to facilitate re-use
This commit is contained in:
parent
9d5aa56c2f
commit
863ff6789b
@ -1,12 +1,8 @@
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 5.5.9
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- 7.1
|
||||
- hhvm
|
||||
|
||||
env:
|
||||
global:
|
||||
|
@ -53,7 +53,7 @@
|
||||
"require": {
|
||||
"paragonie/constant_time_encoding": "^1|^2",
|
||||
"paragonie/random_compat": "^1.4|^2.0",
|
||||
"php": ">=5.3.3"
|
||||
"php": ">=7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phing/phing": "~2.7",
|
||||
|
80
phpseclib/Crypt/Common/PKCS.php
Normal file
80
phpseclib/Crypt/Common/PKCS.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PKCS Formatted Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Common
|
||||
* @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\Crypt\Common;
|
||||
|
||||
/**
|
||||
* PKCS1 Formatted Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
abstract class PKCS
|
||||
{
|
||||
/**
|
||||
* Auto-detect the format
|
||||
*/
|
||||
const MODE_ANY = 0;
|
||||
/**
|
||||
* Require base64-encoded PEM's be supplied
|
||||
*/
|
||||
const MODE_PEM = 1;
|
||||
/**
|
||||
* Require raw DER's be supplied
|
||||
*/
|
||||
const MODE_DER = 2;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Is the key a base-64 encoded PEM, DER or should it be auto-detected?
|
||||
*
|
||||
* @access private
|
||||
* @param int
|
||||
*/
|
||||
static $format = self::MODE_ANY;
|
||||
|
||||
/**
|
||||
* Require base64-encoded PEM's be supplied
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
static function requirePEM()
|
||||
{
|
||||
self::$format = self::MODE_PEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require raw DER's be supplied
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
static function requireDER()
|
||||
{
|
||||
self::$format = self::MODE_DER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept any format and auto detect the format
|
||||
*
|
||||
* This is the default setting
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
static function requireAny()
|
||||
{
|
||||
self::$format = self::MODE_ANY;
|
||||
}
|
||||
}
|
224
phpseclib/Crypt/Common/PKCS1.php
Normal file
224
phpseclib/Crypt/Common/PKCS1.php
Normal file
@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PKCS1 Formatted Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Common
|
||||
* @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\Crypt\Common;
|
||||
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use ParagonIE\ConstantTime\Hex;
|
||||
use phpseclib\Crypt\Common\BlockCipher;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\Base;
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\TripleDES;
|
||||
use phpseclib\File\ASN1;
|
||||
|
||||
/**
|
||||
* PKCS1 Formatted Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
abstract class PKCS1 extends PKCS
|
||||
{
|
||||
/**
|
||||
* Default encryption algorithm
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
static $defaultEncryptionAlgorithm = 'AES-128-CBC';
|
||||
|
||||
/**
|
||||
* Sets the default encryption algorithm
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function setEncryptionAlgorithm($algo)
|
||||
{
|
||||
self::$defaultEncryptionAlgorithm = $algo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mode constant corresponding to the mode string
|
||||
*
|
||||
* @access public
|
||||
* @param string $mode
|
||||
* @return int
|
||||
* @throws \UnexpectedValueException if the block cipher mode is unsupported
|
||||
*/
|
||||
static function getEncryptionMode($mode)
|
||||
{
|
||||
switch ($mode) {
|
||||
case 'CBC':
|
||||
return BlockCipher::MODE_CBC;
|
||||
case 'ECB':
|
||||
return BlockCipher::MODE_ECB;
|
||||
case 'CFB':
|
||||
return BlockCipher::MODE_CFB;
|
||||
case 'OFB':
|
||||
return BlockCipher::MODE_OFB;
|
||||
case 'CTR':
|
||||
return BlockCipher::MODE_CTR;
|
||||
}
|
||||
throw new \UnexpectedValueException('Unsupported block cipher mode of operation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cipher object corresponding to a string
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
* @return string
|
||||
* @throws \UnexpectedValueException if the encryption algorithm is unsupported
|
||||
*/
|
||||
static function getEncryptionObject($algo)
|
||||
{
|
||||
$modes = '(CBC|ECB|CFB|OFB|CTR)';
|
||||
switch (true) {
|
||||
case preg_match("#^AES-(128|192|256)-$modes$#", $algo, $matches):
|
||||
$cipher = new AES(self::getEncryptionMode($matches[2]));
|
||||
$cipher->setKeyLength($matches[1]);
|
||||
return $cipher;
|
||||
case preg_match("#^DES-EDE3-$modes$#", $algo, $matches):
|
||||
return new TripleDES(self::getEncryptionMode($matches[1]));
|
||||
case preg_match("#^DES-$modes$#", $algo, $matches):
|
||||
return new DES(self::getEncryptionMode($matches[1]));
|
||||
default:
|
||||
throw new \UnexpectedValueException('Unsupported encryption algorithmn');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a symmetric key for PKCS#1 keys
|
||||
*
|
||||
* @access public
|
||||
* @param string $password
|
||||
* @param string $iv
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
static function generateSymmetricKey($password, $iv, $length)
|
||||
{
|
||||
$symkey = '';
|
||||
$iv = substr($iv, 0, 8);
|
||||
while (strlen($symkey) < $length) {
|
||||
$symkey.= md5($symkey . $password . $iv, true);
|
||||
}
|
||||
return substr($symkey, 0, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password)
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
|
||||
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
|
||||
protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
|
||||
two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
|
||||
|
||||
http://tools.ietf.org/html/rfc1421#section-4.6.1.1
|
||||
http://tools.ietf.org/html/rfc1421#section-4.6.1.3
|
||||
|
||||
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
|
||||
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
|
||||
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
|
||||
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
|
||||
implementation are part of the standard, as well.
|
||||
|
||||
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
|
||||
if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
|
||||
$iv = Hex::decode(trim($matches[2]));
|
||||
// remove the Proc-Type / DEK-Info sections as they're no longer needed
|
||||
$key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
|
||||
$ciphertext = ASN1::extractBER($key);
|
||||
if ($ciphertext === false) {
|
||||
$ciphertext = $key;
|
||||
}
|
||||
$crypto = self::getEncryptionObject($matches[1]);
|
||||
$crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
|
||||
$crypto->setIV($iv);
|
||||
$key = $crypto->decrypt($ciphertext);
|
||||
} else {
|
||||
if (self::$format != self::MODE_DER) {
|
||||
$decoded = ASN1::extractBER($key);
|
||||
if ($decoded !== false) {
|
||||
$key = $decoded;
|
||||
} elseif (self::$format == self::MODE_PEM) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a private key appropriately
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $type
|
||||
* @param string $password
|
||||
* @return string
|
||||
*/
|
||||
static function wrapPrivateKey($key, $type, $password)
|
||||
{
|
||||
if (empty($password) || !is_string($password)) {
|
||||
return "-----BEGIN $type PRIVATE KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($key), 64) .
|
||||
"-----END $type PRIVATE KEY-----";
|
||||
}
|
||||
|
||||
$cipher = self::getEncryptionObject(self::$defaultEncryptionAlgorithm);
|
||||
$iv = Random::string($cipher->getBlockLength() >> 3);
|
||||
$cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
|
||||
$cipher->setIV($iv);
|
||||
$iv = strtoupper(Hex::encode($iv));
|
||||
return "-----BEGIN $type PRIVATE KEY-----\r\n" .
|
||||
"Proc-Type: 4,ENCRYPTED\r\n" .
|
||||
"DEK-Info: " . self::$defaultEncryptionAlgorithm . ",$iv\r\n" .
|
||||
"\r\n" .
|
||||
chunk_split(Base64::encode($cipher->encrypt($key)), 64) .
|
||||
"-----END $type PRIVATE KEY-----";
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a public key appropriately
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
static function wrapPublicKey($key, $type)
|
||||
{
|
||||
return "-----BEGIN $type PUBLIC KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($key), 64) .
|
||||
"-----END $type PUBLIC KEY-----";
|
||||
}
|
||||
}
|
713
phpseclib/Crypt/Common/PKCS8.php
Normal file
713
phpseclib/Crypt/Common/PKCS8.php
Normal file
@ -0,0 +1,713 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PKCS#8 Formatted Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
|
||||
*
|
||||
* Processes keys with the following headers:
|
||||
*
|
||||
* -----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
* -----BEGIN PRIVATE KEY-----
|
||||
* -----BEGIN PUBLIC KEY-----
|
||||
*
|
||||
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
|
||||
* is specific to private keys it's basically creating a DER-encoded wrapper
|
||||
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Common
|
||||
* @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\Crypt\Common;
|
||||
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\RC2;
|
||||
use phpseclib\Crypt\RC4;
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\TripleDES;
|
||||
use phpseclib\Crypt\Common\BlockCipher;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\File\ASN1;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
|
||||
// version is the syntax version number, for compatibility with
|
||||
// future revisions of this document. It shall be 0 for this version
|
||||
// of the document.
|
||||
define(__NAMESPACE__ . '\Version', [
|
||||
'type' => ASN1::TYPE_INTEGER,
|
||||
'mapping' => ['v1']
|
||||
]);
|
||||
|
||||
// we can replace this later once the X509 definitions are rewritten
|
||||
define(__NAMESPACE__ . '\AlgorithmIdentifier', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'algorithm' => ['type' => ASN1::TYPE_OBJECT_IDENTIFIER],
|
||||
'parameters' => [
|
||||
'type' => ASN1::TYPE_ANY,
|
||||
'optional' => true
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\PrivateKey', ['type' => ASN1::TYPE_OCTET_STRING]);
|
||||
|
||||
// we can replace this later once the X509 definitions are rewritten
|
||||
define(__NAMESPACE__ . '\AttributeType', ['type' => ASN1::TYPE_OBJECT_IDENTIFIER]);
|
||||
|
||||
// we can replace this later once the X509 definitions are rewritten
|
||||
define(__NAMESPACE__ . '\AttributeValue', ['type' => ASN1::TYPE_ANY]);
|
||||
|
||||
// we can replace this later once the X509 definitions are rewritten
|
||||
define(__NAMESPACE__ . '\Attribute', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'type' => AttributeType,
|
||||
'value'=> [
|
||||
'type' => ASN1::TYPE_SET,
|
||||
'min' => 1,
|
||||
'max' => -1,
|
||||
'children' => AttributeValue
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\Attributes', [
|
||||
'type' => ASN1::TYPE_SET,
|
||||
'children' => Attribute
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\PrivateKeyInfo', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'version' => Version,
|
||||
'privateKeyAlgorithm'=> AlgorithmIdentifier,
|
||||
'privateKey' => PrivateKey,
|
||||
'attributes' => [
|
||||
'constant' => 0,
|
||||
'optional' => true,
|
||||
'implicit' => true
|
||||
] + Attributes
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\EncryptedData', ['type' => ASN1::TYPE_OCTET_STRING]);
|
||||
|
||||
define(__NAMESPACE__ . '\EncryptedPrivateKeyInfo', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'encryptionAlgorithm' => AlgorithmIdentifier,
|
||||
'encryptedData' => EncryptedData
|
||||
]
|
||||
]);
|
||||
|
||||
// this format is not formally defined anywhere but is none-the-less the form you
|
||||
// get when you do "openssl rsa -in private.pem -outform PEM -pubout"
|
||||
define(__NAMESPACE__ . '\PublicKeyInfo', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'publicKeyAlgorithm'=> AlgorithmIdentifier,
|
||||
'publicKey' => ['type' => ASN1::TYPE_BIT_STRING]
|
||||
]
|
||||
]);
|
||||
|
||||
// from https://tools.ietf.org/html/rfc2898#appendix-A.3
|
||||
define(__NAMESPACE__ . '\PBEParameter', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'salt' => ['type' => ASN1::TYPE_OCTET_STRING],
|
||||
'iterationCount' => ['type' => ASN1::TYPE_INTEGER]
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\PBES2params', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'keyDerivationFunc'=> AlgorithmIdentifier,
|
||||
'encryptionScheme' => AlgorithmIdentifier
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\PBMAC1params', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'keyDerivationFunc'=> AlgorithmIdentifier,
|
||||
'messageAuthScheme'=> AlgorithmIdentifier
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\RC2CBCParameter', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'rc2ParametersVersion'=> [
|
||||
'type' => ASN1::TYPE_INTEGER,
|
||||
'optional' => true
|
||||
],
|
||||
'iv'=> ['type' => ASN1::TYPE_OCTET_STRING]
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\PBKDF2params', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
// technically, this is a CHOICE in RFC2898 but the other "choice" is, currently, more of a placeholder
|
||||
// in the RFC
|
||||
'salt'=> ['type' => ASN1::TYPE_OCTET_STRING],
|
||||
'iterationCount'=> ['type' => ASN1::TYPE_INTEGER],
|
||||
'keyLength' => [
|
||||
'type' => ASN1::TYPE_INTEGER,
|
||||
'optional' => true
|
||||
],
|
||||
'prf' => AlgorithmIdentifier + ['optional' => true]
|
||||
]
|
||||
]);
|
||||
|
||||
// from https://tools.ietf.org/html/rfc2898
|
||||
define(__NAMESPACE__ . '\oids', [
|
||||
// PBES1 encryption schemes
|
||||
'1.2.840.113549.1.5.1' => 'pbeWithMD2AndDES-CBC',
|
||||
'1.2.840.113549.1.5.4' => 'pbeWithMD2AndRC2-CBC',
|
||||
'1.2.840.113549.1.5.3' => 'pbeWithMD5AndDES-CBC',
|
||||
'1.2.840.113549.1.5.6' => 'pbeWithMD5AndRC2-CBC',
|
||||
'1.2.840.113549.1.5.10'=> 'pbeWithSHA1AndDES-CBC',
|
||||
'1.2.840.113549.1.5.11'=> 'pbeWithSHA1AndRC2-CBC',
|
||||
|
||||
// from PKCS#12:
|
||||
// https://tools.ietf.org/html/rfc7292
|
||||
'1.2.840.113549.1.12.1.1' => 'pbeWithSHAAnd128BitRC4',
|
||||
'1.2.840.113549.1.12.1.2' => 'pbeWithSHAAnd40BitRC4',
|
||||
'1.2.840.113549.1.12.1.3' => 'pbeWithSHAAnd3-KeyTripleDES-CBC',
|
||||
'1.2.840.113549.1.12.1.4' => 'pbeWithSHAAnd2-KeyTripleDES-CBC',
|
||||
'1.2.840.113549.1.12.1.5' => 'pbeWithSHAAnd128BitRC2-CBC',
|
||||
'1.2.840.113549.1.12.1.6' => 'pbeWithSHAAnd40BitRC2-CBC',
|
||||
|
||||
'1.2.840.113549.1.5.12' => 'id-PBKDF2',
|
||||
'1.2.840.113549.1.5.13' => 'id-PBES2',
|
||||
'1.2.840.113549.1.5.14' => 'id-PBMAC1',
|
||||
|
||||
// from PKCS#5 v2.1:
|
||||
// http://www.rsa.com/rsalabs/pkcs/files/h11302-wp-pkcs5v2-1-password-based-cryptography-standard.pdf
|
||||
'1.2.840.113549.2.7' => 'id-hmacWithSHA1',
|
||||
'1.2.840.113549.2.8' => 'id-hmacWithSHA224',
|
||||
'1.2.840.113549.2.9' => 'id-hmacWithSHA256',
|
||||
'1.2.840.113549.2.10'=> 'id-hmacWithSHA384',
|
||||
'1.2.840.113549.2.11'=> 'id-hmacWithSHA512',
|
||||
'1.2.840.113549.2.12'=> 'id-hmacWithSHA512-224',
|
||||
'1.2.840.113549.2.13'=> 'id-hmacWithSHA512-256',
|
||||
|
||||
'1.3.14.3.2.7' => 'desCBC',
|
||||
'1.2.840.113549.3.7' => 'des-EDE3-CBC',
|
||||
'1.2.840.113549.3.2' => 'rc2CBC',
|
||||
'1.2.840.113549.3.9' => 'rc5-CBC-PAD',
|
||||
|
||||
'2.16.840.1.101.3.4.1.2' => 'aes128-CBC-PAD',
|
||||
'2.16.840.1.101.3.4.1.22'=> 'aes192-CBC-PAD',
|
||||
'2.16.840.1.101.3.4.1.42'=> 'aes256-CBC-PAD'
|
||||
]);
|
||||
|
||||
/**
|
||||
* PKCS#8 Formatted Key Handler
|
||||
*
|
||||
* @package Common
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PKCS8 extends PKCS
|
||||
{
|
||||
/**
|
||||
* Default encryption algorithm
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
static $defaultEncryptionAlgorithm = 'id-PBES2';
|
||||
|
||||
/**
|
||||
* Default encryption scheme
|
||||
*
|
||||
* Only used when defaultEncryptionAlgorithm is id-PBES2
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
static $defaultEncryptionScheme = 'aes128-CBC-PAD';
|
||||
|
||||
/**
|
||||
* Default PRF
|
||||
*
|
||||
* Only used when defaultEncryptionAlgorithm is id-PBES2
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
static $defaultPRF = 'id-hmacWithSHA256';
|
||||
|
||||
/**
|
||||
* Default Iteration Count
|
||||
*
|
||||
* @var int
|
||||
* @access private
|
||||
*/
|
||||
static $defaultIterationCount = 2048;
|
||||
|
||||
/**
|
||||
* Sets the default encryption algorithm
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function setEncryptionAlgorithm($algo)
|
||||
{
|
||||
self::$defaultEncryptionAlgorithm = $algo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default encryption algorithm for PBES2
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function setEncryptionScheme($algo)
|
||||
{
|
||||
self::$defaultEncryptionScheme = $algo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the iteration count
|
||||
*
|
||||
* @access public
|
||||
* @param int $count
|
||||
*/
|
||||
static function setIterationCount($count)
|
||||
{
|
||||
self::$defaultIterationCount = $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the PRF for PBES2
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function setPRF($algo)
|
||||
{
|
||||
self::$defaultPRF = $algo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SymmetricKey object based on a PBES1 $algo
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function getPBES1EncryptionObject($algo)
|
||||
{
|
||||
$algo = preg_match('#^pbeWith(?:MD2|MD5|SHA1|SHA)And(.*?)-CBC$#', $algo, $matches) ?
|
||||
$matches[1] :
|
||||
substr($algo, 13); // strlen('pbeWithSHAAnd') == 13
|
||||
|
||||
switch ($algo) {
|
||||
case 'DES':
|
||||
$cipher = new DES(BlockCipher::MODE_CBC);
|
||||
break;
|
||||
case 'RC2':
|
||||
$cipher = new RC2(BlockCipher::MODE_CBC);
|
||||
break;
|
||||
case '3-KeyTripleDES':
|
||||
$cipher = new TripleDES(BlockCipher::MODE_CBC);
|
||||
break;
|
||||
case '2-KeyTripleDES':
|
||||
$cipher = new TripleDES(BlockCipher::MODE_CBC);
|
||||
$cipher->setKeyLength(128);
|
||||
break;
|
||||
case '128BitRC2':
|
||||
$cipher = new RC2(BlockCipher::MODE_CBC);
|
||||
$cipher->setKeyLength(128);
|
||||
break;
|
||||
case '40BitRC2':
|
||||
$cipher = new RC2(BlockCipher::MODE_CBC);
|
||||
$cipher->setKeyLength(40);
|
||||
break;
|
||||
case '128BitRC4':
|
||||
$cipher = new RC4();
|
||||
$cipher->setKeyLength(128);
|
||||
break;
|
||||
case '40BitRC4':
|
||||
$cipher = new RC4();
|
||||
$cipher->setKeyLength(40);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException("$algo is not a supported algorithm");
|
||||
}
|
||||
|
||||
return $cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash based on a PBES1 $algo
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function getPBES1Hash($algo)
|
||||
{
|
||||
if (preg_match('#^pbeWith(MD2|MD5|SHA1|SHA)And.*?-CBC$#', $algo, $matches)) {
|
||||
return $matches[1] == 'SHA' ? 'sha1' : $matches[1];
|
||||
}
|
||||
|
||||
return 'sha1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a KDF baesd on a PBES1 $algo
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function getPBES1KDF($algo)
|
||||
{
|
||||
switch ($algo) {
|
||||
case 'pbeWithMD2AndDES-CBC':
|
||||
case 'pbeWithMD2AndRC2-CBC':
|
||||
case 'pbeWithMD5AndDES-CBC':
|
||||
case 'pbeWithMD5AndRC2-CBC':
|
||||
case 'pbeWithSHA1AndDES-CBC':
|
||||
case 'pbeWithSHA1AndRC2-CBC':
|
||||
return 'pbkdf1';
|
||||
}
|
||||
|
||||
return 'pkcs12';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SymmetricKey object baesd on a PBES2 $algo
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
*/
|
||||
static function getPBES2EncryptionObject($algo)
|
||||
{
|
||||
switch ($algo) {
|
||||
case 'desCBC':
|
||||
$cipher = new TripleDES(BlockCipher::MODE_CBC);
|
||||
break;
|
||||
case 'des-EDE3-CBC':
|
||||
$cipher = new TripleDES(BlockCipher::MODE_CBC);
|
||||
break;
|
||||
case 'rc2CBC':
|
||||
$cipher = new RC2(BlockCipher::MODE_CBC);
|
||||
// in theory this can be changed
|
||||
$cipher->setKeyLength(128);
|
||||
break;
|
||||
case 'rc5-CBC-PAD':
|
||||
throw new UnsupportedAlgorithmException('rc5-CBC-PAD is not supported for PBES2 PKCS#8 keys');
|
||||
case 'aes128-CBC-PAD':
|
||||
case 'aes192-CBC-PAD':
|
||||
case 'aes256-CBC-PAD':
|
||||
$cipher = new AES(BlockCipher::MODE_CBC);
|
||||
$cipher->setKeyLength(substr($algo, 3, 3));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException("$algo is not supported");
|
||||
}
|
||||
|
||||
return $cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::$format != self::MODE_DER) {
|
||||
$decoded = ASN1::extractBER($key);
|
||||
if ($decoded !== false) {
|
||||
$key = $decoded;
|
||||
} elseif (self::$format == self::MODE_PEM) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$asn1 = new ASN1();
|
||||
$decoded = $asn1->decodeBER($key);
|
||||
if (empty($decoded)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$meta = [];
|
||||
|
||||
$asn1->loadOIDs(oids);
|
||||
$decrypted = $asn1->asn1map($decoded[0], EncryptedPrivateKeyInfo);
|
||||
if (strlen($password) && is_array($decrypted)) {
|
||||
$algorithm = $decrypted['encryptionAlgorithm']['algorithm'];
|
||||
switch ($algorithm) {
|
||||
// PBES1
|
||||
case 'pbeWithMD2AndDES-CBC':
|
||||
case 'pbeWithMD2AndRC2-CBC':
|
||||
case 'pbeWithMD5AndDES-CBC':
|
||||
case 'pbeWithMD5AndRC2-CBC':
|
||||
case 'pbeWithSHA1AndDES-CBC':
|
||||
case 'pbeWithSHA1AndRC2-CBC':
|
||||
case 'pbeWithSHAAnd3-KeyTripleDES-CBC':
|
||||
case 'pbeWithSHAAnd2-KeyTripleDES-CBC':
|
||||
case 'pbeWithSHAAnd128BitRC2-CBC':
|
||||
case 'pbeWithSHAAnd40BitRC2-CBC':
|
||||
case 'pbeWithSHAAnd128BitRC4':
|
||||
case 'pbeWithSHAAnd40BitRC4':
|
||||
$cipher = self::getPBES1EncryptionObject($algorithm);
|
||||
$hash = self::getPBES1Hash($algorithm);
|
||||
$kdf = self::getPBES1KDF($algorithm);
|
||||
|
||||
$meta['meta']['algorithm'] = $algorithm;
|
||||
|
||||
$temp = $asn1->decodeBER($decrypted['encryptionAlgorithm']['parameters']);
|
||||
extract($asn1->asn1map($temp[0], PBEParameter));
|
||||
$iterationCount = (int) $iterationCount->toString();
|
||||
$cipher->setPassword($password, $kdf, $hash, Base64::decode($salt), $iterationCount);
|
||||
$key = $cipher->decrypt(Base64::decode($decrypted['encryptedData']));
|
||||
$decoded = $asn1->decodeBER($key);
|
||||
if (empty($decoded)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
case 'id-PBES2':
|
||||
$meta['meta']['algorithm'] = $algorithm;
|
||||
|
||||
$temp = $asn1->decodeBER($decrypted['encryptionAlgorithm']['parameters']);
|
||||
$temp = $asn1->asn1map($temp[0], PBES2params);
|
||||
extract($temp);
|
||||
|
||||
$cipher = self::getPBES2EncryptionObject($encryptionScheme['algorithm']);
|
||||
$meta['meta']['cipher'] = $encryptionScheme['algorithm'];
|
||||
|
||||
$temp = $asn1->decodeBER($decrypted['encryptionAlgorithm']['parameters']);
|
||||
$temp = $asn1->asn1map($temp[0], PBES2params);
|
||||
extract($temp);
|
||||
|
||||
if (!$cipher instanceof RC2) {
|
||||
$cipher->setIV(Base64::decode($encryptionScheme['parameters']['octetString']));
|
||||
} else {
|
||||
$temp = $asn1->decodeBER($encryptionScheme['parameters']);
|
||||
extract($asn1->asn1map($temp[0], RC2CBCParameter));
|
||||
$effectiveKeyLength = (int) $rc2ParametersVersion->toString();
|
||||
switch ($effectiveKeyLength) {
|
||||
case 160:
|
||||
$effectiveKeyLength = 40;
|
||||
break;
|
||||
case 120:
|
||||
$effectiveKeyLength = 64;
|
||||
break;
|
||||
case 58:
|
||||
$effectiveKeyLength = 128;
|
||||
break;
|
||||
//default: // should be >= 256
|
||||
}
|
||||
$cipher->setIV(Base64::decode($iv));
|
||||
$cipher->setKeyLength($effectiveKeyLength);
|
||||
}
|
||||
|
||||
$meta['meta']['keyDerivationFunc'] = $keyDerivationFunc['algorithm'];
|
||||
switch ($keyDerivationFunc['algorithm']) {
|
||||
case 'id-PBKDF2':
|
||||
$temp = $asn1->decodeBER($keyDerivationFunc['parameters']);
|
||||
$prf = ['algorithm' => 'id-hmacWithSHA1'];
|
||||
$params = $asn1->asn1map($temp[0], PBKDF2params);
|
||||
extract($params);
|
||||
$meta['meta']['prf'] = $prf['algorithm'];
|
||||
$hash = str_replace('-', '/', substr($prf['algorithm'], 11));
|
||||
$params = [
|
||||
$password,
|
||||
'pbkdf2',
|
||||
$hash,
|
||||
Base64::decode($salt),
|
||||
(int) $iterationCount->toString()
|
||||
];
|
||||
if (isset($keyLength)) {
|
||||
$params[] = (int) $keyLength->toString();
|
||||
}
|
||||
call_user_func_array([$cipher, 'setPassword'], $params);
|
||||
$key = $cipher->decrypt(Base64::decode($decrypted['encryptedData']));
|
||||
$decoded = $asn1->decodeBER($key);
|
||||
if (empty($decoded)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('Only PBKDF2 is supported for PBES2 PKCS#8 keys');
|
||||
}
|
||||
break;
|
||||
case 'id-PBMAC1':
|
||||
//$temp = $asn1->decodeBER($decrypted['encryptionAlgorithm']['parameters']);
|
||||
//$value = $asn1->asn1map($temp[0], PBMAC1params);
|
||||
// since i can't find any implementation that does PBMAC1 it is unsupported
|
||||
throw new UnsupportedAlgorithmException('Only PBES1 and PBES2 PKCS#8 keys are supported.');
|
||||
// at this point we'll assume that the key conforms to PublicKeyInfo
|
||||
}
|
||||
}
|
||||
|
||||
$private = $asn1->asn1map($decoded[0], PrivateKeyInfo);
|
||||
if (is_array($private)) {
|
||||
return $private + $meta;
|
||||
}
|
||||
|
||||
// EncryptedPrivateKeyInfo and PublicKeyInfo have largely identical "signatures". the only difference
|
||||
// is that the former has an octet string and the later has a bit string. the first byte of a bit
|
||||
// string represents the number of bits in the last byte that are to be ignored but, currently,
|
||||
// bit strings wanting a non-zero amount of bits trimmed are not supported
|
||||
$public = $asn1->asn1map($decoded[0], PublicKeyInfo);
|
||||
if (is_array($public)) {
|
||||
$public['publicKey'] = base64_decode($public['publicKey']);
|
||||
if ($public['publicKey'][0] != "\0") {
|
||||
return false;
|
||||
}
|
||||
$public['publicKey'] = base64_encode(substr($public['publicKey'], 1));
|
||||
return $public;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a private key appropriately
|
||||
*
|
||||
* @access public
|
||||
* @param string $algorithm
|
||||
* @param string $key
|
||||
* @param string $attr
|
||||
* @param string $password
|
||||
* @return string
|
||||
*/
|
||||
static function wrapPrivateKey($key, $algorithm, $attr, $password)
|
||||
{
|
||||
$asn1 = new ASN1();
|
||||
$asn1->loadOIDs(oids);
|
||||
|
||||
$key = [
|
||||
'version' => 'v1',
|
||||
'privateKeyAlgorithm' => ['algorithm' => $algorithm], // parameters are not currently supported
|
||||
'privateKey' => Base64::encode($key)
|
||||
];
|
||||
if (!empty($attr)) {
|
||||
$key['attributes'] = $attr;
|
||||
}
|
||||
$key = $asn1->encodeDER($key, PrivateKeyInfo);
|
||||
if (!empty($password) && is_string($password)) {
|
||||
$salt = Random::string(8);
|
||||
$iterationCount = self::$defaultIterationCount;
|
||||
|
||||
if (self::$defaultEncryptionAlgorithm == 'id-PBES2') {
|
||||
$crypto = self::getPBES2EncryptionObject(self::$defaultEncryptionScheme);
|
||||
$hash = str_replace('-', '/', substr(self::$defaultPRF, 11));
|
||||
$kdf = 'pbkdf2';
|
||||
$iv = Random::string($crypto->getBlockLength() >> 3);
|
||||
|
||||
$PBKDF2params = [
|
||||
'salt' => Base64::encode($salt),
|
||||
'iterationCount' => $iterationCount,
|
||||
'prf' => ['algorithm' => self::$defaultPRF, 'parameters' => null]
|
||||
];
|
||||
$PBKDF2params = $asn1->encodeDER($PBKDF2params, PBKDF2params);
|
||||
|
||||
if (!$crypto instanceof RC2) {
|
||||
$params = ['octetString' => Base64::encode($iv)];
|
||||
} else {
|
||||
$params = [
|
||||
'rc2ParametersVersion' => 58,
|
||||
'iv' => Base64::encode($iv)
|
||||
];
|
||||
$params = $asn1->encodeDER($params, RC2CBCParameter);
|
||||
$params = new ASN1\Element($params);
|
||||
}
|
||||
|
||||
$params = [
|
||||
'keyDerivationFunc' => [
|
||||
'algorithm' => 'id-PBKDF2',
|
||||
'parameters' => new ASN1\Element($PBKDF2params)
|
||||
],
|
||||
'encryptionScheme' => [
|
||||
'algorithm' => self::$defaultEncryptionScheme,
|
||||
'parameters' => $params
|
||||
]
|
||||
];
|
||||
$params = $asn1->encodeDER($params, PBES2params);
|
||||
|
||||
$crypto->setIV($iv);
|
||||
} else {
|
||||
$crypto = self::getPBES1EncryptionObject(self::$defaultEncryptionAlgorithm);
|
||||
$hash = self::getPBES1Hash(self::$defaultEncryptionAlgorithm);
|
||||
$kdf = self::getPBES1KDF(self::$defaultEncryptionAlgorithm);
|
||||
|
||||
$params = [
|
||||
'salt' => Base64::encode($salt),
|
||||
'iterationCount' => $iterationCount
|
||||
];
|
||||
$params = $asn1->encodeDER($params, PBEParameter);
|
||||
}
|
||||
$crypto->setPassword($password, $kdf, $hash, $salt, $iterationCount);
|
||||
$key = $crypto->encrypt($key);
|
||||
|
||||
$key = [
|
||||
'encryptionAlgorithm' => [
|
||||
'algorithm' => self::$defaultEncryptionAlgorithm,
|
||||
'parameters' => new ASN1\Element($params)
|
||||
],
|
||||
'encryptedData' => Base64::encode($key)
|
||||
];
|
||||
|
||||
$key = $asn1->encodeDER($key, EncryptedPrivateKeyInfo);
|
||||
|
||||
return "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($key), 64) .
|
||||
"-----END ENCRYPTED PRIVATE KEY-----";
|
||||
}
|
||||
|
||||
return "-----BEGIN PRIVATE KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($key), 64) .
|
||||
"-----END PRIVATE KEY-----";
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a public key appropriately
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
static function wrapPublicKey($key, $algorithm)
|
||||
{
|
||||
$asn1 = new ASN1();
|
||||
|
||||
$key = [
|
||||
'publicKeyAlgorithm' => [
|
||||
'algorithm' => $algorithm,
|
||||
'parameters' => null // parameters are not currently supported
|
||||
],
|
||||
'publicKey' => Base64::encode("\0" . $key)
|
||||
];
|
||||
|
||||
$key = $asn1->encodeDER($key, PublicKeyInfo);
|
||||
|
||||
return "-----BEGIN PUBLIC KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($key), 64) .
|
||||
"-----END PUBLIC KEY-----";
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ namespace phpseclib\Crypt\Common;
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Common\Functions\Strings;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
* Base Class for all \phpseclib\Crypt\* cipher classes
|
||||
@ -512,7 +513,7 @@ abstract class SymmetricKey
|
||||
throw new \InvalidArgumentException('This mode does not require an IV.');
|
||||
}
|
||||
|
||||
if ($this->mode == self::MODE_STREAM && $this->usesIV()) {
|
||||
if (!$this->usesIV()) {
|
||||
throw new \InvalidArgumentException('This algorithm does not use an IV.');
|
||||
}
|
||||
|
||||
@ -622,12 +623,17 @@ abstract class SymmetricKey
|
||||
{
|
||||
$key = '';
|
||||
|
||||
$method = strtolower($method);
|
||||
switch ($method) {
|
||||
default: // 'pbkdf2' or 'pbkdf1'
|
||||
case 'pkcs12': // from https://tools.ietf.org/html/rfc7292#appendix-B.2
|
||||
case 'pbkdf1':
|
||||
case 'pbkdf2':
|
||||
$func_args = func_get_args();
|
||||
|
||||
// Hash function
|
||||
$hash = isset($func_args[2]) ? $func_args[2] : 'sha1';
|
||||
$hash = isset($func_args[2]) ? strtolower($func_args[2]) : 'sha1';
|
||||
$hashObj = new Hash();
|
||||
$hashObj->setHash($hash);
|
||||
|
||||
// WPA and WPA2 use the SSID as the salt
|
||||
$salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
|
||||
@ -645,10 +651,63 @@ abstract class SymmetricKey
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case $method == 'pkcs12':
|
||||
/*
|
||||
In this specification, however, all passwords are created from
|
||||
BMPStrings with a NULL terminator. This means that each character in
|
||||
the original BMPString is encoded in 2 bytes in big-endian format
|
||||
(most-significant byte first). There are no Unicode byte order
|
||||
marks. The 2 bytes produced from the last character in the BMPString
|
||||
are followed by 2 additional bytes with the value 0x00.
|
||||
|
||||
-- https://tools.ietf.org/html/rfc7292#appendix-B.1
|
||||
*/
|
||||
$password = "\0". chunk_split($password, 1, "\0") . "\0";
|
||||
|
||||
/*
|
||||
This standard specifies 3 different values for the ID byte mentioned
|
||||
above:
|
||||
|
||||
1. If ID=1, then the pseudorandom bits being produced are to be used
|
||||
as key material for performing encryption or decryption.
|
||||
|
||||
2. If ID=2, then the pseudorandom bits being produced are to be used
|
||||
as an IV (Initial Value) for encryption or decryption.
|
||||
|
||||
3. If ID=3, then the pseudorandom bits being produced are to be used
|
||||
as an integrity key for MACing.
|
||||
*/
|
||||
// Construct a string, D (the "diversifier"), by concatenating v/8
|
||||
// copies of ID.
|
||||
$blockLength = $hashObj->getBlockLengthInBytes();
|
||||
$d1 = str_repeat(chr(1), $blockLength);
|
||||
$d2 = str_repeat(chr(2), $blockLength);
|
||||
$s = '';
|
||||
if (strlen($salt)) {
|
||||
while (strlen($s) < $blockLength) {
|
||||
$s.= $salt;
|
||||
}
|
||||
}
|
||||
$s = substr($s, 0, $blockLength);
|
||||
|
||||
$p = '';
|
||||
if (strlen($password)) {
|
||||
while (strlen($p) < $blockLength) {
|
||||
$p.= $password;
|
||||
}
|
||||
}
|
||||
$p = substr($p, 0, $blockLength);
|
||||
|
||||
$i = $s . $p;
|
||||
|
||||
$this->setKey(self::_pkcs12helper($dkLen, $hashObj, $i, $d1, $count));
|
||||
if ($this->usesIV()) {
|
||||
$this->setIV(self::_pkcs12helper($this->block_size, $hashObj, $i, $d2, $count));
|
||||
}
|
||||
|
||||
return true;
|
||||
case $method == 'pbkdf1':
|
||||
$hashObj = new Hash();
|
||||
$hashObj->setHash($hash);
|
||||
if ($dkLen > $hashObj->getLength()) {
|
||||
if ($dkLen > $hashObj->getLengthInBytes()) {
|
||||
throw new \LengthException('Derived key length cannot be longer than the hash length');
|
||||
}
|
||||
$t = $password . $salt;
|
||||
@ -658,21 +717,20 @@ abstract class SymmetricKey
|
||||
$key = substr($t, 0, $dkLen);
|
||||
|
||||
$this->setKey(substr($key, 0, $dkLen >> 1));
|
||||
$this->setIV(substr($key, $dkLen >> 1));
|
||||
if ($this->usesIV()) {
|
||||
$this->setIV(substr($key, $dkLen >> 1));
|
||||
}
|
||||
|
||||
return true;
|
||||
// Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
|
||||
case !function_exists('hash_pbkdf2'):
|
||||
case !function_exists('hash_algos'):
|
||||
case !in_array($hash, hash_algos()):
|
||||
$i = 1;
|
||||
$hashObj->setKey($password);
|
||||
while (strlen($key) < $dkLen) {
|
||||
$hmac = new Hash();
|
||||
$hmac->setHash($hash);
|
||||
$hmac->setKey($password);
|
||||
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
||||
$f = $u = $hashObj->hash($salt . pack('N', $i++));
|
||||
for ($j = 2; $j <= $count; ++$j) {
|
||||
$u = $hmac->hash($u);
|
||||
$u = $hashObj->hash($u);
|
||||
$f^= $u;
|
||||
}
|
||||
$key.= $f;
|
||||
@ -682,6 +740,9 @@ abstract class SymmetricKey
|
||||
default:
|
||||
$key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException($method . ' is not a supported password hashing method');
|
||||
}
|
||||
|
||||
$this->setKey($key);
|
||||
@ -689,6 +750,60 @@ abstract class SymmetricKey
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* PKCS#12 KDF Helper Function
|
||||
*
|
||||
* As discussed here:
|
||||
*
|
||||
* {@link https://tools.ietf.org/html/rfc7292#appendix-B}
|
||||
*
|
||||
* @see self::setPassword()
|
||||
* @access private
|
||||
* @param int $n
|
||||
* @param \phpseclib\Crypt\Hash $hashObj
|
||||
* @param string $i
|
||||
* @param string $d
|
||||
* @param int $count
|
||||
* @return string $a
|
||||
*/
|
||||
static function _pkcs12helper($n, $hashObj, $i, $d, $count)
|
||||
{
|
||||
static $one;
|
||||
if (!isset($one)) {
|
||||
$one = new BigInteger(1);
|
||||
}
|
||||
|
||||
$blockLength = $hashObj->getBlockLength() >> 3;
|
||||
|
||||
$c = ceil($n / $hashObj->getLengthInBytes());
|
||||
$a = '';
|
||||
for ($j = 1; $j <= $c; $j++) {
|
||||
$ai = $d . $i;
|
||||
for ($k = 0; $k < $count; $k++) {
|
||||
$ai = $hashObj->hash($ai);
|
||||
}
|
||||
$b = '';
|
||||
while (strlen($b) < $blockLength) {
|
||||
$b.= $ai;
|
||||
}
|
||||
$b = substr($b, 0, $blockLength);
|
||||
$b = new BigInteger($b, 256);
|
||||
$newi = '';
|
||||
for ($k = 0; $k < strlen($i); $k+= $blockLength) {
|
||||
$temp = substr($i, $k, $blockLength);
|
||||
$temp = new BigInteger($temp, 256);
|
||||
$temp->setPrecision($blockLength << 3);
|
||||
$temp = $temp->add($b);
|
||||
$temp = $temp->add($one);
|
||||
$newi.= $temp->toBytes(false);
|
||||
}
|
||||
$i = $newi;
|
||||
$a.= $ai;
|
||||
}
|
||||
|
||||
return substr($a, 0, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a message.
|
||||
*
|
||||
|
@ -203,6 +203,23 @@ class Hash
|
||||
);
|
||||
}
|
||||
|
||||
switch ($hash) {
|
||||
case 'md2-96':
|
||||
case 'md5-96':
|
||||
case 'sha1-96':
|
||||
case 'sha224-96':
|
||||
case 'sha256-96':
|
||||
case 'md2':
|
||||
case 'md5':
|
||||
case 'sha1':
|
||||
case 'sha224':
|
||||
case 'sha256':
|
||||
$this->blockSize = 512;
|
||||
break;
|
||||
default:
|
||||
$this->blockSize = 1024;
|
||||
}
|
||||
|
||||
if ($hash == 'sha512/224' || $hash == 'sha512/256') {
|
||||
// from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24
|
||||
$this->initial = $hash == 'sha512/256' ?
|
||||
@ -264,16 +281,49 @@ class Hash
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash length (in bytes)
|
||||
* Returns the hash length (in bits)
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
function getLength()
|
||||
{
|
||||
return $this->length << 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash length (in bytes)
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
function getLengthInBytes()
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block length (in bits)
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
function getBlockLength()
|
||||
{
|
||||
return $this->blockSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the block length (in bytes)
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
function getBlockLengthInBytes()
|
||||
{
|
||||
return $this->blockSize >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of SHA512
|
||||
*
|
||||
|
@ -319,6 +319,7 @@ class RC2 extends BlockCipher
|
||||
}
|
||||
|
||||
$this->default_key_length = $this->current_key_length = $length;
|
||||
$this->explicit_key_length = $length >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -340,9 +341,6 @@ class RC2 extends BlockCipher
|
||||
* has more then 128 bytes in it, and set $key to a single null byte if
|
||||
* it is empty.
|
||||
*
|
||||
* If the key is not explicitly set, it'll be assumed to be a single
|
||||
* null byte.
|
||||
*
|
||||
* @see \phpseclib\Crypt\Common\SymmetricKey::setKey()
|
||||
* @access public
|
||||
* @param string $key
|
||||
@ -362,8 +360,10 @@ class RC2 extends BlockCipher
|
||||
}
|
||||
|
||||
$this->current_key_length = $t1;
|
||||
// Key byte count should be 1..128.
|
||||
$key = strlen($key) ? substr($key, 0, 128) : "\x00";
|
||||
if (strlen($key) < 1 || strlen($key) > 128) {
|
||||
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes between 8 and 1024 bits, inclusive, are supported');
|
||||
}
|
||||
|
||||
$t = strlen($key);
|
||||
|
||||
// The mcrypt RC2 implementation only supports effective key length
|
||||
@ -392,7 +392,10 @@ class RC2 extends BlockCipher
|
||||
$l[0] = $this->invpitable[$l[0]];
|
||||
array_unshift($l, 'C*');
|
||||
|
||||
parent::setKey(call_user_func_array('pack', $l));
|
||||
$this->key = call_user_func_array('pack', $l);
|
||||
$this->key_length = strlen($this->key);
|
||||
$this->changed = true;
|
||||
$this->_setEngine();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,7 +109,7 @@ class RC4 extends StreamCipher
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $key = "\0";
|
||||
var $key;
|
||||
|
||||
/**
|
||||
* The Key Stream for decryption and encryption
|
||||
|
@ -118,32 +118,6 @@ class RSA
|
||||
const PADDING_RELAXED_PKCS1 = 5;
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see self::createKey()
|
||||
*/
|
||||
/**
|
||||
* ASN1 Integer
|
||||
*/
|
||||
const ASN1_INTEGER = 2;
|
||||
/**
|
||||
* ASN1 Bit String
|
||||
*/
|
||||
const ASN1_BITSTRING = 3;
|
||||
/**
|
||||
* ASN1 Octet String
|
||||
*/
|
||||
const ASN1_OCTETSTRING = 4;
|
||||
/**
|
||||
* ASN1 Object Identifier
|
||||
*/
|
||||
const ASN1_OBJECT = 6;
|
||||
/**
|
||||
* ASN1 Sequence (with the constucted bit set)
|
||||
*/
|
||||
const ASN1_SEQUENCE = 48;
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see self::__construct()
|
||||
@ -151,13 +125,13 @@ class RSA
|
||||
/**
|
||||
* To use the pure-PHP implementation
|
||||
*/
|
||||
const MODE_INTERNAL = 1;
|
||||
const ENGINE_INTERNAL = 1;
|
||||
/**
|
||||
* To use the OpenSSL library
|
||||
*
|
||||
* (if enabled; otherwise, the internal implementation will be used)
|
||||
*/
|
||||
const MODE_OPENSSL = 2;
|
||||
const ENGINE_OPENSSL = 2;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
@ -182,7 +156,7 @@ class RSA
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
var $privateKeyFormat = 'PKCS1';
|
||||
var $privateKeyFormat = 'PKCS8';
|
||||
|
||||
/**
|
||||
* Public Key Format
|
||||
@ -341,6 +315,39 @@ class RSA
|
||||
*/
|
||||
static $origFileFormats = false;
|
||||
|
||||
/**
|
||||
* Public exponent
|
||||
*
|
||||
* @var int
|
||||
* @link http://en.wikipedia.org/wiki/65537_%28number%29
|
||||
* @access private
|
||||
*/
|
||||
static $defaultExponent = 65537;
|
||||
|
||||
/**
|
||||
* Smallest Prime
|
||||
*
|
||||
* Per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
|
||||
* than 256 bits. As a consequence if the key you're trying to create is 1024 bits and you've set smallestPrime
|
||||
* to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). At least if
|
||||
* engine is set to self::ENGINE_INTERNAL. If Engine is set to self::ENGINE_OPENSSL then smallest Prime is
|
||||
* ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key generation when there's
|
||||
* a chance neither gmp nor OpenSSL are installed)
|
||||
*
|
||||
* @var int
|
||||
* @access private
|
||||
*/
|
||||
static $smallestPrime = 4096;
|
||||
|
||||
/**
|
||||
* Engine
|
||||
*
|
||||
* This is only used for key generation. Valid values are RSA::ENGINE_INTERNAL and RSA::ENGINE_OPENSSL
|
||||
*
|
||||
* @var int
|
||||
* @access private
|
||||
*/
|
||||
static $engine = NULL;
|
||||
|
||||
/**
|
||||
* Initialize static variables
|
||||
@ -384,10 +391,49 @@ class RSA
|
||||
self::_initialize_static_variables();
|
||||
|
||||
$this->hash = new Hash('sha256');
|
||||
$this->hLen = $this->hash->getLength();
|
||||
$this->hLen = $this->hash->getLengthInBytes();
|
||||
$this->hashName = 'sha256';
|
||||
$this->mgfHash = new Hash('sha256');
|
||||
$this->mgfHLen = $this->mgfHash->getLength();
|
||||
$this->mgfHLen = $this->mgfHash->getLengthInBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the public exponent
|
||||
*
|
||||
* This will be 65537 unless changed.
|
||||
*
|
||||
* @access public
|
||||
* @param int $val
|
||||
*/
|
||||
static function setExponent($val)
|
||||
{
|
||||
self::$defaultExponent = $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the smallest prime number in bits
|
||||
*
|
||||
* This will be 4096 unless changed.
|
||||
*
|
||||
* @access public
|
||||
* @param int $val
|
||||
*/
|
||||
static function setSmallestPrime($val)
|
||||
{
|
||||
self::$smallestPrime = $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the engine
|
||||
*
|
||||
* Only used in the constructor. Valid values are RSA::ENGINE_OPENSSL and RSA::ENGINE_INTERNAL
|
||||
*
|
||||
* @access public
|
||||
* @param int $val
|
||||
*/
|
||||
static function setEngine($val)
|
||||
{
|
||||
self::$engine = $val;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -404,42 +450,29 @@ class RSA
|
||||
* @param int $timeout
|
||||
* @param array $p
|
||||
*/
|
||||
static function createKey($bits = 2048, $timeout = false, $partial = array())
|
||||
static function createKey($bits = 2048)
|
||||
{
|
||||
self::_initialize_static_variables();
|
||||
|
||||
if (!defined('CRYPT_RSA_MODE')) {
|
||||
if (!isset(self::$engine)) {
|
||||
switch (true) {
|
||||
// Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
|
||||
// Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
|
||||
// can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
|
||||
case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
|
||||
define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
|
||||
self::$engine = self::ENGINE_INTERNAL;
|
||||
break;
|
||||
case extension_loaded('openssl') && file_exists(self::$configFile):
|
||||
define('CRYPT_RSA_MODE', self::MODE_OPENSSL);
|
||||
self::$engine = self::ENGINE_OPENSSL;
|
||||
break;
|
||||
default:
|
||||
define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
|
||||
self::$engine = self::ENGINE_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!defined('CRYPT_RSA_EXPONENT')) {
|
||||
// http://en.wikipedia.org/wiki/65537_%28number%29
|
||||
define('CRYPT_RSA_EXPONENT', '65537');
|
||||
}
|
||||
// per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
|
||||
// than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
|
||||
// to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
|
||||
// CRYPT_RSA_MODE is set to self::MODE_INTERNAL. if CRYPT_RSA_MODE is set to self::MODE_OPENSSL then
|
||||
// CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
|
||||
// generation when there's a chance neither gmp nor OpenSSL are installed)
|
||||
if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
|
||||
define('CRYPT_RSA_SMALLEST_PRIME', 4096);
|
||||
}
|
||||
|
||||
// OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
|
||||
if (CRYPT_RSA_MODE == self::MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
|
||||
|
||||
if (self::$engine == self::ENGINE_OPENSSL && $bits >= 384 && self::$defaultExponent == 65537) {
|
||||
$config = array();
|
||||
if (isset(self::$configFile)) {
|
||||
$config['config'] = self::$configFile;
|
||||
@ -466,75 +499,34 @@ class RSA
|
||||
|
||||
static $e;
|
||||
if (!isset($e)) {
|
||||
$e = new BigInteger(CRYPT_RSA_EXPONENT);
|
||||
$e = new BigInteger(self::$defaultExponent);
|
||||
}
|
||||
|
||||
extract(self::_generateMinMax($bits));
|
||||
$absoluteMin = $min;
|
||||
$temp = $bits >> 1; // divide by two to see how many bits P and Q would be
|
||||
if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
|
||||
$num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
|
||||
$temp = CRYPT_RSA_SMALLEST_PRIME;
|
||||
$regSize = $bits >> 1; // divide by two to see how many bits P and Q would be
|
||||
if ($regSize > self::$smallestPrime) {
|
||||
$num_primes = floor($bits / self::$smallestPrime);
|
||||
$regSize = self::$smallestPrime;
|
||||
} else {
|
||||
$num_primes = 2;
|
||||
}
|
||||
$regSize = $temp;
|
||||
$finalSize = $temp + $bits % $temp;
|
||||
|
||||
$n = clone self::$one;
|
||||
if (!empty($partial)) {
|
||||
extract(unserialize($partial));
|
||||
} else {
|
||||
$exponents = $coefficients = $primes = array();
|
||||
$lcm = array(
|
||||
'top' => clone self::$one,
|
||||
'bottom' => false
|
||||
);
|
||||
}
|
||||
|
||||
$start = time();
|
||||
$i0 = count($primes) + 1;
|
||||
$exponents = $coefficients = $primes = array();
|
||||
$lcm = array(
|
||||
'top' => clone self::$one,
|
||||
'bottom' => false
|
||||
);
|
||||
|
||||
do {
|
||||
for ($i = $i0; $i <= $num_primes; $i++) {
|
||||
if ($timeout !== false) {
|
||||
$timeout-= time() - $start;
|
||||
$start = time();
|
||||
if ($timeout <= 0) {
|
||||
return array(
|
||||
'privatekey' => '',
|
||||
'publickey' => '',
|
||||
'partialkey' => serialize(array(
|
||||
'primes' => $primes,
|
||||
'coefficients' => $coefficients,
|
||||
'lcm' => $lcm,
|
||||
'exponents' => $exponents
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$size = $i == $num_primes ? $finalSize : $regSize;
|
||||
$primes[$i] = BigInteger::randomPrime($size, $timeout);
|
||||
|
||||
if ($primes[$i] === false) { // if we've reached the timeout
|
||||
if (count($primes) > 1) {
|
||||
$partialkey = '';
|
||||
} else {
|
||||
array_pop($primes);
|
||||
$partialkey = serialize(array(
|
||||
'primes' => $primes,
|
||||
'coefficients' => $coefficients,
|
||||
'lcm' => $lcm,
|
||||
'exponents' => $exponents
|
||||
));
|
||||
}
|
||||
|
||||
return array(
|
||||
'privatekey' => false,
|
||||
'publickey' => false,
|
||||
'partialkey' => $partialkey
|
||||
);
|
||||
for ($i = 1; $i <= $num_primes; $i++) {
|
||||
if ($i != $num_primes) {
|
||||
$primes[$i] = BigInteger::randomPrime($regSize);
|
||||
} else {
|
||||
extract(BigInteger::minMaxBits($bits));
|
||||
list($min) = $min->divide($n);
|
||||
$min = $min->add(self::$one);
|
||||
list($max) = $max->divide($n);
|
||||
$primes[$i] = BigInteger::randomRangePrime($min, $max);
|
||||
}
|
||||
|
||||
// the first coefficient is calculated differently from the rest
|
||||
@ -551,8 +543,6 @@ class RSA
|
||||
// see http://en.wikipedia.org/wiki/Euler%27s_totient_function
|
||||
$lcm['top'] = $lcm['top']->multiply($temp);
|
||||
$lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
|
||||
|
||||
$exponents[$i] = $e->modInverse($temp);
|
||||
}
|
||||
|
||||
list($temp) = $lcm['top']->divide($lcm['bottom']);
|
||||
@ -560,9 +550,14 @@ class RSA
|
||||
$i0 = 1;
|
||||
} while (!$gcd->equals(self::$one));
|
||||
|
||||
$coefficients[2] = $primes[2]->modInverse($primes[1]);
|
||||
|
||||
$d = $e->modInverse($temp);
|
||||
|
||||
$coefficients[2] = $primes[2]->modInverse($primes[1]);
|
||||
foreach ($primes as $i => $prime) {
|
||||
$temp = $prime->subtract(self::$one);
|
||||
$exponents[$i] = $e->modInverse($temp);
|
||||
}
|
||||
|
||||
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
|
||||
// RSAPrivateKey ::= SEQUENCE {
|
||||
@ -594,8 +589,7 @@ class RSA
|
||||
|
||||
return array(
|
||||
'privatekey' => $privatekey,
|
||||
'publickey' => $publickey,
|
||||
'partialkey' => false
|
||||
'publickey' => $publickey
|
||||
);
|
||||
}
|
||||
|
||||
@ -705,11 +699,7 @@ class RSA
|
||||
$format = strtolower($type);
|
||||
if (isset(self::$fileFormats[$format])) {
|
||||
$format = self::$fileFormats[$format];
|
||||
try {
|
||||
$components = $format::load($key, $this->password);
|
||||
} catch (\Exception $e) {
|
||||
$components = false;
|
||||
}
|
||||
$components = $format::load($key, $this->password);
|
||||
}
|
||||
}
|
||||
|
||||
@ -721,7 +711,7 @@ class RSA
|
||||
$this->format = $format;
|
||||
|
||||
$this->modulus = $components['modulus'];
|
||||
$this->k = strlen($this->modulus->toBytes());
|
||||
$this->k = $this->modulus->getLengthInBytes();
|
||||
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
|
||||
if (isset($components['primes'])) {
|
||||
$this->primes = $components['primes'];
|
||||
@ -788,6 +778,34 @@ class RSA
|
||||
}
|
||||
|
||||
return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password);
|
||||
|
||||
/*
|
||||
$key = $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password);
|
||||
if ($key !== false || count($this->primes) == 2) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
$nSize = $this->getSize() >> 1;
|
||||
|
||||
$primes = [1 => clone self::$one, clone self::$one];
|
||||
$i = 1;
|
||||
foreach ($this->primes as $prime) {
|
||||
$primes[$i] = $primes[$i]->multiply($prime);
|
||||
if ($primes[$i]->getLength() >= $nSize) {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$exponents = [];
|
||||
$coefficients = [2 => $primes[2]->modInverse($primes[1])];
|
||||
|
||||
foreach ($primes as $i => $prime) {
|
||||
$temp = $prime->subtract(self::$one);
|
||||
$exponents[$i] = $this->modulus->modInverse($temp);
|
||||
}
|
||||
|
||||
return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $primes, $exponents, $coefficients, $this->password);
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -798,9 +816,9 @@ class RSA
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
function getSize()
|
||||
function getLength()
|
||||
{
|
||||
return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
|
||||
return !isset($this->modulus) ? 0 : $this->modulus->getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1038,12 +1056,16 @@ class RSA
|
||||
*/
|
||||
function __toString()
|
||||
{
|
||||
$key = $this->getPrivateKey($this->privateKeyFormat);
|
||||
if (is_string($key)) {
|
||||
return $key;
|
||||
try {
|
||||
$key = $this->getPrivateKey($this->privateKeyFormat);
|
||||
if (is_string($key)) {
|
||||
return $key;
|
||||
}
|
||||
$key = $this->_getPrivatePublicKey($this->publicKeyFormat);
|
||||
return is_string($key) ? $key : '';
|
||||
} catch (\Exception $e) {
|
||||
return '';
|
||||
}
|
||||
$key = $this->_getPrivatePublicKey($this->publicKeyFormat);
|
||||
return is_string($key) ? $key : '';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1112,7 +1134,7 @@ class RSA
|
||||
$this->hash = new Hash('sha256');
|
||||
$this->hashName = 'sha256';
|
||||
}
|
||||
$this->hLen = $this->hash->getLength();
|
||||
$this->hLen = $this->hash->getLengthInBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1142,7 +1164,7 @@ class RSA
|
||||
default:
|
||||
$this->mgfHash = new Hash('sha256');
|
||||
}
|
||||
$this->mgfHLen = $this->mgfHash->getLength();
|
||||
$this->mgfHLen = $this->mgfHash->getLengthInBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1316,7 +1338,7 @@ class RSA
|
||||
* @param string $y
|
||||
* @return bool
|
||||
*/
|
||||
function _equals($x, $y)
|
||||
static function _equals($x, $y)
|
||||
{
|
||||
if (strlen($x) != strlen($y)) {
|
||||
return false;
|
||||
@ -1528,7 +1550,7 @@ class RSA
|
||||
$db = $maskedDB ^ $dbMask;
|
||||
$lHash2 = substr($db, 0, $this->hLen);
|
||||
$m = substr($db, $this->hLen);
|
||||
if ($lHash != $lHash2) {
|
||||
if (!self::_equals($lHash, $lHash2)) {
|
||||
return false;
|
||||
}
|
||||
$m = ltrim($m, chr(0));
|
||||
@ -1746,7 +1768,7 @@ class RSA
|
||||
$salt = substr($db, $temp + 1); // should be $sLen long
|
||||
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
||||
$h2 = $this->hash->hash($m2);
|
||||
return $this->_equals($h, $h2);
|
||||
return self::_equals($h, $h2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1940,7 +1962,7 @@ class RSA
|
||||
}
|
||||
|
||||
// Compare
|
||||
return $this->_equals($em, $em2);
|
||||
return self::_equals($em, $em2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2044,7 +2066,7 @@ class RSA
|
||||
$em = $hash->hash($m);
|
||||
$em2 = Base64::decode($decoded['digest']);
|
||||
|
||||
return $this->_equals($em, $em2);
|
||||
return self::_equals($em, $em2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,433 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PKCS Formatted RSA Key Handler
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package RSA
|
||||
* @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\Crypt\RSA;
|
||||
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use ParagonIE\ConstantTime\Hex;
|
||||
use phpseclib\Crypt\Common\BlockCipher;
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\Base;
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\TripleDES;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Common\Functions\Strings;
|
||||
use phpseclib\Common\Functions\ASN1;
|
||||
|
||||
/**
|
||||
* PKCS Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
abstract class PKCS
|
||||
{
|
||||
/**#@+
|
||||
* @access private
|
||||
* @see \phpseclib\Crypt\RSA::createKey()
|
||||
*/
|
||||
/**
|
||||
* ASN1 Integer
|
||||
*/
|
||||
const ASN1_INTEGER = 2;
|
||||
/**
|
||||
* ASN1 Bit String
|
||||
*/
|
||||
const ASN1_BITSTRING = 3;
|
||||
/**
|
||||
* ASN1 Octet String
|
||||
*/
|
||||
const ASN1_OCTETSTRING = 4;
|
||||
/**
|
||||
* ASN1 Object Identifier
|
||||
*/
|
||||
const ASN1_OBJECT = 6;
|
||||
/**
|
||||
* ASN1 Sequence (with the constucted bit set)
|
||||
*/
|
||||
const ASN1_SEQUENCE = 48;
|
||||
/**#@-*/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
*/
|
||||
/**
|
||||
* Auto-detect the format
|
||||
*/
|
||||
const MODE_ANY = 0;
|
||||
/**
|
||||
* Require base64-encoded PEM's be supplied
|
||||
*/
|
||||
const MODE_PEM = 1;
|
||||
/**
|
||||
* Require raw DER's be supplied
|
||||
*/
|
||||
const MODE_DER = 2;
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Is the key a base-64 encoded PEM, DER or should it be auto-detected?
|
||||
*
|
||||
* @access private
|
||||
* @param int
|
||||
*/
|
||||
static $format = self::MODE_ANY;
|
||||
|
||||
/**
|
||||
* Returns the mode constant corresponding to the mode string
|
||||
*
|
||||
* @access public
|
||||
* @param string $mode
|
||||
* @return int
|
||||
* @throws \UnexpectedValueException if the block cipher mode is unsupported
|
||||
*/
|
||||
static function getEncryptionMode($mode)
|
||||
{
|
||||
switch ($mode) {
|
||||
case 'CBC':
|
||||
return BlockCipher::MODE_CBC;
|
||||
case 'ECB':
|
||||
return BlockCipher::MODE_ECB;
|
||||
case 'CFB':
|
||||
return BlockCipher::MODE_CFB;
|
||||
case 'OFB':
|
||||
return BlockCipher::MODE_OFB;
|
||||
case 'CTR':
|
||||
return BlockCipher::MODE_CTR;
|
||||
}
|
||||
throw new \UnexpectedValueException('Unsupported block cipher mode of operation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cipher object corresponding to a string
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
* @return string
|
||||
* @throws \UnexpectedValueException if the encryption algorithm is unsupported
|
||||
*/
|
||||
static function getEncryptionObject($algo)
|
||||
{
|
||||
$modes = '(CBC|ECB|CFB|OFB|CTR)';
|
||||
switch (true) {
|
||||
case preg_match("#^AES-(128|192|256)-$modes$#", $algo, $matches):
|
||||
$cipher = new AES(self::getEncryptionMode($matches[2]));
|
||||
$cipher->setKeyLength($matches[1]);
|
||||
return $cipher;
|
||||
case preg_match("#^DES-EDE3-$modes$#", $algo, $matches):
|
||||
return new TripleDES(self::getEncryptionMode($matches[1]));
|
||||
case preg_match("#^DES-$modes$#", $algo, $matches):
|
||||
return new DES(self::getEncryptionMode($matches[1]));
|
||||
default:
|
||||
throw new \UnexpectedValueException('Unsupported encryption algorithmn');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a symmetric key for PKCS#1 keys
|
||||
*
|
||||
* @access public
|
||||
* @param string $password
|
||||
* @param string $iv
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
static function generateSymmetricKey($password, $iv, $length)
|
||||
{
|
||||
$symkey = '';
|
||||
$iv = substr($iv, 0, 8);
|
||||
while (strlen($symkey) < $length) {
|
||||
$symkey.= md5($symkey . $password . $iv, true);
|
||||
}
|
||||
return substr($symkey, 0, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$components = array('isPublicKey' => strpos($key, 'PUBLIC') !== false);
|
||||
|
||||
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
|
||||
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
|
||||
protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
|
||||
two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
|
||||
|
||||
http://tools.ietf.org/html/rfc1421#section-4.6.1.1
|
||||
http://tools.ietf.org/html/rfc1421#section-4.6.1.3
|
||||
|
||||
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
|
||||
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
|
||||
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
|
||||
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
|
||||
implementation are part of the standard, as well.
|
||||
|
||||
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
|
||||
if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
|
||||
$iv = Hex::decode(trim($matches[2]));
|
||||
// remove the Proc-Type / DEK-Info sections as they're no longer needed
|
||||
$key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
|
||||
$ciphertext = self::_extractBER($key);
|
||||
if ($ciphertext === false) {
|
||||
$ciphertext = $key;
|
||||
}
|
||||
$crypto = self::getEncryptionObject($matches[1]);
|
||||
$crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
|
||||
$crypto->setIV($iv);
|
||||
$key = $crypto->decrypt($ciphertext);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (self::$format != self::MODE_DER) {
|
||||
$decoded = self::_extractBER($key);
|
||||
if ($decoded !== false) {
|
||||
$key = $decoded;
|
||||
} elseif (self::$format == self::MODE_PEM) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
if (ASN1::decodeLength($key) != strlen($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tag = ord(Strings::shift($key));
|
||||
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
||||
|
||||
0:d=0 hl=4 l= 631 cons: SEQUENCE
|
||||
4:d=1 hl=2 l= 1 prim: INTEGER :00
|
||||
7:d=1 hl=2 l= 13 cons: SEQUENCE
|
||||
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
||||
20:d=2 hl=2 l= 0 prim: NULL
|
||||
22:d=1 hl=4 l= 609 prim: OCTET STRING
|
||||
|
||||
ie. PKCS8 keys */
|
||||
|
||||
if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
|
||||
Strings::shift($key, 3);
|
||||
$tag = self::ASN1_SEQUENCE;
|
||||
}
|
||||
|
||||
if ($tag == self::ASN1_SEQUENCE) {
|
||||
$temp = Strings::shift($key, ASN1::decodeLength($key));
|
||||
if (ord(Strings::shift($temp)) != self::ASN1_OBJECT) {
|
||||
return false;
|
||||
}
|
||||
$length = ASN1::decodeLength($temp);
|
||||
switch (Strings::shift($temp, $length)) {
|
||||
case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
|
||||
break;
|
||||
case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
|
||||
/*
|
||||
PBEParameter ::= SEQUENCE {
|
||||
salt OCTET STRING (SIZE(8)),
|
||||
iterationCount INTEGER }
|
||||
*/
|
||||
if (ord(Strings::shift($temp)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
if (ASN1::decodeLength($temp) != strlen($temp)) {
|
||||
return false;
|
||||
}
|
||||
Strings::shift($temp); // assume it's an octet string
|
||||
$salt = Strings::shift($temp, ASN1::decodeLength($temp));
|
||||
if (ord(Strings::shift($temp)) != self::ASN1_INTEGER) {
|
||||
return false;
|
||||
}
|
||||
ASN1::decodeLength($temp);
|
||||
list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
|
||||
Strings::shift($key); // assume it's an octet string
|
||||
$length = ASN1::decodeLength($key);
|
||||
if (strlen($key) != $length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$crypto = new DES(DES::MODE_CBC);
|
||||
$crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
|
||||
$key = $crypto->decrypt($key);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
return self::load($key);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
||||
|
||||
0:d=0 hl=4 l= 290 cons: SEQUENCE
|
||||
4:d=1 hl=2 l= 13 cons: SEQUENCE
|
||||
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
||||
17:d=2 hl=2 l= 0 prim: NULL
|
||||
19:d=1 hl=4 l= 271 prim: BIT STRING */
|
||||
$tag = ord(Strings::shift($key)); // skip over the BIT STRING / OCTET STRING tag
|
||||
ASN1::decodeLength($key); // skip over the BIT STRING / OCTET STRING length
|
||||
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
|
||||
// unused bits in the final subsequent octet. The number shall be in the range zero to seven."
|
||||
// -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
|
||||
if ($tag == self::ASN1_BITSTRING) {
|
||||
Strings::shift($key);
|
||||
}
|
||||
if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
if (ASN1::decodeLength($key) != strlen($key)) {
|
||||
return false;
|
||||
}
|
||||
$tag = ord(Strings::shift($key));
|
||||
}
|
||||
if ($tag != self::ASN1_INTEGER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$length = ASN1::decodeLength($key);
|
||||
$temp = Strings::shift($key, $length);
|
||||
if (strlen($temp) != 1 || ord($temp) > 2) {
|
||||
$components['modulus'] = new BigInteger($temp, 256);
|
||||
Strings::shift($key); // skip over self::ASN1_INTEGER
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
|
||||
return $components;
|
||||
}
|
||||
if (ord(Strings::shift($key)) != self::ASN1_INTEGER) {
|
||||
return false;
|
||||
}
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['modulus'] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['publicExponent'] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['privateExponent'] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['primes'] = array(1 => new BigInteger(Strings::shift($key, $length), 256));
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['primes'][] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['exponents'] = array(1 => new BigInteger(Strings::shift($key, $length), 256));
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['exponents'][] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['coefficients'] = array(2 => new BigInteger(Strings::shift($key, $length), 256));
|
||||
|
||||
if (!empty($key)) {
|
||||
if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
ASN1::decodeLength($key);
|
||||
while (!empty($key)) {
|
||||
if (ord(Strings::shift($key)) != self::ASN1_SEQUENCE) {
|
||||
return false;
|
||||
}
|
||||
ASN1::decodeLength($key);
|
||||
$key = substr($key, 1);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['primes'][] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['exponents'][] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
Strings::shift($key);
|
||||
$length = ASN1::decodeLength($key);
|
||||
$components['coefficients'][] = new BigInteger(Strings::shift($key, $length), 256);
|
||||
}
|
||||
}
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require base64-encoded PEM's be supplied
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requirePEM()
|
||||
{
|
||||
self::$format = self::MODE_PEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require raw DER's be supplied
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requireDER()
|
||||
{
|
||||
self::$format = self::MODE_DER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept any format and auto detect the format
|
||||
*
|
||||
* This is the default setting
|
||||
*
|
||||
* @see self::load()
|
||||
* @access public
|
||||
*/
|
||||
static function requireAny()
|
||||
{
|
||||
self::$format = self::MODE_ANY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract raw BER from Base64 encoding
|
||||
*
|
||||
* @access private
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
static function _extractBER($str)
|
||||
{
|
||||
/* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
|
||||
* above and beyond the ceritificate.
|
||||
* ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
|
||||
*
|
||||
* Bag Attributes
|
||||
* localKeyID: 01 00 00 00
|
||||
* subject=/O=organization/OU=org unit/CN=common name
|
||||
* issuer=/O=organization/CN=common name
|
||||
*/
|
||||
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
|
||||
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
|
||||
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
|
||||
// remove new lines
|
||||
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
|
||||
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false;
|
||||
return $temp != false ? $temp : $str;
|
||||
}
|
||||
}
|
@ -24,14 +24,55 @@
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use ParagonIE\ConstantTime\Hex;
|
||||
use phpseclib\Crypt\AES;
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Crypt\TripleDES;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Common\Functions\ASN1;
|
||||
use phpseclib\Crypt\Common\PKCS1 as Progenitor;
|
||||
use phpseclib\File\ASN1;
|
||||
|
||||
// version must be multi if otherPrimeInfos present
|
||||
define(__NAMESPACE__ . '\Version', [
|
||||
'type' => ASN1::TYPE_INTEGER,
|
||||
'mapping' => ['two-prime', 'multi']
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\OtherPrimeInfo', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'prime' => ['type' => ASN1::TYPE_INTEGER], // ri
|
||||
'exponent' => ['type' => ASN1::TYPE_INTEGER], // di
|
||||
'coefficient' => ['type' => ASN1::TYPE_INTEGER] // ti
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\OtherPrimeInfos', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'min' => 1,
|
||||
'max' => -1,
|
||||
'children' => OtherPrimeInfo
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\RSAPrivateKey', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'version' => Version,
|
||||
'modulus' => ['type' => ASN1::TYPE_INTEGER], // n
|
||||
'publicExponent' => ['type' => ASN1::TYPE_INTEGER], // e
|
||||
'privateExponent' => ['type' => ASN1::TYPE_INTEGER], // d
|
||||
'prime1' => ['type' => ASN1::TYPE_INTEGER], // p
|
||||
'prime2' => ['type' => ASN1::TYPE_INTEGER], // q
|
||||
'exponent1' => ['type' => ASN1::TYPE_INTEGER], // d mod (p-1)
|
||||
'exponent2' => ['type' => ASN1::TYPE_INTEGER], // d mod (q-1)
|
||||
'coefficient' => ['type' => ASN1::TYPE_INTEGER], // (inverse of q) mod p
|
||||
'otherPrimeInfos' => OtherPrimeInfos + ['optional' => true]
|
||||
]
|
||||
]);
|
||||
|
||||
define(__NAMESPACE__ . '\RSAPublicKey', [
|
||||
'type' => ASN1::TYPE_SEQUENCE,
|
||||
'children' => [
|
||||
'modulus' => ['type' => ASN1::TYPE_INTEGER],
|
||||
'publicExponent' => ['type' => ASN1::TYPE_INTEGER]
|
||||
]
|
||||
]);
|
||||
|
||||
/**
|
||||
* PKCS#1 Formatted RSA Key Handler
|
||||
@ -40,25 +81,58 @@ use phpseclib\Common\Functions\ASN1;
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PKCS1 extends PKCS
|
||||
class PKCS1 extends Progenitor
|
||||
{
|
||||
/**
|
||||
* Default encryption algorithm
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
static $defaultEncryptionAlgorithm = 'DES-EDE3-CBC';
|
||||
|
||||
/**
|
||||
* Sets the default encryption algorithm
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $algo
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function setEncryptionAlgorithm($algo)
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
self::$defaultEncryptionAlgorithm = $algo;
|
||||
if (!is_string($key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$components = ['isPublicKey' => strpos($key, 'PUBLIC') !== false];
|
||||
|
||||
$key = parent::load($key, $password);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$asn1 = new ASN1();
|
||||
$decoded = $asn1->decodeBER($key);
|
||||
if (empty($decoded)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$key = $asn1->asn1map($decoded[0], RSAPrivateKey);
|
||||
if (is_array($key)) {
|
||||
$components+= [
|
||||
'modulus' => $key['modulus'],
|
||||
'publicExponent' => $key['publicExponent'],
|
||||
'privateExponent' => $key['privateExponent'],
|
||||
'primes' => [1 => $key['prime1'], $key['prime2']],
|
||||
'exponents' => [1 => $key['exponent1'], $key['exponent2']],
|
||||
'coefficients' => [2 => $key['coefficient']]
|
||||
];
|
||||
if ($key['version'] == 'multi') {
|
||||
foreach ($key['otherPrimeInfos'] as $primeInfo) {
|
||||
$components['primes'][] = $primeInfo['prime'];
|
||||
$components['exponents'][] = $primeInfo['exponent'];
|
||||
$components['coefficients'][] = $primeInfo['coefficient'];
|
||||
}
|
||||
}
|
||||
return $components;
|
||||
}
|
||||
|
||||
$key = $asn1->asn1map($decoded[0], RSAPublicKey);
|
||||
|
||||
return is_array($key) ? $components + $key : false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,64 +151,29 @@ class PKCS1 extends PKCS
|
||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||
{
|
||||
$num_primes = count($primes);
|
||||
$raw = array(
|
||||
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
||||
'modulus' => $n->toBytes(true),
|
||||
'publicExponent' => $e->toBytes(true),
|
||||
'privateExponent' => $d->toBytes(true),
|
||||
'prime1' => $primes[1]->toBytes(true),
|
||||
'prime2' => $primes[2]->toBytes(true),
|
||||
'exponent1' => $exponents[1]->toBytes(true),
|
||||
'exponent2' => $exponents[2]->toBytes(true),
|
||||
'coefficient' => $coefficients[2]->toBytes(true)
|
||||
);
|
||||
|
||||
$components = array();
|
||||
foreach ($raw as $name => $value) {
|
||||
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($value)), $value);
|
||||
$key = [
|
||||
'version' => $num_primes == 2 ? 'two-prime' : 'multi',
|
||||
'modulus' => $n,
|
||||
'publicExponent' => $e,
|
||||
'privateExponent' => $d,
|
||||
'prime1' => $primes[1],
|
||||
'prime2' => $primes[2],
|
||||
'exponent1' => $exponents[1],
|
||||
'exponent2' => $exponents[2],
|
||||
'coefficient' => $coefficients[2]
|
||||
];
|
||||
for ($i = 3; $i <= $num_primes; $i++) {
|
||||
$key['otherPrimeInfos'][] = [
|
||||
'prime' => $primes[$i],
|
||||
'exponent' => $exponents[$i],
|
||||
'coefficient' => $coefficients[$i]
|
||||
];
|
||||
}
|
||||
|
||||
$RSAPrivateKey = implode('', $components);
|
||||
$asn1 = new ASN1();
|
||||
$key = $asn1->encodeDER($key, RSAPrivateKey);
|
||||
|
||||
if ($num_primes > 2) {
|
||||
$OtherPrimeInfos = '';
|
||||
for ($i = 3; $i <= $num_primes; $i++) {
|
||||
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
||||
//
|
||||
// OtherPrimeInfo ::= SEQUENCE {
|
||||
// prime INTEGER, -- ri
|
||||
// exponent INTEGER, -- di
|
||||
// coefficient INTEGER -- ti
|
||||
// }
|
||||
$OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
|
||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
|
||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
|
||||
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, ASN1::encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
|
||||
}
|
||||
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, ASN1::encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
|
||||
}
|
||||
|
||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, ASN1::encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
||||
|
||||
if (!empty($password) || is_string($password)) {
|
||||
$cipher = self::getEncryptionObject(self::$defaultEncryptionAlgorithm);
|
||||
$iv = Random::string($cipher->getBlockLength() >> 3);
|
||||
$cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
|
||||
$cipher->setIV($iv);
|
||||
$iv = strtoupper(Hex::encode($iv));
|
||||
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
||||
"Proc-Type: 4,ENCRYPTED\r\n" .
|
||||
"DEK-Info: " . self::$defaultEncryptionAlgorithm . ",$iv\r\n" .
|
||||
"\r\n" .
|
||||
chunk_split(Base64::encode($cipher->encrypt($RSAPrivateKey)), 64) .
|
||||
'-----END RSA PRIVATE KEY-----';
|
||||
} else {
|
||||
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($RSAPrivateKey), 64) .
|
||||
'-----END RSA PRIVATE KEY-----';
|
||||
}
|
||||
|
||||
return $RSAPrivateKey;
|
||||
return self::wrapPrivateKey($key, 'RSA', $password);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,31 +186,14 @@ class PKCS1 extends PKCS
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
$modulus = $n->toBytes(true);
|
||||
$publicExponent = $e->toBytes(true);
|
||||
$key = [
|
||||
'modulus' => $n,
|
||||
'publicExponent' => $e
|
||||
];
|
||||
|
||||
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
||||
// RSAPublicKey ::= SEQUENCE {
|
||||
// modulus INTEGER, -- n
|
||||
// publicExponent INTEGER -- e
|
||||
// }
|
||||
$components = array(
|
||||
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($modulus)), $modulus),
|
||||
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($publicExponent)), $publicExponent)
|
||||
);
|
||||
$asn1 = new ASN1();
|
||||
$key = $asn1->encodeDER($key, RSAPublicKey);
|
||||
|
||||
$RSAPublicKey = pack(
|
||||
'Ca*a*a*',
|
||||
self::ASN1_SEQUENCE,
|
||||
ASN1::encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
||||
$components['modulus'],
|
||||
$components['publicExponent']
|
||||
);
|
||||
|
||||
$RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($RSAPublicKey), 64) .
|
||||
'-----END RSA PUBLIC KEY-----';
|
||||
|
||||
return $RSAPublicKey;
|
||||
return self::wrapPublicKey($key, 'RSA');
|
||||
}
|
||||
}
|
||||
|
@ -27,21 +27,51 @@
|
||||
|
||||
namespace phpseclib\Crypt\RSA;
|
||||
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use phpseclib\Crypt\DES;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Common\Functions\ASN1;
|
||||
use phpseclib\Crypt\Common\PKCS8 as Progenitor;
|
||||
use phpseclib\File\ASN1;
|
||||
|
||||
/**
|
||||
* PKCS#8 Formatted RSA Key Handler
|
||||
* PKCS#1 Formatted RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PKCS8 extends PKCS
|
||||
class PKCS8 extends Progenitor
|
||||
{
|
||||
/**
|
||||
* Break a public or private key down into its constituent components
|
||||
*
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
* @return array
|
||||
*/
|
||||
static function load($key, $password = '')
|
||||
{
|
||||
$components = ['isPublicKey' => strpos($key, 'PUBLIC') !== false];
|
||||
|
||||
$key = parent::load($key, $password);
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$type = isset($key['privateKey']) ? 'private' : 'public';
|
||||
|
||||
if ($key[$type . 'KeyAlgorithm']['algorithm'] != '1.2.840.113549.1.1.1') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $components + PKCS1::load($key[$type . 'Key']);
|
||||
|
||||
if (isset($key['meta'])) {
|
||||
$result['meta'] = $key['meta'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a private key to the appropriate format.
|
||||
*
|
||||
@ -57,108 +87,9 @@ class PKCS8 extends PKCS
|
||||
*/
|
||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||
{
|
||||
$num_primes = count($primes);
|
||||
$raw = array(
|
||||
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
||||
'modulus' => $n->toBytes(true),
|
||||
'publicExponent' => $e->toBytes(true),
|
||||
'privateExponent' => $d->toBytes(true),
|
||||
'prime1' => $primes[1]->toBytes(true),
|
||||
'prime2' => $primes[2]->toBytes(true),
|
||||
'exponent1' => $exponents[1]->toBytes(true),
|
||||
'exponent2' => $exponents[2]->toBytes(true),
|
||||
'coefficient' => $coefficients[2]->toBytes(true)
|
||||
);
|
||||
|
||||
$components = array();
|
||||
foreach ($raw as $name => $value) {
|
||||
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($value)), $value);
|
||||
}
|
||||
|
||||
$RSAPrivateKey = implode('', $components);
|
||||
|
||||
if ($num_primes > 2) {
|
||||
$OtherPrimeInfos = '';
|
||||
for ($i = 3; $i <= $num_primes; $i++) {
|
||||
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
||||
//
|
||||
// OtherPrimeInfo ::= SEQUENCE {
|
||||
// prime INTEGER, -- ri
|
||||
// exponent INTEGER, -- di
|
||||
// coefficient INTEGER -- ti
|
||||
// }
|
||||
$OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
|
||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
|
||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
|
||||
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, ASN1::encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
|
||||
}
|
||||
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, ASN1::encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
|
||||
}
|
||||
|
||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, ASN1::encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
||||
|
||||
$rsaOID = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00"; // hex version of MA0GCSqGSIb3DQEBAQUA
|
||||
$RSAPrivateKey = pack(
|
||||
'Ca*a*Ca*a*',
|
||||
self::ASN1_INTEGER,
|
||||
"\01\00",
|
||||
$rsaOID,
|
||||
4,
|
||||
ASN1::encodeLength(strlen($RSAPrivateKey)),
|
||||
$RSAPrivateKey
|
||||
);
|
||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, ASN1::encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
||||
if (!empty($password) || is_string($password)) {
|
||||
$salt = Random::string(8);
|
||||
$iterationCount = 2048;
|
||||
|
||||
$crypto = new DES(DES::MODE_CBC);
|
||||
$crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
|
||||
$RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
|
||||
|
||||
$parameters = pack(
|
||||
'Ca*a*Ca*N',
|
||||
self::ASN1_OCTETSTRING,
|
||||
ASN1::encodeLength(strlen($salt)),
|
||||
$salt,
|
||||
self::ASN1_INTEGER,
|
||||
ASN1::encodeLength(4),
|
||||
$iterationCount
|
||||
);
|
||||
$pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
|
||||
|
||||
$encryptionAlgorithm = pack(
|
||||
'Ca*a*Ca*a*',
|
||||
self::ASN1_OBJECT,
|
||||
ASN1::encodeLength(strlen($pbeWithMD5AndDES_CBC)),
|
||||
$pbeWithMD5AndDES_CBC,
|
||||
self::ASN1_SEQUENCE,
|
||||
ASN1::encodeLength(strlen($parameters)),
|
||||
$parameters
|
||||
);
|
||||
|
||||
$RSAPrivateKey = pack(
|
||||
'Ca*a*Ca*a*',
|
||||
self::ASN1_SEQUENCE,
|
||||
ASN1::encodeLength(strlen($encryptionAlgorithm)),
|
||||
$encryptionAlgorithm,
|
||||
self::ASN1_OCTETSTRING,
|
||||
ASN1::encodeLength(strlen($RSAPrivateKey)),
|
||||
$RSAPrivateKey
|
||||
);
|
||||
|
||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, ASN1::encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
||||
|
||||
$RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($RSAPrivateKey), 64) .
|
||||
'-----END ENCRYPTED PRIVATE KEY-----';
|
||||
} else {
|
||||
$RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($RSAPrivateKey), 64) .
|
||||
'-----END PRIVATE KEY-----';
|
||||
}
|
||||
|
||||
return $RSAPrivateKey;
|
||||
$key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients);
|
||||
$key = ASN1::extractBER($key);
|
||||
return self::wrapPrivateKey($key, '1.2.840.113549.1.1.1', [], $password);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,43 +102,8 @@ class PKCS8 extends PKCS
|
||||
*/
|
||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||
{
|
||||
$modulus = $n->toBytes(true);
|
||||
$publicExponent = $e->toBytes(true);
|
||||
|
||||
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
||||
// RSAPublicKey ::= SEQUENCE {
|
||||
// modulus INTEGER, -- n
|
||||
// publicExponent INTEGER -- e
|
||||
// }
|
||||
$components = array(
|
||||
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($modulus)), $modulus),
|
||||
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, ASN1::encodeLength(strlen($publicExponent)), $publicExponent)
|
||||
);
|
||||
|
||||
$RSAPublicKey = pack(
|
||||
'Ca*a*a*',
|
||||
self::ASN1_SEQUENCE,
|
||||
ASN1::encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
||||
$components['modulus'],
|
||||
$components['publicExponent']
|
||||
);
|
||||
|
||||
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
|
||||
$rsaOID = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00"; // hex version of MA0GCSqGSIb3DQEBAQUA
|
||||
$RSAPublicKey = chr(0) . $RSAPublicKey;
|
||||
$RSAPublicKey = chr(3) . ASN1::encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
|
||||
|
||||
$RSAPublicKey = pack(
|
||||
'Ca*a*',
|
||||
self::ASN1_SEQUENCE,
|
||||
ASN1::encodeLength(strlen($rsaOID . $RSAPublicKey)),
|
||||
$rsaOID . $RSAPublicKey
|
||||
);
|
||||
|
||||
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
|
||||
chunk_split(Base64::encode($RSAPublicKey), 64) .
|
||||
'-----END PUBLIC KEY-----';
|
||||
|
||||
return $RSAPublicKey;
|
||||
$key = PKCS1::savePublicKey($n, $e);
|
||||
$key = ASN1::extractBER($key);
|
||||
return self::wrapPublicKey($key, '1.2.840.113549.1.1.1');
|
||||
}
|
||||
}
|
||||
|
@ -138,9 +138,6 @@ class PuTTY
|
||||
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
|
||||
$crypto->disablePadding();
|
||||
$private = $crypto->decrypt($private);
|
||||
if ($private === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extract(unpack('Nlength', Strings::shift($private, 4)));
|
||||
@ -289,7 +286,7 @@ class PuTTY
|
||||
$n
|
||||
);
|
||||
$key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" .
|
||||
'Comment: "' . str_replace(array('\\', '"'), array('\\\\', '\"'), self::$comment) . "\"\r\n";
|
||||
'Comment: "' . str_replace(array('\\', '"'), array('\\\\', '\"'), self::$comment) . "\"\r\n" .
|
||||
chunk_split(Base64::encode($key), 64) .
|
||||
'---- END SSH2 PUBLIC KEY ----';
|
||||
|
||||
|
@ -184,6 +184,7 @@ class Random
|
||||
$v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
|
||||
$result.= $r;
|
||||
}
|
||||
|
||||
return substr($result, 0, $length);
|
||||
}
|
||||
|
||||
|
@ -1286,4 +1286,31 @@ class ASN1
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract raw BER from Base64 encoding
|
||||
*
|
||||
* @access private
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
static function extractBER($str)
|
||||
{
|
||||
/* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
|
||||
* above and beyond the ceritificate.
|
||||
* ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
|
||||
*
|
||||
* Bag Attributes
|
||||
* localKeyID: 01 00 00 00
|
||||
* subject=/O=organization/OU=org unit/CN=common name
|
||||
* issuer=/O=organization/CN=common name
|
||||
*/
|
||||
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
|
||||
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
|
||||
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
|
||||
// remove new lines
|
||||
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
|
||||
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false;
|
||||
return $temp != false ? $temp : $str;
|
||||
}
|
||||
}
|
||||
|
@ -1462,7 +1462,7 @@ class X509
|
||||
$asn1 = new ASN1();
|
||||
|
||||
if ($mode != self::FORMAT_DER) {
|
||||
$newcert = $this->_extractBER($cert);
|
||||
$newcert = ASN1::extractBER($cert);
|
||||
if ($mode == self::FORMAT_PEM && $cert == $newcert) {
|
||||
return false;
|
||||
}
|
||||
@ -2974,7 +2974,7 @@ class X509
|
||||
$asn1 = new ASN1();
|
||||
|
||||
if ($mode != self::FORMAT_DER) {
|
||||
$newcsr = $this->_extractBER($csr);
|
||||
$newcsr = ASN1::extractBER($csr);
|
||||
if ($mode == self::FORMAT_PEM && $csr == $newcsr) {
|
||||
return false;
|
||||
}
|
||||
@ -3216,7 +3216,7 @@ class X509
|
||||
$asn1 = new ASN1();
|
||||
|
||||
if ($mode != self::FORMAT_DER) {
|
||||
$newcrl = $this->_extractBER($crl);
|
||||
$newcrl = ASN1::extractBER($crl);
|
||||
if ($mode == self::FORMAT_PEM && $crl == $newcrl) {
|
||||
return false;
|
||||
}
|
||||
@ -3847,7 +3847,7 @@ class X509
|
||||
if (strtolower($date) == 'lifetime') {
|
||||
$temp = '99991231235959Z';
|
||||
$asn1 = new ASN1();
|
||||
$temp = chr(ASN1::TYPE_GENERALIZED_TIME) . $asn1->_encodeLength(strlen($temp)) . $temp;
|
||||
$temp = chr(ASN1::TYPE_GENERALIZED_TIME) . Functions::encodeLength(strlen($temp)) . $temp;
|
||||
$this->endDate = new Element($temp);
|
||||
} else {
|
||||
$this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
|
||||
@ -4465,7 +4465,7 @@ class X509
|
||||
}
|
||||
|
||||
// If in PEM format, convert to binary.
|
||||
$key = $this->_extractBER($key);
|
||||
$key = ASN1::extractBER($key);
|
||||
|
||||
// Now we have the key string: compute its sha-1 sum.
|
||||
$hash = new Hash('sha1');
|
||||
@ -4770,33 +4770,6 @@ class X509
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract raw BER from Base64 encoding
|
||||
*
|
||||
* @access private
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
function _extractBER($str)
|
||||
{
|
||||
/* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
|
||||
* above and beyond the ceritificate.
|
||||
* ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
|
||||
*
|
||||
* Bag Attributes
|
||||
* localKeyID: 01 00 00 00
|
||||
* subject=/O=organization/OU=org unit/CN=common name
|
||||
* issuer=/O=organization/CN=common name
|
||||
*/
|
||||
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
|
||||
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
|
||||
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
|
||||
// remove new lines
|
||||
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
|
||||
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false;
|
||||
return $temp != false ? $temp : $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OID corresponding to a name
|
||||
*
|
||||
|
@ -53,6 +53,7 @@ namespace phpseclib\Math;
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use ParagonIE\ConstantTime\Hex;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Common\Functions\ASN1;
|
||||
|
||||
/**
|
||||
* Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
|
||||
@ -1602,26 +1603,26 @@ class BigInteger
|
||||
);
|
||||
|
||||
$components = array(
|
||||
'modulus' => pack('Ca*a*', 2, self::_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
|
||||
'publicExponent' => pack('Ca*a*', 2, self::_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
|
||||
'modulus' => pack('Ca*a*', 2, ASN1::encodeLength(strlen($components['modulus'])), $components['modulus']),
|
||||
'publicExponent' => pack('Ca*a*', 2, ASN1::encodeLength(strlen($components['publicExponent'])), $components['publicExponent'])
|
||||
);
|
||||
|
||||
$RSAPublicKey = pack(
|
||||
'Ca*a*a*',
|
||||
48,
|
||||
self::_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
||||
ASN1::encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
||||
$components['modulus'],
|
||||
$components['publicExponent']
|
||||
);
|
||||
|
||||
$rsaOID = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00"; // hex version of MA0GCSqGSIb3DQEBAQUA
|
||||
$RSAPublicKey = chr(0) . $RSAPublicKey;
|
||||
$RSAPublicKey = chr(3) . self::_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
|
||||
$RSAPublicKey = chr(3) . ASN1::encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
|
||||
|
||||
$encapsulated = pack(
|
||||
'Ca*a*',
|
||||
48,
|
||||
self::_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)),
|
||||
ASN1::encodeLength(strlen($rsaOID . $RSAPublicKey)),
|
||||
$rsaOID . $RSAPublicKey
|
||||
);
|
||||
|
||||
@ -3009,10 +3010,35 @@ class BigInteger
|
||||
return $this->bitwise_leftRotate(-$shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest and largest n-bit number
|
||||
*
|
||||
* @param int $bits
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
* @access public
|
||||
*/
|
||||
static function minMaxBits($bits)
|
||||
{
|
||||
$bytes = $bits >> 3;
|
||||
$min = str_repeat(chr(0), $bytes);
|
||||
$max = str_repeat(chr(0xFF), $bytes);
|
||||
$msb = $bits & 7;
|
||||
if ($msb) {
|
||||
$min = chr(1 << ($msb - 1)) . $min;
|
||||
$max = chr((1 << $msb) - 1) . $max;
|
||||
} else {
|
||||
$min[0] = chr(0x80);
|
||||
}
|
||||
return array(
|
||||
'min' => new static($min, 256),
|
||||
'max' => new static($max, 256)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random number of a certain size
|
||||
*
|
||||
* Byte length is equal to $size. Uses \phpseclib\Crypt\Random if it's loaded and mt_rand if it's not.
|
||||
* Bit length is equal to $size.
|
||||
*
|
||||
* @param int $size
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
@ -3020,23 +3046,8 @@ class BigInteger
|
||||
*/
|
||||
static function random($size)
|
||||
{
|
||||
if (class_exists('\phpseclib\Crypt\Random')) {
|
||||
$random = Random::string($size);
|
||||
} else {
|
||||
$random = '';
|
||||
|
||||
if ($size & 1) {
|
||||
$random.= chr(mt_rand(0, 255));
|
||||
}
|
||||
|
||||
$blocks = $size >> 1;
|
||||
for ($i = 0; $i < $blocks; ++$i) {
|
||||
// mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
|
||||
$random.= pack('n', mt_rand(0, 0xFFFF));
|
||||
}
|
||||
}
|
||||
|
||||
return new static($random, 256);
|
||||
extract(self::minMaxBits($size));
|
||||
return self::randomRange($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3058,7 +3069,7 @@ class BigInteger
|
||||
$compare = $max->compare($min);
|
||||
|
||||
if (!$compare) {
|
||||
return $this->_normalize($min);
|
||||
return $min;
|
||||
} elseif ($compare < 0) {
|
||||
// if $min is bigger then $max, swap $min and $max
|
||||
$temp = $max;
|
||||
@ -3072,6 +3083,7 @@ class BigInteger
|
||||
}
|
||||
|
||||
$max = $max->subtract($min->subtract($one));
|
||||
|
||||
$size = strlen(ltrim($max->toBytes(), chr(0)));
|
||||
|
||||
/*
|
||||
@ -3090,7 +3102,7 @@ class BigInteger
|
||||
http://crypto.stackexchange.com/questions/5708/creating-a-small-number-from-a-cryptographically-secure-random-string
|
||||
*/
|
||||
$random_max = new static(chr(1) . str_repeat("\0", $size), 256);
|
||||
$random = static::random($size);
|
||||
$random = new static(Random::string($size), 256);
|
||||
|
||||
list($max_multiple) = $random_max->divide($max);
|
||||
$max_multiple = $max_multiple->multiply($max);
|
||||
@ -3099,7 +3111,7 @@ class BigInteger
|
||||
$random = $random->subtract($max_multiple);
|
||||
$random_max = $random_max->subtract($max_multiple);
|
||||
$random = $random->bitwise_leftShift(8);
|
||||
$random = $random->add(self::random(1));
|
||||
$random = $random->add(new static(Random::string(1), 256));
|
||||
$random_max = $random_max->bitwise_leftShift(8);
|
||||
list($max_multiple) = $random_max->divide($max);
|
||||
$max_multiple = $max_multiple->multiply($max);
|
||||
@ -3112,46 +3124,30 @@ class BigInteger
|
||||
/**
|
||||
* Generates a random prime number of a certain size
|
||||
*
|
||||
* Byte length is equal to $size
|
||||
* Bit length is equal to $size
|
||||
*
|
||||
* @param int $size
|
||||
* @param int $timeout
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
* @access public
|
||||
*/
|
||||
static function randomPrime($size, $timeout = false)
|
||||
static function randomPrime($size)
|
||||
{
|
||||
$min = str_repeat(chr(0), $bytes);
|
||||
$max = str_repeat(chr(0xFF), $bytes);
|
||||
$msb = $bits & 7;
|
||||
if ($msb) {
|
||||
$min = chr(1 << ($msb - 1)) . $min;
|
||||
$max = chr((1 << $msb) - 1) . $max;
|
||||
} else {
|
||||
$min[0] = chr(0x80);
|
||||
}
|
||||
|
||||
return self::randomRangePrime(
|
||||
new Math_BigInteger($min, 256),
|
||||
new Math_BigInteger($max, 256),
|
||||
$timeout
|
||||
);
|
||||
extract(self::minMaxBits($size));
|
||||
return self::randomRangePrime($min, $max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random prime number between a range
|
||||
*
|
||||
* If there's not a prime within the given range, false will be returned.
|
||||
* If more than $timeout seconds have elapsed, give up and return false.
|
||||
*
|
||||
* @param \phpseclib\Math\BigInteger $min
|
||||
* @param \phpseclib\Math\BigInteger $max
|
||||
* @param int $timeout
|
||||
* @return Math_BigInteger|false
|
||||
* @access public
|
||||
* @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
|
||||
*/
|
||||
static function randomRangePrime(BigInteger $min, BigInteger $max, $timeout = false)
|
||||
static function randomRangePrime(BigInteger $min, BigInteger $max)
|
||||
{
|
||||
$compare = $max->compare($min);
|
||||
|
||||
@ -3170,9 +3166,7 @@ class BigInteger
|
||||
$two = new static(2);
|
||||
}
|
||||
|
||||
$start = time();
|
||||
|
||||
$x = self::random($min, $max);
|
||||
$x = self::randomRange($min, $max);
|
||||
|
||||
// gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
|
||||
if (MATH_BIGINTEGER_MODE == self::MODE_GMP && extension_loaded('gmp')) {
|
||||
@ -3187,7 +3181,7 @@ class BigInteger
|
||||
$x = $x->subtract($one);
|
||||
}
|
||||
|
||||
return self::randomPrime($min, $x);
|
||||
return self::randomRangePrime($min, $x);
|
||||
}
|
||||
|
||||
if ($x->equals($two)) {
|
||||
@ -3207,10 +3201,6 @@ class BigInteger
|
||||
$initial_x = clone $x;
|
||||
|
||||
while (true) {
|
||||
if ($timeout !== false && time() - $start > $timeout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($x->isPrime()) {
|
||||
return $x;
|
||||
}
|
||||
@ -3391,7 +3381,7 @@ class BigInteger
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $t; ++$i) {
|
||||
$a = self::random($two, $n_2);
|
||||
$a = self::randomRange($two, $n_2);
|
||||
$y = $a->modPow($r, $n);
|
||||
|
||||
if (!$y->equals($one) && !$y->equals($n_1)) {
|
||||
@ -3661,26 +3651,6 @@ class BigInteger
|
||||
return $temp['int'];
|
||||
}
|
||||
|
||||
/**
|
||||
* DER-encode an integer
|
||||
*
|
||||
* The ability to DER-encode integers is needed to create RSA public keys for use with OpenSSL
|
||||
*
|
||||
* @see self::modPow()
|
||||
* @access private
|
||||
* @param int $length
|
||||
* @return string
|
||||
*/
|
||||
static function _encodeASN1Length($length)
|
||||
{
|
||||
if ($length <= 0x7F) {
|
||||
return chr($length);
|
||||
}
|
||||
|
||||
$temp = ltrim(pack('N', $length), chr(0));
|
||||
return pack('Ca*', 0x80 | strlen($temp), $temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Single digit division
|
||||
*
|
||||
@ -3723,7 +3693,6 @@ class BigInteger
|
||||
* @param \phpseclib\Math\BigInteger $n
|
||||
* @access public
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
*
|
||||
* @internal This function is based off of {@link http://mathforum.org/library/drmath/view/52605.html this page} and {@link http://stackoverflow.com/questions/11242920/calculating-nth-root-with-bcmath-in-php this stackoverflow question}.
|
||||
*/
|
||||
function root($n = null)
|
||||
@ -3876,4 +3845,26 @@ class BigInteger
|
||||
}
|
||||
return $max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of a BigInteger in bits
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
function getLength()
|
||||
{
|
||||
return strlen($this->toBits());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of a BigInteger in bytes
|
||||
*
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
function getLengthInBytes()
|
||||
{
|
||||
return strlen($this->toBytes());
|
||||
}
|
||||
}
|
||||
|
@ -1511,7 +1511,7 @@ class SSH2
|
||||
|
||||
-- http://tools.ietf.org/html/rfc4419#section-6.2 */
|
||||
$one = new BigInteger(1);
|
||||
$keyLength = min($kexHash->getLength(), max($encryptKeyLength, $decryptKeyLength));
|
||||
$keyLength = min($kexHash->getLengthInBytes(), max($encryptKeyLength, $decryptKeyLength));
|
||||
$max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength
|
||||
$max = $max->subtract($one);
|
||||
|
||||
@ -2928,9 +2928,6 @@ class SSH2
|
||||
if ($this->decrypt !== false) {
|
||||
$raw = $this->decrypt->decrypt($raw);
|
||||
}
|
||||
if ($raw === false) {
|
||||
throw new \RuntimeException('Unable to decrypt content');
|
||||
}
|
||||
|
||||
extract(unpack('Npacket_length/Cpadding_length', Strings::shift($raw, 5)));
|
||||
|
||||
|
@ -375,7 +375,7 @@ class Unit_Crypt_HashTest extends PhpseclibTestCase
|
||||
public function testGetLengthKnown($algorithm, $length)
|
||||
{
|
||||
$hash = new Hash($algorithm);
|
||||
$this->assertSame($hash->getLength(), $length);
|
||||
$this->assertSame($hash->getLengthInBytes(), $length);
|
||||
}
|
||||
|
||||
public function lengths()
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2015 Jim Wigginton
|
||||
@ -6,6 +7,7 @@
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\RSA\PKCS1;
|
||||
|
||||
class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
||||
{
|
||||
@ -16,6 +18,8 @@ class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $publickey);
|
||||
$this->assertNotEmpty("$privatekey");
|
||||
$this->assertNotEmpty("$publickey");
|
||||
$this->assertSame($privatekey->getLength(), 768);
|
||||
$this->assertSame($publickey->getLength(), 768);
|
||||
|
||||
return array($publickey, $privatekey);
|
||||
}
|
||||
@ -31,4 +35,31 @@ class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
||||
$plaintext = $privatekey->decrypt($ciphertext);
|
||||
$this->assertSame($plaintext, 'zzz');
|
||||
}
|
||||
|
||||
public function testMultiPrime()
|
||||
{
|
||||
RSA::setEngine(RSA::ENGINE_INTERNAL);
|
||||
RSA::setSmallestPrime(256);
|
||||
extract(RSA::createKey(1024));
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $privatekey);
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $publickey);
|
||||
$privatekey->setPrivateKeyFormat('PKCS1');
|
||||
$this->assertNotEmpty("$privatekey");
|
||||
$this->assertNotEmpty("$publickey");
|
||||
$this->assertSame($privatekey->getLength(), 1024);
|
||||
$this->assertSame($publickey->getLength(), 1024);
|
||||
$r = PKCS1::load("$privatekey");
|
||||
$this->assertCount(4, $r['primes']);
|
||||
// the last prime number could be slightly over. eg. 99 * 99 == 9801 but 10 * 10 = 100. the more numbers you're
|
||||
// multiplying the less certain you are to have each of them multiply to an n-bit number
|
||||
foreach (array_slice($r['primes'], 0, 3) as $i => $prime) {
|
||||
$this->assertSame($prime->getLength(), 256);
|
||||
}
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($privatekey->getPrivateKey());
|
||||
$signature = $rsa->sign('zzz');
|
||||
$rsa->load($rsa->getPublicKey());
|
||||
$this->assertTrue($rsa->verify('zzz', $signature));
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\RSA\PKCS1;
|
||||
use phpseclib\Crypt\RSA\PKCS8;
|
||||
use phpseclib\Crypt\RSA\PuTTY;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
@ -376,6 +377,8 @@ Private-MAC: 03e2cb74e1d67652fbad063d2ed0478f31bdf256
|
||||
$key = preg_replace('#(?<!\r)\n#', "\r\n", $key);
|
||||
$this->assertTrue($rsa->load($key));
|
||||
|
||||
$rsa->setPrivateKeyFormat('PKCS1');
|
||||
|
||||
PKCS1::setEncryptionAlgorithm('AES-256-CBC');
|
||||
$rsa->setPassword('demo');
|
||||
|
||||
@ -554,4 +557,368 @@ AAIBAAIBAAIBAAIBAA==
|
||||
|
||||
$rsa->sign('zzzz', RSA::PADDING_PKCS1);
|
||||
}
|
||||
|
||||
public function pkcs8tester($key, $pass)
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->setPassword($pass);
|
||||
$rsa->load($key);
|
||||
$r = PKCS8::load($key, $pass);
|
||||
PKCS8::setEncryptionAlgorithm($r['meta']['algorithm']);
|
||||
if (isset($r['meta']['cipher'])) {
|
||||
PKCS8::setEncryptionScheme($r['meta']['cipher']);
|
||||
}
|
||||
if (isset($r['meta']['prf'])) {
|
||||
PKCS8::setPRF($r['meta']['prf']);
|
||||
}
|
||||
$newkey = "$rsa";
|
||||
|
||||
$r2 = PKCS8::load($newkey, $pass);
|
||||
$this->assertSame($r['meta']['algorithm'], $r2['meta']['algorithm']);
|
||||
if (isset($r['meta']['cipher']) || isset($r2['meta']['cipher'])) {
|
||||
$this->assertSame($r['meta']['cipher'], $r2['meta']['cipher']);
|
||||
}
|
||||
if (isset($r['meta']['prf']) || isset($r2['meta']['prf'])) {
|
||||
$this->assertSame($r['meta']['prf'], $r2['meta']['prf']);
|
||||
}
|
||||
|
||||
$rsa2 = new RSA();
|
||||
$rsa2->setPassword($pass);
|
||||
$rsa2->load($newkey);
|
||||
|
||||
// comparing $key to $newkey won't work since phpseclib randomly generates IV's and salt's
|
||||
// so we'll strip the encryption
|
||||
|
||||
$rsa->setPassword();
|
||||
$rsa2->setPassword();
|
||||
$this->assertSame("$rsa", "$rsa2");
|
||||
}
|
||||
|
||||
public function testPKCS8AES256CBC()
|
||||
{
|
||||
// openssl pkcs8 -in private.pem -topk8 -v2 aes-256-cbc -v2prf hmacWithSHA256 -out enckey.pem
|
||||
|
||||
// EncryptionAlgorithm: id-PBES2
|
||||
// EncryptionScheme: aes256-CBC-PAD
|
||||
// PRF: id-hmacWithSHA256 (default)
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIIU53ox17kUkCAggA
|
||||
MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBATi8ZER9juR41S2c35WXTQBIIE
|
||||
0K98r5dQq/OxbwA2CH0ENs9Jw2qjvW0uGkH8DdO8XvCJohMrIU8FABxw/50Af5Ew
|
||||
Nq4FJIYz90LjZzlI7kf97TDMZKw2K3AleymwmfMcKer5pZ6jqdxLGXFztdj3Fm/S
|
||||
P+NcVjEZFSEH1MNDEPhiPSIUAf1yQcLwKAzHH0JTnZBOFSBbGxTZLYfvD2angVNL
|
||||
xTivLYJGdr1cUrAuZQcM3JGQEvCA5qAC7oRhdVgGyJrl8xXY3mVlaXMsW8A+Q7xj
|
||||
NyH7lJUFEF3YPMbpWr8zblCQYgGByM++yOfYQXno50AgWdYjPO88pPzKcCe4x6WV
|
||||
qKlvqTYZqb1HgZurTd3BS/e6GWRgnRt8W87nuNcyJasud92Z0FhSGwIirlE89gUW
|
||||
EinbY8m6+sL9VZZ5+t66TROtpj1Ohj8t3W+01oLDCtdSTGwLuq9XUsEyuYZSqUN9
|
||||
0F43U8pOykNbChi1S8vfFdwf7U1R+hgoF0MRNDwh3hRfSS0zPUnCGb6hDZrOZB9C
|
||||
e3xbfXiujVlfhRc7r2qbZHAwqNLcccC98oLfbEIUdBXn6M7GfFIwiuNiS48rehp0
|
||||
dA9+CiWJBq+7b/lRdcgQJxjwUpxtMXr/812Bky4dDoMDs32cmMghH2sgUvht0imy
|
||||
ZhA3IvSCAV1wVoQLqUuPXLMskcKsNCTbL9AYEpJm612dm43btXec2vtjCc4ajpCg
|
||||
wICLE2V1jwzWw0girrT/IMt8QUd3fkJZkEAbmFHwuZptFnreRCidZjfQqYhWfyqJ
|
||||
nGW+cc7G1bGwxt32fC5eu23hBTJERmRlvkhC+v2WKhYXcKyOKQn5/I4eaEZauDn3
|
||||
wmg3f4h/PPuQgqv/vspOai9a5HhPRNyeIjXsk3hxHepEgV+kVSU50BpchSSzBuhK
|
||||
71F3nOMTyJ/XXxaZrLLtpo3CcXmI0/JuNG7pjDS++Vx/BQFs8xxDfxRs0Um7RlT1
|
||||
piGZGDn9zHNpbspHkAeoQmlplbmjtCClojhfBj4HbXTtlYmDgwKHul4YIni6kgCr
|
||||
G+WduGXLeyxmH976vvJasD4wyttL2CZTHLR7Elp+yl0xjXMlj/iP4WYozJAmGifq
|
||||
xjLWMsZ0gaBtAoOFrvcgOueE7+E+NdbIHzU4u5FTbz0DLCvrsZeKwpOPEsMw0LVG
|
||||
T6rNsBzMY3XyBtV1FdXwmuOcWha62Ezr/RRrfvRPRImy/xVVKOrOQ/KbyELkjroh
|
||||
UAEPs7s+89Ovc7P30IfS0Xzlhz2aSRflZarOIqu1JtjTYZ0XWLTWoQT2fjZdnMDV
|
||||
qFrbTPdXezqTAAzk3rnkkghgamTVQ7Y8D+BIGHIc4+oVT2jxzSjBQC7szmudanGQ
|
||||
hfGLyO+vwLg4r1lanzSULtqfwTZMarjYGxLqpQp8cIjJfzvLI3psRDFyuWCdIbEs
|
||||
y3VKgoNsa+PmyimGSa7x2cw6ayTx9wlOhPzaBwqMhHxr4qJwS2ohDONeRfnPr34+
|
||||
oVD7mnCBLB14qiZcpQv+qPGvd/Q/tA5SBNbZhPuWtjqvy7/K+1FQX6xvx1kl7p9W
|
||||
l0Q99rwqECl8y+CiKEXdItkCTA/vgxblSt465Mbdic7cbcP6wAMSGmpryrmZomm/
|
||||
mKVKf5kPx2aR2W2KAcgw3TJIu1QX7N+l3kFrf9Owtz1a
|
||||
-----END ENCRYPTED PRIVATE KEY-----';
|
||||
$pass = 'asdf';
|
||||
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
|
||||
public function testPKCS8RC2CBC()
|
||||
{
|
||||
// openssl pkcs8 -in private.pem -topk8 -v2 rc2 -out enckey.pem
|
||||
|
||||
// EncryptionAlgorithm: id-PBES2
|
||||
// EncryptionScheme: rc2CBC
|
||||
// PRF: id-hmacWithSHA1
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIFFjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQI/V5Qw9+hKt4CAggA
|
||||
AgEQMBkGCCqGSIb3DQMCMA0CAToECPxrtS4U+IIBBIIEyKQyYpJ8tfWXVvitxaPq
|
||||
+gtrVVWd/ukjwZ+jQY3g/ZjZNWQPq5XbuoP5F3u5g4V+RoXzAIkdwyiveEv+XssV
|
||||
DJVHfNiL6VcdxhFJ1rmt2uq9vFW/x9UHDqAWsnytn46NFRWUqgKzkYWMDqU71IC/
|
||||
wyq7UzjTtqdLzaCxkTWYst1o+Iu7VXapFVcscPYyGshLVyZ0x/etc/09LOC4bIpk
|
||||
3Qzf+f+adrNxW0mbD3SyDfVadvS8mApsd7bJR320iEKd4CmW0sNAzKkm2ya2aUIi
|
||||
Hrk3DEgr4rPmpn3BVfZ6pg+yRu+MOxBhl+8yfA+E8kXfe/F7BiMkJQcJTOfLRLfH
|
||||
TXipyb4f8oa+gmwwWK0jfCuxoxiOTA1CBCjZoTvdSuFYVTdblysQO3BivvSQgbmD
|
||||
oHntb7HEoZ6yB49u/LrrowUQNH+XihBcototyLCmC5K+x8N5cZsp+yaLJekDHlQs
|
||||
ATVMeKCbPjYaS4g48lDyC1VbtNtJc/zN5gOUB0PM80iB02iZegYyeW5+WWzY+Lgu
|
||||
lpWLH7PdpqL5KtoH6SJKD6Szl8dKJLYzpHI2esckpp9YsDtX2z/VkUFKTd0PeeNh
|
||||
WefX0q8A47NBeBLFEZqmzPrL6IyaPnnPCUsvqk6MEA1DgsmY3DFd8nEYhzJIAwoy
|
||||
Rw1mCqwL0uukQPqFGByU9YRHyhJd5aAPyF1xSLfUQUJb9xn+wyN57xoamFePPWMi
|
||||
UXdESZWX+rjA0ChfEtL9AzXcfO9PBS1p/2JkVxUt/UPfI9SgQn92kLo0LRi/iRLk
|
||||
H4zjnkaDy65ZY15bzyK+EvJ+VZ+P24QI7X12f1m+rkssMekHWHf5/SitUpW26ZFe
|
||||
M6vXyz3RlXxow+0WcsPob19n/vbgeJQPTfMY0zPS0iCRIggC/liWMEOzP/R1jCYi
|
||||
q8TEaUi1Ztx3Gp4Y8Vcf33a/YsxKoUsQlFFtyE6KE3ZEI03E6cMiX21nWULKrk9l
|
||||
+8Tq4T1a8I4goVa+e4CYBYwMAY9fdfUJ/p1EnrG6Ynj06a2Zx0IK/dF5w0b/5TeL
|
||||
PMyafb4FHkpkyYYFlktQdKIqGjjtmKUr56/7vumVHUyItf5nSuM8lLps8to2MLkE
|
||||
MAolD+X4FIGs/1Z5NlUb5AlNVNRY1c7tf+YSXI21PlkBpaRSAvN9/2fmGnxWSvAa
|
||||
BEGR0JA4zMPrCSpxrBQpOrZPh/cD9YXNu+N9P4dtf57smCviKTJg8eMl9NYu4vtc
|
||||
FygdqPKuhJM2WI5Qdrqjbf4NQ1mngSxXNKrcNmC/m60JPNKHC7dM2ynbN8QyZqEE
|
||||
EzSdL0Z3YQGnuwr+4zKHHsNnO4nRJfUowWks4Gvi2HIyy3DBVqqyEPxDDGEpcqs+
|
||||
8GNKTGBg1PCVg+I9Xjxio4tBuwLDo6Y8Ef8SphN/0DC9svaQRfEOY3/9WB+fDnrq
|
||||
SUSNZNWetkCd247WHwl+JvJDXCuzGJ2+JG5DXuEdCq2EhEVNUWPuotXTPvI+0wsP
|
||||
Kq23uvzS53ZArQnxlqgwyXQ06jzc+J4AiNtl3uIw8D6LrRyaDsOsKQCEh7qjkqTc
|
||||
khzefbnNRDL5PIJnTfM7vSQ4nUzdAxs/7YzX6GMx1DaCtBANbUVUoIE+3oKdqpGV
|
||||
9AmO2phYWCBefw==
|
||||
-----END ENCRYPTED PRIVATE KEY-----';
|
||||
$pass = 'asdf';
|
||||
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
|
||||
public function testPKCS83DES()
|
||||
{
|
||||
// openssl pkcs8 -in private.pem -topk8 -v1 PBE-SHA1-3DES -out enckey.pem
|
||||
|
||||
// EncryptionAlgorithm: pbeWithSHAAnd3-KeyTripleDES-CBC
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEDMA4ECHwurC0qxNK7AgIIAASCBMjRJefQ1oLo/pml
|
||||
Zw1qTE2NMgSNdP6z3vEap0qMMs/EXO37GDuHGla/yvvBIZbBXPVoQwd7K9QfU1NP
|
||||
JCBtNBTD9Pl7a4fJIlrf2dN5SCP8lu+nFa5ZyCiBvUtxfdROnhXfkhs0kqOowLaq
|
||||
1mw+Di9FPSA3ZkdJTPpAyMNPMlYpQII2ex+j6NmRB8t7O121o6ynbmDj0Rh87dv9
|
||||
VtRhO9sonTy160Mv2HPMLMliXMwFUvpEH9XNE+K6V6DnoMc7I9jmEnqLAzmjsKv/
|
||||
AOwuX8t8cPboeGOu++/0h3879+OVcnkXGMW0aAT+3sX4oMgEVREHDwkn2IGsrIuV
|
||||
SerUKg8WSoyhRNb9j7uJAlvU6bCrivcOujjNasdWKG47ojeiySFUkKu9JBohQ+vI
|
||||
mrlkqZv+FMwEKgApPhCKbQYqLuKl/kp6lNBXmhcusuxsGCnaw7/Wa+Y6p+Gz6UL5
|
||||
caFpDm6FX+Snvi5/6sUpMKL9LPAAZZVRpKj9JWcidEoXa5rINIMtKyVpl+GEQmac
|
||||
9lCdFq+5zO2r94af9AKRUIqTquyCkcy2s2mzNq2IIv2atibnb2HQex0/EhLFxMC/
|
||||
UZbl61YaSBxrH52LY4SNOUy+ppCsP4z0ojTdci9Yc3BnMqzSPD3FMQPmGpWWRGOq
|
||||
Jdj2/B76Q7rYZjIdrh6UbSROrgTNgmbeASxfDSHHmmcZyIUtMzBC45bmz3ra/FO0
|
||||
eb+6srXOmdIG368/xRdo9o1R/cNw9BHgGu5R/Bx+AxhK8DuhL7rMYLVn3Ukl2qrt
|
||||
0koCtDbPxq2YgF8VYXz4WNRCmLuUroty99WVOM7BvM3XyfSP5iLynoRr8B7Rju5K
|
||||
t5o/OJUrNqSNjtzYd3PZEXqi7ShWkYp5BACzBfSxkGfL6bBMfoM8Yd3dBLrplRu8
|
||||
WpVbJSA3DbJwAyGhKP3dQmmhBH9nJEppSK0iQPCruAyyZJT6kEmPhcNuYq8CyWe4
|
||||
+l9Hs5qIHMrkEq1BcLYiQFBLVLXR6eHf3J8fAMmz8I74TWNM2u3FZUcDoIwqHmHG
|
||||
zDwYZ9h1tkijvyvbH5RkMWRb7WAB2b9Q9ZsPR0naQbqHmO73Uypu/pfugx+cmOPr
|
||||
AiYOQHnwSCDcaTHJnO33L7KhgA+RfIRoigJXgeYzlWmjW/U6SRK8RTvda4lxPsOo
|
||||
/bXTZOoUA8qTDKT02n20h0Ab6kLDApSigGQlYI8Jhfre/PGFWfrLxPpy4ED53sPg
|
||||
xY1d6tIa18yQCAznC3k6Q9OK02bGaFTcGnTPg88PBgyUFuqljKGrG9rpm4uTPzwa
|
||||
1vzKv05oYjK9xyzy6LkIPYHyp6R2tedVO34pa52LNCO3/DaLnwiDfMRW5SFu0J0E
|
||||
P7/viLPTwwR6zdAAlt8hsT6apBYlLzVqGRy9nbN60ZS3Q8lIe6xR47koWAJvnHuS
|
||||
uBx9xP3JWcs+Cnis85wODY1qxXa0Yx58kUVmoyyiBOWHcwsi82YtgwAAjhR8K1wy
|
||||
gRJR72XIKmdZ/RINp7f2dN7xswy8iU2m3vBxgc1AH2/8knlGLebNS7/RJwW1KXsb
|
||||
pp/6vHRPSla5cxzsF9NmYHmSAUpk1t+Mo+YjjoT63bVC4xNzkXdft4l4QyUQQXU2
|
||||
aENeUJKn2r8X3Tpz92U=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
';
|
||||
$pass = 'asdf';
|
||||
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
|
||||
public function testPKCS82DES()
|
||||
{
|
||||
// openssl pkcs8 -in private.pem -topk8 -v1 PBE-SHA1-2DES -out enckey.pem
|
||||
|
||||
// EncryptionAlgorithm: pbeWithSHAAnd2-KeyTripleDES-CBC
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEEMA4ECGT21lf3Tl4dAgIIAASCBMgJmnyaQktoSk8u
|
||||
JyUAaB4ZgGWW22BX1xRA7en0sNj4PhBxj1DEXGKNUBx3k6u6Cd7JUupxGfeag5aw
|
||||
fi0bWNgEw7YSITmZKaKO5Ee4shQrEDucaH6KEGYV6YspNys5dD817hmd4Yc31q2e
|
||||
Ig5k3rIpP72Yy9Si0FXmKDE8/GmCYckdIQVUCGZD9nLugvqEC0adludfMAwzCHUY
|
||||
68jeyKiPJGTFSmE0wPD5EaWknn3U0eRcmKwZPtFpWEAEv5GTm1h6Y5q+P2X2Qsia
|
||||
Neoa4jjnSEww85zbno/k0KdoRIuSEM8qOHdNuU6XNTCGKxEkgBLkY+vjRjOCi+K4
|
||||
fzJSAPxaYATGX+W8EWegz3yhwiFujjDPkO9nfeoyks/saFbP9uT8aesZUn4/rIw0
|
||||
KyW7lYW0TUyBxfIXg1DEsKcmSrrb0WrFLN/MnjO8Y1bAY63KgKgpFZk+7H/7eCmD
|
||||
2Egj6o2LXTEPkxwYyeR41k64LM5RFF5qs4wS0Gfo1oTc6lSbuZNFHSgsXkb+CXFL
|
||||
JZ3CuaYFY5Ldfm+1HsrZ9s3GmNAnog6WABXIcz9aULUyJfLr+oZaQR7TC5KpM5Xy
|
||||
dyztlsN43D9UZKdz93zW2V3LxbzbOWTrcd9dB1GwrPvWIy/0/dqFOvpcr9k/4S1T
|
||||
AJ6pja4x19EQLj2DUvO7JQEy2Rlam+SI/ARQTc0W0dJ8x7FboHZDxUQCRDih5Qw3
|
||||
s/xoGflLUYYtAR5hfgjbWuvG3Told4IYlBn2vvVu7UxXQekUOaZLePqucAP3sTDC
|
||||
pK7JK+OT223FNU5NieGS4hh+jxZQnLuuyxWQaTCJM9isYPqJYsWT9X+c44ixOgLJ
|
||||
unYtg+8Lck3On6wiDUPWTLCGJvjb53NhPSovTjNBW2Q7YszXXjeO5svwwxtKHabx
|
||||
vCDsG0zdNdwIgupqynbtcuUhsmIsJKBu5c+9i8P21rNF0DZjOkv8mThRA6YQLce8
|
||||
mLTcnpLsvCGNehVEStD6pr+CtGsQEEtH3bPc2ZBrpxtz1EHmrI7H3kX1gjbD7bsT
|
||||
XWzaxsId+8pmqnAcMRzU3mRv4Fe+387X2irG4OxR/6cFMk3+yfpKJLSsNh6HAVRX
|
||||
xzYwVz2WP7RM0KuLh7auAcI1mHk+0xAvDi7s3ggy3SzLzQq9p+EEFVGVSYuVFLbi
|
||||
TtlY6HQ3b1Z6KgntoPj79YuOmri6/8w7nBkKt09faYLUf9wZWHLL9/LjZqoJxPfl
|
||||
lX5Ss4+MDV1aG9aJoTT53d8Gn8ApWK+XFToFg2InYZzZqBnKP8DHPG8D2Gh/MZlA
|
||||
Yt4hPDNLf733zm1zJTWo0TF6+4AwZp7XUKTg+pM1CZJDOTbJlEA+cXY3BxOq10bl
|
||||
JPJmV/JFINqSeBLN8V2Ong8Q0Dt4uabSmlOUz19SXpimBrO8ztxaqigMFIKMbLXX
|
||||
uIVAoxG7KLPuv44yK3Fjsg6OtwZnrWqea02b1qwFFrIKoqmQ8FNFBMYqcHU2IkSq
|
||||
gJqSylfqcre5Y1DOSlcjGa7aP4C8AyB5qOG7LZ/CLAePKqgAHtMd/K40Zgku36Ir
|
||||
9OAcUXy/H5PFJIleEyjvLLBE0VWs0TVBXi/FiIqwvAYNOFqXl/gtRcZ0kVex/QeN
|
||||
rcONqwmUGJOjrfhUyJA=
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
';
|
||||
$pass = 'asdf';
|
||||
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
|
||||
public function testPKCS8RC2()
|
||||
{
|
||||
// openssl pkcs8 -in private.pem -topk8 -v1 PBE-SHA1-RC2-128 -out enckey.pem
|
||||
|
||||
// EncryptionAlgorithm: pbeWithSHAAnd128BitRC2-CBC
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEFMA4ECAdC2l5rzAQeAgIIAASCBMjuEQDNkvSX6ylp
|
||||
WsgQZUSvPdNpdlG084oLmhTV0z4pZeLB0YCyKCM7GMVQ0tsprRW0ky86ulbY3W5Q
|
||||
86WNHXYtVIFXEmIjN1syRG5Pq3RZ4Ba6wf36Gc/1713p6GjcPxLZ+JOw1xBEm1rh
|
||||
1nI9b43PzbKmczs+6IvRO5b9MjKNkBeNzH9kh4b3zsEW/IFgYaz8zip/zRu4hCSW
|
||||
ORhnRYFvbI22E84g4/SB1WS34nR/flyZBXT4P87s7bwXEOsXAGnEeVF38znV3awD
|
||||
V8rry2e1drRmlhfNhvDroQrkv7O9X2ee91I9gahPKpXtAlGXBgRb8qjVHeI8Ea3K
|
||||
Ty2zcWnjdE7/jt6pO07+B+FlHNdKySlFdKTHEmJ1x+O5Ui4JaGjI2UML0yGHoYFU
|
||||
wGH/1DYJ4+R9d97BYJ/yp9+JAQAjpG7UUt3jFgNx0CAbP7d438l06z2EE87EqIEa
|
||||
3Y0ZG1Q5PWE60hPJsvUELdgzcUiKkVCxhOPhwmbSlQpEYXZRBWv0RAJzey6yPMQ+
|
||||
L/TkMDpgTNUk9x+n3ehnRuA/tlthxXN/ViDthPO7ovSVCsKsUq6lXotO+3hHLGs0
|
||||
u8ZyVKHNEqGso7PfAFsjcJq2C46mQNME4HPOWm5J+TFf/vvwqdYKCiF3arV0hUtW
|
||||
x9lyPR2PvZM1ik9jXi6lc5hPegcwmx9/j5yc4/3rQNiwe4dtUpL5JLKAxecKBLgr
|
||||
atyVnAs69JYaaUT9aKRDzYzCRjo0jIQ9/lgJl2DqVRF9aYnknrVWRIjyKbfKjw7N
|
||||
w0yfXlVRw46YuJ72PSHpr7HcfzL1EWzmKcAEPDH/UCpIaoeNTwxeEQSltOM0D0Su
|
||||
ZzyAQP8sWSXSwdtD5YD7iiUjDN4UMDuIwAEMLN9231/RjvKuLAys0oNRQfHkkiCo
|
||||
9rt/VUP8be98UTyKu7Bx7JUEW6VVnYM+Y274MLQk6TcjZyXgbKwhHFJyAjcBAFQp
|
||||
5kkYES0kk+57HeBImcB0a5qBor/uAnlsCV690roUlBtkVhBOkTjVi7w/uZsSjIWr
|
||||
MBndNHTFqqnkbm8xOOoSH6vS32c1KE8FrGpmkPGc6wziX9Ja/MkuLDXrBIlnP4Yj
|
||||
aCf0sVMSR1/LoHIGGaGXmTzs0VTR8Z5EyW5uvvCy6dWCWnTKEWmTTS+zqW1RYVBZ
|
||||
n/P2ovj2Kl4rhQuSpfOE9xBFWsgPAD6T2FJzfvu0/D3Sw5pI/RT4NnQ77oJSs+jN
|
||||
lV33FeceRoJqjcP6YMAiRX4RmkTeD5Hgy0YRLrfQ4PKwAQG82uIj3yqXWveexwb0
|
||||
Cpm5XxzgCMWGBRvIvM+yByf0SP7fIWYHbzsEWJkN5btF3tMc6i12q7AJ0/UFMQLt
|
||||
KNiMg+dLWP18cySU8OysXqPq1JKHDU1NMg2Xf9o2c35eOktLfcO9axS4oAAz4bGN
|
||||
hTB8rk+MWnHfSlWvMPMzlJyndXv/WxfojujLogDTOHd4/q4KyoOwJY3H44eeW79u
|
||||
sS7pDbjKMl8A15BLMLx01DaOYk7EiHFnGIpY2V2+2Xm7vQu9+8fHSf8whuCRVmBY
|
||||
Drhy2HTF1veKrQ6IrIyQicmzTtW6moSnNg69SpuzKTegYyCRsSHDIL3WxMoopVwr
|
||||
Pu3ed6UvXDfotj3v8rE=
|
||||
-----END ENCRYPTED PRIVATE KEY-----';
|
||||
$pass = 'asdf';
|
||||
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
|
||||
public function testPKCS8RC240()
|
||||
{
|
||||
// openssl pkcs8 -in private.pem -topk8 -v1 PBE-SHA1-RC2-40 -out enckey.pem
|
||||
|
||||
// EncryptionAlgorithm: pbeWithSHAAnd40BitRC2-CBC
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6jAcBgoqhkiG9w0BDAEGMA4ECHzZ2FqUJyiCAgIIAASCBMiKVNJiU/1UCaoq
|
||||
V6VSX33gL8CjQqhzDEUlXhHoSYx7IWAJIx7C1DDgeLDfJ//cCMlBPbIOr6knohFQ
|
||||
KegbsulIYm2DXUQvEoivh02F4An2RLkP0JSMl5CmYTbiu/nJic2jdin+vaKWhRA8
|
||||
Kznk5wEuhz4t6Oo4Hp3k3+0sd6YqLbmdcFCiYSXE52WN271VvUXqwz3TosUgOUVH
|
||||
YNzlER1xzNBFgcUyrfiyA+t5NaSDfpYncD64zXFz2KgkjcpfPBBMRnQ2I4mperbe
|
||||
3uUt8ZFCVeRiROWtx9WQgCVDDWztlrYzfEo/lFtNKjdseiYDj1/1gG6S2x5/S5dP
|
||||
LzEndNYiVEB2q9XrocrdKVumr7EqNe7C/AMNxuyfAoU2QV5SRyDDSRa1muYwHBa7
|
||||
x2XIThMS2tQLdN9bjJGcT653DKoq0Qwf1uMAOdHuqBLNXOpZw8PG8d3xmVHCyB4u
|
||||
rr5E48L2DmD0TwY3YBjfb3KCw/r/CvT1/cWkCpO90aNmSS4JMuOBiFlKaERMvXcw
|
||||
Ffo0ErZWwlgDN40hQO7xySxI3Paz6/QbxXunVnFQkTclkcQG63K6nWO9fMtgxRaZ
|
||||
ZGsv/jdWUZ6fBvOvW09zLvF2ZXKhTbfwU47C+2TefvENVz4rTAJcGgtF1wiFv1Lt
|
||||
0XT2FeJ6/jVGhk6745cHgOhsxqamOTuQ/y948ViMmR037INHouazD8dWHkjOY45d
|
||||
hy0DjRGIiig94/r+b7YZn81QUkk0HddyH4zi18f5Lx+ExiLDKaLqLv57PQ3ZCeBy
|
||||
v6Hoq/5tpZWCdXkLIAHx/a7ltiJQlyRUr8QcKPcGfr/qvIcYsUocHZ3iwkhxCnZ9
|
||||
77E2f/Owf8VaS3x4g5V6RYNlkhuqVixLq/3QyphykcqDK2g4PnWfq8prGY97jHXN
|
||||
+LZdwwV8LJkkoxCG1aehPlvtpGYGS75aeU1iFbqfke+gF2JG4LJZQsl1dAoL8R+X
|
||||
ZdILuN+182CpwwptK4QmCvSWXk/ZJtYK9e6OtE1keLM4oQW122fxwyVkEnnAR2/f
|
||||
Qc2U3WLk/UZSuhcHExxreWP4kiN8cYgSpw+k2uk7Xuw2kelu6hv6UzB4EtL8Xy4O
|
||||
kK7y6EjCkRJVqQoZ3vVny5408edc7Kh6bz0P5G4LIaCpvrcCYOJv2f57/lr8dMM6
|
||||
XcoZ0YIXATdUzKzhXKNFiib7SzBwFRRD+jMwzLnNeUhss8IUVl5LYwD6sOWbhdep
|
||||
LtUO2eXa74i6pa7sz1PLLWDZQ64f9fVPX7EEBy2LBVP3iLqLd2x/OHw+s7pTPT0G
|
||||
EgRpW0+IYBZGQjGN9s1VXXyhTm3RL03KeYls7aHmmcVqDqvozarqplN/kAhSGPmD
|
||||
N99FlSrIfihCEZlXO4iP2LRkJaFy11mU0ZvIMkDJ51fNO8PWypca4Rgi4azMCaiR
|
||||
HW/dtSBH2N8St0G80c2gUKXRmmJWFqebUIk4000VrpDcZlg0INC2unY0NwRFDe2a
|
||||
55/NR7TO9GdhWYDWsZedRatUFul5DWznncIfrXAD3T32gUR3I9zc62OFVsH2Dve3
|
||||
oMZUabvnj3g1sQqiRgJyIe5aVZljgXMh0cdWjcUi34vOVBU8yOU921/jSinJWyH7
|
||||
GxyNlS3BiKQ22CLvbjc=
|
||||
-----END ENCRYPTED PRIVATE KEY-----';
|
||||
$pass = 'asdf';
|
||||
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
|
||||
public function testPKCS8RC4()
|
||||
{
|
||||
// openssl pkcs8 -in private.pem -topk8 -v1 PBE-SHA1-RC4-128 -out enckey.pem
|
||||
|
||||
// EncryptionAlgorithm: pbeWithSHAAnd128BitRC4
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE5DAcBgoqhkiG9w0BDAEBMA4ECKQOMmQxsqe0AgIIAASCBMJ86iav9sz/nsgC
|
||||
KrPC1m7fPDuJF1BCPd6Yu+b+D4++4htITNBujK+Ur0xgQnfs7+Et8/cz521KR1zp
|
||||
kalr56rqvPu9X45l86f/PYv6D+3660jxAadk1bZ9Y7nXzjXsFlZljEi/oLYSAKwh
|
||||
rn88ZNBM7hwoEtEZJXOK7yZlcpfLuNyRJhfxRp893yeG3SHDN+SAKzqbjrGtPnJY
|
||||
2X0Y/KidhYAYLi3onhxkq6I9aEI54oBZUiKLHhRD5/ASx8EeSPK2Ydj20PfDIRIk
|
||||
t75Tlqn5eLC124xdO0rm/vrczIrzo+JaqLq8dO0T7PGrR7hv9OyFwM6ssfzl2MyT
|
||||
Si4Yv3gBk6dUQ4lySj6XfscjEPwnUSjO3SMwAV0uBoBxDyeKg+58sT0e4Ow7k+6U
|
||||
SFoqa2m+gBAjXzL8SaGfvjfy0ViBtgLycGrK80dp7k0L5pJAZou7WCPWlP+5+kIl
|
||||
IprSGD1luOm1olQBSaQO+GkhQlMg4jK7cMKM2bRWyT2ibq8KZujlhWlcqXbbaqSh
|
||||
nJdadTfAsaCf3/hK1fiFwwSyFbiPjIE1H+WS+JMcg826S7FzoZ3BzcEVbiHRsBXy
|
||||
PS95ZM3v/HWOejEO44NEqnrwjyqBlSJXOK2WLOUWWlf6t8pdQEjA1xUfJARXqv16
|
||||
rQEXq2ZTGBOGeorwKLeUNgMQS7SfVP56Mmi23A3QQk7JNPXfkcrQscHu3mzesYKA
|
||||
+ckJwDsyjnTwYWFXfDxfReKVA17YSV160oKCPhO7jIeiHO8azw7RKaaIaueKe5QU
|
||||
boKWPAKeEfsDrSxtEYxy6hQ/45LYB+gUlAauaFlT4d0qMWQzt05Zs4ugUtx8SuI3
|
||||
hWB80fi8XEJajti/3JIg0+cDEmv9XtYQXpaFKR/gTHl1ReSscY/rNyiUc7t1dBsn
|
||||
kAwMhk/7p/0MZdEpG0e3qQ9Fs2pELlShzORobM0HWd41d2BkW54W/TJ9ERJhMU9Q
|
||||
NJ5KZDukkCdTIgvnPKJ/50byYVGtt8VBXDzMQsm5ex9yDkEmBLtc14z7UaGd7FCK
|
||||
xmbcVfkf+h5GPuJqXiZv9RsOfV0eVXlNx7jQ8Pq3FM5EiL8Wtj1XB3+cpFkPREoC
|
||||
lA9enCZNdjXPB4SSz4kF+UwWdaNS77SGXDq4NQRT/cu4mce+1VPjepEc1WzLw5m+
|
||||
aaHtJJCdLhaUJmYfaPGz4kg2CSdFCDjzDLOQCOwGtqAY6667ZOFb2VCukQR2aSfK
|
||||
XJF4Br7UsKhtlZvRDZGLSdxS/6IPe3KgzInP+27kLpv5UcolD3GfuS9WZhfa7tlB
|
||||
37n5nyGJCgVHufWRrYdKPI32Dn4R312/k+6X9zR1G4FlYzbuA+g2Q5CX8n5e/9jm
|
||||
1WjCv8ppB3p3BjIv8iEAyfPShwe4uk2ohry+nY/pq7qYl3E7Y6vS1MOmRJT5jvBA
|
||||
oCWQITjRu/d0xocYp6agkMEBgkyiqzLEW8PV2bziRZVGsYvC/4ky1MVERFO9jiSk
|
||||
3L6Xllp1yB+Mw9y12bUhDAZNAqpkNtL0CJbLKh6fQ7x6l4d0t/QqpuKXPvF5l0wr
|
||||
+Fb131STrh7fkiTT1glrra1UhJzz/KVOR+TG32GOSI0hOTqu4/gDQ/vUV0gh0SJw
|
||||
OvndKFWbSnE=
|
||||
-----END ENCRYPTED PRIVATE KEY-----';
|
||||
$pass = 'asdf';
|
||||
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
|
||||
public function testPKCS8RC440()
|
||||
{
|
||||
// openssl pkcs8 -in private.pem -topk8 -v1 PBE-SHA1-RC4-40 -out enckey.pem
|
||||
|
||||
// EncryptionAlgorithm: pbeWithSHAAnd40BitRC4
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE5DAcBgoqhkiG9w0BDAECMA4ECNrUHnZnezluAgIIAASCBMKm0lEML1hIdzcu
|
||||
pglVZSwG8JyigX3xgHwnN4oAz6HYTNeatkV3xqGP23DP84e9En7mQTRxuQ9Tk8sN
|
||||
NoEK2VsjYmrJtsbyTH21M0vPlAvFv/sIgxVYcF7jv58jHhLNnibPtDeMXZDjd4uq
|
||||
vdppAGRxIr5z8XZ8ruAlsAB/xzcz1bIK8CwWH9NBOWLDe195/OYoUrgf9h+U2s8e
|
||||
1rbq+U/woJZHD7+3RuPmtWTtrneY/NVTiU03OUUleys88eCSqZrQzR0faNxdVzTg
|
||||
mhSrtkqwho9xxUFY6KqLOTF4BQufD+ZSNt9LN3EaFdvGcI1QWWDH11ne98oz3GUa
|
||||
GCGhaADTOAAOdvXyv+6YRfj1VvtisUeiGjttFmaUHGOmHCCYoyVkbhsRq4QnbbCv
|
||||
641ogRbuISBHwr+mzqjwTZXC5Laxsrn5EnCZ309vohq7l+g3M1Y9nzR8hOsiqTFu
|
||||
7PPj1jYM8znYkVx/me+xnpB/d3Ot86K6NszbTaWk9cHr4qfkF+pu2kUYQ/26CUBE
|
||||
y7DxYmhXnOBRGUTvQebrMoSK8hOaw0uWEQtYp3gLOS1hituL965m2qRbP/ysDP85
|
||||
DAorOSbKDEMHYy7UP3xh743FErEOoY83GtugnJgjrTlJ/5NyS1KFr5QUsQD/N/Zw
|
||||
bIkjdFT5mjWVaotHzpNc1IigpAPbNpe4J1E1E2nB8YE5ckSEVseUJ+ypgWSvJxmU
|
||||
G68YvidODClnBekff8sRDCNN4dekQgnNEMbAWgHRWtMERvXS/9xfJZiqiq+7WvIE
|
||||
Xvu1Qq5zG3+mESNX9AVLngv5btD2m6QFEqOLG9JKQWp61J3c2lG/kdtWBjsXiWoi
|
||||
zvkA4u9ZxUzX3s3T2aHozg9O4+0ti947l7wSIxbxLYA0d1M7cQoeKAuRnpwzfCZ9
|
||||
gpQ9VG9acDhU9LCxcZBHfuKROeI7D7wL//MJp/ue26uhOZY7Z0gbFIfjeSPW+HD0
|
||||
fRGA849/1aKIsRarKg2YleqsXO04E3J/lpTt1gjy3aGE25Arq6qo+4DRsUIIWeS+
|
||||
QwzdDeqy1zs8BIPxa51U/jvbqxCvqXsMw4la0txkSwymMvc6U+QpJgm2KqSDCs8W
|
||||
+QYIz4SYlADLgl+MVDGd9IB/PN8AIZ0Lr7QqKKBIrfyegO/gjCkHCdNIh1Q/Bzbf
|
||||
rq8AYwbxHnp2Jn2MAzw9s13ncENpZqCDHkhmd89hJc1B4f8rv5KhDsIVb85XQJek
|
||||
pdpqugcYjxohSBEa9yzp0JDRa97Btir7D4+9HG2NUullFgXvbqKvlKPj+ORUDxJd
|
||||
DMGC2Uov1koiVBvvahtmr8eTBNdA48cA7l/c5t8UsGbjrwpqLZLTJ1FHjnVKybuu
|
||||
soPwPAxr3WBE4Ien7WqPj+GTeLWMb9//kpi5grguv3Db6rdH2Y4PT9Fi4UBxd+6N
|
||||
LqB1rPkt4AQtQwda1ccixYXIFfWSJ6+XEyp6/wsW05DZAiu3R4o/T9Z59KPGlbf0
|
||||
aaEAW+FZ9jYa6sDBlMwCN2TEmnBFkytJYe8+B5UxkEAIn3g/Vr9R4t4YDCSE2ugs
|
||||
q6YJC1bQ8jHojcWTs47zcefCXhOkKOg3oxzYIQe9Ikdmf70JxIo+bS92O2vrkV0p
|
||||
OFLPBrLe4Hw=
|
||||
-----END ENCRYPTED PRIVATE KEY-----';
|
||||
$pass = 'asdf';
|
||||
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user