Updated phpseclib, continuing to write prime module

This commit is contained in:
danogentili 2016-08-03 21:49:11 +02:00
parent cc20b7407f
commit 7b2b9c3315
87 changed files with 48195 additions and 3246 deletions

37721
o Normal file

File diff suppressed because it is too large Load Diff

View File

@ -92,20 +92,20 @@ class PrimeModule
list($g, $r, $q) = [$one, $one, $one];
while ($g->equals($one)) {
$x = $y;
$range = $r;
while (!$range->equals($zero)) {
$y = $y->powMod($two, $n)->add($c)->powMod($one, $n);
$range = $range->subtract($one);
}
$params = ["y" => $y, "two" => $two, "c" => $c, "one" => $one, "n" => $n];
$r->foreach(function ($i, $params) {
$params["y"] = $params["y"]->powMod($params["two"], $params["n"])->add($params["c"])->powMod($params["one"], $params["n"]);
}, $params);
each($params, EXTR_OVERWRITE);
$k = $zero;
while ($k->compare($r) == -1 && $g->equals($one)) {
$ys = $y;
$range = $big->min($m, $r->subtract($k));
while (!$range->equals($zero)) {
$y = $y->powMod($two, $n)->add($c)->powMod($one, $n);
$q = $q->multiply($x->subtract($y)->abs())->powMod($one, $n);
$range = $range->subtract($one);
}
$params = ["x" => $x, "y" => $y, "two" => $two, "c" => $c, "one" => $one, "n" => $n, "q" => $q];
$m->min($r->subtract($k))->foreach(function ($i, $params) {
$params["y"] = $params["y"]->powMod($params["two"], $params["n"])->add($params["c"])->powMod($params["one"], $params["n"]);
$params["q"] = $params["q"]->multiply($params["x"]->subtract($params["y"])->abs())->powMod($params["one"], $params["n"]);
}, $params);
each($params, EXTR_OVERWRITE);
$g = $q->gcd($n);
$k = $k->add($m);
}

View File

@ -62,7 +62,7 @@ def pollard_brent(n):
x = y
for i in range(r):
y = (pow(y, 2, n) + c) % n
print(y)
print(i)
k = 0
while k < r and g==1:
@ -71,7 +71,7 @@ def pollard_brent(n):
for i in range(min(m, r-k)):
y = (pow(y, 2, n) + c) % n
q = q * abs(x-y) % n
exit()
g = gcd(q, n)
k += m
r *= 2

160
vendor/phpseclib/phpseclib/CHANGELOG.md vendored Normal file
View File

@ -0,0 +1,160 @@
# Changelog
## 2.0.2 - 2016-06-04
- All Ciphers: fix issue with CBC mode / OpenSSL / continuous buffers / decryption (#938)
- Random: fix issues with serialize() (#932)
- RC2: fix issue with decrypting
- RC4: fix issue with key not being truncated correctly
- SFTP: nlist() on a non-existant directory resulted in error
- SFTP: add is_writable, is_writeable, is_readable
- X509: add IPv6 support for subjectaltname extension (#936)
## 2.0.1 - 2016-01-18
- RSA: fix regression in PSS mode ([#769](https://github.com/phpseclib/phpseclib/pull/769))
- RSA: fix issue loading PKCS8 specific keys ([#861](https://github.com/phpseclib/phpseclib/pull/861))
- X509: add getOID() method ([#789](https://github.com/phpseclib/phpseclib/pull/789))
- X509: improve base64-encoded detection rules ([#855](https://github.com/phpseclib/phpseclib/pull/855))
- SFTP: fix quirky behavior with put() ([#830](https://github.com/phpseclib/phpseclib/pull/830))
- SFTP: fix E_NOTICE ([#883](https://github.com/phpseclib/phpseclib/pull/883))
- SFTP/Stream: fix issue with filenames with hashes ([#901](https://github.com/phpseclib/phpseclib/pull/901))
- SSH2: add isAuthenticated() method ([#897](https://github.com/phpseclib/phpseclib/pull/897))
- SSH/Agent: fix possible PHP warning ([#923](https://github.com/phpseclib/phpseclib/issues/923))
- BigInteger: add __debugInfo() magic method ([#881](https://github.com/phpseclib/phpseclib/pull/881))
- BigInteger: fix issue with doing bitwise not on 0
- add getBlockLength() method to symmetric ciphers
## 2.0.0 - 2015-08-04
- Classes were renamed and namespaced ([#243](https://github.com/phpseclib/phpseclib/issues/243))
- The use of an autoloader is now required (e.g. Composer)
## 1.0.2 - 2016-05-07
- All Ciphers: fix issue with CBC mode / OpenSSL / continuous buffers / decryption (#938)
- Random: fix issues with serialize() (#932)
- RC2: fix issue with decrypting
- RC4: fix issue with key not being truncated correctly
- SFTP: nlist() on a non-existant directory resulted in error
- SFTP: add is_writable, is_writeable, is_readable
- RSA: fix PHP4 compatability issue
## 1.0.1 - 2016-01-18
- RSA: fix regression in PSS mode ([#769](https://github.com/phpseclib/phpseclib/pull/769))
- RSA: fix issue loading PKCS8 specific keys ([#861](https://github.com/phpseclib/phpseclib/pull/861))
- X509: add getOID() method ([#789](https://github.com/phpseclib/phpseclib/pull/789))
- X509: improve base64-encoded detection rules ([#855](https://github.com/phpseclib/phpseclib/pull/855))
- SFTP: fix quirky behavior with put() ([#830](https://github.com/phpseclib/phpseclib/pull/830))
- SFTP: fix E_NOTICE ([#883](https://github.com/phpseclib/phpseclib/pull/883))
- SFTP/Stream: fix issue with filenames with hashes ([#901](https://github.com/phpseclib/phpseclib/pull/901))
- SSH2: add isAuthenticated() method ([#897](https://github.com/phpseclib/phpseclib/pull/897))
- SSH/Agent: fix possible PHP warning ([#923](https://github.com/phpseclib/phpseclib/issues/923))
- BigInteger: add __debugInfo() magic method ([#881](https://github.com/phpseclib/phpseclib/pull/881))
- BigInteger: fix issue with doing bitwise not on 0
- add getBlockLength() method to symmetric ciphers
## 1.0.0 - 2015-08-02
- OpenSSL support for symmetric ciphers ([#507](https://github.com/phpseclib/phpseclib/pull/507))
- rewritten vt100 terminal emulator (File_ANSI) ([#689](https://github.com/phpseclib/phpseclib/pull/689))
- agent-forwarding support (System_SSH_Agent) ([#592](https://github.com/phpseclib/phpseclib/pull/592))
- Net_SSH2 improvements
- diffie-hellman-group-exchange-sha1/sha256 support ([#714](https://github.com/phpseclib/phpseclib/pull/714))
- window size handling updates ([#717](https://github.com/phpseclib/phpseclib/pull/717))
- Net_SFTP improvements
- add callback support to put() ([#655](https://github.com/phpseclib/phpseclib/pull/655))
- stat cache fixes ([#743](https://github.com/phpseclib/phpseclib/issues/743), [#730](https://github.com/phpseclib/phpseclib/issues/730), [#709](https://github.com/phpseclib/phpseclib/issues/709), [#726](https://github.com/phpseclib/phpseclib/issues/726))
- add "none" encryption mode to Crypt_RSA ([#692](https://github.com/phpseclib/phpseclib/pull/692))
- misc ASN.1 / X.509 parsing fixes ([#721](https://github.com/phpseclib/phpseclib/pull/721), [#627](https://github.com/phpseclib/phpseclib/pull/627))
- use a random serial number for new X509 certs ([#740](https://github.com/phpseclib/phpseclib/pull/740))
- add getPublicKeyFingerprint() to Crypt_RSA ([#677](https://github.com/phpseclib/phpseclib/pull/677))
## 0.3.10 - 2015-02-04
- simplify SSH2 window size handling ([#538](https://github.com/phpseclib/phpseclib/pull/538))
- slightly relax the conditions under which OpenSSL is used ([#598](https://github.com/phpseclib/phpseclib/pull/598))
- fix issue with empty constructed context-specific tags in ASN1 ([#606](https://github.com/phpseclib/phpseclib/pull/606))
## 0.3.9 - 2014-11-09
- PHP 5.6 improvements ([#482](https://github.com/phpseclib/phpseclib/pull/482), [#491](https://github.com/phpseclib/phpseclib/issues/491))
## 0.3.8 - 2014-09-12
- improve support for indef lengths in File_ASN1
- add hmac-sha2-256 support to Net_SSH2
- make it so negotiated algorithms can be seen before Net_SSH2 login
- add sha256-96 and sha512-96 to Crypt_Hash
- window size handling adjustments in Net_SSH2
## 0.3.7 - 2014-07-05
- auto-detect public vs private keys
- add file_exists, is_dir, is_file, readlink and symlink to Net_SFTP
- add support for recursive nlist and rawlist
- make it so nlist and rawlist can return pre-sorted output
- make it so callback functions can make exec() return early
- add signSPKAC and saveSPKAC methods to File_X509
- add support for PKCS8 keys in Crypt_RSA
- add pbkdf1 support to setPassword() in Crypt_Base
- add getWindowColumns, getWindowRows, setWindowColumns, setWindowRows to Net_SSH2
- add support for filenames with spaces in them to Net_SCP
## 0.3.6 - 2014-02-23
- add preliminary support for custom SSH subsystems
- add ssh-agent support
## 0.3.5 - 2013-07-11
- numerous SFTP changes:
- chown
- chgrp
- truncate
- improved file type detection
- put() can write to te middle of a file
- mkdir accepts the same paramters that PHP's mkdir does
- the ability to upload/download 2GB files
- across-the-board speedups for the various encryption algorithms
- multi-factor authentication support for Net_SSH2
- a $callback parameter for Net_SSH2::exec
- new classes:
- Net_SFTP_StreamWrapper
- Net_SCP
- Crypt_Twofish
- Crypt_Blowfish
## 0.3.1 - 2012-11-20
- add Net_SSH2::enableQuietMode() for suppressing stderr
- add Crypt_RSA::__toString() and Crypt_RSA::getSize()
- fix problems with File_X509::validateDate(), File_X509::sign() and Crypt_RSA::verify()
- use OpenSSL to speed up modular exponention in Math_BigInteger
- improved timeout functionality in Net_SSH2
- add support for SFTPv2
- add support for CRLs in File_X509
- SSH-2.0-SSH doesn't implement hmac-*-96 correctly
## 0.3.0 - 2012-07-08
- add support for reuming Net_SFTP::put()
- add support for recursive deletes and recursive chmods to Net_SFTP
- add setTimeout() to Net_SSH2
- add support for PBKDF2 to the various Crypt_* classes via setPassword()
- add File_X509 and File_ASN1
- add the ability to decode various formats in Crypt_RSA
- make Net_SSH2::getServerPublicHostKey() return a printer-friendly version of the public key
## 0.2.2 - 2011-05-09
- CFB and OFB modes were added to all block ciphers
- support for interactive mode was added to Net_SSH2
- Net_SSH2 now has limited keyboard_interactive authentication support
- support was added for PuTTY formatted RSA private keys and XML formatted RSA private keys
- Crypt_RSA::loadKey() will now try all key types automatically
= add support for AES-128-CBC and DES-EDE3-CFB encrypted RSA private keys
- add Net_SFTP::stat(), Net_SFTP::lstat() and Net_SFTP::rawlist()
- logging was added to Net_SSH1
- the license was changed to the less restrictive MIT license

View File

@ -1,6 +1,6 @@
# phpseclib - PHP Secure Communications Library
[![Build Status](https://travis-ci.org/phpseclib/phpseclib.svg?branch=2.0)](https://travis-ci.org/phpseclib/phpseclib)
[![Build Status](https://travis-ci.org/phpseclib/phpseclib.svg?branch=master)](https://travis-ci.org/phpseclib/phpseclib)
MIT-licensed pure-PHP implementations of an arbitrary-precision integer
arithmetic library, fully PKCS#1 (v2.1) compliant RSA, DES, 3DES, RC4, Rijndael,
@ -8,7 +8,7 @@ AES, Blowfish, Twofish, SSH-1, SSH-2, SFTP, and X.509
* [Download (1.0.2)](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.2.zip/download)
* [Browse Git](https://github.com/phpseclib/phpseclib)
* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/2.0/latest/)
* [Code Coverage Report](http://phpseclib.bantux.org/code_coverage/master/latest/)
<img src="http://phpseclib.sourceforge.net/pear-icon.png" alt="PEAR Channel" width="16" height="16">
PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.htm)
@ -16,7 +16,7 @@ PEAR Channel: [phpseclib.sourceforge.net](http://phpseclib.sourceforge.net/pear.
## Documentation
* [Documentation / Manual](http://phpseclib.sourceforge.net/)
* [API Documentation](http://phpseclib.bantux.org/api/2.0/) (generated by Sami)
* [API Documentation](http://phpseclib.bantux.org/api/master/) (generated by Sami)
## Support

View File

@ -51,6 +51,8 @@
}
],
"require": {
"paragonie/constant_time_encoding": "^1|^2",
"paragonie/random_compat": "^1.4|^2.0",
"php": ">=5.3.3"
},
"require-dev": {

View File

@ -4,9 +4,120 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "8599992bf6058a9da82372eb8bcae2c2",
"content-hash": "fde47c84178c55c06de858a2128e3d07",
"packages": [],
"hash": "422b05a6ce122760976256ff21e9381b",
"content-hash": "3bd75e9c1741d7c0c0930855e5b96abb",
"packages": [
{
"name": "paragonie/constant_time_encoding",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
"reference": "d96e63b79a7135a65659ba5b1cb02826172bfedd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d96e63b79a7135a65659ba5b1cb02826172bfedd",
"reference": "d96e63b79a7135a65659ba5b1cb02826172bfedd",
"shasum": ""
},
"require": {
"php": "^5.3|^7"
},
"require-dev": {
"paragonie/random_compat": "^1.4|^2.0",
"phpunit/phpunit": "4.*|5.*"
},
"type": "library",
"autoload": {
"psr-4": {
"ParagonIE\\ConstantTime\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com",
"role": "Maintainer"
},
{
"name": "Steve 'Sc00bz' Thomas",
"email": "steve@tobtu.com",
"homepage": "https://www.tobtu.com",
"role": "Original Developer"
}
],
"description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
"keywords": [
"base16",
"base32",
"base32_decode",
"base32_encode",
"base64",
"base64_decode",
"base64_encode",
"bin2hex",
"encoding",
"hex",
"hex2bin",
"rfc4648"
],
"time": "2016-06-13 01:00:24"
},
{
"name": "paragonie/random_compat",
"version": "v2.0.2",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
},
"type": "library",
"autoload": {
"files": [
"lib/random.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [
"csprng",
"pseudorandom",
"random"
],
"time": "2016-04-03 06:00:07"
}
],
"packages-dev": [
{
"name": "doctrine/instantiator",
@ -250,38 +361,87 @@
"time": "2016-03-10 21:39:23"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "2.0.4",
"name": "phpdocumentor/reflection-common",
"version": "1.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8"
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8",
"reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
"php": ">=5.5"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"suggest": {
"dflydev/markdown": "~1.0",
"erusev/parsedown": "~1.0"
"phpunit/phpunit": "^4.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"phpDocumentor": [
"psr-4": {
"phpDocumentor\\Reflection\\": [
"src"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jaap van Otterdijk",
"email": "opensource@ijaap.nl"
}
],
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
"homepage": "http://www.phpdoc.org",
"keywords": [
"FQSEN",
"phpDocumentor",
"phpdoc",
"reflection",
"static analysis"
],
"time": "2015-12-27 11:43:31"
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "9270140b940ff02e58ec577c237274e92cd40cdd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd",
"reference": "9270140b940ff02e58ec577c237274e92cd40cdd",
"shasum": ""
},
"require": {
"php": ">=5.5",
"phpdocumentor/reflection-common": "^1.0@dev",
"phpdocumentor/type-resolver": "^0.2.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^4.4"
},
"type": "library",
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
"src/"
]
}
@ -293,39 +453,87 @@
"authors": [
{
"name": "Mike van Riel",
"email": "mike.vanriel@naenius.com"
"email": "me@mikevanriel.com"
}
],
"time": "2015-02-03 12:10:50"
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2016-06-10 09:48:41"
},
{
"name": "phpspec/prophecy",
"version": "v1.6.0",
"name": "phpdocumentor/type-resolver",
"version": "0.2",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
"reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
"reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
"shasum": ""
},
"require": {
"php": ">=5.5",
"phpdocumentor/reflection-common": "^1.0"
},
"require-dev": {
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^5.2||^4.8.24"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "me@mikevanriel.com"
}
],
"time": "2016-06-10 07:14:17"
},
{
"name": "phpspec/prophecy",
"version": "v1.6.1",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "58a8137754bc24b25740d4281399a4a3596058e0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
"reference": "58a8137754bc24b25740d4281399a4a3596058e0",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "~2.0",
"sebastian/comparator": "~1.1",
"sebastian/recursion-context": "~1.0"
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
"sebastian/comparator": "^1.1",
"sebastian/recursion-context": "^1.0"
},
"require-dev": {
"phpspec/phpspec": "~2.0"
"phpspec/phpspec": "^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.5.x-dev"
"dev-master": "1.6.x-dev"
}
},
"autoload": {
@ -358,7 +566,7 @@
"spy",
"stub"
],
"time": "2016-02-15 07:46:21"
"time": "2016-06-07 08:13:47"
},
{
"name": "phpunit/php-code-coverage",
@ -512,21 +720,24 @@
},
{
"name": "phpunit/php-timer",
"version": "1.0.7",
"version": "1.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
"reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b"
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
"reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b",
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4|~5"
},
"type": "library",
"autoload": {
"classmap": [
@ -549,7 +760,7 @@
"keywords": [
"timer"
],
"time": "2015-06-21 08:01:12"
"time": "2016-05-12 18:03:57"
},
{
"name": "phpunit/php-token-stream",
@ -602,16 +813,16 @@
},
{
"name": "phpunit/phpunit",
"version": "4.8.24",
"version": "4.8.26",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "a1066c562c52900a142a0e2bbf0582994671385e"
"reference": "fc1d8cd5b5de11625979125c5639347896ac2c74"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e",
"reference": "a1066c562c52900a142a0e2bbf0582994671385e",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74",
"reference": "fc1d8cd5b5de11625979125c5639347896ac2c74",
"shasum": ""
},
"require": {
@ -625,7 +836,7 @@
"phpunit/php-code-coverage": "~2.1",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": ">=1.0.6",
"phpunit/php-timer": "^1.0.6",
"phpunit/phpunit-mock-objects": "~2.3",
"sebastian/comparator": "~1.1",
"sebastian/diff": "~1.2",
@ -670,7 +881,7 @@
"testing",
"xunit"
],
"time": "2016-03-14 06:16:08"
"time": "2016-05-17 03:09:28"
},
{
"name": "phpunit/phpunit-mock-objects",
@ -949,16 +1160,16 @@
},
{
"name": "sebastian/environment",
"version": "1.3.5",
"version": "1.3.7",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf"
"reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
"reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716",
"reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716",
"shasum": ""
},
"require": {
@ -995,20 +1206,20 @@
"environment",
"hhvm"
],
"time": "2016-02-26 18:40:46"
"time": "2016-05-17 03:18:57"
},
{
"name": "sebastian/exporter",
"version": "1.2.1",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "7ae5513327cb536431847bcc0c10edba2701064e"
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
"reference": "7ae5513327cb536431847bcc0c10edba2701064e",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
"shasum": ""
},
"require": {
@ -1016,12 +1227,13 @@
"sebastian/recursion-context": "~1.0"
},
"require-dev": {
"ext-mbstring": "*",
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
"dev-master": "1.3.x-dev"
}
},
"autoload": {
@ -1061,7 +1273,7 @@
"export",
"exporter"
],
"time": "2015-06-21 07:55:53"
"time": "2016-06-17 09:04:28"
},
{
"name": "sebastian/global-state",
@ -1204,16 +1416,16 @@
},
{
"name": "squizlabs/php_codesniffer",
"version": "2.6.0",
"version": "2.6.1",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "1bcdf03b068a530ac1962ce671dead356eeba43b"
"reference": "fb72ed32f8418db5e7770be1653e62e0d6f5dd3d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1bcdf03b068a530ac1962ce671dead356eeba43b",
"reference": "1bcdf03b068a530ac1962ce671dead356eeba43b",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/fb72ed32f8418db5e7770be1653e62e0d6f5dd3d",
"reference": "fb72ed32f8418db5e7770be1653e62e0d6f5dd3d",
"shasum": ""
},
"require": {
@ -1278,20 +1490,20 @@
"phpcs",
"standards"
],
"time": "2016-04-03 22:58:34"
"time": "2016-05-30 22:24:32"
},
{
"name": "symfony/console",
"version": "v2.8.4",
"version": "v2.8.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154"
"reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/9a5aef5fc0d4eff86853d44202b02be8d5a20154",
"reference": "9a5aef5fc0d4eff86853d44202b02be8d5a20154",
"url": "https://api.github.com/repos/symfony/console/zipball/5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
"reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
"shasum": ""
},
"require": {
@ -1338,20 +1550,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2016-03-17 09:19:04"
"time": "2016-06-06 15:06:25"
},
{
"name": "symfony/filesystem",
"version": "v2.8.4",
"version": "v2.8.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "f08ffdf229252cd2745558cb2112df43903bcae4"
"reference": "dee379131dceed90a429e951546b33edfe7dccbb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/f08ffdf229252cd2745558cb2112df43903bcae4",
"reference": "f08ffdf229252cd2745558cb2112df43903bcae4",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/dee379131dceed90a429e951546b33edfe7dccbb",
"reference": "dee379131dceed90a429e951546b33edfe7dccbb",
"shasum": ""
},
"require": {
@ -1387,20 +1599,20 @@
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2016-03-27 10:20:16"
"time": "2016-04-12 18:01:21"
},
{
"name": "symfony/finder",
"version": "v2.8.4",
"version": "v2.8.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1"
"reference": "3ec095fab1800222732ca522a95dce8fa124007b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/ca24cf2cd4e3826f571e0067e535758e73807aa1",
"reference": "ca24cf2cd4e3826f571e0067e535758e73807aa1",
"url": "https://api.github.com/repos/symfony/finder/zipball/3ec095fab1800222732ca522a95dce8fa124007b",
"reference": "3ec095fab1800222732ca522a95dce8fa124007b",
"shasum": ""
},
"require": {
@ -1436,20 +1648,20 @@
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2016-03-10 10:53:53"
"time": "2016-06-06 11:11:27"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.1.1",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "1289d16209491b584839022f29257ad859b8532d"
"reference": "dff51f72b0706335131b00a7f49606168c582594"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
"reference": "1289d16209491b584839022f29257ad859b8532d",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
"reference": "dff51f72b0706335131b00a7f49606168c582594",
"shasum": ""
},
"require": {
@ -1461,7 +1673,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
"dev-master": "1.2-dev"
}
},
"autoload": {
@ -1495,20 +1707,20 @@
"portable",
"shim"
],
"time": "2016-01-20 09:13:37"
"time": "2016-05-18 14:26:46"
},
{
"name": "symfony/process",
"version": "v2.8.4",
"version": "v2.8.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "fb467471952ef5cf8497c029980e556b47545333"
"reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/fb467471952ef5cf8497c029980e556b47545333",
"reference": "fb467471952ef5cf8497c029980e556b47545333",
"url": "https://api.github.com/repos/symfony/process/zipball/115347d00c342198cdc52a7bd8bc15b5ab43500c",
"reference": "115347d00c342198cdc52a7bd8bc15b5ab43500c",
"shasum": ""
},
"require": {
@ -1544,20 +1756,20 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2016-03-23 13:11:46"
"time": "2016-06-06 11:11:27"
},
{
"name": "symfony/yaml",
"version": "v2.8.4",
"version": "v2.8.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "584e52cb8f788a887553ba82db6caacb1d6260bb"
"reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/584e52cb8f788a887553ba82db6caacb1d6260bb",
"reference": "584e52cb8f788a887553ba82db6caacb1d6260bb",
"url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34",
"reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34",
"shasum": ""
},
"require": {
@ -1593,20 +1805,20 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2016-03-04 07:54:35"
"time": "2016-06-06 11:11:27"
},
{
"name": "twig/twig",
"version": "v1.24.0",
"version": "v1.24.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8"
"reference": "3566d311a92aae4deec6e48682dc5a4528c4a512"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
"reference": "3e5aa30ebfbafd5951fb1b01e338e1800ce7e0e8",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512",
"reference": "3566d311a92aae4deec6e48682dc5a4528c4a512",
"shasum": ""
},
"require": {
@ -1654,7 +1866,56 @@
"keywords": [
"templating"
],
"time": "2016-01-25 21:22:18"
"time": "2016-05-30 09:11:59"
},
{
"name": "webmozart/assert",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde",
"reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "^4.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"Webmozart\\Assert\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Bernhard Schussek",
"email": "bschussek@gmail.com"
}
],
"description": "Assertions to validate method input/output with nice error messages.",
"keywords": [
"assert",
"check",
"validate"
],
"time": "2015-08-24 13:29:44"
}
],
"aliases": [],

View File

@ -66,30 +66,32 @@ class AES extends Rijndael
* @see \phpseclib\Crypt\Rijndael::setBlockLength()
* @access public
* @param int $length
* @throws \BadMethodCallException anytime it's called
*/
function setBlockLength($length)
{
return;
throw new \BadMethodCallException('The block length cannot be set for AES.');
}
/**
* Sets the key length
*
* Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
* Valid key lengths are 128, 192, and 256. Set the link to bool(false) to disable a fixed key length
*
* @see \phpseclib\Crypt\Rijndael:setKeyLength()
* @access public
* @param int $length
* @throws \LengthException if the key length isn't supported
*/
function setKeyLength($length)
{
switch ($length) {
case 160:
$length = 192;
case 128:
case 192:
case 256:
break;
case 224:
$length = 256;
default:
throw new \LengthException('Key of size ' . $length . ' not supported by this algorithm. Only keys of sizes 128, 192 or 256 supported');
}
parent::setKeyLength($length);
}
@ -103,24 +105,19 @@ class AES extends Rijndael
* @see setKeyLength()
* @access public
* @param string $key
* @throws \LengthException if the key length isn't supported
*/
function setKey($key)
{
parent::setKey($key);
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_length = 16;
break;
case $length <= 24:
$this->key_length = 24;
break;
default:
$this->key_length = 32;
}
$this->_setEngine();
switch (strlen($key)) {
case 16:
case 24:
case 32:
break;
default:
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
}
parent::setKey($key);
}
}

View File

@ -139,7 +139,7 @@ abstract class Base
* @var string
* @access private
*/
var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
var $key = false;
/**
* The Initialization Vector
@ -148,7 +148,7 @@ abstract class Base
* @var string
* @access private
*/
var $iv;
var $iv = false;
/**
* A "sliding" Initialization Vector
@ -429,15 +429,6 @@ abstract class Base
*/
var $openssl_options;
/**
* Has the key length explicitly been set or should it be derived from the key, itself?
*
* @see self::setKeyLength()
* @var bool
* @access private
*/
var $explicit_key_length = false;
/**
* Don't truncate / null pad key
*
@ -448,9 +439,16 @@ abstract class Base
var $skip_key_adjustment = false;
/**
* Default Constructor.
* Has the key length explicitly been set or should it be derived from the key, itself?
*
* Determines whether or not the mcrypt extension should be used.
* @see self::setKeyLength()
* @var bool
* @access private
*/
var $explicit_key_length = false;
/**
* Default Constructor.
*
* $mode could be:
*
@ -464,32 +462,29 @@ abstract class Base
*
* - self::MODE_OFB
*
* If not explicitly set, self::MODE_CBC will be used.
*
* @param int $mode
* @access public
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
*/
function __construct($mode = self::MODE_CBC)
function __construct($mode)
{
// $mode dependent settings
switch ($mode) {
case self::MODE_ECB:
case self::MODE_CBC:
$this->paddable = true;
$this->mode = self::MODE_ECB;
break;
case self::MODE_CTR:
case self::MODE_CFB:
case self::MODE_OFB:
case self::MODE_STREAM:
$this->mode = $mode;
$this->paddable = false;
break;
case self::MODE_CBC:
default:
$this->paddable = true;
$this->mode = self::MODE_CBC;
throw new \InvalidArgumentException('No valid mode has been specified');
}
$this->_setEngine();
$this->mode = $mode;
// Determining whether inline crypting can be used by the cipher
if ($this->use_inline_crypt !== false && function_exists('create_function')) {
@ -498,19 +493,28 @@ abstract class Base
}
/**
* Sets the initialization vector. (optional)
* Sets the initialization vector.
*
* SetIV is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used. If not explicitly set, it'll be assumed
* to be all zero's.
* setIV() is not required when self::MODE_ECB (or ie for AES: \phpseclib\Crypt\AES::MODE_ECB) is being used.
*
* @access public
* @param string $iv
* @throws \LengthException if the IV length isn't equal to the block size
* @throws \InvalidArgumentException if an IV is provided when one shouldn't be
* @internal Can be overwritten by a sub class, but does not have to be
*/
function setIV($iv)
{
if ($this->mode == self::MODE_ECB) {
return;
throw new \InvalidArgumentException('This mode does not require an IV.');
}
if ($this->mode == self::MODE_STREAM && $this->usesIV()) {
throw new \InvalidArgumentException('This algorithm does not use an IV.');
}
if (strlen($iv) != $this->block_size) {
throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size . ' is required');
}
$this->iv = $iv;
@ -518,18 +522,14 @@ abstract class Base
}
/**
* Sets the key length.
*
* Keys with explicitly set lengths need to be treated accordingly
* Returns whether or not the algorithm uses an IV
*
* @access public
* @param int $length
* @return bool
*/
function setKeyLength($length)
function usesIV()
{
$this->explicit_key_length = true;
$this->changed = true;
$this->_setEngine();
return true;
}
/**
@ -554,6 +554,24 @@ abstract class Base
return $this->block_size << 3;
}
/**
* Sets the key length.
*
* Keys with explicitly set lengths need to be treated accordingly
*
* @access public
* @param int $length
*/
function setKeyLength($length)
{
$this->explicit_key_length = $length >> 3;
if (is_string($this->key) && strlen($this->key) != $this->explicit_key_length) {
$this->key = false;
throw new \LengthException('Key has already been set and is not ' .$this->explicit_key_length . ' bytes long');
}
}
/**
* Sets the key.
*
@ -570,12 +588,12 @@ abstract class Base
*/
function setKey($key)
{
if (!$this->explicit_key_length) {
$this->setKeyLength(strlen($key) << 3);
$this->explicit_key_length = false;
if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
}
$this->key = $key;
$this->key_length = strlen($key);
$this->changed = true;
$this->_setEngine();
}
@ -592,6 +610,7 @@ abstract class Base
* @see Crypt/Hash.php
* @param string $password
* @param string $method
* @throws \LengthException if pbkdf1 is being used and the derived key length exceeds the hash length
* @return bool
* @access public
* @internal Could, but not must, extend by the child Crypt_* class
@ -618,7 +637,8 @@ abstract class Base
if (isset($func_args[5])) {
$dkLen = $func_args[5];
} else {
$dkLen = $method == 'pbkdf1' ? 2 * $this->key_length : $this->key_length;
$key_length = $this->explicit_key_length !== false ? $this->explicit_key_length : $this->key_length;
$dkLen = $method == 'pbkdf1' ? 2 * $key_length : $key_length;
}
switch (true) {
@ -626,8 +646,7 @@ abstract class Base
$hashObj = new Hash();
$hashObj->setHash($hash);
if ($dkLen > $hashObj->getLength()) {
user_error('Derived key too long');
return false;
throw new \LengthException('Derived key length cannot be longer than the hash length');
}
$t = $password . $salt;
for ($i = 0; $i < $count; ++$i) {
@ -774,7 +793,7 @@ abstract class Base
$this->changed = false;
}
if ($this->enchanged) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
mcrypt_generic_init($this->enmcrypt, $this->key, $this->_getIV($this->encryptIV));
$this->enchanged = false;
}
@ -837,7 +856,7 @@ abstract class Base
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
mcrypt_generic_init($this->enmcrypt, $this->key, $this->_getIV($this->encryptIV));
}
return $ciphertext;
@ -986,14 +1005,13 @@ abstract class Base
* @access public
* @param string $ciphertext
* @return string $plaintext
* @throws \LengthException if we're inside a block cipher and the ciphertext length is not a multiple of the block size
* @internal Could, but not must, extend by the child Crypt_* class
*/
function decrypt($ciphertext)
{
if ($this->paddable) {
// we pad with chr(0) since that's what mcrypt_generic does. to quote from {@link http://www.php.net/function.mcrypt-generic}:
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
if ($this->paddable && strlen($ciphertext) % $this->block_size) {
throw new \LengthException('The ciphertext length (' . strlen($ciphertext) . ') needs to be a multiple of the block size (' . $this->block_size . ')');
}
if ($this->engine === self::ENGINE_OPENSSL) {
@ -1086,7 +1104,7 @@ abstract class Base
$this->changed = false;
}
if ($this->dechanged) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
mcrypt_generic_init($this->demcrypt, $this->key, $this->_getIV($this->decryptIV));
$this->dechanged = false;
}
@ -1131,7 +1149,7 @@ abstract class Base
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
mcrypt_generic_init($this->demcrypt, $this->key, $this->_getIV($this->decryptIV));
}
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
@ -1268,6 +1286,22 @@ abstract class Base
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
}
/**
* Get the IV
*
* mcrypt requires an IV even if ECB is used
*
* @see self::encrypt()
* @see self::decrypt()
* @param string $iv
* @return string
* @access private
*/
function _getIV($iv)
{
return $this->mode == self::MODE_ECB ? str_repeat("\0", $this->block_size) : $iv;
}
/**
* OpenSSL CTR Processor
*
@ -1820,6 +1854,7 @@ abstract class Base
*
* @see self::_unpad()
* @param string $text
* @throws \LengthException if padding is disabled and the plaintext's length is not a multiple of the block size
* @access private
* @return string
*/
@ -1831,8 +1866,7 @@ abstract class Base
if ($length % $this->block_size == 0) {
return $text;
} else {
user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})");
$this->padding = true;
throw new \LengthException("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size}). Try enabling padding.");
}
}
@ -1849,6 +1883,7 @@ abstract class Base
*
* @see self::_pad()
* @param string $text
* @throws \LengthException if the ciphertext's length is not a multiple of the block size
* @access private
* @return string
*/
@ -1861,7 +1896,7 @@ abstract class Base
$length = ord($text[strlen($text) - 1]);
if (!$length || $length > $this->block_size) {
return false;
throw new \LengthException("The ciphertext has an invalid padding length ($length) compared to the block size ({$this->block_size})");
}
return substr($text, 0, -$length);
@ -1874,20 +1909,19 @@ abstract class Base
* after disableContinuousBuffer() or on cipher $engine (re)init
* ie after setKey() or setIV()
*
* @access public
* @access private
* @internal Could, but not must, extend by the child Crypt_* class
* @throws \UnexpectedValueException when an IV is required but not defined
*/
function _clearBuffers()
{
$this->enbuffer = $this->debuffer = array('ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true);
// mcrypt's handling of invalid's $iv:
// $this->encryptIV = $this->decryptIV = strlen($this->iv) == $this->block_size ? $this->iv : str_repeat("\0", $this->block_size);
$this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
if (!$this->skip_key_adjustment) {
$this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
if ($this->iv === false && !in_array($this->mode, array(self::MODE_STREAM, self::MODE_ECB))) {
throw new \UnexpectedValueException('No IV has been defined');
}
$this->encryptIV = $this->decryptIV = $this->iv;
}
/**
@ -2544,10 +2578,10 @@ abstract class Base
$len = strlen($bytes);
for ($i = 0; $i < $len; $i+=20) {
$t = substr($bytes, $i, 20);
$hash = pack('H*', sha1($hash));
$hash = sha1($hash, true);
$result .= $t ^ $hash;
}
return $result . pack('H*', sha1($hash));
return $result . sha1($hash, true);
}
}
}

View File

@ -283,6 +283,22 @@ class Blowfish extends Base
*/
var $key_length = 16;
/**
* Default Constructor.
*
* @param int $mode
* @access public
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
*/
function __construct($mode)
{
if ($mode == self::MODE_STREAM) {
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
}
parent::__construct($mode);
}
/**
* Sets the key length.
*
@ -293,14 +309,12 @@ class Blowfish extends Base
*/
function setKeyLength($length)
{
if ($length < 32) {
$this->key_length = 7;
} elseif ($length > 448) {
$this->key_length = 56;
} else {
$this->key_length = $length >> 3;
if ($length < 32 || $length > 448) {
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes between 32 and 448 bits are supported');
}
$this->key_length = $length >> 3;
parent::setKeyLength($length);
}

View File

@ -578,6 +578,22 @@ class DES extends Base
0x00000820, 0x00020020, 0x08000000, 0x08020800
);
/**
* Default Constructor.
*
* @param int $mode
* @access public
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
*/
function __construct($mode)
{
if ($mode == self::MODE_STREAM) {
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
}
parent::__construct($mode);
}
/**
* Test for engine validity
*
@ -603,24 +619,18 @@ class DES extends Base
/**
* Sets the key.
*
* Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
* only use the first eight, if $key has more then eight characters in it, and pad $key with the
* null byte if it is less then eight characters long.
* Keys must be 64-bits long or 8 bytes long.
*
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
*
* If the key is not explicitly set, it'll be assumed to be all zero's.
*
* @see \phpseclib\Crypt\Base::setKey()
* @access public
* @param string $key
*/
function setKey($key)
{
// We check/cut here only up to max length of the key.
// Key padding to the proper length will be done in _setupKey()
if (strlen($key) > $this->key_length_max) {
$key = substr($key, 0, $this->key_length_max);
if (!($this instanceof TripleDES) && strlen($key) != 8) {
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of size 8 are supported');
}
// Sets the key

View File

@ -1,26 +1,19 @@
<?php
/**
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
* Wrapper around hash() and hash_hmac() functions supporting truncated hashes
* such as sha256-96. Any hash algorithm returned by hash_algos() (and
* truncated versions thereof) are supported.
*
* Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
*
* md2, md5, md5-96, sha1, sha1-96, sha256, sha256-96, sha384, and sha512, sha512-96
*
* If {@link self::setKey() setKey()} is called, {@link self::hash() hash()} will return the HMAC as opposed to
* the hash. If no valid algorithm is provided, sha1 will be used.
*
* PHP version 5
*
* {@internal The variable names are the same as those in
* {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
* If {@link self::setKey() setKey()} is called, {@link self::hash() hash()} will
* return the HMAC as opposed to the hash.
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $hash = new \phpseclib\Crypt\Hash('sha1');
* $hash = new \phpseclib\Crypt\Hash('sha512');
*
* $hash->setKey('abcdefg');
*
@ -31,7 +24,9 @@
* @category Crypt
* @package Hash
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2007 Jim Wigginton
* @copyright 2015 Jim Wigginton
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2015 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
@ -39,34 +34,16 @@
namespace phpseclib\Crypt;
use phpseclib\Math\BigInteger;
use phpseclib\Exception\UnsupportedAlgorithmException;
/**
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
*
* @package Hash
* @author Jim Wigginton <terrafrost@php.net>
* @author Andreas Fischer <bantu@phpbb.com>
* @access public
*/
class Hash
{
/**#@+
* @access private
* @see \phpseclib\Crypt\Hash::__construct()
*/
/**
* Toggles the internal implementation
*/
const MODE_INTERNAL = 1;
/**
* Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
*/
const MODE_MHASH = 2;
/**
* Toggles the hash() implementation, which works on PHP 5.1.2+.
*/
const MODE_HASH = 3;
/**#@-*/
/**
* Hash Parameter
*
@ -76,15 +53,6 @@ class Hash
*/
var $hashParam;
/**
* Byte-length of compression blocks / key (Internal HMAC)
*
* @see self::setAlgorithm()
* @var int
* @access private
*/
var $b;
/**
* Byte-length of hash output (Internal HMAC)
*
@ -92,7 +60,7 @@ class Hash
* @var int
* @access private
*/
var $l = false;
var $length;
/**
* Hash Algorithm
@ -112,10 +80,23 @@ class Hash
*/
var $key = false;
/**
* Initial Hash
*
* Used only for sha512/*
*
* @see self::_sha512()
* @var array
* @access private
*/
var $initial = false;
/**
* Outer XOR (Internal HMAC)
*
* @see self::setKey()
* Used only for sha512/*
*
* @see self::hash()
* @var string
* @access private
*/
@ -124,7 +105,9 @@ class Hash
/**
* Inner XOR (Internal HMAC)
*
* @see self::setKey()
* Used only for sha512/*
*
* @see self::hash()
* @var string
* @access private
*/
@ -134,25 +117,14 @@ class Hash
* Default Constructor.
*
* @param string $hash
* @return \phpseclib\Crypt\Hash
* @access public
*/
function __construct($hash = 'sha1')
function __construct($hash = 'sha256')
{
if (!defined('CRYPT_HASH_MODE')) {
switch (true) {
case extension_loaded('hash'):
define('CRYPT_HASH_MODE', self::MODE_HASH);
break;
case extension_loaded('mhash'):
define('CRYPT_HASH_MODE', self::MODE_MHASH);
break;
default:
define('CRYPT_HASH_MODE', self::MODE_INTERNAL);
}
}
$this->setHash($hash);
$this->ipad = str_repeat(chr(0x36), 128);
$this->opad = str_repeat(chr(0x5C), 128);
}
/**
@ -191,101 +163,63 @@ class Hash
{
$this->hashParam = $hash = strtolower($hash);
switch ($hash) {
case 'md2-96':
case 'md5-96':
case 'sha1-96':
case 'sha224-96':
case 'sha256-96':
case 'sha384-96':
case 'sha512-96':
case 'sha512/224-96':
case 'sha512/256-96':
$hash = substr($hash, 0, -3);
$this->l = 12; // 96 / 8 = 12
$this->length = 12; // 96 / 8 = 12
break;
case 'md2':
case 'md5':
$this->l = 16;
$this->length = 16;
break;
case 'sha1':
$this->l = 20;
$this->length = 20;
break;
case 'sha224':
case 'sha512/224':
$this->length = 28;
break;
case 'sha256':
$this->l = 32;
case 'sha512/256':
$this->length = 32;
break;
case 'sha384':
$this->l = 48;
$this->length = 48;
break;
case 'sha512':
$this->l = 64;
}
switch ($hash) {
case 'md2':
$mode = CRYPT_HASH_MODE == self::MODE_HASH && in_array('md2', hash_algos()) ?
self::MODE_HASH : self::MODE_INTERNAL;
break;
case 'sha384':
case 'sha512':
$mode = CRYPT_HASH_MODE == self::MODE_MHASH ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
$this->length = 64;
break;
default:
$mode = CRYPT_HASH_MODE;
throw new UnsupportedAlgorithmException(
"$hash is not a supported algorithm"
);
}
switch ($mode) {
case self::MODE_MHASH:
switch ($hash) {
case 'md5':
$this->hash = MHASH_MD5;
break;
case 'sha256':
$this->hash = MHASH_SHA256;
break;
case 'sha1':
default:
$this->hash = MHASH_SHA1;
}
return;
case self::MODE_HASH:
switch ($hash) {
case 'md5':
$this->hash = 'md5';
return;
case 'md2':
case 'sha256':
case 'sha384':
case 'sha512':
$this->hash = $hash;
return;
case 'sha1':
default:
$this->hash = 'sha1';
}
return;
if ($hash == 'sha512/224' || $hash == 'sha512/256') {
// from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24
$this->initial = $hash == 'sha512/256' ?
array(
'22312194FC2BF72C', '9F555FA3C84C64C2', '2393B86B6F53B151', '963877195940EABD',
'96283EE2A88EFFE3', 'BE5E1E2553863992', '2B0199FC2C85B8AA', '0EB72DDC81C52CA2'
) :
array(
'8C3D37C819544DA2', '73E1996689DCD4D6', '1DFAB7AE32FF9C82', '679DD514582F9FCF',
'0F6D2B697BD44DA8', '77E36F7304C48942', '3F9D85A86A1D36C8', '1112E6AD91D692A1'
);
for ($i = 0; $i < 8; $i++) {
$this->initial[$i] = new BigInteger($this->initial[$i], 16);
$this->initial[$i]->setPrecision(64);
}
}
switch ($hash) {
case 'md2':
$this->b = 16;
$this->hash = array($this, '_md2');
break;
case 'md5':
$this->b = 64;
$this->hash = array($this, '_md5');
break;
case 'sha256':
$this->b = 64;
$this->hash = array($this, '_sha256');
break;
case 'sha384':
case 'sha512':
$this->b = 128;
$this->hash = array($this, '_sha512');
break;
case 'sha1':
default:
$this->b = 64;
$this->hash = array($this, '_sha1');
}
$this->ipad = str_repeat(chr(0x36), $this->b);
$this->opad = str_repeat(chr(0x5C), $this->b);
$this->hash = $hash;
}
/**
@ -297,45 +231,35 @@ class Hash
*/
function hash($text)
{
$mode = is_array($this->hash) ? self::MODE_INTERNAL : CRYPT_HASH_MODE;
switch ($this->hash) {
case 'sha512/224':
case 'sha512/256':
if (empty($this->key) || !is_string($this->key)) {
return substr(self::_sha512($text, $this->initial), 0, $this->length);
}
/* "Applications that use keys longer than B bytes will first hash the key using H and then use the
resultant L byte string as the actual key to HMAC."
if (!empty($this->key) || is_string($this->key)) {
switch ($mode) {
case self::MODE_MHASH:
$output = mhash($this->hash, $text, $this->key);
break;
case self::MODE_HASH:
$output = hash_hmac($this->hash, $text, $this->key, true);
break;
case self::MODE_INTERNAL:
/* "Applications that use keys longer than B bytes will first hash the key using H and then use the
resultant L byte string as the actual key to HMAC."
-- http://tools.ietf.org/html/rfc2104#section-2 */
$key = strlen($this->key) > $this->b ? self::_sha512($this->key, $this->initial) : $this->key;
-- http://tools.ietf.org/html/rfc2104#section-2 */
$key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
$key = str_pad($this->key, 128, chr(0)); // step 1
$temp = $this->ipad ^ $this->key; // step 2
$temp .= $text; // step 3
$temp = self::_sha512($temp, $this->initial); // step 4
$output = $this->opad ^ $this->key; // step 5
$output.= $temp; // step 6
$output = self::_sha512($output, $this->initial); // step 7
$key = str_pad($key, $this->b, chr(0)); // step 1
$temp = $this->ipad ^ $key; // step 2
$temp .= $text; // step 3
$temp = call_user_func($this->hash, $temp); // step 4
$output = $this->opad ^ $key; // step 5
$output.= $temp; // step 6
$output = call_user_func($this->hash, $output); // step 7
}
} else {
switch ($mode) {
case self::MODE_MHASH:
$output = mhash($this->hash, $text);
break;
case self::MODE_HASH:
$output = hash($this->hash, $text, true);
break;
case self::MODE_INTERNAL:
$output = call_user_func($this->hash, $text);
}
return substr($output, 0, $this->length);
}
$output = !empty($this->key) || is_string($this->key) ?
hash_hmac($this->hash, $text, $this->key, true) :
hash($this->hash, $text, true);
return substr($output, 0, $this->l);
return strlen($output) > $this->length
? substr($output, 0, $this->length)
: $output;
}
/**
@ -346,243 +270,20 @@ class Hash
*/
function getLength()
{
return $this->l;
return $this->length;
}
/**
* Wrapper for MD5
* Pure-PHP implementation of SHA512
*
* @access private
* @param string $m
*/
function _md5($m)
static function _sha512($m, $hash)
{
return pack('H*', md5($m));
}
/**
* Wrapper for SHA1
*
* @access private
* @param string $m
*/
function _sha1($m)
{
return pack('H*', sha1($m));
}
/**
* Pure-PHP implementation of MD2
*
* See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
*
* @access private
* @param string $m
*/
function _md2($m)
{
static $s = array(
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
);
// Step 1. Append Padding Bytes
$pad = 16 - (strlen($m) & 0xF);
$m.= str_repeat(chr($pad), $pad);
$length = strlen($m);
// Step 2. Append Checksum
$c = str_repeat(chr(0), 16);
$l = chr(0);
for ($i = 0; $i < $length; $i+= 16) {
for ($j = 0; $j < 16; $j++) {
// RFC1319 incorrectly states that C[j] should be set to S[c xor L]
//$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
// per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
$c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
$l = $c[$j];
}
}
$m.= $c;
$length+= 16;
// Step 3. Initialize MD Buffer
$x = str_repeat(chr(0), 48);
// Step 4. Process Message in 16-Byte Blocks
for ($i = 0; $i < $length; $i+= 16) {
for ($j = 0; $j < 16; $j++) {
$x[$j + 16] = $m[$i + $j];
$x[$j + 32] = $x[$j + 16] ^ $x[$j];
}
$t = chr(0);
for ($j = 0; $j < 18; $j++) {
for ($k = 0; $k < 48; $k++) {
$x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
//$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
}
$t = chr(ord($t) + $j);
}
}
// Step 5. Output
return substr($x, 0, 16);
}
/**
* Pure-PHP implementation of SHA256
*
* See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
*
* @access private
* @param string $m
*/
function _sha256($m)
{
if (extension_loaded('suhosin')) {
return pack('H*', sha256($m));
}
// Initialize variables
$hash = array(
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
);
// Initialize table of round constants
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
static $k = array(
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
);
// Pre-processing
$length = strlen($m);
// to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
$m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
$m[$length] = chr(0x80);
// we don't support hashing strings 512MB long
$m.= pack('N2', 0, $length << 3);
// Process the message in successive 512-bit chunks
$chunks = str_split($m, 64);
foreach ($chunks as $chunk) {
$w = array();
for ($i = 0; $i < 16; $i++) {
extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
$w[] = $temp;
}
// Extend the sixteen 32-bit words into sixty-four 32-bit words
for ($i = 16; $i < 64; $i++) {
// @codingStandardsIgnoreStart
$s0 = $this->_rightRotate($w[$i - 15], 7) ^
$this->_rightRotate($w[$i - 15], 18) ^
$this->_rightShift( $w[$i - 15], 3);
$s1 = $this->_rightRotate($w[$i - 2], 17) ^
$this->_rightRotate($w[$i - 2], 19) ^
$this->_rightShift( $w[$i - 2], 10);
// @codingStandardsIgnoreEnd
$w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
}
// Initialize hash value for this chunk
list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
// Main loop
for ($i = 0; $i < 64; $i++) {
$s0 = $this->_rightRotate($a, 2) ^
$this->_rightRotate($a, 13) ^
$this->_rightRotate($a, 22);
$maj = ($a & $b) ^
($a & $c) ^
($b & $c);
$t2 = $this->_add($s0, $maj);
$s1 = $this->_rightRotate($e, 6) ^
$this->_rightRotate($e, 11) ^
$this->_rightRotate($e, 25);
$ch = ($e & $f) ^
($this->_not($e) & $g);
$t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
$h = $g;
$g = $f;
$f = $e;
$e = $this->_add($d, $t1);
$d = $c;
$c = $b;
$b = $a;
$a = $this->_add($t1, $t2);
}
// Add this chunk's hash to result so far
$hash = array(
$this->_add($hash[0], $a),
$this->_add($hash[1], $b),
$this->_add($hash[2], $c),
$this->_add($hash[3], $d),
$this->_add($hash[4], $e),
$this->_add($hash[5], $f),
$this->_add($hash[6], $g),
$this->_add($hash[7], $h)
);
}
// Produce the final hash value (big-endian)
return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
}
/**
* Pure-PHP implementation of SHA384 and SHA512
*
* @access private
* @param string $m
*/
function _sha512($m)
{
static $init384, $init512, $k;
static $k;
if (!isset($k)) {
// Initialize variables
$init384 = array( // initial values for SHA384
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
);
$init512 = array( // initial values for SHA512
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
);
for ($i = 0; $i < 8; $i++) {
$init384[$i] = new BigInteger($init384[$i], 16);
$init384[$i]->setPrecision(64);
$init512[$i] = new BigInteger($init512[$i], 16);
$init512[$i]->setPrecision(64);
}
// Initialize table of round constants
// (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
$k = array(
@ -613,8 +314,6 @@ class Hash
}
}
$hash = $this->l == 48 ? $init384 : $init512;
// Pre-processing
$length = strlen($m);
// to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
@ -628,7 +327,7 @@ class Hash
foreach ($chunks as $chunk) {
$w = array();
for ($i = 0; $i < 16; $i++) {
$temp = new BigInteger($this->_string_shift($chunk, 8), 256);
$temp = new BigInteger(self::_string_shift($chunk, 8), 256);
$temp->setPrecision(64);
$w[] = $temp;
}
@ -649,21 +348,21 @@ class Hash
);
$s1 = $temp[0]->bitwise_xor($temp[1]);
$s1 = $s1->bitwise_xor($temp[2]);
$w[$i] = $w[$i - 16]->copy();
$w[$i] = clone $w[$i - 16];
$w[$i] = $w[$i]->add($s0);
$w[$i] = $w[$i]->add($w[$i - 7]);
$w[$i] = $w[$i]->add($s1);
}
// Initialize hash value for this chunk
$a = $hash[0]->copy();
$b = $hash[1]->copy();
$c = $hash[2]->copy();
$d = $hash[3]->copy();
$e = $hash[4]->copy();
$f = $hash[5]->copy();
$g = $hash[6]->copy();
$h = $hash[7]->copy();
$a = clone $hash[0];
$b = clone $hash[1];
$c = clone $hash[2];
$d = clone $hash[3];
$e = clone $hash[4];
$f = clone $hash[5];
$g = clone $hash[6];
$h = clone $hash[7];
// Main loop
for ($i = 0; $i < 80; $i++) {
@ -700,13 +399,13 @@ class Hash
$t1 = $t1->add($k[$i]);
$t1 = $t1->add($w[$i]);
$h = $g->copy();
$g = $f->copy();
$f = $e->copy();
$h = clone $g;
$g = clone $f;
$f = clone $e;
$e = $d->add($t1);
$d = $c->copy();
$c = $b->copy();
$b = $a->copy();
$d = clone $c;
$c = clone $b;
$b = clone $a;
$a = $t1->add($t2);
}
@ -726,85 +425,11 @@ class Hash
// Produce the final hash value (big-endian)
// (\phpseclib\Crypt\Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
$temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
$hash[4]->toBytes() . $hash[5]->toBytes();
if ($this->l != 48) {
$temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
}
$hash[4]->toBytes() . $hash[5]->toBytes() . $hash[6]->toBytes() . $hash[7]->toBytes();
return $temp;
}
/**
* Right Rotate
*
* @access private
* @param int $int
* @param int $amt
* @see self::_sha256()
* @return int
*/
function _rightRotate($int, $amt)
{
$invamt = 32 - $amt;
$mask = (1 << $invamt) - 1;
return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
}
/**
* Right Shift
*
* @access private
* @param int $int
* @param int $amt
* @see self::_sha256()
* @return int
*/
function _rightShift($int, $amt)
{
$mask = (1 << (32 - $amt)) - 1;
return ($int >> $amt) & $mask;
}
/**
* Not
*
* @access private
* @param int $int
* @see self::_sha256()
* @return int
*/
function _not($int)
{
return ~$int & 0xFFFFFFFF;
}
/**
* Add
*
* _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
* possibility of overflow exists, care has to be taken. BigInteger could be used but this should be faster.
*
* @param int $...
* @return int
* @see self::_sha256()
* @access private
*/
function _add()
{
static $mod;
if (!isset($mod)) {
$mod = pow(2, 32);
}
$result = 0;
$arguments = func_get_args();
foreach ($arguments as $argument) {
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
}
return fmod($result, $mod);
}
/**
* String Shift
*
@ -815,7 +440,7 @@ class Hash
* @return string
* @access private
*/
function _string_shift(&$string, $index = 1)
static function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);

View File

@ -259,6 +259,22 @@ class RC2 extends Base
0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6
);
/**
* Default Constructor.
*
* @param int $mode
* @access public
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
*/
function __construct($mode)
{
if ($mode == self::MODE_STREAM) {
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
}
parent::__construct($mode);
}
/**
* Test for engine validity
*
@ -292,19 +308,15 @@ class RC2 extends Base
*
* @access public
* @param int $length in bits
* @throws \LengthException if the key length isn't supported
*/
function setKeyLength($length)
{
if ($length < 8) {
$this->default_key_length = 8;
} elseif ($length > 1024) {
$this->default_key_length = 128;
} else {
$this->default_key_length = $length;
if ($length < 8 || $length > 1024) {
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
}
$this->current_key_length = $this->default_key_length;
parent::setKeyLength($length);
$this->default_key_length = $this->current_key_length = $length;
}
/**
@ -333,16 +345,20 @@ class RC2 extends Base
* @access public
* @param string $key
* @param int $t1 optional Effective key length in bits.
* @throws \LengthException if the key length isn't supported
*/
function setKey($key, $t1 = 0)
function setKey($key, $t1 = false)
{
$this->orig_key = $key;
if ($t1 <= 0) {
if ($t1 === false) {
$t1 = $this->default_key_length;
} elseif ($t1 > 1024) {
$t1 = 1024;
}
if ($t1 < 1 || $t1 > 1024) {
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 1024 bits, inclusive, are supported');
}
$this->current_key_length = $t1;
// Key byte count should be 1..128.
$key = strlen($key) ? substr($key, 0, 128) : "\x00";

View File

@ -121,8 +121,6 @@ class RC4 extends Base
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* @see \phpseclib\Crypt\Base::__construct()
* @return \phpseclib\Crypt\RC4
* @access public
@ -165,26 +163,14 @@ class RC4 extends Base
}
/**
* Dummy function.
* RC4 does not use an IV
*
* Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
* If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
* calling setKey().
*
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
* the IV's are relatively easy to predict, an attack described by
* {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
* can be used to quickly guess at the rest of the key. The following links elaborate:
*
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
*
* @param string $iv
* @see self::setKey()
* @access public
* @return bool
*/
function setIV($iv)
function usesIV()
{
return false;
}
/**
@ -194,20 +180,38 @@ class RC4 extends Base
*
* @access public
* @param int $length
* @throws \LengthException if the key length is invalid
*/
function setKeyLength($length)
{
if ($length < 8) {
$this->key_length = 1;
} elseif ($length > 2048) {
$this->key_length = 256;
} else {
$this->key_length = $length >> 3;
if ($length < 8 || $length > 2048) {
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys between 1 and 256 bytes are supported');
}
$this->key_length = $length >> 3;
parent::setKeyLength($length);
}
/**
* Sets the key length
*
* Keys can be between 1 and 256 bytes long.
*
* @access public
* @param int $length
* @throws \LengthException if the key length is invalid
*/
function setKey($key)
{
$length = strlen($key);
if ($length < 1 || $length > 256) {
throw new \LengthException('Key size of ' . $length . ' bytes is not supported by RC4. Keys must be between 1 and 256 bytes long');
}
parent::setKey($key);
}
/**
* Encrypts a message.
*

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,224 @@
<?php
/**
* Miccrosoft BLOB Formatted RSA Key Handler
*
* More info:
*
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx
*
* 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 phpseclib\Math\BigInteger;
/**
* Microsoft BLOB Formatted RSA Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class MSBLOB
{
/**#@+
* @access private
*/
/**
* Public/Private Key Pair
*/
const PRIVATEKEYBLOB = 0x7;
/**
* Public Key
*/
const PUBLICKEYBLOB = 0x6;
/**
* Public Key
*/
const PUBLICKEYBLOBEX = 0xA;
/**
* RSA public key exchange algorithm
*/
const CALG_RSA_KEYX = 0x0000A400;
/**
* RSA public key exchange algorithm
*/
const CALG_RSA_SIGN = 0x00002400;
/**
* Public Key
*/
const RSA1 = 0x31415352;
/**
* Private Key
*/
const RSA2 = 0x32415352;
/**#@-*/
/**
* 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;
}
$key = Base64::decode($key);
if (!is_string($key) || strlen($key) < 20) {
return false;
}
// PUBLICKEYSTRUC publickeystruc
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx
extract(unpack('atype/aversion/vreserved/Valgo', self::_string_shift($key, 8)));
switch (ord($type)) {
case self::PUBLICKEYBLOB:
case self::PUBLICKEYBLOBEX:
$publickey = true;
break;
case self::PRIVATEKEYBLOB:
$publickey = false;
break;
default:
return false;
}
$components = array('isPublicKey' => $publickey);
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
switch ($algo) {
case self::CALG_RSA_KEYX:
case self::CALG_RSA_SIGN:
break;
default:
return false;
}
// RSAPUBKEY rsapubkey
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx
// could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit
extract(unpack('Vmagic/Vbitlen/a4pubexp', self::_string_shift($key, 12)));
switch ($magic) {
case self::RSA2:
$components['isPublicKey'] = false;
case self::RSA1:
break;
default:
return false;
}
$baseLength = $bitlen / 16;
if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) {
return false;
}
$components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256);
// BYTE modulus[rsapubkey.bitlen/8]
$components['modulus'] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 8)), 256);
if ($publickey) {
return $components;
}
$components['isPublicKey'] = false;
// BYTE prime1[rsapubkey.bitlen/16]
$components['primes'] = array(1 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
// BYTE prime2[rsapubkey.bitlen/16]
$components['primes'][] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256);
// BYTE exponent1[rsapubkey.bitlen/16]
$components['exponents'] = array(1 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
// BYTE exponent2[rsapubkey.bitlen/16]
$components['exponents'][] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256);
// BYTE coefficient[rsapubkey.bitlen/16]
$components['coefficients'] = array(2 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
if (isset($components['privateExponent'])) {
$components['publicExponent'] = $components['privateExponent'];
}
// BYTE privateExponent[rsapubkey.bitlen/8]
$components['privateExponent'] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 8)), 256);
return $components;
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @param \phpseclib\Math\BigInteger $d
* @param array $primes
* @param array $exponents
* @param array $coefficients
* @param string $password optional
* @return string
*/
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
{
$n = strrev($n->toBytes());
$e = str_pad(strrev($e->toBytes()), 4, "\0");
$key = pack('aavV', chr(self::PRIVATEKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
$key.= pack('VVa*', self::RSA2, 8 * strlen($n), $e);
$key.= $n;
$key.= strrev($primes[1]->toBytes());
$key.= strrev($primes[2]->toBytes());
$key.= strrev($exponents[1]->toBytes());
$key.= strrev($exponents[2]->toBytes());
$key.= strrev($coefficients[1]->toBytes());
$key.= strrev($d->toBytes());
return Base64::encode($key);
}
/**
* Convert a public key to the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @return string
*/
static function savePublicKey(BigInteger $n, BigInteger $e)
{
$n = strrev($n->toBytes());
$e = str_pad(strrev($e->toBytes()), 4, "\0");
$key = pack('aavV', chr(self::PUBLICKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
$key.= pack('VVa*', self::RSA1, 8 * strlen($n), $e);
$key.= $n;
return Base64::encode($key);
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
static function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}

View File

@ -0,0 +1,141 @@
<?php
/**
* OpenSSH Formatted RSA Key Handler
*
* PHP version 5
*
* Place in $HOME/.ssh/authorized_keys
*
* @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 phpseclib\Math\BigInteger;
/**
* OpenSSH Formatted RSA Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class OpenSSH
{
/**
* Default comment
*
* @var string
* @access private
*/
static $comment = 'phpseclib-generated-key';
/**
* Sets the default comment
*
* @access public
* @param string $comment
*/
static function setComment($comment)
{
self::$comment = str_replace(array("\r", "\n"), '', $comment);
}
/**
* 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;
}
$parts = explode(' ', $key, 3);
$key = isset($parts[1]) ? Base64::decode($parts[1]) : Base64::decode($parts[0]);
if ($key === false) {
return false;
}
$comment = isset($parts[2]) ? $parts[2] : false;
if (substr($key, 0, 11) != "\0\0\0\7ssh-rsa") {
return false;
}
self::_string_shift($key, 11);
if (strlen($key) <= 4) {
return false;
}
extract(unpack('Nlength', self::_string_shift($key, 4)));
if (strlen($key) <= $length) {
return false;
}
$publicExponent = new BigInteger(self::_string_shift($key, $length), -256);
if (strlen($key) <= 4) {
return false;
}
extract(unpack('Nlength', self::_string_shift($key, 4)));
if (strlen($key) != $length) {
return false;
}
$modulus = new BigInteger(self::_string_shift($key, $length), -256);
return array(
'isPublicKey' => true,
'modulus' => $modulus,
'publicExponent' => $publicExponent,
'comment' => $comment
);
}
/**
* Convert a public key to the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @return string
*/
static function savePublicKey(BigInteger $n, BigInteger $e)
{
$publicExponent = $e->toBytes(true);
$modulus = $n->toBytes(true);
// from <http://tools.ietf.org/html/rfc4253#page-15>:
// string "ssh-rsa"
// mpint e
// mpint n
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
$RSAPublicKey = 'ssh-rsa ' . Base64::encode($RSAPublicKey) . ' ' . self::$comment;
return $RSAPublicKey;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
static function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
}

View File

@ -0,0 +1,487 @@
<?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\AES;
use phpseclib\Crypt\Base;
use phpseclib\Crypt\DES;
use phpseclib\Crypt\TripleDES;
use phpseclib\Math\BigInteger;
/**
* 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 Base::MODE_CBC;
case 'ECB':
return Base::MODE_ECB;
case 'CFB':
return Base::MODE_CFB;
case 'OFB':
return Base::MODE_OFB;
case 'CTR':
return Base::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(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
return false;
}
if (self::_decodeLength($key) != strlen($key)) {
return false;
}
$tag = ord(self::_string_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") {
self::_string_shift($key, 3);
$tag = self::ASN1_SEQUENCE;
}
if ($tag == self::ASN1_SEQUENCE) {
$temp = self::_string_shift($key, self::_decodeLength($key));
if (ord(self::_string_shift($temp)) != self::ASN1_OBJECT) {
return false;
}
$length = self::_decodeLength($temp);
switch (self::_string_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(self::_string_shift($temp)) != self::ASN1_SEQUENCE) {
return false;
}
if (self::_decodeLength($temp) != strlen($temp)) {
return false;
}
self::_string_shift($temp); // assume it's an octet string
$salt = self::_string_shift($temp, self::_decodeLength($temp));
if (ord(self::_string_shift($temp)) != self::ASN1_INTEGER) {
return false;
}
self::_decodeLength($temp);
list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
self::_string_shift($key); // assume it's an octet string
$length = self::_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(self::_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
self::_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) {
self::_string_shift($key);
}
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
return false;
}
if (self::_decodeLength($key) != strlen($key)) {
return false;
}
$tag = ord(self::_string_shift($key));
}
if ($tag != self::ASN1_INTEGER) {
return false;
}
$length = self::_decodeLength($key);
$temp = self::_string_shift($key, $length);
if (strlen($temp) != 1 || ord($temp) > 2) {
$components['modulus'] = new BigInteger($temp, 256);
self::_string_shift($key); // skip over self::ASN1_INTEGER
$length = self::_decodeLength($key);
$components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
return $components;
}
if (ord(self::_string_shift($key)) != self::ASN1_INTEGER) {
return false;
}
$length = self::_decodeLength($key);
$components['modulus'] = new BigInteger(self::_string_shift($key, $length), 256);
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['publicExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['privateExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['primes'] = array(1 => new BigInteger(self::_string_shift($key, $length), 256));
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['primes'][] = new BigInteger(self::_string_shift($key, $length), 256);
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['exponents'] = array(1 => new BigInteger(self::_string_shift($key, $length), 256));
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['exponents'][] = new BigInteger(self::_string_shift($key, $length), 256);
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['coefficients'] = array(2 => new BigInteger(self::_string_shift($key, $length), 256));
if (!empty($key)) {
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
return false;
}
self::_decodeLength($key);
while (!empty($key)) {
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
return false;
}
self::_decodeLength($key);
$key = substr($key, 1);
$length = self::_decodeLength($key);
$components['primes'][] = new BigInteger(self::_string_shift($key, $length), 256);
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['exponents'][] = new BigInteger(self::_string_shift($key, $length), 256);
self::_string_shift($key);
$length = self::_decodeLength($key);
$components['coefficients'][] = new BigInteger(self::_string_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;
}
/**
* DER-decode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @access private
* @param string $string
* @return int
*/
static function _decodeLength(&$string)
{
$length = ord(self::_string_shift($string));
if ($length & 0x80) { // definite length, long form
$length&= 0x7F;
$temp = self::_string_shift($string, $length);
list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
}
return $length;
}
/**
* DER-encode the length
*
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
*
* @access private
* @param int $length
* @return string
*/
static function _encodeLength($length)
{
if ($length <= 0x7F) {
return chr($length);
}
$temp = ltrim(pack('N', $length), chr(0));
return pack('Ca*', 0x80 | strlen($temp), $temp);
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
static function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* 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;
}
}

View File

@ -0,0 +1,174 @@
<?php
/**
* PKCS#1 Formatted RSA Key Handler
*
* PHP version 5
*
* Used by File/X509.php
*
* Has the following header:
*
* -----BEGIN RSA PUBLIC KEY-----
*
* Analogous to ssh-keygen's pem format (as specified by -m)
*
* @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\AES;
use phpseclib\Crypt\DES;
use phpseclib\Crypt\Random;
use phpseclib\Crypt\TripleDES;
use phpseclib\Math\BigInteger;
/**
* PKCS#1 Formatted RSA Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class PKCS1 extends PKCS
{
/**
* Default encryption algorithm
*
* @var string
* @access private
*/
static $defaultEncryptionAlgorithm = 'DES-EDE3-CBC';
/**
* Sets the default encryption algorithm
*
* @access public
* @param string $algo
*/
static function setEncryptionAlgorithm($algo)
{
self::$defaultEncryptionAlgorithm = $algo;
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @param \phpseclib\Math\BigInteger $d
* @param array $primes
* @param array $exponents
* @param array $coefficients
* @param string $password optional
* @return string
*/
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
{
$num_primes = count($primes);
$raw = array(
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
'modulus' => $n->toBytes(true),
'publicExponent' => $e->toBytes(true),
'privateExponent' => $d->toBytes(true),
'prime1' => $primes[1]->toBytes(true),
'prime2' => $primes[2]->toBytes(true),
'exponent1' => $exponents[1]->toBytes(true),
'exponent2' => $exponents[2]->toBytes(true),
'coefficient' => $coefficients[2]->toBytes(true)
);
$components = array();
foreach ($raw as $name => $value) {
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_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, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
}
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
}
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
if (!empty($password) || is_string($password)) {
$cipher = self::getEncryptionObject(self::$defaultEncryptionAlgorithm);
$iv = Random::string($cipher->getBlockLength() >> 3);
$cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
$cipher->setIV($iv);
$iv = strtoupper(Hex::encode($iv));
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
"Proc-Type: 4,ENCRYPTED\r\n" .
"DEK-Info: " . self::$defaultEncryptionAlgorithm . ",$iv\r\n" .
"\r\n" .
chunk_split(Base64::encode($cipher->encrypt($RSAPrivateKey)), 64) .
'-----END RSA PRIVATE KEY-----';
} else {
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
chunk_split(Base64::encode($RSAPrivateKey), 64) .
'-----END RSA PRIVATE KEY-----';
}
return $RSAPrivateKey;
}
/**
* Convert a public key to the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @return string
*/
static function savePublicKey(BigInteger $n, BigInteger $e)
{
$modulus = $n->toBytes(true);
$publicExponent = $e->toBytes(true);
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
// RSAPublicKey ::= SEQUENCE {
// modulus INTEGER, -- n
// publicExponent INTEGER -- e
// }
$components = array(
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
);
$RSAPublicKey = pack(
'Ca*a*a*',
self::ASN1_SEQUENCE,
self::_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;
}
}

View File

@ -0,0 +1,209 @@
<?php
/**
* PKCS#8 Formatted RSA Key Handler
*
* PHP version 5
*
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
*
* Has the following header:
*
* -----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 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 phpseclib\Crypt\DES;
use phpseclib\Crypt\Random;
use phpseclib\Math\BigInteger;
/**
* PKCS#8 Formatted RSA Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class PKCS8 extends PKCS
{
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @param \phpseclib\Math\BigInteger $d
* @param array $primes
* @param array $exponents
* @param array $coefficients
* @param string $password optional
* @return string
*/
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
{
$num_primes = count($primes);
$raw = array(
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
'modulus' => $n->toBytes(true),
'publicExponent' => $e->toBytes(true),
'privateExponent' => $d->toBytes(true),
'prime1' => $primes[1]->toBytes(true),
'prime2' => $primes[2]->toBytes(true),
'exponent1' => $exponents[1]->toBytes(true),
'exponent2' => $exponents[2]->toBytes(true),
'coefficient' => $coefficients[2]->toBytes(true)
);
$components = array();
foreach ($raw as $name => $value) {
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_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, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
}
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
}
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_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,
self::_encodeLength(strlen($RSAPrivateKey)),
$RSAPrivateKey
);
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_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,
self::_encodeLength(strlen($salt)),
$salt,
self::ASN1_INTEGER,
self::_encodeLength(4),
$iterationCount
);
$pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
$encryptionAlgorithm = pack(
'Ca*a*Ca*a*',
self::ASN1_OBJECT,
self::_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
$pbeWithMD5AndDES_CBC,
self::ASN1_SEQUENCE,
self::_encodeLength(strlen($parameters)),
$parameters
);
$RSAPrivateKey = pack(
'Ca*a*Ca*a*',
self::ASN1_SEQUENCE,
self::_encodeLength(strlen($encryptionAlgorithm)),
$encryptionAlgorithm,
self::ASN1_OCTETSTRING,
self::_encodeLength(strlen($RSAPrivateKey)),
$RSAPrivateKey
);
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_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;
}
/**
* Convert a public key to the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @return string
*/
static function savePublicKey(BigInteger $n, BigInteger $e)
{
$modulus = $n->toBytes(true);
$publicExponent = $e->toBytes(true);
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
// RSAPublicKey ::= SEQUENCE {
// modulus INTEGER, -- n
// publicExponent INTEGER -- e
// }
$components = array(
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
);
$RSAPublicKey = pack(
'Ca*a*a*',
self::ASN1_SEQUENCE,
self::_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) . self::_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
$RSAPublicKey = pack(
'Ca*a*',
self::ASN1_SEQUENCE,
self::_encodeLength(strlen($rsaOID . $RSAPublicKey)),
$rsaOID . $RSAPublicKey
);
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(Base64::encode($RSAPublicKey), 64) .
'-----END PUBLIC KEY-----';
return $RSAPublicKey;
}
}

View File

@ -0,0 +1,313 @@
<?php
/**
* PuTTY 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\AES;
use phpseclib\Crypt\Hash;
use phpseclib\Math\BigInteger;
/**
* PuTTY Formatted RSA Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class PuTTY
{
/**
* Default comment
*
* @var string
* @access private
*/
static $comment = 'phpseclib-generated-key';
/**
* Sets the default comment
*
* @access public
* @param string $comment
*/
static function setComment($comment)
{
self::$comment = str_replace(array("\r", "\n"), '', $comment);
}
/**
* Generate a symmetric key for PuTTY keys
*
* @access public
* @param string $password
* @param string $iv
* @param int $length
* @return string
*/
static function generateSymmetricKey($password, $length)
{
$symkey = '';
$sequence = 0;
while (strlen($symkey) < $length) {
$temp = pack('Na*', $sequence++, $password);
$symkey.= Hex::decode(sha1($temp));
}
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;
}
static $one;
if (!isset($one)) {
$one = new BigInteger(1);
}
if (strpos($key, 'BEGIN SSH2 PUBLIC KEY')) {
$data = preg_split('#[\r\n]+#', $key);
$data = array_splice($data, 2, -1);
$data = implode('', $data);
$components = OpenSSH::load($data);
if ($components === false) {
return false;
}
if (!preg_match('#Comment: "(.+)"#', $key, $matches)) {
return false;
}
$components['comment'] = str_replace(array('\\\\', '\"'), array('\\', '"'), $matches[1]);
return $components;
}
$components = array('isPublicKey' => false);
$key = preg_split('#\r\n|\r|\n#', $key);
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
if ($type != 'ssh-rsa') {
return false;
}
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
$components['comment'] = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
$publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
$public = Base64::decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
$public = substr($public, 11);
extract(unpack('Nlength', self::_string_shift($public, 4)));
$components['publicExponent'] = new BigInteger(self::_string_shift($public, $length), -256);
extract(unpack('Nlength', self::_string_shift($public, 4)));
$components['modulus'] = new BigInteger(self::_string_shift($public, $length), -256);
$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
$private = Base64::decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
switch ($encryption) {
case 'aes256-cbc':
$symkey = static::generateSymmetricKey($password, 32);
$crypto = new AES(AES::MODE_CBC);
}
if ($encryption != 'none') {
$crypto->setKey($symkey);
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
$crypto->disablePadding();
$private = $crypto->decrypt($private);
if ($private === false) {
return false;
}
}
extract(unpack('Nlength', self::_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['privateExponent'] = new BigInteger(self::_string_shift($private, $length), -256);
extract(unpack('Nlength', self::_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['primes'] = array(1 => new BigInteger(self::_string_shift($private, $length), -256));
extract(unpack('Nlength', self::_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['primes'][] = new BigInteger(self::_string_shift($private, $length), -256);
$temp = $components['primes'][1]->subtract($one);
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
$temp = $components['primes'][2]->subtract($one);
$components['exponents'][] = $components['publicExponent']->modInverse($temp);
extract(unpack('Nlength', self::_string_shift($private, 4)));
if (strlen($private) < $length) {
return false;
}
$components['coefficients'] = array(2 => new BigInteger(self::_string_shift($private, $length), -256));
return $components;
}
/**
* String Shift
*
* Inspired by array_shift
*
* @param string $string
* @param int $index
* @return string
* @access private
*/
static function _string_shift(&$string, $index = 1)
{
$substr = substr($string, 0, $index);
$string = substr($string, $index);
return $substr;
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @param \phpseclib\Math\BigInteger $d
* @param array $primes
* @param array $exponents
* @param array $coefficients
* @param string $password optional
* @return string
*/
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
{
if (count($primes) != 2) {
return false;
}
$raw = array(
'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)
);
$key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
$encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none';
$key.= $encryption;
$key.= "\r\nComment: " . self::$comment . "\r\n";
$public = pack(
'Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($raw['publicExponent']),
$raw['publicExponent'],
strlen($raw['modulus']),
$raw['modulus']
);
$source = pack(
'Na*Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($encryption),
$encryption,
strlen(self::$comment),
self::$comment,
strlen($public),
$public
);
$public = Base64::encode($public);
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
$key.= chunk_split($public, 64);
$private = pack(
'Na*Na*Na*Na*',
strlen($raw['privateExponent']),
$raw['privateExponent'],
strlen($raw['prime1']),
$raw['prime1'],
strlen($raw['prime2']),
$raw['prime2'],
strlen($raw['coefficient']),
$raw['coefficient']
);
if (empty($password) && !is_string($password)) {
$source.= pack('Na*', strlen($private), $private);
$hashkey = 'putty-private-key-file-mac-key';
} else {
$private.= Random::string(16 - (strlen($private) & 15));
$source.= pack('Na*', strlen($private), $private);
$crypto = new AES();
$crypto->setKey(static::generateSymmetricKey($password, 32));
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
$crypto->disablePadding();
$private = $crypto->encrypt($private);
$hashkey = 'putty-private-key-file-mac-key' . $password;
}
$private = Base64::encode($private);
$key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
$key.= chunk_split($private, 64);
$hash = new Hash('sha1');
$hash->setKey(sha1($hashkey, true));
$key.= 'Private-MAC: ' . Hex::encode($hash->hash($source)) . "\r\n";
return $key;
}
/**
* Convert a public key to the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @return string
*/
static function savePublicKey(BigInteger $n, BigInteger $e)
{
$n = $n->toBytes(true);
$e = $e->toBytes(true);
$key = pack(
'Na*Na*Na*',
strlen('ssh-rsa'),
'ssh-rsa',
strlen($e),
$e,
strlen($n),
$n
);
$key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" .
'Comment: "' . str_replace(array('\\', '"'), array('\\\\', '\"'), self::$comment) . "\"\r\n";
chunk_split(Base64::encode($key), 64) .
'---- END SSH2 PUBLIC KEY ----';
return $key;
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* Raw RSA Key Handler
*
* PHP version 5
*
* An array containing two \phpseclib\Math\BigInteger objects.
*
* The exponent can be indexed with any of the following:
*
* 0, e, exponent, publicExponent
*
* The modulus can be indexed with any of the following:
*
* 1, n, modulo, modulus
*
* @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 phpseclib\Math\BigInteger;
/**
* Raw RSA Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Raw
{
/**
* 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_array($key)) {
return false;
}
if (isset($key['isPublicKey']) && isset($key['modulus'])) {
if (isset($key['privateExponent']) || isset($key['publicExponent'])) {
if (!isset($key['primes'])) {
return $key;
}
if (isset($key['exponents']) && isset($key['coefficients']) && isset($key['publicExponent']) && isset($key['privateExponent'])) {
return $key;
}
}
}
$components = array('isPublicKey' => true);
switch (true) {
case isset($key['e']):
$components['publicExponent'] = $key['e'];
break;
case isset($key['exponent']):
$components['publicExponent'] = $key['exponent'];
break;
case isset($key['publicExponent']):
$components['publicExponent'] = $key['publicExponent'];
break;
case isset($key[0]):
$components['publicExponent'] = $key[0];
}
switch (true) {
case isset($key['n']):
$components['modulus'] = $key['n'];
break;
case isset($key['modulo']):
$components['modulus'] = $key['modulo'];
break;
case isset($key['modulus']):
$components['modulus'] = $key['modulus'];
break;
case isset($key[1]):
$components['modulus'] = $key[1];
}
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
}
/**
* Convert a public key to the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @return string
*/
static function savePublicKey(BigInteger $n, BigInteger $e)
{
return array('e' => clone $e, 'n' => clone $n);
}
}

View File

@ -0,0 +1,147 @@
<?php
/**
* XML Formatted RSA Key Handler
*
* More info:
*
* http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
* http://en.wikipedia.org/wiki/XML_Signature
*
* 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 phpseclib\Math\BigInteger;
/**
* XML Formatted RSA Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class XML
{
/**
* 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' => false,
'primes' => array(),
'exponents' => array(),
'coefficients' => array()
);
$use_errors = libxml_use_internal_errors(true);
$dom = new \DOMDocument();
if (!$dom->loadXML('<xml>' . $key . '</xml>')) {
return false;
}
$xpath = new \DOMXPath($dom);
$keys = array('modulus', 'exponent', 'p', 'q', 'dp', 'dq', 'inverseq', 'd');
foreach ($keys as $key) {
// $dom->getElementsByTagName($key) is case-sensitive
$temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']");
if (!$temp->length) {
continue;
}
$value = new BigInteger(Base64::decode($temp->item(0)->nodeValue), 256);
switch ($key) {
case 'modulus':
$components['modulus'] = $value;
break;
case 'exponent':
$components['publicExponent'] = $value;
break;
case 'p':
$components['primes'][1] = $value;
break;
case 'q':
$components['primes'][2] = $value;
break;
case 'dp':
$components['exponents'][1] = $value;
break;
case 'dq':
$components['exponents'][2] = $value;
break;
case 'inverseq':
$components['coefficients'][2] = $value;
break;
case 'd':
$components['privateExponent'] = $value;
}
}
libxml_use_internal_errors($use_errors);
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @param \phpseclib\Math\BigInteger $d
* @param array $primes
* @param array $exponents
* @param array $coefficients
* @param string $password optional
* @return string
*/
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
{
if (count($primes) != 2) {
return false;
}
return "<RSAKeyValue>\r\n" .
' <Modulus>' . Base64::encode($n->toBytes()) . "</Modulus>\r\n" .
' <Exponent>' . Base64::encode($e->toBytes()) . "</Exponent>\r\n" .
' <P>' . Base64::encode($primes[1]->toBytes()) . "</P>\r\n" .
' <Q>' . Base64::encode($primes[2]->toBytes()) . "</Q>\r\n" .
' <DP>' . Base64::encode($exponents[1]->toBytes()) . "</DP>\r\n" .
' <DQ>' . Base64::encode($exponents[2]->toBytes()) . "</DQ>\r\n" .
' <InverseQ>' . Base64::encode($coefficients[2]->toBytes()) . "</InverseQ>\r\n" .
' <D>' . Base64::encode($d->toBytes()) . "</D>\r\n" .
'</RSAKeyValue>';
}
/**
* Convert a public key to the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $n
* @param \phpseclib\Math\BigInteger $e
* @return string
*/
static function savePublicKey(BigInteger $n, BigInteger $e)
{
return "<RSAKeyValue>\r\n" .
' <Modulus>' . Base64::encode($n->toBytes()) . "</Modulus>\r\n" .
' <Exponent>' . Base64::encode($e->toBytes()) . "</Exponent>\r\n" .
'</RSAKeyValue>';
}
}

View File

@ -41,68 +41,22 @@ class Random
* eg. for RSA key generation.
*
* @param int $length
* @throws \RuntimeException if a symmetric cipher is needed but not loaded
* @return string
*/
static function string($length)
{
if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
try {
return \random_bytes($length);
} catch (\Throwable $e) {
// If a sufficient source of randomness is unavailable, random_bytes() will throw an
// object that implements the Throwable interface (Exception, TypeError, Error).
// We don't actually need to do anything here. The string() method should just continue
// as normal. Note, however, that if we don't have a sufficient source of randomness for
// random_bytes(), most of the other calls here will fail too, so we'll end up using
// the PHP implementation.
}
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
// method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
// ie. class_alias is a function that was introduced in PHP 5.3
if (extension_loaded('mcrypt') && function_exists('class_alias')) {
return mcrypt_create_iv($length);
}
// method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
// to quote <http://php.net/ChangeLog-5.php#5.3.4>, "possible blocking behavior". as of 5.3.4
// openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both
// call php_win32_get_random_bytes():
//
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392
//
// php_win32_get_random_bytes() is defined thusly:
//
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
//
// we're calling it, all the same, in the off chance that the mcrypt extension is not available
if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
return openssl_random_pseudo_bytes($length);
}
} else {
// method 1. the fastest
if (extension_loaded('openssl')) {
return openssl_random_pseudo_bytes($length);
}
// method 2
static $fp = true;
if ($fp === true) {
// warning's will be output unles the error suppression operator is used. errors such as
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
$fp = @fopen('/dev/urandom', 'rb');
}
if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource()
return fread($fp, $length);
}
// method 3. pretty much does the same thing as method 2 per the following url:
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
// restrictions or some such
if (extension_loaded('mcrypt')) {
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
}
try {
return \random_bytes($length);
} catch (\Exception $e) {
// random_compat will throw an Exception, which in PHP 5 does not implement Throwable
} catch (\Throwable $e) {
// If a sufficient source of randomness is unavailable, random_bytes() will throw an
// object that implements the Throwable interface (Exception, TypeError, Error).
// We don't actually need to do anything here. The string() method should just continue
// as normal. Note, however, that if we don't have a sufficient source of randomness for
// random_bytes(), most of the other calls here will fail too, so we'll end up using
// the PHP implementation.
}
// at this point we have no choice but to use a pure-PHP CSPRNG
@ -139,15 +93,14 @@ class Random
session_cache_limiter('');
session_start();
$v = $seed = $_SESSION['seed'] = pack('H*', sha1(
(isset($_SERVER) ? phpseclib_safe_serialize($_SERVER) : '') .
(isset($_POST) ? phpseclib_safe_serialize($_POST) : '') .
(isset($_GET) ? phpseclib_safe_serialize($_GET) : '') .
(isset($_COOKIE) ? phpseclib_safe_serialize($_COOKIE) : '') .
phpseclib_safe_serialize($GLOBALS) .
phpseclib_safe_serialize($_SESSION) .
phpseclib_safe_serialize($_OLD_SESSION)
));
$v = (isset($_SERVER) ? self::safe_serialize($_SERVER) : '') .
(isset($_POST) ? self::safe_serialize($_POST) : '') .
(isset($_GET) ? self::safe_serialize($_GET) : '') .
(isset($_COOKIE) ? self::safe_serialize($_COOKIE) : '') .
self::safe_serialize($GLOBALS) .
self::safe_serialize($_SESSION) .
self::safe_serialize($_OLD_SESSION);
$v = $seed = $_SESSION['seed'] = sha1($v, true);
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
}
@ -178,8 +131,8 @@ class Random
// http://tools.ietf.org/html/rfc4253#section-7.2
//
// see the is_string($crypto) part for an example of how to expand the keys
$key = pack('H*', sha1($seed . 'A'));
$iv = pack('H*', sha1($seed . 'C'));
$key = sha1($seed . 'A', true);
$iv = sha1($seed . 'C', true);
// ciphers are used as per the nist.gov link below. also, see this link:
//
@ -204,12 +157,11 @@ class Random
$crypto = new RC4();
break;
default:
user_error(__CLASS__ . ' requires at least one symmetric cipher be loaded');
return false;
throw new \RuntimeException(__CLASS__ . ' requires at least one symmetric cipher be loaded');
}
$crypto->setKey($key);
$crypto->setIV($iv);
$crypto->setKey(substr($key, 0, $crypto->getKeyLength() >> 3));
$crypto->setIV(substr($iv, 0, $crypto->getBlockLength() >> 3));
$crypto->enableContinuousBuffer();
}
@ -232,19 +184,16 @@ class Random
}
return substr($result, 0, $length);
}
}
if (!function_exists('phpseclib_safe_serialize')) {
/**
* Safely serialize variables
*
* If a class has a private __sleep() method it'll give a fatal error on PHP 5.2 and earlier.
* PHP 5.3 will emit a warning.
* If a class has a private __sleep() it'll emit a warning
*
* @param mixed $arr
* @access public
*/
function phpseclib_safe_serialize(&$arr)
static function safe_serialize(&$arr)
{
if (is_object($arr)) {
return '';
@ -261,7 +210,7 @@ if (!function_exists('phpseclib_safe_serialize')) {
foreach (array_keys($arr) as $key) {
// do not recurse on the '__phpseclib_marker' key itself, for smaller memory usage
if ($key !== '__phpseclib_marker') {
$safearr[$key] = phpseclib_safe_serialize($arr[$key]);
$safearr[$key] = self::safe_serialize($arr[$key]);
}
}
unset($arr['__phpseclib_marker']);

View File

@ -168,11 +168,26 @@ class Rijndael extends Base
*/
var $kl;
/**
* Default Constructor.
*
* @param int $mode
* @access public
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
*/
function __construct($mode)
{
if ($mode == self::MODE_STREAM) {
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
}
parent::__construct($mode);
}
/**
* Sets the key length.
*
* Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
* Valid key lengths are 128, 160, 192, 224, and 256.
*
* Note: phpseclib extends Rijndael (and AES) for using 160- and 224-bit keys but they are officially not defined
* and the most (if not all) implementations are not able using 160/224-bit keys but round/pad them up to
@ -186,49 +201,75 @@ class Rijndael extends Base
* This results then in slower encryption.
*
* @access public
* @throws \LengthException if the key length is invalid
* @param int $length
*/
function setKeyLength($length)
{
switch (true) {
case $length <= 128:
$this->key_length = 16;
break;
case $length <= 160:
$this->key_length = 20;
break;
case $length <= 192:
$this->key_length = 24;
break;
case $length <= 224:
$this->key_length = 28;
switch ($length) {
case 128:
case 160:
case 192:
case 224:
case 256:
$this->key_length = $length >> 3;
break;
default:
$this->key_length = 32;
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported');
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths
*
* @see setKeyLength()
* @access public
* @param string $key
* @throws \LengthException if the key length isn't supported
*/
function setKey($key)
{
switch (strlen($key)) {
case 16:
case 20:
case 24:
case 28:
case 32:
break;
default:
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 20, 24, 28 or 32 are supported');
}
parent::setKey($key);
}
/**
* Sets the block length
*
* Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
* Valid block lengths are 128, 160, 192, 224, and 256.
*
* @access public
* @param int $length
*/
function setBlockLength($length)
{
$length >>= 5;
if ($length > 8) {
$length = 8;
} elseif ($length < 4) {
$length = 4;
switch ($length) {
case 128:
case 160:
case 192:
case 224:
case 256:
break;
default:
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128, 160, 192, 224 or 256 bits are supported');
}
$this->Nb = $length;
$this->block_size = $length << 2;
$this->Nb = $length >> 5;
$this->block_size = $length >> 3;
$this->changed = true;
$this->_setEngine();
}

View File

@ -128,7 +128,7 @@ class TripleDES extends DES
/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
* Determines whether or not the mcrypt or OpenSSL extensions should be used.
*
* $mode could be:
*
@ -142,16 +142,14 @@ class TripleDES extends DES
*
* - \phpseclib\Crypt\Base::MODE_OFB
*
* - \phpseclib\Crypt\TripleDES::MODE_3CBC
*
* If not explicitly set, \phpseclib\Crypt\Base::MODE_CBC will be used.
* - \phpseclib\Crypt\TripleDES::MODE_3CB
*
* @see \phpseclib\Crypt\DES::__construct()
* @see \phpseclib\Crypt\Base::__construct()
* @param int $mode
* @access public
*/
function __construct($mode = Base::MODE_CBC)
function __construct($mode)
{
switch ($mode) {
// In case of self::MODE_3CBC, we init as CRYPT_DES_MODE_CBC
@ -200,10 +198,9 @@ class TripleDES extends DES
}
/**
* Sets the initialization vector. (optional)
* Sets the initialization vector.
*
* SetIV is not required when \phpseclib\Crypt\Base::MODE_ECB is being used. If not explicitly set, it'll be assumed
* to be all zero's.
* SetIV is not required when \phpseclib\Crypt\Base::MODE_ECB is being used.
*
* @see \phpseclib\Crypt\Base::setIV()
* @access public
@ -222,24 +219,23 @@ class TripleDES extends DES
/**
* Sets the key length.
*
* Valid key lengths are 64, 128 and 192
* Valid key lengths are 128 and 192 bits.
*
* If you want to use a 64-bit key use DES.php
*
* @see \phpseclib\Crypt\Base:setKeyLength()
* @access public
* @throws \LengthException if the key length is invalid
* @param int $length
*/
function setKeyLength($length)
{
$length >>= 3;
switch (true) {
case $length <= 8:
$this->key_length = 8;
break;
case $length <= 16:
$this->key_length = 16;
switch ($length) {
case 128:
case 192:
break;
default:
$this->key_length = 24;
throw new \LengthException('Key size of ' . $length . ' bits is not supported by this algorithm. Only keys of sizes 128 or 192 bits are supported');
}
parent::setKeyLength($length);
@ -248,36 +244,38 @@ class TripleDES extends DES
/**
* Sets the key.
*
* Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
* 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
* Triple DES can use 128-bit (eg. strlen($key) == 16) or 192-bit (eg. strlen($key) == 24) keys.
*
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
*
* If the key is not explicitly set, it'll be assumed to be all null bytes.
*
* @access public
* @see \phpseclib\Crypt\DES::setKey()
* @see \phpseclib\Crypt\Base::setKey()
* @throws \LengthException if the key length is invalid
* @param string $key
*/
function setKey($key)
{
$length = $this->explicit_key_length ? $this->key_length : strlen($key);
if ($length > 8) {
$key = str_pad(substr($key, 0, 24), 24, chr(0));
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
// http://php.net/function.mcrypt-encrypt#47973
$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
} else {
$key = str_pad($key, 8, chr(0));
if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
throw new \LengthException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
}
parent::setKey($key);
// And in case of self::MODE_3CBC:
// if key <= 64bits we not need the 3 $des to work,
// because we will then act as regular DES-CBC with just a <= 64bit key.
// So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des.
if ($this->mode_3cbc && $length > 8) {
switch (strlen($key)) {
case 16:
$key.= substr($key, 0, 8);
case 24:
break;
default:
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16 or 24 are supported');
}
// copied from Base::setKey()
$this->key = $key;
$this->key_length = strlen($key);
$this->changed = true;
$this->_setEngine();
if ($this->mode_3cbc) {
$this->des[0]->setKey(substr($key, 0, 8));
$this->des[1]->setKey(substr($key, 8, 8));
$this->des[2]->setKey(substr($key, 16, 8));

View File

@ -368,6 +368,22 @@ class Twofish extends Base
*/
var $key_length = 16;
/**
* Default Constructor.
*
* @param int $mode
* @access public
* @throws \InvalidArgumentException if an invalid / unsupported mode is provided
*/
function __construct($mode)
{
if ($mode == self::MODE_STREAM) {
throw new \InvalidArgumentException('Block ciphers cannot be ran in stream mode');
}
parent::__construct($mode);
}
/**
* Sets the key length.
*
@ -378,20 +394,42 @@ class Twofish extends Base
*/
function setKeyLength($length)
{
switch (true) {
case $length <= 128:
$this->key_length = 16;
break;
case $length <= 192:
$this->key_length = 24;
switch ($length) {
case 128:
case 192:
case 256:
break;
default:
$this->key_length = 32;
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
}
parent::setKeyLength($length);
}
/**
* Sets the key.
*
* Rijndael supports five different key lengths
*
* @see setKeyLength()
* @access public
* @param string $key
* @throws \LengthException if the key length isn't supported
*/
function setKey($key)
{
switch (strlen($key)) {
case 16:
case 24:
case 32:
break;
default:
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported');
}
parent::setKey($key);
}
/**
* Setup the key (expansion)
*

View File

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

View File

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

View File

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

View File

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

View File

@ -23,6 +23,7 @@
namespace phpseclib\File;
use ParagonIE\ConstantTime\Base64;
use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
@ -224,14 +225,15 @@ class ASN1
*
* @param string $encoded
* @param int $start
* @param int $encoded_pos
* @return array
* @access private
*/
function _decode_ber($encoded, $start = 0)
function _decode_ber($encoded, $start = 0, $encoded_pos = 0)
{
$current = array('start' => $start);
$type = ord($this->_string_shift($encoded));
$type = ord($encoded[$encoded_pos++]);
$start++;
$constructed = ($type >> 5) & 1;
@ -243,23 +245,24 @@ class ASN1
do {
$loop = ord($encoded[0]) >> 7;
$tag <<= 7;
$tag |= ord($this->_string_shift($encoded)) & 0x7F;
$tag |= ord($encoded[$encoded_pos++]) & 0x7F;
$start++;
} while ($loop);
}
// Length, as discussed in paragraph 8.1.3 of X.690-0207.pdf#page=13
$length = ord($this->_string_shift($encoded));
$length = ord($encoded[$encoded_pos++]);
$start++;
if ($length == 0x80) { // indefinite length
// "[A sender shall] use the indefinite form (see 8.1.3.6) if the encoding is constructed and is not all
// immediately available." -- paragraph 8.1.3.2.c
$length = strlen($encoded);
$length = strlen($encoded) - $encoded_pos;
} elseif ($length & 0x80) { // definite length, long form
// technically, the long form of the length can be represented by up to 126 octets (bytes), but we'll only
// support it up to four.
$length&= 0x7F;
$temp = $this->_string_shift($encoded, $length);
$temp = substr($encoded, $encoded_pos, $length);
$encoded_pos += $length;
// tags of indefinte length don't really have a header length; this length includes the tag
$current+= array('headerlength' => $length + 2);
$start+= $length;
@ -268,11 +271,12 @@ class ASN1
$current+= array('headerlength' => 2);
}
if ($length > strlen($encoded)) {
if ($length > (strlen($encoded) - $encoded_pos)) {
return false;
}
$content = $this->_string_shift($encoded, $length);
$content = substr($encoded, $encoded_pos, $length);
$content_pos = 0;
// at this point $length can be overwritten. it's only accurate for definite length things as is
@ -305,7 +309,7 @@ class ASN1
$temp = $this->_decode_ber($content, $start);
$length = $temp['length'];
// end-of-content octets - see paragraph 8.1.5
if (substr($content, $length, 2) == "\0\0") {
if (substr($content, $content_pos + $length, 2) == "\0\0") {
$length+= 2;
$start+= $length;
$newcontent[] = $temp;
@ -314,7 +318,7 @@ class ASN1
$start+= $length;
$remainingLength-= $length;
$newcontent[] = $temp;
$this->_string_shift($content, $length);
$content_pos += $length;
}
return array(
@ -338,11 +342,11 @@ class ASN1
//if (strlen($content) != 1) {
// return false;
//}
$current['content'] = (bool) ord($content[0]);
$current['content'] = (bool) ord($content[$content_pos]);
break;
case self::TYPE_INTEGER:
case self::TYPE_ENUMERATED:
$current['content'] = new BigInteger($content, -256);
$current['content'] = new BigInteger(substr($content, $content_pos), -256);
break;
case self::TYPE_REAL: // not currently supported
return false;
@ -351,10 +355,10 @@ class ASN1
// the number of unused bits in the final subsequent octet. The number shall be in the range zero to
// seven.
if (!$constructed) {
$current['content'] = $content;
$current['content'] = substr($content, $content_pos);
} else {
$temp = $this->_decode_ber($content, $start);
$length-= strlen($content);
$temp = $this->_decode_ber($content, $start, $content_pos);
$length-= (strlen($content) - $content_pos);
$last = count($temp) - 1;
for ($i = 0; $i < $last; $i++) {
// all subtags should be bit strings
@ -372,13 +376,13 @@ class ASN1
break;
case self::TYPE_OCTET_STRING:
if (!$constructed) {
$current['content'] = $content;
$current['content'] = substr($content, $content_pos);
} else {
$current['content'] = '';
$length = 0;
while (substr($content, 0, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start);
$this->_string_shift($content, $temp['length']);
while (substr($content, $content_pos, 2) != "\0\0") {
$temp = $this->_decode_ber($content, $length + $start, $content_pos);
$content_pos += $temp['length'];
// all subtags should be octet strings
//if ($temp['type'] != self::TYPE_OCTET_STRING) {
// return false;
@ -386,7 +390,7 @@ class ASN1
$current['content'].= $temp['content'];
$length+= $temp['length'];
}
if (substr($content, 0, 2) == "\0\0") {
if (substr($content, $content_pos, 2) == "\0\0") {
$length+= 2; // +2 for the EOC
}
}
@ -401,26 +405,28 @@ class ASN1
case self::TYPE_SET:
$offset = 0;
$current['content'] = array();
while (strlen($content)) {
$content_len = strlen($content);
while ($content_pos < $content_len) {
// if indefinite length construction was used and we have an end-of-content string next
// see paragraphs 8.1.1.3, 8.1.3.2, 8.1.3.6, 8.1.5, and (for an example) 8.6.4.2
if (!isset($current['headerlength']) && substr($content, 0, 2) == "\0\0") {
if (!isset($current['headerlength']) && substr($content, $content_pos, 2) == "\0\0") {
$length = $offset + 2; // +2 for the EOC
break 2;
}
$temp = $this->_decode_ber($content, $start + $offset);
$this->_string_shift($content, $temp['length']);
$temp = $this->_decode_ber($content, $start + $offset, $content_pos);
$content_pos += $temp['length'];
$current['content'][] = $temp;
$offset+= $temp['length'];
}
break;
case self::TYPE_OBJECT_IDENTIFIER:
$temp = ord($this->_string_shift($content));
$temp = ord($content[$content_pos++]);
$current['content'] = sprintf('%d.%d', floor($temp / 40), $temp % 40);
$valuen = 0;
// process septets
while (strlen($content)) {
$temp = ord($this->_string_shift($content));
$content_len = strlen($content);
while ($content_pos < $content_len) {
$temp = ord($content[$content_pos++]);
$valuen <<= 7;
$valuen |= $temp & 0x7F;
if (~$temp & 0x80) {
@ -461,11 +467,11 @@ class ASN1
case self::TYPE_UTF8_STRING:
// ????
case self::TYPE_BMP_STRING:
$current['content'] = $content;
$current['content'] = substr($content, $content_pos);
break;
case self::TYPE_UTC_TIME:
case self::TYPE_GENERALIZED_TIME:
$current['content'] = $this->_decodeTime($content, $tag);
$current['content'] = $this->_decodeTime(substr($content, $content_pos), $tag);
default:
}
@ -497,7 +503,7 @@ class ASN1
switch (true) {
case $mapping['type'] == self::TYPE_ANY:
$intype = $decoded['type'];
if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || ($this->encoded[$decoded['start']] & 0x20)) {
if (isset($decoded['constant']) || !isset($this->ANYmap[$intype]) || (ord($this->encoded[$decoded['start']]) & 0x20)) {
return new Element(substr($this->encoded, $decoded['start'], $decoded['length']));
}
$inmap = $this->ANYmap[$intype];
@ -733,7 +739,7 @@ class ASN1
return $values;
}
case self::TYPE_OCTET_STRING:
return base64_encode($decoded['content']);
return Base64::encode($decoded['content']);
case self::TYPE_NULL:
return '';
case self::TYPE_BOOLEAN:
@ -793,6 +799,7 @@ class ASN1
* @param string $mapping
* @param int $idx
* @return string
* @throws \RuntimeException if the input has an error in it
* @access private
*/
function _encode_der($source, $mapping, $idx = null, $special = array())
@ -819,10 +826,10 @@ class ASN1
case self::TYPE_SET: // Children order is not important, thus process in sequence.
case self::TYPE_SEQUENCE:
$tag|= 0x20; // set the constructed bit
$value = '';
// ignore the min and max
if (isset($mapping['min']) && isset($mapping['max'])) {
$value = array();
$child = $mapping['children'];
foreach ($source as $content) {
@ -830,11 +837,21 @@ class ASN1
if ($temp === false) {
return false;
}
$value.= $temp;
$value[]= $temp;
}
/* "The encodings of the component values of a set-of value shall appear in ascending order, the encodings being compared
as octet strings with the shorter components being padded at their trailing end with 0-octets.
NOTE - The padding octets are for comparison purposes only and do not appear in the encodings."
-- sec 11.6 of http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf */
if ($mapping['type'] == self::TYPE_SET) {
sort($value);
}
$value = implode($value, '');
break;
}
$value = '';
foreach ($mapping['children'] as $key => $child) {
if (!array_key_exists($key, $source)) {
if (!isset($child['optional'])) {
@ -980,12 +997,12 @@ class ASN1
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#page=16 */
$value = base64_decode($source);
$value = Base64::decode($source);
break;
case self::TYPE_OBJECT_IDENTIFIER:
$oid = preg_match('#(?:\d+\.)+#', $source) ? $source : array_search($source, $this->oids);
if ($oid === false) {
user_error('Invalid OID');
throw new \RuntimeException('Invalid OID');
return false;
}
$value = '';
@ -1038,7 +1055,7 @@ class ASN1
$filters = $filters[$part];
}
if ($filters === false) {
user_error('No filters defined for ' . implode('/', $loc));
throw new \RuntimeException('No filters defined for ' . implode('/', $loc));
return false;
}
return $this->_encode_der($source, $filters + $mapping, null, $special);
@ -1062,7 +1079,7 @@ class ASN1
$value = $source ? "\xFF" : "\x00";
break;
default:
user_error('Mapping provides no type definition for ' . implode('/', $this->location));
throw new \RuntimeException('Mapping provides no type definition for ' . implode('/', $this->location));
return false;
}

View File

@ -26,9 +26,12 @@
namespace phpseclib\File;
use ParagonIE\ConstantTime\Base64;
use ParagonIE\ConstantTime\Hex;
use phpseclib\Crypt\Hash;
use phpseclib\Crypt\Random;
use phpseclib\Crypt\RSA;
use phpseclib\Exception\UnsupportedAlgorithmException;
use phpseclib\File\ASN1\Element;
use phpseclib\Math\BigInteger;
@ -144,6 +147,7 @@ class X509
var $CertificatePolicies;
var $AuthorityInfoAccessSyntax;
var $SubjectAltName;
var $SubjectDirectoryAttributes;
var $PrivateKeyUsagePeriod;
var $IssuerAltName;
var $PolicyMappings;
@ -167,6 +171,14 @@ class X509
var $SignedPublicKeyAndChallenge;
/**#@-*/
/**#@+
* ASN.1 syntax for various DN attributes
*
* @access private
*/
var $PostalAddress;
/**#@-*/
/**
* ASN.1 syntax for Certificate Signing Requests (RFC2986)
*
@ -1069,6 +1081,13 @@ class X509
)
);
$this->SubjectDirectoryAttributes = array(
'type' => ASN1::TYPE_SEQUENCE,
'min' => 1,
'max' => -1,
'children' => $Attribute
);
// adapted from <http://tools.ietf.org/html/rfc2986>
$Attributes = array(
@ -1236,6 +1255,14 @@ class X509
)
);
$this->PostalAddress = array(
'type' => ASN1::TYPE_SEQUENCE,
'optional' => true,
'min' => 1,
'max' => -1,
'children' => $this->DirectoryString
);
// OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
$this->oids = array(
'1.3.6.1.5.5.7' => 'id-pkix',
@ -1270,6 +1297,7 @@ class X509
'2.5.4.9' => 'id-at-streetAddress',
'2.5.4.45' => 'id-at-uniqueIdentifier',
'2.5.4.72' => 'id-at-role',
'2.5.4.16' => 'id-at-postalAddress',
'0.9.2342.19200300.100.1.25' => 'id-domainComponent',
'1.2.840.113549.1.9' => 'pkcs-9',
@ -1459,7 +1487,11 @@ class X509
$this->signatureSubject = substr($cert, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
$this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
if ($this->_isSubArrayValid($x509, 'tbsCertificate/extensions')) {
$this->_mapInExtensions($x509, 'tbsCertificate/extensions', $asn1);
}
$this->_mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence', $asn1);
$this->_mapInDNs($x509, 'tbsCertificate/subject/rdnSequence', $asn1);
$key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
$key = $this->_reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
@ -1496,7 +1528,7 @@ class X509
switch ($algorithm) {
case 'rsaEncryption':
$cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
= Base64::encode("\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'])));
/* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
-- https://tools.ietf.org/html/rfc3279#section-2.3.1
@ -1536,6 +1568,8 @@ class X509
$asn1->loadFilters($filters);
$this->_mapOutExtensions($cert, 'tbsCertificate/extensions', $asn1);
$this->_mapOutDNs($cert, 'tbsCertificate/issuer/rdnSequence', $asn1);
$this->_mapOutDNs($cert, 'tbsCertificate/subject/rdnSequence', $asn1);
$cert = $asn1->encodeDER($cert, $this->Certificate);
@ -1544,7 +1578,7 @@ class X509
return $cert;
// case self::FORMAT_PEM:
default:
return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(base64_encode($cert), 64) . '-----END CERTIFICATE-----';
return "-----BEGIN CERTIFICATE-----\r\n" . chunk_split(Base64::encode($cert), 64) . '-----END CERTIFICATE-----';
}
}
@ -1559,13 +1593,13 @@ class X509
*/
function _mapInExtensions(&$root, $path, $asn1)
{
$extensions = &$this->_subArray($root, $path);
$extensions = &$this->_subArrayUnchecked($root, $path);
if (is_array($extensions)) {
if ($extensions) {
for ($i = 0; $i < count($extensions); $i++) {
$id = $extensions[$i]['extnId'];
$value = &$extensions[$i]['extnValue'];
$value = base64_decode($value);
$value = Base64::decode($value);
$decoded = $asn1->decodeBER($value);
/* [extnValue] contains the DER encoding of an ASN.1 value
corresponding to the extension type identified by extnID */
@ -1592,7 +1626,7 @@ class X509
}
}
} else {
$value = base64_encode($value);
$value = Base64::encode($value);
}
}
}
@ -1653,12 +1687,12 @@ class X509
$map = $this->_getMapping($id);
if (is_bool($map)) {
if (!$map) {
user_error($id . ' is not a currently supported extension');
//user_error($id . ' is not a currently supported extension');
unset($extensions[$i]);
}
} else {
$temp = $asn1->encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP')));
$value = base64_encode($temp);
$value = Base64::encode($temp);
}
}
}
@ -1693,11 +1727,11 @@ class X509
if ($mapped !== false) {
$values[$j] = $mapped;
}
if ($id == 'pkcs-9-at-extensionRequest') {
if ($id == 'pkcs-9-at-extensionRequest' && $this->_isSubArrayValid($values, $j)) {
$this->_mapInExtensions($values, $j, $asn1);
}
} elseif ($map) {
$values[$j] = base64_encode($value);
$values[$j] = Base64::encode($value);
}
}
}
@ -1726,7 +1760,7 @@ class X509
$id = $attributes[$i]['type'];
$map = $this->_getMapping($id);
if ($map === false) {
user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
//user_error($id . ' is not a currently supported attribute', E_USER_NOTICE);
unset($attributes[$i]);
} elseif (is_array($attributes[$i]['value'])) {
$values = &$attributes[$i]['value'];
@ -1748,6 +1782,68 @@ class X509
}
}
/**
* Map DN values from ANY type to DN-specific internal
* format.
*
* @param array ref $root
* @param string $path
* @param object $asn1
* @access private
*/
function _mapInDNs(&$root, $path, $asn1)
{
$dns = &$this->_subArray($root, $path);
if (is_array($dns)) {
for ($i = 0; $i < count($dns); $i++) {
for ($j = 0; $j < count($dns[$i]); $j++) {
$type = $dns[$i][$j]['type'];
$value = &$dns[$i][$j]['value'];
if (is_object($value) && $value instanceof Element) {
$map = $this->_getMapping($type);
if (!is_bool($map)) {
$decoded = $asn1->decodeBER($value);
$value = $asn1->asn1map($decoded[0], $map);
}
}
}
}
}
}
/**
* Map DN values from DN-specific internal format to
* ANY type.
*
* @param array ref $root
* @param string $path
* @param object $asn1
* @access private
*/
function _mapOutDNs(&$root, $path, $asn1)
{
$dns = &$this->_subArray($root, $path);
if (is_array($dns)) {
$size = count($dns);
for ($i = 0; $i < $size; $i++) {
for ($j = 0; $j < count($dns[$i]); $j++) {
$type = $dns[$i][$j]['type'];
$value = &$dns[$i][$j]['value'];
if (is_object($value) && $value instanceof Element) {
continue;
}
$map = $this->_getMapping($type);
if (!is_bool($map)) {
$value = new Element($asn1->encodeDER($value, $map));
}
}
}
}
}
/**
* Associate an extension ID to an extension mapping
*
@ -1780,6 +1876,8 @@ class X509
return $this->AuthorityInfoAccessSyntax;
case 'id-ce-subjectAltName':
return $this->SubjectAltName;
case 'id-ce-subjectDirectoryAttributes':
return $this->SubjectDirectoryAttributes;
case 'id-ce-privateKeyUsagePeriod':
return $this->PrivateKeyUsagePeriod;
case 'id-ce-issuerAltName':
@ -1839,6 +1937,8 @@ class X509
return $this->CertificateIssuer;
case 'id-ce-holdInstructionCode':
return $this->HoldInstructionCode;
case 'id-at-postalAddress':
return $this->PostalAddress;
}
return false;
@ -2030,14 +2130,16 @@ class X509
switch (true) {
case isset($this->currentCert['tbsCertificate']):
// self-signed cert
if ($this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']) {
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
switch (true) {
case !is_array($authorityKey):
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $this->currentCert; // working cert
}
switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $this->currentCert['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getIssuerDN(self::DN_STRING) === $this->getDN(self::DN_STRING):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier');
switch (true) {
case !is_array($authorityKey):
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $this->currentCert; // working cert
}
}
if (!empty($this->CAs)) {
@ -2045,15 +2147,17 @@ class X509
// even if the cert is a self-signed one we still want to see if it's a CA;
// if not, we'll conditionally return an error
$ca = $this->CAs[$i];
if ($this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']) {
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $ca; // working cert
break 2;
}
switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertificate']['issuer'] === $ca['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertificate']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $ca; // working cert
break 3;
}
}
}
if (count($this->CAs) == $i && $caonly) {
@ -2066,7 +2170,7 @@ class X509
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
substr(Base64::decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['certificationRequestInfo']):
@ -2074,7 +2178,7 @@ class X509
$this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'],
$this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
substr(Base64::decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['publicKeyAndChallenge']):
@ -2082,22 +2186,24 @@ class X509
$this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'],
$this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
substr(Base64::decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
case isset($this->currentCert['tbsCertList']):
if (!empty($this->CAs)) {
for ($i = 0; $i < count($this->CAs); $i++) {
$ca = $this->CAs[$i];
if ($this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']) {
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $ca; // working cert
break 2;
}
switch (true) {
case !defined('FILE_X509_IGNORE_TYPE') && $this->currentCert['tbsCertList']['issuer'] === $ca['tbsCertificate']['subject']:
case defined('FILE_X509_IGNORE_TYPE') && $this->getDN(self::DN_STRING, $this->currentCert['tbsCertList']['issuer']) === $this->getDN(self::DN_STRING, $ca['tbsCertificate']['subject']):
$authorityKey = $this->getExtension('id-ce-authorityKeyIdentifier');
$subjectKeyID = $this->getExtension('id-ce-subjectKeyIdentifier', $ca);
switch (true) {
case !is_array($authorityKey):
case is_array($authorityKey) && isset($authorityKey['keyIdentifier']) && $authorityKey['keyIdentifier'] === $subjectKeyID:
$signingCert = $ca; // working cert
break 3;
}
}
}
}
@ -2108,7 +2214,7 @@ class X509
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'],
$signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'],
$this->currentCert['signatureAlgorithm']['algorithm'],
substr(base64_decode($this->currentCert['signature']), 1),
substr(Base64::decode($this->currentCert['signature']), 1),
$this->signatureSubject
);
default:
@ -2119,7 +2225,8 @@ class X509
/**
* Validates a signature
*
* Returns true if the signature is verified, false if it is not correct or null on error
* Returns true if the signature is verified and false if it is not correct.
* If the algorithms are unsupposed an exception is thrown.
*
* @param string $publicKeyAlgorithm
* @param string $publicKey
@ -2127,14 +2234,15 @@ class X509
* @param string $signature
* @param string $signatureSubject
* @access private
* @return int
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
* @return bool
*/
function _validateSignature($publicKeyAlgorithm, $publicKey, $signatureAlgorithm, $signature, $signatureSubject)
{
switch ($publicKeyAlgorithm) {
case 'rsaEncryption':
$rsa = new RSA();
$rsa->loadKey($publicKey);
$rsa->load($publicKey);
switch ($signatureAlgorithm) {
case 'md2WithRSAEncryption':
@ -2145,17 +2253,16 @@ class X509
case 'sha384WithRSAEncryption':
case 'sha512WithRSAEncryption':
$rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
if (!@$rsa->verify($signatureSubject, $signature)) {
if (!@$rsa->verify($signatureSubject, $signature, RSA::PADDING_PKCS1)) {
return false;
}
break;
default:
return null;
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
}
break;
default:
return null;
throw new UnsupportedAlgorithmException('Public key algorithm unsupported');
}
return true;
@ -2180,7 +2287,7 @@ class X509
// subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
// in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
// uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
chunk_split(base64_encode(substr(base64_decode($key), 1)), 64) .
chunk_split(Base64::encode(substr(Base64::decode($key), 1)), 64) .
'-----END RSA PUBLIC KEY-----';
default:
return $key;
@ -2198,7 +2305,7 @@ class X509
*/
function _decodeIP($ip)
{
return inet_ntop(base64_decode($ip));
return inet_ntop(Base64::decode($ip));
}
/**
@ -2212,7 +2319,7 @@ class X509
*/
function _encodeIP($ip)
{
return base64_encode(inet_pton($ip));
return Base64::encode(inet_pton($ip));
}
/**
@ -2299,6 +2406,9 @@ class X509
case 'uniqueidentifier':
case 'x500uniqueidentifier':
return 'id-at-uniqueIdentifier';
case 'postaladdress':
case 'id-at-postaladdress':
return 'id-at-postalAddress';
default:
return false;
}
@ -2388,25 +2498,38 @@ class X509
return false;
}
$asn1 = new ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
$dn = $dn['rdnSequence'];
$result = array();
$asn1 = new ASN1();
for ($i = 0; $i < count($dn); $i++) {
if ($dn[$i][0]['type'] == $propName) {
$v = $dn[$i][0]['value'];
if (!$withType && is_array($v)) {
foreach ($v as $type => $s) {
$type = array_search($type, $asn1->ANYmap, true);
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
$s = $asn1->convert($s, $type);
if ($s !== false) {
$v = $s;
break;
if (!$withType) {
if (is_array($v)) {
foreach ($v as $type => $s) {
$type = array_search($type, $asn1->ANYmap, true);
if ($type !== false && isset($asn1->stringTypeSize[$type])) {
$s = $asn1->convert($s, $type);
if ($s !== false) {
$v = $s;
break;
}
}
}
}
if (is_array($v)) {
$v = array_pop($v); // Always strip data type.
if (is_array($v)) {
$v = array_pop($v); // Always strip data type.
}
} elseif (is_object($v) && $v instanceof Element) {
$map = $this->_getMapping($propName);
if (!is_bool($map)) {
$decoded = $asn1->decodeBER($v);
$v = $asn1->asn1map($decoded[0], $map);
}
}
}
$result[] = $v;
@ -2447,7 +2570,7 @@ class X509
}
// handles everything else
$results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
$results = preg_split('#((?:^|, *|/)(?:C=|O=|OU=|CN=|L=|ST=|SN=|postalCode=|streetAddress=|emailAddress=|serialNumber=|organizationalUnitName=|title=|description=|role=|x500UniqueIdentifier=|postalAddress=))#', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
for ($i = 1; $i < count($results); $i+=2) {
$prop = trim($results[$i], ', =/');
$value = $results[$i + 1];
@ -2482,33 +2605,19 @@ class X509
$filters = array();
$filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
return $asn1->encodeDER($dn, $this->Name);
case self::DN_OPENSSL:
$dn = $this->getDN(self::DN_STRING, $dn);
if ($dn === false) {
return false;
}
$attrs = preg_split('#((?:^|, *|/)[a-z][a-z0-9]*=)#i', $dn, -1, PREG_SPLIT_DELIM_CAPTURE);
$dn = array();
for ($i = 1; $i < count($attrs); $i += 2) {
$prop = trim($attrs[$i], ', =/');
$value = $attrs[$i + 1];
if (!isset($dn[$prop])) {
$dn[$prop] = $value;
} else {
$dn[$prop] = array_merge((array) $dn[$prop], array($value));
}
}
return $dn;
case self::DN_CANON:
// No SEQUENCE around RDNs and all string values normalized as
// trimmed lowercase UTF-8 with all spacing as one blank.
// trimmed lowercase UTF-8 with all spacing as one blank.
// constructed RDNs will not be canonicalized
$asn1 = new ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$result = '';
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
foreach ($dn['rdnSequence'] as $rdn) {
foreach ($rdn as $i => $attr) {
$attr = &$rdn[$i];
@ -2534,13 +2643,21 @@ class X509
$hash = new Hash('sha1');
$hash = $hash->hash($dn);
extract(unpack('Vhash', $hash));
return strtolower(bin2hex(pack('N', $hash)));
return strtolower(Hex::encode(pack('N', $hash)));
}
// Default is to return a string.
$start = true;
$output = '';
$result = array();
$asn1 = new ASN1();
$asn1->loadOIDs($this->oids);
$filters = array();
$filters['rdnSequence']['value'] = array('type' => ASN1::TYPE_UTF8_STRING);
$asn1->loadFilters($filters);
$this->_mapOutDNs($dn, 'rdnSequence', $asn1);
foreach ($dn['rdnSequence'] as $field) {
$prop = $field[0]['type'];
$value = $field[0]['value'];
@ -2548,33 +2665,37 @@ class X509
$delim = ', ';
switch ($prop) {
case 'id-at-countryName':
$desc = 'C=';
$desc = 'C';
break;
case 'id-at-stateOrProvinceName':
$desc = 'ST=';
$desc = 'ST';
break;
case 'id-at-organizationName':
$desc = 'O=';
$desc = 'O';
break;
case 'id-at-organizationalUnitName':
$desc = 'OU=';
$desc = 'OU';
break;
case 'id-at-commonName':
$desc = 'CN=';
$desc = 'CN';
break;
case 'id-at-localityName':
$desc = 'L=';
$desc = 'L';
break;
case 'id-at-surname':
$desc = 'SN=';
$desc = 'SN';
break;
case 'id-at-uniqueIdentifier':
$delim = '/';
$desc = 'x500UniqueIdentifier=';
$desc = 'x500UniqueIdentifier';
break;
case 'id-at-postalAddress':
$delim = '/';
$desc = 'postalAddress';
break;
default:
$delim = '/';
$desc = preg_replace('#.+-([^-]+)$#', '$1', $prop) . '=';
$desc = preg_replace('#.+-([^-]+)$#', '$1', $prop);
}
if (!$start) {
@ -2594,12 +2715,18 @@ class X509
if (is_array($value)) {
$value = array_pop($value); // Always strip data type.
}
} elseif (is_object($value) && $value instanceof Element) {
$callback = create_function('$x', 'return "\x" . bin2hex($x[0]);');
$value = strtoupper(preg_replace_callback('#[^\x20-\x7E]#', $callback, $value->element));
}
$output.= $desc . $value;
$output.= $desc . '=' . $value;
$result[$desc] = isset($result[$desc]) ?
array_merge((array) $dn[$prop], array($value)) :
$value;
$start = false;
}
return $output;
return $format == self::DN_OPENSSL ? $result : $output;
}
/**
@ -2810,7 +2937,7 @@ class X509
switch ($keyinfo['algorithm']['algorithm']) {
case 'rsaEncryption':
$publicKey = new RSA();
$publicKey->loadKey($key);
$publicKey->load($key);
$publicKey->setPublicKey();
break;
default:
@ -2874,8 +3001,10 @@ class X509
return false;
}
$this->dn = $csr['certificationRequestInfo']['subject'];
$this->_mapInAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
$this->_mapInDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
$this->dn = $csr['certificationRequestInfo']['subject'];
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
@ -2886,7 +3015,7 @@ class X509
switch ($algorithm) {
case 'rsaEncryption':
$this->publicKey = new RSA();
$this->publicKey->loadKey($key);
$this->publicKey->load($key);
$this->publicKey->setPublicKey();
break;
default:
@ -2921,7 +3050,10 @@ class X509
switch ($algorithm) {
case 'rsaEncryption':
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
= Base64::encode("\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'])));
$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
$csr['signatureAlgorithm']['parameters'] = null;
$csr['certificationRequestInfo']['signature']['parameters'] = null;
}
}
@ -2935,6 +3067,7 @@ class X509
$asn1->loadFilters($filters);
$this->_mapOutDNs($csr, 'certificationRequestInfo/subject/rdnSequence', $asn1);
$this->_mapOutAttributes($csr, 'certificationRequestInfo/attributes', $asn1);
$csr = $asn1->encodeDER($csr, $this->CertificationRequest);
@ -2943,7 +3076,7 @@ class X509
return $csr;
// case self::FORMAT_PEM:
default:
return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(base64_encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
return "-----BEGIN CERTIFICATE REQUEST-----\r\n" . chunk_split(Base64::encode($csr), 64) . '-----END CERTIFICATE REQUEST-----';
}
}
@ -2974,7 +3107,7 @@ class X509
// OpenSSL produces SPKAC's that are preceeded by the string SPKAC=
$temp = preg_replace('#(?:SPKAC=)|[ \r\n\\\]#', '', $spkac);
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false;
if ($temp != false) {
$spkac = $temp;
}
@ -3009,7 +3142,7 @@ class X509
switch ($algorithm) {
case 'rsaEncryption':
$this->publicKey = new RSA();
$this->publicKey->loadKey($key);
$this->publicKey->load($key);
$this->publicKey->setPublicKey();
break;
default:
@ -3045,7 +3178,7 @@ class X509
switch ($algorithm) {
case 'rsaEncryption':
$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
= base64_encode("\0" . base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
= Base64::encode("\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'])));
}
}
@ -3061,7 +3194,7 @@ class X509
default:
// OpenSSL's implementation of SPKAC requires the SPKAC be preceeded by SPKAC= and since there are pretty much
// no other SPKAC decoders phpseclib will use that same format
return 'SPKAC=' . base64_encode($spkac);
return 'SPKAC=' . Base64::encode($spkac);
}
}
@ -3112,11 +3245,19 @@ class X509
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
$this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
$rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
if (is_array($rclist)) {
foreach ($rclist as $i => $extension) {
$this->_mapInExtensions($rclist, "$i/crlEntryExtensions", $asn1);
$this->_mapInDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
if ($this->_isSubArrayValid($crl, 'tbsCertList/crlExtensions')) {
$this->_mapInExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
}
if ($this->_isSubArrayValid($crl, 'tbsCertList/revokedCertificates')) {
$rclist_ref = &$this->_subArrayUnchecked($crl, 'tbsCertList/revokedCertificates');
if ($rclist_ref) {
$rclist = $crl['tbsCertList']['revokedCertificates'];
foreach ($rclist as $i => $extension) {
if ($this->_isSubArrayValid($rclist, "$i/crlEntryExtensions", $asn1)) {
$this->_mapInExtensions($rclist_ref, "$i/crlEntryExtensions", $asn1);
}
}
}
}
@ -3164,6 +3305,7 @@ class X509
$asn1->loadFilters($filters);
$this->_mapOutDNs($crl, 'tbsCertList/issuer/rdnSequence', $asn1);
$this->_mapOutExtensions($crl, 'tbsCertList/crlExtensions', $asn1);
$rclist = &$this->_subArray($crl, 'tbsCertList/revokedCertificates');
if (is_array($rclist)) {
@ -3179,7 +3321,7 @@ class X509
return $crl;
// case self::FORMAT_PEM:
default:
return "-----BEGIN X509 CRL-----\r\n" . chunk_split(base64_encode($crl), 64) . '-----END X509 CRL-----';
return "-----BEGIN X509 CRL-----\r\n" . chunk_split(Base64::encode($crl), 64) . '-----END X509 CRL-----';
}
}
@ -3218,7 +3360,7 @@ class X509
* @access public
* @return mixed
*/
function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
function sign($issuer, $subject, $signatureAlgorithm = 'sha256WithRSAEncryption')
{
if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
return false;
@ -3371,7 +3513,7 @@ class X509
);
if (!isset($subject->currentKeyIdentifier)) {
$this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
$this->setExtension('id-ce-subjectKeyIdentifier', Base64::encode($this->computeKeyIdentifier($this->currentCert)), false, false);
}
}
@ -3404,7 +3546,7 @@ class X509
$origPublicKey = $this->publicKey;
$class = get_class($this->privateKey);
$this->publicKey = new $class();
$this->publicKey->loadKey($this->privateKey->getPublicKey());
$this->publicKey->load($this->privateKey->getPublicKey());
$this->publicKey->setPublicKey();
if (!($publicKey = $this->_formatSubjectPublicKey())) {
return false;
@ -3462,7 +3604,7 @@ class X509
$origPublicKey = $this->publicKey;
$class = get_class($this->privateKey);
$this->publicKey = new $class();
$this->publicKey->loadKey($this->privateKey->getPublicKey());
$this->publicKey->load($this->privateKey->getPublicKey());
$this->publicKey->setPublicKey();
$publicKey = $this->_formatSubjectPublicKey();
if (!$publicKey) {
@ -3650,6 +3792,7 @@ class X509
* @param \phpseclib\File\X509 $subject
* @param string $signatureAlgorithm
* @access public
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
* @return mixed
*/
function _sign($key, $signatureAlgorithm)
@ -3664,14 +3807,15 @@ class X509
case 'sha384WithRSAEncryption':
case 'sha512WithRSAEncryption':
$key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
$key->setSignatureMode(RSA::SIGNATURE_PKCS1);
$this->currentCert['signature'] = base64_encode("\0" . $key->sign($this->signatureSubject));
$this->currentCert['signature'] = Base64::encode("\0" . $key->sign($this->signatureSubject, RSA::PADDING_PKCS1));
return $this->currentCert;
default:
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
}
}
return false;
throw new UnsupportedAlgorithmException('Unsupported public key algorithm');
}
/**
@ -3732,6 +3876,74 @@ class X509
$this->caFlag = true;
}
/**
* Check for validity of subarray
*
* This is intended for use in conjunction with _subArrayUnchecked(),
* implementing the checks included in _subArray() but without copying
* a potentially large array by passing its reference by-value to is_array().
*
* @param array $root
* @param string $path
* @return boolean
* @access private
*/
function _isSubArrayValid($root, $path)
{
if (!is_array($root)) {
return false;
}
foreach (explode('/', $path) as $i) {
if (!is_array($root)) {
return false;
}
if (!isset($root[$i])) {
return true;
}
$root = $root[$i];
}
return true;
}
/**
* Get a reference to a subarray
*
* This variant of _subArray() does no is_array() checking,
* so $root should be checked with _isSubArrayValid() first.
*
* This is here for performance reasons:
* Passing a reference (i.e. $root) by-value (i.e. to is_array())
* creates a copy. If $root is an especially large array, this is expensive.
*
* @param array $root
* @param string $path absolute path with / as component separator
* @param bool $create optional
* @access private
* @return array|false
*/
function &_subArrayUnchecked(&$root, $path, $create = false)
{
$false = false;
foreach (explode('/', $path) as $i) {
if (!isset($root[$i])) {
if (!$create) {
return $false;
}
$root[$i] = array();
}
$root = &$root[$i];
}
return $root;
}
/**
* Get a reference to a subarray
*
@ -4177,7 +4389,7 @@ class X509
if (empty($value)) {
unset($this->currentKeyIdentifier);
} else {
$this->currentKeyIdentifier = base64_encode($value);
$this->currentKeyIdentifier = Base64::encode($value);
}
}
@ -4225,10 +4437,10 @@ class X509
if (empty($raw)) {
return false;
}
$raw = base64_decode($raw);
$raw = Base64::decode($raw);
// If the key is private, compute identifier from its corresponding public key.
$key = new RSA();
if (!$key->loadKey($raw)) {
if (!$key->load($raw)) {
return false; // Not an unencrypted RSA key.
}
if ($key->getPrivateKey() !== false) { // If private.
@ -4248,7 +4460,7 @@ class X509
}
return false;
default: // Should be a key object (i.e.: \phpseclib\Crypt\RSA).
$key = $key->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
$key = $key->getPublicKey('PKCS1');
break;
}
@ -4278,10 +4490,10 @@ class X509
if ($this->publicKey instanceof RSA) {
// the following two return statements do the same thing. i dunno.. i just prefer the later for some reason.
// the former is a good example of how to do fuzzing on the public key
//return new Element(base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
//return new Element(Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())));
return array(
'algorithm' => array('algorithm' => 'rsaEncryption'),
'subjectPublicKey' => $this->publicKey->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1)
'subjectPublicKey' => $this->publicKey->getPublicKey('PKCS1')
);
}
@ -4581,7 +4793,7 @@ class X509
$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;
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? Base64::decode($temp) : false;
return $temp != false ? $temp : $str;
}

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,8 @@
namespace phpseclib\Net;
use phpseclib\Exception\FileNotFoundException;
/**
* Pure-PHP implementations of SCP.
*
@ -137,6 +139,7 @@ class SCP
* @param string $data
* @param int $mode
* @param callable $callback
* @throws \phpseclib\Exception\FileNotFoundException if you're uploading via a file and the file doesn't exist
* @return bool
* @access public
*/
@ -165,8 +168,7 @@ class SCP
$size = strlen($data);
} else {
if (!is_file($data)) {
user_error("$data is not a valid file", E_USER_NOTICE);
return false;
throw new FileNotFoundException("$data is not a valid file");
}
$fp = @fopen($data, 'rb');
@ -286,6 +288,7 @@ class SCP
* Receives a packet from an SSH server
*
* @return string
* @throws \UnexpectedValueException on receipt of an unexpected packet
* @access private
*/
function _receive()
@ -311,8 +314,7 @@ class SCP
$this->ssh->bitmap = 0;
return false;
default:
user_error('Unknown packet received', E_USER_NOTICE);
return false;
throw new \UnexpectedValueException('Unknown packet received');
}
}
}

View File

@ -37,6 +37,9 @@
namespace phpseclib\Net;
use ParagonIE\ConstantTime\Hex;
use phpseclib\Exception\FileNotFoundException;
/**
* Pure-PHP implementations of SFTP.
*
@ -381,6 +384,7 @@ class SFTP extends SSH2
*
* @param string $username
* @param string $password
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@ -468,8 +472,7 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_VERSION) {
user_error('Expected SSH_FXP_VERSION');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_VERSION');
}
extract(unpack('Nversion', $this->_string_shift($response, 4)));
@ -600,6 +603,21 @@ class SFTP extends SSH2
}
}
/**
* Returns canonicalized absolute pathname
*
* realpath() expands all symbolic links and resolves references to '/./', '/../' and extra '/' characters in the input
* path and returns the canonicalized absolute pathname.
*
* @param string $path
* @return mixed
* @access public
*/
function realpath($path)
{
return $this->_realpath($path);
}
/**
* Canonicalize the Server-Side Path Name
*
@ -608,6 +626,7 @@ class SFTP extends SSH2
*
* @see self::chdir()
* @param string $path
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access private
*/
@ -632,8 +651,7 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
}
}
@ -664,6 +682,7 @@ class SFTP extends SSH2
* Changes the current directory
*
* @param string $dir
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@ -708,8 +727,7 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
}
if (!$this->_close_handle($handle)) {
@ -811,6 +829,7 @@ class SFTP extends SSH2
* @param string $dir
* @param bool $raw
* @return mixed
* @throws \UnexpectedValueException on receipt of unexpected packets
* @access private
*/
function _list($dir, $raw = true)
@ -842,8 +861,7 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
}
$this->_update_stat_cache($dir, array());
@ -897,8 +915,7 @@ class SFTP extends SSH2
}
break 2;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
}
}
@ -1257,6 +1274,7 @@ class SFTP extends SSH2
*
* @param string $filename
* @param int $type
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access private
*/
@ -1277,8 +1295,7 @@ class SFTP extends SSH2
return false;
}
user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
}
/**
@ -1304,6 +1321,7 @@ class SFTP extends SSH2
* @param string $filename
* @param int $time
* @param int $atime
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@ -1340,8 +1358,7 @@ class SFTP extends SSH2
$this->_logError($response);
break;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
}
return $this->_setstat($filename, $attr, false);
@ -1394,6 +1411,7 @@ class SFTP extends SSH2
* @param int $mode
* @param string $filename
* @param bool $recursive
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access public
*/
@ -1432,8 +1450,7 @@ class SFTP extends SSH2
return false;
}
user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
}
/**
@ -1442,6 +1459,7 @@ class SFTP extends SSH2
* @param string $filename
* @param string $attr
* @param bool $recursive
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access private
*/
@ -1480,8 +1498,7 @@ class SFTP extends SSH2
*/
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
@ -1569,6 +1586,7 @@ class SFTP extends SSH2
* Return the target of a symbolic link
*
* @param string $link
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access public
*/
@ -1592,8 +1610,7 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
}
extract(unpack('Ncount', $this->_string_shift($response, 4)));
@ -1613,6 +1630,7 @@ class SFTP extends SSH2
*
* @param string $target
* @param string $link
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@ -1622,7 +1640,7 @@ class SFTP extends SSH2
return false;
}
$target = $this->_realpath($target);
//$target = $this->_realpath($target);
$link = $this->_realpath($link);
$packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link);
@ -1632,8 +1650,7 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
@ -1685,6 +1702,7 @@ class SFTP extends SSH2
*
* @param string $dir
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @access private
*/
function _mkdir_helper($dir, $attr)
@ -1695,8 +1713,7 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
@ -1712,6 +1729,7 @@ class SFTP extends SSH2
* Removes a directory.
*
* @param string $dir
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return bool
* @access public
*/
@ -1732,8 +1750,7 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
@ -1793,6 +1810,9 @@ class SFTP extends SSH2
* @param int $start
* @param int $local_start
* @param callable|null $progressCallback
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \BadFunctionCallException if you're uploading via a callback and the callback function is invalid
* @throws \phpseclib\Exception\FileNotFoundException if you're uploading via a file and the file doesn't exist
* @return bool
* @access public
* @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - \phpseclib\Net\SFTP::setMode().
@ -1840,8 +1860,7 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
}
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
@ -1849,7 +1868,7 @@ class SFTP extends SSH2
switch (true) {
case $mode & self::SOURCE_CALLBACK:
if (!is_callable($data)) {
user_error("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
throw new \BadFunctionCallException("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
}
$dataCallback = $data;
// do nothing
@ -1860,8 +1879,7 @@ class SFTP extends SSH2
break;
case $mode & self::SOURCE_LOCAL_FILE:
if (!is_file($data)) {
user_error("$data is not a valid file");
return false;
throw new FileNotFoundException("$data is not a valid file");
}
$fp = @fopen($data, 'rb');
if (!$fp) {
@ -1890,7 +1908,7 @@ class SFTP extends SSH2
// make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header"
$sftp_packet_size-= strlen($handle) + 25;
$i = 0;
while ($dataCallback || $sent < $size) {
while ($dataCallback || ($size === 0 || $sent < $size)) {
if ($dataCallback) {
$temp = call_user_func($dataCallback, $sftp_packet_size);
if (is_null($temp)) {
@ -1898,7 +1916,11 @@ class SFTP extends SSH2
}
} else {
$temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
if ($temp === false) {
break;
}
}
$subtemp = $offset + $sent;
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
@ -1946,6 +1968,7 @@ class SFTP extends SSH2
*
* @param int $i
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @access private
*/
function _read_put_responses($i)
@ -1953,8 +1976,7 @@ class SFTP extends SSH2
while ($i--) {
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
@ -1972,6 +1994,7 @@ class SFTP extends SSH2
*
* @param string $handle
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @access private
*/
function _close_handle($handle)
@ -1984,8 +2007,7 @@ class SFTP extends SSH2
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
@ -2010,6 +2032,7 @@ class SFTP extends SSH2
* @param string $local_file
* @param int $offset
* @param int $length
* @throws \UnexpectedValueException on receipt of unexpected packets
* @return mixed
* @access public
*/
@ -2038,8 +2061,7 @@ class SFTP extends SSH2
$this->_logError($response);
return false;
default:
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
}
if (is_resource($local_file)) {
@ -2061,40 +2083,68 @@ class SFTP extends SSH2
$fclose_check = $local_file !== false && !is_resource($local_file);
$start = $offset;
$size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length;
$read = 0;
while (true) {
$packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size);
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
if ($fclose_check) {
fclose($fp);
}
return false;
}
$i = 0;
$response = $this->_get_sftp_packet();
switch ($this->packet_type) {
case NET_SFTP_DATA:
$temp = substr($response, 4);
$offset+= strlen($temp);
if ($local_file === false) {
$content.= $temp;
} else {
fputs($fp, $temp);
}
break;
case NET_SFTP_STATUS:
// could, in theory, return false if !strlen($content) but we'll hold off for the time being
$this->_logError($response);
break 2;
default:
user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
while ($i < NET_SFTP_QUEUE_SIZE && ($length < 0 || $read < $length)) {
$tempoffset = $start + $read;
$packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
$packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
if ($fclose_check) {
fclose($fp);
}
return false;
}
$packet = null;
$read+= $packet_size;
$i++;
}
if ($length > 0 && $length <= $offset - $start) {
if (!$i) {
break;
}
$clear_responses = false;
while ($i > 0) {
$i--;
if ($clear_responses) {
$this->_get_sftp_packet();
continue;
} else {
$response = $this->_get_sftp_packet();
}
switch ($this->packet_type) {
case NET_SFTP_DATA:
$temp = substr($response, 4);
$offset+= strlen($temp);
if ($local_file === false) {
$content.= $temp;
} else {
fputs($fp, $temp);
}
$temp = null;
break;
case NET_SFTP_STATUS:
// could, in theory, return false if !strlen($content) but we'll hold off for the time being
$this->_logError($response);
$clear_responses = true; // don't break out of the loop yet, so we can read the remaining responses
break;
default:
if ($fclose_check) {
fclose($fp);
}
throw new \UnexpectedValueException('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
}
$response = null;
}
if ($clear_responses) {
break;
}
}
@ -2125,6 +2175,7 @@ class SFTP extends SSH2
* @param string $path
* @param bool $recursive
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @access public
*/
function delete($path, $recursive = true)
@ -2145,8 +2196,7 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
@ -2548,6 +2598,7 @@ class SFTP extends SSH2
* @param string $oldname
* @param string $newname
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @access public
*/
function rename($oldname, $newname)
@ -2570,8 +2621,7 @@ class SFTP extends SSH2
$response = $this->_get_sftp_packet();
if ($this->packet_type != NET_SFTP_STATUS) {
user_error('Expected SSH_FXP_STATUS');
return false;
throw new \UnexpectedValueException('Expected SSH_FXP_STATUS');
}
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
@ -2613,7 +2663,7 @@ class SFTP extends SSH2
// IEEE 754 binary64 "double precision" on such platforms and
// as such can represent integers of at least 2^50 without loss
// of precision. Interpreted in filesize, 2^50 bytes = 1024 TiB.
$attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
$attr['size'] = hexdec(Hex::encode($this->_string_shift($response, 8)));
break;
case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
$attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
@ -2745,13 +2795,13 @@ class SFTP extends SSH2
if (defined('NET_SFTP_LOGGING')) {
$packet_type = '-> ' . $this->packet_types[$type] .
' (' . round($stop - $start, 4) . 's)';
if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
echo "<pre>\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n</pre>\r\n";
flush();
ob_flush();
} else {
$this->packet_type_log[] = $packet_type;
if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
$this->packet_log[] = $data;
}
}
@ -2821,13 +2871,13 @@ class SFTP extends SSH2
if (defined('NET_SFTP_LOGGING')) {
$packet_type = '<- ' . $this->packet_types[$this->packet_type] .
' (' . round($stop - $start, 4) . 's)';
if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
if (NET_SFTP_LOGGING == self::LOG_REALTIME) {
echo "<pre>\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n</pre>\r\n";
flush();
ob_flush();
} else {
$this->packet_type_log[] = $packet_type;
if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
if (NET_SFTP_LOGGING == self::LOG_COMPLEX) {
$this->packet_log[] = $packet;
}
}
@ -2839,7 +2889,7 @@ class SFTP extends SSH2
/**
* Returns a log of the packets that have been sent and received.
*
* Returns a string if NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX, an array if NET_SFTP_LOGGING == NET_SFTP_LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
* Returns a string if NET_SFTP_LOGGING == self::LOG_COMPLEX, an array if NET_SFTP_LOGGING == self::LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
*
* @access public
* @return string or Array
@ -2851,10 +2901,10 @@ class SFTP extends SSH2
}
switch (NET_SFTP_LOGGING) {
case NET_SFTP_LOG_COMPLEX:
case self::LOG_COMPLEX:
return $this->_format_log($this->packet_log, $this->packet_type_log);
break;
//case NET_SFTP_LOG_SIMPLE:
//case self::LOG_SIMPLE:
default:
return $this->packet_type_log;
}

View File

@ -19,6 +19,7 @@ namespace phpseclib\Net\SFTP;
use phpseclib\Crypt\RSA;
use phpseclib\Net\SFTP;
use phpseclib\Net\SSH2;
/**
* SFTP Stream Wrapper
@ -177,13 +178,12 @@ class Stream
}
}
if ($host[0] == '$') {
$host = substr($host, 1);
global $$host;
if (($$host instanceof SFTP) === false) {
if (preg_match('/^{[a-z0-9]+}$/i', $host)) {
$host = SSH2::getConnectionByResourceId($host);
if ($host === false) {
return false;
}
$this->sftp = $$host;
$this->sftp = $host;
} else {
if (isset($this->context)) {
$context = stream_context_get_options($this->context);

View File

@ -48,6 +48,7 @@
namespace phpseclib\Net;
use ParagonIE\ConstantTime\Hex;
use phpseclib\Crypt\DES;
use phpseclib\Crypt\Random;
use phpseclib\Crypt\TripleDES;
@ -537,14 +538,15 @@ class SSH1
* Connect to an SSHv1 server
*
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access private
*/
function _connect()
{
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->connectionTimeout);
if (!$this->fsock) {
user_error(rtrim("Cannot connect to {$this->host}:{$this->port}. Error $errno. $errstr"));
return false;
throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
}
$this->server_identification = $init_line = fgets($this->fsock, 255);
@ -555,20 +557,17 @@ class SSH1
}
if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
user_error('Can only connect to SSH servers');
return false;
throw new \RuntimeException('Can only connect to SSH servers');
}
if ($parts[1][0] != 1) {
user_error("Cannot connect to SSH $parts[1] servers");
return false;
throw new \RuntimeException("Cannot connect to $parts[1] servers");
}
fputs($this->fsock, $this->identifier."\r\n");
$response = $this->_get_binary_packet();
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
user_error('Expected SSH_SMSG_PUBLIC_KEY');
return false;
throw new \UnexpectedValueException('Expected SSH_SMSG_PUBLIC_KEY');
}
$anti_spoofing_cookie = $this->_string_shift($response[self::RESPONSE_DATA], 8);
@ -611,7 +610,7 @@ class SSH1
}
}
$session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
$session_id = md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie, true);
$session_key = Random::string(32);
$double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
@ -652,8 +651,7 @@ class SSH1
$data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_SESSION_KEY');
return false;
throw new \RuntimeException('Error sending SSH_CMSG_SESSION_KEY');
}
switch ($cipher) {
@ -661,16 +659,20 @@ class SSH1
// $this->crypto = new \phpseclib\Crypt\Null();
// break;
case self::CIPHER_DES:
$this->crypto = new DES();
$this->crypto = new DES(DES::MODE_CBC);
$this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 8));
// "The iv (initialization vector) is initialized to all zeroes."
$this->crypto->setIV(str_repeat("\0", 8));
break;
case self::CIPHER_3DES:
$this->crypto = new TripleDES(TripleDES::MODE_3CBC);
$this->crypto->disablePadding();
$this->crypto->enableContinuousBuffer();
$this->crypto->setKey(substr($session_key, 0, 24));
// "All three initialization vectors are initialized to zero."
$this->crypto->setIV(str_repeat("\0", 8));
break;
//case self::CIPHER_RC4:
// $this->crypto = new RC4();
@ -682,8 +684,7 @@ class SSH1
$response = $this->_get_binary_packet();
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS');
return false;
throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
}
$this->bitmap = self::MASK_CONNECTED;
@ -697,6 +698,8 @@ class SSH1
* @param string $username
* @param string $password
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access public
*/
function login($username, $password = '')
@ -715,8 +718,7 @@ class SSH1
$data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_USER');
return false;
throw new \RuntimeException('Error sending SSH_CMSG_USER');
}
$response = $this->_get_binary_packet();
@ -728,15 +730,13 @@ class SSH1
$this->bitmap |= self::MASK_LOGIN;
return true;
} elseif ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
}
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_AUTH_PASSWORD');
return false;
throw new \RuntimeException('Error sending SSH_CMSG_AUTH_PASSWORD');
}
// remove the username and password from the last logged packet
@ -756,8 +756,7 @@ class SSH1
} elseif ($response[self::RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
return false;
} else {
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
return false;
throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE');
}
}
@ -792,20 +791,19 @@ class SSH1
* @see self::interactiveWrite()
* @param string $cmd
* @return mixed
* @throws \RuntimeException on error sending command
* @access public
*/
function exec($cmd, $block = true)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
throw new \RuntimeException('Operation disallowed prior to login()');
}
$data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_CMD');
return false;
throw new \RuntimeException('Error sending SSH_CMSG_EXEC_CMD');
}
if (!$block) {
@ -841,6 +839,8 @@ class SSH1
* @see self::interactiveRead()
* @see self::interactiveWrite()
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access private
*/
function _initShell()
@ -851,8 +851,7 @@ class SSH1
$data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, self::TTY_OP_END);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_REQUEST_PTY');
return false;
throw new \RuntimeException('Error sending SSH_CMSG_REQUEST_PTY');
}
$response = $this->_get_binary_packet();
@ -861,15 +860,13 @@ class SSH1
return false;
}
if ($response[self::RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
user_error('Expected SSH_SMSG_SUCCESS');
return false;
throw new \UnexpectedValueException('Expected SSH_SMSG_SUCCESS');
}
$data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_EXEC_SHELL');
return false;
throw new \RuntimeException('Error sending SSH_CMSG_EXEC_SHELL');
}
$this->bitmap |= self::MASK_SHELL;
@ -902,18 +899,17 @@ class SSH1
* @param string $expect
* @param int $mode
* @return bool
* @throws \RuntimeException on connection error
* @access public
*/
function read($expect, $mode = self::READ__SIMPLE)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
throw new \RuntimeException('Operation disallowed prior to login()');
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
throw new \RuntimeException('Unable to initiate an interactive shell session');
}
$match = $expect;
@ -941,25 +937,23 @@ class SSH1
* @see self::interactiveRead()
* @param string $cmd
* @return bool
* @throws \RuntimeException on connection error
* @access public
*/
function interactiveWrite($cmd)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
throw new \RuntimeException('Operation disallowed prior to login()');
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
throw new \RuntimeException('Unable to initiate an interactive shell session');
}
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
if (!$this->_send_binary_packet($data)) {
user_error('Error sending SSH_CMSG_STDIN');
return false;
throw new \RuntimeException('Error sending SSH_CMSG_STDIN');
}
return true;
@ -976,18 +970,17 @@ class SSH1
*
* @see self::interactiveRead()
* @return string
* @throws \RuntimeException on connection error
* @access public
*/
function interactiveRead()
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
throw new \RuntimeException('Operation disallowed prior to login()');
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
throw new \RuntimeException('Unable to initiate an interactive shell session');
}
$read = array($this->fsock);
@ -1313,9 +1306,9 @@ class SSH1
{
/*
$rsa = new RSA();
$rsa->loadKey($key, RSA::PUBLIC_FORMAT_RAW);
$rsa->setEncryptionMode(RSA::ENCRYPTION_PKCS1);
return $rsa->encrypt($m);
$rsa->load($key, 'raw');
$rsa->setHash('sha1');
return $rsa->encrypt($m, RSA::PADDING_PKCS1);
*/
// To quote from protocol-1.5.txt:

View File

@ -26,7 +26,7 @@
*
* $key = new \phpseclib\Crypt\RSA();
* //$key->setPassword('whatever');
* $key->loadKey(file_get_contents('privatekey'));
* $key->load(file_get_contents('privatekey'));
*
* $ssh = new \phpseclib\Net\SSH2('www.domain.tld');
* if (!$ssh->login('username', $key)) {
@ -49,6 +49,7 @@
namespace phpseclib\Net;
use ParagonIE\ConstantTime\Base64;
use phpseclib\Crypt\Base;
use phpseclib\Crypt\Blowfish;
use phpseclib\Crypt\Hash;
@ -60,6 +61,7 @@ use phpseclib\Crypt\TripleDES;
use phpseclib\Crypt\Twofish;
use phpseclib\Math\BigInteger; // Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
use phpseclib\System\SSH\Agent;
use phpseclib\Exception\NoSupportedAlgorithmsException;
/**
* Pure-PHP implementation of SSHv2.
@ -866,6 +868,14 @@ class SSH2
*/
var $agent;
/**
* Connection storage to replicates ssh2 extension functionality:
* {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
*
* @var SSH2[]
*/
static $connections;
/**
* Default Constructor.
*
@ -959,6 +969,8 @@ class SSH2
31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY')
);
self::$connections[$this->getResourceId()] = $this;
if (is_resource($host)) {
$this->fsock = $host;
return;
@ -989,6 +1001,8 @@ class SSH2
* Connect to an SSHv2 server
*
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access private
*/
function _connect()
@ -1008,8 +1022,7 @@ class SSH2
$this->fsock = @fsockopen($this->host, $this->port, $errno, $errstr, $this->curTimeout);
if (!$this->fsock) {
$host = $this->host . ':' . $this->port;
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"));
return false;
throw new \RuntimeException(rtrim("Cannot connect to $host. Error $errno. $errstr"));
}
$elapsed = microtime(true) - $start;
@ -1028,70 +1041,74 @@ class SSH2
Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
MUST be able to process such lines." */
$temp = '';
$extra = '';
while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
if (substr($temp, -2) == "\r\n") {
$extra.= $temp;
$temp = '';
}
if ($this->curTimeout) {
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return false;
$data = '';
while (!feof($this->fsock) && !preg_match('#(.*)^(SSH-(\d\.\d+).*)#ms', $data, $matches)) {
$line = '';
while (true) {
if ($this->curTimeout) {
if ($this->curTimeout < 0) {
$this->is_timeout = true;
return false;
}
$read = array($this->fsock);
$write = $except = null;
$start = microtime(true);
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);
// on windows this returns a "Warning: Invalid CRT parameters detected" error
// the !count() is done as a workaround for <https://bugs.php.net/42682>
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
$this->is_timeout = true;
return false;
}
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
}
$read = array($this->fsock);
$write = $except = null;
$start = microtime(true);
$sec = floor($this->curTimeout);
$usec = 1000000 * ($this->curTimeout - $sec);
// on windows this returns a "Warning: Invalid CRT parameters detected" error
// the !count() is done as a workaround for <https://bugs.php.net/42682>
if (!@stream_select($read, $write, $except, $sec, $usec) && !count($read)) {
$this->is_timeout = true;
return false;
}
$elapsed = microtime(true) - $start;
$this->curTimeout-= $elapsed;
}
$temp.= fgets($this->fsock, 255);
$temp = stream_get_line($this->fsock, 255, "\n");
if (strlen($temp) == 255) {
continue;
}
$line.= "$temp\n";
if (substr($line, -2) == "\r\n") {
break;
}
}
$data.= $line;
}
if (feof($this->fsock)) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
$extra = $matches[1];
$this->identifier = $this->_generate_identifier();
if (defined('NET_SSH2_LOGGING')) {
$this->_append_log('<-', $extra . $temp);
$this->_append_log('<-', $matches[0]);
$this->_append_log('->', $this->identifier . "\r\n");
}
$this->server_identifier = trim($temp, "\r\n");
if (strlen($extra)) {
$this->errors[] = utf8_decode($extra);
$this->errors[] = utf8_decode($data);
}
if ($matches[1] != '1.99' && $matches[1] != '2.0') {
user_error("Cannot connect to SSH $matches[1] servers");
return false;
if ($matches[3] != '1.99' && $matches[3] != '2.0') {
throw new \RuntimeException("Cannot connect to SSH $matches[1] servers");
}
fputs($this->fsock, $this->identifier . "\r\n");
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
user_error('Expected SSH_MSG_KEXINIT');
return false;
throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT');
}
if (!$this->_key_exchange($response)) {
@ -1143,6 +1160,9 @@ class SSH2
* Key Exchange
*
* @param string $kexinit_payload_server
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @throws \phpseclib\Exception\NoSupportedAlgorithmsException when none of the algorithms phpseclib has loaded are compatible
* @access private
*/
function _key_exchange($kexinit_payload_server)
@ -1354,27 +1374,28 @@ class SSH2
// here ends the second place.
// we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
// we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
// diffie-hellman key exchange as fast as possible
$decrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_server_to_client);
$decryptKeyLength = $this->_encryption_algorithm_to_key_size($decrypt);
if ($decryptKeyLength === null) {
user_error('No compatible server to client encryption algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new NoSupportedAlgorithmsException('No compatible server to client encryption algorithms found');
}
$encrypt = $this->_array_intersect_first($encryption_algorithms, $this->encryption_algorithms_client_to_server);
$encryptKeyLength = $this->_encryption_algorithm_to_key_size($encrypt);
if ($encryptKeyLength === null) {
user_error('No compatible client to server encryption algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new NoSupportedAlgorithmsException('No compatible client to server encryption algorithms found');
}
// through diffie-hellman key exchange a symmetric key is obtained
$kex_algorithm = $this->_array_intersect_first($kex_algorithms, $this->kex_algorithms);
if ($kex_algorithm === false) {
user_error('No compatible key exchange algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new NoSupportedAlgorithmsException('No compatible key exchange algorithms found');
}
// Only relevant in diffie-hellman-group-exchange-sha{1,256}, otherwise empty.
@ -1483,7 +1504,7 @@ class SSH2
$max = $one->bitwise_leftShift(16 * $keyLength); // 2 * 8 * $keyLength
$max = $max->subtract($one);
$x = $one->random($one, $max);
$x = BigInteger::random($one, $max);
$e = $g->modPow($x, $prime);
$eBytes = $e->toBytes(true);
@ -1491,20 +1512,17 @@ class SSH2
$data = pack('CNa*', $clientKexInitMessage, strlen($eBytes), $eBytes);
if (!$this->_send_binary_packet($data)) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != $serverKexReplyMessage) {
user_error('Expected SSH_MSG_KEXDH_REPLY');
return false;
throw new \UnexpectedValueException('Expected SSH_MSG_KEXDH_REPLY');
}
$temp = unpack('Nlength', $this->_string_shift($response, 4));
@ -1564,13 +1582,13 @@ class SSH2
$server_host_key_algorithm = $this->_array_intersect_first($server_host_key_algorithms, $this->server_host_key_algorithms);
if ($server_host_key_algorithm === false) {
user_error('No compatible server host key algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new NoSupportedAlgorithmsException('No compatible server host key algorithms found');
}
if ($public_key_format != $server_host_key_algorithm || $this->signature_format != $server_host_key_algorithm) {
user_error('Server Host Key Algorithm Mismatch');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new \RuntimeException('Server Host Key Algorithm Mismatch');
}
$packet = pack(
@ -1585,15 +1603,13 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_NEWKEYS) {
user_error('Expected SSH_MSG_NEWKEYS');
return false;
throw new \UnexpectedValueException('Expected SSH_MSG_NEWKEYS');
}
$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
@ -1609,11 +1625,13 @@ class SSH2
$this->encrypt->enableContinuousBuffer();
$this->encrypt->disablePadding();
$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
while ($this->encrypt_block_size > strlen($iv)) {
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
if ($this->encrypt->usesIV()) {
$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id);
while ($this->encrypt_block_size > strlen($iv)) {
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
}
$this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
}
$this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id);
while ($encryptKeyLength > strlen($key)) {
@ -1633,11 +1651,13 @@ class SSH2
$this->decrypt->enableContinuousBuffer();
$this->decrypt->disablePadding();
$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
while ($this->decrypt_block_size > strlen($iv)) {
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
if ($this->decrypt->usesIV()) {
$iv = $kexHash->hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id);
while ($this->decrypt_block_size > strlen($iv)) {
$iv.= $kexHash->hash($keyBytes . $this->exchange_hash . $iv);
}
$this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
}
$this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
$key = $kexHash->hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id);
while ($decryptKeyLength > strlen($key)) {
@ -1662,8 +1682,8 @@ class SSH2
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_client_to_server);
if ($mac_algorithm === false) {
user_error('No compatible client to server message authentication algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new NoSupportedAlgorithmsException('No compatible client to server message authentication algorithms found');
}
$createKeyLength = 0; // ie. $mac_algorithm == 'none'
@ -1691,8 +1711,8 @@ class SSH2
$mac_algorithm = $this->_array_intersect_first($mac_algorithms, $this->mac_algorithms_server_to_client);
if ($mac_algorithm === false) {
user_error('No compatible server to client message authentication algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new NoSupportedAlgorithmsException('No compatible server to client message authentication algorithms found');
}
$checkKeyLength = 0;
@ -1738,15 +1758,15 @@ class SSH2
$compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_server_to_client);
if ($compression_algorithm === false) {
user_error('No compatible server to client compression algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new NoSupportedAlgorithmsException('No compatible server to client compression algorithms found');
}
$this->decompress = $compression_algorithm == 'zlib';
$compression_algorithm = $this->_array_intersect_first($compression_algorithms, $this->compression_algorithms_client_to_server);
if ($compression_algorithm === false) {
user_error('No compatible client to server compression algorithms found');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new NoSupportedAlgorithmsException('No compatible client to server compression algorithms found');
}
$this->compress = $compression_algorithm == 'zlib';
@ -1804,26 +1824,26 @@ class SSH2
{
switch ($algorithm) {
case '3des-cbc':
return new TripleDES();
return new TripleDES(Base::MODE_CBC);
case '3des-ctr':
return new TripleDES(Base::MODE_CTR);
case 'aes256-cbc':
case 'aes192-cbc':
case 'aes128-cbc':
return new Rijndael();
return new Rijndael(Base::MODE_CBC);
case 'aes256-ctr':
case 'aes192-ctr':
case 'aes128-ctr':
return new Rijndael(Base::MODE_CTR);
case 'blowfish-cbc':
return new Blowfish();
return new Blowfish(Base::MODE_CBC);
case 'blowfish-ctr':
return new Blowfish(Base::MODE_CTR);
case 'twofish128-cbc':
case 'twofish192-cbc':
case 'twofish256-cbc':
case 'twofish-cbc':
return new Twofish();
return new Twofish(Base::MODE_CBC);
case 'twofish128-ctr':
case 'twofish192-ctr':
case 'twofish256-ctr':
@ -1891,6 +1911,8 @@ class SSH2
* @param string $username
* @param string $password
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access private
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
* by sending dummy SSH_MSG_IGNORE messages.
@ -1915,15 +1937,13 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
user_error('Expected SSH_MSG_SERVICE_ACCEPT');
return false;
throw new \UnexpectedValueException('Expected SSH_MSG_SERVICE_ACCEPT');
}
$this->bitmap |= self::MASK_LOGIN_REQ;
}
@ -1964,8 +1984,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
@ -2019,8 +2038,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
@ -2096,6 +2114,7 @@ class SSH2
*
* @param string $responses...
* @return bool
* @throws \RuntimeException on connection error
* @access private
*/
function _keyboard_interactive_process()
@ -2107,8 +2126,7 @@ class SSH2
} else {
$orig = $response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
}
@ -2232,6 +2250,7 @@ class SSH2
* @param string $username
* @param \phpseclib\Crypt\RSA $password
* @return bool
* @throws \RuntimeException on connection error
* @access private
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
* by sending dummy SSH_MSG_IGNORE messages.
@ -2239,7 +2258,7 @@ class SSH2
function _privatekey_login($username, $privatekey)
{
// see http://tools.ietf.org/html/rfc4253#page-15
$publickey = $privatekey->getPublicKey(RSA::PUBLIC_FORMAT_RAW);
$publickey = $privatekey->getPublicKey('Raw');
if ($publickey === false) {
return false;
}
@ -2277,8 +2296,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
@ -2301,8 +2319,8 @@ class SSH2
}
$packet = $part1 . chr(1) . $part2;
$privatekey->setSignatureMode(RSA::SIGNATURE_PKCS1);
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
$privatekey->setHash('sha1');
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet), RSA::PADDING_PKCS1);
$signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature);
$packet.= pack('Na*', strlen($signature), $signature);
@ -2312,8 +2330,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
extract(unpack('Ctype', $this->_string_shift($response, 1)));
@ -2363,6 +2380,7 @@ class SSH2
* @param string $command
* @param Callback $callback
* @return string
* @throws \RuntimeException on connection error
* @access public
*/
function exec($command, $callback = null)
@ -2430,8 +2448,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
list(, $type) = unpack('C', $this->_string_shift($response, 1));
@ -2441,8 +2458,8 @@ class SSH2
break;
case NET_SSH2_MSG_CHANNEL_FAILURE:
default:
user_error('Unable to request pseudo-terminal');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
throw new \RuntimeException('Unable to request pseudo-terminal');
}
$this->in_request_pty_exec = true;
}
@ -2510,6 +2527,8 @@ class SSH2
* @see self::read()
* @see self::write()
* @return bool
* @throws \UnexpectedValueException on receipt of unexpected packets
* @throws \RuntimeException on other errors
* @access private
*/
function _initShell()
@ -2566,8 +2585,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
list(, $type) = unpack('C', $this->_string_shift($response, 1));
@ -2578,8 +2596,8 @@ class SSH2
case NET_SSH2_MSG_CHANNEL_FAILURE:
break;
default:
user_error('Unable to request pseudo-terminal');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
throw new \UnexpectedValueException('Unable to request pseudo-terminal');
}
$packet = pack(
@ -2656,6 +2674,7 @@ class SSH2
* @param string $expect
* @param int $mode
* @return string
* @throws \RuntimeException on connection error
* @access public
*/
function read($expect = '', $mode = self::READ_SIMPLE)
@ -2664,13 +2683,11 @@ class SSH2
$this->is_timeout = false;
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
throw new \RuntimeException('Operation disallowed prior to login()');
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
throw new \RuntimeException('Unable to initiate an interactive shell session');
}
$channel = $this->_get_interactive_channel();
@ -2701,18 +2718,17 @@ class SSH2
* @see self::read()
* @param string $cmd
* @return bool
* @throws \RuntimeException on connection error
* @access public
*/
function write($cmd)
{
if (!($this->bitmap & self::MASK_LOGIN)) {
user_error('Operation disallowed prior to login()');
return false;
throw new \RuntimeException('Operation disallowed prior to login()');
}
if (!($this->bitmap & self::MASK_SHELL) && !$this->_initShell()) {
user_error('Unable to initiate an interactive shell session');
return false;
throw new \RuntimeException('Unable to initiate an interactive shell session');
}
return $this->_send_channel_packet($this->_get_interactive_channel(), $cmd);
@ -2836,6 +2852,7 @@ class SSH2
if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
fclose($this->realtime_log_file);
}
unset(self::$connections[$this->getResourceId()]);
}
/**
@ -2880,18 +2897,18 @@ class SSH2
*
* @see self::_send_binary_packet()
* @return string
* @throws \RuntimeException on connection errors
* @access private
*/
function _get_binary_packet()
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
user_error('Connection closed prematurely');
$this->bitmap = 0;
return false;
throw new \RuntimeException('Connection closed prematurely');
}
$start = microtime(true);
$raw = fread($this->fsock, $this->decrypt_block_size);
$raw = stream_get_contents($this->fsock, $this->decrypt_block_size);
if (!strlen($raw)) {
return '';
@ -2901,8 +2918,7 @@ class SSH2
$raw = $this->decrypt->decrypt($raw);
}
if ($raw === false) {
user_error('Unable to decrypt content');
return false;
throw new \RuntimeException('Unable to decrypt content');
}
extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
@ -2913,17 +2929,15 @@ class SSH2
// "implementations SHOULD check that the packet length is reasonable"
// PuTTY uses 0x9000 as the actual max packet size and so to shall we
if ($remaining_length < -$this->decrypt_block_size || $remaining_length > 0x9000 || $remaining_length % $this->decrypt_block_size != 0) {
user_error('Invalid size');
return false;
throw new \RuntimeException('Invalid size');
}
$buffer = '';
while ($remaining_length > 0) {
$temp = fread($this->fsock, $remaining_length);
$temp = stream_get_contents($this->fsock, $remaining_length);
if ($temp === false || feof($this->fsock)) {
user_error('Error reading from socket');
$this->bitmap = 0;
return false;
throw new \RuntimeException('Error reading from socket');
}
$buffer.= $temp;
$remaining_length-= strlen($temp);
@ -2937,14 +2951,12 @@ class SSH2
$padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty
if ($this->hmac_check !== false) {
$hmac = fread($this->fsock, $this->hmac_size);
$hmac = stream_get_contents($this->fsock, $this->hmac_size);
if ($hmac === false || strlen($hmac) != $this->hmac_size) {
user_error('Error reading socket');
$this->bitmap = 0;
return false;
throw new \RuntimeException('Error reading socket');
} elseif ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
user_error('Invalid HMAC');
return false;
throw new \RuntimeException('Invalid HMAC');
}
}
@ -3170,6 +3182,7 @@ class SSH2
*
* @param $client_channel
* @return mixed
* @throws \RuntimeException on connection error
* @access private
*/
function _get_channel_packet($client_channel, $skip_extended = false)
@ -3202,8 +3215,7 @@ class SSH2
$response = $this->_get_binary_packet();
if ($response === false) {
user_error('Connection closed by server');
return false;
throw new \RuntimeException('Connection closed by server');
}
if ($client_channel == -1 && $response === true) {
return true;
@ -3252,8 +3264,8 @@ class SSH2
return $result;
//case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
default:
user_error('Unable to open channel');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
throw new \RuntimeException('Unable to open channel');
}
break;
case NET_SSH2_MSG_CHANNEL_REQUEST:
@ -3263,8 +3275,8 @@ class SSH2
case NET_SSH2_MSG_CHANNEL_FAILURE:
return false;
default:
user_error('Unable to fulfill channel request');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
throw new \RuntimeException('Unable to fulfill channel request');
}
case NET_SSH2_MSG_CHANNEL_CLOSE:
return $type == NET_SSH2_MSG_CHANNEL_CLOSE ? true : $this->_get_channel_packet($client_channel, $skip_extended);
@ -3369,12 +3381,14 @@ class SSH2
}
$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
return true;
if ($client_channel == $channel) {
return true;
}
case NET_SSH2_MSG_CHANNEL_EOF:
break;
default:
user_error('Error reading channel data');
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
throw new \RuntimeException('Error reading channel data');
}
}
}
@ -3393,9 +3407,8 @@ class SSH2
function _send_binary_packet($data, $logged = null)
{
if (!is_resource($this->fsock) || feof($this->fsock)) {
user_error('Connection closed prematurely');
$this->bitmap = 0;
return false;
throw new \RuntimeException('Connection closed prematurely');
}
//if ($this->compress) {
@ -3486,14 +3499,14 @@ class SSH2
@flush();
@ob_flush();
break;
// basically the same thing as self::LOG_REALTIME with the caveat that self::LOG_REALTIME_FILE
// basically the same thing as self::LOG_REALTIME with the caveat that NET_SFTP_LOG_REALTIME_FILENAME
// needs to be defined and that the resultant log file will be capped out at self::LOG_MAX_SIZE.
// the earliest part of the log file is denoted by the first <<< START >>> and is not going to necessarily
// at the beginning of the file
case self::LOG_REALTIME_FILE:
if (!isset($this->realtime_log_file)) {
// PHP doesn't seem to like using constants in fopen()
$filename = self::LOG_REALTIME_FILENAME;
$filename = NET_SSH2_LOG_REALTIME_FILENAME;
$fp = fopen($filename, 'w');
$this->realtime_log_file = $fp;
}
@ -3958,6 +3971,8 @@ class SSH2
* is recommended. Returns false if the server signature is not signed correctly with the public host key.
*
* @return mixed
* @throws \RuntimeException on badly formatted keys
* @throws \phpseclib\Exception\NoSupportedAlgorithmsException when the key isn't in a supported format
* @access public
*/
function getServerPublicHostKey()
@ -3976,7 +3991,7 @@ class SSH2
if ($this->signature_validated) {
return $this->bitmap ?
$this->signature_format . ' ' . base64_encode($this->server_public_host_key) :
$this->signature_format . ' ' . Base64::encode($this->server_public_host_key) :
false;
}
@ -4003,8 +4018,8 @@ class SSH2
padding, unsigned, and in network byte order). */
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
if ($temp['length'] != 40) {
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new \RuntimeException('Invalid signature');
}
$r = new BigInteger($this->_string_shift($signature, 20), 256);
@ -4015,8 +4030,8 @@ class SSH2
case $r->compare($q) >= 0:
case $s->equals($zero):
case $s->compare($q) >= 0:
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new \RuntimeException('Invalid signature');
}
$w = $s->modInverse($q);
@ -4035,7 +4050,7 @@ class SSH2
list(, $v) = $v->divide($q);
if (!$v->equals($r)) {
user_error('Bad server signature');
//user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
@ -4054,10 +4069,10 @@ class SSH2
$signature = $this->_string_shift($signature, $temp['length']);
$rsa = new RSA();
$rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
$rsa->loadKey(array('e' => $e, 'n' => $n), RSA::PUBLIC_FORMAT_RAW);
if (!$rsa->verify($this->exchange_hash, $signature)) {
user_error('Bad server signature');
$rsa->load(array('e' => $e, 'n' => $n), 'raw');
$rsa->setHash('sha1');
if (!$rsa->verify($this->exchange_hash, $signature, RSA::PADDING_PKCS1)) {
//user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
*/
@ -4072,8 +4087,8 @@ class SSH2
// also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
if ($s->compare(new BigInteger()) < 0 || $s->compare($n->subtract(new BigInteger(1))) > 0) {
user_error('Invalid signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
$this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
throw new \RuntimeException('Invalid signature');
}
$s = $s->modPow($e, $n);
@ -4083,16 +4098,16 @@ class SSH2
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 2 - strlen($h)) . $h;
if ($s != $h) {
user_error('Bad server signature');
//user_error('Bad server signature');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
}
break;
default:
user_error('Unsupported signature format');
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
$this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
throw new NoSupportedAlgorithmsException('Unsupported signature format');
}
return $this->signature_format . ' ' . base64_encode($this->server_public_host_key);
return $this->signature_format . ' ' . Base64::encode($this->server_public_host_key);
}
/**
@ -4165,4 +4180,47 @@ class SSH2
$this->windowColumns = $columns;
$this->windowRows = $rows;
}
/**
* @return string
*/
function __toString()
{
return $this->getResourceId();
}
/**
* We use {} because that symbols should not be in URL according to
* {@link http://tools.ietf.org/html/rfc3986#section-2 RFC}.
* It will safe us from any conflicts, because otherwise regexp will
* match all alphanumeric domains.
*
* @return string
*/
function getResourceId()
{
return '{' . spl_object_hash($this) . '}';
}
/**
* Return existing connection
*
* @param string $id
*
* @return bool|SSH2 will return false if no such connection
*/
static function getConnectionByResourceId($id)
{
return isset(self::$connections[$id]) ? self::$connections[$id] : false;
}
/**
* Return all excising connections
*
* @return SSH2[]
*/
static function getConnections()
{
return self::$connections;
}
}

View File

@ -33,7 +33,9 @@
namespace phpseclib\System\SSH;
use ParagonIE\ConstantTime\Base64;
use phpseclib\Crypt\RSA;
use phpseclib\Exception\BadConfigurationException;
use phpseclib\System\SSH\Agent\Identity;
/**
@ -115,6 +117,8 @@ class Agent
* Default Constructor
*
* @return \phpseclib\System\SSH\Agent
* @throws \phpseclib\Exception\BadConfigurationException if SSH_AUTH_SOCK cannot be found
* @throws \RuntimeException on connection errors
* @access public
*/
function __construct()
@ -127,13 +131,12 @@ class Agent
$address = $_ENV['SSH_AUTH_SOCK'];
break;
default:
user_error('SSH_AUTH_SOCK not found');
return false;
throw new BadConfigurationException('SSH_AUTH_SOCK not found');
}
$this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr);
if (!$this->fsock) {
user_error("Unable to connect to ssh-agent (Error $errno: $errstr)");
throw new \RuntimeException("Unable to connect to ssh-agent (Error $errno: $errstr)");
}
}
@ -144,6 +147,7 @@ class Agent
* Returns an array containing zero or more \phpseclib\System\SSH\Agent\Identity objects
*
* @return array
* @throws \RuntimeException on receipt of unexpected packets
* @access public
*/
function requestIdentities()
@ -154,13 +158,13 @@ class Agent
$packet = pack('NC', 1, self::SSH_AGENTC_REQUEST_IDENTITIES);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed while requesting identities');
throw new \RuntimeException('Connection closed while requesting identities');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != self::SSH_AGENT_IDENTITIES_ANSWER) {
user_error('Unable to request identities');
throw new \RuntimeException('Unable to request identities');
}
$identities = array();
@ -168,7 +172,7 @@ class Agent
for ($i = 0; $i < $keyCount; $i++) {
$length = current(unpack('N', fread($this->fsock, 4)));
$key_blob = fread($this->fsock, $length);
$key_str = 'ssh-rsa ' . base64_encode($key_blob);
$key_str = 'ssh-rsa ' . Base64::encode($key_blob);
$length = current(unpack('N', fread($this->fsock, 4)));
if ($length) {
$key_str.= ' ' . fread($this->fsock, $length);
@ -178,7 +182,7 @@ class Agent
switch ($key_type) {
case 'ssh-rsa':
$key = new RSA();
$key->loadKey($key_str);
$key->load($key_str);
break;
case 'ssh-dss':
// not currently supported
@ -274,6 +278,7 @@ class Agent
*
* @param string $data
* @return data from SSH Agent
* @throws \RuntimeException on connection errors
* @access private
*/
function _forward_data($data)
@ -292,7 +297,7 @@ class Agent
}
if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) {
user_error('Connection closed attempting to forward data to SSH agent');
throw new \RuntimeException('Connection closed attempting to forward data to SSH agent');
}
$this->socket_buffer = '';

View File

@ -15,6 +15,8 @@
namespace phpseclib\System\SSH\Agent;
use phpseclib\Crypt\RSA;
use phpseclib\Exception\UnsupportedAlgorithmException;
use phpseclib\System\SSH\Agent;
/**
@ -23,9 +25,8 @@ use phpseclib\System\SSH\Agent;
* Instantiation should only be performed by \phpseclib\System\SSH\Agent class.
* This could be thought of as implementing an interface that phpseclib\Crypt\RSA
* implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something.
* The methods in this interface would be getPublicKey, setSignatureMode
* and sign since those are the methods phpseclib looks for to perform
* public key authentication.
* The methods in this interface would be getPublicKey and sign since those are the
* methods phpseclib looks for to perform public key authentication.
*
* @package SSH\Agent
* @author Jim Wigginton <terrafrost@php.net>
@ -105,26 +106,29 @@ class Identity
*
* Wrapper for $this->key->getPublicKey()
*
* @param int $format optional
* @param int $type optional
* @return mixed
* @access public
*/
function getPublicKey($format = null)
function getPublicKey($type = 'PKCS8')
{
return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format);
return $this->key->getPublicKey($type);
}
/**
* Set Signature Mode
* Sets the hash
*
* Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie.
* ssh-agent's only supported mode is \phpseclib\Crypt\RSA::SIGNATURE_PKCS1
* ssh-agent only supports signatures with sha1 hashes but to maintain BC with RSA.php this function exists
*
* @param int $mode
* @param string $hash optional
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
* @access public
*/
function setSignatureMode($mode)
function setHash($hash = 'sha1')
{
if ($hash != 'sha1') {
throw new UnsupportedAlgorithmException('ssh-agent can only be used with the sha1 hash');
}
}
/**
@ -133,22 +137,29 @@ class Identity
* See "2.6.2 Protocol 2 private key signature request"
*
* @param string $message
* @param int $padding optional
* @return string
* @throws \RuntimeException on connection errors
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
* @access public
*/
function sign($message)
function sign($message, $padding = RSA::PADDING_PKCS1)
{
if ($padding != RSA::PADDING_PKCS1 && $padding != RSA::PADDING_RELAXED_PKCS1) {
throw new UnsupportedAlgorithmException('ssh-agent can only create PKCS1 signatures');
}
// the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
$packet = pack('CNa*Na*N', Agent::SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0);
$packet = pack('Na*', strlen($packet), $packet);
if (strlen($packet) != fputs($this->fsock, $packet)) {
user_error('Connection closed during signing');
throw new \RuntimeException('Connection closed during signing');
}
$length = current(unpack('N', fread($this->fsock, 4)));
$type = ord(fread($this->fsock, 1));
if ($type != Agent::SSH_AGENT_SIGN_RESPONSE) {
user_error('Unable to retreive signature');
throw new \RuntimeException('Unable to retreive signature');
}
$signature_blob = fread($this->fsock, $length - 1);

View File

@ -1,14 +1,18 @@
<?php
/**
* Bootstrapping File for phpseclib
*
* composer isn't a requirement for phpseclib 2.0 but this file isn't really required
* either. it's a bonus for those using composer but if you're not phpseclib will
* still work
*
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
if (extension_loaded('mbstring')) {
// 2 - MB_OVERLOAD_STRING
if (ini_get('mbstring.func_overload') & 2) {
throw new \UnexpectedValueException(
throw new UnexpectedValueException(
'Overloading of string functions using mbstring.func_overload ' .
'is not supported by phpseclib.'
);

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php"
colors="true"
>
<testsuites>
<testsuite name="phpseclib Unit Test Suite">
<directory>./tests/Unit/</directory>
</testsuite>
<testsuite name="phpseclib Functional Test Suite">
<directory>./tests/Functional/</directory>
</testsuite>
</testsuites>
<!-- Code Coverage -->
<filter>
<whitelist>
<directory>./phpseclib/</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,100 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Net\SCP;
use phpseclib\Net\SSH2;
class Functional_Net_SCPSSH2UserStoryTest extends PhpseclibFunctionalTestCase
{
static protected $remoteFile;
static protected $exampleData;
static protected $exampleDataLength;
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
self::$remoteFile = uniqid('phpseclib-scp-ssh2-') . '.txt';
self::$exampleData = str_repeat('abscp12345', 1000);
self::$exampleDataLength = 10000;
}
public function testConstructSSH2()
{
$ssh = new SSH2($this->getEnv('SSH_HOSTNAME'));
$this->assertTrue(
$ssh->login(
$this->getEnv('SSH_USERNAME'),
$this->getEnv('SSH_PASSWORD')
)
);
return $ssh;
}
/**
* @depends testConstructSSH2
* @param \phpseclib\Net\SSH2 $ssh
*/
public function testConstructor($ssh)
{
$scp = new SCP($ssh);
$this->assertTrue(
is_object($scp),
'Could not construct \phpseclib\Net\SCP object.'
);
return $scp;
}
/**
* @depends testConstructor
* @param \phpseclib\Net\SCP $scp
*/
public function testPutGetString($scp)
{
$this->assertTrue(
$scp->put(self::$remoteFile, self::$exampleData),
'Failed asserting that data could successfully be put() into file.'
);
$content = $scp->get(self::$remoteFile);
// TODO: Address https://github.com/phpseclib/phpseclib/issues/146
$this->assertContains(
strlen($content),
array(self::$exampleDataLength, self::$exampleDataLength + 1),
'Failed asserting that string length matches expected length.'
);
$this->assertContains(
$content,
array(self::$exampleData, self::$exampleData . "\0"),
'Failed asserting that string content matches expected content.'
);
return $scp;
}
/**
* @depends testPutGetString
* @param \phpseclib\Net\SCP $scp
*/
public function testGetFile($scp)
{
$localFilename = $this->createTempFile();
$this->assertTrue(
$scp->get(self::$remoteFile, $localFilename),
'Failed asserting that get() into file was successful.'
);
// TODO: Address https://github.com/phpseclib/phpseclib/issues/146
$this->assertContains(
filesize($localFilename),
array(self::$exampleDataLength, self::$exampleDataLength + 1),
'Failed asserting that filesize matches expected data size.'
);
$this->assertContains(
file_get_contents($localFilename),
array(self::$exampleData, self::$exampleData . "\0"),
'Failed asserting that file content matches expected content.'
);
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
use phpseclib\Net\SFTP;
class Functional_Net_SFTPLargeFileTest extends Functional_Net_SFTPTestCase
{
public static function setUpBeforeClass()
{
if (!extension_loaded('mcrypt') && !extension_loaded('openssl')) {
self::markTestSkipped('This test depends on mcrypt or openssl for performance.');
}
parent::setUpBeforeClass();
}
/**
* @group github298
* @group github455
* @group github457
*/
public function testPutSizeLocalFile()
{
$tmp_filename = $this->createTempFile(128, 1024 * 1024);
$filename = 'file-large-from-local.txt';
$this->assertTrue(
$this->sftp->put($filename, $tmp_filename, SFTP::SOURCE_LOCAL_FILE),
'Failed asserting that local file could be successfully put().'
);
$this->assertSame(
128 * 1024 * 1024,
$this->sftp->size($filename),
'Failed asserting that uploaded local file has the expected length.'
);
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2015 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Net\SFTP\Stream;
class Functional_Net_SFTPStreamTest extends Functional_Net_SFTPTestCase
{
public static function setUpBeforeClass()
{
Stream::register();
parent::setUpBeforeClass();
}
public function testFopenFcloseCreatesFile()
{
$context = stream_context_create(array(
'sftp' => array('session' => $this->sftp),
));
$fp = fopen($this->buildUrl('fooo.txt'), 'wb', false, $context);
$this->assertTrue(is_resource($fp));
fclose($fp);
$this->assertSame(0, $this->sftp->size('fooo.txt'));
}
/**
* @group github778
*/
public function testFilenameWithHash()
{
$context = stream_context_create(array(
'sftp' => array('session' => $this->sftp),
));
$fp = fopen($this->buildUrl('te#st.txt'), 'wb', false, $context);
fputs($fp, 'zzzz');
fclose($fp);
$this->assertTrue(in_array('te#st.txt', $this->sftp->nlist()));
}
/**
* Tests connection reuse functionality same as ssh2 extension:
* {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
*/
public function testConnectionReuse()
{
$originalConnectionsCount = count(\phpseclib\Net\SSH2::getConnections());
$session = $this->sftp;
$dirs = scandir("sftp://$session/");
$this->assertCount($originalConnectionsCount, \phpseclib\Net\SSH2::getConnections());
$this->assertEquals(array('.', '..'), array_slice($dirs, 0, 2));
}
protected function buildUrl($suffix)
{
return sprintf(
'sftp://via-context/%s/%s',
$this->sftp->pwd(),
$suffix
);
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2015 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Net\SFTP;
/**
* This class provides each test method with a new and empty $this->scratchDir.
*/
abstract class Functional_Net_SFTPTestCase extends PhpseclibFunctionalTestCase
{
/**
* @var SFTP
*/
protected $sftp;
protected $scratchDir;
public function setUp()
{
parent::setUp();
$this->scratchDir = uniqid('phpseclib-sftp-scratch-');
$this->sftp = new SFTP($this->getEnv('SSH_HOSTNAME'));
$this->assertTrue($this->sftp->login(
$this->getEnv('SSH_USERNAME'),
$this->getEnv('SSH_PASSWORD')
));
$this->assertTrue($this->sftp->mkdir($this->scratchDir));
$this->assertTrue($this->sftp->chdir($this->scratchDir));
}
public function tearDown()
{
if ($this->sftp) {
$this->sftp->chdir($this->getEnv('SSH_HOME'));
$this->sftp->delete($this->scratchDir);
}
parent::tearDown();
}
}

View File

@ -0,0 +1,728 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Net\SFTP;
class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
{
static protected $scratchDir;
static protected $exampleData;
static protected $exampleDataLength;
static protected $buffer;
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
self::$scratchDir = uniqid('phpseclib-sftp-scratch-');
self::$exampleData = str_repeat('abcde12345', 1000);
self::$exampleDataLength = 10000;
}
public function testConstructor()
{
$sftp = new SFTP($this->getEnv('SSH_HOSTNAME'));
$this->assertTrue(
is_object($sftp),
'Could not construct NET_SFTP object.'
);
return $sftp;
}
/**
* @depends testConstructor
*/
public function testPasswordLogin($sftp)
{
$username = $this->getEnv('SSH_USERNAME');
$password = $this->getEnv('SSH_PASSWORD');
$this->assertTrue(
$sftp->login($username, $password),
'SSH2/SFTP login using password failed.'
);
return $sftp;
}
/**
* @depends testPasswordLogin
*/
public function testPwdHome($sftp)
{
$this->assertEquals(
$this->getEnv('SSH_HOME'),
$sftp->pwd(),
'Failed asserting that pwd() returns home directory after login.'
);
return $sftp;
}
/**
* @depends testPwdHome
*/
public function testMkDirScratch($sftp)
{
$dirname = self::$scratchDir;
$this->assertTrue(
$sftp->mkdir($dirname),
"Failed asserting that a new scratch directory $dirname could " .
'be created.'
);
$this->assertFalse(
$sftp->mkdir($dirname),
"Failed asserting that a new scratch directory $dirname could " .
'not be created (because it already exists).'
);
return $sftp;
}
/**
* @depends testMkDirScratch
*/
public function testChDirScratch($sftp)
{
$this->assertTrue(
$sftp->chdir(self::$scratchDir),
sprintf(
'Failed asserting that working directory could be changed ' .
'to scratch directory %s.',
self::$scratchDir
)
);
$pwd = $sftp->pwd();
$this->assertStringStartsWith(
$this->getEnv('SSH_HOME'),
$pwd,
'Failed asserting that the home directory is a prefix of the ' .
'current working directory.'
);
$this->assertStringEndsWith(
self::$scratchDir,
$pwd,
'Failed asserting that the scratch directory name is a suffix ' .
'of the current working directory.'
);
return $sftp;
}
/**
* @depends testChDirScratch
*/
public function testStatOnDir($sftp)
{
$this->assertNotSame(
array(),
$sftp->stat('.'),
'Failed asserting that the cwd has a non-empty stat.'
);
return $sftp;
}
/**
* @depends testStatOnDir
*/
public function testPutSizeGetFile($sftp)
{
$this->assertTrue(
$sftp->put('file1.txt', self::$exampleData),
'Failed asserting that example data could be successfully put().'
);
$this->assertSame(
self::$exampleDataLength,
$sftp->size('file1.txt'),
'Failed asserting that put example data has the expected length'
);
$this->assertSame(
self::$exampleData,
$sftp->get('file1.txt'),
'Failed asserting that get() returns expected example data.'
);
return $sftp;
}
static function callback($length)
{
$r = substr(self::$buffer, 0, $length);
self::$buffer = substr(self::$buffer, $length);
if (strlen($r)) {
return $r;
}
return null;
}
/**
* @depends testStatOnDir
*/
public function testPutSizeGetFileCallback($sftp)
{
self::$buffer = self::$exampleData;
$this->assertTrue(
$sftp->put('file1.txt', array(__CLASS__, 'callback'), $sftp::SOURCE_CALLBACK),
'Failed asserting that example data could be successfully put().'
);
$this->assertSame(
self::$exampleDataLength,
$sftp->size('file1.txt'),
'Failed asserting that put example data has the expected length'
);
$this->assertSame(
self::$exampleData,
$sftp->get('file1.txt'),
'Failed asserting that get() returns expected example data.'
);
return $sftp;
}
/**
* @depends testPutSizeGetFile
*/
public function testTouch($sftp)
{
$this->assertTrue(
$sftp->touch('file2.txt'),
'Failed asserting that touch() successfully ran.'
);
$this->assertTrue(
$sftp->file_exists('file2.txt'),
'Failed asserting that touch()\'d file exists'
);
return $sftp;
}
/**
* @depends testTouch
*/
public function testTruncate($sftp)
{
$this->assertTrue(
$sftp->touch('file3.txt'),
'Failed asserting that touch() successfully ran.'
);
$this->assertTrue(
$sftp->truncate('file3.txt', 1024 * 1024),
'Failed asserting that touch() successfully ran.'
);
$this->assertSame(
1024 * 1024,
$sftp->size('file3.txt'),
'Failed asserting that truncate()\'d file has the expected length'
);
return $sftp;
}
/**
* @depends testTruncate
* @group github850
*/
public function testChModOnFile($sftp)
{
$this->assertNotFalse(
$sftp->chmod(0755, 'file1.txt'),
'Failed asserting that chmod() was successful.'
);
return $sftp;
}
/**
* @depends testChModOnFile
*/
public function testChDirOnFile($sftp)
{
$this->assertFalse(
$sftp->chdir('file1.txt'),
'Failed to assert that the cwd cannot be changed to a file'
);
return $sftp;
}
/**
* @depends testChDirOnFile
*/
public function testFileExistsIsFileIsDirFile($sftp)
{
$this->assertTrue(
$sftp->file_exists('file1.txt'),
'Failed asserting that file_exists() on example file returns true.'
);
$this->assertTrue(
$sftp->is_file('file1.txt'),
'Failed asserting that is_file() on example file returns true.'
);
$this->assertFalse(
$sftp->is_dir('file1.txt'),
'Failed asserting that is_dir() on example file returns false.'
);
return $sftp;
}
/**
* @depends testFileExistsIsFileIsDirFile
*/
public function testFileExistsIsFileIsDirFileNonexistent($sftp)
{
$this->assertFalse(
$sftp->file_exists('file4.txt'),
'Failed asserting that a nonexistent file does not exist.'
);
$this->assertFalse(
$sftp->is_file('file4.txt'),
'Failed asserting that is_file() on nonexistent file returns false.'
);
$this->assertFalse(
$sftp->is_dir('file4.txt'),
'Failed asserting that is_dir() on nonexistent file returns false.'
);
return $sftp;
}
/**
* @depends testFileExistsIsFileIsDirFileNonexistent
*/
public function testSortOrder($sftp)
{
$this->assertTrue(
$sftp->mkdir('temp'),
"Failed asserting that a new scratch directory temp could " .
'be created.'
);
$sftp->setListOrder('filename', SORT_DESC);
$list = $sftp->nlist();
$expected = array('.', '..', 'temp', 'file3.txt', 'file2.txt', 'file1.txt');
$this->assertSame(
$list,
$expected,
'Failed asserting that list sorted correctly.'
);
$sftp->setListOrder('filename', SORT_ASC);
$list = $sftp->nlist();
$expected = array('.', '..', 'temp', 'file1.txt', 'file2.txt', 'file3.txt');
$this->assertSame(
$list,
$expected,
'Failed asserting that list sorted correctly.'
);
$sftp->setListOrder('size', SORT_DESC);
$files = $sftp->nlist();
$last_size = 0x7FFFFFFF;
foreach ($files as $file) {
if ($sftp->is_file($file)) {
$cur_size = $sftp->size($file);
$this->assertLessThanOrEqual(
$last_size,
$cur_size,
'Failed asserting that nlist() is in descending order'
);
$last_size = $cur_size;
}
}
return $sftp;
}
/**
* @depends testSortOrder
*/
public function testResourceXfer($sftp)
{
$fp = fopen('res.txt', 'w+');
$sftp->get('file1.txt', $fp);
rewind($fp);
$sftp->put('file4.txt', $fp);
fclose($fp);
$this->assertSame(
self::$exampleData,
$sftp->get('file4.txt'),
'Failed asserting that a file downloaded into a resource and reuploaded from a resource has the correct data'
);
return $sftp;
}
/**
* @depends testResourceXfer
*/
public function testSymlink($sftp)
{
$this->assertTrue(
$sftp->symlink('file3.txt', 'symlink'),
'Failed asserting that a symlink could be created'
);
return $sftp;
}
/**
* @depends testSymlink
*/
public function testStatLstatCache($sftp)
{
$stat = $sftp->stat('symlink');
$lstat = $sftp->lstat('symlink');
$this->assertNotEquals(
$stat,
$lstat,
'Failed asserting that stat and lstat returned different output for a symlink'
);
return $sftp;
}
/**
* @depends testStatLstatCache
*/
public function testLinkFile($sftp)
{
$this->assertTrue(
$sftp->is_link('symlink'),
'Failed asserting that symlink is a link'
);
$this->assertTrue(
$sftp->is_file('symlink'),
'Failed asserting that symlink is a file'
);
$this->assertFalse(
$sftp->is_dir('symlink'),
'Failed asserting that symlink is not a directory'
);
return $sftp;
}
/**
* @depends testLinkFile
*/
public function testReadlink($sftp)
{
$this->assertInternalType(
'string',
$sftp->readlink('symlink'),
'Failed asserting that a symlink\'s target could be read'
);
return $sftp;
}
/**
* @depends testReadlink
* @group github716
*/
public function testStatOnCWD($sftp)
{
$stat = $sftp->stat('.');
$this->assertInternalType(
'array',
$stat,
'Failed asserting that stat on . returns an array'
);
$lstat = $sftp->lstat('.');
$this->assertInternalType(
'array',
$lstat,
'Failed asserting that lstat on . returns an array'
);
return $sftp;
}
/**
* on older versions this would result in a fatal error
* @depends testStatOnCWD
* @group github402
*/
public function testStatcacheFix($sftp)
{
// Name used for both directory and file.
$name = 'stattestdir';
$this->assertTrue($sftp->mkdir($name));
$this->assertTrue($sftp->is_dir($name));
$this->assertTrue($sftp->chdir($name));
$this->assertStringEndsWith(self::$scratchDir . '/' . $name, $sftp->pwd());
$this->assertFalse($sftp->file_exists($name));
$this->assertTrue($sftp->touch($name));
$this->assertTrue($sftp->is_file($name));
$this->assertTrue($sftp->chdir('..'));
$this->assertStringEndsWith(self::$scratchDir, $sftp->pwd());
$this->assertTrue($sftp->is_dir($name));
$this->assertTrue($sftp->is_file("$name/$name"));
$this->assertTrue($sftp->delete($name, true));
return $sftp;
}
/**
* @depends testStatcacheFix
*/
public function testChDirUpHome($sftp)
{
$this->assertTrue(
$sftp->chdir('../'),
'Failed asserting that directory could be changed one level up.'
);
$this->assertEquals(
$this->getEnv('SSH_HOME'),
$sftp->pwd(),
'Failed asserting that pwd() returns home directory.'
);
return $sftp;
}
/**
* @depends testChDirUpHome
*/
public function testFileExistsIsFileIsDirDir($sftp)
{
$this->assertTrue(
$sftp->file_exists(self::$scratchDir),
'Failed asserting that file_exists() on scratch dir returns true.'
);
$this->assertFalse(
$sftp->is_file(self::$scratchDir),
'Failed asserting that is_file() on example file returns false.'
);
$this->assertTrue(
$sftp->is_dir(self::$scratchDir),
'Failed asserting that is_dir() on example file returns true.'
);
return $sftp;
}
/**
* @depends testFileExistsIsFileIsDirDir
*/
public function testTruncateLargeFile($sftp)
{
$filesize = (4 * 1024 + 16) * 1024 * 1024;
$filename = 'file-large-from-truncate-4112MiB.txt';
$this->assertTrue($sftp->touch($filename));
$this->assertTrue($sftp->truncate($filename, $filesize));
$this->assertSame($filesize, $sftp->size($filename));
return $sftp;
}
/**
* @depends testTruncateLargeFile
*/
public function testRmDirScratch($sftp)
{
$this->assertFalse(
$sftp->rmdir(self::$scratchDir),
'Failed asserting that non-empty scratch directory could ' .
'not be deleted using rmdir().'
);
return $sftp;
}
/**
* @depends testRmDirScratch
*/
public function testDeleteRecursiveScratch($sftp)
{
$this->assertTrue(
$sftp->delete(self::$scratchDir),
'Failed asserting that non-empty scratch directory could ' .
'be deleted using recursive delete().'
);
return $sftp;
}
/**
* @depends testDeleteRecursiveScratch
*/
public function testRmDirScratchNonexistent($sftp)
{
$this->assertFalse(
$sftp->rmdir(self::$scratchDir),
'Failed asserting that nonexistent scratch directory could ' .
'not be deleted using rmdir().'
);
return $sftp;
}
/**
* @depends testRmDirScratchNonexistent
* @group github706
*/
public function testDeleteEmptyDir($sftp)
{
$this->assertTrue(
$sftp->mkdir(self::$scratchDir),
'Failed asserting that scratch directory could ' .
'be created.'
);
$this->assertInternalType(
'array',
$sftp->stat(self::$scratchDir),
'Failed asserting that stat on an existant empty directory returns an array'
);
$this->assertTrue(
$sftp->delete(self::$scratchDir),
'Failed asserting that empty scratch directory could ' .
'be deleted using recursive delete().'
);
$this->assertFalse(
$sftp->stat(self::$scratchDir),
'Failed asserting that stat on a deleted directory returns false'
);
return $sftp;
}
/**
* @depends testDeleteEmptyDir
* @group github735
*/
public function testStatVsLstat($sftp)
{
$this->assertTrue($sftp->mkdir(self::$scratchDir));
$this->assertTrue($sftp->chdir(self::$scratchDir));
$this->assertTrue($sftp->put('text.txt', 'zzzzz'));
$this->assertTrue($sftp->symlink('text.txt', 'link.txt'));
$this->assertTrue($sftp->mkdir('subdir'));
$this->assertTrue($sftp->symlink('subdir', 'linkdir'));
$sftp->clearStatCache();
// pre-populate the stat cache
$sftp->nlist();
$stat = $sftp->stat('link.txt');
$this->assertSame($stat['type'], NET_SFTP_TYPE_REGULAR);
$stat = $sftp->lstat('link.txt');
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
$stat = $sftp->stat('linkdir');
$this->assertSame($stat['type'], NET_SFTP_TYPE_DIRECTORY);
$stat = $sftp->lstat('link.txt');
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
$sftp->disableStatCache();
$sftp->nlist();
$stat = $sftp->stat('link.txt');
$this->assertSame($stat['type'], NET_SFTP_TYPE_REGULAR);
$stat = $sftp->lstat('link.txt');
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
$stat = $sftp->stat('linkdir');
$this->assertSame($stat['type'], NET_SFTP_TYPE_DIRECTORY);
$stat = $sftp->lstat('link.txt');
$this->assertSame($stat['type'], NET_SFTP_TYPE_SYMLINK);
$sftp->enableStatCache();
return $sftp;
}
/**
* @depends testStatVsLstat
* @group github830
*/
public function testUploadOffsets($sftp)
{
$sftp->put('offset.txt', 'res.txt', SFTP::SOURCE_LOCAL_FILE, 0, 10);
$this->assertSame(
substr(self::$exampleData, 10),
$sftp->get('offset.txt'),
'Failed asserting that portions of a file could be uploaded.'
);
$sftp->put('offset.txt', 'res.txt', SFTP::SOURCE_LOCAL_FILE, self::$exampleDataLength - 100);
$this->assertSame(
substr(self::$exampleData, 10, -90) . self::$exampleData,
$sftp->get('offset.txt'),
'Failed asserting that you could upload into the middle of a file.'
);
return $sftp;
}
/**
* @depends testUploadOffsets
*/
public function testReadableWritable($sftp)
{
$sftp->chmod(0000, 'offset.txt');
$this->assertFalse($sftp->is_writable('offset.txt'));
$this->assertFalse($sftp->is_writeable('offset.txt'));
$this->assertFalse($sftp->is_readable('offset.txt'));
$sftp->chmod(0777, 'offset.txt');
$this->assertTrue($sftp->is_writable('offset.txt'));
$this->assertTrue($sftp->is_writeable('offset.txt'));
$this->assertTrue($sftp->is_readable('offset.txt'));
$this->assertFalse($sftp->is_writable('nonexistantfile.ext'));
$this->assertFalse($sftp->is_writeable('nonexistantfile.ext'));
$this->assertFalse($sftp->is_readable('nonexistantfile.ext'));
return $sftp;
}
/**
* @depends testReadableWritable
* @group github999
*/
public function testExecNlist($sftp)
{
$sftp->enablePTY();
$sftp->exec('ping google.com -c 5');
sleep(5);
$sftp->nlist();
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Net\SSH2;
use phpseclib\System\SSH\Agent;
class Functional_Net_SSH2AgentTest extends PhpseclibFunctionalTestCase
{
public static function setUpBeforeClass()
{
if (!isset($_SERVER['SSH_AUTH_SOCK'])) {
self::markTestSkipped(
'This test requires an SSH Agent (SSH_AUTH_SOCK env variable).'
);
}
parent::setUpBeforeClass();
}
public function testAgentLogin()
{
$ssh = new SSH2($this->getEnv('SSH_HOSTNAME'));
$agent = new Agent;
$this->assertTrue(
$ssh->login($this->getEnv('SSH_USERNAME'), $agent),
'SSH2 login using Agent failed.'
);
return array('ssh' => $ssh, 'ssh-agent' => $agent);
}
/**
* @depends testAgentLogin
*/
public function testAgentForward($args)
{
$ssh = $args['ssh'];
$agent = $args['ssh-agent'];
$hostname = $this->getEnv('SSH_HOSTNAME');
$username = $this->getEnv('SSH_USERNAME');
$this->assertEquals($username, trim($ssh->exec('whoami')));
$agent->startSSHForwarding($ssh);
$this->assertEquals($username, trim($ssh->exec("ssh " . $username . "@" . $hostname . ' \'whoami\'')));
return $args;
}
}

View File

@ -0,0 +1,138 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Net\SSH2;
class Functional_Net_SSH2Test extends PhpseclibFunctionalTestCase
{
public function testConstructor()
{
$ssh = new SSH2($this->getEnv('SSH_HOSTNAME'));
$this->assertTrue(
is_object($ssh),
'Could not construct NET_SSH2 object.'
);
return $ssh;
}
/**
* @depends testConstructor
* @group github408
* @group github412
*/
public function testPreLogin($ssh)
{
$this->assertFalse(
$ssh->isConnected(),
'Failed asserting that SSH2 is not connected after construction.'
);
$this->assertFalse(
$ssh->isAuthenticated(),
'Failed asserting that SSH2 is not authenticated after construction.'
);
$this->assertNotEmpty(
$ssh->getServerPublicHostKey(),
'Failed asserting that a non-empty public host key was fetched.'
);
$this->assertTrue(
$ssh->isConnected(),
'Failed asserting that SSH2 is connected after public key fetch.'
);
$this->assertNotEmpty(
$ssh->getServerIdentification(),
'Failed asserting that the server identifier was set after connect.'
);
return $ssh;
}
/**
* @depends testPreLogin
*/
public function testBadPassword($ssh)
{
$username = $this->getEnv('SSH_USERNAME');
$password = $this->getEnv('SSH_PASSWORD');
$this->assertFalse(
$ssh->login($username, 'zzz' . $password),
'SSH2 login using password succeeded.'
);
$this->assertTrue(
$ssh->isConnected(),
'Failed asserting that SSH2 is connected after bad login attempt.'
);
$this->assertFalse(
$ssh->isAuthenticated(),
'Failed asserting that SSH2 is not authenticated after bad login attempt.'
);
return $ssh;
}
/**
* @depends testBadPassword
*/
public function testPasswordLogin($ssh)
{
$username = $this->getEnv('SSH_USERNAME');
$password = $this->getEnv('SSH_PASSWORD');
$this->assertTrue(
$ssh->login($username, $password),
'SSH2 login using password failed.'
);
$this->assertTrue(
$ssh->isAuthenticated(),
'Failed asserting that SSH2 is authenticated after good login attempt.'
);
return $ssh;
}
/**
* @depends testPasswordLogin
* @group github280
*/
public function testExecWithMethodCallback($ssh)
{
$callbackObject = $this->getMock('stdClass', array('callbackMethod'));
$callbackObject
->expects($this->atLeastOnce())
->method('callbackMethod')
->will($this->returnValue(true));
$ssh->exec('pwd', array($callbackObject, 'callbackMethod'));
}
public function testGetServerPublicHostKey()
{
$ssh = new SSH2($this->getEnv('SSH_HOSTNAME'));
$this->assertInternalType('string', $ssh->getServerPublicHostKey());
}
public function testOpenSocketConnect()
{
$fsock = fsockopen($this->getEnv('SSH_HOSTNAME'), 22);
$ssh = new SSH2($fsock);
$username = $this->getEnv('SSH_USERNAME');
$password = $this->getEnv('SSH_PASSWORD');
$this->assertTrue(
$ssh->login($username, $password),
'SSH2 login using an open socket failed.'
);
}
}

View File

@ -0,0 +1,73 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Hash;
use phpseclib\Math\BigInteger;
abstract class PhpseclibFunctionalTestCase extends PhpseclibTestCase
{
public static function setUpBeforeClass()
{
if (extension_loaded('runkit')) {
if (extension_loaded('gmp')) {
self::ensureConstant(
'MATH_BIGINTEGER_MODE',
BigInteger::MODE_GMP
);
} elseif (extension_loaded('bcmath')) {
self::ensureConstant(
'MATH_BIGINTEGER_MODE',
BigInteger::MODE_BCMATH
);
} else {
self::markTestSkipped(
'Should have gmp or bcmath extension for functional test.'
);
}
self::reRequireFile('Math/BigInteger.php');
}
parent::setUpBeforeClass();
}
/**
* @param string $variable
* @param string|null $message
*
* @return null
*/
protected function requireEnv($variable, $message = null)
{
if ($this->_getEnv($variable) === false) {
$msg = $message ? $message : sprintf(
"This test requires the '%s' environment variable.",
$this->_prefixEnvVariable($variable)
);
$this->markTestSkipped($msg);
}
}
/**
* @param string $variable
*
* @return string
*/
protected function getEnv($variable)
{
$this->requireEnv($variable);
return $this->_getEnv($variable);
}
private function _getEnv($variable)
{
return getenv($this->_prefixEnvVariable($variable));
}
private function _prefixEnvVariable($variable)
{
return 'PHPSECLIB_' . $variable;
}
}

View File

@ -0,0 +1,104 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
abstract class PhpseclibTestCase extends PHPUnit_Framework_TestCase
{
protected $tempFilesToUnlinkOnTearDown = array();
public function tearDown()
{
foreach ($this->tempFilesToUnlinkOnTearDown as $filename) {
if (!file_exists($filename) || unlink($filename)) {
unset($this->tempFilesToUnlinkOnTearDown[$filename]);
}
}
parent::tearDown();
}
/**
* Creates a temporary file on the local filesystem and returns its path.
* The $number_of_writes and $bytes_per_write parameters can be used to
* write $number_of_writes * $bytes_per_write times the character 'a' to the
* temporary file. All files created using this method will be deleted from
* the filesystem on tearDown(), i.e. after each test method was run.
*
* @param int $number_of_writes
* @param int $bytes_per_write
*
* @return string
*/
protected function createTempFile($number_of_writes = 0, $bytes_per_write = 0)
{
$filename = tempnam(sys_get_temp_dir(), 'phpseclib-test-');
$this->assertTrue(file_exists($filename));
$this->tempFilesToUnlinkOnTearDown[] = $filename;
if ($number_of_writes > 0 && $bytes_per_write > 0) {
$fp = fopen($filename, 'wb');
for ($i = 0; $i < $number_of_writes; ++$i) {
fwrite($fp, str_repeat('a', $bytes_per_write));
}
fclose($fp);
$this->assertSame($number_of_writes * $bytes_per_write, filesize($filename));
}
return $filename;
}
/**
* @param string $constant
* @param mixed $expected
*
* @return null
*/
protected static function ensureConstant($constant, $expected)
{
if (defined($constant)) {
$value = constant($constant);
if ($value !== $expected) {
if (extension_loaded('runkit')) {
if (!runkit_constant_redefine($constant, $expected)) {
self::markTestSkipped(sprintf(
"Failed to redefine constant %s to %s",
$constant,
$expected
));
}
} else {
self::markTestSkipped(sprintf(
"Skipping test because constant %s is %s instead of %s",
$constant,
$value,
$expected
));
}
}
} else {
define($constant, $expected);
}
}
/**
* @param string $filename Filename relative to library directory.
*
* @return null
*/
protected static function reRequireFile($filename)
{
if (extension_loaded('runkit')) {
$result = runkit_import(
sprintf('%s/../phpseclib/%s', __DIR__, $filename),
RUNKIT_IMPORT_FUNCTIONS |
RUNKIT_IMPORT_CLASS_METHODS |
RUNKIT_IMPORT_OVERRIDE
);
if (!$result) {
self::markTestSkipped("Failed to reimport file $filename");
}
}
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
class Unit_Crypt_AES_InternalTest extends Unit_Crypt_AES_TestCase
{
protected function setUp()
{
$this->engine = Base::ENGINE_INTERNAL;
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
class Unit_Crypt_AES_McryptTest extends Unit_Crypt_AES_TestCase
{
protected function setUp()
{
$this->engine = Base::ENGINE_MCRYPT;
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
class Unit_Crypt_AES_OpenSSLTest extends Unit_Crypt_AES_TestCase
{
protected function setUp()
{
$this->engine = Base::ENGINE_OPENSSL;
}
}

View File

@ -0,0 +1,401 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\AES;
use phpseclib\Crypt\Base;
use phpseclib\Crypt\Rijndael;
abstract class Unit_Crypt_AES_TestCase extends PhpseclibTestCase
{
protected $engine;
private function _checkEngine($aes)
{
if ($aes->getEngine() != $this->engine) {
$engine = 'internal';
switch ($this->engine) {
case Base::ENGINE_OPENSSL:
$engine = 'OpenSSL';
break;
case Base::ENGINE_MCRYPT:
$engine = 'mcrypt';
}
self::markTestSkipped('Unable to initialize ' . $engine . ' engine');
}
}
/**
* Produces all combinations of test values.
*
* @return array
*/
public function continuousBufferCombos()
{
$modes = array(
Base::MODE_CTR,
Base::MODE_OFB,
Base::MODE_CFB,
);
$plaintexts = array(
'',
'12345678901234567', // https://github.com/phpseclib/phpseclib/issues/39
"\xDE\xAD\xBE\xAF",
':-):-):-):-):-):-)', // https://github.com/phpseclib/phpseclib/pull/43
);
$ivs = array(
str_repeat("\0", 16),
str_pad('test123', 16, "\0"),
);
$keys = array(
str_repeat("\0", 16),
str_pad(':-8', 16, "\0"), // https://github.com/phpseclib/phpseclib/pull/43
str_pad('FOOBARZ', 16, "\0"),
);
$result = array();
foreach ($modes as $mode) {
foreach ($plaintexts as $plaintext) {
foreach ($ivs as $iv) {
foreach ($keys as $key) {
$result[] = array($mode, $plaintext, $iv, $key);
}
}
}
}
return $result;
}
/**
* @dataProvider continuousBufferCombos
*/
public function testEncryptDecryptWithContinuousBuffer($mode, $plaintext, $iv, $key)
{
$aes = new AES($mode);
$aes->setPreferredEngine($this->engine);
$aes->enableContinuousBuffer();
$aes->setIV($iv);
$aes->setKey($key);
$this->_checkEngine($aes);
$actual = '';
for ($i = 0, $strlen = strlen($plaintext); $i < $strlen; ++$i) {
$actual .= $aes->decrypt($aes->encrypt($plaintext[$i]));
}
$this->assertEquals($plaintext, $actual);
}
/**
* @group github451
*/
public function testKeyPaddingRijndael()
{
// this test case is from the following URL:
// https://web.archive.org/web/20070209120224/http://fp.gladman.plus.com/cryptography_technology/rijndael/aesdvec.zip
$aes = new Rijndael(Base::MODE_CBC);
$aes->setPreferredEngine($this->engine);
$aes->disablePadding();
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. Valid in Rijndael.
$aes->setIV(str_repeat("\0", 16));
//$this->_checkEngine($aes); // should only work in internal mode
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
$this->assertEquals($ciphertext, pack('H*', '231d844639b31b412211cfe93712b880'));
}
/**
* @group github451
* @expectedException \LengthException
*/
public function testKeyPaddingAES()
{
// same as the above - just with a different ciphertext
$aes = new AES(Base::MODE_CBC);
$aes->setPreferredEngine($this->engine);
$aes->disablePadding();
$aes->setKey(pack('H*', '2b7e151628aed2a6abf7158809cf4f3c762e7160')); // 160-bit key. supported by Rijndael - not AES
$aes->setIV(str_repeat("\0", 16));
$this->_checkEngine($aes);
$ciphertext = $aes->encrypt(pack('H*', '3243f6a8885a308d313198a2e0370734'));
$this->assertEquals($ciphertext, pack('H*', 'c109292b173f841b88e0ee49f13db8c0'));
}
/**
* Produces all combinations of test values.
*
* @return array
*/
public function continuousBufferBatteryCombos()
{
$modes = array(
Base::MODE_CTR,
Base::MODE_OFB,
Base::MODE_CFB,
);
$combos = array(
array(16),
array(17),
array(1, 16),
array(3, 6, 7), // (3 to test the openssl_encrypt call and the buffer creation, 6 to test the exclusive use of the buffer and 7 to test the buffer's exhaustion and recreation)
array(15, 4), // (15 to test openssl_encrypt call and buffer creation and 4 to test something that spans multpile bloc
array(3, 6, 10, 16), // this is why the strlen check in the buffer-only code was needed
array(16, 16), // two full size blocks
array(3, 6, 7, 16), // partial block + full size block
array(16, 3, 6, 7),
// a few others just for fun
array(32,32),
array(31,31),
array(17,17),
array(99, 99)
);
$result = array();
foreach ($modes as $mode) {
foreach ($combos as $combo) {
foreach (array('encrypt', 'decrypt') as $op) {
$result[] = array($op, $mode, $combo);
}
}
}
return $result;
}
/**
* @dataProvider continuousBufferBatteryCombos
*/
public function testContinuousBufferBattery($op, $mode, $test)
{
$iv = str_repeat('x', 16);
$key = str_repeat('a', 16);
$aes = new AES($mode);
$aes->setPreferredEngine($this->engine);
$aes->setKey($key);
$aes->setIV($iv);
$this->_checkEngine($aes);
$str = '';
$result = '';
foreach ($test as $len) {
$temp = str_repeat('d', $len);
$str.= $temp;
}
$c1 = $aes->$op($str);
$aes = new AES($mode);
$aes->setPreferredEngine($this->engine);
$aes->enableContinuousBuffer();
$aes->setKey($key);
$aes->setIV($iv);
if (!$this->_checkEngine($aes)) {
return;
}
foreach ($test as $len) {
$temp = str_repeat('d', $len);
$output = $aes->$op($temp);
$result.= $output;
}
$c2 = $result;
$this->assertSame(bin2hex($c1), bin2hex($c2));
}
/**
* Pretty much the same as testContinuousBufferBattery with the caveat that continuous mode is not enabled.
*
* @dataProvider continuousBufferBatteryCombos
*/
public function testNonContinuousBufferBattery($op, $mode, $test)
{
if (count($test) == 1) {
return;
}
$iv = str_repeat('x', 16);
$key = str_repeat('a', 16);
$aes = new AES($mode);
$aes->setPreferredEngine($this->engine);
$aes->setKey($key);
$aes->setIV($iv);
$this->_checkEngine($aes);
$str = '';
$result = '';
foreach ($test as $len) {
$temp = str_repeat('d', $len);
$str.= $temp;
}
$c1 = $aes->$op($str);
$aes = new AES($mode);
$aes->setPreferredEngine($this->engine);
$aes->setKey($key);
$aes->setIV($iv);
$this->_checkEngine($aes);
foreach ($test as $len) {
$temp = str_repeat('d', $len);
$output = $aes->$op($temp);
$result.= $output;
}
$c2 = $result;
$this->assertNotSame(bin2hex($c1), bin2hex($c2));
}
// from http://csrc.nist.gov/groups/STM/cavp/documents/aes/AESAVS.pdf#page=16
public function testGFSBox128()
{
$aes = new AES(Base::MODE_CBC);
$aes->setKey(pack('H*', '00000000000000000000000000000000'));
$aes->setIV(pack('H*', '00000000000000000000000000000000'));
$aes->disablePadding();
$aes->setPreferredEngine($this->engine);
$this->_checkEngine($aes);
$result = bin2hex($aes->encrypt(pack('H*', 'f34481ec3cc627bacd5dc3fb08f273e6')));
$this->assertSame($result, '0336763e966d92595a567cc9ce537f5e');
$result = bin2hex($aes->encrypt(pack('H*', '9798c4640bad75c7c3227db910174e72')));
$this->assertSame($result, 'a9a1631bf4996954ebc093957b234589');
$result = bin2hex($aes->encrypt(pack('H*', '96ab5c2ff612d9dfaae8c31f30c42168')));
$this->assertSame($result, 'ff4f8391a6a40ca5b25d23bedd44a597');
$result = bin2hex($aes->encrypt(pack('H*', '6a118a874519e64e9963798a503f1d35')));
$this->assertSame($result, 'dc43be40be0e53712f7e2bf5ca707209');
$result = bin2hex($aes->encrypt(pack('H*', 'cb9fceec81286ca3e989bd979b0cb284')));
$this->assertSame($result, '92beedab1895a94faa69b632e5cc47ce');
$result = bin2hex($aes->encrypt(pack('H*', 'b26aeb1874e47ca8358ff22378f09144')));
$this->assertSame($result, '459264f4798f6a78bacb89c15ed3d601');
$result = bin2hex($aes->encrypt(pack('H*', '58c8e00b2631686d54eab84b91f0aca1')));
$this->assertSame($result, '08a4e2efec8a8e3312ca7460b9040bbf');
}
public function testGFSBox192()
{
$aes = new AES(Base::MODE_CBC);
$aes->setKey(pack('H*', '000000000000000000000000000000000000000000000000'));
$aes->setIV(pack('H*', '00000000000000000000000000000000'));
$aes->disablePadding();
$aes->setPreferredEngine($this->engine);
$this->_checkEngine($aes);
$result = bin2hex($aes->encrypt(pack('H*', '1b077a6af4b7f98229de786d7516b639')));
$this->assertSame($result, '275cfc0413d8ccb70513c3859b1d0f72');
$result = bin2hex($aes->encrypt(pack('H*', '9c2d8842e5f48f57648205d39a239af1')));
$this->assertSame($result, 'c9b8135ff1b5adc413dfd053b21bd96d');
$result = bin2hex($aes->encrypt(pack('H*', 'bff52510095f518ecca60af4205444bb')));
$this->assertSame($result, '4a3650c3371ce2eb35e389a171427440');
$result = bin2hex($aes->encrypt(pack('H*', '51719783d3185a535bd75adc65071ce1')));
$this->assertSame($result, '4f354592ff7c8847d2d0870ca9481b7c');
$result = bin2hex($aes->encrypt(pack('H*', '26aa49dcfe7629a8901a69a9914e6dfd')));
$this->assertSame($result, 'd5e08bf9a182e857cf40b3a36ee248cc');
$result = bin2hex($aes->encrypt(pack('H*', '941a4773058224e1ef66d10e0a6ee782')));
$this->assertSame($result, '067cd9d3749207791841562507fa9626');
}
public function testGFSBox256()
{
$aes = new AES(Base::MODE_CBC);
$aes->setKey(pack('H*', '00000000000000000000000000000000' . '00000000000000000000000000000000'));
$aes->setIV(pack('H*', '00000000000000000000000000000000'));
$aes->disablePadding();
$aes->setPreferredEngine($this->engine);
$this->_checkEngine($aes);
$result = bin2hex($aes->encrypt(pack('H*', '014730f80ac625fe84f026c60bfd547d')));
$this->assertSame($result, '5c9d844ed46f9885085e5d6a4f94c7d7');
$result = bin2hex($aes->encrypt(pack('H*', '0b24af36193ce4665f2825d7b4749c98')));
$this->assertSame($result, 'a9ff75bd7cf6613d3731c77c3b6d0c04');
$result = bin2hex($aes->encrypt(pack('H*', '761c1fe41a18acf20d241650611d90f1')));
$this->assertSame($result, '623a52fcea5d443e48d9181ab32c7421');
$result = bin2hex($aes->encrypt(pack('H*', '8a560769d605868ad80d819bdba03771')));
$this->assertSame($result, '38f2c7ae10612415d27ca190d27da8b4');
$result = bin2hex($aes->encrypt(pack('H*', '91fbef2d15a97816060bee1feaa49afe')));
$this->assertSame($result, '1bc704f1bce135ceb810341b216d7abe');
}
public function testGetKeyLengthDefault()
{
$aes = new AES(Base::MODE_CBC);
$this->assertSame($aes->getKeyLength(), 128);
}
public function testGetKeyLengthWith192BitKey()
{
$aes = new AES(Base::MODE_CBC);
$aes->setKey(str_repeat('a', 24));
$this->assertSame($aes->getKeyLength(), 192);
}
/**
* @expectedException \LengthException
*/
public function testSetKeyLengthWithLargerKey()
{
$aes = new AES(Base::MODE_CBC);
$aes->setKeyLength(128);
$aes->setKey(str_repeat('a', 24));
$aes->setIV(str_repeat("\0", 16));
$this->assertSame($aes->getKeyLength(), 128);
$ciphertext = bin2hex($aes->encrypt('a'));
$this->assertSame($ciphertext, '82b7b068dfc60ed2a46893b69fecd6c2');
$this->assertSame($aes->getKeyLength(), 128);
}
/**
* @expectedException \LengthException
*/
public function testSetKeyLengthWithSmallerKey()
{
$aes = new AES(Base::MODE_CBC);
$aes->setKeyLength(256);
$aes->setKey(str_repeat('a', 16));
$aes->setIV(str_repeat("\0", 16));
$this->assertSame($aes->getKeyLength(), 256);
$ciphertext = bin2hex($aes->encrypt('a'));
$this->assertSame($ciphertext, 'fd4250c0d234aa7e1aa592820aa8406b');
$this->assertSame($aes->getKeyLength(), 256);
}
/**
* @group github938
*/
public function testContinuousBuffer()
{
$aes = new AES(AES::MODE_CBC);
$aes->disablePadding();
$aes->enableContinuousBuffer();
$aes->setIV(pack('H*', '0457bdb4a6712986688349a29eb82535'));
$aes->setKey(pack('H*', '00d596e2c8189b2592fac358e7396ad2'));
$aes->decrypt(pack('H*', '9aa234ea7c750a8109a0f32d768b964e'));
$plaintext = $aes->decrypt(pack('H*', '0457bdb4a6712986688349a29eb82535'));
$expected = pack('H*', '6572617574689e1be8d2d8d43c594cf3');
$this->assertSame($plaintext, $expected);
}
}

View File

@ -0,0 +1,88 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright MMXIII Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
use phpseclib\Crypt\Blowfish;
class Unit_Crypt_BlowfishTest extends PhpseclibTestCase
{
public function engineVectors()
{
$engines = array(
Base::ENGINE_INTERNAL => 'internal',
Base::ENGINE_MCRYPT => 'mcrypt',
Base::ENGINE_OPENSSL => 'OpenSSL',
);
// tests from https://www.schneier.com/code/vectors.txt
$tests = array(
// key, plaintext, ciphertext
array(pack('H*', '0000000000000000'), pack('H*', '0000000000000000'), pack('H*', '4EF997456198DD78')),
array(pack('H*', 'FFFFFFFFFFFFFFFF'), pack('H*', 'FFFFFFFFFFFFFFFF'), pack('H*', '51866FD5B85ECB8A')),
array(pack('H*', '3000000000000000'), pack('H*', '1000000000000001'), pack('H*', '7D856F9A613063F2')),
array(pack('H*', '1111111111111111'), pack('H*', '1111111111111111'), pack('H*', '2466DD878B963C9D')),
array(pack('H*', '0123456789ABCDEF'), pack('H*', '1111111111111111'), pack('H*', '61F9C3802281B096')),
array(pack('H*', '1111111111111111'), pack('H*', '0123456789ABCDEF'), pack('H*', '7D0CC630AFDA1EC7')),
array(pack('H*', '0000000000000000'), pack('H*', '0000000000000000'), pack('H*', '4EF997456198DD78')),
array(pack('H*', 'FEDCBA9876543210'), pack('H*', '0123456789ABCDEF'), pack('H*', '0ACEAB0FC6A0A28D')),
array(pack('H*', '7CA110454A1A6E57'), pack('H*', '01A1D6D039776742'), pack('H*', '59C68245EB05282B')),
array(pack('H*', '0131D9619DC1376E'), pack('H*', '5CD54CA83DEF57DA'), pack('H*', 'B1B8CC0B250F09A0')),
array(pack('H*', '07A1133E4A0B2686'), pack('H*', '0248D43806F67172'), pack('H*', '1730E5778BEA1DA4')),
array(pack('H*', '3849674C2602319E'), pack('H*', '51454B582DDF440A'), pack('H*', 'A25E7856CF2651EB')),
array(pack('H*', '04B915BA43FEB5B6'), pack('H*', '42FD443059577FA2'), pack('H*', '353882B109CE8F1A')),
array(pack('H*', '0113B970FD34F2CE'), pack('H*', '059B5E0851CF143A'), pack('H*', '48F4D0884C379918')),
array(pack('H*', '0170F175468FB5E6'), pack('H*', '0756D8E0774761D2'), pack('H*', '432193B78951FC98')),
array(pack('H*', '43297FAD38E373FE'), pack('H*', '762514B829BF486A'), pack('H*', '13F04154D69D1AE5')),
array(pack('H*', '07A7137045DA2A16'), pack('H*', '3BDD119049372802'), pack('H*', '2EEDDA93FFD39C79')),
array(pack('H*', '04689104C2FD3B2F'), pack('H*', '26955F6835AF609A'), pack('H*', 'D887E0393C2DA6E3')),
array(pack('H*', '37D06BB516CB7546'), pack('H*', '164D5E404F275232'), pack('H*', '5F99D04F5B163969')),
array(pack('H*', '1F08260D1AC2465E'), pack('H*', '6B056E18759F5CCA'), pack('H*', '4A057A3B24D3977B')),
array(pack('H*', '584023641ABA6176'), pack('H*', '004BD6EF09176062'), pack('H*', '452031C1E4FADA8E')),
array(pack('H*', '025816164629B007'), pack('H*', '480D39006EE762F2'), pack('H*', '7555AE39F59B87BD')),
array(pack('H*', '49793EBC79B3258F'), pack('H*', '437540C8698F3CFA'), pack('H*', '53C55F9CB49FC019')),
array(pack('H*', '4FB05E1515AB73A7'), pack('H*', '072D43A077075292'), pack('H*', '7A8E7BFA937E89A3')),
array(pack('H*', '49E95D6D4CA229BF'), pack('H*', '02FE55778117F12A'), pack('H*', 'CF9C5D7A4986ADB5')),
array(pack('H*', '018310DC409B26D6'), pack('H*', '1D9D5C5018F728C2'), pack('H*', 'D1ABB290658BC778')),
array(pack('H*', '1C587F1C13924FEF'), pack('H*', '305532286D6F295A'), pack('H*', '55CB3774D13EF201')),
array(pack('H*', '0101010101010101'), pack('H*', '0123456789ABCDEF'), pack('H*', 'FA34EC4847B268B2')),
array(pack('H*', '1F1F1F1F0E0E0E0E'), pack('H*', '0123456789ABCDEF'), pack('H*', 'A790795108EA3CAE')),
array(pack('H*', 'E0FEE0FEF1FEF1FE'), pack('H*', '0123456789ABCDEF'), pack('H*', 'C39E072D9FAC631D')),
array(pack('H*', '0000000000000000'), pack('H*', 'FFFFFFFFFFFFFFFF'), pack('H*', '014933E0CDAFF6E4')),
array(pack('H*', 'FFFFFFFFFFFFFFFF'), pack('H*', '0000000000000000'), pack('H*', 'F21E9A77B71C49BC')),
array(pack('H*', '0123456789ABCDEF'), pack('H*', '0000000000000000'), pack('H*', '245946885754369A')),
array(pack('H*', 'FEDCBA9876543210'), pack('H*', 'FFFFFFFFFFFFFFFF'), pack('H*', '6B5C5A9C5D9E0A5A'))
);
$result = array();
foreach ($engines as $engine => $engineName) {
foreach ($tests as $test) {
$result[] = array($engine, $engineName, $test[0], $test[1], $test[2]);
}
}
return $result;
}
/**
* @dataProvider engineVectors
*/
public function testVectors($engine, $engineName, $key, $plaintext, $expected)
{
$bf = new Blowfish(Blowfish::MODE_CBC);
$bf->setKey($key);
$bf->setIV(str_repeat("\0", $bf->getBlockLength() >> 3));
if (!$bf->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
}
$bf->setPreferredEngine($engine);
$bf->disablePadding();
$result = $bf->encrypt($plaintext);
$plaintext = bin2hex($plaintext);
$this->assertEquals($result, $expected, "Failed asserting that $plaintext yielded expected output in $engineName engine");
}
}

View File

@ -0,0 +1,393 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2012 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Hash;
class Unit_Crypt_HashTest extends PhpseclibTestCase
{
protected function assertHashesTo($hash, $message, $expected)
{
$hash = new Hash($hash);
$this->assertSame(
strtolower($expected),
bin2hex($hash->hash($message)),
sprintf("Failed asserting that '%s' hashes to '%s'.", $message, $expected)
);
}
protected function assertHMACsTo($hash, $key, $message, $expected)
{
$hash = new Hash($hash);
$hash->setKey($key);
$this->assertSame(
strtolower($expected),
bin2hex($hash->hash($message)),
sprintf(
"Failed asserting that '%s' HMACs to '%s' with key '%s'.",
$message,
$expected,
$key
)
);
}
public static function hashData()
{
return array(
array('md5', '', 'd41d8cd98f00b204e9800998ecf8427e'),
array('md5', 'The quick brown fox jumps over the lazy dog', '9e107d9d372bb6826bd81d3542a419d6'),
array('md5', 'The quick brown fox jumps over the lazy dog.', 'e4d909c290d0fb1ca068ffaddf22cbd0'),
array('sha1', 'The quick brown fox jumps over the lazy dog', '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'),
array('sha1', 'The quick brown fox jumps over the lazy dog.', '408d94384216f890ff7a0c3528e8bed1e0b01621'),
array(
'sha256',
'',
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
),
array(
'sha256',
'The quick brown fox jumps over the lazy dog',
'd7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592',
),
array(
'sha256',
'The quick brown fox jumps over the lazy dog.',
'ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c',
),
array(
'sha384',
'',
'38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b'
),
array(
'sha384',
'The quick brown fox jumps over the lazy dog',
'ca737f1014a48f4c0b6dd43cb177b0afd9e5169367544c494011e3317dbf9a509cb1e5dc1e85a941bbee3d7f2afbc9b1',
),
array(
'sha512',
'',
'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e'
),
array(
'sha512',
'The quick brown fox jumps over the lazy dog',
'07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6',
),
array(
'sha512',
'The quick brown fox jumps over the lazy dog.',
'91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed',
),
// from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_224.pdf
array(
'sha512/224',
'abc',
'4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa'
),
array(
'sha512/224',
'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu',
'23fec5bb94d60b23308192640b0c453335d664734fe40e7268674af9'
),
// from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA512_256.pdf
array(
'sha512/256',
'abc',
'53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23'
),
array(
'sha512/256',
'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu',
'3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a'
),
// from http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA224.pdf
array(
'sha224',
'abc',
'23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7'
),
array(
'sha224',
'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq',
'75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B1952522525'
),
);
}
/**
* @dataProvider hmacData()
*/
public function testHMAC($hash, $key, $message, $result)
{
$this->assertHMACsTo($hash, $key, $message, $result);
}
/**
* @dataProvider hmacData()
*/
public function testHMAC96($hash, $key, $message, $result)
{
$this->assertHMACsTo($hash . '-96', $key, $message, substr($result, 0, 24));
}
public static function hmacData()
{
return array(
array('md5', '', '', '74e6f7298a9c2d168935f58c001bad88'),
array('md5', 'key', 'The quick brown fox jumps over the lazy dog', '80070713463e7749b90c2dc24911e275'),
// from https://tools.ietf.org/rfc/rfc4231.txt
// test case 1
array(
'sha224',
str_repeat("\x0b", 20),
'Hi There',
'896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22',
),
// test case 2
array(
'sha224',
'Jefe',
'what do ya want for nothing?',
'a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44',
),
// test case 3
array(
'sha224',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
'7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea',
),
// test case 4
array(
'sha224',
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
'6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a',
),
// skip test case 5; truncation is only supported to 96 bits (eg. sha1-96) and that's already unit tested
// test case 6
array(
'sha224',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
'Test Using Larger Than Block-Size Key - Hash Key First',
'95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e',
),
// test case 7
array(
'sha224',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.',
'3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1'
),
// test case 1
array(
'sha256',
str_repeat("\x0b", 20),
'Hi There',
'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7',
),
// test case 2
array(
'sha256',
'Jefe',
'what do ya want for nothing?',
'5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843',
),
// test case 3
array(
'sha256',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
'773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe',
),
// test case 4
array(
'sha256',
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
'82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b',
),
// skip test case 5; truncation is only supported to 96 bits (eg. sha1-96) and that's already unit tested
// test case 6
array(
'sha256',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
'Test Using Larger Than Block-Size Key - Hash Key First',
'60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54',
),
// test case 7
array(
'sha256',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.',
'9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2'
),
// test case 1
array(
'sha384',
str_repeat("\x0b", 20),
'Hi There',
'afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6',
),
// test case 2
array(
'sha384',
'Jefe',
'what do ya want for nothing?',
'af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649',
),
// test case 3
array(
'sha384',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
'88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27',
),
// test case 4
array(
'sha384',
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
'3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb',
),
// skip test case 5; truncation is only supported to 96 bits (eg. sha1-96) and that's already unit tested
// test case 6
array(
'sha384',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
'Test Using Larger Than Block-Size Key - Hash Key First',
'4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952',
),
// test case 7
array(
'sha384',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.',
'6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e'
),
// test case 1
array(
'sha512',
str_repeat("\x0b", 20),
'Hi There',
'87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854',
),
// test case 2
array(
'sha512',
'Jefe',
'what do ya want for nothing?',
'164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737',
),
// test case 3
array(
'sha512',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
pack('H*', 'dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd'),
'fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb',
),
// test case 4
array(
'sha512',
pack('H*', '0102030405060708090a0b0c0d0e0f10111213141516171819'),
pack('H*', 'cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd'),
'b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd',
),
// skip test case 5; truncation is only supported to 96 bits (eg. sha1-96) and that's already unit tested
// test case 6
array(
'sha512',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
'Test Using Larger Than Block-Size Key - Hash Key First',
'80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598',
),
// test case 7
array(
'sha512',
pack('H*', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),
'This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.',
'e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58'
),
);
}
/**
* @dataProvider hashData()
*/
public function testHash($hash, $message, $result)
{
$this->assertHashesTo($hash, $message, $result);
}
/**
* @dataProvider hashData()
*/
public function testHash96($hash, $message, $result)
{
$this->assertHashesTo($hash . '-96', $message, substr($result, 0, 24));
}
public function testConstructorDefault()
{
$hash = new Hash();
$this->assertSame($hash->getHash(), 'sha256');
}
/**
* @expectedException \phpseclib\Exception\UnsupportedAlgorithmException
*/
public function testConstructorArgumentInvalid()
{
new Hash('abcdefghijklmnopqrst');
}
/**
* @expectedException \phpseclib\Exception\UnsupportedAlgorithmException
*/
public function testSetHashInvalid()
{
$hash = new Hash('md5');
$hash->setHash('abcdefghijklmnopqrst-96');
}
public function testSetHashValid()
{
$hash = new Hash('md5');
$this->assertSame($hash->getHash(), 'md5');
$hash->setHash('sha1');
$this->assertSame($hash->getHash(), 'sha1');
}
/**
* @dataProvider lengths
*/
public function testGetLengthKnown($algorithm, $length)
{
$hash = new Hash($algorithm);
$this->assertSame($hash->getLength(), $length);
}
public function lengths()
{
return array(
// known
array('md5-96', 12),
array('md5', 16),
array('sha1', 20),
array('sha256', 32),
array('sha384', 48),
array('sha512', 64),
);
}
}

View File

@ -0,0 +1,129 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright MMXIII Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
use phpseclib\Crypt\RC2;
class Unit_Crypt_RC2Test extends PhpseclibTestCase
{
var $engines = array(
Base::ENGINE_INTERNAL => 'internal',
Base::ENGINE_MCRYPT => 'mcrypt',
Base::ENGINE_OPENSSL => 'OpenSSL',
);
public function engineVectors()
{
// tests from https://tools.ietf.org/html/rfc2268#page-8
$tests = array(
// key, effective key length, plaintext, ciphertext
array('0000000000000000', 63, '0000000000000000', 'ebb773f993278eff'),
array('ffffffffffffffff', 64, 'ffffffffffffffff', '278b27e42e2f0d49'),
array('3000000000000000', 64, '1000000000000001', '30649edf9be7d2c2'),
array('88', 64, '0000000000000000', '61a8a244adacccf0'),
array('88bca90e90875a', 64, '0000000000000000', '6ccf4308974c267f'),
array('88bca90e90875a7f0f79c384627bafb2', 64, '0000000000000000', '1a807d272bbe5db1'),
array('88bca90e90875a7f0f79c384627bafb2', 128, '0000000000000000', '2269552ab0f85ca6'),
array('88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e', 129, '0000000000000000', '5b78d3a43dfff1f1')
);
$result = array();
foreach ($this->engines as $engine => $engineName) {
foreach ($tests as $test) {
$result[] = array($engine, $engineName, $test[0], $test[1], $test[2], $test[3]);
}
}
return $result;
}
// this test is just confirming RC2's key expansion
public function testEncryptPadding()
{
$rc2 = new RC2(Base::MODE_ECB);
// unlike Crypt_AES / Crypt_Rijndael, when you tell Crypt_RC2 that the key length is 128-bits the key isn't null padded to that length.
// instead, RC2 key expansion is used to extend it out to that length. this isn't done for AES / Rijndael since that doesn't define any
// sort of key expansion algorithm.
// admittedly, phpseclib is inconsistent in this regard. RC4 and Blowfish support arbitrary key lengths between a certain range, as well,
// and they don't have any way to set the key length. but then again, neither do those algorithms have their own key expansion algorithm,
// whereas RC2 does. and technically, AES / Rijndael (and even Twofish) don't support arbitrary key lengths - they support variable key
// lengths. so in some ways, i suppose this inconsistency somewhat makes sense, although the fact that Crypt_Twofish doesn't have a
// setKeyLength() function whereas Crypt_AES / Crypt_Rijndael do not is, itself, an inconsistency.
// but that said, Crypt_RC2 is inconsistent in other ways: if you pass a 128-bit (16-byte) key to it via setKey() the key is not treated
// as a 128-bit key but rather as a 1024-bit key and is expanded accordingly, not via null padding, but via RC2's key expansion algorithm.
// this behavior is in contrast to mcrypt, which extends keys via null padding to 1024 bits. it is also in contrast to OpenSSL, which
// extends keys, via null padding, to 128 bits. mcrypt's approach seems preferable as one can simulate 128 bit keys by using RC2's
// key expansion algorithm to extend the key to 1024 bits and then changing the first byte of the new key with an inverse pitable mapping.
// in contrast, to my knowledge, there is no technique for expanding a key less than 128 bits to 128 bits, via RC2 key expansion. the only
// scenario in that regard is null padding.
// simple truncation is insufficient, since, quoting RFC2268, "the purpose of the key-expansion algorithm [in RC2] is to modify the key buffer
// so that each bit of the expanded key depends in a complicated way on every bit of the supplied input key".
// now, to OpenSSL's credit, null padding is internally consistent with OpenSSL. OpenSSL only supports fixed length keys. For rc2, rc4 and
// bf (blowfish), all keys are 128 bits (or are null padded / truncated accordingly). to use 40-bit or 64-bit keys with RC4 with OpenSSL you
// don't use the rc4 algorithm - you use the rc4-40 or rc4-64 algorithm. and similarily, it's not aes-cbc that you use - it's either aes-128-cbc
// or aes-192-cbc or aes-256-cbc. this is in contrast to mcrypt, which (with the exception of RC2) actually supports variable and arbitrary
// length keys.
// superficially, it seens like Rijndael would be another exception to mcrypt's key length handling, but it in fact is not. the reason being that,
// with mcrypt, when you specify MCRYPT_RIJNDAEL_128 or MCRYPT_RIJNDAEL_192 or MCRYPT_RIJNDAEL_256 the numbers at the end aren't referring to the
// key length, but rather, the block length. ie. Rijndael, unlike most block ciphers, doesn't just have a variable (but not arbitrary) key length -
// it also has a variable block length. AES's block length, however, is not variable, so technically, only MCRYPT_RIJNDAEL_128 is AES.
$rc2->setKey(str_repeat('d', 16), 128);
$rc2->setPreferredEngine(Base::ENGINE_INTERNAL);
$internal = $rc2->encrypt('d');
$result = pack('H*', 'e3b36057f4821346');
$this->assertEquals($result, $internal, 'Failed asserting that the internal engine produced the correct result');
$rc2->setPreferredEngine(Base::ENGINE_MCRYPT);
if ($rc2->getEngine() == Base::ENGINE_MCRYPT) {
$mcrypt = $rc2->encrypt('d');
$this->assertEquals($result, $mcrypt, 'Failed asserting that the mcrypt engine produced the correct result');
} else {
self::markTestSkipped('Unable to initialize mcrypt engine');
}
$rc2->setPreferredEngine(Base::ENGINE_OPENSSL);
if ($rc2->getEngine() == Base::ENGINE_OPENSSL) {
$openssl = $rc2->encrypt('d');
$this->assertEquals($result, $openssl, 'Failed asserting that the OpenSSL engine produced the correct result');
} else {
self::markTestSkipped('Unable to initialize OpenSSL engine');
}
}
/**
* @dataProvider engineVectors
*/
public function testVectors($engine, $engineName, $key, $keyLen, $plaintext, $ciphertext)
{
$rc2 = new RC2(RC2::MODE_CBC);
$rc2->disablePadding();
$rc2->setKeyLength($keyLen);
$rc2->setKey(pack('H*', $key)); // could also do $rc2->setKey(pack('H*', $key), $keyLen)
$rc2->setIV(str_repeat("\0", $rc2->getBlockLength() >> 3));
if (!$rc2->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
}
$rc2->setPreferredEngine($engine);
$result = bin2hex($rc2->encrypt(pack('H*', $plaintext)));
$this->assertEquals($result, $ciphertext, "Failed asserting that $plaintext yielded expected output in $engineName engine");
$result = bin2hex($rc2->decrypt(pack('H*', $ciphertext)));
$this->assertEquals($result, $plaintext, "Failed asserting that decrypted result yielded $plaintext as a result in $engineName engine");
}
}

View File

@ -0,0 +1,212 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
use phpseclib\Crypt\RC4;
class Unit_Crypt_RC4Test extends PhpseclibTestCase
{
public function engineVectors()
{
$engines = array(
Base::ENGINE_INTERNAL => 'internal',
Base::ENGINE_MCRYPT => 'mcrypt',
Base::ENGINE_OPENSSL => 'OpenSSL',
);
// tests from https://tools.ietf.org/html/rfc6229
$tests = array(
array(
'key' => pack('H*', '0102030405'), // 40-bit key
'output' => array(
array('offset' => 0, 'result' => 'b2396305f03dc027ccc3524a0a1118a8'),
array('offset' => 16, 'result' => '6982944f18fc82d589c403a47a0d0919'),
array('offset' => 240, 'result' => '28cb1132c96ce286421dcaadb8b69eae'),
array('offset' => 256, 'result' => '1cfcf62b03eddb641d77dfcf7f8d8c93'),
array('offset' => 496, 'result' => '42b7d0cdd918a8a33dd51781c81f4041'),
array('offset' => 512, 'result' => '6459844432a7da923cfb3eb4980661f6'),
array('offset' => 752, 'result' => 'ec10327bde2beefd18f9277680457e22'),
array('offset' => 768, 'result' => 'eb62638d4f0ba1fe9fca20e05bf8ff2b'),
array('offset' => 1008, 'result' => '45129048e6a0ed0b56b490338f078da5'),
array('offset' => 1024, 'result' => '30abbcc7c20b01609f23ee2d5f6bb7df'),
array('offset' => 1520, 'result' => '3294f744d8f9790507e70f62e5bbceea'),
array('offset' => 1536, 'result' => 'd8729db41882259bee4f825325f5a130'),
array('offset' => 2032, 'result' => '1eb14a0c13b3bf47fa2a0ba93ad45b8b'),
array('offset' => 2048, 'result' => 'cc582f8ba9f265e2b1be9112e975d2d7'),
array('offset' => 3056, 'result' => 'f2e30f9bd102ecbf75aaade9bc35c43c'),
array('offset' => 3072, 'result' => 'ec0e11c479dc329dc8da7968fe965681'),
array('offset' => 4080, 'result' => '068326a2118416d21f9d04b2cd1ca050'),
array('offset' => 4096, 'result' => 'ff25b58995996707e51fbdf08b34d875')
)
),
array(
'key' => pack('H*', '01020304050607'), // 56-bit key
'output' => array(
array('offset' => 0, 'result' => '293f02d47f37c9b633f2af5285feb46b'),
array('offset' => 16, 'result' => 'e620f1390d19bd84e2e0fd752031afc1'),
array('offset' => 240, 'result' => '914f02531c9218810df60f67e338154c'),
array('offset' => 256, 'result' => 'd0fdb583073ce85ab83917740ec011d5'),
array('offset' => 496, 'result' => '75f81411e871cffa70b90c74c592e454'),
array('offset' => 512, 'result' => '0bb87202938dad609e87a5a1b079e5e4'),
array('offset' => 752, 'result' => 'c2911246b612e7e7b903dfeda1dad866'),
array('offset' => 768, 'result' => '32828f91502b6291368de8081de36fc2'),
array('offset' => 1008, 'result' => 'f3b9a7e3b297bf9ad804512f9063eff1'),
array('offset' => 1024, 'result' => '8ecb67a9ba1f55a5a067e2b026a3676f'),
array('offset' => 1520, 'result' => 'd2aa902bd42d0d7cfd340cd45810529f'),
array('offset' => 1536, 'result' => '78b272c96e42eab4c60bd914e39d06e3'),
array('offset' => 2032, 'result' => 'f4332fd31a079396ee3cee3f2a4ff049'),
array('offset' => 2048, 'result' => '05459781d41fda7f30c1be7e1246c623'),
array('offset' => 3056, 'result' => 'adfd3868b8e51485d5e610017e3dd609'),
array('offset' => 3072, 'result' => 'ad26581c0c5be45f4cea01db2f3805d5'),
array('offset' => 4080, 'result' => 'f3172ceffc3b3d997c85ccd5af1a950c'),
array('offset' => 4096, 'result' => 'e74b0b9731227fd37c0ec08a47ddd8b8')
)
),
array(
'key' => pack('H*', '0102030405060708'), // 64-bit key
'output' => array(
array('offset' => 0, 'result' => '97ab8a1bf0afb96132f2f67258da15a8'),
array('offset' => 16, 'result' => '8263efdb45c4a18684ef87e6b19e5b09'),
array('offset' => 240, 'result' => '9636ebc9841926f4f7d1f362bddf6e18'),
array('offset' => 256, 'result' => 'd0a990ff2c05fef5b90373c9ff4b870a'),
array('offset' => 496, 'result' => '73239f1db7f41d80b643c0c52518ec63'),
array('offset' => 512, 'result' => '163b319923a6bdb4527c626126703c0f'),
array('offset' => 752, 'result' => '49d6c8af0f97144a87df21d91472f966'),
array('offset' => 768, 'result' => '44173a103b6616c5d5ad1cee40c863d0'),
array('offset' => 1008, 'result' => '273c9c4b27f322e4e716ef53a47de7a4'),
array('offset' => 1024, 'result' => 'c6d0e7b226259fa9023490b26167ad1d'),
array('offset' => 1520, 'result' => '1fe8986713f07c3d9ae1c163ff8cf9d3'),
array('offset' => 1536, 'result' => '8369e1a965610be887fbd0c79162aafb'),
array('offset' => 2032, 'result' => '0a0127abb44484b9fbef5abcae1b579f'),
array('offset' => 2048, 'result' => 'c2cdadc6402e8ee866e1f37bdb47e42c'),
array('offset' => 3056, 'result' => '26b51ea37df8e1d6f76fc3b66a7429b3'),
array('offset' => 3072, 'result' => 'bc7683205d4f443dc1f29dda3315c87b'),
array('offset' => 4080, 'result' => 'd5fa5a3469d29aaaf83d23589db8c85b'),
array('offset' => 4096, 'result' => '3fb46e2c8f0f068edce8cdcd7dfc5862')
)
),
array(
'key' => pack('H*', '0102030405060708090a'), // 80-bit key
'output' => array(
array('offset' => 0, 'result' => 'ede3b04643e586cc907dc21851709902'),
array('offset' => 16, 'result' => '03516ba78f413beb223aa5d4d2df6711'),
array('offset' => 240, 'result' => '3cfd6cb58ee0fdde640176ad0000044d'),
array('offset' => 256, 'result' => '48532b21fb6079c9114c0ffd9c04a1ad'),
array('offset' => 496, 'result' => '3e8cea98017109979084b1ef92f99d86'),
array('offset' => 512, 'result' => 'e20fb49bdb337ee48b8d8dc0f4afeffe'),
array('offset' => 752, 'result' => '5c2521eacd7966f15e056544bea0d315'),
array('offset' => 768, 'result' => 'e067a7031931a246a6c3875d2f678acb'),
array('offset' => 1008, 'result' => 'a64f70af88ae56b6f87581c0e23e6b08'),
array('offset' => 1024, 'result' => 'f449031de312814ec6f319291f4a0516'),
array('offset' => 1520, 'result' => 'bdae85924b3cb1d0a2e33a30c6d79599'),
array('offset' => 1536, 'result' => '8a0feddbac865a09bcd127fb562ed60a'),
array('offset' => 2032, 'result' => 'b55a0a5b51a12a8be34899c3e047511a'),
array('offset' => 2048, 'result' => 'd9a09cea3ce75fe39698070317a71339'),
array('offset' => 3056, 'result' => '552225ed1177f44584ac8cfa6c4eb5fc'),
array('offset' => 3072, 'result' => '7e82cbabfc95381b080998442129c2f8'),
array('offset' => 4080, 'result' => '1f135ed14ce60a91369d2322bef25e3c'),
array('offset' => 4096, 'result' => '08b6be45124a43e2eb77953f84dc8553')
)
),
array(
'key' => pack('H*', '0102030405060708090a0b0c0d0e0f10'), // 128-bit key
'output' => array(
array('offset' => 0, 'result' => '9ac7cc9a609d1ef7b2932899cde41b97'),
array('offset' => 16, 'result' => '5248c4959014126a6e8a84f11d1a9e1c'),
array('offset' => 240, 'result' => '065902e4b620f6cc36c8589f66432f2b'),
array('offset' => 256, 'result' => 'd39d566bc6bce3010768151549f3873f'),
array('offset' => 496, 'result' => 'b6d1e6c4a5e4771cad79538df295fb11'),
array('offset' => 512, 'result' => 'c68c1d5c559a974123df1dbc52a43b89'),
array('offset' => 752, 'result' => 'c5ecf88de897fd57fed301701b82a259'),
array('offset' => 768, 'result' => 'eccbe13de1fcc91c11a0b26c0bc8fa4d'),
array('offset' => 1008, 'result' => 'e7a72574f8782ae26aabcf9ebcd66065'),
array('offset' => 1024, 'result' => 'bdf0324e6083dcc6d3cedd3ca8c53c16'),
array('offset' => 1520, 'result' => 'b40110c4190b5622a96116b0017ed297'),
array('offset' => 1536, 'result' => 'ffa0b514647ec04f6306b892ae661181'),
array('offset' => 2032, 'result' => 'd03d1bc03cd33d70dff9fa5d71963ebd'),
array('offset' => 2048, 'result' => '8a44126411eaa78bd51e8d87a8879bf5'),
array('offset' => 3056, 'result' => 'fabeb76028ade2d0e48722e46c4615a3'),
array('offset' => 3072, 'result' => 'c05d88abd50357f935a63c59ee537623'),
array('offset' => 4080, 'result' => 'ff38265c1642c1abe8d3c2fe5e572bf8'),
array('offset' => 4096, 'result' => 'a36a4c301ae8ac13610ccbc12256cacc')
)
),
array(
'key' => pack('H*', '0102030405060708090a0b0c0d0e0f101112131415161718'), // 192-bit key
'output' => array(
array('offset' => 0, 'result' => '0595e57fe5f0bb3c706edac8a4b2db11'),
array('offset' => 16, 'result' => 'dfde31344a1af769c74f070aee9e2326'),
array('offset' => 240, 'result' => 'b06b9b1e195d13d8f4a7995c4553ac05'),
array('offset' => 256, 'result' => '6bd2378ec341c9a42f37ba79f88a32ff'),
array('offset' => 496, 'result' => 'e70bce1df7645adb5d2c4130215c3522'),
array('offset' => 512, 'result' => '9a5730c7fcb4c9af51ffda89c7f1ad22'),
array('offset' => 752, 'result' => '0485055fd4f6f0d963ef5ab9a5476982'),
array('offset' => 768, 'result' => '591fc66bcda10e452b03d4551f6b62ac'),
array('offset' => 1008, 'result' => '2753cc83988afa3e1688a1d3b42c9a02'),
array('offset' => 1024, 'result' => '93610d523d1d3f0062b3c2a3bbc7c7f0'),
array('offset' => 1520, 'result' => '96c248610aadedfeaf8978c03de8205a'),
array('offset' => 1536, 'result' => '0e317b3d1c73b9e9a4688f296d133a19'),
array('offset' => 2032, 'result' => 'bdf0e6c3cca5b5b9d533b69c56ada120'),
array('offset' => 2048, 'result' => '88a218b6e2ece1e6246d44c759d19b10'),
array('offset' => 3056, 'result' => '6866397e95c140534f94263421006e40'),
array('offset' => 3072, 'result' => '32cb0a1e9542c6b3b8b398abc3b0f1d5'),
array('offset' => 4080, 'result' => '29a0b8aed54a132324c62e423f54b4c8'),
array('offset' => 4096, 'result' => '3cb0f3b5020a98b82af9fe154484a168')
)
),
array(
'key' => pack('H*', '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20'), // 256-bit key
'output' => array(
array('offset' => 0, 'result' => 'eaa6bd25880bf93d3f5d1e4ca2611d91'),
array('offset' => 16, 'result' => 'cfa45c9f7e714b54bdfa80027cb14380'),
array('offset' => 240, 'result' => '114ae344ded71b35f2e60febad727fd8'),
array('offset' => 256, 'result' => '02e1e7056b0f623900496422943e97b6'),
array('offset' => 496, 'result' => '91cb93c787964e10d9527d999c6f936b'),
array('offset' => 512, 'result' => '49b18b42f8e8367cbeb5ef104ba1c7cd'),
array('offset' => 752, 'result' => '87084b3ba700bade955610672745b374'),
array('offset' => 768, 'result' => 'e7a7b9e9ec540d5ff43bdb12792d1b35'),
array('offset' => 1008, 'result' => 'c799b596738f6b018c76c74b1759bd90'),
array('offset' => 1024, 'result' => '7fec5bfd9f9b89ce6548309092d7e958'),
array('offset' => 1520, 'result' => '40f250b26d1f096a4afd4c340a588815'),
array('offset' => 1536, 'result' => '3e34135c79db010200767651cf263073'),
array('offset' => 2032, 'result' => 'f656abccf88dd827027b2ce917d464ec'),
array('offset' => 2048, 'result' => '18b62503bfbc077fbabb98f20d98ab34'),
array('offset' => 3056, 'result' => '8aed95ee5b0dcbfbef4eb21d3a3f52f9'),
array('offset' => 3072, 'result' => '625a1ab00ee39a5327346bddb01a9c18'),
array('offset' => 4080, 'result' => 'a13a7c79c7e119b5ab0296ab28c300b9'),
array('offset' => 4096, 'result' => 'f3e4c0a2e02d1d01f7f0a74618af2b48')
)
)
);
$result = array();
foreach ($engines as $engine => $engineName) {
foreach ($tests as $test) {
foreach ($test['output'] as $output) {
$result[] = array($engine, $engineName, $test['key'], $output['offset'], $output['result']);
}
}
}
return $result;
}
/**
* @dataProvider engineVectors
*/
public function testVectors($engine, $engineName, $key, $offset, $expected)
{
$rc4 = new RC4();
$rc4->setPreferredEngine($engine);
$rc4->setKey($key);
if ($rc4->getEngine() != $engine) {
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine for ' . (strlen($key) * 8) . '-bit key');
}
$result = $rc4->encrypt(str_repeat("\0", $offset + 16));
$this->assertEquals(bin2hex(substr($result, -16)), $expected, "Failed asserting that key $key yielded expected output at offset $offset in $engineName engine");
}
}

View File

@ -0,0 +1,34 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\RSA;
class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
{
public function testCreateKey()
{
extract(RSA::createKey(768));
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $privatekey);
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $publickey);
$this->assertNotEmpty("$privatekey");
$this->assertNotEmpty("$publickey");
return array($publickey, $privatekey);
}
/**
* @depends testCreateKey
*/
public function testEncryptDecrypt($args)
{
list($publickey, $privatekey) = $args;
$ciphertext = $publickey->encrypt('zzz');
$this->assertInternalType('string', $ciphertext);
$plaintext = $privatekey->decrypt($ciphertext);
$this->assertSame($plaintext, 'zzz');
}
}

View File

@ -0,0 +1,557 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2013 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\RSA;
use phpseclib\Crypt\RSA\PKCS1;
use phpseclib\Crypt\RSA\PuTTY;
use phpseclib\Math\BigInteger;
class Unit_Crypt_RSA_LoadKeyTest extends PhpseclibTestCase
{
public function testBadKey()
{
$rsa = new RSA();
$key = 'zzzzzzzzzzzzzz';
$this->assertFalse($rsa->load($key));
}
public function testPKCS1Key()
{
$rsa = new RSA();
$key = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPrivateKey());
}
public function testPKCS1SpacesKey()
{
$rsa = new RSA();
$key = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
$key = str_replace(array("\r", "\n", "\r\n"), ' ', $key);
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPrivateKey());
}
public function testPKCS1NoHeaderKey()
{
$rsa = new RSA();
$key = 'MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPrivateKey());
}
public function testPKCS1NoWhitespaceNoHeaderKey()
{
$rsa = new RSA();
$key = 'MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp' .
'wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5' .
'1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh' .
'3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2' .
'pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX' .
'GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il' .
'AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF' .
'L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k' .
'X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl' .
'U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ' .
'37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPrivateKey());
}
public function testRawPKCS1Key()
{
$rsa = new RSA();
$key = 'MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp' .
'wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5' .
'1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh' .
'3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2' .
'pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX' .
'GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il' .
'AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF' .
'L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k' .
'X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl' .
'U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ' .
'37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
$key = base64_decode($key);
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPrivateKey());
}
public function testLoadPKCS8PrivateKey()
{
$rsa = new RSA();
$rsa->setPassword('password');
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIE6TAbBgkqhkiG9w0BBQMwDgQIcWWgZeQYPTcCAggABIIEyLoa5b3ktcPmy4VB
hHkpHzVSEsKJPmQTUaQvUwIp6+hYZeuOk78EPehrYJ/QezwJRdyBoD51oOxqWCE2
fZ5Wf6Mi/9NIuPyqQccP2ouErcMAcDLaAx9C0Ot37yoG0S6hOZgaxqwnCdGYKHgS
7cYUv40kLOJmTOJlHJbatfXHocrHcHkCBJ1q8wApA1KVQIZsqmyBUBuwbrfFwpC9
d/R674XxCWJpXvU63VNZRFYUvd7YEWCrdSeleb99p0Vn1kxI5463PXurgs/7GPiO
SLSdX44DESP9l7lXenC4gbuT8P0xQRDzGrB5l9HHoV3KMXFODWTMnLcp1nuhA0OT
fPS2yzT9zJgqHiVKWgcUUJ5uDelVfnsmDhnh428p0GBFbniH07qREC9kq78UqQNI
Kybp4jQ4sPs64zdYm/VyLWtAYz8QNAKHLcnPwmTPr/XlJmox8rlQhuSQTK8E+lDr
TOKpydrijN3lF+pgyUuUj6Ha8TLMcOOwqcrpBig4SGYoB56gjAO0yTE9uCPdBakj
yxi3ksn51ErigGM2pGMNcVdwkpJ/x+DEBBO0auy3t9xqM6LK8pwNcOT1EWO+16zY
79LVSavc49t+XxMc3Xasz/G5xQgD1FBp6pEnsg5JhTTG/ih6Y/DQD8z3prjC3qKc
rpL4NA9KBI/IF1iIXlrfmN/zCKbBuEOEGqwcHBDHPySZbhL2XLSpGcK/NBl1bo1Z
G+2nUTauoC67Qb0+fnzTcvOiMNAbHMiqkirs4anHX33MKL2gR/3dp8ca9hhWWXZz
Mkk2FK9sC/ord9F6mTtvTiOSDzpiEhb94uTxXqBhIbsrGXCUUd0QQN5s2dmW2MfS
M35KeSv2rwDGzC1+Qf3MhHGIZDqoQwuZEzM5yHHafCatAbZd2sjaFWegg0r2ca7a
eZkZFj3ZuDYXJFnL82guOASh7rElWO2Ys7ncXAKnaV3WkkF+JDv/CUHr+Q/h6Ae5
qEvgubTCVSYHzRP37XJItlcdywTIcTY+t6jymmyEBJ66LmUoD47gt/vDUSbhT6Oa
GlcZ+MZGlUnPOSq4YknOgwKH8izboY4UgVCrmXvlaZYQhZemNDkVbpYVDf+s6cPf
tJwVoZf+qf2SsRTUsI10isoIzCyGw2ie8kmipdP434Z/99uVU3zxD6raNDlyp33q
FWMgpr2JU6NVAla7N51g7Jk8VjIIn7SvCYyWkmvv4kLB1UHl3NFqYb9YuIZUaDyt
j/NMcKMLLOaEorRZ2N2mDNoihMxMf8J3J9APnzUigAtaalGKNOrd2Fom5OVADePv
Tb5sg1uVQzfcpFrjIlLVh+2cekX0JM84phbMpHmm5vCjjfYvUvcMy0clCf0x3jz6
LZf5Fzc8xbZmpse5OnOrsDLCNh+SlcYOzsagSZq4TgvSeI9Tr4lv48dLJHCCcYKL
eymS9nhlCFuuHbi7zI7edcI49wKUW1Sj+kvKq3LMIEkMlgzqGKA6JqSVxHP51VH5
FqV4aKq70H6dNJ43bLVRPhtF5Bip5P7k/6KIsGTPUd54PHey+DuWRjitfheL0G2w
GF/qoZyC1mbqdtyyeWgHtVbJVUORmpbNnXOII9duEqBUNDiO9VSZNn/8h/VsYeAB
xryZaRDVmtMuf/OZBQ==
-----END ENCRYPTED PRIVATE KEY-----';
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPrivateKey());
}
public function testSavePKCS8PrivateKey()
{
$rsa = new RSA();
$key = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
$rsa->setPassword('password');
$this->assertTrue($rsa->load($key));
$key = $rsa->getPrivateKey('PKCS8');
$this->assertInternalType('string', $key);
$this->assertTrue($rsa->load($key));
}
public function testPubKey1()
{
$rsa = new RSA();
$key = '-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
-----END RSA PUBLIC KEY-----';
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPublicKey());
$this->assertFalse($rsa->getPrivateKey());
}
public function testPubKey2()
{
$rsa = new RSA();
$key = '-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA61BjmfXGEvWmegnBGSuS
+rU9soUg2FnODva32D1AqhwdziwHINFaD1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBS
EVCgJjtHAGZIm5GL/KA86KDp/CwDFMSwluowcXwDwoyinmeOY9eKyh6aY72xJh7n
oLBBq1N0bWi1e2i+83txOCg4yV2oVXhBo8pYEJ8LT3el6Smxol3C1oFMVdwPgc0v
Tl25XucMcG/ALE/KNY6pqC2AQ6R2ERlVgPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeu
lmCpGSynXNcpZ/06+vofGi/2MlpQZNhHAo8eayMp6FcvNucIpUndo1X8dKMv3Y26
ZQIDAQAB
-----END PUBLIC KEY-----';
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPublicKey());
$this->assertFalse($rsa->getPrivateKey());
}
public function testSSHPubKey()
{
$rsa = new RSA();
$key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4e' .
'CZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMS' .
'GkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZw== ' .
'phpseclib-generated-key';
$this->assertTrue($rsa->load($key));
$this->assertInternalType('string', $rsa->getPublicKey());
$this->assertFalse($rsa->getPrivateKey());
}
public function testSSHPubKeyFingerprint()
{
$rsa = new RSA();
$key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD9K+ebJRMN10kGanhi6kDz6EYFqZttZWZh0'.
'YoEbIbbere9N2Yvfc7oIoCTHYowhXND9WSJaIs1E4bx0085CZnofWaqf4NbZTzAh18iZup08ec'.
'COB5gJVS1efpgVSviDF2L7jxMsBVoOBfqsmA8m0RwDDVezyWvw4y+STSuVzu2jI8EfwN7ZFGC6'.
'Yo8m/Z94qIGzqPYGKJLuCeidB0TnUE0ZtzOJTiOc/WoTm/NOpCdfQZEJggd1MOTi+QUnqRu4Wu'.
'b6wYtY/q/WtUFr3nK+x0lgOtokhnJfRR/6fnmC1CztPnIT4BWK81VGKWONAxuhMyQ5XChyu6S9'.
'mWG5tUlUI/5';
$this->assertTrue($rsa->load($key));
$this->assertSame($rsa->getPublicKeyFingerprint('md5'), 'bd:2c:2f:31:b9:ef:b8:f8:ad:fc:40:a6:94:4f:28:82');
$this->assertSame($rsa->getPublicKeyFingerprint('sha256'), 'N9sV2uSNZEe8TITODku0pRI27l+Zk0IY0TrRTw3ozwM');
}
public function testSetPrivate()
{
$rsa = new RSA();
$key = '-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
-----END RSA PUBLIC KEY-----';
$this->assertTrue($rsa->load($key));
$this->assertTrue($rsa->setPrivateKey());
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
$this->assertFalse($rsa->getPublicKey());
}
/**
* make phpseclib generated XML keys be unsigned. this may need to be reverted
* if it is later learned that XML keys are, in fact, supposed to be signed
* @group github468
*/
public function testUnsignedXML()
{
$rsa = new RSA();
$key = '<RSAKeyValue>
<Modulus>v5OxcEgxPUfa701NpxnScCmlRkbwSGBiTWobHkIWZEB+AlRTHaVoZg/D8l6YzR7VdQidG6gF+nuUMjY75dBXgY/XcyVq0Hccf1jTfgARuNuq4GGG3hnCJVi2QsOgcf9R7TeXn+p1RKIhjQoWCiEQeEBTotNbJhcabNcPGSEJw+s=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>';
$rsa->load($key);
$rsa->setPublicKey();
$newkey = $rsa->getPublicKey('XML');
$this->assertSame(strtolower(preg_replace('#\s#', '', $key)), strtolower(preg_replace('#\s#', '', $newkey)));
}
/**
* @group github468
*/
public function testSignedPKCS1()
{
$rsa = new RSA();
$key = '-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/k7FwSDE9R9rvTU2nGdJwKaVG
RvBIYGJNahseQhZkQH4CVFMdpWhmD8PyXpjNHtV1CJ0bqAX6e5QyNjvl0FeBj9dz
JWrQdxx/WNN+ABG426rgYYbeGcIlWLZCw6Bx/1HtN5ef6nVEoiGNChYKIRB4QFOi
01smFxps1w8ZIQnD6wIDAQAB
-----END PUBLIC KEY-----';
$rsa->load($key);
$rsa->setPublicKey();
$newkey = $rsa->getPublicKey();
$this->assertSame(preg_replace('#\s#', '', $key), preg_replace('#\s#', '', $newkey));
}
/**
* @group github861
*/
public function testPKCS8Only()
{
$rsa = new RSA();
$key = '-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKB0yPMAbUHKqJxP
5sjG9AOrQSAYNDc34NsnZ1tsi7fZ9lHlBaKZ6gjm2U9q+/qCKv2BuGINxWo2CMJp
DHNY0QTt7hThr3B4U62z1CWWGnfLhFtHKH6jNYYOGc4x0jgT88uSrKFvUOLhjkjW
bURmJMpN+OjLJuZQZ7uwoqtT3IEDAgMBAAECgYBaElS/fEzYst/Fp2DA8lYGPTs4
vf2JxbdWrp7phlxEH3mTbUGljkr/Jj90wnSiojFpz0jm2h4oyh5Oq9OOaJwkCYcu
2lcHJvFlhR2XEJpd1bHHcvDwZHdUjSpnO8kvwQtjuTnho2ntRzAA4wIJVSd7Tynj
0IFEKmzhSKIvIIeN8QJBANLa10R1vs+YqpLdpAuc6Z9GYhHuh1TysBPw2xNtw3Xf
tGPx4/53eQ0RwiHdw9Opgt8CBHErD6KzziflfxUrIXkCQQDCz4t01qYWT43kxS6k
TcnZb/obho6akGc8C1hSxFIIGUa9hAhMpY2W6GXeGpv5TZtEJZIJE1VHTLvcLSGm
ILNbAkEAgq9mWqULxYket3Yt1ZDEb5Zk9C49rJXaMhHHBoyyZ51mJcfngnE0Erid
9PWJCOf4GBYdALMqtrHwpWOlV05rKQJAd6Tz50w1MRqm8MvRe4Ny5qIJH4Kibncl
kBD/q8V7BBJSCe7fEgPTU81jUudQx+pL46yXZg+DnoiYD/9/3QHUZQJBAMBiKiZ7
qMnD/pkHR/NFcYSYShUJS0cHyryVl7/eCclsQlZTRdnVTtKF9xPGTQC8fK0G7BDN
Z2sKniRCcDT1ZP4=
-----END PRIVATE KEY-----';
$result = $rsa->load($key, 'PKCS8');
$this->assertTrue($result);
}
public function testPKCS1EncryptionChange()
{
$rsa = new RSA();
$key = 'PuTTY-User-Key-File-2: ssh-rsa
Encryption: none
Comment: phpseclib-generated-key
Public-Lines: 4
AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4
eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RK
NUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDy
R4e9T04ZZw==
Private-Lines: 8
AAAAgBYo5KOevqhsjfDNEVcmkQF8/vsU6hwS4d7ceFYDLa0PlhIAo4aE8KNtyjAQ
LiRkmJ0ZqAWTN5TH0ynryJAInTxMb2AnZuXWKt106C5JC7+S9qSCFThTAxvihEpw
BVe5dnPnJ80TFtPm+n/JkdQic2bsVSy+kNNn7y4uef5m0mMRAAAAQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJ
rmfPwIGm63ilAAAAQQDEIvkdBvZtCvgHKitwxab+EQ/YxnNE5XvfIXjWE+xEL2br
oquF470c9Mm6jf/2zmn6yobE6UUvQ0O3hKSiyOAbAAAAQBGoiuSoSjafUhV7i1cE
Gpb88h5NBYZzWXGZ37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ
4p0=
Private-MAC: 03e2cb74e1d67652fbad063d2ed0478f31bdf256
';
$key = preg_replace('#(?<!\r)\n#', "\r\n", $key);
$this->assertTrue($rsa->load($key));
PKCS1::setEncryptionAlgorithm('AES-256-CBC');
$rsa->setPassword('demo');
$encryptedKey = (string) $rsa;
$this->assertRegExp('#AES-256-CBC#', $encryptedKey);
$rsa = new RSA();
$rsa->setPassword('demo');
$this->assertTrue($rsa->load($encryptedKey));
$rsa->setPassword();
$rsa->setPrivateKeyFormat('PuTTY');
$key2 = (string) $rsa;
$this->assertSame($key, $key2);
}
public function testRawKey()
{
$rsa = new RSA();
$key = array(
'e' => new BigInteger('10001', 16),
'n' => new BigInteger('aa18aba43b50deef38598faf87d2ab634e4571c130a9bca7b878267414faab8b471bd8965f5c9fc3' .
'818485eaf529c26246f3055064a8de19c8c338be5496cbaeb059dc0b358143b44a35449eb2641131' .
'21a455bd7fde3fac919e94b56fb9bb4f651cdb23ead439d6cd523eb08191e75b35fd13a7419b3090' .
'f24787bd4f4e1967', 16)
);
$this->assertTrue($rsa->load($key));
$rsa->setPublicKeyFormat('raw');
$this->assertEmpty("$rsa");
}
public function testRawComment()
{
$key = 'PuTTY-User-Key-File-2: ssh-rsa
Encryption: aes256-cbc
Comment: phpseclib-generated-key
Public-Lines: 4
AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4
eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RK
NUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDy
R4e9T04ZZw==
Private-Lines: 8
llx04QMegql0/nE5RvcJSrGrodxt6ytuv/JX2caeZBUyQwQc2WBNYagLHyHPM9jI
9OUWz59FLhjFXZMDNMoUXxVmjwQpOAaVPYNxxFM9AF6/NXFji64K7huD9n4A+kLn
sHwMLWPR5a/tZA0r05DZNz9ULA3mQu7Hz4EQ8ifu3uTPJuTmL51x6RmudYKysb20
fM8VzC3ukvzzRh0pujUVTr/yQdmciASVFnZlt4xQy+ZEOVUAOfwjd//AFfXTvk6x
7A45rNlU/uicHwLgoY1APvRHCFxw7F+uVW5L4mSX7NNzqBKkZ+1qpQTAfQvIfEIb
444+CXsgIyOpqt6VxJH2u6elAtE1wau3YaFR8Alm8m97rFYzRi3oDP5NZYkTCWSV
EOpSeghXSs7IilJu8I6/sB1w5dakdeBSFkIynrlFXkO0uUw+QJJWjxY8SypzgIuP
DzduF6XsQrCyo6dnIpGQCQ==
Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
$raw = PuTTY::load($key, 'password');
$this->assertArrayHasKey('comment', $raw);
$this->assertEquals($raw['comment'], 'phpseclib-generated-key');
$rsa = new RSA();
$rsa->load($raw);
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
}
public function testPrivateMSBlob()
{
$key = 'BwIAAACkAABSU0EyAAQAAAEAAQAnh6FFs6kYe/gmb9dzqsQKmtjFE9mxNAe9mEU3OwOEEfyI' .
'wkAx0/8dwh12fuP4wzNbdZAq4mmqCE6Lo8wTNNIJVNYEhKq5chHg1+hPDgfETFgtEO54JZSg' .
'3cBZWEV/Tq3LHEX8CaLvHZxMEfFXbTfliFYMLoJ+YK1mpg9GYcmbrVmMAKSoOgETkkiJJzYm' .
'XftO3KOveBtvkAzjHxxSS1yP/Ba10BzeIleH96SbTuQtQRLXwRykdX9uazK+YsiSud9/PyLb' .
'gy5TI+o28OHq5P+0y5+a9IaAQ/92UwlrkHUYfhN/xTVlUIxKlTEdUQTIf+iHif8d4ABb3OdY' .
'JXZOW6fGeUP10jMyvbnrEoPDsYy9qfNk++0/8UP2NeO1IATszuZYg1nEXOW/5jmUxMCdiFyd' .
'p9ES211kpEZ4XcvjGaDlaQ+bLWj05i2m/9aHYcBrfcxxvlMa/9ZvrX4DfPWeydUDDDQ4+ntp' .
'T50BunSvmyf7cUk76Bf2sPgLXUQFoufEQ5g1Qo/v1uyhWBJzh6OSUO/DDXN/s8ec/tN05RQQ' .
'FZQ0na+v0hOCrV9IuRqtBuj4WAj1I/A1JjwyyP9Y/6yWFPM6EcS/6lyPy30lJPoULh7G29zk' .
'n7NVdTEkDtthdDjtX7Qhgd9qWvm5ADlmnvsS9A5m7ToOgQyOxtJoSlLitLbf/09LRycl/cdI' .
'zoMOCEdPe3DQcyEKqUPsghAq+DKw3uZpXwHzwTdfqlHSWAnHDggFKV1HZuWc1c4rV4k4b513TqE=';
$plaintext = 'zzz';
$privKey = new RSA();
$privKey->load($key);
$this->assertSame($privKey->getLoadedFormat(), 'MSBLOB');
$this->assertGreaterThanOrEqual(1, strlen("$privKey"));
$pubKey = new RSA();
$pubKey->load($privKey->getPublicKey('msblob'));
$this->assertGreaterThanOrEqual(1, strlen("$pubKey"));
$ciphertext = $pubKey->encrypt($plaintext);
$this->assertSame($privKey->decrypt($ciphertext), $plaintext);
}
public function testNakedOpenSSHKey()
{
$key = 'AAAAB3NzaC1yc2EAAAABIwAAAIEA/NcGSQFZ0ZgN1EbDusV6LLwLnQjs05ljKcVVP7Z6aKIJUyhUDHE30uJa5XfwPPBsZ3L3Q7S0yycVcuuHjdauugmpn9xx+gyoYs7UiV5G5rvxNcA/Tc+MofGhAMiTmNicorNAs5mv6fRoVbkpIONRXPz6WK0kjx/X04EV42Vm9Qk=';
$rsa = new RSA();
$rsa->load($key);
$this->assertSame($rsa->getLoadedFormat(), 'OpenSSH');
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
}
public function testPuttyPublicKey()
{
$key = '---- BEGIN SSH2 PUBLIC KEY ----
Comment: "rsa-key-20151023"
AAAAB3NzaC1yc2EAAAABJQAAAIEAhC/CSqJ+8vgeQ4H7fJru29h/McqAC9zdGzw0
9QsifLQ7s5MvXCavhjUPYIfV0KsdLQydNPLJcbKpXmpVD9azo61zLXwsYr8d1eHr
C/EwUYl8b0fAwEsEF3myb+ryzgA9ihY08Zs9NZdmt1Maa+I7lQcLX9F/65YdcAch
ILaEujU=
---- END SSH2 PUBLIC KEY ----';
$rsa = new RSA();
$rsa->load($key);
$this->assertSame($rsa->getLoadedFormat(), 'PuTTY');
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
}
/**
* @group github960
*/
public function testSetLoad()
{
$key = 'PuTTY-User-Key-File-2: ssh-rsa
Encryption: aes256-cbc
Comment: phpseclib-generated-key
Public-Lines: 4
AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4
eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RK
NUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDy
R4e9T04ZZw==
Private-Lines: 8
llx04QMegql0/nE5RvcJSrGrodxt6ytuv/JX2caeZBUyQwQc2WBNYagLHyHPM9jI
9OUWz59FLhjFXZMDNMoUXxVmjwQpOAaVPYNxxFM9AF6/NXFji64K7huD9n4A+kLn
sHwMLWPR5a/tZA0r05DZNz9ULA3mQu7Hz4EQ8ifu3uTPJuTmL51x6RmudYKysb20
fM8VzC3ukvzzRh0pujUVTr/yQdmciASVFnZlt4xQy+ZEOVUAOfwjd//AFfXTvk6x
7A45rNlU/uicHwLgoY1APvRHCFxw7F+uVW5L4mSX7NNzqBKkZ+1qpQTAfQvIfEIb
444+CXsgIyOpqt6VxJH2u6elAtE1wau3YaFR8Alm8m97rFYzRi3oDP5NZYkTCWSV
EOpSeghXSs7IilJu8I6/sB1w5dakdeBSFkIynrlFXkO0uUw+QJJWjxY8SypzgIuP
DzduF6XsQrCyo6dnIpGQCQ==
Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
$rsa = new RSA();
$rsa->setPrivateKey($key);
$rsa->load($key);
$rsa = new RSA();
$rsa->load($key);
$rsa->setPrivateKey();
$rsa->load($rsa);
}
/**
* @group github980
*/
public function testZeroComponents()
{
$key = '-----BEGIN RSA PRIVATE KEY-----
MIGaAgEAAkEAt5yrcHAAjhglnCEn6yecMWPeUXcMyo0+itXrLlkpcKIIyqPw546b
GThhlb1ppX1ySX/OUA4jSakHekNP5eWPawIBAAJAW6/aVD05qbsZHMvZuS2Aa5Fp
NNj0BDlf38hOtkhDzz/hkYb+EBYLLvldhgsD0OvRNy8yhz7EjaUqLCB0juIN4QIB
AAIBAAIBAAIBAAIBAA==
-----END RSA PRIVATE KEY-----';
$rsa = new RSA();
$rsa->load($key);
$rsa->setHash('md5');
$rsa->setMGFHash('md5');
$rsa->sign('zzzz', RSA::PADDING_PKCS1);
}
}

View File

@ -0,0 +1,135 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2013 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\RSA;
use phpseclib\Math\BigInteger;
class Unit_Crypt_RSA_ModeTest extends PhpseclibTestCase
{
public function testEncryptionModeNone()
{
$plaintext = 'a';
$rsa = new RSA();
$privatekey = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
$rsa->load($privatekey);
$rsa->load($rsa->getPublicKey());
$expected = '105b92f59a87a8ad4da52c128b8c99491790ef5a54770119e0819060032fb9e772ed6772828329567f3d7e9472154c1530f8156ba7fd732f52ca1c06' .
'5a3f5ed8a96c442e4662e0464c97f133aed31262170201993085a589565d67cc9e727e0d087e3b225c8965203b271e38a499c92fc0d6502297eca712' .
'4d04bd467f6f1e7c';
$expected = pack('H*', $expected);
$result = $rsa->encrypt($plaintext, RSA::PADDING_NONE);
$this->assertEquals($result, $expected);
$rsa->load($privatekey);
$this->assertEquals(trim($rsa->decrypt($result, RSA::PADDING_NONE), "\0"), $plaintext);
}
/**
* @group github768
*/
public function testPSSSigs()
{
$rsa = new RSA();
$rsa->setHash('sha1');
$rsa->setMGFHash('sha1');
$rsa->load('-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVx
wTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFnc
CzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0T
p0GbMJDyR4e9T04ZZwIDAQAB
-----END PUBLIC KEY-----');
$sig = pack('H*', '1bd29a1d704a906cd7f726370ce1c63d8fb7b9a620871a05f3141a311c0d6e75fefb5d36dfb50d3ea2d37cd67992471419bfadd35da6e13b494' .
'058ddc9b568d4cfea13ddc3c62b86a6256f5f296980d1131d3eaec6089069a3de79983f73eae20198a18721338b4a66e9cfe80e4f8e4fcef7a5bead5cbb' .
'b8ac4c76adffbc178c');
$this->assertTrue($rsa->verify('zzzz', $sig));
}
/**
* @expectedException \OutOfBoundsException
*/
public function testSmallModulo()
{
$plaintext = 'x';
$n = new BigInteger(base64_decode('272435F22706FA96DE26E980D22DFF67'), 256);
$e = new BigInteger(base64_decode('158753FF2AF4D1E5BBAB574D5AE6B54D'), 256);
$rsa = new RSA();
$rsa->load(array('n' => $n, 'e' => $e));
$rsa->encrypt($plaintext);
}
public function testPKCS1LooseVerify()
{
$rsa = new RSA();
$rsa->load('-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAMuqkz8ij+ESAaNvgocVGmapjlrIldmhRo4h2NX4e6IXiCLTSxASQtY4
iqRnmyxqQSfaan2okTfQ6sP95bl8Qz8lgneW3ClC6RXG/wpJgsx7TXQ2kodlcKBF
m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE=
-----END RSA PUBLIC KEY-----');
$message = base64_decode('MYIBLjAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNDA1MTUxNDM4MzRaMC8GCSqGSIb3DQEJBDEiBCBLzLIBGdOf0L2WRrIY' .
'9KTwiHnReBW48S9C7LNRaPp5mDCBwgYLKoZIhvcNAQkQAi8xgbIwga8wgawwgakEIJDB9ZGwihf+TaiwrHQNkNHkqbN8Nuws0e77QNObkvFZMIGEMHCkbjBs' .
'MQswCQYDVQQGEwJJVDEYMBYGA1UECgwPQXJ1YmFQRUMgUy5wLkEuMSEwHwYDVQQLDBhDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eUMxIDAeBgNVBAMMF0FydWJh' .
'UEVDIFMucC5BLiBORyBDQSAzAhAv4L3QcFssQNLDYN/Vu40R');
$sig = base64_decode('XDSZWw6IcUj8ICxRJf04HzF8stzoiFAZSR2a0Rw3ziZxTOT0/NVUYJO5+9TaaREXEgxuCLpgmA+6W2SWrrGoxbbNfaI90ZoKeOAws4IX+9RfiWuooibjKcvt' .
'GJYVVOCcjvQYxUUNbQ4EjCUonk3h7ECXfCCmWqbeq2LsyXeeYGE=');
$this->assertTrue($rsa->verify($message, $sig, RSA::PADDING_RELAXED_PKCS1));
}
public function testZeroLengthSalt()
{
$plaintext = 'a';
$rsa = new RSA();
$privatekey = '-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----';
$rsa->load($privatekey);
$rsa->setSaltLength(0);
$rsa->setHash('sha1');
$rsa->setMGFHash('sha1');
// Check we generate the correct signature.
$sig = pack('H*', '0ddfc93548e21d015c0a289a640b3b79aecfdfae045f583c5925b91cc5c399bba181616ad6ae20d9662d966f0eb2fddb550f4733268e34d640f4c9dadcaf25b3c82c42130a5081c6ebad7883331c65b25b6a37ffa7c4233a468dae56180787e2718ed87c48d8d50b72f5850e4a40963b4f36710be250ecef6fe0bb91249261a3');
$this->assertEquals($sig, $rsa->sign($plaintext));
// Check we can verify the signature correctly.
$rsa->load($rsa->getPublicKey());
$this->assertTrue($rsa->verify($plaintext, $sig));
}
}

View File

@ -0,0 +1,55 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Random;
class Unit_Crypt_RandomTest extends PhpseclibTestCase
{
public function stringLengthData()
{
return array_map(array($this, 'wrap'), array(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 17, 19, 20, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 111, 128, 1000,
1024, 10000, 12345, 100000, 123456
));
}
/** @dataProvider stringLengthData */
public function testStringLength($length)
{
$this->assertSame(
$length,
strlen(Random::string($length)),
'Failed asserting that a string of expected length was generated.'
);
}
/**
* Takes a set of random values of length 128 bits and asserts all taken
* values are unique.
*/
public function testStringUniqueness()
{
$values = array();
for ($i = 0; $i < 10000; ++$i) {
$rand = Random::string(16);
$this->assertSame(16, strlen($rand));
$this->assertArrayNotHasKey(
$rand,
$values,
'Failed asserting that generated value does not exist in set.'
);
$values[$rand] = true;
}
}
protected function wrap($x)
{
// array() is not a function, but $this->wrap() is.
return array($x);
}
}

View File

@ -0,0 +1,191 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
use phpseclib\Crypt\TripleDES;
class Unit_Crypt_TripleDESTest extends PhpseclibTestCase
{
var $engines = array(
Base::ENGINE_INTERNAL => 'internal',
Base::ENGINE_MCRYPT => 'mcrypt',
Base::ENGINE_OPENSSL => 'OpenSSL',
);
public function engineVectors()
{
// tests from http://csrc.nist.gov/publications/nistpubs/800-20/800-20.pdf#page=273
$tests = array(
// Table A.1
// key, plaintext, ciphertext
array(str_repeat("\x01", 24), pack('H*', '8000000000000000'), pack('H*', '95F8A5E5DD31D900')),
array(str_repeat("\x01", 24), pack('H*', '4000000000000000'), pack('H*', 'DD7F121CA5015619')),
array(str_repeat("\x01", 24), pack('H*', '2000000000000000'), pack('H*', '2E8653104F3834EA')),
array(str_repeat("\x01", 24), pack('H*', '1000000000000000'), pack('H*', '4BD388FF6CD81D4F')),
array(str_repeat("\x01", 24), pack('H*', '0800000000000000'), pack('H*', '20B9E767B2FB1456')),
array(str_repeat("\x01", 24), pack('H*', '0400000000000000'), pack('H*', '55579380D77138EF')),
array(str_repeat("\x01", 24), pack('H*', '0200000000000000'), pack('H*', '6CC5DEFAAF04512F')),
array(str_repeat("\x01", 24), pack('H*', '0100000000000000'), pack('H*', '0D9F279BA5D87260')),
array(str_repeat("\x01", 24), pack('H*', '0080000000000000'), pack('H*', 'D9031B0271BD5A0A')),
array(str_repeat("\x01", 24), pack('H*', '0040000000000000'), pack('H*', '424250B37C3DD951')),
array(str_repeat("\x01", 24), pack('H*', '0020000000000000'), pack('H*', 'B8061B7ECD9A21E5')),
array(str_repeat("\x01", 24), pack('H*', '0010000000000000'), pack('H*', 'F15D0F286B65BD28')),
array(str_repeat("\x01", 24), pack('H*', '0008000000000000'), pack('H*', 'ADD0CC8D6E5DEBA1')),
array(str_repeat("\x01", 24), pack('H*', '0004000000000000'), pack('H*', 'E6D5F82752AD63D1')),
array(str_repeat("\x01", 24), pack('H*', '0002000000000000'), pack('H*', 'ECBFE3BD3F591A5E')),
array(str_repeat("\x01", 24), pack('H*', '0001000000000000'), pack('H*', 'F356834379D165CD')),
array(str_repeat("\x01", 24), pack('H*', '0000800000000000'), pack('H*', '2B9F982F20037FA9')),
array(str_repeat("\x01", 24), pack('H*', '0000400000000000'), pack('H*', '889DE068A16F0BE6')),
array(str_repeat("\x01", 24), pack('H*', '0000200000000000'), pack('H*', 'E19E275D846A1298')),
array(str_repeat("\x01", 24), pack('H*', '0000100000000000'), pack('H*', '329A8ED523D71AEC')),
array(str_repeat("\x01", 24), pack('H*', '0000080000000000'), pack('H*', 'E7FCE22557D23C97')),
array(str_repeat("\x01", 24), pack('H*', '0000040000000000'), pack('H*', '12A9F5817FF2D65D')),
array(str_repeat("\x01", 24), pack('H*', '0000020000000000'), pack('H*', 'A484C3AD38DC9C19')),
array(str_repeat("\x01", 24), pack('H*', '0000010000000000'), pack('H*', 'FBE00A8A1EF8AD72')),
array(str_repeat("\x01", 24), pack('H*', '0000008000000000'), pack('H*', '750D079407521363')),
array(str_repeat("\x01", 24), pack('H*', '0000004000000000'), pack('H*', '64FEED9C724C2FAF')),
array(str_repeat("\x01", 24), pack('H*', '0000002000000000'), pack('H*', 'F02B263B328E2B60')),
array(str_repeat("\x01", 24), pack('H*', '0000001000000000'), pack('H*', '9D64555A9A10B852')),
array(str_repeat("\x01", 24), pack('H*', '0000000800000000'), pack('H*', 'D106FF0BED5255D7')),
array(str_repeat("\x01", 24), pack('H*', '0000000400000000'), pack('H*', 'E1652C6B138C64A5')),
array(str_repeat("\x01", 24), pack('H*', '0000000200000000'), pack('H*', 'E428581186EC8F46')),
array(str_repeat("\x01", 24), pack('H*', '0000000100000000'), pack('H*', 'AEB5F5EDE22D1A36')),
array(str_repeat("\x01", 24), pack('H*', '0000000080000000'), pack('H*', 'E943D7568AEC0C5C')),
array(str_repeat("\x01", 24), pack('H*', '0000000040000000'), pack('H*', 'DF98C8276F54B04B')),
array(str_repeat("\x01", 24), pack('H*', '0000000020000000'), pack('H*', 'B160E4680F6C696F')),
array(str_repeat("\x01", 24), pack('H*', '0000000010000000'), pack('H*', 'FA0752B07D9C4AB8')),
array(str_repeat("\x01", 24), pack('H*', '0000000008000000'), pack('H*', 'CA3A2B036DBC8502')),
array(str_repeat("\x01", 24), pack('H*', '0000000004000000'), pack('H*', '5E0905517BB59BCF')),
array(str_repeat("\x01", 24), pack('H*', '0000000002000000'), pack('H*', '814EEB3B91D90726')),
array(str_repeat("\x01", 24), pack('H*', '0000000001000000'), pack('H*', '4D49DB1532919C9F')),
array(str_repeat("\x01", 24), pack('H*', '0000000000800000'), pack('H*', '25EB5FC3F8CF0621')),
array(str_repeat("\x01", 24), pack('H*', '0000000000400000'), pack('H*', 'AB6A20C0620D1C6F')),
array(str_repeat("\x01", 24), pack('H*', '0000000000200000'), pack('H*', '79E90DBC98F92CCA')),
array(str_repeat("\x01", 24), pack('H*', '0000000000100000'), pack('H*', '866ECEDD8072BB0E')),
array(str_repeat("\x01", 24), pack('H*', '0000000000080000'), pack('H*', '8B54536F2F3E64A8')),
array(str_repeat("\x01", 24), pack('H*', '0000000000040000'), pack('H*', 'EA51D3975595B86B')),
array(str_repeat("\x01", 24), pack('H*', '0000000000020000'), pack('H*', 'CAFFC6AC4542DE31')),
array(str_repeat("\x01", 24), pack('H*', '0000000000010000'), pack('H*', '8DD45A2DDF90796C')),
array(str_repeat("\x01", 24), pack('H*', '0000000000008000'), pack('H*', '1029D55E880EC2D0')),
array(str_repeat("\x01", 24), pack('H*', '0000000000004000'), pack('H*', '5D86CB23639DBEA9')),
array(str_repeat("\x01", 24), pack('H*', '0000000000002000'), pack('H*', '1D1CA853AE7C0C5F')),
array(str_repeat("\x01", 24), pack('H*', '0000000000001000'), pack('H*', 'CE332329248F3228')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000800'), pack('H*', '8405D1ABE24FB942')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000400'), pack('H*', 'E643D78090CA4207')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000200'), pack('H*', '48221B9937748A23')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000100'), pack('H*', 'DD7C0BBD61FAFD54')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000080'), pack('H*', '2FBC291A570DB5C4')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000040'), pack('H*', 'E07C30D7E4E26E12')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000020'), pack('H*', '0953E2258E8E90A1')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000010'), pack('H*', '5B711BC4CEEBF2EE')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000008'), pack('H*', 'CC083F1E6D9E85F6')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000004'), pack('H*', 'D2FD8867D50D2DFE')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000002'), pack('H*', '06E7EA22CE92708F')),
array(str_repeat("\x01", 24), pack('H*', '0000000000000001'), pack('H*', '166B40B44ABA4BD6'))
);
$result = array();
foreach ($this->engines as $engine => $engineName) {
foreach ($tests as $test) {
$result[] = array($engine, $engineName, $test[0], $test[1], $test[2]);
}
}
return $result;
}
/**
* @dataProvider engineVectors
*/
public function testVectors($engine, $engineName, $key, $plaintext, $expected)
{
$des = new TripleDES(TripleDES::MODE_CBC);
if (!$des->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
}
$des->setPreferredEngine($engine);
$des->setKey($key);
$des->setIV(str_repeat("\0", $des->getBlockLength() >> 3));
$des->disablePadding();
$result = $des->encrypt($plaintext);
$plaintext = bin2hex($plaintext);
$this->assertEquals($result, $expected, "Failed asserting that $plaintext yielded expected output in $engineName engine");
}
public function engineIVVectors()
{
$engines = array(
Base::ENGINE_INTERNAL => 'internal',
Base::ENGINE_MCRYPT => 'mcrypt',
Base::ENGINE_OPENSSL => 'OpenSSL',
);
// tests from http://csrc.nist.gov/groups/STM/cavp/documents/des/DESMMT.pdf
$tests = array(
// key, iv, plaintext, ciphertext
array(
pack('H*', '627f460e08104a10' . '43cd265d5840eaf1' . '313edf97df2a8a8c'),
pack('H*', '8e29f75ea77e5475'),
pack('H*', '326a494cd33fe756'),
pack('H*', 'b22b8d66de970692')),
array(
pack('H*', '37ae5ebf46dff2dc' . '0754b94f31cbb385' . '5e7fd36dc870bfae'),
pack('H*', '3d1de3cc132e3b65'),
pack('H*', '84401f78fe6c10876d8ea23094ea5309'),
pack('H*', '7b1f7c7e3b1c948ebd04a75ffba7d2f5'))
);
$result = array();
foreach ($engines as $engine => $engineName) {
foreach ($tests as $test) {
$result[] = array($engine, $engineName, $test[0], $test[1], $test[2], $test[3]);
}
}
return $result;
}
/**
* @dataProvider engineIVVectors
*/
public function testVectorsWithIV($engine, $engineName, $key, $iv, $plaintext, $expected)
{
$des = new TripleDES(TripleDES::MODE_CBC);
if (!$des->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
}
$des->setPreferredEngine($engine);
$des->setKey($key);
$des->setIV($iv);
$des->disablePadding();
$result = $des->encrypt($plaintext);
$plaintext = bin2hex($plaintext);
$this->assertEquals($result, $expected, "Failed asserting that $plaintext yielded expected output in $engineName engine");
}
public function testInnerChaining()
{
// regular CBC returns
// e089b6d84708c6bc80be6c2da82bd19a79ffe11f02933ac1
$expected = 'e089b6d84708c6bc6f04c8971121603d7be2861efae0f3f5';
$des = new TripleDES(TripleDES::MODE_3CBC);
$des->setKey('abcdefghijklmnopqrstuvwx');
$des->setIV(str_repeat("\0", $des->getBlockLength() >> 3));
foreach ($this->engines as $engine => $engineName) {
$des->setPreferredEngine($engine);
if (!$des->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $engineName . ' engine');
}
$result = bin2hex($des->encrypt(str_repeat('a', 16)));
$this->assertEquals($result, $expected, "Failed asserting inner chainin worked correctly in $engineName engine");
}
}
}

View File

@ -0,0 +1,75 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright MMXIII Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Crypt\Base;
use phpseclib\Crypt\Twofish;
class Unit_Crypt_TwofishTest extends PhpseclibTestCase
{
public function testVectors()
{
$engines = array(
Base::ENGINE_INTERNAL => 'internal',
Base::ENGINE_MCRYPT => 'mcrypt',
Base::ENGINE_OPENSSL => 'OpenSSL',
);
foreach ($engines as $engine => $name) {
$tf = new Twofish(Twofish::MODE_CBC);
$tf->setIV(str_repeat("\0", $tf->getBlockLength() >> 3));
$tf->disablePadding();
// tests from https://www.schneier.com/code/ecb_ival.txt
// key size = 128
$key = pack('H*', '00000000000000000000000000000000');
$tf->setKey($key);
if (!$tf->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $name . ' engine');
}
$plaintext = pack('H*', '00000000000000000000000000000000');
$ciphertext = $tf->encrypt($plaintext);
$expected = strtolower('9F589F5CF6122C32B6BFEC2F2AE8C35A');
$this->assertEquals(bin2hex($ciphertext), $expected, "Failed asserting that $plaintext yielded expected output in $name engine");
$expected = bin2hex($plaintext);
$plaintext = bin2hex($tf->decrypt($ciphertext));
$this->assertEquals($plaintext, $expected, "Failed asserting that $plaintext yielded expected output in $name engine");
// key size = 192
$key = pack('H*', '0123456789ABCDEFFEDCBA98765432100011223344556677');
$tf->setKey($key);
if (!$tf->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $name . ' engine');
}
$plaintext = pack('H*', '00000000000000000000000000000000');
$ciphertext = $tf->encrypt($plaintext);
$expected = strtolower('CFD1D2E5A9BE9CDF501F13B892BD2248');
$this->assertEquals(bin2hex($ciphertext), $expected, "Failed asserting that $plaintext yielded expected output in $name engine");
$expected = bin2hex($plaintext);
$plaintext = bin2hex($tf->decrypt($ciphertext));
$this->assertEquals($plaintext, $expected, "Failed asserting that $plaintext yielded expected output in $name engine");
// key size = 256
$key = pack('H*', '0123456789ABCDEFFEDCBA987654321000112233445566778899AABBCCDDEEFF');
$tf->setKey($key);
if (!$tf->isValidEngine($engine)) {
self::markTestSkipped('Unable to initialize ' . $name . ' engine');
}
$plaintext = pack('H*', '00000000000000000000000000000000');
$ciphertext = $tf->encrypt($plaintext);
$expected = strtolower('37527BE0052334B89F0CFCCAE87CFA20');
$this->assertEquals(bin2hex($ciphertext), $expected, "Failed asserting that $plaintext yielded expected output in $name engine");
$expected = bin2hex($plaintext);
$plaintext = bin2hex($tf->decrypt($ciphertext));
$this->assertEquals($plaintext, $expected, "Failed asserting that $plaintext yielded expected output in $name engine");
}
}
}

View File

@ -0,0 +1,31 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\File\ANSI;
class Unit_File_ANSITest extends PhpseclibTestCase
{
public function testCase1()
{
$str = "\x1B[07m"; // turn reverse video on
$str.= "aaaaaaaaaaaaaaaaaa";
$str.= "\x1B[10D"; // move cursor left 10 lines
$str.= "\x1B[m"; // reset everything
$str.= "bbb";
$ansi = new ANSI();
$ansi->appendString($str);
$expected = '<pre width="80" style="color: white; background: black">';
$expected.= '<span style="color: black"><span style="background: white">aaaaaaaa</span></span>';
$expected.= 'bbb';
$expected.= '<span style="color: black"><span style="background: white">aaaaaaa</span></span>';
$expected.= '</pre>';
$this->assertSame($ansi->getScreen(), $expected);
}
}

Binary file not shown.

View File

@ -0,0 +1,292 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\File\ASN1;
class Unit_File_ASN1Test extends PhpseclibTestCase
{
/**
* on older versions of \phpseclib\File\ASN1 this would yield a PHP Warning
* @group github275
*/
public function testAnyString()
{
$KDC_REP = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'pvno' => array(
'constant' => 0,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY),
'msg-type' => array(
'constant' => 1,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY),
'padata' => array(
'constant' => 2,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY),
'crealm' => array(
'constant' => 3,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY),
'cname' => array(
'constant' => 4,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY),
'ticket' => array(
'constant' => 5,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY),
'enc-part' => array(
'constant' => 6,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY)
)
);
$AS_REP = array(
'class' => ASN1::CLASS_APPLICATION,
'cast' => 11,
'optional' => true,
'explicit' => true
) + $KDC_REP;
$str = 'a4IC3jCCAtqgAwIBBaEDAgELoi8wLTAroQMCAROiJAQiMCAwHqADAgEXoRcbFUNSRUFUVUlUWS5ORVR0ZXN0dXNlcqMPGw' .
'1DUkVBVFVJVFkuTkVUpBUwE6ADAgEBoQwwChsIdGVzdHVzZXKlggFOYYIBSjCCAUagAwIBBaEPGw1DUkVBVFVJVFkuTkVU' .
'oiIwIKADAgECoRkwFxsGa3JidGd0Gw1DUkVBVFVJVFkuTkVUo4IBCDCCAQSgAwIBF6EDAgEBooH3BIH0AQlxgm/j4z74Ki' .
'GsJJnROhh8JAiN7pdvlnkxCYKdG6UgdfK/K0NZ+yz+Xg4kgFO1cQ4XYT4Fm3MTmOHzlFmbzlVkUqBI/RnWA9YTREC9Q7Mf' .
'PPYfRxRG/C6FlahxHCOKj9GUj7bXg7Oq3Sm+QsKTS2bZT05biNf1s7tPCkdIOO0AAd7hvTCpTNAKl+OLN4cpA6pwwk5c3h' .
'58Ce5/Uri5yBmrfwgkCD5AJUAI/WH56SEEvpifLc6C96w/7y2krAiZm5PyEO0HVhTzUjKGSHoSMb+Z3HI/ul+G9z0Z4qDu' .
'NjvgP0jKdrKiwWN00NjpiQ0byZd4y6aCASEwggEdoAMCAReiggEUBIIBEHyi8DIbdcfw2DpniBJ3Sh8dDaEbQx+gWx3omC' .
'TBEyts4sQGTwgQcqkWfeer8M+SkZs/GGZq2YYkyeF+9b6TxlYuX145NuB3KcyzaS7VNrX37E5nGgG8K6r5gTFOhLCqsjjv' .
'gPXXqLeJo5D1nV+c8BPIEVsu/bbBPgSqpDwUs2mX1WkEg5vfb7kZMC8+LHiRy+sItvIiTtxxEsQ/GEF/ono3hZrEnDa/C+' .
'4P3wep6uNMLnLzXJmUaAMaopjE+MOcai/t6T9Vg4pERF5Waqwg5ibAbVGK19HuS4LiKiaY3JsyYBuNkEDwiqM7i1Ekw3V+' .
'+zoEIxqgXjGgPdrWkzU/H6rnXiqMtiZZqUXwWY0zkCmy';
$asn1 = new ASN1();
$decoded = $asn1->decodeBER(base64_decode($str));
$result = $asn1->asn1map($decoded[0], $AS_REP);
$this->assertInternalType('array', $result);
}
/**
* on older versions of \phpseclib\File\ASN1 this would produce a null instead of an array
* @group github275
*/
public function testIncorrectString()
{
$PA_DATA = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'padata-type' => array(
'constant' => 1,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_INTEGER
),
'padata-value' => array(
'constant' => 2,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_OCTET_STRING
)
)
);
$PrincipalName = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'name-type' => array(
'constant' => 0,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_INTEGER
),
'name-string' => array(
'constant' => 1,
'optional' => true,
'explicit' => true,
'min' => 0,
'max' => -1,
'type' => ASN1::TYPE_SEQUENCE,
'children' => array('type' => ASN1::TYPE_IA5_STRING) // should be \phpseclib\File\ASN1::TYPE_GENERAL_STRING
)
)
);
$Ticket = array(
'class' => ASN1::CLASS_APPLICATION,
'cast' => 1,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'tkt-vno' => array(
'constant' => 0,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_INTEGER
),
'realm' => array(
'constant' => 1,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY
),
'sname' => array(
'constant' => 2,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY
),
'enc-part' => array(
'constant' => 3,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY
)
)
);
$KDC_REP = array(
'type' => ASN1::TYPE_SEQUENCE,
'children' => array(
'pvno' => array(
'constant' => 0,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_INTEGER),
'msg-type' => array(
'constant' => 1,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_INTEGER),
'padata' => array(
'constant' => 2,
'optional' => true,
'explicit' => true,
'min' => 0,
'max' => -1,
'type' => ASN1::TYPE_SEQUENCE,
'children' => $PA_DATA),
'crealm' => array(
'constant' => 3,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_OCTET_STRING),
'cname' => array(
'constant' => 4,
'optional' => true,
'explicit' => true) + $PrincipalName,
//'type' => ASN1::TYPE_ANY),
'ticket' => array(
'constant' => 5,
'optional' => true,
'implicit' => true,
'min' => 0,
'max' => 1,
'type' => ASN1::TYPE_SEQUENCE,
'children' => $Ticket),
'enc-part' => array(
'constant' => 6,
'optional' => true,
'explicit' => true,
'type' => ASN1::TYPE_ANY)
)
);
$AS_REP = array(
'class' => ASN1::CLASS_APPLICATION,
'cast' => 11,
'optional' => true,
'explicit' => true
) + $KDC_REP;
$str = 'a4IC3jCCAtqgAwIBBaEDAgELoi8wLTAroQMCAROiJAQiMCAwHqADAgEXoRcbFUNSRUFUVUlUWS5ORVR0ZXN0dXNlcqMPGw' .
'1DUkVBVFVJVFkuTkVUpBUwE6ADAgEBoQwwChsIdGVzdHVzZXKlggFOYYIBSjCCAUagAwIBBaEPGw1DUkVBVFVJVFkuTkVU' .
'oiIwIKADAgECoRkwFxsGa3JidGd0Gw1DUkVBVFVJVFkuTkVUo4IBCDCCAQSgAwIBF6EDAgEBooH3BIH0AQlxgm/j4z74Ki' .
'GsJJnROhh8JAiN7pdvlnkxCYKdG6UgdfK/K0NZ+yz+Xg4kgFO1cQ4XYT4Fm3MTmOHzlFmbzlVkUqBI/RnWA9YTREC9Q7Mf' .
'PPYfRxRG/C6FlahxHCOKj9GUj7bXg7Oq3Sm+QsKTS2bZT05biNf1s7tPCkdIOO0AAd7hvTCpTNAKl+OLN4cpA6pwwk5c3h' .
'58Ce5/Uri5yBmrfwgkCD5AJUAI/WH56SEEvpifLc6C96w/7y2krAiZm5PyEO0HVhTzUjKGSHoSMb+Z3HI/ul+G9z0Z4qDu' .
'NjvgP0jKdrKiwWN00NjpiQ0byZd4y6aCASEwggEdoAMCAReiggEUBIIBEHyi8DIbdcfw2DpniBJ3Sh8dDaEbQx+gWx3omC' .
'TBEyts4sQGTwgQcqkWfeer8M+SkZs/GGZq2YYkyeF+9b6TxlYuX145NuB3KcyzaS7VNrX37E5nGgG8K6r5gTFOhLCqsjjv' .
'gPXXqLeJo5D1nV+c8BPIEVsu/bbBPgSqpDwUs2mX1WkEg5vfb7kZMC8+LHiRy+sItvIiTtxxEsQ/GEF/ono3hZrEnDa/C+' .
'4P3wep6uNMLnLzXJmUaAMaopjE+MOcai/t6T9Vg4pERF5Waqwg5ibAbVGK19HuS4LiKiaY3JsyYBuNkEDwiqM7i1Ekw3V+' .
'+zoEIxqgXjGgPdrWkzU/H6rnXiqMtiZZqUXwWY0zkCmy';
$asn1 = new ASN1();
$decoded = $asn1->decodeBER(base64_decode($str));
$result = $asn1->asn1map($decoded[0], $AS_REP);
$this->assertInternalType('array', $result);
}
/**
* older versions of ASN1 didn't handle indefinite length tags very well
*/
public function testIndefiniteLength()
{
$asn1 = new ASN1();
$decoded = $asn1->decodeBER(file_get_contents(dirname(__FILE__) . '/ASN1/FE.pdf.p7m'));
$this->assertCount(5, $decoded[0]['content'][1]['content'][0]['content']); // older versions would have returned 3
}
public function testDefiniteLength()
{
// the following base64-encoded string is the X.509 cert from <http://phpseclib.sourceforge.net/x509/decoder.php>
$str = 'MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM' .
'MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg' .
'THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x' .
'MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh' .
'MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw' .
'FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC' .
'gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy' .
'wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B' .
'd3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM' .
'BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl' .
'LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF' .
'BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw' .
'Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0' .
'ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF' .
'AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp' .
'ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le' .
'IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==';
$asn1 = new ASN1();
$decoded = $asn1->decodeBER(base64_decode($str));
$this->assertCount(3, $decoded[0]['content']);
}
/**
* @group github477
*/
public function testContextSpecificNonConstructed()
{
$asn1 = new ASN1();
$decoded = $asn1->decodeBER(base64_decode('MBaAFJtUo7c00HsI5EPZ4bkICfkOY2Pv'));
$this->assertInternalType('string', $decoded[0]['content'][0]['content']);
}
/**
* @group github602
*/
public function testEmptyContextTag()
{
$asn1 = new ASN1();
$decoded = $asn1->decodeBER("\xa0\x00");
$this->assertInternalType('array', $decoded);
$this->assertCount(0, $decoded[0]['content']);
}
}

View File

@ -0,0 +1,121 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\File\X509;
use phpseclib\Crypt\RSA;
class Unit_File_X509_CSRTest extends PhpseclibTestCase
{
public function testLoadCSR()
{
$test = '-----BEGIN CERTIFICATE REQUEST-----
MIIBWzCBxQIBADAeMRwwGgYDVQQKDBNwaHBzZWNsaWIgZGVtbyBjZXJ0MIGdMAsG
CSqGSIb3DQEBAQOBjQAwgYkCgYEAtHDb4zoUyiRYsJ5PZrF/IJKAF9ZoHRpTxMA8
a7iyFdsl/vvZLNPsNnFTXXnGdvsyFDEsF7AubaIXw8UKFPYqQRTzSVsvnNgIoVYj
tTAXlB4oHipr7Kxcn4CXfmR0TYogyLvVZSZJYxh+CAuG4V9XM4HqkeE5gyBOsKGy
5FUU8zMCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBAJjdaA9K9DN5xvSiOlCmmV1E
npzHkI1Trraveu0gtRjT/EzHoqjCBI0ekCZ9+fhrex8Sm6Nsq9IgHYyrqnE+PQko
4Nf2w2U3DWxU26D5E9DlI+bLyOCq4jqATLjHyyAsOZY/2+U73AZ82MJM/mGdh5fQ
v5RwaQHmQEzHofTzF7I+
-----END CERTIFICATE REQUEST-----';
$x509 = new X509();
$spkac = $x509->loadCSR($test);
$this->assertInternalType('array', $spkac);
}
public function testCSRWithAttributes()
{
$test = '-----BEGIN NEW CERTIFICATE REQUEST-----
MIIFGDCCAwACAQAwOjEWMBQGCgmSJomT8ixkARkWBnNlY3VyZTEgMB4GA1UEAxMX
LlNlY3VyZSBFbnRlcnByaXNlIENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
ggIKAoICAQCzgEpL+Za7a3y7YpURDrxlGIBlks25fD0tHaZIYkBTaXA5h+9MWoXn
FA7AlIUt8pbBvXdJbOCmGaeQmBfBH0Qy9vTbx/DR2IOwzqy2ZHuurI5bPL12ceE2
Mxa9xgY/i7U6MAUtoA3amEd7cKj2fz9EWZruRladOX0DXv9KexSan+45QjCWH+u2
Cxem2zH9ZDNPGBuAF9YsAvkdHdAoX8aSm05ZAjUiO2e/+L57whh7zZiDY3WIhin7
N/2JNTKVO6lx50S8a34XUKBt3SKgSR941hcLrBYUNftUYsTPo40bzKKcWqemiH+w
jQiDrln4V2b5EbVeoGWe4UDPXCVmC6UPklG7iYfF0eeK4ujV8uc9PtV2LvGLOFdm
AYE3+FAba5byQATw/DY8EJKQ7ptPigJhVe47NNeJlsKwk1haJ9k8ZazjS+vT45B5
pqe0yBFAEon8TFnOLnAOblmKO12i0zqMUNAAlmr1c8jNjLr+dhruS+QropZmzZ24
mAnFG+Y0qpfhMzAxTGQyVjyGwDfRK/ARmtrGpmROjj5+6VuMmZ6Ljf3xN09epmtH
gJe+lYNBlpfUYg16tm+OusnziYnXL6nIo2ChOY/7GNJJif9fjvvaPDCC98K64av5
5rpIx7N/XH4hwHeQQkEQangExE+8UMyBNFNmvPnIHVHUZdYo4SLsYwIDAQABoIGY
MBsGCisGAQQBgjcNAgMxDRYLNi4zLjk2MDAuMi4weQYJKoZIhvcNAQkOMWwwajAQ
BgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU5nEIMEUT5mMd1WepmviwgK7dIzww
GQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAKZl6bAeaID3b/ic4aztL8ZZI7vi
D3A9otUKx6v1Xe63zDPR+DiWSnxb9m+l8OPtnWkcLkzEIM/IMWorHKUAJ/J871D0
Qx+0/HbkcrjMtVu/dNrtb9Z9CXup66ZvxTPcpEziq0/n2yw8QdBaa+lli65Qcwcy
tzMQK6WQTRYfvVCIX9AKcPKxwx1DLH+7hL/bERB1lUDu59Jx6fQfqJrFVOY2N8c0
MGvurfoHGmEoyCMIyvmIMu4+/wSNEE/sSDp4lZ6zuF6rf1m0GiLdTX2XJE+gfvep
JTFmp4S3WFqkszKvaxBIT+jV0XKTNDwnO+dpExwU4jZUh18CdEFkIUuQb0gFF8B7
WJFVpNdsRqZRPBz83BW1Kjo0yAmaoTrGNmG0p6Qf3K2zbk1+Jik3VZq4rvKoTi20
6RvLA2//cMNfkYPsuqvoHGe2e0GOLtIB63wJzloWROpb72ohEHsvCKullIJVSuiS
9sfTBAenHCyndgAEd4T3npTUdaiNumVEm5ilZId7LAYekJhkgFu3vlcl8blBJKjE
skVTp7JpBmdXCL/G/6H2SFjca4JMOAy3DxwlGdgneIaXazHs5nBK/BgKPIyPzZ4w
secxBTTCNgI48YezK3GDkn65cmlnkt6F6Mf0MwoDaXTuB88Jycbwb5ihKnHEJIsO
draiRBZruwMPwPIP
-----END NEW CERTIFICATE REQUEST-----';
$x509 = new X509();
$csr = $x509->loadCSR($test);
$this->assertInternalType('array', $csr);
}
public function testCSRDER()
{
$csr = 'MIICdzCCAV8CAQEwDDEKMAgGA1UEAwwBeDCCASIwDQYJKoZIhvcNAQEBBQADggEP' .
'ADCCAQoCggEBALtcrFDD2AHe3x2bR00wPDsPH6FJLxr5uc1ybb+ldDB5xNVImC8P' .
'LU6VXDZ5z68KjSovs1q0OWJWfCjlAuGLzqO35s86LI1CFuTFdkScVHMwh8zUVFoP' .
'pG7/9rKaNxCgaHs4evxjxQP2+Ny7tBqPLb/KV0exm6Twocf963jC/Tyn57G5erRf' .
'zpFrfK7DozhxY7znumJ4FuSn0TVkD6PPwZFn9VoTjv2ZoJmacGK+0r5yNKG799F5' .
'K8EgDrOCfbzCZjX6GJctyn2SNPTeBuXS9piH21FGnJAryv80zG+zUqFdEyoLUGJt' .
'4Vy6+tDP9cW68fiwTZS1Oc1VeFdL1G/CrjkCAwEAAaAmMCQGCSqGSIb3DQEJDjEX' .
'MBUwEwYKKwYBBAGCqlsBCQQFMAOCAQEwDQYJKoZIhvcNAQELBQADggEBAF4XOd+1' .
'jkJOYRInNpHfhzSD/ktDY50gpLPuDvl4f/ZBlKrb1eDYQG5F3bnYzoZWHN4n+6Zs' .
'CkljXs5ZPUZ5LuVpASumoG/aHXGz8c8NC3asJ1V73ljEPAfIXwqoIUoaP9jLL+Ee' .
'zy/ZCi2NKWVo2D7ocnn79oblAem9ksSeQl4z3Gvhuug6MsMqn96NU/ZY/vjYzAjb' .
'MAvJIVRY0rbCxbFa0K+XNJtF7GLyBxyPNFWCvADhvm9C4uPmoypYg7MY6EewJInN' .
'xzMH7I4xDLjNu0VBa6lAxTvflp0joQHKlTYX0SDIKPbQivjZMuObPuxDtkVZ0rQl' .
'AjmgMowaN5otTXM=';
$csr = base64_decode($csr);
$x509 = new X509();
$csr = $x509->loadCSR($csr);
$this->assertInternalType('array', $csr);
}
// on PHP 7.1, with older versions of phpseclib, this would produce a "A non-numeric value encountered" warning
public function testNewCSR()
{
$rsa = new RSA();
$x509 = new X509();
$rsa->load('-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----');
$x509->setPrivateKey($rsa);
$x509->setDN(array('cn' => 'website.com'));
$x509->saveCSR($x509->signCSR('sha256WithRSAEncryption'), X509::FORMAT_DER);
}
}

View File

@ -0,0 +1,97 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\File\X509;
use phpseclib\Crypt\RSA;
class Unit_File_X509_SPKACTest extends PhpseclibTestCase
{
public function testLoadSPKAC()
{
$test = 'MIICQDCCASgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChgo9mWzQm3TSwGgpZnIc54' .
'TZ8gYpfAO/AI0etvyWDqnFfdNCUQsqxTdSi6/rtrJdLGBsszRGrRIc/0JqmjM+jCHGYutLeo4xwgr' .
'a3HAZrWDypL5IlRWnLmLA4U/qGXCXNSk+9NrJl39X3IDA8o/aOJyr9iMUJMvswcWjVjPom3NhAgmJ' .
'ZwW0vUEMw9zszExpiRnGSO5XXntQW2qvfzo+J3NzS3BBbKxEmTsfOLHextcXeFQUaBQHXB/WOtweW' .
'Y/Bd4iZ8ETmhal28g1HWVcTFPD+V+KPRFeARlVEW6JmcJucW2WdJlBGKXXXPEfdHrDS3OgD/eDWfM' .
'JE4mChZ/icxAgMBAAEWADANBgkqhkiG9w0BAQQFAAOCAQEAUMvIKhlSgEgbC081b/FJwh6mbuVgYN' .
'ZV37Ts2WjrHoDFlabu9WXU8xzgaXct3sO51vJM5I36rY4UPyc6w3y9dLaamEwKUoWnpHG8mlXs2JG' .
'GEUOvxh5z9yfk/2ZmdCVBlKnU1LDB+ZDyNyNh5B0YULrJKw9e0jV+ymP7srwUSBcdUfZh1KEKGVIN' .
'Uv4J3GuL8V63E2unWCHGRPw4EmFVTbWpgMx96XR7p/pMavu6/pVKgYQqWLOmEeOK+dmT/QVon28d5' .
'dmeL7aWrpP+3x3L0A9cATksracQX676XogdAEXJ59fcr/S5AGw1TFErbyBbfyeAWvzDZIXeMXpb9h' .
'yNtA==';
$x509 = new X509();
$spkac = $x509->loadSPKAC($test);
$this->assertInternalType('array', $spkac);
$spkac = $x509->loadSPKAC('SPKAC=' . $test);
$this->assertInternalType('array', $spkac);
$this->assertTrue(
$x509->validateSignature(),
'Failed asserting that the signature is valid'
);
$pubKey = $x509->getPublicKey();
$this->assertInternalType('string', "$pubKey");
}
public function testSaveSPKAC()
{
$privKey = new RSA();
extract($privKey->createKey());
$x509 = new X509();
$x509->setPrivateKey($privatekey);
$x509->setChallenge('...');
$spkac = $x509->signSPKAC();
$this->assertInternalType('array', $spkac);
$this->assertInternalType('string', $x509->saveSPKAC($spkac));
$x509 = new X509();
$x509->setPrivateKey($privKey);
$spkac = $x509->signSPKAC();
$this->assertInternalType('array', $spkac);
$this->assertInternalType('string', $x509->saveSPKAC($spkac));
}
public function testBadSignatureSPKAC()
{
$test = 'MIICQDCCASgwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQChgo9mWzQm3TSwGgpZnIc54' .
'TZ8gYpfAO/AI0etvyWDqnFfdNCUQsqxTdSi6/rtrJdLGBsszRGrRIc/0JqmjM+jCHGYutLeo4xwgr' .
'a3HAZrWDypL5IlRWnLmLA4U/qGXCXNSk+9NrJl39X3IDA8o/aOJyr9iMUJMvswcWjVjPom3NhAgmJ' .
'ZwW0vUEMw9zszExpiRnGSO5XXntQW2qvfzo+J3NzS3BBbKxEmTsfOLHextcXeFQUaBQHXB/WOtweW' .
'Y/Bd4iZ8ETmhal28g1HWVcTFPD+V+KPRFeARlVEW6JmcJucW2WdJlBGKXXXPEfdHrDS3OgD/eDWfM' .
'JE4mChZ/icxAgMBAAEWADANBgkqhkiG9w0BAQQFAAOCAQEAUMvIKhlSgEgbC081b/FJwh6mbuVgYN' .
'ZV37Ts2WjrHoDFlabu9WXU8xzgaXct3sO51vJM5I36rY4UPyc6w3y9dLaamEwKUoWnpHG8mlXs2JG' .
'GEUOvxh5z9yfk/2ZmdCVBlKnU1LDB+ZDyNyNh5B0YULrJKw9e0jV+ymP7srwUSBcdUfZh1KEKGVIN' .
'Uv4J3GuL8V63E2unWCHGRPw4EmFVTbWpgMx96XR7p/pMavu6/pVKgYQqWLOmEeOK+dmT/QVon28d5' .
'dmeL7aWrpP+3x3L0A9cATksracQX676XogdAEXJ59fcr/S5AGw1TFErbyBbfyeAWvzDZIXeMXpb9h' .
'yNtA==';
$x509 = new X509();
$spkac = $x509->loadSPKAC($test);
$spkac['publicKeyAndChallenge']['challenge'] = 'zzzz';
$x509->loadSPKAC($x509->saveSPKAC($spkac));
$this->assertFalse(
$x509->validateSignature(),
'Failed asserting that the signature is invalid'
);
}
}

View File

@ -0,0 +1,457 @@
<?php
/**
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2014 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\File\ASN1;
use phpseclib\File\ASN1\Element;
use phpseclib\File\X509;
use phpseclib\Crypt\RSA;
class Unit_File_X509_X509Test extends PhpseclibTestCase
{
public function testExtensionMapping()
{
$test = '-----BEGIN CERTIFICATE-----
MIIG1jCCBL6gAwIBAgITUAAAAA0qg8bE6DhrLAAAAAAADTANBgkqhkiG9w0BAQsF
ADAiMSAwHgYDVQQDExcuU2VjdXJlIEVudGVycHJpc2UgQ0EgMTAeFw0xNTAyMjMx
NTE1MDdaFw0xNjAyMjMxNTE1MDdaMD8xFjAUBgoJkiaJk/IsZAEZFgZzZWN1cmUx
DjAMBgNVBAMTBVVzZXJzMRUwEwYDVQQDEwxtZXRhY2xhc3NpbmcwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMdG1CzR/gTalbLN9J+2cvMGeD7wsR7S78
HU5hdwE+kECROjRAcjFBOR57ezSDrkmhkTzo28tj0oAHjOh8N9vuXtASfZSCXugx
H+ImJ+E7PA4aXBp+0H2hohW9sXNNCFiVNmJLX66O4bxIeKtVRq/+eSNijV4OOEkC
zMyTHAUbOFP0t6KoJtM1syNoQ1+fKdfcjz5XtiEzSVcp2zf0MwNFSeZSgGQ0jh8A
Kd6YVKA8ZnrqOWZxKETT+bBNTjIT0ggjQfzcE4zW2RzrN7zWabUowoU92+DAp4s3
sAEywX9ISSge62DEzTnZZSf9bpoScAfT8raRFA3BkoJ/s4c4CgfPAgMBAAGjggLm
MIIC4jAdBgNVHQ4EFgQULlIyJL9+ZwAI/SkVdsJMxFOVp+EwHwYDVR0jBBgwFoAU
5nEIMEUT5mMd1WepmviwgK7dIzwwggEKBgNVHR8EggEBMIH+MIH7oIH4oIH1hoG5
bGRhcDovLy9DTj0uU2VjdXJlJTIwRW50ZXJwcmlzZSUyMENBJTIwMSxDTj1hdXRo
LENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxD
Tj1Db25maWd1cmF0aW9uLERDPXNlY3VyZT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25M
aXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnSGN2h0dHA6
Ly9jcmwuc2VjdXJlb2JzY3VyZS5jb20vP2FjdGlvbj1jcmwmY2E9ZW50ZXJwcmlz
ZTEwgccGCCsGAQUFBwEBBIG6MIG3MIG0BggrBgEFBQcwAoaBp2xkYXA6Ly8vQ049
LlNlY3VyZSUyMEVudGVycHJpc2UlMjBDQSUyMDEsQ049QUlBLENOPVB1YmxpYyUy
MEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9
c2VjdXJlP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0
aW9uQXV0aG9yaXR5MBcGCSsGAQQBgjcUAgQKHggAVQBzAGUAcjAOBgNVHQ8BAf8E
BAMCBaAwKQYDVR0lBCIwIAYKKwYBBAGCNwoDBAYIKwYBBQUHAwQGCCsGAQUFBwMC
MC4GA1UdEQQnMCWgIwYKKwYBBAGCNxQCA6AVDBNtZXRhY2xhc3NpbmdAc2VjdXJl
MEQGCSqGSIb3DQEJDwQ3MDUwDgYIKoZIhvcNAwICAgCAMA4GCCqGSIb3DQMEAgIA
gDAHBgUrDgMCBzAKBggqhkiG9w0DBzANBgkqhkiG9w0BAQsFAAOCAgEAKNmjYh+h
cObJEM0CWgz50jOYKZ4M5iIxoAWgrYY9Pv+0O9aPjvPLzjd5bY322L8lxh5wy5my
DKmip+irzjdVdxzQfoyy+ceODmCbX9L6MfEDn0RBzdwjLe1/eOxE1na0sZztrVCc
yt5nI91NNGZJUcVqVQsIA/25FWlkvo/FTfuqTuXdQiEVM5MCKJI915anmTdugy+G
0CmBJALIxtyz5P7sZhaHZFNdpKnx82QsauErqjP9H0RXc6VXX5qt+tEDvYfSlFcc
0lv3aQnV/eIdfm7APJkQ3lmNWWQwdkVf7adXJ7KAAPHSt1yvSbVxThJR/jmIkyeQ
XW/TOP5m7JI/GrmvdlzI1AgwJ+zO8fOmCDuif99pDb1CvkzQ65RZ8p5J1ZV6hzlb
VvOhn4LDnT1jnTcEqigmx1gxM/5ifvMorXn/ItMjKPlb72vHpeF7OeKE8GHsvZAm
osHcKyJXbTIcXchmpZX1efbmCMJBqHgJ/qBTBMl9BX0+YqbTZyabRJSs9ezbTRn0
oRYl21Q8EnvS71CemxEUkSsKJmfJKkQNCsOjc8AbX/V/X9R7LJkH3UEx6K2zQQKK
k6m17mi63YW/+iPCGOWZ2qXmY5HPEyyF2L4L4IDryFJ+8xLyw3pH9/yp5aHZDtp6
833K6qyjgHJT+fUzSEYpiwF5rSBJIGClOCY=
-----END CERTIFICATE-----';
$x509 = new X509();
$cert = $x509->loadX509($test);
$this->assertInternalType('array', $cert['tbsCertificate']['extensions'][3]['extnValue']);
}
public function testLoadUnsupportedExtension()
{
$test = '-----BEGIN CERTIFICATE-----
MIIG1jCCBL6gAwIBAgITUAAAAA0qg8bE6DhrLAAAAAAADTANBgkqhkiG9w0BAQsF
ADAiMSAwHgYDVQQDExcuU2VjdXJlIEVudGVycHJpc2UgQ0EgMTAeFw0xNTAyMjMx
NTE1MDdaFw0xNjAyMjMxNTE1MDdaMD8xFjAUBgoJkiaJk/IsZAEZFgZzZWN1cmUx
DjAMBgNVBAMTBVVzZXJzMRUwEwYDVQQDEwxtZXRhY2xhc3NpbmcwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMdG1CzR/gTalbLN9J+2cvMGeD7wsR7S78
HU5hdwE+kECROjRAcjFBOR57ezSDrkmhkTzo28tj0oAHjOh8N9vuXtASfZSCXugx
H+ImJ+E7PA4aXBp+0H2hohW9sXNNCFiVNmJLX66O4bxIeKtVRq/+eSNijV4OOEkC
zMyTHAUbOFP0t6KoJtM1syNoQ1+fKdfcjz5XtiEzSVcp2zf0MwNFSeZSgGQ0jh8A
Kd6YVKA8ZnrqOWZxKETT+bBNTjIT0ggjQfzcE4zW2RzrN7zWabUowoU92+DAp4s3
sAEywX9ISSge62DEzTnZZSf9bpoScAfT8raRFA3BkoJ/s4c4CgfPAgMBAAGjggLm
MIIC4jAdBgNVHQ4EFgQULlIyJL9+ZwAI/SkVdsJMxFOVp+EwHwYDVR0jBBgwFoAU
5nEIMEUT5mMd1WepmviwgK7dIzwwggEKBgNVHR8EggEBMIH+MIH7oIH4oIH1hoG5
bGRhcDovLy9DTj0uU2VjdXJlJTIwRW50ZXJwcmlzZSUyMENBJTIwMSxDTj1hdXRo
LENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxD
Tj1Db25maWd1cmF0aW9uLERDPXNlY3VyZT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25M
aXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnSGN2h0dHA6
Ly9jcmwuc2VjdXJlb2JzY3VyZS5jb20vP2FjdGlvbj1jcmwmY2E9ZW50ZXJwcmlz
ZTEwgccGCCsGAQUFBwEBBIG6MIG3MIG0BggrBgEFBQcwAoaBp2xkYXA6Ly8vQ049
LlNlY3VyZSUyMEVudGVycHJpc2UlMjBDQSUyMDEsQ049QUlBLENOPVB1YmxpYyUy
MEtleSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9
c2VjdXJlP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0
aW9uQXV0aG9yaXR5MBcGCSsGAQQBgjcUAgQKHggAVQBzAGUAcjAOBgNVHQ8BAf8E
BAMCBaAwKQYDVR0lBCIwIAYKKwYBBAGCNwoDBAYIKwYBBQUHAwQGCCsGAQUFBwMC
MC4GA1UdEQQnMCWgIwYKKwYBBAGCNxQCA6AVDBNtZXRhY2xhc3NpbmdAc2VjdXJl
MEQGCSqGSIb3DQEJDwQ3MDUwDgYIKoZIhvcNAwICAgCAMA4GCCqGSIb3DQMEAgIA
gDAHBgUrDgMCBzAKBggqhkiG9w0DBzANBgkqhkiG9w0BAQsFAAOCAgEAKNmjYh+h
cObJEM0CWgz50jOYKZ4M5iIxoAWgrYY9Pv+0O9aPjvPLzjd5bY322L8lxh5wy5my
DKmip+irzjdVdxzQfoyy+ceODmCbX9L6MfEDn0RBzdwjLe1/eOxE1na0sZztrVCc
yt5nI91NNGZJUcVqVQsIA/25FWlkvo/FTfuqTuXdQiEVM5MCKJI915anmTdugy+G
0CmBJALIxtyz5P7sZhaHZFNdpKnx82QsauErqjP9H0RXc6VXX5qt+tEDvYfSlFcc
0lv3aQnV/eIdfm7APJkQ3lmNWWQwdkVf7adXJ7KAAPHSt1yvSbVxThJR/jmIkyeQ
XW/TOP5m7JI/GrmvdlzI1AgwJ+zO8fOmCDuif99pDb1CvkzQ65RZ8p5J1ZV6hzlb
VvOhn4LDnT1jnTcEqigmx1gxM/5ifvMorXn/ItMjKPlb72vHpeF7OeKE8GHsvZAm
osHcKyJXbTIcXchmpZX1efbmCMJBqHgJ/qBTBMl9BX0+YqbTZyabRJSs9ezbTRn0
oRYl21Q8EnvS71CemxEUkSsKJmfJKkQNCsOjc8AbX/V/X9R7LJkH3UEx6K2zQQKK
k6m17mi63YW/+iPCGOWZ2qXmY5HPEyyF2L4L4IDryFJ+8xLyw3pH9/yp5aHZDtp6
833K6qyjgHJT+fUzSEYpiwF5rSBJIGClOCY=
-----END CERTIFICATE-----';
$x509 = new X509();
$cert = $x509->loadX509($test);
$this->assertEquals('MDUwDgYIKoZIhvcNAwICAgCAMA4GCCqGSIb3DQMEAgIAgDAHBgUrDgMCBzAKBggqhkiG9w0DBw==', $cert['tbsCertificate']['extensions'][8]['extnValue']);
}
public function testSaveUnsupportedExtension()
{
$x509 = new X509();
$cert = $x509->loadX509('-----BEGIN CERTIFICATE-----
MIIDITCCAoqgAwIBAgIQT52W2WawmStUwpV8tBV9TTANBgkqhkiG9w0BAQUFADBM
MQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhhd3RlIENvbnN1bHRpbmcgKFB0eSkg
THRkLjEWMBQGA1UEAxMNVGhhd3RlIFNHQyBDQTAeFw0xMTEwMjYwMDAwMDBaFw0x
MzA5MzAyMzU5NTlaMGgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlh
MRYwFAYDVQQHFA1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKFApHb29nbGUgSW5jMRcw
FQYDVQQDFA53d3cuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
gYEA3rcmQ6aZhc04pxUJuc8PycNVjIjujI0oJyRLKl6g2Bb6YRhLz21ggNM1QDJy
wI8S2OVOj7my9tkVXlqGMaO6hqpryNlxjMzNJxMenUJdOPanrO/6YvMYgdQkRn8B
d3zGKokUmbuYOR2oGfs5AER9G5RqeC1prcB6LPrQ2iASmNMCAwEAAaOB5zCB5DAM
BgNVHRMBAf8EAjAAMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwudGhhd3Rl
LmNvbS9UaGF3dGVTR0NDQS5jcmwwKAYDVR0lBCEwHwYIKwYBBQUHAwEGCCsGAQUF
BwMCBglghkgBhvhCBAEwcgYIKwYBBQUHAQEEZjBkMCIGCCsGAQUFBzABhhZodHRw
Oi8vb2NzcC50aGF3dGUuY29tMD4GCCsGAQUFBzAChjJodHRwOi8vd3d3LnRoYXd0
ZS5jb20vcmVwb3NpdG9yeS9UaGF3dGVfU0dDX0NBLmNydDANBgkqhkiG9w0BAQUF
AAOBgQAhrNWuyjSJWsKrUtKyNGadeqvu5nzVfsJcKLt0AMkQH0IT/GmKHiSgAgDp
ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le
IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==
-----END CERTIFICATE-----');
$asn1 = new ASN1();
$value = $this->_encodeOID('1.2.3.4');
$ext = chr(ASN1::TYPE_OBJECT_IDENTIFIER) . $asn1->_encodeLength(strlen($value)) . $value;
$value = 'zzzzzzzzz';
$ext.= chr(ASN1::TYPE_OCTET_STRING) . $asn1->_encodeLength(strlen($value)) . $value;
$ext = chr(ASN1::TYPE_SEQUENCE | 0x20) . $asn1->_encodeLength(strlen($ext)) . $ext;
$cert['tbsCertificate']['extensions'][4] = new Element($ext);
$result = $x509->loadX509($x509->saveX509($cert));
$this->assertCount(5, $result['tbsCertificate']['extensions']);
}
/**
* @group github705
*/
public function testSaveNullRSAParam()
{
$privKey = new RSA();
$privKey->load('-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDMswfEpAgnUDWA74zZw5XcPsWh1ly1Vk99tsqwoFDkLF7jvXy1
dDLHYfuquvfxCgcp8k/4fQhx4ubR8bbGgEq9B05YRnViK0R0iBB5Ui4IaxWYYhKE
8xqAEH2fL+/7nsqqNFKkEN9KeFwc7WbMY49U2adlMrpBdRjk1DqIEW3QTwIDAQAB
AoGBAJ+83cT/1DUJjJcPWLTeweVbPtJp+3Ku5d1OdaGbmURVs764scbP5Ihe2AuF
V9LLZoe/RdS9jYeB72nJ3D3PA4JVYYgqMOnJ8nlUMNQ+p0yGl5TqQk6EKLI8MbX5
kQEazNqFXsiWVQXubAd5wjtb6g0n0KD3zoT/pWLES7dtUFexAkEA89h5+vbIIl2P
H/NnkPie2NWYDZ1YiMGHFYxPDwsd9KCZMSbrLwAhPg9bPgqIeVNfpwxrzeksS6D9
P98tJt335QJBANbnCe+LhDSrkpHMy9aOG2IdbLGG63MSRUCPz8v2gKPq3kYXDxq6
Y1iqF8N5g0k5iirHD2qlWV5Q+nuGvFTafCMCQQC1wQiC0IkyXEw/Q31RqI82Dlcs
5rhEDwQyQof3LZEhcsdcxKaOPOmKSYX4A3/f9w4YBIEiVQfoQ1Ig1qfgDZklAkAT
TQDJcOBY0qgBTEFqbazr7PScJR/0X8m0eLYS/XqkPi3kYaHLpr3RcsVbmwg9hVtx
aBtsWpliLSex/HHhtRW9AkBGcq67zKmEpJ9kXcYLEjJii3flFS+Ct/rNm+Hhm1l7
4vca9v/F2hGVJuHIMJ8mguwYlNYzh2NqoIDJTtgOkBmt
-----END RSA PRIVATE KEY-----');
$pubKey = new RSA();
$pubKey->load($privKey->getPublicKey());
$pubKey->setPublicKey();
$subject = new X509();
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
$subject->setPublicKey($pubKey);
$issuer = new X509();
$issuer->setPrivateKey($privKey);
$issuer->setDN($subject->getDN());
$x509 = new X509();
$result = $x509->sign($issuer, $subject);
$cert = $x509->saveX509($result);
$cert = $x509->loadX509($cert);
$this->assertArrayHasKey('parameters', $cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']);
$this->assertArrayHasKey('parameters', $cert['signatureAlgorithm']);
$this->assertArrayHasKey('parameters', $cert['tbsCertificate']['signature']);
}
private function _encodeOID($oid)
{
if ($oid === false) {
user_error('Invalid OID');
return false;
}
$value = '';
$parts = explode('.', $oid);
$value = chr(40 * $parts[0] + $parts[1]);
for ($i = 2; $i < count($parts); $i++) {
$temp = '';
if (!$parts[$i]) {
$temp = "\0";
} else {
while ($parts[$i]) {
$temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
$parts[$i] >>= 7;
}
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
}
$value.= $temp;
}
return $value;
}
public function testGetOID()
{
$x509 = new X509();
$this->assertEquals($x509->getOID('2.16.840.1.101.3.4.2.1'), '2.16.840.1.101.3.4.2.1');
$this->assertEquals($x509->getOID('id-sha256'), '2.16.840.1.101.3.4.2.1');
$this->assertEquals($x509->getOID('zzz'), 'zzz');
}
public function testIPAddressSubjectAltNamesDecoding()
{
$test = '-----BEGIN CERTIFICATE-----
MIIEcTCCAlmgAwIBAgIBDjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBQuU2Vj
dXJlIElzc3VpbmcgQ0EgMTAeFw0xNjAxMjUyMzIwMjZaFw0yMTAxMjYyMzIwMjZa
MBoxGDAWBgNVBAMMDzIwNC4xNTIuMjAwLjI1MDCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAM9lMPiYQ26L5qXR1rlUXM0Z3DeRhDsJ/9NadLFJnvxKCV5L
M9rlrThpK6V5VbgPgEwKVLXGtJoGSEUkLd4roJ25ZTH08GcYszWyp8nLPQRovYnN
+aeE1aefnHcpt524f0Es9NFXh0uwRWV3ZCWSwN+mo9Qo6507KZq+q34if7/q9+De
O5RJumVQWc9OCjCt6pQBnBua9oCAca+SIHftOdgWXqVw+Xvl6/dLeF70jJD43P00
+bdAnGDgBdgO+p+K+XrOCaCWMcCsRX5xiK4hUG54UM5ayBST+McyfjsKxpO2djPg
FlSL0RLg+Nj8WehANUUuaNU874Pp3FV5GTI0ZbUCAwEAAaOBvDCBuTAMBgNVHRMB
Af8EAjAAMAsGA1UdDwQEAwIF4DATBgNVHSUEDDAKBggrBgEFBQcDATAhBgNVHREE
GjAYhwTMmMj6hxAgAQRw8wkACQAAAAAAAAADMEMGA1UdHwQ8MDowOKA2oDSGMmh0
dHA6Ly9jcmwuc2VjdXJlb2JzY3VyZS5jb20vP2FjdGlvbj1jcmwmY2E9aXNzdWUx
MB8GA1UdIwQYMBaAFOJWVCX4poZSBzemgihf9dAhFNHJMA0GCSqGSIb3DQEBCwUA
A4ICAQAce9whx4InRtzk1to6oeRxTCbeNDjNFuTkotphSws4hDoaz3nyFLSYyMT4
aKFnNP9AmMS5nEXphtP4HP9wAluTcAFMuip0rDJjiRA/khIE27KurO6cg1faFWHl
6lh6xnEf9UFZZzTLsXt2miBiMb8olgPrBuVFWjPZ/ConesJRZRFqMd5mfntXC+2V
zRcXdtwp9h/Am/WuvjsG/gBAPdeRNKffCokIcgfvffd2oklSDD0T9baG2MTgaxnX
oG6e5saWjoN8bLWuCJpvjA7aErXQwXUyXx1nrTWQ1TCR2N+M62X7e07jZLKSAECP
v6SqZ9/LDmCacVQbfg4wDC/gbpjDSKaD5fkusH6leXleWQ7X8Z03LsKvVq43a71z
jO61kkiFAh3CegWsY+TSYjZxDq58xGMiE7y/fK+SHQXDLyY7HU4eky2l3DSy8bXQ
p64vTJ/OmAcXVNUASfBCNw0kpxuFjlxers/+6zheowB1RIKo0xvSRC4cEDRl/jFA
b7WUT/MIe6B1r0v1gxHnFG2bFI/MhTT9V+tICOLo7+69z4jf/OFkzjYvqq2QWPgc
sE3f2TNnmKFRJx67bEMoaaWLIR94Yuq/TWB6dTiWwk9meZkGG3OjQg/YbO6vl/Am
NDEuGt30Vl2de7G1glnhaceB6Q9KfH7p2gAwNP9JMTtx3PtEcA==
-----END CERTIFICATE-----';
$x509 = new X509();
$cert = $x509->loadX509($test);
$this->assertEquals($cert['tbsCertificate']['extensions'][3]['extnValue'][0]['iPAddress'], '204.152.200.250');
$this->assertEquals($cert['tbsCertificate']['extensions'][3]['extnValue'][1]['iPAddress'], '2001:470:f309:9::3');
}
public function testPostalAddress()
{
$x509 = new X509();
$decoded = $x509->loadX509('-----BEGIN CERTIFICATE-----
MIIFzzCCBLegAwIBAgIDAfdlMA0GCSqGSIb3DQEBBQUAMHMxCzAJBgNVBAYTAlBM
MSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMSQwIgYD
VQQDDBtDT1BFIFNaQUZJUiAtIEt3YWxpZmlrb3dhbnkxFDASBgNVBAUTC05yIHdw
aXN1OiA2MB4XDTExMTEwOTA2MDAwMFoXDTEzMTEwOTA2MDAwMFowgdkxCzAJBgNV
BAYTAlBMMRwwGgYDVQQKDBNVcnrEhWQgTWlhc3RhIEdkeW5pMRswGQYDVQQFExJQ
RVNFTDogNjEwNjA2MDMxMTgxGTAXBgNVBAMMEEplcnp5IFByemV3b3Jza2kxTzBN
BgNVBBAwRgwiQWwuIE1hcnN6YcWCa2EgUGnFgnN1ZHNraWVnbyA1Mi81NAwNODEt
MzgyIEdkeW5pYQwGUG9sc2thDAlwb21vcnNraWUxDjAMBgNVBCoMBUplcnp5MRMw
EQYDVQQEDApQcnpld29yc2tpMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCM
m5vjGqHPthJCMqKpqssSISRos0PYDTcEQzyyurfX67EJWKtZj6HNwuDMEGJ02iBN
ZfjUl7r8dIi28bSKhNlsfycXZKYRcIjp0+r5RqtR2auo9GQ6veKb61DEAGIqaR+u
LLcJVTHCu0w9oXLGbRlGth5eNoj03CxXVAH2IfhbNwIDAQABo4IChzCCAoMwDAYD
VR0TAQH/BAIwADCCAUgGA1UdIAEB/wSCATwwggE4MIIBNAYJKoRoAYb3IwEBMIIB
JTCB3QYIKwYBBQUHAgIwgdAMgc1EZWtsYXJhY2phIHRhIGplc3Qgb8Wbd2lhZGN6
ZW5pZW0gd3lkYXdjeSwgxbxlIHRlbiBjZXJ0eWZpa2F0IHpvc3RhxYIgd3lkYW55
IGpha28gY2VydHlmaWthdCBrd2FsaWZpa293YW55IHpnb2RuaWUgeiB3eW1hZ2Fu
aWFtaSB1c3Rhd3kgbyBwb2RwaXNpZSBlbGVrdHJvbmljem55bSBvcmF6IHRvd2Fy
enlzesSFY3ltaSBqZWogcm96cG9yesSFZHplbmlhbWkuMEMGCCsGAQUFBwIBFjdo
dHRwOi8vd3d3Lmtpci5jb20ucGwvY2VydHlmaWthY2phX2tsdWN6eS9wb2xpdHlr
YS5odG1sMAkGA1UdCQQCMAAwIQYDVR0RBBowGIEWai5wcnpld29yc2tpQGdkeW5p
YS5wbDAOBgNVHQ8BAf8EBAMCBkAwgZ4GA1UdIwSBljCBk4AU3TGldJXipN4oGS3Z
YmnBDMFs8gKhd6R1MHMxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6
YmEgUm96bGljemVuaW93YSBTLkEuMSQwIgYDVQQDDBtDT1BFIFNaQUZJUiAtIEt3
YWxpZmlrb3dhbnkxFDASBgNVBAUTC05yIHdwaXN1OiA2ggJb9jBIBgNVHR8EQTA/
MD2gO6A5hjdodHRwOi8vd3d3Lmtpci5jb20ucGwvY2VydHlmaWthY2phX2tsdWN6
eS9DUkxfT1pLMzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQBYPIqnAreyeql7/opJ
jcar/qWZy9ruhB2q0lZFsJOhwgMnbQXzp/4vv93YJqcHGAXdHP6EO8FQX47mjo2Z
KQmi+cIHJHLONdX/3Im+M17V0iNAh7Z1lOSfTRT+iiwe/F8phcEaD5q2RmvYusR7
zXZq/cLL0If0hXoPZ/EHQxjN8pxzxiUx6bJAgturnIMEfRNesxwghdr1dkUjOhGL
f3kHVzgM6j3VAM7oFmMUb5y5s96Bzl10DodWitjOEH0vvnIcsppSxH1C1dCAi0o9
f/1y2XuLNhBNHMAyTqpYPX8Yvav1c+Z50OMaSXHAnTa20zv8UtiHbaAhwlifCelU
Mj93S
-----END CERTIFICATE-----');
$x509->loadX509($x509->saveX509($decoded));
$expected = array(
array(
array('utf8String' => "Al. Marsza\xC5\x82ka Pi\xC5\x82sudskiego 52/54"),
array('utf8String' => '81-382 Gdynia'),
array('utf8String' => 'Polska'),
array('utf8String' => 'pomorskie')
)
);
$this->assertEquals($x509->getDNProp('id-at-postalAddress'), $expected);
$expected = "C=PL, O=Urz\xC4\x85d Miasta Gdyni/serialNumber=PESEL: 61060603118, CN=Jerzy Przeworski/postalAddress=" . '0F\X0C"AL. MARSZA\XC5\X82KA PI\XC5\X82SUDSKIEGO 52/54\X0C\X0D81-382 GDYNIA\X0C\X06POLSKA\X0C\X09POMORSKIE/givenName=Jerzy, SN=Przeworski';
$this->assertEquals($x509->getDN(X509::DN_STRING), $expected);
}
public function testStrictComparison()
{
$x509 = new X509();
$x509->loadCA('-----BEGIN CERTIFICATE-----
MIIEbDCCA1SgAwIBAgIUJguKOMpJm/yRMDlMOW04NV0YPXowDQYJKoZIhvcNAQEF
BQAwYTELMAkGA1UEBhMCUEwxNzA1BgNVBAoTLkNaaUMgQ2VudHJhc3QgU0EgdyBp
bWllbml1IE1pbmlzdHJhIEdvc3BvZGFya2kxGTAXBgNVBAMTEENaaUMgQ2VudHJh
c3QgU0EwHhcNMDkwNDI5MTE1MzIxWhcNMTMxMjEzMjM1OTU5WjBzMQswCQYDVQQG
EwJQTDEoMCYGA1UEChMfS3Jham93YSBJemJhIFJvemxpY3plbmlvd2EgUy5BLjEk
MCIGA1UEAxMbQ09QRSBTWkFGSVIgLSBLd2FsaWZpa293YW55MRQwEgYDVQQFEwtO
ciB3cGlzdTogNjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIjNy3EL
oK0uKTqAJokiP8VIxER/0OfwhY4DBhJGW38W6Pfema8iUs4net0NgoIeDpMQ8IHj
FDSKkSaRkyL5f7PgvqBwzKe0HD1Duf9G/Lr2lu/J4QUMF3rqKaMRipXKkkEoKrub
Qe41/mPiPXeClNswNQUEyInqWpfWNncU8AIs2GKIFTfSNqK4PgWOY1kG9MYfoNVr
74dhejv7yHexEw9eAIcM1fIkEEq0vWIOjRtBXBAuWtUyD8iSeBs4nIN+614pHIjv
ncHxG7xTDbmOAVZFgGZ8Hk5CUseAtTpazQNdU66XRUuCj4km01L4wsfZ1X8tfYQA
6msMRYj+F7hLtoECAwEAAaOCAQgwggEEMA8GA1UdEwEB/wQFMAMBAf8wgY4GA1Ud
IwSBhjCBg4AU2a7r85Cp1iJNW0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBM
MTcwNQYDVQQKEy5DWmlDIENlbnRyYXN0IFNBIHcgaW1pZW5pdSBNaW5pc3RyYSBH
b3Nwb2RhcmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNBggQ9/0sQMDEGA1Ud
IAEB/wQnMCUwIwYEVR0gADAbMBkGCCsGAQUFBwIBFg13d3cubmNjZXJ0LnBsMA4G
A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU3TGldJXipN4oGS3ZYmnBDMFs8gIwDQYJ
KoZIhvcNAQEFBQADggEBAJrkn3XycfimT5C6D+lYvQNB4/X44KZRhxhnplMOdr/V
3O13oJA/G2SkVaRZS1Rqy01vC9H3YSFfYnjFXJTOXldzodwszHEcGLHF/3JazHI9
BTpP1F4oFyd0Un/wkp1usGU4e1riU5RAlSp8YcMX3q+nOqyCh0JsxnP7LjauHkE3
KZ1RuBDZYbsYOwkAKjHax8srKugdWtq4sMNcqpxGFUah/4uLQn6hD4jeRpP4VGDv
HZDmxaIoJdmCxfn9XeIS5PcZR+mHHkUOIhYLnfdUp/T3Yxxo+XrrTckC6AjtsL5/
OA0vBLngVqqeuzVf0tUhcrCwPKQo5rKoakbApeXrows=
-----END CERTIFICATE-----');
$x509->loadX509('-----BEGIN CERTIFICATE-----
MIIFzzCCBLegAwIBAgIDAfdlMA0GCSqGSIb3DQEBBQUAMHMxCzAJBgNVBAYTAlBM
MSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMSQwIgYD
VQQDDBtDT1BFIFNaQUZJUiAtIEt3YWxpZmlrb3dhbnkxFDASBgNVBAUTC05yIHdw
aXN1OiA2MB4XDTExMTEwOTA2MDAwMFoXDTEzMTEwOTA2MDAwMFowgdkxCzAJBgNV
BAYTAlBMMRwwGgYDVQQKDBNVcnrEhWQgTWlhc3RhIEdkeW5pMRswGQYDVQQFExJQ
RVNFTDogNjEwNjA2MDMxMTgxGTAXBgNVBAMMEEplcnp5IFByemV3b3Jza2kxTzBN
BgNVBBAwRgwiQWwuIE1hcnN6YcWCa2EgUGnFgnN1ZHNraWVnbyA1Mi81NAwNODEt
MzgyIEdkeW5pYQwGUG9sc2thDAlwb21vcnNraWUxDjAMBgNVBCoMBUplcnp5MRMw
EQYDVQQEDApQcnpld29yc2tpMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCM
m5vjGqHPthJCMqKpqssSISRos0PYDTcEQzyyurfX67EJWKtZj6HNwuDMEGJ02iBN
ZfjUl7r8dIi28bSKhNlsfycXZKYRcIjp0+r5RqtR2auo9GQ6veKb61DEAGIqaR+u
LLcJVTHCu0w9oXLGbRlGth5eNoj03CxXVAH2IfhbNwIDAQABo4IChzCCAoMwDAYD
VR0TAQH/BAIwADCCAUgGA1UdIAEB/wSCATwwggE4MIIBNAYJKoRoAYb3IwEBMIIB
JTCB3QYIKwYBBQUHAgIwgdAMgc1EZWtsYXJhY2phIHRhIGplc3Qgb8Wbd2lhZGN6
ZW5pZW0gd3lkYXdjeSwgxbxlIHRlbiBjZXJ0eWZpa2F0IHpvc3RhxYIgd3lkYW55
IGpha28gY2VydHlmaWthdCBrd2FsaWZpa293YW55IHpnb2RuaWUgeiB3eW1hZ2Fu
aWFtaSB1c3Rhd3kgbyBwb2RwaXNpZSBlbGVrdHJvbmljem55bSBvcmF6IHRvd2Fy
enlzesSFY3ltaSBqZWogcm96cG9yesSFZHplbmlhbWkuMEMGCCsGAQUFBwIBFjdo
dHRwOi8vd3d3Lmtpci5jb20ucGwvY2VydHlmaWthY2phX2tsdWN6eS9wb2xpdHlr
YS5odG1sMAkGA1UdCQQCMAAwIQYDVR0RBBowGIEWai5wcnpld29yc2tpQGdkeW5p
YS5wbDAOBgNVHQ8BAf8EBAMCBkAwgZ4GA1UdIwSBljCBk4AU3TGldJXipN4oGS3Z
YmnBDMFs8gKhd6R1MHMxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6
YmEgUm96bGljemVuaW93YSBTLkEuMSQwIgYDVQQDDBtDT1BFIFNaQUZJUiAtIEt3
YWxpZmlrb3dhbnkxFDASBgNVBAUTC05yIHdwaXN1OiA2ggJb9jBIBgNVHR8EQTA/
MD2gO6A5hjdodHRwOi8vd3d3Lmtpci5jb20ucGwvY2VydHlmaWthY2phX2tsdWN6
eS9DUkxfT1pLMzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQBYPIqnAreyeql7/opJ
jcar/qWZy9ruhB2q0lZFsJOhwgMnbQXzp/4vv93YJqcHGAXdHP6EO8FQX47mjo2Z
KQmi+cIHJHLONdX/3Im+M17V0iNAh7Z1lOSfTRT+iiwe/F8phcEaD5q2RmvYusR7
zXZq/cLL0If0hXoPZ/EHQxjN8pxzxiUx6bJAgturnIMEfRNesxwghdr1dkUjOhGL
f3kHVzgM6j3VAM7oFmMUb5y5s96Bzl10DodWitjOEH0vvnIcsppSxH1C1dCAi0o9
f/1y2XuLNhBNHMAyTqpYPX8Yvav1c+Z50OMaSXHAnTa20zv8UtiHbaAhwlifCelU
Mj93S
-----END CERTIFICATE-----');
$this->assertFalse($x509->validateSignature());
}
public function testLooseComparison()
{
if (!extension_loaded('runkit')) {
return false;
}
define('FILE_X509_IGNORE_TYPE', true);
$x509 = new X509();
$x509->loadCA('-----BEGIN CERTIFICATE-----
MIIEbDCCA1SgAwIBAgIUJguKOMpJm/yRMDlMOW04NV0YPXowDQYJKoZIhvcNAQEF
BQAwYTELMAkGA1UEBhMCUEwxNzA1BgNVBAoTLkNaaUMgQ2VudHJhc3QgU0EgdyBp
bWllbml1IE1pbmlzdHJhIEdvc3BvZGFya2kxGTAXBgNVBAMTEENaaUMgQ2VudHJh
c3QgU0EwHhcNMDkwNDI5MTE1MzIxWhcNMTMxMjEzMjM1OTU5WjBzMQswCQYDVQQG
EwJQTDEoMCYGA1UEChMfS3Jham93YSBJemJhIFJvemxpY3plbmlvd2EgUy5BLjEk
MCIGA1UEAxMbQ09QRSBTWkFGSVIgLSBLd2FsaWZpa293YW55MRQwEgYDVQQFEwtO
ciB3cGlzdTogNjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIjNy3EL
oK0uKTqAJokiP8VIxER/0OfwhY4DBhJGW38W6Pfema8iUs4net0NgoIeDpMQ8IHj
FDSKkSaRkyL5f7PgvqBwzKe0HD1Duf9G/Lr2lu/J4QUMF3rqKaMRipXKkkEoKrub
Qe41/mPiPXeClNswNQUEyInqWpfWNncU8AIs2GKIFTfSNqK4PgWOY1kG9MYfoNVr
74dhejv7yHexEw9eAIcM1fIkEEq0vWIOjRtBXBAuWtUyD8iSeBs4nIN+614pHIjv
ncHxG7xTDbmOAVZFgGZ8Hk5CUseAtTpazQNdU66XRUuCj4km01L4wsfZ1X8tfYQA
6msMRYj+F7hLtoECAwEAAaOCAQgwggEEMA8GA1UdEwEB/wQFMAMBAf8wgY4GA1Ud
IwSBhjCBg4AU2a7r85Cp1iJNW0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBM
MTcwNQYDVQQKEy5DWmlDIENlbnRyYXN0IFNBIHcgaW1pZW5pdSBNaW5pc3RyYSBH
b3Nwb2RhcmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNBggQ9/0sQMDEGA1Ud
IAEB/wQnMCUwIwYEVR0gADAbMBkGCCsGAQUFBwIBFg13d3cubmNjZXJ0LnBsMA4G
A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU3TGldJXipN4oGS3ZYmnBDMFs8gIwDQYJ
KoZIhvcNAQEFBQADggEBAJrkn3XycfimT5C6D+lYvQNB4/X44KZRhxhnplMOdr/V
3O13oJA/G2SkVaRZS1Rqy01vC9H3YSFfYnjFXJTOXldzodwszHEcGLHF/3JazHI9
BTpP1F4oFyd0Un/wkp1usGU4e1riU5RAlSp8YcMX3q+nOqyCh0JsxnP7LjauHkE3
KZ1RuBDZYbsYOwkAKjHax8srKugdWtq4sMNcqpxGFUah/4uLQn6hD4jeRpP4VGDv
HZDmxaIoJdmCxfn9XeIS5PcZR+mHHkUOIhYLnfdUp/T3Yxxo+XrrTckC6AjtsL5/
OA0vBLngVqqeuzVf0tUhcrCwPKQo5rKoakbApeXrows=
-----END CERTIFICATE-----');
$x509->loadX509('-----BEGIN CERTIFICATE-----
MIIFzzCCBLegAwIBAgIDAfdlMA0GCSqGSIb3DQEBBQUAMHMxCzAJBgNVBAYTAlBM
MSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMSQwIgYD
VQQDDBtDT1BFIFNaQUZJUiAtIEt3YWxpZmlrb3dhbnkxFDASBgNVBAUTC05yIHdw
aXN1OiA2MB4XDTExMTEwOTA2MDAwMFoXDTEzMTEwOTA2MDAwMFowgdkxCzAJBgNV
BAYTAlBMMRwwGgYDVQQKDBNVcnrEhWQgTWlhc3RhIEdkeW5pMRswGQYDVQQFExJQ
RVNFTDogNjEwNjA2MDMxMTgxGTAXBgNVBAMMEEplcnp5IFByemV3b3Jza2kxTzBN
BgNVBBAwRgwiQWwuIE1hcnN6YcWCa2EgUGnFgnN1ZHNraWVnbyA1Mi81NAwNODEt
MzgyIEdkeW5pYQwGUG9sc2thDAlwb21vcnNraWUxDjAMBgNVBCoMBUplcnp5MRMw
EQYDVQQEDApQcnpld29yc2tpMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCM
m5vjGqHPthJCMqKpqssSISRos0PYDTcEQzyyurfX67EJWKtZj6HNwuDMEGJ02iBN
ZfjUl7r8dIi28bSKhNlsfycXZKYRcIjp0+r5RqtR2auo9GQ6veKb61DEAGIqaR+u
LLcJVTHCu0w9oXLGbRlGth5eNoj03CxXVAH2IfhbNwIDAQABo4IChzCCAoMwDAYD
VR0TAQH/BAIwADCCAUgGA1UdIAEB/wSCATwwggE4MIIBNAYJKoRoAYb3IwEBMIIB
JTCB3QYIKwYBBQUHAgIwgdAMgc1EZWtsYXJhY2phIHRhIGplc3Qgb8Wbd2lhZGN6
ZW5pZW0gd3lkYXdjeSwgxbxlIHRlbiBjZXJ0eWZpa2F0IHpvc3RhxYIgd3lkYW55
IGpha28gY2VydHlmaWthdCBrd2FsaWZpa293YW55IHpnb2RuaWUgeiB3eW1hZ2Fu
aWFtaSB1c3Rhd3kgbyBwb2RwaXNpZSBlbGVrdHJvbmljem55bSBvcmF6IHRvd2Fy
enlzesSFY3ltaSBqZWogcm96cG9yesSFZHplbmlhbWkuMEMGCCsGAQUFBwIBFjdo
dHRwOi8vd3d3Lmtpci5jb20ucGwvY2VydHlmaWthY2phX2tsdWN6eS9wb2xpdHlr
YS5odG1sMAkGA1UdCQQCMAAwIQYDVR0RBBowGIEWai5wcnpld29yc2tpQGdkeW5p
YS5wbDAOBgNVHQ8BAf8EBAMCBkAwgZ4GA1UdIwSBljCBk4AU3TGldJXipN4oGS3Z
YmnBDMFs8gKhd6R1MHMxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6
YmEgUm96bGljemVuaW93YSBTLkEuMSQwIgYDVQQDDBtDT1BFIFNaQUZJUiAtIEt3
YWxpZmlrb3dhbnkxFDASBgNVBAUTC05yIHdwaXN1OiA2ggJb9jBIBgNVHR8EQTA/
MD2gO6A5hjdodHRwOi8vd3d3Lmtpci5jb20ucGwvY2VydHlmaWthY2phX2tsdWN6
eS9DUkxfT1pLMzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQBYPIqnAreyeql7/opJ
jcar/qWZy9ruhB2q0lZFsJOhwgMnbQXzp/4vv93YJqcHGAXdHP6EO8FQX47mjo2Z
KQmi+cIHJHLONdX/3Im+M17V0iNAh7Z1lOSfTRT+iiwe/F8phcEaD5q2RmvYusR7
zXZq/cLL0If0hXoPZ/EHQxjN8pxzxiUx6bJAgturnIMEfRNesxwghdr1dkUjOhGL
f3kHVzgM6j3VAM7oFmMUb5y5s96Bzl10DodWitjOEH0vvnIcsppSxH1C1dCAi0o9
f/1y2XuLNhBNHMAyTqpYPX8Yvav1c+Z50OMaSXHAnTa20zv8UtiHbaAhwlifCelU
Mj93S
-----END CERTIFICATE-----');
$this->assertTrue($x509->validateSignature());
runkit_constant_remove('FILE_X509_IGNORE_TYPE');
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Math_BigInteger_BCMathTest extends Unit_Math_BigInteger_TestCase
{
public static function setUpBeforeClass()
{
if (!extension_loaded('bcmath')) {
self::markTestSkipped('BCMath extension is not available.');
}
parent::setUpBeforeClass();
self::ensureConstant('MATH_BIGINTEGER_MODE', \phpseclib\Math\BigInteger::MODE_BCMATH);
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Math_BigInteger_GMPTest extends Unit_Math_BigInteger_TestCase
{
public static function setUpBeforeClass()
{
if (!extension_loaded('gmp')) {
self::markTestSkipped('GNU Multiple Precision (GMP) extension is not available.');
}
parent::setUpBeforeClass();
self::ensureConstant('MATH_BIGINTEGER_MODE', \phpseclib\Math\BigInteger::MODE_GMP);
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Math_BigInteger_InternalOpenSSLTest extends Unit_Math_BigInteger_TestCase
{
public static function setUpBeforeClass()
{
if (!extension_loaded('openssl')) {
self::markTestSkipped('openssl_public_encrypt() function is not available.');
}
parent::setUpBeforeClass();
self::ensureConstant('MATH_BIGINTEGER_MODE', \phpseclib\Math\BigInteger::MODE_INTERNAL);
}
}

View File

@ -0,0 +1,24 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2013 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Math_BigInteger_InternalTest extends Unit_Math_BigInteger_TestCase
{
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
self::ensureConstant('MATH_BIGINTEGER_MODE', \phpseclib\Math\BigInteger::MODE_INTERNAL);
self::ensureConstant('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
}
public function testInternalRepresentation()
{
$x = new \phpseclib\Math\BigInteger('FFFFFFFFFFFFFFFFC90FDA', 16);
$y = new \phpseclib\Math\BigInteger("$x");
$this->assertSame($x->value, $y->value);
}
}

View File

@ -0,0 +1,484 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2012 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
abstract class Unit_Math_BigInteger_TestCase extends PhpseclibTestCase
{
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
self::reRequireFile('Math/BigInteger.php');
}
public function getInstance($x = 0, $base = 10)
{
return new \phpseclib\Math\BigInteger($x, $base);
}
public function testConstructorBase2()
{
// 2**65 = 36893488147419103232
$this->assertSame('36893488147419103232', (string) $this->getInstance('1' . str_repeat('0', 65), 2));
}
public function testConstructorBase10()
{
$this->assertSame('18446744073709551616', (string) $this->getInstance('18446744073709551616'));
}
public function testConstructorBase16()
{
$this->assertSame('50', (string) $this->getInstance('0x32', 16));
$this->assertSame('12345678910', (string) $this->getInstance('0x2DFDC1C3E', 16));
$this->assertSame('18446744073709551615', (string) $this->getInstance('0xFFFFFFFFFFFFFFFF', 16));
$this->assertSame('18446744073709551616', (string) $this->getInstance('0x10000000000000000', 16));
}
public function testToBytes()
{
$this->assertSame(chr(65), $this->getInstance('65')->toBytes());
}
public function testToBytesTwosCompliment()
{
$this->assertSame(chr(126), $this->getInstance('01111110', 2)->toBytes(true));
}
public function testToHex()
{
$this->assertSame('41', $this->getInstance('65')->toHex());
}
public function testToBits()
{
$this->assertSame('1000001', $this->getInstance('65')->toBits());
}
public function testAdd()
{
$x = $this->getInstance('18446744073709551615');
$y = $this->getInstance('100000000000');
$a = $x->add($y);
$b = $y->add($x);
$this->assertTrue($a->equals($b));
$this->assertTrue($b->equals($a));
$this->assertSame('18446744173709551615', (string) $a);
$this->assertSame('18446744173709551615', (string) $b);
}
public function testSubtract()
{
$x = $this->getInstance('18446744073709551618');
$y = $this->getInstance('4000000000000');
$this->assertSame('18446740073709551618', (string) $x->subtract($y));
}
public function testMultiply()
{
$x = $this->getInstance('8589934592'); // 2**33
$y = $this->getInstance('36893488147419103232'); // 2**65
$a = $x->multiply($y); // 2**98
$b = $y->multiply($x); // 2**98
$this->assertTrue($a->equals($b));
$this->assertTrue($b->equals($a));
$this->assertSame('316912650057057350374175801344', (string) $a);
$this->assertSame('316912650057057350374175801344', (string) $b);
}
public function testDivide()
{
$x = $this->getInstance('1180591620717411303425'); // 2**70 + 1
$y = $this->getInstance('12345678910');
list($q, $r) = $x->divide($y);
$this->assertSame('95627922070', (string) $q);
$this->assertSame('10688759725', (string) $r);
}
public function testModPow()
{
$a = $this->getInstance('10');
$b = $this->getInstance('20');
$c = $this->getInstance('30');
$d = $a->modPow($b, $c);
$this->assertSame('10', (string) $d);
}
public function testModInverse()
{
$a = $this->getInstance(30);
$b = $this->getInstance(17);
$c = $a->modInverse($b);
$this->assertSame('4', (string) $c);
$d = $a->multiply($c);
list($q, $r) = $d->divide($b);
$this->assertSame('1', (string) $r);
}
public function testExtendedGCD()
{
$a = $this->getInstance(693);
$b = $this->getInstance(609);
$arr = $a->extendedGCD($b);
$this->assertSame('21', (string) $arr['gcd']);
$this->assertSame(21, $a->toString() * $arr['x']->toString() + $b->toString() * $arr['y']->toString());
}
public function testGCD()
{
$x = $this->getInstance(693);
$y = $this->getInstance(609);
$this->assertSame('21', (string) $x->gcd($y));
}
public function testAbs()
{
$x = $this->getInstance('-18446744073709551617');
$y = $x->abs();
$this->assertSame('-18446744073709551617', (string) $x);
$this->assertSame('18446744073709551617', (string) $y);
}
public function testEquals()
{
$x = $this->getInstance('18446744073709551616');
$y = $this->getInstance('18446744073709551616');
$this->assertTrue($x->equals($y));
$this->assertTrue($y->equals($x));
}
public function testCompare()
{
$a = $this->getInstance('-18446744073709551616');
$b = $this->getInstance('36893488147419103232');
$c = $this->getInstance('36893488147419103232');
$d = $this->getInstance('316912650057057350374175801344');
// a < b
$this->assertLessThan(0, $a->compare($b));
$this->assertGreaterThan(0, $b->compare($a));
// b = c
$this->assertSame(0, $b->compare($c));
$this->assertSame(0, $c->compare($b));
// c < d
$this->assertLessThan(0, $c->compare($d));
$this->assertGreaterThan(0, $d->compare($c));
}
public function testBitwiseAND()
{
$x = $this->getInstance('66666666666666666666666', 16);
$y = $this->getInstance('33333333333333333333333', 16);
$z = $this->getInstance('22222222222222222222222', 16);
$this->assertSame($z->toHex(), $x->bitwise_AND($y)->toHex());
}
public function testBitwiseOR()
{
$x = $this->getInstance('11111111111111111111111', 16);
$y = $this->getInstance('EEEEEEEEEEEEEEEEEEEEEEE', 16);
$z = $this->getInstance('FFFFFFFFFFFFFFFFFFFFFFF', 16);
$this->assertSame($z->toHex(), $x->bitwise_OR($y)->toHex());
}
public function testBitwiseXOR()
{
$x = $this->getInstance('AFAFAFAFAFAFAFAFAFAFAFAF', 16);
$y = $this->getInstance('133713371337133713371337', 16);
$z = $this->getInstance('BC98BC98BC98BC98BC98BC98', 16);
$this->assertSame($z->toHex(), $x->bitwise_XOR($y)->toHex());
}
public function testBitwiseNOT()
{
$x = $this->getInstance('EEEEEEEEEEEEEEEEEEEEEEE', 16);
$z = $this->getInstance('11111111111111111111111', 16);
$this->assertSame($z->toHex(), $x->bitwise_NOT()->toHex());
$a = $this->getInstance(0);
$a->bitwise_not();
$this->assertSame($a->toString(), '0');
}
public function testBitwiseLeftShift()
{
$x = $this->getInstance('0x0000000FF0000000', 16);
$y = $this->getInstance('0x000FF00000000000', 16);
$this->assertSame($y->toHex(), $x->bitwise_LeftShift(16)->toHex());
}
public function testBitwiseRightShift()
{
$x = $this->getInstance('0x0000000FF0000000', 16);
$y = $this->getInstance('0x00000000000FF000', 16);
$z = $this->getInstance('0x000000000000000F', 16);
$n = $this->getInstance(0);
$this->assertSame($y->toHex(), $x->bitwise_RightShift(16)->toHex());
$this->assertSame($z->toHex(), $x->bitwise_RightShift(32)->toHex());
$this->assertSame($n->toHex(), $x->bitwise_RightShift(36)->toHex());
}
public function testSerializable()
{
$x = $this->getInstance('18446744073709551616');
$y = unserialize(serialize($x));
$this->assertTrue($x->equals($y));
$this->assertTrue($y->equals($x));
$this->assertSame('18446744073709551616', (string) $x);
$this->assertSame('18446744073709551616', (string) $y);
}
public function testClone()
{
$x = $this->getInstance('18446744073709551616');
$y = clone $x;
$this->assertTrue($x->equals($y));
$this->assertTrue($y->equals($x));
$this->assertSame('18446744073709551616', (string) $x);
$this->assertSame('18446744073709551616', (string) $y);
}
public function testRandomTwoArgument()
{
$min = $this->getInstance(0);
$max = $this->getInstance('18446744073709551616');
$rand1 = \phpseclib\Math\BigInteger::random($min, $max);
// technically $rand1 can equal $min but with the $min and $max we've
// chosen it's just not that likely
$this->assertTrue($rand1->compare($min) > 0);
$this->assertTrue($rand1->compare($max) < 0);
}
/**
* @group github279
*/
public function testDiffieHellmanKeyAgreement()
{
if (getenv('TRAVIS') && PHP_VERSION === '5.3.3'
&& MATH_BIGINTEGER_MODE === \phpseclib\Math\BigInteger::MODE_INTERNAL
) {
$this->markTestIncomplete(
'This test hangs on PHP 5.3.3 using internal mode.'
);
}
// "Oakley Group 14" 2048-bit modular exponentiation group as used in
// SSH2 diffie-hellman-group14-sha1
$prime = $this->getInstance(
'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1' .
'29024E088A67CC74020BBEA63B139B22514A08798E3404DD' .
'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245' .
'E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D' .
'C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F' .
'83655D23DCA3AD961C62F356208552BB9ED529077096966D' .
'670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9' .
'DE2BCBF6955817183995497CEA956AE515D2261898FA0510' .
'15728E5A8AACAA68FFFFFFFFFFFFFFFF',
16
);
$generator = $this->getInstance(2);
/*
Code for generation of $alicePrivate and $bobPrivate.
$one = $this->getInstance(1);
$max = $one->bitwise_leftShift(512)->subtract($one);
$alicePrivate = \phpseclib\Math\BigInteger::random($one, $max);
$bobPrivate = \phpseclib\Math\BigInteger::random($one, $max);
var_dump($alicePrivate->toHex(), $bobPrivate->toHex());
*/
$alicePrivate = $this->getInstance(
'22606EDA7960458BC9D65F46DD96F114F9A004F0493C1F26' .
'2139D2C8063B733162E876182CA3BF063AB1A167ABDB7F03' .
'E0A225A6205660439F6CE46D252069FF',
16
);
$bobPrivate = $this->getInstance(
'6E3EFA13A96025D63E4B0D88A09B3A46DDFE9DD3BC9D1655' .
'4898C02B4AC181F0CEB4E818664B12F02C71A07215C400F9' .
'88352A4779F3E88836F7C3D3B3C739DE',
16
);
$alicePublic = $generator->modPow($alicePrivate, $prime);
$bobPublic = $generator->modPow($bobPrivate, $prime);
$aliceShared = $bobPublic->modPow($alicePrivate, $prime);
$bobShared = $alicePublic->modPow($bobPrivate, $prime);
$this->assertTrue(
$aliceShared->equals($bobShared),
'Failed asserting that Alice and Bob share the same BigInteger.'
);
}
/**
* @requires PHP 5.6
*/
public function testDebugInfo()
{
$num = $this->getInstance(50);
$str = print_r($num, true);
$this->assertContains('[value] => 0x32', $str);
}
public function testPrecision()
{
$a = $this->getInstance(51);
$this->assertSame($a->getPrecision(), -1);
$b = $a;
$c = clone $a;
$b->setPrecision(1);
$this->assertSame($a->getPrecision(), 1);
$this->assertSame("$a", '1');
$this->assertSame($b->getPrecision(), 1);
$this->assertSame("$b", '1');
$this->assertSame($c->getPrecision(), -1);
$this->assertSame("$c", '51');
}
/**
* @group github954
*/
public function testSlidingWindow()
{
$e = $this->getInstance(str_repeat('1', 1794), 2);
$x = $this->getInstance(1);
$n = $this->getInstance(2);
$x->powMod($e, $n);
}
public function testRoot()
{
$bigInteger = new \phpseclib\Math\BigInteger('64000000'); // (20^2)^3
$three = new \phpseclib\Math\BigInteger('3');
$bigInteger = $bigInteger->root();
$this->assertSame('8000', (string) $bigInteger);
$bigInteger = $bigInteger->root($three);
$this->assertSame('20', (string) $bigInteger);
}
public function testPow()
{
$bigInteger = new \phpseclib\Math\BigInteger('20');
$two = new \phpseclib\Math\BigInteger('2');
$three = new \phpseclib\Math\BigInteger('3');
$bigInteger = $bigInteger->pow($two);
$this->assertSame('400', (string) $bigInteger);
$bigInteger = $bigInteger->pow($three);
$this->assertSame('64000000', (string) $bigInteger); // (20^2)^3
}
public function testMax()
{
$min = new \phpseclib\Math\BigInteger('20');
$max = new \phpseclib\Math\BigInteger('20000');
$this->assertSame((string) $max, (string) $min->max($max));
$this->assertSame((string) $max, (string) $max->max($min));
}
public function testMin()
{
$min = new \phpseclib\Math\BigInteger('20');
$max = new \phpseclib\Math\BigInteger('20000');
$this->assertSame((string) $min, (string) $min->min($max));
$this->assertSame((string) $min, (string) $max->min($min));
}
public function testLoopForeach()
{
$maxBigInteger = new \phpseclib\Math\BigInteger('34');
$one = new \phpseclib\Math\BigInteger('1');
$vars = [];
$maxBigInteger->loopforeach(
function ($i, &$vars) {
if ($i == 0) {
$vars['first'] = $i;
} else {
$vars['last'] = $i;
}
},
$vars
);
$this->assertSame(0, $vars['first']);
$this->assertSame(33, $vars['last']);
/* Nope, too slow
$maxBigInteger = new \phpseclib\Math\BigInteger(PHP_INT_MAX);
$maxBigInteger = $maxBigInteger->add($one);
$maxBigInteger->loopforeach(
function ($i, &$vars) {
if ($i == 0) {
$vars["first"] = $i;
} else {
$vars["last"] = $i;
}
},
$vars
);
$this->assertSame("0", $vars["first"]);
$this->assertSame((string)$maxBigInteger->subtract($one), $vars["last"]);*/
$maxBigInteger = new \phpseclib\Math\BigInteger(-34);
$maxBigInteger->loopforeach(
function ($i, &$vars) {
if ($i == 0) {
$vars['first'] = $i;
} else {
$vars['last'] = $i;
}
},
$vars
);
$this->assertSame(0, $vars['first']);
$this->assertSame(-33, $vars['last']);
/* Nope, too slow
$maxBigInteger = new \phpseclib\Math\BigInteger(-PHP_INT_MAX - 1);
$maxBigInteger = $maxBigInteger->subtract($one);
$maxBigInteger->loopforeach(
function ($i, &$vars) {
if ($i == 0) {
$vars["first"] = $i;
} else {
$vars["last"] = $i;
}
},
$vars
);
$this->assertSame("0", $vars["first"]);
$this->assertSame((string)$maxBigInteger->add($one), $vars["last"]);*/
}
}

View File

@ -0,0 +1,26 @@
<?php
/**
* @author Andreas Fischer <bantu@phpbb.com>
* @copyright 2014 Andreas Fischer
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use phpseclib\Net\SFTP\Stream;
class Unit_Net_SFTPStreamTest extends PhpseclibTestCase
{
public function testRegisterWithoutArgument()
{
$this->assertTrue(Stream::register());
$this->assertContains('sftp', stream_get_wrappers());
$this->assertTrue(stream_wrapper_unregister('sftp'));
}
public function testRegisterWithArgument()
{
$protocol = 'sftptest';
$this->assertTrue(Stream::register($protocol));
$this->assertContains($protocol, stream_get_wrappers());
$this->assertTrue(stream_wrapper_unregister($protocol));
}
}

View File

@ -0,0 +1,41 @@
<?php
/**
* @author Marc Scholten <marc@pedigital.de>
* @copyright 2013 Marc Scholten
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Net_SSH1Test extends PhpseclibTestCase
{
public function formatLogDataProvider()
{
return array(
array(
array('hello world'),
array('<--'),
"<--\r\n00000000 68:65:6c:6c:6f:20:77:6f:72:6c:64 hello world\r\n\r\n"
),
array(
array('hello', 'world'),
array('<--', '<--'),
"<--\r\n00000000 68:65:6c:6c:6f hello\r\n\r\n" .
"<--\r\n00000000 77:6f:72:6c:64 world\r\n\r\n"
),
);
}
/**
* @dataProvider formatLogDataProvider
*/
public function testFormatLog(array $message_log, array $message_number_log, $expected)
{
$ssh = $this->getMockBuilder('phpseclib\Net\SSH1')
->disableOriginalConstructor()
->setMethods(null)
->getMock();
$result = $ssh->_format_log($message_log, $message_number_log);
$this->assertEquals($expected, $result);
}
}

View File

@ -0,0 +1,135 @@
<?php
/**
* @author Marc Scholten <marc@pedigital.de>
* @copyright 2013 Marc Scholten
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
class Unit_Net_SSH2Test extends PhpseclibTestCase
{
public function formatLogDataProvider()
{
return array(
array(
array('hello world'),
array('<--'),
"<--\r\n00000000 68:65:6c:6c:6f:20:77:6f:72:6c:64 hello world\r\n\r\n"
),
array(
array('hello', 'world'),
array('<--', '<--'),
"<--\r\n00000000 68:65:6c:6c:6f hello\r\n\r\n" .
"<--\r\n00000000 77:6f:72:6c:64 world\r\n\r\n"
),
);
}
/**
* @dataProvider formatLogDataProvider
*/
public function testFormatLog(array $message_log, array $message_number_log, $expected)
{
$ssh = $this->createSSHMock();
$result = $ssh->_format_log($message_log, $message_number_log);
$this->assertEquals($expected, $result);
}
public function testGenerateIdentifier()
{
$identifier = $this->createSSHMock()->_generate_identifier();
$this->assertStringStartsWith('SSH-2.0-phpseclib_2.0', $identifier);
if (extension_loaded('libsodium')) {
$this->assertContains('libsodium', $identifier);
}
if (extension_loaded('openssl')) {
$this->assertContains('openssl', $identifier);
$this->assertNotContains('mcrypt', $identifier);
} elseif (extension_loaded('mcrypt')) {
$this->assertNotContains('openssl', $identifier);
$this->assertContains('mcrypt', $identifier);
} else {
$this->assertNotContains('openssl', $identifier);
$this->assertNotContains('mcrypt', $identifier);
}
if (extension_loaded('gmp')) {
$this->assertContains('gmp', $identifier);
$this->assertNotContains('bcmath', $identifier);
} elseif (extension_loaded('bcmath')) {
$this->assertNotContains('gmp', $identifier);
$this->assertContains('bcmath', $identifier);
} else {
$this->assertNotContains('gmp', $identifier);
$this->assertNotContains('bcmath', $identifier);
}
}
public function testGetExitStatusIfNotConnected()
{
$ssh = $this->createSSHMock();
$this->assertFalse($ssh->getExitStatus());
}
public function testPTYIDefaultValue()
{
$ssh = $this->createSSHMock();
$this->assertFalse($ssh->isPTYEnabled());
}
public function testEnablePTY()
{
$ssh = $this->createSSHMock();
$ssh->enablePTY();
$this->assertTrue($ssh->isPTYEnabled());
$ssh->disablePTY();
$this->assertFalse($ssh->isPTYEnabled());
}
public function testQuietModeDefaultValue()
{
$ssh = $this->createSSHMock();
$this->assertFalse($ssh->isQuietModeEnabled());
}
public function testEnableQuietMode()
{
$ssh = $this->createSSHMock();
$ssh->enableQuietMode();
$this->assertTrue($ssh->isQuietModeEnabled());
$ssh->disableQuietMode();
$this->assertFalse($ssh->isQuietModeEnabled());
}
public function testGetConnectionByResourceId()
{
$ssh = new \phpseclib\Net\SSH2('localhost');
$this->assertSame($ssh, \phpseclib\Net\SSH2::getConnectionByResourceId($ssh->getResourceId()));
}
public function testGetResourceId()
{
$ssh = new \phpseclib\Net\SSH2('localhost');
$this->assertSame('{' . spl_object_hash($ssh) . '}', $ssh->getResourceId());
}
/**
* @return \phpseclib\Net\SSH2
*/
protected function createSSHMock()
{
return $this->getMockBuilder('phpseclib\Net\SSH2')
->disableOriginalConstructor()
->setMethods(array('__destruct'))
->getMock();
}
}

View File

@ -0,0 +1,19 @@
<?php
/**
* Bootstrapping File for phpseclib Test Suite
*
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
date_default_timezone_set('UTC');
$loader_path = __DIR__ . '/../vendor/autoload.php';
if (!file_exists($loader_path)) {
echo "Dependencies must be installed using composer:\n\n";
echo "php composer.phar install\n\n";
echo "See http://getcomposer.org for help with installing composer\n";
exit(1);
}
$loader = include $loader_path;
$loader->add('', __DIR__);

View File

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,2F15FCF0B21FCFB5A37D709322F9B9EB
JpGgJqRnr0+3mHQoeYXXUzSWeA1wGwMzm6KOPnQLEmA9ztPlBQulzZRh6QJckCwy
TC7BMo+XRnYVXF3e0rjji0k7cfEk5Gs8saNcxxOa0u0SUOCXelGnZeqzwiT0a6Fe
qAc7NLgTEo9zul9s+MHsplkVk71Oke+1dL7kksMRT0TdXIaqSvk/+nyAeLzAot04
wo61T3+Y7/v/8oVxlCbxI5YfYZkm/4jTy7AfbXZBvC0R+F0ZYvIDRCuBe6h6XvcH
AiYtw5+Qek6FwIa2CFVxsefvsEnZQYaiJpEFAq2xVHlTjQHHYrfd5cgu1koUNsAt
nX1zpsK7tIregXFa07KfDaBBPxfEBqVJQInzj0Rc8HUt0AZ+MrPldrZ28+YQ4RXk
/qk5UyKkdHMSKBb4va3mxcpDq1As9HREfeUeOjjduRh1LnNQCJaOhydXBqCFvhFy
+Q9utDXP6q4OUxeDHCPGQ7K1I7erwiwuTeSXB3BEDZyZywHXABvJpsidkDlD/aNo
QmM19V8y0IAxEAZvc8N0MIOO8hmd8R9U1RK4S24o9M8mgRrmuXjViJjZd5E3h6tX
Mgxm8dpOiT77i+NsJwyp2A+MhkAHg2ruwlCIrSCC81zvdphVTfuc/vx3JpXYvhTP
Xf9R8ppGnDUFauroN7E7odJKDhLVuAbmU1lWwue2iaNEKZ3L/o9dpRz4Td4NzzSf
HKvKbJR35FCsqZq2krmNVd6ynF5PzWfYmz850yn/qdU8zwnW0fV+iHKS2oXuH9X1
ZW02/MDdCylpRftNJMntR4Yxim7WEZ5Dif9ZLj8IGRQdWbbIn0WjtiVrFrcUbIfk
TCP/3GeEcUa/XbE9hO9APw+7rO3sOehGJ84n4tXxFTFSnOJ5ZxTKpLvxRrmC8DaD
cvqy8bbjPfn1EjZmRpCjanLZ1UJbLitFfpUT55aTrcozS4FMHmFm74X2xZGeBhxC
CpWQe/agxhWxG+ZXdxt9ExI78ftQCQoGE0Si1KZXH5KQ/xiGmebY9wbtEHWG+q25
sKqvjQHQsE3NZq7kne3mnyvjzMDDFYPLDlQLgcKInNrLZ3GszyemtzqcVf3YVur4
N+nN0gu6LCx0vtw3yNRqjjmGN1V6sKMCqmIAtFDh9zRTlDTs7ZUBGPgakmmJLLVM
ESme0JrRxCP+eEU8JNti9pKlKPGOFVpu4shLjmnmKuDpOytFNpcB/NylkGwZCxvE
1KI+EQMZOE5VROAfkvwBLE0SsVxMq7H87zSEOtOqr+QN8RoY1V6N/woBVWda9GFk
HI44PM2ZywQbLGthaQV/Kxwf9YZruJdunNoTfEufZgv2Vp+3VAs+gCTGIsbblTnH
J8QGfs/lHRBqK1pMZrYy0ubFqifA+b9Xa6VJWToCgcQuWbOVWn1zKQTTXZPksVbB
qyE8BJkQCDGgoeq4kdxm0XUR5p3UZWQv0HoykQt33U06TCzU9HOcp0z+Glhrzsvd
rbNBhRK0zXF/BFSNBHwKEg02TNlj7gSFJXmvZqvyCAFo5D6nSDbzqm6ARuscsrF0
6Zd3toOZTWmrVsKvTlsNPfHXyoGqP3+0NXcTY+kKXG58u4TbEtw8pVyPikuVdh/m
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,25 @@
#!/bin/bash
#
# This file is part of the phpseclib project.
#
# (c) Andreas Fischer <bantu@phpbb.com>
#
# For the full copyright and license information, please view the LICENSE
# file that was distributed with this source code.
#
set -e
function install_php_extension
{
cd "$1"
phpize
./configure
make
make install
cd ..
echo "extension=$1.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`
}
# runkit
git clone https://github.com/zenovich/runkit.git
install_php_extension 'runkit'

View File

@ -0,0 +1,34 @@
#!/bin/sh
set -e
set -x
export PHPSECLIB_SSH_HOSTNAME='localhost'
export PHPSECLIB_SSH_USERNAME='phpseclib'
export PHPSECLIB_SSH_PASSWORD='EePoov8po1aethu2kied1ne0'
export PHPSECLIB_SSH_HOME='/home/phpseclib'
if [ "$TRAVIS_PHP_VERSION" = '5.2' ]
then
PHPUNIT="phpunit"
else
PHPUNIT="$(dirname "$0")/../vendor/bin/phpunit"
fi
PHPUNIT_ARGS='--verbose'
if [ `php -r "echo (int) version_compare(PHP_VERSION, '5.4', '<');"` = "1" ]
then
PHPUNIT_ARGS="$PHPUNIT_ARGS -d zend.enable_gc=0"
fi
if [ "$TRAVIS_PHP_VERSION" = 'hhvm' -o "$TRAVIS_PHP_VERSION" = '7.0' ]
then
find tests -type f -name "*Test.php" | \
parallel --gnu --keep-order \
"echo '== {} =='; \"$PHPUNIT\" $PHPUNIT_ARGS {};"
else
"$PHPUNIT" \
$PHPUNIT_ARGS \
--coverage-text \
--coverage-clover code_coverage/clover.xml \
--coverage-html code_coverage/
fi

View File

@ -0,0 +1,3 @@
#!/bin/sh
composer self-update --no-interaction
composer install --no-interaction

View File

@ -0,0 +1,33 @@
#!/bin/sh
#
# This file is part of the phpseclib project.
#
# (c) Andreas Fischer <bantu@phpbb.com>
#
# For the full copyright and license information, please view the LICENSE
# file that was distributed with this source code.
#
set -e
set -x
USERNAME='phpseclib'
PASSWORD='EePoov8po1aethu2kied1ne0'
# Create phpseclib user and home directory
sudo useradd --create-home --base-dir /home "$USERNAME"
# Set phpseclib user password
echo "$USERNAME:$PASSWORD" | sudo chpasswd
# Create a 1024 bit RSA SSH key pair without passphrase for the travis user
ssh-keygen -t rsa -b 1024 -f "$HOME/.ssh/id_rsa" -q -N ""
# Add the generated private key to SSH agent of travis user
ssh-add "$HOME/.ssh/id_rsa"
# Allow the private key of the travis user to log in as phpseclib user
sudo mkdir -p "/home/$USERNAME/.ssh/"
sudo cp "$HOME/.ssh/id_rsa.pub" "/home/$USERNAME/.ssh/authorized_keys"
sudo ssh-keyscan -t rsa localhost > "/tmp/known_hosts"
sudo cp "/tmp/known_hosts" "/home/$USERNAME/.ssh/known_hosts"
sudo chown "$USERNAME:$USERNAME" "/home/$USERNAME/.ssh/" -R

View File

@ -0,0 +1,50 @@
#!/bin/sh
#
# This file is part of the phpseclib project.
#
# (c) Andreas Fischer <bantu@phpbb.com>
#
# For the full copyright and license information, please view the LICENSE
# file that was distributed with this source code.
#
USERNAME='phpseclib'
HOSTNAME='phpseclib.bantux.org'
HOSTRSAF='09:40:96:14:6a:cd:67:46:17:e5:b4:39:24:24:6e:9d'
LDIRNAME='code_coverage'
RDIRNAME='code_coverage'
ID_RSA='travis/code_coverage_id_rsa'
# Install expect if necessary
if ! which expect > /dev/null
then
sudo apt-get update -qq
sudo apt-get install -qq expect
fi
# Workaround for rsync not creating target directories with depth > 1
mv "$LDIRNAME" "x$LDIRNAME"
RROOT="$RDIRNAME/$TRAVIS_BRANCH/$TRAVIS_BUILD_NUMBER"
mkdir -p "$RROOT"
mv "x$LDIRNAME" "$RROOT/PHP-$TRAVIS_PHP_VERSION/"
# Update latest symlink
ln -s "$TRAVIS_BUILD_NUMBER" "$RDIRNAME/$TRAVIS_BRANCH/latest"
# Stop complaints about world-readable key file.
chmod 600 "$ID_RSA"
export RSYNC_RSH="ssh -4 -i $ID_RSA -o ConnectTimeout=5"
RSYNC_OPT="--recursive --times --links --progress"
expect << EOF
spawn rsync $RSYNC_OPT "$RDIRNAME/" "$USERNAME@$HOSTNAME:$RDIRNAME/"
expect "RSA key fingerprint is $HOSTRSAF."
send "yes\n"
expect "Enter passphrase for key '$ID_RSA':"
send "$CODE_COVERAGE_PASSPHRASE\n"
expect eof
EOF