mirror of
https://github.com/phpseclib/phpseclib.git
synced 2024-09-28 07:09:01 +00:00
Merge pull request #1061 from terrafrost/pkcs18-rewrite
RSA: refactor PKCS1/PKCS8 to facilitate re-use
This commit is contained in:
commit
81bae5ce8b
@ -1,12 +1,8 @@
|
|||||||
language: php
|
language: php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 5.5.9
|
|
||||||
- 5.5
|
|
||||||
- 5.6
|
|
||||||
- 7.0
|
- 7.0
|
||||||
- 7.1
|
- 7.1
|
||||||
- hhvm
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
"require": {
|
"require": {
|
||||||
"paragonie/constant_time_encoding": "^1|^2",
|
"paragonie/constant_time_encoding": "^1|^2",
|
||||||
"paragonie/random_compat": "^1.4|^2.0",
|
"paragonie/random_compat": "^1.4|^2.0",
|
||||||
"php": ">=5.3.3"
|
"php": ">=7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phing/phing": "~2.7",
|
"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\Crypt\Hash;
|
||||||
use phpseclib\Common\Functions\Strings;
|
use phpseclib\Common\Functions\Strings;
|
||||||
|
use phpseclib\Math\BigInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base Class for all \phpseclib\Crypt\* cipher classes
|
* 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.');
|
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.');
|
throw new \InvalidArgumentException('This algorithm does not use an IV.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,12 +623,17 @@ abstract class SymmetricKey
|
|||||||
{
|
{
|
||||||
$key = '';
|
$key = '';
|
||||||
|
|
||||||
|
$method = strtolower($method);
|
||||||
switch ($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();
|
$func_args = func_get_args();
|
||||||
|
|
||||||
// Hash function
|
// 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
|
// WPA and WPA2 use the SSID as the salt
|
||||||
$salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
|
$salt = isset($func_args[3]) ? $func_args[3] : $this->password_default_salt;
|
||||||
@ -645,10 +651,63 @@ abstract class SymmetricKey
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (true) {
|
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':
|
case $method == 'pbkdf1':
|
||||||
$hashObj = new Hash();
|
if ($dkLen > $hashObj->getLengthInBytes()) {
|
||||||
$hashObj->setHash($hash);
|
|
||||||
if ($dkLen > $hashObj->getLength()) {
|
|
||||||
throw new \LengthException('Derived key length cannot be longer than the hash length');
|
throw new \LengthException('Derived key length cannot be longer than the hash length');
|
||||||
}
|
}
|
||||||
$t = $password . $salt;
|
$t = $password . $salt;
|
||||||
@ -658,21 +717,20 @@ abstract class SymmetricKey
|
|||||||
$key = substr($t, 0, $dkLen);
|
$key = substr($t, 0, $dkLen);
|
||||||
|
|
||||||
$this->setKey(substr($key, 0, $dkLen >> 1));
|
$this->setKey(substr($key, 0, $dkLen >> 1));
|
||||||
|
if ($this->usesIV()) {
|
||||||
$this->setIV(substr($key, $dkLen >> 1));
|
$this->setIV(substr($key, $dkLen >> 1));
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
// Determining if php[>=5.5.0]'s hash_pbkdf2() function avail- and useable
|
|
||||||
case !function_exists('hash_pbkdf2'):
|
case !function_exists('hash_pbkdf2'):
|
||||||
case !function_exists('hash_algos'):
|
case !function_exists('hash_algos'):
|
||||||
case !in_array($hash, hash_algos()):
|
case !in_array($hash, hash_algos()):
|
||||||
$i = 1;
|
$i = 1;
|
||||||
|
$hashObj->setKey($password);
|
||||||
while (strlen($key) < $dkLen) {
|
while (strlen($key) < $dkLen) {
|
||||||
$hmac = new Hash();
|
$f = $u = $hashObj->hash($salt . pack('N', $i++));
|
||||||
$hmac->setHash($hash);
|
|
||||||
$hmac->setKey($password);
|
|
||||||
$f = $u = $hmac->hash($salt . pack('N', $i++));
|
|
||||||
for ($j = 2; $j <= $count; ++$j) {
|
for ($j = 2; $j <= $count; ++$j) {
|
||||||
$u = $hmac->hash($u);
|
$u = $hashObj->hash($u);
|
||||||
$f^= $u;
|
$f^= $u;
|
||||||
}
|
}
|
||||||
$key.= $f;
|
$key.= $f;
|
||||||
@ -682,6 +740,9 @@ abstract class SymmetricKey
|
|||||||
default:
|
default:
|
||||||
$key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
|
$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);
|
$this->setKey($key);
|
||||||
@ -689,6 +750,60 @@ abstract class SymmetricKey
|
|||||||
return true;
|
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.
|
* 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') {
|
if ($hash == 'sha512/224' || $hash == 'sha512/256') {
|
||||||
// from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24
|
// from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24
|
||||||
$this->initial = $hash == 'sha512/256' ?
|
$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
|
* @access public
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
function getLength()
|
function getLength()
|
||||||
|
{
|
||||||
|
return $this->length << 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hash length (in bytes)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
function getLengthInBytes()
|
||||||
{
|
{
|
||||||
return $this->length;
|
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
|
* Pure-PHP implementation of SHA512
|
||||||
*
|
*
|
||||||
|
@ -319,6 +319,7 @@ class RC2 extends BlockCipher
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->default_key_length = $this->current_key_length = $length;
|
$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
|
* has more then 128 bytes in it, and set $key to a single null byte if
|
||||||
* it is empty.
|
* 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()
|
* @see \phpseclib\Crypt\Common\SymmetricKey::setKey()
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $key
|
* @param string $key
|
||||||
@ -362,8 +360,10 @@ class RC2 extends BlockCipher
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->current_key_length = $t1;
|
$this->current_key_length = $t1;
|
||||||
// Key byte count should be 1..128.
|
if (strlen($key) < 1 || strlen($key) > 128) {
|
||||||
$key = strlen($key) ? substr($key, 0, 128) : "\x00";
|
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);
|
$t = strlen($key);
|
||||||
|
|
||||||
// The mcrypt RC2 implementation only supports effective key length
|
// The mcrypt RC2 implementation only supports effective key length
|
||||||
@ -392,7 +392,10 @@ class RC2 extends BlockCipher
|
|||||||
$l[0] = $this->invpitable[$l[0]];
|
$l[0] = $this->invpitable[$l[0]];
|
||||||
array_unshift($l, 'C*');
|
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
|
* @var string
|
||||||
* @access private
|
* @access private
|
||||||
*/
|
*/
|
||||||
var $key = "\0";
|
var $key;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Key Stream for decryption and encryption
|
* The Key Stream for decryption and encryption
|
||||||
|
@ -118,32 +118,6 @@ class RSA
|
|||||||
const PADDING_RELAXED_PKCS1 = 5;
|
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
|
* @access private
|
||||||
* @see self::__construct()
|
* @see self::__construct()
|
||||||
@ -151,13 +125,13 @@ class RSA
|
|||||||
/**
|
/**
|
||||||
* To use the pure-PHP implementation
|
* To use the pure-PHP implementation
|
||||||
*/
|
*/
|
||||||
const MODE_INTERNAL = 1;
|
const ENGINE_INTERNAL = 1;
|
||||||
/**
|
/**
|
||||||
* To use the OpenSSL library
|
* To use the OpenSSL library
|
||||||
*
|
*
|
||||||
* (if enabled; otherwise, the internal implementation will be used)
|
* (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
|
* @var string
|
||||||
* @access private
|
* @access private
|
||||||
*/
|
*/
|
||||||
var $privateKeyFormat = 'PKCS1';
|
var $privateKeyFormat = 'PKCS8';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public Key Format
|
* Public Key Format
|
||||||
@ -341,6 +315,39 @@ class RSA
|
|||||||
*/
|
*/
|
||||||
static $origFileFormats = false;
|
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
|
* Initialize static variables
|
||||||
@ -384,10 +391,49 @@ class RSA
|
|||||||
self::_initialize_static_variables();
|
self::_initialize_static_variables();
|
||||||
|
|
||||||
$this->hash = new Hash('sha256');
|
$this->hash = new Hash('sha256');
|
||||||
$this->hLen = $this->hash->getLength();
|
$this->hLen = $this->hash->getLengthInBytes();
|
||||||
$this->hashName = 'sha256';
|
$this->hashName = 'sha256';
|
||||||
$this->mgfHash = new Hash('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 int $timeout
|
||||||
* @param array $p
|
* @param array $p
|
||||||
*/
|
*/
|
||||||
static function createKey($bits = 2048, $timeout = false, $partial = array())
|
static function createKey($bits = 2048)
|
||||||
{
|
{
|
||||||
self::_initialize_static_variables();
|
self::_initialize_static_variables();
|
||||||
|
|
||||||
if (!defined('CRYPT_RSA_MODE')) {
|
if (!isset(self::$engine)) {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
// Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
|
// 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
|
// 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.
|
// can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
|
||||||
case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
|
case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
|
||||||
define('CRYPT_RSA_MODE', self::MODE_INTERNAL);
|
self::$engine = self::ENGINE_INTERNAL;
|
||||||
break;
|
break;
|
||||||
case extension_loaded('openssl') && file_exists(self::$configFile):
|
case extension_loaded('openssl') && file_exists(self::$configFile):
|
||||||
define('CRYPT_RSA_MODE', self::MODE_OPENSSL);
|
self::$engine = self::ENGINE_OPENSSL;
|
||||||
break;
|
break;
|
||||||
default:
|
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
|
// 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();
|
$config = array();
|
||||||
if (isset(self::$configFile)) {
|
if (isset(self::$configFile)) {
|
||||||
$config['config'] = self::$configFile;
|
$config['config'] = self::$configFile;
|
||||||
@ -466,75 +499,34 @@ class RSA
|
|||||||
|
|
||||||
static $e;
|
static $e;
|
||||||
if (!isset($e)) {
|
if (!isset($e)) {
|
||||||
$e = new BigInteger(CRYPT_RSA_EXPONENT);
|
$e = new BigInteger(self::$defaultExponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
extract(self::_generateMinMax($bits));
|
$regSize = $bits >> 1; // divide by two to see how many bits P and Q would be
|
||||||
$absoluteMin = $min;
|
if ($regSize > self::$smallestPrime) {
|
||||||
$temp = $bits >> 1; // divide by two to see how many bits P and Q would be
|
$num_primes = floor($bits / self::$smallestPrime);
|
||||||
if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
|
$regSize = self::$smallestPrime;
|
||||||
$num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
|
|
||||||
$temp = CRYPT_RSA_SMALLEST_PRIME;
|
|
||||||
} else {
|
} else {
|
||||||
$num_primes = 2;
|
$num_primes = 2;
|
||||||
}
|
}
|
||||||
$regSize = $temp;
|
|
||||||
$finalSize = $temp + $bits % $temp;
|
|
||||||
|
|
||||||
$n = clone self::$one;
|
$n = clone self::$one;
|
||||||
if (!empty($partial)) {
|
|
||||||
extract(unserialize($partial));
|
|
||||||
} else {
|
|
||||||
$exponents = $coefficients = $primes = array();
|
$exponents = $coefficients = $primes = array();
|
||||||
$lcm = array(
|
$lcm = array(
|
||||||
'top' => clone self::$one,
|
'top' => clone self::$one,
|
||||||
'bottom' => false
|
'bottom' => false
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
$start = time();
|
|
||||||
$i0 = count($primes) + 1;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
for ($i = $i0; $i <= $num_primes; $i++) {
|
for ($i = 1; $i <= $num_primes; $i++) {
|
||||||
if ($timeout !== false) {
|
if ($i != $num_primes) {
|
||||||
$timeout-= time() - $start;
|
$primes[$i] = BigInteger::randomPrime($regSize);
|
||||||
$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 {
|
} else {
|
||||||
array_pop($primes);
|
extract(BigInteger::minMaxBits($bits));
|
||||||
$partialkey = serialize(array(
|
list($min) = $min->divide($n);
|
||||||
'primes' => $primes,
|
$min = $min->add(self::$one);
|
||||||
'coefficients' => $coefficients,
|
list($max) = $max->divide($n);
|
||||||
'lcm' => $lcm,
|
$primes[$i] = BigInteger::randomRangePrime($min, $max);
|
||||||
'exponents' => $exponents
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'privatekey' => false,
|
|
||||||
'publickey' => false,
|
|
||||||
'partialkey' => $partialkey
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the first coefficient is calculated differently from the rest
|
// 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
|
// see http://en.wikipedia.org/wiki/Euler%27s_totient_function
|
||||||
$lcm['top'] = $lcm['top']->multiply($temp);
|
$lcm['top'] = $lcm['top']->multiply($temp);
|
||||||
$lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
|
$lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
|
||||||
|
|
||||||
$exponents[$i] = $e->modInverse($temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list($temp) = $lcm['top']->divide($lcm['bottom']);
|
list($temp) = $lcm['top']->divide($lcm['bottom']);
|
||||||
@ -560,9 +550,14 @@ class RSA
|
|||||||
$i0 = 1;
|
$i0 = 1;
|
||||||
} while (!$gcd->equals(self::$one));
|
} while (!$gcd->equals(self::$one));
|
||||||
|
|
||||||
|
$coefficients[2] = $primes[2]->modInverse($primes[1]);
|
||||||
|
|
||||||
$d = $e->modInverse($temp);
|
$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>:
|
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
|
||||||
// RSAPrivateKey ::= SEQUENCE {
|
// RSAPrivateKey ::= SEQUENCE {
|
||||||
@ -594,8 +589,7 @@ class RSA
|
|||||||
|
|
||||||
return array(
|
return array(
|
||||||
'privatekey' => $privatekey,
|
'privatekey' => $privatekey,
|
||||||
'publickey' => $publickey,
|
'publickey' => $publickey
|
||||||
'partialkey' => false
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -705,11 +699,7 @@ class RSA
|
|||||||
$format = strtolower($type);
|
$format = strtolower($type);
|
||||||
if (isset(self::$fileFormats[$format])) {
|
if (isset(self::$fileFormats[$format])) {
|
||||||
$format = self::$fileFormats[$format];
|
$format = self::$fileFormats[$format];
|
||||||
try {
|
|
||||||
$components = $format::load($key, $this->password);
|
$components = $format::load($key, $this->password);
|
||||||
} catch (\Exception $e) {
|
|
||||||
$components = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -721,7 +711,7 @@ class RSA
|
|||||||
$this->format = $format;
|
$this->format = $format;
|
||||||
|
|
||||||
$this->modulus = $components['modulus'];
|
$this->modulus = $components['modulus'];
|
||||||
$this->k = strlen($this->modulus->toBytes());
|
$this->k = $this->modulus->getLengthInBytes();
|
||||||
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
|
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
|
||||||
if (isset($components['primes'])) {
|
if (isset($components['primes'])) {
|
||||||
$this->primes = $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);
|
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
|
* @access public
|
||||||
* @return int
|
* @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()
|
function __toString()
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
$key = $this->getPrivateKey($this->privateKeyFormat);
|
$key = $this->getPrivateKey($this->privateKeyFormat);
|
||||||
if (is_string($key)) {
|
if (is_string($key)) {
|
||||||
return $key;
|
return $key;
|
||||||
}
|
}
|
||||||
$key = $this->_getPrivatePublicKey($this->publicKeyFormat);
|
$key = $this->_getPrivatePublicKey($this->publicKeyFormat);
|
||||||
return is_string($key) ? $key : '';
|
return is_string($key) ? $key : '';
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1112,7 +1134,7 @@ class RSA
|
|||||||
$this->hash = new Hash('sha256');
|
$this->hash = new Hash('sha256');
|
||||||
$this->hashName = 'sha256';
|
$this->hashName = 'sha256';
|
||||||
}
|
}
|
||||||
$this->hLen = $this->hash->getLength();
|
$this->hLen = $this->hash->getLengthInBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1142,7 +1164,7 @@ class RSA
|
|||||||
default:
|
default:
|
||||||
$this->mgfHash = new Hash('sha256');
|
$this->mgfHash = new Hash('sha256');
|
||||||
}
|
}
|
||||||
$this->mgfHLen = $this->mgfHash->getLength();
|
$this->mgfHLen = $this->mgfHash->getLengthInBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1316,7 +1338,7 @@ class RSA
|
|||||||
* @param string $y
|
* @param string $y
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
function _equals($x, $y)
|
static function _equals($x, $y)
|
||||||
{
|
{
|
||||||
if (strlen($x) != strlen($y)) {
|
if (strlen($x) != strlen($y)) {
|
||||||
return false;
|
return false;
|
||||||
@ -1528,7 +1550,7 @@ class RSA
|
|||||||
$db = $maskedDB ^ $dbMask;
|
$db = $maskedDB ^ $dbMask;
|
||||||
$lHash2 = substr($db, 0, $this->hLen);
|
$lHash2 = substr($db, 0, $this->hLen);
|
||||||
$m = substr($db, $this->hLen);
|
$m = substr($db, $this->hLen);
|
||||||
if ($lHash != $lHash2) {
|
if (!self::_equals($lHash, $lHash2)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$m = ltrim($m, chr(0));
|
$m = ltrim($m, chr(0));
|
||||||
@ -1746,7 +1768,7 @@ class RSA
|
|||||||
$salt = substr($db, $temp + 1); // should be $sLen long
|
$salt = substr($db, $temp + 1); // should be $sLen long
|
||||||
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
||||||
$h2 = $this->hash->hash($m2);
|
$h2 = $this->hash->hash($m2);
|
||||||
return $this->_equals($h, $h2);
|
return self::_equals($h, $h2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1940,7 +1962,7 @@ class RSA
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
return $this->_equals($em, $em2);
|
return self::_equals($em, $em2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2044,7 +2066,7 @@ class RSA
|
|||||||
$em = $hash->hash($m);
|
$em = $hash->hash($m);
|
||||||
$em2 = Base64::decode($decoded['digest']);
|
$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;
|
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\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
|
* PKCS#1 Formatted RSA Key Handler
|
||||||
@ -40,25 +81,58 @@ use phpseclib\Common\Functions\ASN1;
|
|||||||
* @author Jim Wigginton <terrafrost@php.net>
|
* @author Jim Wigginton <terrafrost@php.net>
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
class PKCS1 extends PKCS
|
class PKCS1 extends Progenitor
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Default encryption algorithm
|
* Break a public or private key down into its constituent components
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
static $defaultEncryptionAlgorithm = 'DES-EDE3-CBC';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default encryption algorithm
|
|
||||||
*
|
*
|
||||||
* @access public
|
* @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 = '')
|
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||||
{
|
{
|
||||||
$num_primes = count($primes);
|
$num_primes = count($primes);
|
||||||
$raw = array(
|
$key = [
|
||||||
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
'version' => $num_primes == 2 ? 'two-prime' : 'multi',
|
||||||
'modulus' => $n->toBytes(true),
|
'modulus' => $n,
|
||||||
'publicExponent' => $e->toBytes(true),
|
'publicExponent' => $e,
|
||||||
'privateExponent' => $d->toBytes(true),
|
'privateExponent' => $d,
|
||||||
'prime1' => $primes[1]->toBytes(true),
|
'prime1' => $primes[1],
|
||||||
'prime2' => $primes[2]->toBytes(true),
|
'prime2' => $primes[2],
|
||||||
'exponent1' => $exponents[1]->toBytes(true),
|
'exponent1' => $exponents[1],
|
||||||
'exponent2' => $exponents[2]->toBytes(true),
|
'exponent2' => $exponents[2],
|
||||||
'coefficient' => $coefficients[2]->toBytes(true)
|
'coefficient' => $coefficients[2]
|
||||||
);
|
];
|
||||||
|
|
||||||
$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++) {
|
for ($i = 3; $i <= $num_primes; $i++) {
|
||||||
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
$key['otherPrimeInfos'][] = [
|
||||||
//
|
'prime' => $primes[$i],
|
||||||
// OtherPrimeInfo ::= SEQUENCE {
|
'exponent' => $exponents[$i],
|
||||||
// prime INTEGER, -- ri
|
'coefficient' => $coefficients[$i]
|
||||||
// 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);
|
$asn1 = new ASN1();
|
||||||
|
$key = $asn1->encodeDER($key, RSAPrivateKey);
|
||||||
|
|
||||||
if (!empty($password) || is_string($password)) {
|
return self::wrapPrivateKey($key, 'RSA', $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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,31 +186,14 @@ class PKCS1 extends PKCS
|
|||||||
*/
|
*/
|
||||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||||
{
|
{
|
||||||
$modulus = $n->toBytes(true);
|
$key = [
|
||||||
$publicExponent = $e->toBytes(true);
|
'modulus' => $n,
|
||||||
|
'publicExponent' => $e
|
||||||
|
];
|
||||||
|
|
||||||
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
$asn1 = new ASN1();
|
||||||
// RSAPublicKey ::= SEQUENCE {
|
$key = $asn1->encodeDER($key, RSAPublicKey);
|
||||||
// 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(
|
return self::wrapPublicKey($key, 'RSA');
|
||||||
'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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,21 +27,51 @@
|
|||||||
|
|
||||||
namespace phpseclib\Crypt\RSA;
|
namespace phpseclib\Crypt\RSA;
|
||||||
|
|
||||||
use ParagonIE\ConstantTime\Base64;
|
|
||||||
use phpseclib\Crypt\DES;
|
|
||||||
use phpseclib\Crypt\Random;
|
|
||||||
use phpseclib\Math\BigInteger;
|
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
|
* @package RSA
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
* @author Jim Wigginton <terrafrost@php.net>
|
||||||
* @access public
|
* @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.
|
* 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 = '')
|
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
||||||
{
|
{
|
||||||
$num_primes = count($primes);
|
$key = PKCS1::savePrivateKey($n, $e, $d, $primes, $exponents, $coefficients);
|
||||||
$raw = array(
|
$key = ASN1::extractBER($key);
|
||||||
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
return self::wrapPrivateKey($key, '1.2.840.113549.1.1.1', [], $password);
|
||||||
'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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -171,43 +102,8 @@ class PKCS8 extends PKCS
|
|||||||
*/
|
*/
|
||||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
static function savePublicKey(BigInteger $n, BigInteger $e)
|
||||||
{
|
{
|
||||||
$modulus = $n->toBytes(true);
|
$key = PKCS1::savePublicKey($n, $e);
|
||||||
$publicExponent = $e->toBytes(true);
|
$key = ASN1::extractBER($key);
|
||||||
|
return self::wrapPublicKey($key, '1.2.840.113549.1.1.1');
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,9 +138,6 @@ class PuTTY
|
|||||||
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
|
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
|
||||||
$crypto->disablePadding();
|
$crypto->disablePadding();
|
||||||
$private = $crypto->decrypt($private);
|
$private = $crypto->decrypt($private);
|
||||||
if ($private === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extract(unpack('Nlength', Strings::shift($private, 4)));
|
extract(unpack('Nlength', Strings::shift($private, 4)));
|
||||||
@ -289,7 +286,7 @@ class PuTTY
|
|||||||
$n
|
$n
|
||||||
);
|
);
|
||||||
$key = "---- BEGIN SSH2 PUBLIC KEY ----\r\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) .
|
chunk_split(Base64::encode($key), 64) .
|
||||||
'---- END SSH2 PUBLIC KEY ----';
|
'---- END SSH2 PUBLIC KEY ----';
|
||||||
|
|
||||||
|
@ -184,6 +184,7 @@ class Random
|
|||||||
$v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
|
$v = $crypto->encrypt($r ^ $i); // strlen($r) == 20
|
||||||
$result.= $r;
|
$result.= $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return substr($result, 0, $length);
|
return substr($result, 0, $length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1286,4 +1286,31 @@ class ASN1
|
|||||||
}
|
}
|
||||||
return $out;
|
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();
|
$asn1 = new ASN1();
|
||||||
|
|
||||||
if ($mode != self::FORMAT_DER) {
|
if ($mode != self::FORMAT_DER) {
|
||||||
$newcert = $this->_extractBER($cert);
|
$newcert = ASN1::extractBER($cert);
|
||||||
if ($mode == self::FORMAT_PEM && $cert == $newcert) {
|
if ($mode == self::FORMAT_PEM && $cert == $newcert) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2974,7 +2974,7 @@ class X509
|
|||||||
$asn1 = new ASN1();
|
$asn1 = new ASN1();
|
||||||
|
|
||||||
if ($mode != self::FORMAT_DER) {
|
if ($mode != self::FORMAT_DER) {
|
||||||
$newcsr = $this->_extractBER($csr);
|
$newcsr = ASN1::extractBER($csr);
|
||||||
if ($mode == self::FORMAT_PEM && $csr == $newcsr) {
|
if ($mode == self::FORMAT_PEM && $csr == $newcsr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3216,7 +3216,7 @@ class X509
|
|||||||
$asn1 = new ASN1();
|
$asn1 = new ASN1();
|
||||||
|
|
||||||
if ($mode != self::FORMAT_DER) {
|
if ($mode != self::FORMAT_DER) {
|
||||||
$newcrl = $this->_extractBER($crl);
|
$newcrl = ASN1::extractBER($crl);
|
||||||
if ($mode == self::FORMAT_PEM && $crl == $newcrl) {
|
if ($mode == self::FORMAT_PEM && $crl == $newcrl) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3847,7 +3847,7 @@ class X509
|
|||||||
if (strtolower($date) == 'lifetime') {
|
if (strtolower($date) == 'lifetime') {
|
||||||
$temp = '99991231235959Z';
|
$temp = '99991231235959Z';
|
||||||
$asn1 = new ASN1();
|
$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);
|
$this->endDate = new Element($temp);
|
||||||
} else {
|
} else {
|
||||||
$this->endDate = @date('D, d M Y H:i:s O', @strtotime($date));
|
$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.
|
// 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.
|
// Now we have the key string: compute its sha-1 sum.
|
||||||
$hash = new Hash('sha1');
|
$hash = new Hash('sha1');
|
||||||
@ -4770,33 +4770,6 @@ class X509
|
|||||||
return false;
|
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
|
* Returns the OID corresponding to a name
|
||||||
*
|
*
|
||||||
|
@ -53,6 +53,7 @@ namespace phpseclib\Math;
|
|||||||
use ParagonIE\ConstantTime\Base64;
|
use ParagonIE\ConstantTime\Base64;
|
||||||
use ParagonIE\ConstantTime\Hex;
|
use ParagonIE\ConstantTime\Hex;
|
||||||
use phpseclib\Crypt\Random;
|
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
|
* 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(
|
$components = array(
|
||||||
'modulus' => pack('Ca*a*', 2, self::_encodeASN1Length(strlen($components['modulus'])), $components['modulus']),
|
'modulus' => pack('Ca*a*', 2, ASN1::encodeLength(strlen($components['modulus'])), $components['modulus']),
|
||||||
'publicExponent' => pack('Ca*a*', 2, self::_encodeASN1Length(strlen($components['publicExponent'])), $components['publicExponent'])
|
'publicExponent' => pack('Ca*a*', 2, ASN1::encodeLength(strlen($components['publicExponent'])), $components['publicExponent'])
|
||||||
);
|
);
|
||||||
|
|
||||||
$RSAPublicKey = pack(
|
$RSAPublicKey = pack(
|
||||||
'Ca*a*a*',
|
'Ca*a*a*',
|
||||||
48,
|
48,
|
||||||
self::_encodeASN1Length(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
ASN1::encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
||||||
$components['modulus'],
|
$components['modulus'],
|
||||||
$components['publicExponent']
|
$components['publicExponent']
|
||||||
);
|
);
|
||||||
|
|
||||||
$rsaOID = "\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00"; // hex version of MA0GCSqGSIb3DQEBAQUA
|
$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(0) . $RSAPublicKey;
|
||||||
$RSAPublicKey = chr(3) . self::_encodeASN1Length(strlen($RSAPublicKey)) . $RSAPublicKey;
|
$RSAPublicKey = chr(3) . ASN1::encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
|
||||||
|
|
||||||
$encapsulated = pack(
|
$encapsulated = pack(
|
||||||
'Ca*a*',
|
'Ca*a*',
|
||||||
48,
|
48,
|
||||||
self::_encodeASN1Length(strlen($rsaOID . $RSAPublicKey)),
|
ASN1::encodeLength(strlen($rsaOID . $RSAPublicKey)),
|
||||||
$rsaOID . $RSAPublicKey
|
$rsaOID . $RSAPublicKey
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3009,10 +3010,35 @@ class BigInteger
|
|||||||
return $this->bitwise_leftRotate(-$shift);
|
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
|
* 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
|
* @param int $size
|
||||||
* @return \phpseclib\Math\BigInteger
|
* @return \phpseclib\Math\BigInteger
|
||||||
@ -3020,23 +3046,8 @@ class BigInteger
|
|||||||
*/
|
*/
|
||||||
static function random($size)
|
static function random($size)
|
||||||
{
|
{
|
||||||
if (class_exists('\phpseclib\Crypt\Random')) {
|
extract(self::minMaxBits($size));
|
||||||
$random = Random::string($size);
|
return self::randomRange($min, $max);
|
||||||
} 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -3058,7 +3069,7 @@ class BigInteger
|
|||||||
$compare = $max->compare($min);
|
$compare = $max->compare($min);
|
||||||
|
|
||||||
if (!$compare) {
|
if (!$compare) {
|
||||||
return $this->_normalize($min);
|
return $min;
|
||||||
} elseif ($compare < 0) {
|
} elseif ($compare < 0) {
|
||||||
// if $min is bigger then $max, swap $min and $max
|
// if $min is bigger then $max, swap $min and $max
|
||||||
$temp = $max;
|
$temp = $max;
|
||||||
@ -3072,6 +3083,7 @@ class BigInteger
|
|||||||
}
|
}
|
||||||
|
|
||||||
$max = $max->subtract($min->subtract($one));
|
$max = $max->subtract($min->subtract($one));
|
||||||
|
|
||||||
$size = strlen(ltrim($max->toBytes(), chr(0)));
|
$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
|
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_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);
|
list($max_multiple) = $random_max->divide($max);
|
||||||
$max_multiple = $max_multiple->multiply($max);
|
$max_multiple = $max_multiple->multiply($max);
|
||||||
@ -3099,7 +3111,7 @@ class BigInteger
|
|||||||
$random = $random->subtract($max_multiple);
|
$random = $random->subtract($max_multiple);
|
||||||
$random_max = $random_max->subtract($max_multiple);
|
$random_max = $random_max->subtract($max_multiple);
|
||||||
$random = $random->bitwise_leftShift(8);
|
$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);
|
$random_max = $random_max->bitwise_leftShift(8);
|
||||||
list($max_multiple) = $random_max->divide($max);
|
list($max_multiple) = $random_max->divide($max);
|
||||||
$max_multiple = $max_multiple->multiply($max);
|
$max_multiple = $max_multiple->multiply($max);
|
||||||
@ -3112,46 +3124,30 @@ class BigInteger
|
|||||||
/**
|
/**
|
||||||
* Generates a random prime number of a certain size
|
* 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 $size
|
||||||
* @param int $timeout
|
|
||||||
* @return \phpseclib\Math\BigInteger
|
* @return \phpseclib\Math\BigInteger
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
static function randomPrime($size, $timeout = false)
|
static function randomPrime($size)
|
||||||
{
|
{
|
||||||
$min = str_repeat(chr(0), $bytes);
|
extract(self::minMaxBits($size));
|
||||||
$max = str_repeat(chr(0xFF), $bytes);
|
return self::randomRangePrime($min, $max);
|
||||||
$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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a random prime number between a range
|
* Generate a random prime number between a range
|
||||||
*
|
*
|
||||||
* If there's not a prime within the given range, false will be returned.
|
* 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 $min
|
||||||
* @param \phpseclib\Math\BigInteger $max
|
* @param \phpseclib\Math\BigInteger $max
|
||||||
* @param int $timeout
|
|
||||||
* @return Math_BigInteger|false
|
* @return Math_BigInteger|false
|
||||||
* @access public
|
* @access public
|
||||||
* @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
|
* @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);
|
$compare = $max->compare($min);
|
||||||
|
|
||||||
@ -3170,9 +3166,7 @@ class BigInteger
|
|||||||
$two = new static(2);
|
$two = new static(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
$start = time();
|
$x = self::randomRange($min, $max);
|
||||||
|
|
||||||
$x = self::random($min, $max);
|
|
||||||
|
|
||||||
// gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
|
// gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
|
||||||
if (MATH_BIGINTEGER_MODE == self::MODE_GMP && extension_loaded('gmp')) {
|
if (MATH_BIGINTEGER_MODE == self::MODE_GMP && extension_loaded('gmp')) {
|
||||||
@ -3187,7 +3181,7 @@ class BigInteger
|
|||||||
$x = $x->subtract($one);
|
$x = $x->subtract($one);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::randomPrime($min, $x);
|
return self::randomRangePrime($min, $x);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($x->equals($two)) {
|
if ($x->equals($two)) {
|
||||||
@ -3207,10 +3201,6 @@ class BigInteger
|
|||||||
$initial_x = clone $x;
|
$initial_x = clone $x;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if ($timeout !== false && time() - $start > $timeout) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($x->isPrime()) {
|
if ($x->isPrime()) {
|
||||||
return $x;
|
return $x;
|
||||||
}
|
}
|
||||||
@ -3391,7 +3381,7 @@ class BigInteger
|
|||||||
}
|
}
|
||||||
|
|
||||||
for ($i = 0; $i < $t; ++$i) {
|
for ($i = 0; $i < $t; ++$i) {
|
||||||
$a = self::random($two, $n_2);
|
$a = self::randomRange($two, $n_2);
|
||||||
$y = $a->modPow($r, $n);
|
$y = $a->modPow($r, $n);
|
||||||
|
|
||||||
if (!$y->equals($one) && !$y->equals($n_1)) {
|
if (!$y->equals($one) && !$y->equals($n_1)) {
|
||||||
@ -3661,26 +3651,6 @@ class BigInteger
|
|||||||
return $temp['int'];
|
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
|
* Single digit division
|
||||||
*
|
*
|
||||||
@ -3723,7 +3693,6 @@ class BigInteger
|
|||||||
* @param \phpseclib\Math\BigInteger $n
|
* @param \phpseclib\Math\BigInteger $n
|
||||||
* @access public
|
* @access public
|
||||||
* @return \phpseclib\Math\BigInteger
|
* @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}.
|
* @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)
|
function root($n = null)
|
||||||
@ -3876,4 +3845,26 @@ class BigInteger
|
|||||||
}
|
}
|
||||||
return $max;
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1514,7 +1514,7 @@ class SSH2
|
|||||||
|
|
||||||
-- http://tools.ietf.org/html/rfc4419#section-6.2 */
|
-- http://tools.ietf.org/html/rfc4419#section-6.2 */
|
||||||
$one = new BigInteger(1);
|
$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 = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength
|
||||||
$max = $max->subtract($one);
|
$max = $max->subtract($one);
|
||||||
|
|
||||||
@ -2931,9 +2931,6 @@ class SSH2
|
|||||||
if ($this->decrypt !== false) {
|
if ($this->decrypt !== false) {
|
||||||
$raw = $this->decrypt->decrypt($raw);
|
$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)));
|
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)
|
public function testGetLengthKnown($algorithm, $length)
|
||||||
{
|
{
|
||||||
$hash = new Hash($algorithm);
|
$hash = new Hash($algorithm);
|
||||||
$this->assertSame($hash->getLength(), $length);
|
$this->assertSame($hash->getLengthInBytes(), $length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function lengths()
|
public function lengths()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
* @author Jim Wigginton <terrafrost@php.net>
|
||||||
* @copyright 2015 Jim Wigginton
|
* @copyright 2015 Jim Wigginton
|
||||||
@ -6,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use phpseclib\Crypt\RSA;
|
use phpseclib\Crypt\RSA;
|
||||||
|
use phpseclib\Crypt\RSA\PKCS1;
|
||||||
|
|
||||||
class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
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->assertInstanceOf('\phpseclib\Crypt\RSA', $publickey);
|
||||||
$this->assertNotEmpty("$privatekey");
|
$this->assertNotEmpty("$privatekey");
|
||||||
$this->assertNotEmpty("$publickey");
|
$this->assertNotEmpty("$publickey");
|
||||||
|
$this->assertSame($privatekey->getLength(), 768);
|
||||||
|
$this->assertSame($publickey->getLength(), 768);
|
||||||
|
|
||||||
return array($publickey, $privatekey);
|
return array($publickey, $privatekey);
|
||||||
}
|
}
|
||||||
@ -31,4 +35,31 @@ class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
|||||||
$plaintext = $privatekey->decrypt($ciphertext);
|
$plaintext = $privatekey->decrypt($ciphertext);
|
||||||
$this->assertSame($plaintext, 'zzz');
|
$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;
|
||||||
use phpseclib\Crypt\RSA\PKCS1;
|
use phpseclib\Crypt\RSA\PKCS1;
|
||||||
|
use phpseclib\Crypt\RSA\PKCS8;
|
||||||
use phpseclib\Crypt\RSA\PuTTY;
|
use phpseclib\Crypt\RSA\PuTTY;
|
||||||
use phpseclib\Math\BigInteger;
|
use phpseclib\Math\BigInteger;
|
||||||
|
|
||||||
@ -376,6 +377,8 @@ Private-MAC: 03e2cb74e1d67652fbad063d2ed0478f31bdf256
|
|||||||
$key = preg_replace('#(?<!\r)\n#', "\r\n", $key);
|
$key = preg_replace('#(?<!\r)\n#', "\r\n", $key);
|
||||||
$this->assertTrue($rsa->load($key));
|
$this->assertTrue($rsa->load($key));
|
||||||
|
|
||||||
|
$rsa->setPrivateKeyFormat('PKCS1');
|
||||||
|
|
||||||
PKCS1::setEncryptionAlgorithm('AES-256-CBC');
|
PKCS1::setEncryptionAlgorithm('AES-256-CBC');
|
||||||
$rsa->setPassword('demo');
|
$rsa->setPassword('demo');
|
||||||
|
|
||||||
@ -554,4 +557,368 @@ AAIBAAIBAAIBAAIBAA==
|
|||||||
|
|
||||||
$rsa->sign('zzzz', RSA::PADDING_PKCS1);
|
$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