├── .gitignore ├── .travis.yml ├── test ├── Unit │ ├── Key │ │ ├── FactoryTest.php │ │ └── Derivation │ │ │ └── PBKDF │ │ │ └── PBKDF2Test.php │ ├── Core │ │ ├── BigMath │ │ │ ├── PHPMathTest.php │ │ │ ├── GMPTest.php │ │ │ └── BCMathTest.php │ │ ├── StrengthTest.php │ │ ├── BigMathTest.php │ │ ├── EnumTest.php │ │ ├── AbstractFactoryTest.php │ │ └── BaseConverterTest.php │ ├── Random │ │ ├── Source │ │ │ ├── CAPICOMTest.php │ │ │ ├── UniqIDTest.php │ │ │ ├── MicroTimeTest.php │ │ │ ├── RandTest.php │ │ │ ├── MTRandTest.php │ │ │ └── URandomTest.php │ │ ├── Mixer │ │ │ └── HashTest.php │ │ └── FactoryTest.php │ ├── Password │ │ ├── Implementation │ │ │ ├── Password_TestCase.php │ │ │ ├── APR1Test.php │ │ │ └── HashTest.php │ │ └── FactoryTest.php │ ├── PasswordLibTest.php │ └── Hash │ │ └── HashTest.php ├── lib │ └── VectorParser │ │ ├── SSV.php │ │ ├── RFC3610.php │ │ ├── CAVS.php │ │ └── NESSIE.php ├── Mocks │ ├── Core │ │ ├── Strength.php │ │ ├── Enum.php │ │ └── Factory.php │ ├── AbstractMock.php │ ├── Random │ │ ├── Generator.php │ │ ├── Source.php │ │ └── Mixer.php │ ├── Key │ │ └── Derivation │ │ │ └── PBKDF.php │ └── Cipher │ │ ├── Block │ │ └── Cipher.php │ │ └── Factory.php ├── Data │ └── Vectors │ │ ├── pbkdf2-draft-josefsson-sha1.test-vectors │ │ ├── apr1.test-vectors │ │ ├── pbkdf2-draft-josefsson-sha256.test-vectors │ │ ├── aes-ecb.test-vectors │ │ ├── aes-ctr.test-vectors │ │ ├── aes-cbc.test-vectors │ │ ├── aes-cfb.test-vectors │ │ ├── aes-ofb.test-vectors │ │ ├── cmac-aes.sp-800-38b.test-vectors │ │ └── hmac.rfc4231.test-vectors ├── Vectors │ ├── Password │ │ └── Implementation │ │ │ ├── PBKDFTest.php │ │ │ ├── PHPBBTest.php │ │ │ ├── DrupalTest.php │ │ │ ├── PHPASSTest.php │ │ │ ├── BlowfishTest.php │ │ │ └── APR1Test.php │ └── Key │ │ └── Derivation │ │ └── PBKDF │ │ └── PBKDF2Test.php └── bootstrap.php ├── composer.json ├── lib └── PasswordLib │ ├── bootstrap.php │ ├── Password │ ├── Implementation │ │ ├── PHPBB.php │ │ ├── MD5.php │ │ ├── Drupal.php │ │ ├── MediaWiki.php │ │ ├── SHA256.php │ │ ├── SHA512.php │ │ ├── Blowfish.php │ │ ├── Joomla.php │ │ ├── Hash.php │ │ └── Crypt.php │ ├── Password.php │ └── Factory.php │ ├── Core │ ├── BigMath │ │ ├── BCMath.php │ │ ├── GMP.php │ │ └── PHPMath.php │ ├── Strength.php │ ├── BigMath.php │ ├── AutoLoader.php │ ├── AbstractFactory.php │ ├── Enum.php │ └── BaseConverter.php │ ├── Random │ ├── Source.php │ ├── Mixer.php │ ├── Source │ │ ├── UniqID.php │ │ ├── CAPICOM.php │ │ ├── URandom.php │ │ ├── Rand.php │ │ ├── MTRand.php │ │ └── MicroTime.php │ ├── Mixer │ │ └── Hash.php │ └── AbstractMixer.php │ └── Key │ ├── Derivation │ ├── AbstractDerivation.php │ ├── PBKDF.php │ └── PBKDF │ │ └── PBKDF2.php │ └── Factory.php ├── phpunit.xml.dist ├── composer.lock └── examples ├── Password └── drupal.php ├── Random ├── numbers.php └── strings.php └── PasswordLib.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5 5 | - 5.4 6 | - 5.3 7 | 8 | before_script: 9 | - composer install --dev 10 | 11 | script: phpunit --configuration phpunit.xml.dist test -------------------------------------------------------------------------------- /test/Unit/Key/FactoryTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($factory->getPBKDF() instanceof \PasswordLib\Key\Derivation\PBKDF\PBKDF2); 14 | } 15 | 16 | /** 17 | * @expectedException InvalidArgumentException 18 | */ 19 | public function testGetPBKDFFail() { 20 | $factory = new Factory; 21 | $factory->getPBKDF('someGibberish'); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /test/lib/VectorParser/SSV.php: -------------------------------------------------------------------------------- 1 | file = $file; 13 | $this->parse(); 14 | } 15 | 16 | public function getVectors() { 17 | return $this->vectors; 18 | } 19 | 20 | protected function parse() { 21 | $data = file($this->file); 22 | foreach ($data as $line) { 23 | $line = trim($line); 24 | if (empty($line) || $line[0] == '#') { 25 | continue; 26 | } 27 | $this->vectors[] = explode(' ', $line); 28 | } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /test/Unit/Core/BigMath/PHPMathTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($expected, $obj->add($left, $right)); 15 | } 16 | 17 | /** 18 | * @dataProvider provideSubtractTest 19 | */ 20 | public function testSubtract($left, $right, $expected) { 21 | $obj = new \PasswordLib\Core\BigMath\PHPMath; 22 | $this->assertEquals($expected, $obj->subtract($left, $right)); 23 | } 24 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PasswordLib/PasswordLib", 3 | "type": "library", 4 | "version": "1.0.0-beta1", 5 | "description": "A Password Hashing Library", 6 | "keywords": ["password", "hash", "hashing", "random", "salt", "crypt"], 7 | "homepage": "https://github.com/ircmaxell/PHP-PasswordLib", 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Anthony Ferrara", 12 | "email": "ircmaxell@ircmaxell.com", 13 | "homepage": "http://blog.ircmaxell.com" 14 | } 15 | ], 16 | "require-dev": { 17 | "mikey179/vfsStream": "1.1.*" 18 | }, 19 | "require": { 20 | "php": ">=5.3.2" 21 | }, 22 | "autoload": { 23 | "psr-0": { 24 | "PasswordLib": "lib" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/PasswordLib/bootstrap.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2011 The Authors 15 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 16 | * @version Build @@version@@ 17 | */ 18 | 19 | namespace PasswordLib; 20 | 21 | require_once __DIR__ . '/Core/AutoLoader.php'; 22 | 23 | $autoloader = new Core\AutoLoader(__NAMESPACE__, dirname(__DIR__)); 24 | 25 | $autoloader->register(); -------------------------------------------------------------------------------- /test/Mocks/Core/Strength.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 12 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 13 | */ 14 | 15 | namespace PasswordLibTest\Mocks\Core; 16 | 17 | /** 18 | * The interface that all hash implementations must implement 19 | * 20 | * @category PHPPasswordLib 21 | * @package Hash 22 | * @author Anthony Ferrara 23 | */ 24 | class Strength extends \PasswordLib\Core\Strength { 25 | 26 | const MEDIUMLOW = 4; 27 | const SUPERHIGH = 999; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /test/Mocks/Core/Enum.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 12 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 13 | */ 14 | 15 | namespace PasswordLibTest\Mocks\Core; 16 | 17 | /** 18 | * The interface that all hash implementations must implement 19 | * 20 | * @category PHPPasswordLib 21 | * @package Hash 22 | * @author Anthony Ferrara 23 | */ 24 | class Enum extends \PasswordLib\Core\Enum { 25 | 26 | const Value1 = 1; 27 | const Value2 = 2; 28 | const Value3 = 3; 29 | const Value4 = 4; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/Data/Vectors/pbkdf2-draft-josefsson-sha1.test-vectors: -------------------------------------------------------------------------------- 1 | Set 1 2 | P=password 3 | S=salt 4 | c=1 5 | dkLen=20 6 | DK=0c60c80f961f0e71f3a9b524af6012062fe037a6 7 | 8 | Set 2 9 | P=password 10 | S=salt 11 | c=2 12 | dkLen=20 13 | DK=ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957 14 | 15 | Set 3 16 | P=password 17 | S=salt 18 | c=4096 19 | dkLen=20 20 | DK=4b007901b765489abead49d926f721d065a429c1 21 | 22 | #Set 4 23 | # P=password 24 | # S=salt 25 | # c=16777216 26 | # dkLen=20 27 | # DK=eefe3d61cd4da4e4e9945b3d6ba2158c2634e984 28 | 29 | Set 5 30 | P=passwordPASSWORDpassword 31 | S=saltSALTsaltSALTsaltSALTsaltSALTsalt 32 | c=4096 33 | dkLen=25 34 | DK=3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038 35 | 36 | Set 6 37 | P=pass\0word 38 | S=sa\0lt 39 | c=4096 40 | dkLen=16 41 | DK=56fa6aa75548099dcc37d7f03425e0c3 42 | -------------------------------------------------------------------------------- /test/Unit/Core/BigMath/GMPTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped('BCMath is not loaded'); 12 | } 13 | } 14 | 15 | /** 16 | * @dataProvider provideAddTest 17 | */ 18 | public function testAdd($left, $right, $expected) { 19 | $obj = new \PasswordLib\Core\BigMath\GMP; 20 | $this->assertEquals($expected, $obj->add($left, $right)); 21 | } 22 | 23 | /** 24 | * @dataProvider provideSubtractTest 25 | */ 26 | public function testSubtract($left, $right, $expected) { 27 | $obj = new \PasswordLib\Core\BigMath\GMP; 28 | $this->assertEquals($expected, $obj->subtract($left, $right)); 29 | } 30 | } -------------------------------------------------------------------------------- /test/Unit/Core/BigMath/BCMathTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped('BCMath is not loaded'); 12 | } 13 | } 14 | 15 | /** 16 | * @dataProvider provideAddTest 17 | */ 18 | public function testAdd($left, $right, $expected) { 19 | $obj = new \PasswordLib\Core\BigMath\BCMath; 20 | $this->assertEquals($expected, $obj->add($left, $right)); 21 | } 22 | 23 | /** 24 | * @dataProvider provideSubtractTest 25 | */ 26 | public function testSubtract($left, $right, $expected) { 27 | $obj = new \PasswordLib\Core\BigMath\BCMath; 28 | $this->assertEquals($expected, $obj->subtract($left, $right)); 29 | } 30 | } -------------------------------------------------------------------------------- /test/Data/Vectors/apr1.test-vectors: -------------------------------------------------------------------------------- 1 | Set 1 2 | P=foobar 3 | H=$apr1$ia4ip/..$2rAEb1KjqPFGEaecm/bbI1 4 | Value=1 5 | 6 | Set 2 7 | P=foobaz 8 | H=$apr1$TAAUp/..$fkSYsSkuBVOsA94kzgJGM0 9 | Value=1 10 | 11 | Set 3 12 | P=foobarbazbizbuz1234567890 13 | H=$apr1$meZXp/..$uIOcNTZpQPwvGr58y4cSC. 14 | Value=1 15 | 16 | Set 4 17 | P=foobarbizbuz 18 | H=$apr1$WIbYp/..$AI5Y4q6CRmb7xkK/sqbRF1 19 | Value=1 20 | 21 | Set 5 22 | P=1234 23 | H=$apr1$qXMZp/..$YCj9UNiOzrr0BZ0jKtqid0 24 | Value=1 25 | 26 | Set 6 27 | P=foo 28 | H=bar 29 | Value=0 30 | 31 | #Salt Change 32 | Set 7 33 | P=foobar 34 | H=$apr1$rgdSp/..$hCnEAB7vjRz33x1zmAYYa0. 35 | Value=0 36 | 37 | #Incorrect Password 38 | Set 8 39 | P=foobuz 40 | H=$apr1$rhdSp/..$hCnEAB7vjRz33x1zmAYYa0. 41 | Value=0 42 | 43 | #Hash Value Change 44 | Set 9 45 | P=foobarbazbizbuz1234567890 46 | H=$apr1$meZXp/..$uIOcNTCpQPwvGr58y4cSC. 47 | Value=0 48 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | test/Unit 22 | 23 | 24 | 25 | 26 | lib/ 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/Vectors/Password/Implementation/PBKDFTest.php: -------------------------------------------------------------------------------- 1 | getVectors() as $vector) { 12 | $results[] = array( 13 | $vector[0], 14 | $vector[1], 15 | true 16 | ); 17 | } 18 | return $results; 19 | } 20 | 21 | /** 22 | * @covers PasswordLib\Password\Implementation\PBKDF::verify 23 | * @dataProvider provideTestVerify 24 | * @group Vectors 25 | */ 26 | public function testVerify($pass, $expect, $value) { 27 | $apr = new PBKDF(); 28 | $this->assertEquals($value, $apr->verify($pass, $expect)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/Vectors/Password/Implementation/PHPBBTest.php: -------------------------------------------------------------------------------- 1 | getVectors() as $vector) { 12 | $results[] = array( 13 | $vector[0], 14 | $vector[1], 15 | true 16 | ); 17 | } 18 | return $results; 19 | } 20 | 21 | /** 22 | * @covers PasswordLib\Password\Implementation\PHPBB::verify 23 | * @dataProvider provideTestVerify 24 | * @group Vectors 25 | */ 26 | public function testVerify($pass, $expect, $value) { 27 | $apr = new PHPBB(); 28 | $this->assertEquals($value, $apr->verify($pass, $expect)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/Vectors/Password/Implementation/DrupalTest.php: -------------------------------------------------------------------------------- 1 | getVectors() as $vector) { 12 | $results[] = array( 13 | $vector[0], 14 | $vector[1], 15 | true 16 | ); 17 | } 18 | return $results; 19 | } 20 | 21 | /** 22 | * @covers PasswordLib\Password\Implementation\Drupal::verify 23 | * @dataProvider provideTestVerify 24 | * @group Vectors 25 | */ 26 | public function testVerify($pass, $expect, $value) { 27 | $apr = new Drupal(); 28 | $this->assertEquals($value, $apr->verify($pass, $expect)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/Vectors/Password/Implementation/PHPASSTest.php: -------------------------------------------------------------------------------- 1 | getVectors() as $vector) { 12 | $results[] = array( 13 | $vector[0], 14 | $vector[1], 15 | true 16 | ); 17 | } 18 | return $results; 19 | } 20 | 21 | /** 22 | * @covers PasswordLib\Password\Implementation\PHPASS::verify 23 | * @dataProvider provideTestVerify 24 | * @group Vectors 25 | */ 26 | public function testVerify($pass, $expect, $value) { 27 | $apr = new PHPASS(); 28 | $this->assertEquals($value, $apr->verify($pass, $expect)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/Vectors/Password/Implementation/BlowfishTest.php: -------------------------------------------------------------------------------- 1 | getVectors() as $vector) { 12 | $results[] = array( 13 | $vector[0], 14 | $vector[1], 15 | true 16 | ); 17 | } 18 | return $results; 19 | } 20 | 21 | /** 22 | * @covers PasswordLib\Password\Implementation\Blowfish::verify 23 | * @dataProvider provideTestVerify 24 | * @group Vectors 25 | */ 26 | public function testVerify($pass, $expect, $value) { 27 | $apr = new Blowfish(); 28 | $this->assertEquals($value, $apr->verify($pass, $expect)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /test/Unit/Core/StrengthTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($obj instanceof \PasswordLib\Core\Strength); 10 | $this->assertTrue($obj instanceof \PasswordLib\Core\Enum); 11 | } 12 | 13 | public function testGetConstList() { 14 | $obj = new Strength(); 15 | $const = $obj->getConstList(); 16 | $this->assertEquals(array( 17 | 'VERYLOW' => 1, 18 | 'LOW' => 3, 19 | 'MEDIUM' => 5, 20 | 'HIGH' => 7, 21 | ), $const); 22 | } 23 | 24 | public function testGetConstListWithDefault() { 25 | $obj = new Strength(); 26 | $const = $obj->getConstList(true); 27 | $this->assertEquals(array( 28 | '__DEFAULT' => 1, 29 | 'VERYLOW' => 1, 30 | 'LOW' => 3, 31 | 'MEDIUM' => 5, 32 | 'HIGH' => 7, 33 | ), $const); 34 | } 35 | } -------------------------------------------------------------------------------- /test/Data/Vectors/pbkdf2-draft-josefsson-sha256.test-vectors: -------------------------------------------------------------------------------- 1 | #PBKDF2 HMAC-SHA256 Test Vectors 2 | 3 | Set 1 4 | P=password 5 | S=salt 6 | c=1 7 | dkLen=32 8 | DK=120fb6cffcf8b32c43e7225256c4f837 9 | a86548c92ccc35480805987cb70be17b 10 | 11 | Set 2 12 | P=password 13 | S=salt 14 | c=2 15 | dkLen=32 16 | DK=ae4d0c95af6b46d32d0adff928f06dd0 17 | 2a303f8ef3c251dfd6e2d85a95474c43 18 | 19 | Set 3 20 | P=password 21 | S=salt 22 | c=4096 23 | dkLen=32 24 | DK=c5e478d59288c841aa530db6845c4c8d 25 | 962893a001ce4e11a4963873aa98134a 26 | 27 | #Set 4 28 | # P=password 29 | # S=salt 30 | # c=16777216 31 | # dkLen=32 32 | # DK=cf81c66fe8cfc04d1f31ecb65dab4089 33 | # f7f179e89b3b0bcb17ad10e3ac6eba46 34 | 35 | Set 5 36 | P=passwordPASSWORDpassword 37 | S=saltSALTsaltSALTsaltSALTsaltSALTsalt 38 | c=4096 39 | dkLen=40 40 | DK=348c89dbcbd32b2f32d814b8116e84cf 41 | 2b17347ebc1800181c4e2a1fb8dd53e1 42 | c635518c7dac47e9 43 | 44 | Set 6 45 | P=pass\0word 46 | S=sa\0lt 47 | c=4096 48 | dkLen=16 49 | DK=89b69d0516f829893c696226650a8687 50 | -------------------------------------------------------------------------------- /test/Unit/Random/Source/CAPICOMTest.php: -------------------------------------------------------------------------------- 1 | 0 ? str_repeat(chr(0), $i) : chr(0); 14 | $data[] = array($i, $not); 15 | } 16 | return $data; 17 | } 18 | 19 | /** 20 | * @covers PasswordLib\Random\Source\CAPICOM::getStrength 21 | */ 22 | public function testGetStrength() { 23 | $strength = new Strength(Strength::MEDIUM); 24 | $actual = CAPICOM::getStrength(); 25 | $this->assertEquals($actual, $strength); 26 | } 27 | 28 | /** 29 | * @covers PasswordLib\Random\Source\CAPICOM::generate 30 | * @dataProvider provideGenerate 31 | * @group slow 32 | */ 33 | public function testGenerate($length, $not) { 34 | $rand = new CAPICOM; 35 | $stub = $rand->generate($length); 36 | $this->assertEquals($length, strlen($stub)); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /test/Unit/Random/Source/UniqIDTest.php: -------------------------------------------------------------------------------- 1 | 0 ? str_repeat(chr(0), $i) : chr(0); 14 | $data[] = array($i, $not); 15 | } 16 | return $data; 17 | } 18 | 19 | /** 20 | * @covers PasswordLib\Random\Source\UniqID::getStrength 21 | */ 22 | public function testGetStrength() { 23 | $strength = new Strength(Strength::LOW); 24 | $actual = UniqID::getStrength(); 25 | $this->assertEquals($actual, $strength); 26 | } 27 | 28 | /** 29 | * @covers PasswordLib\Random\Source\UniqID::generate 30 | * @dataProvider provideGenerate 31 | */ 32 | public function testGenerate($length, $not) { 33 | $rand = new UniqID; 34 | $stub = $rand->generate($length); 35 | $this->assertEquals($length, strlen($stub)); 36 | $this->assertNotEquals($not, $stub); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /test/Mocks/AbstractMock.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 12 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 13 | */ 14 | 15 | namespace PasswordLibTest\Mocks; 16 | 17 | /** 18 | * The interface that all hash implementations must implement 19 | * 20 | * @category PHPPasswordLib 21 | * @package Hash 22 | * @author Anthony Ferrara 23 | */ 24 | class AbstractMock { 25 | 26 | protected $callbacks = array(); 27 | 28 | public static function init() {} 29 | 30 | public function __construct(array $callbacks = array()) { 31 | $this->callbacks = $callbacks; 32 | } 33 | 34 | public function __call($name, array $args = array()) { 35 | if (isset($this->callbacks[$name])) { 36 | return call_user_func_array($this->callbacks[$name], $args); 37 | } 38 | return null; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /test/Unit/Random/Source/MicroTimeTest.php: -------------------------------------------------------------------------------- 1 | 0 ? str_repeat(chr(0), $i) : chr(0); 14 | $data[] = array($i, $not); 15 | } 16 | return $data; 17 | } 18 | 19 | /** 20 | * @covers PasswordLib\Random\Source\MicroTime::getStrength 21 | */ 22 | public function testGetStrength() { 23 | $strength = new Strength(Strength::VERYLOW); 24 | $actual = MicroTime::getStrength(); 25 | $this->assertEquals($actual, $strength); 26 | } 27 | 28 | /** 29 | * @covers PasswordLib\Random\Source\MicroTime::generate 30 | * @dataProvider provideGenerate 31 | */ 32 | public function testGenerate($length, $not) { 33 | $rand = new MicroTime; 34 | $stub = $rand->generate($length); 35 | $this->assertEquals($length, strlen($stub)); 36 | $this->assertNotEquals($not, $stub); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/PHPBB.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2011 The Authors 15 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 16 | * @version Build @@version@@ 17 | */ 18 | 19 | namespace PasswordLib\Password\Implementation; 20 | 21 | use PasswordLib\Random\Factory as RandomFactory; 22 | 23 | /** 24 | * The PHPBB password hashing implementation 25 | * 26 | * Use this class to generate and validate PHPBB password hashes. 27 | * 28 | * @see http://www.openwall.com/phpass/ 29 | * @category PHPPasswordLib 30 | * @package Password 31 | * @subpackage Implementation 32 | * @author Anthony Ferrara 33 | */ 34 | class PHPBB extends PHPASS { 35 | 36 | /** 37 | * @var string The prefix for the generated hash 38 | */ 39 | protected static $prefix = '$H$'; 40 | 41 | } -------------------------------------------------------------------------------- /test/Unit/Random/Source/RandTest.php: -------------------------------------------------------------------------------- 1 | 0 ? str_repeat(chr(0), $i) : chr(0); 12 | $data[] = array($i, $not); 13 | } 14 | return $data; 15 | } 16 | 17 | /** 18 | * @covers PasswordLib\Random\Source\Rand::getStrength 19 | */ 20 | public function testGetStrength() { 21 | if (defined('S_ALL')) { 22 | $strength = new Strength(Strength::LOW); 23 | } else { 24 | $strength = new Strength(Strength::VERYLOW); 25 | } 26 | $actual = Rand::getStrength(); 27 | $this->assertEquals($actual, $strength); 28 | } 29 | 30 | /** 31 | * @covers PasswordLib\Random\Source\Rand::generate 32 | * @dataProvider provideGenerate 33 | */ 34 | public function testGenerate($length, $not) { 35 | $rand = new Rand; 36 | $stub = $rand->generate($length); 37 | $this->assertEquals($length, strlen($stub)); 38 | $this->assertNotEquals($not, $stub); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /test/Unit/Random/Source/MTRandTest.php: -------------------------------------------------------------------------------- 1 | 0 ? str_repeat(chr(0), $i) : chr(0); 14 | $data[] = array($i, $not); 15 | } 16 | return $data; 17 | } 18 | 19 | /** 20 | * @covers PasswordLib\Random\Source\MTRand::getStrength 21 | */ 22 | public function testGetStrength() { 23 | if (defined('S_ALL')) { 24 | $strength = new Strength(Strength::MEDIUM); 25 | } else { 26 | $strength = new Strength(Strength::LOW); 27 | } 28 | $actual = MTRand::getStrength(); 29 | $this->assertEquals($actual, $strength); 30 | } 31 | 32 | /** 33 | * @covers PasswordLib\Random\Source\MTRand::generate 34 | * @dataProvider provideGenerate 35 | */ 36 | public function testGenerate($length, $not) { 37 | $rand = new MTRand; 38 | $stub = $rand->generate($length); 39 | $this->assertEquals($length, strlen($stub)); 40 | $this->assertNotEquals($not, $stub); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "bc20a38645558f91ae19a28e2e9950d4", 3 | "packages": [ 4 | 5 | ], 6 | "packages-dev": [ 7 | { 8 | "name": "mikey179/vfsStream", 9 | "version": "v1.1.0", 10 | "source": { 11 | "type": "git", 12 | "url": "https://github.com/mikey179/vfsStream", 13 | "reference": "v1.1.0" 14 | }, 15 | "dist": { 16 | "type": "zip", 17 | "url": "https://github.com/mikey179/vfsStream/zipball/v1.1.0", 18 | "reference": "v1.1.0", 19 | "shasum": "" 20 | }, 21 | "require": { 22 | "php": ">=5.3.0" 23 | }, 24 | "time": "2012-08-25 05:49:29", 25 | "type": "library", 26 | "autoload": { 27 | "psr-0": { 28 | "org\\bovigo\\vfs": "src/main/php" 29 | } 30 | }, 31 | "notification-url": "https://packagist.org/downloads/", 32 | "license": [ 33 | "BSD" 34 | ], 35 | "homepage": "http://vfs.bovigo.org/" 36 | } 37 | ], 38 | "aliases": [ 39 | 40 | ], 41 | "minimum-stability": "stable", 42 | "stability-flags": [ 43 | 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /test/lib/VectorParser/RFC3610.php: -------------------------------------------------------------------------------- 1 | file = $file; 13 | $this->parse(); 14 | } 15 | 16 | public function getVectors() { 17 | return $this->vectors; 18 | } 19 | 20 | protected function parse() { 21 | $data = file($this->file); 22 | $bufferValid = false; 23 | $buffer = array(); 24 | foreach ($data as $line) { 25 | $line = trim($line); 26 | if (empty($line)) { 27 | $this->processBuffer($buffer); 28 | $buffer = array(); 29 | } elseif ($line[0] == '=' || strpos($line, ':') !== false) { 30 | continue; 31 | } else { 32 | list ($key, $value) = explode('=', $line, 2); 33 | $buffer[trim($key)] = trim($value); 34 | } 35 | } 36 | } 37 | 38 | protected function processBuffer(array $buffer) { 39 | $vector = $buffer; 40 | $adl = strlen($vector['Adata']); 41 | $vector['Cipher'] = substr($vector['Cipher'], $adl); 42 | $vector['Data'] = substr($vector['Data'], $adl); 43 | $this->vectors[] = $vector; 44 | } 45 | } -------------------------------------------------------------------------------- /test/Unit/Random/Source/URandomTest.php: -------------------------------------------------------------------------------- 1 | 0 ? str_repeat(chr(0), $i) : chr(0); 15 | $data[] = array($i, $not); 16 | } 17 | return $data; 18 | } 19 | 20 | /** 21 | * @covers PasswordLib\Random\Source\URandom::getStrength 22 | */ 23 | public function testGetStrength() { 24 | $strength = new Strength(Strength::MEDIUM); 25 | $actual = URandom::getStrength(); 26 | $this->assertEquals($actual, $strength); 27 | } 28 | 29 | /** 30 | * @covers PasswordLib\Random\Source\URandom::generate 31 | * @dataProvider provideGenerate 32 | * @group slow 33 | */ 34 | public function testGenerate($length, $not) { 35 | $rand = new URandom; 36 | $stub = $rand->generate($length); 37 | $this->assertEquals($length, strlen($stub)); 38 | if (file_exists('/dev/urandom')) { 39 | $this->assertNotEquals($not, $stub); 40 | } else { 41 | $this->assertEquals(str_repeat(chr(0), $length), $stub); 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /lib/PasswordLib/Core/BigMath/BCMath.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2011 The Authors 12 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 13 | * @version Build @@version@@ 14 | */ 15 | namespace PasswordLib\Core\BigMath; 16 | 17 | /** 18 | * A class for arbitrary precision math functions implemented using bcmath 19 | * 20 | * @category PHPPasswordLib 21 | * @package Core 22 | * @subpackage BigMath 23 | */ 24 | class BCMath extends \PasswordLib\Core\BigMath { 25 | 26 | /** 27 | * Add two numbers together 28 | * 29 | * @param string $left The left argument 30 | * @param string $right The right argument 31 | * 32 | * @return A base-10 string of the sum of the two arguments 33 | */ 34 | public function add($left, $right) { 35 | return bcadd($left, $right, 0); 36 | } 37 | 38 | /** 39 | * Subtract two numbers 40 | * 41 | * @param string $left The left argument 42 | * @param string $right The right argument 43 | * 44 | * @return A base-10 string of the difference of the two arguments 45 | */ 46 | public function subtract($left, $right) { 47 | return bcsub($left, $right); 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Source.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 14 | * @version Build @@version@@ 15 | */ 16 | 17 | namespace PasswordLib\Random; 18 | 19 | /** 20 | * The Random Number Source interface. 21 | * 22 | * All random number sources must implement this interface 23 | * 24 | * @category PHPPasswordLib 25 | * @package Random 26 | * @author Anthony Ferrara 27 | * @codeCoverageIgnore 28 | */ 29 | interface Source { 30 | 31 | /** 32 | * Return an instance of Strength indicating the strength of the source 33 | * 34 | * @return Strength An instance of one of the strength classes 35 | */ 36 | public static function getStrength(); 37 | 38 | /** 39 | * Generate a random string of the specified size 40 | * 41 | * Note: If the source fails to generate enough data, the result must be 42 | * padded to the requested length. 43 | * 44 | * @param int $size The size of the requested random string 45 | * 46 | * @return string A string of the requested size 47 | */ 48 | public function generate($size); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /lib/PasswordLib/Core/BigMath/GMP.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2011 The Authors 12 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 13 | * @version Build @@version@@ 14 | */ 15 | namespace PasswordLib\Core\BigMath; 16 | 17 | /** 18 | * A class for arbitrary precision math functions implemented using GMP 19 | * 20 | * @category PHPPasswordLib 21 | * @package Core 22 | * @subpackage BigMath 23 | */ 24 | class GMP extends \PasswordLib\Core\BigMath { 25 | 26 | /** 27 | * Add two numbers together 28 | * 29 | * @param string $left The left argument 30 | * @param string $right The right argument 31 | * 32 | * @return A base-10 string of the sum of the two arguments 33 | */ 34 | public function add($left, $right) { 35 | return gmp_strval(gmp_add($left, $right)); 36 | } 37 | 38 | /** 39 | * Subtract two numbers 40 | * 41 | * @param string $left The left argument 42 | * @param string $right The right argument 43 | * 44 | * @return A base-10 string of the difference of the two arguments 45 | */ 46 | public function subtract($left, $right) { 47 | return gmp_strval(gmp_sub($left, $right)); 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /test/Unit/Key/Derivation/PBKDF/PBKDF2Test.php: -------------------------------------------------------------------------------- 1 | assertTrue($pb instanceof PBKDF2); 21 | } 22 | 23 | /** 24 | * @covers PasswordLib\Key\Derivation\PBKDF\PBKDF2::derive 25 | * @dataProvider provideTestDerive 26 | * @group slow 27 | */ 28 | public function testDerive($p, $s, $c, $len, $hash, $expect) { 29 | $pb = new PBKDF2(array('hash'=>$hash)); 30 | $actual = $pb->derive($p, $s, $c, $len); 31 | $this->assertEquals($expect, $actual); 32 | } 33 | 34 | /** 35 | * @covers PasswordLib\Key\Derivation\PBKDF\PBKDF2::getSignature 36 | */ 37 | public function testGetSignature() { 38 | $pb = new PBKDF2(array('hash' => 'test')); 39 | $this->assertEquals('pbkdf2-test', $pb->getSignature()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/lib/VectorParser/CAVS.php: -------------------------------------------------------------------------------- 1 | file = $file; 13 | $this->parse(); 14 | } 15 | 16 | public function getVectors() { 17 | return $this->vectors; 18 | } 19 | 20 | protected function parse() { 21 | $data = file($this->file); 22 | $bufferValid = false; 23 | $buffer = array(); 24 | foreach ($data as $line) { 25 | $line = trim($line); 26 | if (empty($line)) { 27 | if ($bufferValid) { 28 | $this->processBuffer($buffer); 29 | $buffer = array(); 30 | $bufferValid = false; 31 | } 32 | } elseif ($line[0] == '#') { 33 | continue; 34 | } elseif ($line[0] == '[') { 35 | list ($key, $value) = explode('=', substr($line, 1, -1), 2); 36 | $buffer[trim($key)] = trim($value); 37 | } elseif (substr($line, 0, 5) == 'Count') { 38 | $bufferValid = true; 39 | } else { 40 | list ($key, $value) = explode('=', $line, 2); 41 | $buffer[trim($key)] = trim($value); 42 | } 43 | } 44 | } 45 | 46 | protected function processBuffer(array $buffer) { 47 | $this->vectors[] = $buffer; 48 | } 49 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Key/Derivation/AbstractDerivation.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2011 The Authors 12 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 13 | * @version Build @@version@@ 14 | */ 15 | 16 | namespace PasswordLib\Key\Derivation; 17 | 18 | /** 19 | * An abstract implementation of some standard key derivation needs 20 | * 21 | * @category PHPPasswordLib 22 | * @package Key 23 | * @subpackage Derivation 24 | * @author Anthony Ferrara 25 | */ 26 | abstract class AbstractDerivation { 27 | 28 | /** 29 | * @var Hash A hashing algorithm to use for the derivation 30 | */ 31 | protected $hash = null; 32 | 33 | /** 34 | * @var array An array of options for the key derivation function 35 | */ 36 | protected $options = array( 37 | 'hash' => 'sha512', 38 | ); 39 | 40 | /** 41 | * Construct the derivation instance 42 | * 43 | * @param array $options An array of options to set for this instance 44 | * 45 | * @return void 46 | */ 47 | public function __construct(array $options = array()) { 48 | $this->options = $options + $this->options; 49 | $this->hash = $this->options['hash']; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /test/Mocks/Core/Factory.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 12 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 13 | */ 14 | 15 | namespace PasswordLibTest\Mocks\Core; 16 | 17 | /** 18 | * The interface that all hash implementations must implement 19 | * 20 | * @category PHPPasswordLib 21 | * @package Hash 22 | * @author Anthony Ferrara 23 | */ 24 | class Factory extends \PasswordLib\Core\AbstractFactory { 25 | 26 | protected $callbacks = array(); 27 | 28 | public static function init() {} 29 | 30 | public function __construct(array $callbacks = array()) { 31 | $this->callbacks = $callbacks; 32 | } 33 | 34 | public function __call($name, array $args = array()) { 35 | if (isset($this->callbacks[$name])) { 36 | return call_user_func_array($this->callbacks[$name], $args); 37 | } 38 | return null; 39 | } 40 | 41 | public function registerType($a1, $a2, $a3, $a4, $a5 = false) { 42 | return parent::registerType($a1, $a2, $a3, $a4, $a5); 43 | } 44 | 45 | public function loadFiles($dir, $name, $method) { 46 | return parent::loadFiles($dir, $name, $method); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /test/Unit/Password/Implementation/Password_TestCase.php: -------------------------------------------------------------------------------- 1 | setExpectedException('DomainException'); 25 | } 26 | $this->getPassword()->create($password); 27 | } 28 | 29 | /** 30 | * @dataProvider provideCreateTypes 31 | */ 32 | public function testVerifyTypes($password, $valid) { 33 | $hash = $this->getPassword()->create('test'); 34 | if (!$valid) { 35 | $this->setExpectedException('DomainException'); 36 | } 37 | $this->getPassword()->verify($password, $hash); 38 | } 39 | 40 | 41 | protected function getPassword() { 42 | $class = $this->class; 43 | if ($class) { 44 | return new $class; 45 | } 46 | throw new Exception('Class not set!!!'); 47 | } 48 | 49 | } 50 | 51 | class CastTestCase { 52 | public function __toString() { 53 | return 'foo'; 54 | } 55 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Mixer.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 14 | * @version Build @@version@@ 15 | */ 16 | 17 | namespace PasswordLib\Random; 18 | 19 | /** 20 | * The Mixer strategy interface. 21 | * 22 | * All mixing strategies must implement this interface 23 | * 24 | * @category PHPPasswordLib 25 | * @package Random 26 | * @author Anthony Ferrara 27 | * @codeCoverageIgnore 28 | */ 29 | interface Mixer { 30 | 31 | /** 32 | * Return an instance of Strength indicating the strength of the mixer 33 | * 34 | * @return Strength An instance of one of the strength classes 35 | */ 36 | public static function getStrength(); 37 | 38 | /** 39 | * Test to see if the mixer is available 40 | * 41 | * @return boolean If the mixer is available on the system 42 | */ 43 | public static function test(); 44 | 45 | /** 46 | * Mix the provided array of strings into a single output of the same size 47 | * 48 | * All elements of the array should be the same size. 49 | * 50 | * @param array $parts The parts to be mixed 51 | * 52 | * @return string The mixed result 53 | */ 54 | public function mix(array $parts); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /test/bootstrap.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2011 The Authors 15 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 16 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 17 | */ 18 | 19 | namespace PasswordLibTest; 20 | 21 | ini_set('memory_limit', '1G'); 22 | 23 | /** 24 | * The simple autoloader for the PasswordLibTest libraries. 25 | * 26 | * This does not use the PRS-0 standards due to the namespace prefix and directory 27 | * structure 28 | * 29 | * @param string $class The class name to load 30 | * 31 | * @return void 32 | */ 33 | spl_autoload_register(function ($class) { 34 | $nslen = strlen(__NAMESPACE__); 35 | if (substr($class, 0, $nslen) != __NAMESPACE__) { 36 | //Only autoload libraries from this package 37 | return; 38 | } 39 | $path = substr(str_replace('\\', '/', $class), $nslen); 40 | $path = __DIR__ . $path . '.php'; 41 | if (file_exists($path)) { 42 | require $path; 43 | } 44 | }); 45 | 46 | define('PATH_ROOT', dirname(__DIR__)); 47 | 48 | function getTestDataFile($file) { 49 | return __DIR__ . '/Data/' . $file; 50 | } 51 | 52 | require_once dirname(__DIR__) . '/vendor/autoload.php'; 53 | 54 | -------------------------------------------------------------------------------- /test/lib/VectorParser/NESSIE.php: -------------------------------------------------------------------------------- 1 | file = $file; 13 | $this->parse(); 14 | } 15 | 16 | public function getVectors() { 17 | return $this->vectors; 18 | } 19 | 20 | protected function parse() { 21 | $data = file($this->file); 22 | $bufferValid = false; 23 | $buffer = array(); 24 | foreach ($data as $line) { 25 | if (isset($line[0]) && $line[0] != ' ' && $line[0] != "\t") { 26 | if ($bufferValid) { 27 | $this->processBuffer($buffer); 28 | } 29 | $buffer = array(); 30 | $bufferValid = substr($line, 0, 3) == 'Set'; 31 | } 32 | $buffer[] = $line; 33 | } 34 | } 35 | 36 | protected function processBuffer(array $lines) { 37 | $set = array_shift($lines); 38 | $key = ''; 39 | $buffer = ''; 40 | $record = array(); 41 | foreach ($lines as $row) { 42 | $row = trim($row); 43 | if (strpos($row, '=') !== false) { 44 | if ($key) { 45 | $record[$key] = $buffer; 46 | } 47 | list($key, $buffer) = explode('=', $row, 2); 48 | } else { 49 | $buffer .= $row; 50 | } 51 | } 52 | $record[$key] = $buffer; 53 | $this->vectors[] = $record; 54 | } 55 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/MD5.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2011 The Authors 14 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLib\Password\Implementation; 19 | 20 | use PasswordLib\Random\Factory as RandomFactory; 21 | 22 | /** 23 | * The Blowfish password hashing implementation 24 | * 25 | * Use this class to generate and validate Blowfish password hashes. 26 | * 27 | * @category PHPPasswordLib 28 | * @package Password 29 | * @subpackage Implementation 30 | * @author Anthony Ferrara 31 | */ 32 | class MD5 extends Crypt { 33 | 34 | protected static $prefix = '$1$'; 35 | 36 | protected $saltLen = 12; 37 | 38 | /** 39 | * Determine if the hash was made with this method 40 | * 41 | * @param string $hash The hashed data to check 42 | * 43 | * @return boolean Was the hash created by this method 44 | */ 45 | public static function detect($hash) { 46 | static $regex = '/^\$1\$[a-zA-Z0-9.\/]{8}\$[a-zA-Z0-9.\/]{22}/'; 47 | return 1 == preg_match($regex, $hash); 48 | } 49 | 50 | protected function generateSalt() { 51 | $salt = parent::generateSalt(); 52 | return '$1$' . $salt; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/Vectors/Password/Implementation/APR1Test.php: -------------------------------------------------------------------------------- 1 | getVectors() as $vector) { 12 | $results[] = array( 13 | $vector['P'], 14 | $vector['H'], 15 | (boolean) $vector['Value'], 16 | ); 17 | } 18 | $file = \PasswordLibTest\getTestDataFile('Vectors/apr1.custom.test-vectors'); 19 | $nessie = new PasswordLibTest\lib\VectorParser\SSV($file); 20 | foreach ($nessie->getVectors() as $vector) { 21 | $results[] = array( 22 | $vector[0], 23 | $vector[1], 24 | true 25 | ); 26 | } 27 | return $results; 28 | } 29 | 30 | /** 31 | * @covers PasswordLib\Password\Implementation\APR1::verify 32 | * @covers PasswordLib\Password\Implementation\APR1::to64 33 | * @covers PasswordLib\Password\Implementation\APR1::hash 34 | * @covers PasswordLib\Password\Implementation\APR1::iterate 35 | * @covers PasswordLib\Password\Implementation\APR1::convertToHash 36 | * @dataProvider provideTestVerify 37 | * @group Vectors 38 | */ 39 | public function testVerify($pass, $expect, $value) { 40 | $apr = new APR1(); 41 | $this->assertEquals($value, $apr->verify($pass, $expect)); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /test/Unit/Core/BigMathTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('PasswordLib\\Core\\BigMath\\GMP', get_class($instance)); 40 | } elseif (extension_loaded('bcmath')) { 41 | $this->assertEquals('PasswordLib\\Core\\BigMath\\BCMath', get_class($instance)); 42 | } else { 43 | $this->assertEquals('PasswordLib\\Core\\BigMath\\PHPMath', get_class($instance)); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /test/Vectors/Key/Derivation/PBKDF/PBKDF2Test.php: -------------------------------------------------------------------------------- 1 | $nessie->getVectors()); 12 | $file = \PasswordLibTest\getTestDataFile('Vectors/pbkdf2-draft-josefsson-sha256.test-vectors'); 13 | $nessie = new PasswordLibTest\lib\VectorParser\NESSIE($file); 14 | $data['sha256'] = $nessie->getVectors(); 15 | $results = array(); 16 | foreach ($data as $algo => $vectors) { 17 | foreach ($vectors as $row) { 18 | $results[] = array( 19 | str_replace('\0', "\0", $row['P']), 20 | str_replace('\0', "\0", $row['S']), 21 | $row['c'], 22 | $row['dkLen'], 23 | $algo, 24 | strtoupper($row['DK']) 25 | ); 26 | } 27 | } 28 | return $results; 29 | } 30 | 31 | /** 32 | * @covers PasswordLib\Key\Derivation\PBKDF\PBKDF2::derive 33 | * @dataProvider provideTestDerive 34 | * @group Vectors 35 | */ 36 | public function testDerive($p, $s, $c, $len, $hash, $expect) { 37 | $pb = new PBKDF2(array('hash'=>$hash)); 38 | $actual = $pb->derive($p, $s, $c, $len); 39 | $this->assertEquals($expect, strtoupper(bin2hex($actual))); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /lib/PasswordLib/Core/Strength.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 12 | * @version Build @@version@@ 13 | */ 14 | 15 | namespace PasswordLib\Core; 16 | 17 | /** 18 | * The strength FlyweightEnum class 19 | * 20 | * All mixing strategies must extend this class 21 | * 22 | * @category PHPPasswordLib 23 | * @package Core 24 | * @author Anthony Ferrara 25 | */ 26 | class Strength extends Enum { 27 | 28 | /** 29 | * We provide a default value of VeryLow so that we don't accidentally over 30 | * state the strength if we forget to pass in a value... 31 | */ 32 | const __DEFAULT = self::VERYLOW; 33 | 34 | /** 35 | * This represents Non-Cryptographic strengths. It should not be used any time 36 | * that security or confidentiality is at stake 37 | */ 38 | const VERYLOW = 1; 39 | 40 | /** 41 | * This represents the bottom line of Cryptographic strengths. It may be used 42 | * for low security uses where some strength is required. 43 | */ 44 | const LOW = 3; 45 | 46 | /** 47 | * This is the general purpose Cryptographical strength. It should be suitable 48 | * for all uses except the most sensitive. 49 | */ 50 | const MEDIUM = 5; 51 | 52 | /** 53 | * This is the highest strength available. It should not be used unless the 54 | * high strength is needed, due to hardware constraints (and entropy 55 | * limitations). 56 | */ 57 | const HIGH = 7; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/Drupal.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2011 The Authors 15 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 16 | * @version Build @@version@@ 17 | */ 18 | 19 | namespace PasswordLib\Password\Implementation; 20 | 21 | use PasswordLib\Random\Factory as RandomFactory; 22 | 23 | /** 24 | * The PHPASS password hashing implementation 25 | * 26 | * Use this class to generate and validate PHPASS password hashes. 27 | * 28 | * @see http://www.openwall.com/phpass/ 29 | * @category PHPPasswordLib 30 | * @package Password 31 | * @subpackage Implementation 32 | * @author Anthony Ferrara 33 | */ 34 | class Drupal extends PHPASS { 35 | 36 | /** 37 | * @var string The prefix for the generated hash 38 | */ 39 | protected static $prefix = '$S$'; 40 | 41 | /** 42 | * @var string The hash function to use for this instance 43 | */ 44 | protected $hashFunction = 'sha512'; 45 | 46 | /** 47 | * Determine if the hash was made with this method 48 | * 49 | * @param string $hash The hashed data to check 50 | * 51 | * @return boolean Was the hash created by this method 52 | */ 53 | public static function detect($hash) { 54 | $prefix = preg_quote(static::$prefix, '/'); 55 | return 1 == preg_match('/^'.$prefix.'[a-zA-Z0-9.\/]{95}$/', $hash); 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Source/UniqID.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2011 The Authors 15 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 16 | * @version Build @@version@@ 17 | */ 18 | 19 | namespace PasswordLib\Random\Source; 20 | 21 | use PasswordLib\Core\Strength; 22 | 23 | /** 24 | * The UniqID Random Number Source 25 | * 26 | * This uses the internal `uniqid()` function to generate low strength random 27 | * numbers. 28 | * 29 | * @category PHPPasswordLib 30 | * @package Random 31 | * @subpackage Source 32 | * @author Anthony Ferrara 33 | * @codeCoverageIgnore 34 | */ 35 | class UniqID implements \PasswordLib\Random\Source { 36 | 37 | /** 38 | * Return an instance of Strength indicating the strength of the source 39 | * 40 | * @return Strength An instance of one of the strength classes 41 | */ 42 | public static function getStrength() { 43 | return new Strength(Strength::LOW); 44 | } 45 | 46 | /** 47 | * Generate a random string of the specified size 48 | * 49 | * @param int $size The size of the requested random string 50 | * 51 | * @return string A string of the requested size 52 | */ 53 | public function generate($size) { 54 | $result = ''; 55 | while (strlen($result) < $size) { 56 | $result = uniqid($result, true); 57 | } 58 | return substr($result, 0, $size); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /examples/Password/drupal.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2011 The Authors 12 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 13 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 14 | */ 15 | 16 | namespace PasswordLibExamples\Password; 17 | 18 | //We first load the bootstrap file so we have access to the library 19 | require_once dirname(dirname(__DIR__)) . '/lib/PasswordLib/bootstrap.php'; 20 | 21 | /** 22 | * Now, let's create a password that's compatible with Drupal 23 | */ 24 | 25 | // First, let's create an instance of Drupal, where 15 is the iteration count for D7 26 | $hasher = new \PasswordLib\Password\Implementation\Drupal(15); 27 | 28 | $password = 'FooBarBaz'; 29 | 30 | // Now, let's create a password hash of the password "FooBarBaz" 31 | $hash = $hasher->create($password); 32 | 33 | //It's safe to print, so let's output it: 34 | printf( 35 | "Password: %s\nHash: %s\n\n", 36 | $password, 37 | $hash 38 | ); 39 | 40 | /** 41 | * Now, we can also verify any passwords created by Drupal. First, let's load a hash. 42 | * 43 | * This works, because it detects the iteration count that's stored in the hash, and 44 | * pre-configures our instance for us. 45 | */ 46 | $hasher2 = \PasswordLib\Password\Implementation\Drupal::loadFromHash($hash); 47 | 48 | /** 49 | * Next, we verify the hash with the expected password. 50 | */ 51 | $test = $hasher2->verify($password, $hash); 52 | 53 | /** 54 | * $test should now contain a boolean value as to the validity of the hash 55 | */ 56 | printf( 57 | "Verification was %s\n\n", 58 | $test ? "Successful!" : "Failed!" 59 | ); -------------------------------------------------------------------------------- /test/Mocks/Random/Generator.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 14 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 15 | */ 16 | 17 | namespace PasswordLibTest\Mocks\Random; 18 | 19 | 20 | /** 21 | * The Mixer strategy interface. 22 | * 23 | * All mixing strategies must implement this interface 24 | * 25 | * @category PHPPasswordLib 26 | * @package Random 27 | * @author Anthony Ferrara 28 | */ 29 | class Generator extends \PasswordLib\Random\Generator { 30 | protected $callbacks = array(); 31 | 32 | public static function init() {} 33 | 34 | public function __construct(array $callbacks = array()) { 35 | $this->callbacks = $callbacks; 36 | } 37 | 38 | public function __call($name, array $args = array()) { 39 | if (isset($this->callbacks[$name])) { 40 | return call_user_func_array($this->callbacks[$name], $args); 41 | } 42 | return null; 43 | } 44 | 45 | public function addSource(\PasswordLib\Random\Source $source) { 46 | return $this->__call('addSource', array($source)); 47 | } 48 | 49 | public function generate($size) { 50 | return $this->__call('generate', array($size)); 51 | } 52 | 53 | public function generateInt($min = 0, $max = \PHP_INT_MAX) { 54 | return $this->__call('generateInt', array($min, $max)); 55 | } 56 | 57 | public function generateString($length, $chars = '') { 58 | return $this->__call('generateString', array($length, $chars)); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /lib/PasswordLib/Key/Derivation/PBKDF.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2011 The Authors 15 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 16 | * @version Build @@version@@ 17 | */ 18 | 19 | namespace PasswordLib\Key\Derivation; 20 | 21 | /** 22 | * The core PBKDF interface (Password Based Key Derivation Function) 23 | * 24 | * This interface must be used to describe all derivation functions that take a 25 | * password as input and produce a key or hash as output 26 | * 27 | * @category PHPPasswordLib 28 | * @package Key 29 | * @subpackage Derivation 30 | * @author Anthony Ferrara 31 | * @codeCoverageIgnore 32 | */ 33 | interface PBKDF { 34 | 35 | /** 36 | * Derive a key from the supplied arguments 37 | * 38 | * @param string $password The password to derive from 39 | * @param string $salt The salt string to use 40 | * @param int $iterations The number of iterations to use 41 | * @param int $length The size of the string to generate 42 | * 43 | * @return string The derived key 44 | */ 45 | public function derive($passkey, $salt, $iterations, $klen); 46 | 47 | /** 48 | * Get the signature for this implementation 49 | * 50 | * This should include all information needed to build the same isntance 51 | * later. 52 | * 53 | * @return string The signature for this instance 54 | */ 55 | public function getSignature(); 56 | 57 | } 58 | -------------------------------------------------------------------------------- /test/Mocks/Random/Source.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 14 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 15 | */ 16 | 17 | namespace PasswordLibTest\Mocks\Random; 18 | 19 | use PasswordLib\Core\Strength\VeryLow as VeryLowStrength; 20 | 21 | /** 22 | * The Random Number Source interface. 23 | * 24 | * All random number sources must implement this interface 25 | * 26 | * @category PHPPasswordLib 27 | * @package Random 28 | * @author Anthony Ferrara 29 | */ 30 | class Source extends \PasswordLibTest\Mocks\AbstractMock implements \PasswordLib\Random\Source { 31 | 32 | public static $strength = null; 33 | 34 | public static function init() { 35 | static::$strength = new VeryLowStrength; 36 | } 37 | 38 | /** 39 | * Return an instance of Strength indicating the strength of the source 40 | * 41 | * @return Strength An instance of one of the strength classes 42 | */ 43 | public static function getStrength() { 44 | return static::$strength; 45 | } 46 | 47 | 48 | /** 49 | * Generate a random string of the specified size 50 | * 51 | * Note: If the source fails to generate enough data, the result must be 52 | * padded to the requested length. 53 | * 54 | * @param int $size The size of the requested random string 55 | * 56 | * @return string A string of the requested size 57 | */ 58 | public function generate($size) { 59 | return $this->__call('generate', array($size)); 60 | } 61 | 62 | } 63 | 64 | 65 | -------------------------------------------------------------------------------- /test/Unit/Core/EnumTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($obj instanceof \PasswordLib\Core\Enum); 24 | } 25 | 26 | public function testToString() { 27 | $obj = new Enum(Enum::Value3); 28 | $this->assertEquals('3', (string) $obj); 29 | } 30 | 31 | /** 32 | * @covers PasswordLib\Core\Enum::compare 33 | * @dataProvider provideTestCompare 34 | */ 35 | public function testCompare(Enum $from, Enum $to, $expected) { 36 | $this->assertEquals($expected, $from->compare($to)); 37 | } 38 | 39 | public function testGetConstList() { 40 | $obj = new Enum(Enum::Value3); 41 | $const = $obj->getConstList(); 42 | $this->assertEquals(array( 43 | 'Value1' => 1, 44 | 'Value2' => 2, 45 | 'Value3' => 3, 46 | 'Value4' => 4, 47 | ), $const); 48 | } 49 | 50 | public function testGetConstListWithDefault() { 51 | $obj = new Enum(Enum::Value3); 52 | $const = $obj->getConstList(true); 53 | $this->assertEquals(array( 54 | '__DEFAULT' => null, 55 | 'Value1' => 1, 56 | 'Value2' => 2, 57 | 'Value3' => 3, 58 | 'Value4' => 4, 59 | ), $const); 60 | } 61 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Source/CAPICOM.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2011 The Authors 14 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLib\Random\Source; 19 | 20 | use PasswordLib\Core\Strength; 21 | 22 | /** 23 | * The Capicom Random Number Source 24 | * 25 | * This uses the Windows CapiCom Com object to generate random numbers 26 | * 27 | * @category PHPPasswordLib 28 | * @package Random 29 | * @subpackage Source 30 | * @author Anthony Ferrara 31 | * @codeCoverageIgnore 32 | */ 33 | class CAPICOM implements \PasswordLib\Random\Source { 34 | 35 | /** 36 | * Return an instance of Strength indicating the strength of the source 37 | * 38 | * @return Strength An instance of one of the strength classes 39 | */ 40 | public static function getStrength() { 41 | return new Strength(Strength::MEDIUM); 42 | } 43 | 44 | /** 45 | * Generate a random string of the specified size 46 | * 47 | * @param int $size The size of the requested random string 48 | * 49 | * @return string A string of the requested size 50 | */ 51 | public function generate($size) { 52 | if (!class_exists('\\COM', false)) { 53 | return str_repeat(chr(0), $size); 54 | } 55 | try { 56 | $util = new \COM('CAPICOM.Utilities.1'); 57 | $data = base64_decode($util->GetRandom($size, 0)); 58 | return str_pad($data, $size, chr(0)); 59 | } catch (\Exception $e) { 60 | unset($e); 61 | return str_repeat(chr(0), $size); 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /test/Mocks/Key/Derivation/PBKDF.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 14 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLibTest\Mocks\Key\Derivation; 19 | 20 | /** 21 | * An implementation of the RFC 2898 PBKDF2 Standard key derivation function 22 | * 23 | * @see http://www.ietf.org/rfc/rfc2898.txt 24 | * @category PHPPasswordLib 25 | * @package Key 26 | * @subpackage Derivation 27 | * @author Anthony Ferrara 28 | */ 29 | class PBKDF 30 | extends \PasswordLibTest\Mocks\AbstractMock 31 | implements \PasswordLib\Key\Derivation\PBKDF 32 | { 33 | 34 | /** 35 | * Derive a key from the supplied arguments 36 | * 37 | * @param string $password The password to derive from 38 | * @param string $salt The salt string to use 39 | * @param int $iterations The number of iterations to use 40 | * @param int $length The size of the string to generate 41 | * 42 | * @return string The derived key 43 | */ 44 | public function derive($password, $salt, $iterations, $length) { 45 | return $this->__call('derive', func_get_args()); 46 | } 47 | 48 | /** 49 | * Get the signature for this implementation 50 | * 51 | * This should include all information needed to build the same isntance 52 | * later. 53 | * 54 | * @return string The signature for this instance 55 | */ 56 | public function getSignature() { 57 | return $this->__call('getSignature', array()); 58 | } 59 | 60 | } 61 | 62 | -------------------------------------------------------------------------------- /lib/PasswordLib/Core/BigMath.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 12 | * @version Build @@version@@ 13 | */ 14 | namespace PasswordLib\Core; 15 | 16 | /** 17 | * A class for arbitrary precision math functions 18 | * 19 | * @category PHPPasswordLib 20 | * @package Core 21 | * @author Anthony Ferrara 22 | */ 23 | abstract class BigMath { 24 | 25 | /** 26 | * Get an instance of the big math class 27 | * 28 | * This is NOT a singleton. It simply loads the proper strategy 29 | * given the current server configuration 30 | * 31 | * @return \PasswordLib\Core\BigMath A big math instance 32 | */ 33 | public static function createFromServerConfiguration() { 34 | //@codeCoverageIgnoreStart 35 | if (extension_loaded('gmp')) { 36 | return new \PasswordLib\Core\BigMath\GMP(); 37 | } elseif (extension_loaded('bcmath')) { 38 | return new \PasswordLib\Core\BigMath\BCMath(); 39 | } else { 40 | return new \PasswordLib\Core\BigMath\PHPMath(); 41 | } 42 | //@codeCoverageIgnoreEnd 43 | } 44 | 45 | /** 46 | * Add two numbers together 47 | * 48 | * @param string $left The left argument 49 | * @param string $right The right argument 50 | * 51 | * @return A base-10 string of the sum of the two arguments 52 | */ 53 | abstract public function add($left, $right); 54 | 55 | /** 56 | * Subtract two numbers 57 | * 58 | * @param string $left The left argument 59 | * @param string $right The right argument 60 | * 61 | * @return A base-10 string of the difference of the two arguments 62 | */ 63 | abstract public function subtract($left, $right); 64 | 65 | } -------------------------------------------------------------------------------- /test/Unit/Random/Mixer/HashTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($hash instanceof \PasswordLib\Random\Mixer); 31 | } 32 | 33 | /** 34 | * @covers PasswordLib\Random\Mixer\Hash 35 | * @covers PasswordLib\Random\AbstractMixer 36 | */ 37 | public function testGetStrength() { 38 | $strength = new Strength(Strength::MEDIUM); 39 | $actual = Hash::getStrength(); 40 | $this->assertEquals($actual, $strength); 41 | } 42 | 43 | /** 44 | * @covers PasswordLib\Random\Mixer\Hash 45 | * @covers PasswordLib\Random\AbstractMixer 46 | */ 47 | public function testTest() { 48 | $actual = Hash::test(); 49 | $this->assertTrue($actual); 50 | } 51 | 52 | /** 53 | * @covers PasswordLib\Random\Mixer\Hash 54 | * @covers PasswordLib\Random\AbstractMixer 55 | * @dataProvider provideMix 56 | */ 57 | public function testMix($parts, $result) { 58 | $mixer = new Hash('md5'); 59 | $actual = $mixer->mix($parts); 60 | $this->assertEquals($result, bin2hex($actual)); 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /examples/Random/numbers.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 12 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 13 | */ 14 | 15 | namespace PasswordLibExamples\Random; 16 | 17 | 18 | /** 19 | * Let's generate some random integers! For this, we'll use the 20 | * PasswordLib\Random\Factory class to build a random number generator to suit 21 | * our needs here. 22 | */ 23 | 24 | //We first load the bootstrap file so we have access to the library 25 | require_once dirname(dirname(__DIR__)) . '/lib/PasswordLib/bootstrap.php'; 26 | 27 | //Now, let's get a random number factory 28 | $factory = new \PasswordLib\Random\Factory; 29 | 30 | /** 31 | * Now, since we want a low strength random number, let's get a low strength 32 | * generator from the factory. 33 | * 34 | * If we wanted stronger random numbers, we could change this to medium or high 35 | * but both use significantly more resources to generate, so let's just stick 36 | * with low for the purposes of this example: 37 | */ 38 | $generator = $factory->getLowStrengthGenerator(); 39 | 40 | /** 41 | * Now, let's start generating our random numbers! To start off with, let's 42 | * pick a few random number between 1 and 10 43 | */ 44 | $numbers = array(); 45 | for ($i = 0; $i < 5; $i++) { 46 | $numbers[] = $generator->generateInt(1, 10); 47 | } 48 | vprintf("\nRandom Numbers between 1 and 10: %d, %d, %d, %d, %d \n", $numbers); 49 | 50 | /** 51 | * Now, since we have that down, let's have some fun: 52 | */ 53 | printf("\nA negative random number: %d\n", $generator->generateInt(-100, 0)); 54 | 55 | printf("\nA really big random number: %d\n", $generator->generateInt(1234567, 12345678)); 56 | 57 | printf("\nA not-so-random number: %d\n", $generator->generateInt(42, 42)); 58 | 59 | /** 60 | * And that's all there is to it! 61 | */ 62 | -------------------------------------------------------------------------------- /test/Mocks/Random/Mixer.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 14 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 15 | */ 16 | 17 | namespace PasswordLibTest\Mocks\Random; 18 | 19 | use PasswordLib\Core\Strength\High as HighStrength; 20 | 21 | /** 22 | * The Mixer strategy interface. 23 | * 24 | * All mixing strategies must implement this interface 25 | * 26 | * @category PHPPasswordLib 27 | * @package Random 28 | * @author Anthony Ferrara 29 | */ 30 | class Mixer extends \PasswordLibTest\Mocks\AbstractMock implements \PasswordLib\Random\Mixer { 31 | 32 | public static $strength = null; 33 | 34 | public static $test = true; 35 | 36 | public static function init() { 37 | static::$strength = new HighStrength; 38 | static::$test = true; 39 | } 40 | 41 | /** 42 | * Return an instance of Strength indicating the strength of the mixer 43 | * 44 | * @return Strength An instance of one of the strength classes 45 | */ 46 | public static function getStrength() { 47 | return static::$strength; 48 | } 49 | 50 | /** 51 | * Test to see if the mixer is available 52 | * 53 | * @return boolean If the mixer is available on the system 54 | */ 55 | public static function test() { 56 | return static::$test; 57 | } 58 | 59 | /** 60 | * Mix the provided array of strings into a single output of the same size 61 | * 62 | * All elements of the array should be the same size. 63 | * 64 | * @param array $parts The parts to be mixed 65 | * 66 | * @return string The mixed result 67 | */ 68 | public function mix(array $parts) { 69 | return $this->__call('mix', array($parts)); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Source/URandom.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2011 The Authors 14 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLib\Random\Source; 19 | 20 | use PasswordLib\Core\Strength; 21 | 22 | /** 23 | * The URandom Random Number Source 24 | * 25 | * This uses the *nix /dev/urandom device to generate medium strength numbers 26 | * 27 | * @category PHPPasswordLib 28 | * @package Random 29 | * @subpackage Source 30 | * @author Anthony Ferrara 31 | * @codeCoverageIgnore 32 | */ 33 | class URandom implements \PasswordLib\Random\Source { 34 | 35 | /** 36 | * @var string The file to read from 37 | */ 38 | protected $file = '/dev/urandom'; 39 | 40 | /** 41 | * Return an instance of Strength indicating the strength of the source 42 | * 43 | * @return Strength An instance of one of the strength classes 44 | */ 45 | public static function getStrength() { 46 | return new Strength(Strength::MEDIUM); 47 | } 48 | 49 | /** 50 | * Generate a random string of the specified size 51 | * 52 | * @param int $size The size of the requested random string 53 | * 54 | * @return string A string of the requested size 55 | */ 56 | public function generate($size) { 57 | if ($size == 0 || !file_exists($this->file)) { 58 | return str_repeat(chr(0), $size); 59 | } 60 | $file = fopen($this->file, 'rb'); 61 | if (!$file) { 62 | return str_repeat(chr(0), $size); 63 | } 64 | if (function_exists('stream_set_read_buffer')) { 65 | stream_set_read_buffer($file, 0); 66 | } 67 | $result = fread($file, $size); 68 | fclose($file); 69 | return $result; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Source/Rand.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2011 The Authors 16 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 17 | * @version Build @@version@@ 18 | */ 19 | 20 | namespace PasswordLib\Random\Source; 21 | 22 | use PasswordLib\Core\Strength; 23 | 24 | /** 25 | * The Rand Random Number Source 26 | * 27 | * This source generates low strength random numbers by using the internal 28 | * rand() function. By itself it is quite weak. However when combined with 29 | * other sources it does provide significant benefit. 30 | * 31 | * @category PHPPasswordLib 32 | * @package Random 33 | * @subpackage Source 34 | * @author Anthony Ferrara 35 | * @codeCoverageIgnore 36 | */ 37 | class Rand implements \PasswordLib\Random\Source { 38 | 39 | /** 40 | * Return an instance of Strength indicating the strength of the source 41 | * 42 | * @return Strength An instance of one of the strength classes 43 | */ 44 | public static function getStrength() { 45 | // Detect if Suhosin Hardened PHP patch is applied 46 | if (defined('S_ALL')) { 47 | return new Strength(Strength::LOW); 48 | } else { 49 | return new Strength(Strength::VERYLOW); 50 | } 51 | } 52 | 53 | /** 54 | * Generate a random string of the specified size 55 | * 56 | * @param int $size The size of the requested random string 57 | * 58 | * @return string A string of the requested size 59 | */ 60 | public function generate($size) { 61 | $result = ''; 62 | for ($i = 0; $i < $size; $i++) { 63 | $result .= chr((rand() ^ rand()) % 256); 64 | } 65 | return $result; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Password.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 14 | * @version Build @@version@@ 15 | */ 16 | 17 | namespace PasswordLib\Password; 18 | 19 | /** 20 | * The core password key interface 21 | * 22 | * All pasword implementations must implement this interface 23 | * 24 | * @category PHPPasswordLib 25 | * @package Password 26 | * @author Anthony Ferrara 27 | * @codeCoverageIgnore 28 | */ 29 | interface Password { 30 | 31 | /** 32 | * Determine if the hash was made with this method 33 | * 34 | * @param string $hash The hashed data to check 35 | * 36 | * @return boolean Was the hash created by this method 37 | */ 38 | public static function detect($hash); 39 | 40 | /** 41 | * Return the prefix used by this hashing method 42 | * 43 | * @return string The prefix used 44 | */ 45 | public static function getPrefix(); 46 | 47 | /** 48 | * Load an instance of the class based upon the supplied hash 49 | * 50 | * @param string $hash The hash to load from 51 | * 52 | * @return Password the created instance 53 | */ 54 | public static function loadFromHash($hash); 55 | 56 | /** 57 | * Create a password hash for a given plain text password 58 | * 59 | * @param string $password The password to hash 60 | * 61 | * @return string The formatted password hash 62 | */ 63 | public function create($password); 64 | 65 | /** 66 | * Verify a password hash against a given plain text password 67 | * 68 | * @param string $password The password to hash 69 | * @param string $hash The supplied ahsh to validate 70 | * 71 | * @return boolean Does the password validate against the hash 72 | */ 73 | public function verify($password, $hash); 74 | 75 | } 76 | -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/MediaWiki.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2013 The Authors 14 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLib\Password\Implementation; 19 | 20 | use PasswordLib\Random\Factory as RandomFactory; 21 | 22 | /** 23 | * The MediaWiki password hashing implementation 24 | * 25 | * Use this class to generate and validate MediaWiki password hashes. 26 | * 27 | * @category PHPPasswordLib 28 | * @package Password 29 | * @subpackage Implementation 30 | * @author Anthony Ferrara 31 | */ 32 | class MediaWiki extends Crypt { 33 | 34 | protected static $prefix = 'mwB'; 35 | 36 | public static function detect($hash) { 37 | $prefix = static::getPrefix(); 38 | return strncmp($hash, $prefix, strlen($prefix)) === 0; 39 | } 40 | 41 | public function create($password) { 42 | $prefix = static::getPrefix(); 43 | $password = $this->checkPassword($password); 44 | $salt = $this->generateSalt(); 45 | $result = $prefix.$salt.'.'.md5($salt.'-'.md5($password)); 46 | return $result; 47 | } 48 | 49 | public function verify($password, $hash) { 50 | $prefix = static::getPrefix(); 51 | $password = $this->checkPassword($password); 52 | if (!static::detect($hash)) { 53 | throw new \InvalidArgumentException( 54 | 'The hash was not created here, we cannot verify it' 55 | ); 56 | } 57 | preg_match('/^' . $prefix . '(.+)\./', $hash, $match); 58 | $salt = null; 59 | if (isset($match[1])) { 60 | $salt = $match[1]; 61 | } 62 | $test = $prefix.$salt.'.'.md5($salt.'-'.md5($password)); 63 | return $this->compareStrings($test, $hash); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Source/MTRand.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2011 The Authors 16 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 17 | * @version Build @@version@@ 18 | */ 19 | 20 | namespace PasswordLib\Random\Source; 21 | 22 | use PasswordLib\Core\Strength; 23 | 24 | /** 25 | * The MTRand Random Number Source 26 | * 27 | * This source generates low strength random numbers by using the internal 28 | * mt_rand() function. By itself it is quite weak. However when combined with 29 | * other sources it does provide significant benefit. 30 | * 31 | * @category PHPPasswordLib 32 | * @package Random 33 | * @subpackage Source 34 | * @author Anthony Ferrara 35 | * @codeCoverageIgnore 36 | */ 37 | class MTRand implements \PasswordLib\Random\Source { 38 | 39 | /** 40 | * Return an instance of Strength indicating the strength of the source 41 | * 42 | * @return Strength An instance of one of the strength classes 43 | */ 44 | public static function getStrength() { 45 | // Detect if Suhosin Hardened PHP patch is applied 46 | if (defined('S_ALL')) { 47 | return new Strength(Strength::MEDIUM); 48 | } else { 49 | return new Strength(Strength::LOW); 50 | } 51 | } 52 | 53 | /** 54 | * Generate a random string of the specified size 55 | * 56 | * @param int $size The size of the requested random string 57 | * 58 | * @return string A string of the requested size 59 | */ 60 | public function generate($size) { 61 | $result = ''; 62 | for ($i = 0; $i < $size; $i++) { 63 | $result .= chr((mt_rand() ^ mt_rand()) % 256); 64 | } 65 | return $result; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /test/Unit/Core/AbstractFactoryTest.php: -------------------------------------------------------------------------------- 1 | at($root); 13 | $af = vfsStream::newDirectory('AbstractFactory')->at($core); 14 | 15 | // Create Files 16 | vfsStream::newFile('test.php')->at($af); 17 | vfsStream::newFile('Some234Foo234Bar98Name.php')->at($af); 18 | vfsStream::newFile('Invalid.csv')->at($af); 19 | vfsStream::newFile('badlocation.php')->at($core); 20 | } 21 | 22 | /** 23 | * @covers PasswordLib\Core\AbstractFactory::registerType 24 | */ 25 | public function testRegisterType() { 26 | $factory = new Factory; 27 | $factory->registerType('test', 'iteratoraggregate', 'foo', 'ArrayObject', false); 28 | } 29 | 30 | /** 31 | * @covers PasswordLib\Core\AbstractFactory::registerType 32 | * @expectedException InvalidArgumentException 33 | */ 34 | public function testRegisterTypeFail() { 35 | $factory = new Factory; 36 | $factory->registerType('test', 'iterator', 'foo', 'ArrayObject', false); 37 | } 38 | 39 | /** 40 | * @covers PasswordLib\Core\AbstractFactory::registerType 41 | */ 42 | public function testRegisterTypeInstantiate() { 43 | $factory = new Factory; 44 | $factory->registerType('test', 'iteratoraggregate', 'foo', 'ArrayObject', true); 45 | } 46 | 47 | public function testLoadFiles() { 48 | $dir = vfsStream::url('PasswordLibTest/Core/AbstractFactory'); 49 | 50 | $result = array(); 51 | $callback = function($name, $class) use (&$result) { 52 | $result[$name] = $class; 53 | }; 54 | 55 | $factory = new Factory(); 56 | $factory->loadFiles($dir, 'foo\\', $callback); 57 | 58 | $expect = array( 59 | 'test' => 'foo\\test', 60 | 'Some234Foo234Bar98Name' => 'foo\\Some234Foo234Bar98Name' 61 | ); 62 | 63 | $this->assertEquals($expect, $result); 64 | } 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /test/Unit/Core/BaseConverterTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($expect, $result); 35 | } 36 | 37 | /** 38 | * @covers PasswordLib\Core\BaseConverter::convertToBinary 39 | * @covers PasswordLib\Core\BaseConverter::baseConvert 40 | * @dataProvider provideConvertFromBinary 41 | */ 42 | public function testConvertToBinary($expect, $from, $str) { 43 | $result = BaseConverter::convertToBinary($str, $from); 44 | $result = ltrim($result, chr(0)); 45 | $expect = ltrim($expect, chr(0)); 46 | $this->assertEquals($expect, $result); 47 | } 48 | 49 | /** 50 | * @covers PasswordLib\Core\BaseConverter::convertToBinary 51 | * @covers PasswordLib\Core\BaseConverter::convertFromBinary 52 | * @covers PasswordLib\Core\BaseConverter::baseConvert 53 | * @dataProvider provideConvertToFromBinary 54 | */ 55 | public function testConvertToAndFromBinary($str, $from) { 56 | return false; 57 | $result1 = BaseConverter::convertFromBinary($str, $from); 58 | $result = BaseConverter::convertToBinary($result1, $from); 59 | $this->assertEquals($str, $result); 60 | } 61 | 62 | /** 63 | * @covers PasswordLib\Core\BaseConverter::baseConvert 64 | * @expectedException InvalidArgumentException 65 | */ 66 | public function testBaseConvertFailure() { 67 | BaseConverter::baseConvert(array(1), 1, 1); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/Unit/Password/FactoryTest.php: -------------------------------------------------------------------------------- 1 | createHash('foo', $algo); 29 | $this->assertEquals($size, strlen($text)); 30 | } 31 | 32 | /** 33 | * @expectedException DomainException 34 | */ 35 | public function testCreateFailure() { 36 | $factory = new Factory; 37 | $text = $factory->createHash('foo', '$abcdef$'); 38 | } 39 | 40 | /** 41 | * @expectedException DomainException 42 | */ 43 | public function testCreateFailure2() { 44 | $factory = new Factory; 45 | $text = $factory->createHash('foo', false); 46 | } 47 | 48 | /** 49 | * @dataProvider provideTestCreate 50 | */ 51 | public function testCreateThenVerify($algo) { 52 | $factory = new Factory; 53 | $text = $factory->createHash('foo', $algo); 54 | $this->assertTrue($factory->verifyHash('foo', $text)); 55 | } 56 | 57 | /** 58 | * @expectedException DomainException 59 | */ 60 | public function testVerifyFailure() { 61 | $factory = new Factory; 62 | $text = $factory->verifyHash('foo', 'foo'); 63 | } 64 | 65 | public function testVerifyMD5() { 66 | $factory = new Factory; 67 | $this->assertTrue($factory->verifyHash('foo', md5('foo'))); 68 | } 69 | 70 | public function testVerifySHA1() { 71 | $factory = new Factory; 72 | $this->assertTrue($factory->verifyHash('foo', sha1('foo'))); 73 | } 74 | 75 | public function testVerifySHA256() { 76 | $factory = new Factory; 77 | $this->assertTrue($factory->verifyHash('foo', hash('sha256', 'foo'))); 78 | } 79 | 80 | public function testVerifySHA512() { 81 | $factory = new Factory; 82 | $this->assertTrue($factory->verifyHash('foo', hash('sha512', 'foo'))); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lib/PasswordLib/Key/Derivation/PBKDF/PBKDF2.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 14 | * @version Build @@version@@ 15 | */ 16 | 17 | namespace PasswordLib\Key\Derivation\PBKDF; 18 | 19 | use PasswordLib\Hash\Hash; 20 | 21 | /** 22 | * An implementation of the RFC 2898 PBKDF2 Standard key derivation function 23 | * 24 | * @see http://www.ietf.org/rfc/rfc2898.txt 25 | * @category PHPPasswordLib 26 | * @package Key 27 | * @subpackage Derivation 28 | * @author Anthony Ferrara 29 | */ 30 | class PBKDF2 31 | extends \PasswordLib\Key\Derivation\AbstractDerivation 32 | implements \PasswordLib\Key\Derivation\PBKDF 33 | { 34 | 35 | /** 36 | * Derive a key from the supplied arguments 37 | * 38 | * @param string $password The password to derive from 39 | * @param string $salt The salt string to use 40 | * @param int $iterations The number of iterations to use 41 | * @param int $length The size of the string to generate 42 | * 43 | * @return string The derived key 44 | */ 45 | public function derive($password, $salt, $iterations, $length) { 46 | $size = Hash::getHashSize($this->hash); 47 | $len = ceil($length / $size); 48 | $result = ''; 49 | for ($i = 1; $i <= $len; $i++) { 50 | $tmp = hash_hmac( 51 | $this->hash, 52 | $salt . pack('N', $i), 53 | $password, 54 | true 55 | ); 56 | $res = $tmp; 57 | for ($j = 1; $j < $iterations; $j++) { 58 | $tmp = hash_hmac($this->hash, $tmp, $password, true); 59 | $res ^= $tmp; 60 | } 61 | $result .= $res; 62 | } 63 | return substr($result, 0, $length); 64 | } 65 | 66 | /** 67 | * Get the signature for this implementation 68 | * 69 | * This should include all information needed to build the same isntance 70 | * later. 71 | * 72 | * @return string The signature for this instance 73 | */ 74 | public function getSignature() { 75 | return 'pbkdf2-' . $this->hash; 76 | } 77 | 78 | } 79 | 80 | -------------------------------------------------------------------------------- /examples/Random/strings.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 12 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 13 | */ 14 | 15 | namespace PasswordLibExamples\Random; 16 | 17 | /** 18 | * Let's generate some random strings! For this, we'll use the 19 | * PasswordLib\Random\Factory class to build a random number generator to suit 20 | * our needs here. 21 | */ 22 | 23 | //We first load the bootstrap file so we have access to the library 24 | require_once dirname(dirname(__DIR__)) . '/lib/PasswordLib/bootstrap.php'; 25 | 26 | //Now, let's get a random number factory 27 | $factory = new \PasswordLib\Random\Factory; 28 | 29 | /** 30 | * Now, since we want a low strength random number, let's get a low strength 31 | * generator from the factory. 32 | * 33 | * If we wanted stronger random numbers, we could change this to medium or high 34 | * but both use significantly more resources to generate, so let's just stick 35 | * with low for the purposes of this example: 36 | */ 37 | $generator = $factory->getLowStrengthGenerator(); 38 | 39 | /** 40 | * We can now start generating our random strings. The generator by default 41 | * outputs full-byte strings (character 0 - 255), so it's not safe to display 42 | * them directly. Instead, let's convert them to hex to show the string. 43 | */ 44 | $number = $generator->generate(8); 45 | 46 | printf("\nHere's our first random string: %s\n", bin2hex($number)); 47 | 48 | /** 49 | * We can also base64 encode it to display the string 50 | */ 51 | $number = $generator->generate(8); 52 | 53 | printf("\nHere's a base64 encoded random string: %s\n", base64_encode($number)); 54 | 55 | /** 56 | * But, we can also generate random strings against a list of characters. That 57 | * way we can use the random string in user-facing situations: (this can be for 58 | * one-time-use passwords, CRSF tokens, etc). 59 | * 60 | * Now, let's define a string of allowable characters to use for token 61 | * generation. 62 | */ 63 | $characters = '0123456789abcdefghijklmnopqrstuvwxyz' . 64 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%&;<>?'; 65 | 66 | /** 67 | * After that, we can generate the random string 68 | */ 69 | 70 | $string = $generator->generateString(16, $characters); 71 | 72 | printf("\nHere's our token: %s\n", $string); 73 | -------------------------------------------------------------------------------- /test/Unit/PasswordLibTest.php: -------------------------------------------------------------------------------- 1 | createPasswordHash($password, $prefix); 17 | $this->assertTrue($test == crypt($password, $test)); 18 | } 19 | 20 | public function testVerifyPasswordHash() { 21 | $password = 'foobar'; 22 | $prefix = Blowfish::getPrefix(); 23 | $crypt = new PasswordLib; 24 | $test = $crypt->createPasswordHash($password, $prefix); 25 | $this->assertTrue($crypt->verifyPasswordHash($password, $test)); 26 | } 27 | 28 | public function testGetRandomArrayElement() { 29 | $array = range(1, 100); 30 | $crypt = new PasswordLib; 31 | $el = $crypt->getRandomArrayElement($array); 32 | $this->assertTrue(in_array($el, $array)); 33 | } 34 | 35 | public function testGetRandomNumber() { 36 | $crypt = new PasswordLib; 37 | $max = 100; 38 | $min = 0; 39 | $number = $crypt->getRandomNumber($min, $max); 40 | $this->assertGreaterThanOrEqual($min, $number); 41 | $this->assertLessThanOrEqual($max, $number); 42 | } 43 | 44 | public function testGetRandomBytes() { 45 | $crypt = new PasswordLib; 46 | $string = $crypt->getRandomBytes(10); 47 | $this->assertEquals(10, strlen($string)); 48 | } 49 | 50 | public function testGetRandomToken() { 51 | $crypt = new PasswordLib; 52 | $string = $crypt->getRandomToken(10); 53 | $this->assertEquals(10, strlen($string)); 54 | } 55 | 56 | public function testShuffleArray() { 57 | $crypt = new PasswordLib; 58 | $array = array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 59 | $newArray = $crypt->shuffleArray($array); 60 | $this->assertNotEquals($array, array_values($newArray)); 61 | $this->assertEquals($array, $newArray); 62 | } 63 | 64 | public function testShuffleString() { 65 | $crypt = new PasswordLib; 66 | $string = 'abcdefghijklmnopqrstuvwxyz'; 67 | $newString = $crypt->shuffleString($string); 68 | $this->assertNotEquals($string, $newString); 69 | $cnt = count_chars($string, 1); 70 | $cnt2 = count_chars($newString, 1); 71 | $this->assertEquals($cnt, $cnt2); 72 | } 73 | } -------------------------------------------------------------------------------- /test/Data/Vectors/aes-ecb.test-vectors: -------------------------------------------------------------------------------- 1 | Primitive Name: AES 2 | ======================== 3 | Key size: Variable 4 | Block size: 128 bits 5 | 6 | Test vectors -- set 1 7 | ===================== 8 | 9 | Set 1 vector 1 10 | mode=aes-128 11 | key=2b7e151628aed2a6abf7158809cf4f3c 12 | iv= 13 | plain=6bc1bee22e409f96e93d7e117393172a 14 | cipher=3ad77bb40d7a3660a89ecaf32466ef97 15 | 16 | Set 1 vector 2 17 | mode=aes-128 18 | key=2b7e151628aed2a6abf7158809cf4f3c 19 | iv= 20 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 21 | cipher=f5d3d58503b9699de785895a96fdbaaf 22 | 23 | Set 1 vector 3 24 | mode=aes-128 25 | key=2b7e151628aed2a6abf7158809cf4f3c 26 | iv= 27 | plain=30c81c46a35ce411e5fbc1191a0a52ef 28 | cipher=43b1cd7f598ece23881b00e3ed030688 29 | 30 | Set 1 vector 4 31 | mode=aes-128 32 | key=2b7e151628aed2a6abf7158809cf4f3c 33 | iv= 34 | plain=f69f2445df4f9b17ad2b417be66c3710 35 | cipher=7b0c785e27e8ad3f8223207104725dd4 36 | 37 | Set 2 vector 1 38 | mode=aes-192 39 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 40 | iv= 41 | plain=6bc1bee22e409f96e93d7e117393172a 42 | cipher=bd334f1d6e45f25ff712a214571fa5cc 43 | 44 | Set 2 vector 2 45 | mode=aes-192 46 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 47 | iv= 48 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 49 | cipher=974104846d0ad3ad7734ecb3ecee4eef 50 | 51 | Set 2 vector 3 52 | mode=aes-192 53 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 54 | iv= 55 | plain=30c81c46a35ce411e5fbc1191a0a52ef 56 | cipher=ef7afd2270e2e60adce0ba2face6444e 57 | 58 | Set 2 vector 4 59 | mode=aes-192 60 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 61 | iv= 62 | plain=f69f2445df4f9b17ad2b417be66c3710 63 | cipher=9a4b41ba738d6c72fb16691603c18e0e 64 | 65 | Set 3 vector 1 66 | mode=aes-256 67 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 68 | iv= 69 | plain=6bc1bee22e409f96e93d7e117393172a 70 | cipher=f3eed1bdb5d2a03c064b5a7e3db181f8 71 | 72 | Set 3 vector 2 73 | mode=aes-256 74 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 75 | iv= 76 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 77 | cipher=591ccb10d410ed26dc5ba74a31362870 78 | 79 | Set 3 vector 3 80 | mode=aes-256 81 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 82 | iv= 83 | plain=30c81c46a35ce411e5fbc1191a0a52ef 84 | cipher=b6ed21b99ca6f4f9f153e7b1beafed1d 85 | 86 | Set 3 vector 4 87 | mode=aes-256 88 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 89 | iv= 90 | plain=f69f2445df4f9b17ad2b417be66c3710 91 | cipher=23304b7a39f9f3ff067d8d8f9e24ecc7 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /test/Unit/Hash/HashTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($expected, Hash::getHashSize($algo)); 21 | $this->assertEquals($expected * 8, Hash::getHashSizeInBits($algo)); 22 | } 23 | 24 | public function testGetBlockSize() { 25 | $this->assertEquals(2048 / 8, Hash::getBlockSize('test')); 26 | } 27 | 28 | public function testGetBlockSizeDefault() { 29 | $this->assertEquals(0, Hash::getBlockSize('foobarbaz')); 30 | } 31 | 32 | public function testGetBlockSizeInBits() { 33 | $this->assertEquals(2048, Hash::getBlockSizeInBits('test')); 34 | } 35 | 36 | public function testGetBlockSizeInBitsDefault() { 37 | $this->assertEquals(0, Hash::getBlockSizeInBits('foobarbaz')); 38 | } 39 | 40 | public function testGetHashSize() { 41 | $this->assertEquals(4096 / 8, Hash::getHashSize('test')); 42 | } 43 | 44 | public function testGetHashSizeDefault() { 45 | $this->assertEquals(0, Hash::getHashSize('foobarbaz')); 46 | } 47 | 48 | public function testGetHashSizeInBits() { 49 | $this->assertEquals(4096, Hash::getHashSizeInBits('test')); 50 | } 51 | 52 | public function testGetHashSizeInBitsDefault() { 53 | $this->assertEquals(0, Hash::getHashSizeInBits('foobarbaz')); 54 | } 55 | 56 | public function testIsAvailable() { 57 | $this->assertFalse(Hash::isAvailable('test')); 58 | } 59 | 60 | public function testIsSecure() { 61 | $this->assertEquals('yes', Hash::isSecure('test')); 62 | } 63 | 64 | public function testIsSecureDefault() { 65 | $this->assertEquals(false, Hash::isSecure('foobarbaz')); 66 | } 67 | 68 | public function setUp() { 69 | $r = new ReflectionProperty('PasswordLib\\Hash\\Hash', 'hashInfo'); 70 | $r->setAccessible(true); 71 | $prop = $r->getValue(null); 72 | $this->oldHashes = $prop; 73 | $prop['test'] = array( 74 | 'HashSize' => 4096, 75 | 'BlockSize' => 2048, 76 | 'secure' => 'yes', 77 | ); 78 | $r->setValue(null, $prop); 79 | } 80 | 81 | public function tearDown() { 82 | $r = new ReflectionProperty('PasswordLib\\Hash\\Hash', 'hashInfo'); 83 | $r->setAccessible(true); 84 | $r->setValue(null, $this->oldHashes); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /lib/PasswordLib/Core/AutoLoader.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2011 The Authors 12 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 13 | * @version Build @@version@@ 14 | */ 15 | 16 | namespace PasswordLib\Core; 17 | 18 | /** 19 | * An implementation of the PSR-0 Autoloader. This can be replaced at will with 20 | * other implementations if necessary. 21 | * 22 | * @category PHPPasswordLib 23 | * @package Core 24 | * @author Anthony Ferrara 25 | */ 26 | class AutoLoader { 27 | 28 | /** 29 | * @var string The namespace prefix for this instance. 30 | */ 31 | protected $namespace = ''; 32 | 33 | /** 34 | * @var string The filesystem prefix to use for this instance 35 | */ 36 | protected $path = ''; 37 | 38 | /** 39 | * Build the instance of the autoloader 40 | * 41 | * @param string $namespace The prefixed namespace this instance will load 42 | * @param string $path The filesystem path to the root of the namespace 43 | * 44 | * @return void 45 | */ 46 | public function __construct($namespace, $path) { 47 | $this->namespace = ltrim($namespace, '\\'); 48 | $this->path = rtrim($path, '/\\') . DIRECTORY_SEPARATOR; 49 | } 50 | 51 | /** 52 | * Try to load a class 53 | * 54 | * @param string $class The class name to load 55 | * 56 | * @return boolean If the loading was successful 57 | */ 58 | public function load($class) { 59 | $class = ltrim($class, '\\'); 60 | if (strpos($class, $this->namespace) === 0) { 61 | $nsparts = explode('\\', $class); 62 | $class = array_pop($nsparts); 63 | $nsparts[] = ''; 64 | $path = $this->path . implode(DIRECTORY_SEPARATOR, $nsparts); 65 | $path .= str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php'; 66 | if (file_exists($path)) { 67 | require $path; 68 | return true; 69 | } 70 | } 71 | return false; 72 | } 73 | 74 | /** 75 | * Register the autoloader to PHP 76 | * 77 | * @return boolean The status of the registration 78 | */ 79 | public function register() { 80 | return spl_autoload_register(array($this, 'load')); 81 | } 82 | 83 | /** 84 | * Unregister the autoloader to PHP 85 | * 86 | * @return boolean The status of the unregistration 87 | */ 88 | public function unregister() { 89 | return spl_autoload_unregister(array($this, 'load')); 90 | } 91 | 92 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Core/AbstractFactory.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 12 | * @version Build @@version@@ 13 | */ 14 | 15 | namespace PasswordLib\Core; 16 | 17 | /** 18 | * The base abstract factory used by all PasswordLib factories 19 | * 20 | * @category PHPPasswordLib 21 | * @package Core 22 | * @author Anthony Ferrara 23 | */ 24 | abstract class AbstractFactory { 25 | 26 | /** 27 | * Register a type with the factory by name 28 | * 29 | * This is an internal method to check if a provided class name implements 30 | * an interface, and if it does to append that class to an internal array 31 | * by name. 32 | * 33 | * @param string $type The name of the variable to store the class 34 | * @param string $implements The interface to validate against 35 | * @param string $name The name of this particular class 36 | * @param string $class The fully qualified class name 37 | * @param boolean $instantiate Should the class be stored instantiated 38 | * 39 | * @return void 40 | * @throws InvalidArgumentException If class does not implement interface 41 | */ 42 | protected function registerType( 43 | $type, 44 | $implements, 45 | $name, 46 | $class, 47 | $instantiate = false 48 | ) { 49 | $name = strtolower($name); 50 | $refl = new \ReflectionClass($class); 51 | if (!$refl->implementsInterface($implements)) { 52 | $message = sprintf('Class must implement %s', $implements); 53 | throw new \InvalidArgumentException($message); 54 | } 55 | if ($instantiate) { 56 | $class = new $class; 57 | } 58 | 59 | $this->{$type}[$name] = $class; 60 | } 61 | 62 | /** 63 | * Load a set of classes from a directory into the factory 64 | * 65 | * @param string $directory The directory to search for classes in 66 | * @param string $namespace The namespace prefix for any found classes 67 | * @param string $callback The callback with which to register the class 68 | * 69 | * @return void 70 | */ 71 | protected function loadFiles($directory, $namespace, $callback) { 72 | foreach (new \DirectoryIterator($directory) as $file) { 73 | $filename = $file->getBasename(); 74 | if ($file->isFile() && substr($filename, -4) == '.php') { 75 | $name = substr($filename, 0, -4); 76 | $class = $namespace . $name; 77 | call_user_func($callback, $name, $class); 78 | } 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /test/Data/Vectors/aes-ctr.test-vectors: -------------------------------------------------------------------------------- 1 | Primitive Name: AES 2 | ======================== 3 | Key size: Variable 4 | Block size: 128 bits 5 | 6 | Test vectors -- set 1 7 | ===================== 8 | 9 | Set 1 vector 1 10 | mode=aes-128 11 | key=2b7e151628aed2a6abf7158809cf4f3c 12 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 13 | plain=6bc1bee22e409f96e93d7e117393172a 14 | cipher=874d6191b620e3261bef6864990db6ce 15 | 16 | Set 1 vector 2 17 | mode=aes-128 18 | key=2b7e151628aed2a6abf7158809cf4f3c 19 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 20 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 21 | cipher=9806f66b7970fdff8617187bb9fffdff 22 | 23 | Set 1 vector 3 24 | mode=aes-128 25 | key=2b7e151628aed2a6abf7158809cf4f3c 26 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 27 | plain=30c81c46a35ce411e5fbc1191a0a52ef 28 | cipher=5ae4df3edbd5d35e5b4f09020db03eab 29 | 30 | Set 1 vector 4 31 | mode=aes-128 32 | key=2b7e151628aed2a6abf7158809cf4f3c 33 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 34 | plain=f69f2445df4f9b17ad2b417be66c3710 35 | cipher=1e031dda2fbe03d1792170a0f3009cee 36 | 37 | Set 2 vector 1 38 | mode=aes-192 39 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 40 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 41 | plain=6bc1bee22e409f96e93d7e117393172a 42 | cipher=1abc932417521ca24f2b0459fe7e6e0b 43 | 44 | Set 2 vector 2 45 | mode=aes-192 46 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 47 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 48 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 49 | cipher=090339ec0aa6faefd5ccc2c6f4ce8e94 50 | 51 | Set 2 vector 3 52 | mode=aes-192 53 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 54 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 55 | plain=30c81c46a35ce411e5fbc1191a0a52ef 56 | cipher=1e36b26bd1ebc670d1bd1d665620abf7 57 | 58 | Set 2 vector 4 59 | mode=aes-192 60 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 61 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 62 | plain=f69f2445df4f9b17ad2b417be66c3710 63 | cipher=4f78a7f6d29809585a97daec58c6b050 64 | 65 | Set 3 vector 1 66 | mode=aes-256 67 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 68 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 69 | plain=6bc1bee22e409f96e93d7e117393172a 70 | cipher=601ec313775789a5b7a7f504bbf3d228 71 | 72 | Set 3 vector 2 73 | mode=aes-256 74 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 75 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 76 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 77 | cipher=f443e3ca4d62b59aca84e990cacaf5c5 78 | 79 | Set 3 vector 3 80 | mode=aes-256 81 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 82 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 83 | plain=30c81c46a35ce411e5fbc1191a0a52ef 84 | cipher=2b0930daa23de94ce87017ba2d84988d 85 | 86 | Set 3 vector 4 87 | mode=aes-256 88 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 89 | iv=f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff 90 | plain=f69f2445df4f9b17ad2b417be66c3710 91 | cipher=dfc9c58db67aada613c2dd08457941a6 92 | 93 | -------------------------------------------------------------------------------- /test/Data/Vectors/aes-cbc.test-vectors: -------------------------------------------------------------------------------- 1 | Primitive Name: AES 2 | ======================== 3 | Key size: Variable 4 | Block size: 128 bits 5 | 6 | Test vectors -- set 1 7 | ===================== 8 | 9 | Set 1 vector 1 10 | mode=aes-128 11 | key=2b7e151628aed2a6abf7158809cf4f3c 12 | iv=000102030405060708090A0B0C0D0E0F 13 | plain=6bc1bee22e409f96e93d7e117393172a 14 | cipher=7649abac8119b246cee98e9b12e9197d 15 | 16 | Set 1 vector 2 17 | mode=aes-128 18 | key=2b7e151628aed2a6abf7158809cf4f3c 19 | iv=7649ABAC8119B246CEE98E9B12E9197D 20 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 21 | cipher=5086cb9b507219ee95db113a917678b2 22 | 23 | Set 1 vector 3 24 | mode=aes-128 25 | key=2b7e151628aed2a6abf7158809cf4f3c 26 | iv=5086CB9B507219EE95DB113A917678B2 27 | plain=30c81c46a35ce411e5fbc1191a0a52ef 28 | cipher=73bed6b8e3c1743b7116e69e22229516 29 | 30 | Set 1 vector 4 31 | mode=aes-128 32 | key=2b7e151628aed2a6abf7158809cf4f3c 33 | iv=73BED6B8E3C1743B7116E69E22229516 34 | plain=f69f2445df4f9b17ad2b417be66c3710 35 | cipher=3ff1caa1681fac09120eca307586e1a7 36 | 37 | Set 2 vector 1 38 | mode=aes-192 39 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 40 | iv=000102030405060708090A0B0C0D0E0F 41 | plain=6bc1bee22e409f96e93d7e117393172a 42 | cipher=4f021db243bc633d7178183a9fa071e8 43 | 44 | Set 2 vector 2 45 | mode=aes-192 46 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 47 | iv=4F021DB243BC633D7178183A9FA071E8 48 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 49 | cipher=b4d9ada9ad7dedf4e5e738763f69145a 50 | 51 | Set 2 vector 3 52 | mode=aes-192 53 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 54 | iv=B4D9ADA9AD7DEDF4E5E738763F69145A 55 | plain=30c81c46a35ce411e5fbc1191a0a52ef 56 | cipher=571b242012fb7ae07fa9baac3df102e0 57 | 58 | Set 2 vector 4 59 | mode=aes-192 60 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 61 | iv=571B242012FB7AE07FA9BAAC3DF102E0 62 | plain=f69f2445df4f9b17ad2b417be66c3710 63 | cipher=08b0e27988598881d920a9e64f5615cd 64 | 65 | Set 3 vector 1 66 | mode=aes-256 67 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 68 | iv=000102030405060708090A0B0C0D0E0F 69 | plain=6bc1bee22e409f96e93d7e117393172a 70 | cipher=f58c4c04d6e5f1ba779eabfb5f7bfbd6 71 | 72 | Set 3 vector 2 73 | mode=aes-256 74 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 75 | iv=F58C4C04D6E5F1BA779EABFB5F7BFBD6 76 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 77 | cipher=9cfc4e967edb808d679f777bc6702c7d 78 | 79 | Set 3 vector 3 80 | mode=aes-256 81 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 82 | iv=9CFC4E967EDB808D679F777BC6702C7D 83 | plain=30c81c46a35ce411e5fbc1191a0a52ef 84 | cipher=39f23369a9d9bacfa530e26304231461 85 | 86 | Set 3 vector 4 87 | mode=aes-256 88 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 89 | iv=39F23369A9D9BACFA530E26304231461 90 | plain=f69f2445df4f9b17ad2b417be66c3710 91 | cipher=b2eb05e2c39be9fcda6c19078c6a9d1b 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /test/Data/Vectors/aes-cfb.test-vectors: -------------------------------------------------------------------------------- 1 | Primitive Name: AES 2 | ======================== 3 | Key size: Variable 4 | Block size: 128 bits 5 | 6 | Test vectors -- set 1 7 | ===================== 8 | 9 | Set 1 vector 1 10 | mode=aes-128 11 | key=2b7e151628aed2a6abf7158809cf4f3c 12 | iv=000102030405060708090A0B0C0D0E0F 13 | plain=6bc1bee22e409f96e93d7e117393172a 14 | cipher=3b3fd92eb72dad20333449f8e83cfb4a 15 | 16 | Set 1 vector 2 17 | mode=aes-128 18 | key=2b7e151628aed2a6abf7158809cf4f3c 19 | iv=3B3FD92EB72DAD20333449F8E83CFB4A 20 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 21 | cipher=c8a64537a0b3a93fcde3cdad9f1ce58b 22 | 23 | Set 1 vector 3 24 | mode=aes-128 25 | key=2b7e151628aed2a6abf7158809cf4f3c 26 | iv=C8A64537A0B3A93FCDE3CDAD9F1CE58B 27 | plain=30c81c46a35ce411e5fbc1191a0a52ef 28 | cipher=26751f67a3cbb140b1808cf187a4f4df 29 | 30 | Set 1 vector 4 31 | mode=aes-128 32 | key=2b7e151628aed2a6abf7158809cf4f3c 33 | iv=26751F67A3CBB140B1808CF187A4F4DF 34 | plain=f69f2445df4f9b17ad2b417be66c3710 35 | cipher=c04b05357c5d1c0eeac4c66f9ff7f2e6 36 | 37 | Set 2 vector 1 38 | mode=aes-192 39 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 40 | iv=000102030405060708090A0B0C0D0E0F 41 | plain=6bc1bee22e409f96e93d7e117393172a 42 | cipher=cdc80d6fddf18cab34c25909c99a4174 43 | 44 | Set 2 vector 2 45 | mode=aes-192 46 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 47 | iv=CDC80D6FDDF18CAB34C25909C99A4174 48 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 49 | cipher=67ce7f7f81173621961a2b70171d3d7a 50 | 51 | Set 2 vector 3 52 | mode=aes-192 53 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 54 | iv=67CE7F7F81173621961A2B70171D3D7A 55 | plain=30c81c46a35ce411e5fbc1191a0a52ef 56 | cipher=2e1e8a1dd59b88b1c8e60fed1efac4c9 57 | 58 | Set 2 vector 4 59 | mode=aes-192 60 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 61 | iv=2E1E8A1DD59B88B1C8E60FED1EFAC4C9 62 | plain=f69f2445df4f9b17ad2b417be66c3710 63 | cipher=c05f9f9ca9834fa042ae8fba584b09ff 64 | 65 | Set 3 vector 1 66 | mode=aes-256 67 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 68 | iv=000102030405060708090A0B0C0D0E0F 69 | plain=6bc1bee22e409f96e93d7e117393172a 70 | cipher=DC7E84BFDA79164B7ECD8486985D3860 71 | 72 | Set 3 vector 2 73 | mode=aes-256 74 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 75 | iv=DC7E84BFDA79164B7ECD8486985D3860 76 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 77 | cipher=39ffed143b28b1c832113c6331e5407b 78 | 79 | Set 3 vector 3 80 | mode=aes-256 81 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 82 | iv=39FFED143B28B1C832113C6331E5407B 83 | plain=30c81c46a35ce411e5fbc1191a0a52ef 84 | cipher=df10132415e54b92a13ed0a8267ae2f9 85 | 86 | Set 3 vector 4 87 | mode=aes-256 88 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 89 | iv=DF10132415E54B92A13ED0A8267AE2F9 90 | plain=f69f2445df4f9b17ad2b417be66c3710 91 | cipher=75a385741ab9cef82031623d55b1e471 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /test/Data/Vectors/aes-ofb.test-vectors: -------------------------------------------------------------------------------- 1 | Primitive Name: AES 2 | ======================== 3 | Key size: Variable 4 | Block size: 128 bits 5 | 6 | Test vectors -- set 1 7 | ===================== 8 | 9 | Set 1 vector 1 10 | mode=aes-128 11 | key=2b7e151628aed2a6abf7158809cf4f3c 12 | iv=000102030405060708090A0B0C0D0E0F 13 | plain=6bc1bee22e409f96e93d7e117393172a 14 | cipher=3b3fd92eb72dad20333449f8e83cfb4a 15 | 16 | Set 1 vector 2 17 | mode=aes-128 18 | key=2b7e151628aed2a6abf7158809cf4f3c 19 | iv=50FE67CC996D32B6DA0937E99BAFEC60 20 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 21 | cipher=7789508d16918f03f53c52dac54ed825 22 | 23 | Set 1 vector 3 24 | mode=aes-128 25 | key=2b7e151628aed2a6abf7158809cf4f3c 26 | iv=D9A4DADA0892239F6B8B3D7680E15674 27 | plain=30c81c46a35ce411e5fbc1191a0a52ef 28 | cipher=9740051e9c5fecf64344f7a82260edcc 29 | 30 | Set 1 vector 4 31 | mode=aes-128 32 | key=2b7e151628aed2a6abf7158809cf4f3c 33 | iv=A78819583F0308E7A6BF36B1386ABF23 34 | plain=f69f2445df4f9b17ad2b417be66c3710 35 | cipher=304c6528f659c77866a510d9c1d6ae5e 36 | 37 | Set 2 vector 1 38 | mode=aes-192 39 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 40 | iv=000102030405060708090A0B0C0D0E0F 41 | plain=6bc1bee22e409f96e93d7e117393172a 42 | cipher=cdc80d6fddf18cab34c25909c99a4174 43 | 44 | Set 2 vector 2 45 | mode=aes-192 46 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 47 | iv=A609B38DF3B1133DDDFF2718BA09565E 48 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 49 | cipher=fcc28b8d4c63837c09e81700c1100401 50 | 51 | Set 2 vector 3 52 | mode=aes-192 53 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 54 | iv=52EF01DA52602FE0975F78AC84BF8A50 55 | plain=30c81c46a35ce411e5fbc1191a0a52ef 56 | cipher=8d9a9aeac0f6596f559c6d4daf59a5f2 57 | 58 | Set 2 vector 4 59 | mode=aes-192 60 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 61 | iv=BD5286AC63AABD7EB067AC54B553F71D 62 | plain=f69f2445df4f9b17ad2b417be66c3710 63 | cipher=6d9f200857ca6c3e9cac524bd9acc92a 64 | 65 | Set 3 vector 1 66 | mode=aes-256 67 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 68 | iv=000102030405060708090A0B0C0D0E0F 69 | plain=6bc1bee22e409f96e93d7e117393172a 70 | cipher=dc7e84bfda79164b7ecd8486985d3860 71 | 72 | Set 3 vector 2 73 | mode=aes-256 74 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 75 | iv=B7BF3A5DF43989DD97F0FA97EBCE2F4A 76 | plain=ae2d8a571e03ac9c9eb76fac45af8e51 77 | cipher=4febdc6740d20b3ac88f6ad82a4fb08d 78 | 79 | Set 3 vector 3 80 | mode=aes-256 81 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 82 | iv=E1C656305ED1A7A6563805746FE03EDC 83 | plain=30c81c46a35ce411e5fbc1191a0a52ef 84 | cipher=71ab47a086e86eedf39d1c5bba97c408 85 | 86 | Set 3 vector 4 87 | mode=aes-256 88 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 89 | iv=41635BE625B48AFC1666DD42A09D96E7 90 | plain=f69f2445df4f9b17ad2b417be66c3710 91 | cipher=0126141d67f37be8538f5a8be740e484 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/SHA256.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2011 The Authors 14 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLib\Password\Implementation; 19 | 20 | use PasswordLib\Random\Factory as RandomFactory; 21 | 22 | /** 23 | * The Blowfish password hashing implementation 24 | * 25 | * Use this class to generate and validate Blowfish password hashes. 26 | * 27 | * @category PHPPasswordLib 28 | * @package Password 29 | * @subpackage Implementation 30 | * @author Anthony Ferrara 31 | */ 32 | class SHA256 extends Crypt { 33 | 34 | protected static $prefix = '$5$'; 35 | 36 | protected $defaultOptions = array( 37 | 'rounds' => 5000, 38 | ); 39 | 40 | protected $saltLen = 16; 41 | 42 | /** 43 | * Load an instance of the class based upon the supplied hash 44 | * 45 | * @param string $hash The hash to load from 46 | * 47 | * @return Password the created instance 48 | * @throws InvalidArgumentException if the hash wasn't created here 49 | */ 50 | public static function loadFromHash($hash) { 51 | if (!static::detect($hash)) { 52 | throw new \InvalidArgumentException('Hash Not Created Here'); 53 | } 54 | if (!sscanf($hash, '$5$rounds=%d$', $rounds)) { 55 | $rounds = 5000; 56 | } 57 | return new static(array('rounds' => $rounds)); 58 | } 59 | 60 | /** 61 | * Determine if the hash was made with this method 62 | * 63 | * @param string $hash The hashed data to check 64 | * 65 | * @return boolean Was the hash created by this method 66 | */ 67 | public static function detect($hash) { 68 | $regex = '#^\$5\$(rounds=\d{4,9}\$)?[a-zA-Z0-9./]{16}\$[a-zA-Z0-9./]{43}$#'; 69 | return 1 == preg_match($regex, $hash); 70 | } 71 | 72 | /** 73 | * Set an option for the instance 74 | * 75 | * @param string $option The option to set 76 | * @param mixed $value The value to set the option to 77 | * 78 | * @return $this 79 | */ 80 | public function setOption($option, $value) { 81 | if ($option == 'rounds') { 82 | if ($value < 1000 || $value > 999999999) { 83 | throw new \InvalidArgumentException( 84 | 'Invalid cost parameter specified, ' . 85 | 'must be between 1000 and 999999999' 86 | ); 87 | } 88 | } 89 | $this->options[$option] = $value; 90 | return $this; 91 | } 92 | 93 | protected function generateSalt() { 94 | $salt = parent::generateSalt(); 95 | return '$5$rounds=' . $this->options['rounds'] . '$' . $salt; 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/SHA512.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2011 The Authors 14 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLib\Password\Implementation; 19 | 20 | use PasswordLib\Random\Factory as RandomFactory; 21 | 22 | /** 23 | * The Blowfish password hashing implementation 24 | * 25 | * Use this class to generate and validate Blowfish password hashes. 26 | * 27 | * @category PHPPasswordLib 28 | * @package Password 29 | * @subpackage Implementation 30 | * @author Anthony Ferrara 31 | */ 32 | class SHA512 extends Crypt { 33 | 34 | protected static $prefix = '$6$'; 35 | 36 | protected $defaultOptions = array( 37 | 'rounds' => 5000, 38 | ); 39 | 40 | protected $saltLen = 16; 41 | 42 | /** 43 | * Load an instance of the class based upon the supplied hash 44 | * 45 | * @param string $hash The hash to load from 46 | * 47 | * @return Password the created instance 48 | * @throws InvalidArgumentException if the hash wasn't created here 49 | */ 50 | public static function loadFromHash($hash) { 51 | if (!static::detect($hash)) { 52 | throw new \InvalidArgumentException('Hash Not Created Here'); 53 | } 54 | if (!sscanf($hash, '$6$rounds=%d$', $rounds)) { 55 | $rounds = 5000; 56 | } 57 | return new static(array('rounds' => $rounds)); 58 | } 59 | 60 | /** 61 | * Determine if the hash was made with this method 62 | * 63 | * @param string $hash The hashed data to check 64 | * 65 | * @return boolean Was the hash created by this method 66 | */ 67 | public static function detect($hash) { 68 | $regex = '#^\$6\$(rounds=\d{4,9}\$)?[a-zA-Z0-9./]{16}\$[a-zA-Z0-9./]{86}$#'; 69 | return 1 == preg_match($regex, $hash); 70 | } 71 | 72 | /** 73 | * Set an option for the instance 74 | * 75 | * @param string $option The option to set 76 | * @param mixed $value The value to set the option to 77 | * 78 | * @return $this 79 | */ 80 | public function setOption($option, $value) { 81 | if ($option == 'rounds') { 82 | if ($value < 1000 || $value > 999999999) { 83 | throw new \InvalidArgumentException( 84 | 'Invalid cost parameter specified, ' . 85 | 'must be between 1000 and 999999999' 86 | ); 87 | } 88 | } 89 | $this->options[$option] = $value; 90 | return $this; 91 | } 92 | 93 | protected function generateSalt() { 94 | $salt = parent::generateSalt(); 95 | return '$6$rounds=' . $this->options['rounds'] . '$' . $salt; 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /test/Data/Vectors/cmac-aes.sp-800-38b.test-vectors: -------------------------------------------------------------------------------- 1 | Primitive Name: AES 2 | ======================== 3 | Key size: 128 bits 4 | Block size: 128 bits 5 | 6 | Test vectors -- set 1 7 | ===================== 8 | 9 | Set 1 vector 1 10 | mode=aes-128 11 | key=2b7e151628aed2a6abf7158809cf4f3c 12 | plain= 13 | tlen=16 14 | mac=bb1d6929e95937287fa37d129b756746 15 | 16 | Set 1 vector 2 17 | mode=aes-128 18 | key=2b7e151628aed2a6abf7158809cf4f3c 19 | plain=6bc1bee22e409f96e93d7e117393172a 20 | tlen=16 21 | mac=070a16b46b4d4144f79bdd9dd04a287c 22 | 23 | Set 1 vector 3 24 | mode=aes-128 25 | key=2b7e151628aed2a6abf7158809cf4f3c 26 | plain=6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411 27 | tlen=16 28 | mac=dfa66747de9ae63030ca32611497c827 29 | 30 | Set 1 vector 4 31 | mode=aes-128 32 | key=2b7e151628aed2a6abf7158809cf4f3c 33 | plain=6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710 34 | tlen=16 35 | mac=51f0bebf7e3b9d92fc49741779363cfe 36 | 37 | Set 2 vector 1 38 | mode=aes-192 39 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 40 | plain= 41 | tlen=16 42 | mac=d17ddf46adaacde531cac483de7a9367 43 | 44 | Set 2 vector 2 45 | mode=aes-192 46 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 47 | plain=6bc1bee22e409f96e93d7e117393172a 48 | tlen=16 49 | mac=9e99a7bf31e710900662f65e617c5184 50 | 51 | Set 2 vector 3 52 | mode=aes-192 53 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 54 | plain=6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411 55 | tlen=16 56 | mac=8a1de5be2eb31aad089a82e6ee908b0e 57 | 58 | Set 2 vector 4 59 | mode=aes-192 60 | key=8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b 61 | plain=6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710 62 | tlen=16 63 | mac=a1d5df0eed790f794d77589659f39a11 64 | 65 | Set 3 vector 1 66 | mode=aes-256 67 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 68 | plain= 69 | tlen=16 70 | mac=028962f61b7bf89efc6b551f4667d983 71 | 72 | Set 3 vector 2 73 | mode=aes-256 74 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 75 | plain=6bc1bee22e409f96e93d7e117393172a 76 | tlen=16 77 | mac=28a7023f452e8f82bd4bf28d8c37c35c 78 | 79 | Set 3 vector 3 80 | mode=aes-256 81 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 82 | plain=6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411 83 | tlen=16 84 | mac=aaf3d8f1de5640c232f5b169b9c911e6 85 | 86 | Set 3 vector 4 87 | mode=aes-256 88 | key=603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 89 | plain=6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710 90 | tlen=16 91 | mac=e1992190549f6ed5696a2c056c315410 92 | 93 | 94 | -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Mixer/Hash.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2011 The Authors 16 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 17 | * @version Build @@version@@ 18 | */ 19 | 20 | namespace PasswordLib\Random\Mixer; 21 | 22 | use \PasswordLib\Core\Strength; 23 | 24 | /** 25 | * The Hash medium strength mixer class 26 | * 27 | * This class implements a mixer based upon the recommendations in RFC 4086 28 | * section 5.2 29 | * 30 | * @see http://tools.ietf.org/html/rfc4086#section-5.2 31 | * @category PHPPasswordLib 32 | * @package Random 33 | * @subpackage Mixer 34 | * @author Anthony Ferrara 35 | */ 36 | class Hash extends \PasswordLib\Random\AbstractMixer { 37 | 38 | /** 39 | * @var string The hash instance to use 40 | */ 41 | protected $hash = null; 42 | 43 | /** 44 | * Build the hash mixer 45 | * 46 | * @param string $hash The hash instance to use (defaults to sha512) 47 | * 48 | * @return void 49 | */ 50 | public function __construct($hash = 'sha512') { 51 | $this->hash = $hash; 52 | } 53 | 54 | /** 55 | * Return an instance of Strength indicating the strength of the source 56 | * 57 | * @return Strength An instance of one of the strength classes 58 | */ 59 | public static function getStrength() { 60 | return new Strength(Strength::MEDIUM); 61 | } 62 | 63 | /** 64 | * Test to see if the mixer is available 65 | * 66 | * @return boolean If the mixer is available on the system 67 | */ 68 | public static function test() { 69 | return true; 70 | } 71 | 72 | /** 73 | * Get the block size (the size of the individual blocks used for the mixing) 74 | * 75 | * @return int The block size 76 | */ 77 | protected function getPartSize() { 78 | return strlen(hash($this->hash, '', true)); 79 | } 80 | 81 | /** 82 | * Mix 2 parts together using one method 83 | * 84 | * @param string $part1 The first part to mix 85 | * @param string $part2 The second part to mix 86 | * 87 | * @return string The mixed data 88 | */ 89 | protected function mixParts1($part1, $part2) { 90 | return hash_hmac($this->hash, $part1, $part2, true); 91 | } 92 | 93 | /** 94 | * Mix 2 parts together using another different method 95 | * 96 | * @param string $part1 The first part to mix 97 | * @param string $part2 The second part to mix 98 | * 99 | * @return string The mixed data 100 | */ 101 | protected function mixParts2($part1, $part2) { 102 | return hash_hmac($this->hash, $part2, $part1, true); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /lib/PasswordLib/Key/Factory.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 12 | * @version Build @@version@@ 13 | */ 14 | 15 | namespace PasswordLib\Key; 16 | 17 | /** 18 | * The core Key Factory 19 | * 20 | * @category PHPPasswordLib 21 | * @package Key 22 | * @author Anthony Ferrara 23 | */ 24 | class Factory extends \PasswordLib\Core\AbstractFactory { 25 | 26 | /** 27 | * @var array An array of KDF class implementations 28 | */ 29 | protected $kdf = array(); 30 | 31 | /** 32 | * @var array An array of PBKDF class implementations 33 | */ 34 | protected $pbkdf = array(); 35 | 36 | /** 37 | * @var array An array of symmetric key generator implementations 38 | */ 39 | protected $symmetricGenerators = array(); 40 | 41 | /** 42 | * Construct the instance, loading the core implementations 43 | * 44 | * @return void 45 | */ 46 | public function __construct() { 47 | $this->loadPBKDF(); 48 | } 49 | 50 | public function getKDF($name = 'kdf3', array $options = array()) { 51 | if (isset($this->kdf[$name])) { 52 | $class = $this->kdf[$name]; 53 | return new $class($options); 54 | } 55 | throw new \InvalidArgumentException('Unsupported KDF'); 56 | } 57 | 58 | public function getPBKDF($name = 'pbkdf2', array $options = array()) { 59 | if (isset($this->pbkdf[$name])) { 60 | $class = $this->pbkdf[$name]; 61 | return new $class($options); 62 | } 63 | throw new \InvalidArgumentException('Unsupported PBKDF'); 64 | } 65 | 66 | public function getPBKDFFromSignature($signature) { 67 | list ($name, $hash) = explode('-', $signature, 2); 68 | return $this->getPBKDF($name, array('hash' => $hash)); 69 | } 70 | 71 | public function getSymmetricKeyGenerator() { 72 | } 73 | 74 | public function registerKDF($name, $class) { 75 | $this->registerType( 76 | 'kdf', 77 | __NAMESPACE__ . '\\Derivation\\KDF', 78 | $name, 79 | $class 80 | ); 81 | } 82 | 83 | public function registerPBKDF($name, $class) { 84 | $this->registerType( 85 | 'pbkdf', 86 | __NAMESPACE__ . '\\Derivation\\PBKDF', 87 | $name, 88 | $class 89 | ); 90 | } 91 | 92 | protected function loadKDF() { 93 | $this->loadFiles( 94 | __DIR__ . '/Derivation/KDF', 95 | __NAMESPACE__ . '\\Derivation\\KDF\\', 96 | array($this, 'registerKDF') 97 | ); 98 | } 99 | 100 | protected function loadPBKDF() { 101 | $this->loadFiles( 102 | __DIR__ . '/Derivation/PBKDF', 103 | __NAMESPACE__ . '\\Derivation\\PBKDF\\', 104 | array($this, 'registerPBKDF') 105 | ); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /lib/PasswordLib/Random/Source/MicroTime.php: -------------------------------------------------------------------------------- 1 | 15 | * @copyright 2011 The Authors 16 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 17 | * @version Build @@version@@ 18 | */ 19 | 20 | namespace PasswordLib\Random\Source; 21 | 22 | use PasswordLib\Core\Strength; 23 | 24 | /** 25 | * The Microtime Random Number Source 26 | * 27 | * This uses the current micro-second (looped several times) for a **very** weak 28 | * random number source. This is only useful when combined with several other 29 | * stronger sources 30 | * 31 | * @category PHPPasswordLib 32 | * @package Random 33 | * @subpackage Source 34 | * @author Anthony Ferrara 35 | * @codeCoverageIgnore 36 | */ 37 | class MicroTime implements \PasswordLib\Random\Source { 38 | 39 | private $state = null; 40 | 41 | /** 42 | * Return an instance of Strength indicating the strength of the source 43 | * 44 | * @return Strength An instance of one of the strength classes 45 | */ 46 | public static function getStrength() { 47 | return new Strength(Strength::VERYLOW); 48 | } 49 | 50 | public function __construct() { 51 | $state = ''; 52 | if (function_exists('posix_times')) { 53 | $state .= serialize(posix_times()); 54 | } 55 | $state .= getmypid() . memory_get_usage(); 56 | $state .= serialize($_ENV); 57 | $this->state = hash('sha512', $state, true); 58 | } 59 | 60 | /** 61 | * Generate a random string of the specified size 62 | * 63 | * @param int $size The size of the requested random string 64 | * 65 | * @return string A string of the requested size 66 | */ 67 | public function generate($size) { 68 | $result = ''; 69 | $seed = microtime() . memory_get_usage(); 70 | $this->state = hash('sha512', $this->state . $seed, true); 71 | /** 72 | * Make the generated randomness a bit better by forcing a GC run which 73 | * should complete in a indeterminate amount of time, hence improving 74 | * the strength of the randomness a bit. It's still not crypto-safe, 75 | * but at least it's more difficult to predict. 76 | */ 77 | gc_collect_cycles(); 78 | for ($i = 0; $i < $size; $i += 8) { 79 | $seed = $this->state . microtime() . pack('N', $i); 80 | $this->state = hash('sha512', $seed, true); 81 | /** 82 | * We only use the first 8 bytes here to prevent exposing the state 83 | * in its entirety, which could potentially expose other random 84 | * generations in the future (in the same process)... 85 | */ 86 | $result .= substr($this->state, 0, 8); 87 | } 88 | return substr($result, 0, $size); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /test/Mocks/Cipher/Block/Cipher.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2011 The Authors 12 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 13 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 14 | */ 15 | 16 | namespace PasswordLibTest\Mocks\Cipher\Block; 17 | 18 | /** 19 | * The interface that all block ciphers must implement 20 | * 21 | * @category PHPPasswordLib 22 | * @package Cipher 23 | * @subpackage Block 24 | * @author Anthony Ferrara 25 | */ 26 | class Cipher extends \PasswordLibTest\Mocks\AbstractMock implements \PasswordLib\Cipher\Block\Cipher { 27 | 28 | public static $ciphers = array(); 29 | 30 | public static function init() { 31 | static::$ciphers = array(); 32 | } 33 | 34 | 35 | /** 36 | * Get a list of supported ciphers by this cipher 37 | * 38 | * @return array An array of supported cipher names (strings) 39 | */ 40 | public static function getSupportedCiphers() { 41 | return static::$ciphers; 42 | } 43 | 44 | /** 45 | * Decrypt a block of data using the supplied string key 46 | * 47 | * Note that the supplied data should be the same size as the block size of 48 | * the cipher being used. 49 | * 50 | * @param string $data The data to decrypt 51 | * @param string $key The key to decrypt with 52 | * 53 | * @return string The result decrypted data 54 | */ 55 | public function decryptBlock($data) { 56 | return $this->__call('decryptBlock', array($data)); 57 | } 58 | 59 | /** 60 | * Encrypt a block of data using the supplied string key 61 | * 62 | * Note that the supplied data should be the same size as the block size of 63 | * the cipher being used. 64 | * 65 | * @param string $data The data to encrypt 66 | * @param string $key The key to encrypt with 67 | * 68 | * @return string The result encrypted data 69 | */ 70 | public function encryptBlock($data) { 71 | return $this->__call('encryptBlock', array($data)); 72 | } 73 | 74 | 75 | public function setKey($key) { 76 | return $this->__call('setKey', array($key)); 77 | } 78 | 79 | /** 80 | * Get the block size for the current initialized cipher 81 | * 82 | * @param string $key The key the data will be encrypted with 83 | * 84 | * @return int The block size for the current cipher 85 | */ 86 | public function getBlockSize() { 87 | return $this->__call('getBlockSize', array()); 88 | } 89 | 90 | /** 91 | * Get the string name of the current cipher instance 92 | * 93 | * @return string The current instantiated cipher 94 | */ 95 | public function getCipher() { 96 | return $this->__call('getCipher', array()); 97 | } 98 | 99 | /** 100 | * Get the block size for the current initialized cipher 101 | * 102 | * @return int The block size for the current cipher 103 | */ 104 | public function getKeySize() { 105 | return $this->__call('getKeySize', array()); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/Blowfish.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2011 The Authors 14 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLib\Password\Implementation; 19 | 20 | use PasswordLib\Random\Factory as RandomFactory; 21 | 22 | /** 23 | * The Blowfish password hashing implementation 24 | * 25 | * Use this class to generate and validate Blowfish password hashes. 26 | * 27 | * @category PHPPasswordLib 28 | * @package Password 29 | * @subpackage Implementation 30 | * @author Anthony Ferrara 31 | */ 32 | class Blowfish extends Crypt { 33 | 34 | protected static $prefix = '$2a$'; 35 | 36 | protected $saltLen = 22; 37 | 38 | protected $defaultOptions = array( 39 | 'cost' => 10, 40 | ); 41 | 42 | /** 43 | * Return the prefix used by this hashing method 44 | * 45 | * @return string The prefix used 46 | */ 47 | public static function getPrefix() { 48 | if (version_compare(PHP_VERSION, '5.3.7') >= 0) { 49 | return '$2y$'; 50 | } else { 51 | return '$2a$'; 52 | } 53 | } 54 | 55 | /** 56 | * Determine if the hash was made with this method 57 | * 58 | * @param string $hash The hashed data to check 59 | * 60 | * @return boolean Was the hash created by this method 61 | */ 62 | public static function detect($hash) { 63 | static $regex = '/^\$2[ay]\$(0[4-9]|[1-2][0-9]|3[0-1])\$[a-zA-Z0-9.\/]{53}/'; 64 | return 1 == preg_match($regex, $hash); 65 | } 66 | 67 | /** 68 | * Load an instance of the class based upon the supplied hash 69 | * 70 | * @param string $hash The hash to load from 71 | * 72 | * @return Password the created instance 73 | * @throws InvalidArgumentException if the hash wasn't created here 74 | */ 75 | public static function loadFromHash($hash) { 76 | if (!static::detect($hash)) { 77 | throw new \InvalidArgumentException('Hash Not Created Here'); 78 | } 79 | list(, , $iterations) = explode('$', $hash, 4); 80 | return new static(array('cost' => $iterations)); 81 | } 82 | 83 | /** 84 | * Set an option for the instance 85 | * 86 | * @param string $option The option to set 87 | * @param mixed $value The value to set the option to 88 | * 89 | * @return $this 90 | */ 91 | public function setOption($option, $value) { 92 | if ($option == 'cost') { 93 | if ($value < 4 || $value > 31) { 94 | throw new \InvalidArgumentException( 95 | 'Invalid cost parameter specified, must be between 4 and 31' 96 | ); 97 | } 98 | } 99 | $this->options[$option] = $value; 100 | return $this; 101 | } 102 | 103 | protected function generateSalt() { 104 | $salt = parent::generateSalt(); 105 | $prefix = static::getPrefix(); 106 | $prefix .= str_pad($this->options['cost'], 2, '0', STR_PAD_LEFT); 107 | return $prefix . '$' . $salt; 108 | } 109 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/Joomla.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2011 The Authors 15 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 16 | * @version Build @@version@@ 17 | */ 18 | 19 | namespace PasswordLib\Password\Implementation; 20 | 21 | use PasswordLib\Random\Factory as RandomFactory; 22 | 23 | /** 24 | * The Joomla based hash implementation based off of the md5-hex hash method 25 | * 26 | * It's worth noting, since there's no prefix, you cannot create a hash using 27 | * the factory method. 28 | * 29 | * @category PHPPasswordLib 30 | * @package Password 31 | * @subpackage Implementation 32 | * @author Anthony Ferrara 33 | */ 34 | class Joomla extends \PasswordLib\Password\AbstractPassword { 35 | 36 | /** 37 | * @var Generator The random generator to use for seeds 38 | */ 39 | protected $generator = null; 40 | 41 | /** 42 | * Determine if the hash was made with this method 43 | * 44 | * @param string $hash The hashed data to check 45 | * 46 | * @return boolean Was the hash created by this method 47 | */ 48 | public static function detect($hash) { 49 | return (boolean) preg_match('/^[a-fA-F0-9]{32}:[a-zA-z0-9]{32}$/', $hash); 50 | } 51 | 52 | /** 53 | * Load an instance of the class based upon the supplied hash 54 | * 55 | * @param string $hash The hash to load from 56 | * 57 | * @return Password the created instance 58 | * @throws InvalidArgumentException if the hash wasn't created here 59 | */ 60 | public static function loadFromHash($hash) { 61 | if (!static::detect($hash)) { 62 | throw new \InvalidArgumentException('Hash Not Created Here'); 63 | } 64 | return new static(); 65 | } 66 | 67 | /** 68 | * Create a password hash for a given plain text password 69 | * 70 | * @param string $password The password to hash 71 | * 72 | * @return string The formatted password hash 73 | */ 74 | public function create($password) { 75 | $password = $this->checkPassword($password); 76 | $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' 77 | . '0123456789'; 78 | $salt = $this->generator->generateString(32, $chars); 79 | $hash = md5($password . $salt); 80 | return $hash . ':' . $salt; 81 | } 82 | 83 | /** 84 | * Verify a password hash against a given plain text password 85 | * 86 | * @param string $password The password to hash 87 | * @param string $hash The supplied ahsh to validate 88 | * 89 | * @return boolean Does the password validate against the hash 90 | */ 91 | public function verify($password, $hash) { 92 | $password = $this->checkPassword($password); 93 | if (!static::detect($hash)) { 94 | throw new \InvalidArgumentException( 95 | 'The hash was not created here, we cannot verify it' 96 | ); 97 | } 98 | list ($hash, $salt) = explode(':', $hash, 2); 99 | $test = md5($password . $salt); 100 | return $this->compareStrings($test, $hash); 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/Hash.php: -------------------------------------------------------------------------------- 1 | 14 | * @copyright 2011 The Authors 15 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 16 | * @version Build @@version@@ 17 | */ 18 | 19 | namespace PasswordLib\Password\Implementation; 20 | 21 | use PasswordLib\Random\Factory as RandomFactory; 22 | 23 | /** 24 | * The basic Hash implementation. 25 | * 26 | * It's worth noting, since there's no prefix, you cannot create a hash using 27 | * the factory method. 28 | * 29 | * @category PHPPasswordLib 30 | * @package Password 31 | * @subpackage Implementation 32 | * @author Anthony Ferrara 33 | */ 34 | class Hash extends \PasswordLib\Password\AbstractPassword { 35 | 36 | /** 37 | * @var Hash The hash function to use (MD5) 38 | */ 39 | protected $defaultOptions = array( 40 | 'hash' => 'sha512', 41 | ); 42 | 43 | /** 44 | * Determine if the hash was made with this method 45 | * 46 | * @param string $hash The hashed data to check 47 | * 48 | * @return boolean Was the hash created by this method 49 | */ 50 | public static function detect($hash) { 51 | $res = preg_match('/^[a-fA-F0-9]+$/', $hash); 52 | $res &= (int) in_array(strlen($hash), array(32, 40, 64, 128)); 53 | return (boolean) $res; 54 | } 55 | 56 | /** 57 | * Load an instance of the class based upon the supplied hash 58 | * 59 | * @param string $hash The hash to load from 60 | * 61 | * @return Password the created instance 62 | * @throws InvalidArgumentException if the hash wasn't created here 63 | */ 64 | public static function loadFromHash($hash) { 65 | if (!static::detect($hash)) { 66 | throw new \InvalidArgumentException('Hash Not Created Here'); 67 | } 68 | $hashMethod = ''; 69 | switch (strlen($hash)) { 70 | case 32: 71 | $hashMethod = 'md5'; 72 | break; 73 | case 40: 74 | $hashMethod = 'sha1'; 75 | break; 76 | case 64: 77 | $hashMethod = 'sha256'; 78 | break; 79 | case 128: 80 | $hashMethod = 'sha512'; 81 | break; 82 | } 83 | return new static(array('hash' => $hashMethod)); 84 | } 85 | 86 | /** 87 | * Create a password hash for a given plain text password 88 | * 89 | * @param string $password The password to hash 90 | * 91 | * @return string The formatted password hash 92 | */ 93 | public function create($password) { 94 | throw new \BadMethodCallException( 95 | 'Unsalted Passwords are only implemented for verification' 96 | ); 97 | } 98 | 99 | /** 100 | * Verify a password hash against a given plain text password 101 | * 102 | * @param string $password The password to hash 103 | * @param string $hash The supplied ahsh to validate 104 | * 105 | * @return boolean Does the password validate against the hash 106 | */ 107 | public function verify($password, $hash) { 108 | $password = $this->checkPassword($password); 109 | $test = hash($this->options['hash'], $password); 110 | return $this->compareStrings($test, $hash); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /lib/PasswordLib/Core/Enum.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 12 | * @version Build @@version@@ 13 | */ 14 | namespace PasswordLib\Core; 15 | 16 | use \ReflectionObject; 17 | 18 | /** 19 | * The Enum base class for Enum functionality 20 | * 21 | * This is based off of the SplEnum class implementation (which is only available 22 | * as a PECL extension in 5.3) 23 | * 24 | * @see http://www.php.net/manual/en/class.splenum.php 25 | * @category PHPPasswordLib 26 | * @package Core 27 | * @author Anthony Ferrara 28 | */ 29 | abstract class Enum { 30 | 31 | /** 32 | * A default value of null is provided. Override this to set your own default 33 | */ 34 | const __DEFAULT = null; 35 | 36 | /** 37 | * @var string The name of the constant this instance is using 38 | */ 39 | protected $name = ''; 40 | 41 | /** 42 | * @var scalar The value of the constant this instance is using. 43 | */ 44 | protected $value = ''; 45 | 46 | /** 47 | * Creates a new value of the Enum type 48 | * 49 | * @param mixed $value The value this instance represents 50 | * @param boolean $strict Not Implemented at this time 51 | * 52 | * @return void 53 | * @throws UnexpectedValueException If the value is not a constant 54 | */ 55 | public function __construct($value = null, $strict = false) { 56 | if (is_null($value)) { 57 | $value = static::__DEFAULT; 58 | } 59 | $validValues = $this->getConstList(); 60 | $this->name = array_search($value, $validValues); 61 | if (!$this->name) { 62 | throw new \UnexpectedValueException( 63 | 'Value not a const in enum ' . get_class($this) 64 | ); 65 | } 66 | $this->value = $value; 67 | } 68 | 69 | /** 70 | * Cast the current object to a string and return its value 71 | * 72 | * @return mixed the current value of the instance 73 | */ 74 | public function __toString() { 75 | return (string) $this->value; 76 | } 77 | 78 | /** 79 | * Compare two enums using numeric comparison 80 | * 81 | * @param Enum $arg The enum to compare this instance to 82 | * 83 | * @return int 0 if same, 1 if the argument is greater, -1 else 84 | */ 85 | public function compare(Enum $arg) { 86 | if ($this->value == $arg->value) { 87 | return 0; 88 | } elseif ($this->value > $arg->value) { 89 | return -1; 90 | } else { 91 | return 1; 92 | } 93 | } 94 | 95 | /** 96 | * Returns all constants (including values) as an associative array 97 | * 98 | * @param boolean $include_default Include the __default magic value? 99 | * 100 | * @return array All of the constants found against this instance 101 | */ 102 | public function getConstList($include_default = false) { 103 | static $constCache = array(); 104 | $class = get_class($this); 105 | if (!isset($constCache[$class])) { 106 | $reflector = new ReflectionObject($this); 107 | $constCache[$class] = $reflector->getConstants(); 108 | } 109 | if (!$include_default) { 110 | $constants = $constCache[$class]; 111 | unset($constants['__DEFAULT']); 112 | return $constants; 113 | } 114 | return $constCache[$class]; 115 | } 116 | 117 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Factory.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 12 | * @version Build @@version@@ 13 | */ 14 | 15 | namespace PasswordLib\Password; 16 | 17 | use PasswordLib\Password\Implementation\Blowfish; 18 | 19 | /** 20 | * The Password Factory 21 | * 22 | * @category PHPPasswordLib 23 | * @package Password 24 | * @author Anthony Ferrara 25 | */ 26 | class Factory extends \PasswordLib\Core\AbstractFactory { 27 | 28 | /** 29 | * @var array An array of implementation classes 30 | */ 31 | protected $implementations = array(); 32 | 33 | /** 34 | * Build a new instance of the factory, loading core implementations 35 | * 36 | * @return void 37 | */ 38 | public function __construct() { 39 | $this->loadImplementations(); 40 | } 41 | 42 | /** 43 | * Create a new password hash from the supplied password 44 | * 45 | * This defaults to using Blowfish if $prefix is not supplied 46 | * 47 | * @param string $password The password to hash 48 | * @param string $prefix The prefix for the implementation 49 | * 50 | * @return string The hashed password 51 | * @throws DomainException if the supplied prefix is not supported 52 | */ 53 | public function createHash( 54 | $password, 55 | $prefix = '$2a$', 56 | array $options = array() 57 | ) { 58 | if ($prefix === false) { 59 | throw new \DomainException('Unsupported Prefix Supplied'); 60 | } 61 | foreach ($this->implementations as $impl) { 62 | if ($impl::getPrefix() == $prefix) { 63 | $instance = new $impl($options); 64 | return $instance->create($password); 65 | } 66 | } 67 | throw new \DomainException('Unsupported Prefix Supplied'); 68 | } 69 | 70 | /** 71 | * Verify a hash with a supplied password 72 | * 73 | * @param string $password The password to check against 74 | * @param string $hash The hash to verify 75 | * 76 | * @return boolean True if valid, false if not 77 | * @throws DomainException if the supplied prefix is not supported 78 | */ 79 | public function verifyHash($password, $hash) { 80 | foreach ($this->implementations as $impl) { 81 | if ($impl::detect($hash)) { 82 | $instance = $impl::loadFromHash($hash); 83 | return $instance->verify($password, $hash); 84 | } 85 | } 86 | throw new \DomainException('Unsupported Password Hash Supplied'); 87 | } 88 | 89 | /** 90 | * Register a password implementation for this factory instance 91 | * 92 | * @param string $name The name of the stategy 93 | * @param string $class The class name of the implementation 94 | * 95 | * @return Factory $this The current factory instance 96 | */ 97 | public function registerImplementation($name, $class) { 98 | $this->registerType( 99 | 'implementations', 100 | __NAMESPACE__ . '\\Password', 101 | $name, 102 | $class 103 | ); 104 | return $this; 105 | } 106 | 107 | /** 108 | * Load all core password hashing implementations 109 | * 110 | * @return void 111 | */ 112 | protected function loadImplementations() { 113 | $this->loadFiles( 114 | __DIR__ . '/Implementation', 115 | __NAMESPACE__ . '\\Implementation\\', 116 | array($this, 'registerImplementation') 117 | ); 118 | } 119 | 120 | } -------------------------------------------------------------------------------- /lib/PasswordLib/Random/AbstractMixer.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 12 | * @version Build @@version@@ 13 | */ 14 | 15 | namespace PasswordLib\Random; 16 | 17 | /** 18 | * An abstract mixer to implement a common mixing strategy 19 | * 20 | * @see http://tools.ietf.org/html/rfc4086#section-5.2 21 | * @category PHPPasswordLib 22 | * @package Random 23 | * @author Anthony Ferrara 24 | */ 25 | abstract class AbstractMixer implements \PasswordLib\Random\Mixer { 26 | 27 | /** 28 | * Get the block size (the size of the individual blocks used for the mixing) 29 | * 30 | * @return int The block size 31 | */ 32 | abstract protected function getPartSize(); 33 | 34 | /** 35 | * Mix 2 parts together using one method 36 | * 37 | * @param string $part1 The first part to mix 38 | * @param string $part2 The second part to mix 39 | * 40 | * @return string The mixed data 41 | */ 42 | abstract protected function mixParts1($part1, $part2); 43 | 44 | /** 45 | * Mix 2 parts together using another different method 46 | * 47 | * @param string $part1 The first part to mix 48 | * @param string $part2 The second part to mix 49 | * 50 | * @return string The mixed data 51 | */ 52 | abstract protected function mixParts2($part1, $part2); 53 | 54 | /** 55 | * Mix the provided array of strings into a single output of the same size 56 | * 57 | * All elements of the array should be the same size. 58 | * 59 | * @param array $parts The parts to be mixed 60 | * 61 | * @return string The mixed result 62 | */ 63 | public function mix(array $parts) { 64 | if (empty($parts)) { 65 | return ''; 66 | } 67 | $len = strlen($parts[0]); 68 | $parts = $this->normalizeParts($parts); 69 | $stringSize = count($parts[0]); 70 | $partsSize = count($parts); 71 | $result = ''; 72 | $offset = 0; 73 | for ($i = 0; $i < $stringSize; $i++) { 74 | $stub = $parts[$offset][$i]; 75 | for ($j = 1; $j < $partsSize; $j++) { 76 | $newKey = $parts[($j + $offset) % $partsSize][$i]; 77 | //Alternately mix the output for each source 78 | if ($j % 2 == 1) { 79 | $stub ^= $this->mixParts1($stub, $newKey); 80 | } else { 81 | $stub ^= $this->mixParts2($stub, $newKey); 82 | } 83 | } 84 | $result .= $stub; 85 | $offset = ($offset + 1) % $partsSize; 86 | } 87 | return substr($result, 0, $len); 88 | } 89 | 90 | /** 91 | * Normalize the part array and split it block part size. 92 | * 93 | * This will make all parts the same length and a multiple 94 | * of the part size 95 | * 96 | * @param array $parts The parts to normalize 97 | * 98 | * @return array The normalized and split parts 99 | */ 100 | protected function normalizeParts(array $parts) { 101 | $blockSize = $this->getPartSize(); 102 | $callback = function($value) { 103 | return strlen($value); 104 | }; 105 | $maxSize = max(array_map($callback, $parts)); 106 | if ($maxSize % $blockSize != 0) { 107 | $maxSize += $blockSize - ($maxSize % $blockSize); 108 | } 109 | foreach ($parts as &$part) { 110 | $part = str_pad($part, $maxSize, chr(0)); 111 | $part = str_split($part, $blockSize); 112 | } 113 | return $parts; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /test/Mocks/Cipher/Factory.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2011 The Authors 14 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 15 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 16 | */ 17 | 18 | namespace PasswordLibTest\Mocks\Cipher; 19 | 20 | 21 | /** 22 | * The Cipher Factory 23 | * 24 | * Use this factory to instantiate ciphers and modes based upon their names. You 25 | * can register new ciphers and modes by simply calling the appropriate methods. 26 | * 27 | * @category PHPPasswordLib 28 | * @package Cipher 29 | * @author Anthony Ferrara 30 | */ 31 | class Factory extends \PasswordLib\Cipher\Factory { 32 | 33 | protected $callbacks = array(); 34 | 35 | /** 36 | * Instantiate the factory 37 | * 38 | * This automatically loads and registers the default cipher and mode 39 | * implementations. 40 | * 41 | * @return void 42 | */ 43 | public function __construct(array $callbacks = array()) { 44 | $this->callbacks = $callbacks; 45 | } 46 | 47 | public function __call($name, $args) { 48 | if (isset($this->callbacks[$name])) { 49 | return call_user_func_array($this->callbacks[$name], $args); 50 | } 51 | return null; 52 | } 53 | 54 | /** 55 | * Get an instance of a cipher by name 56 | * 57 | * Note that this will return the passed argument if it is an instance of 58 | * the Block cipher interface. 59 | * 60 | * @param string|Block $cipher The cipher name or instance to load 61 | * 62 | * @return Block The loaded block cipher 63 | * @throws RuntimeException if the cipher is not supported 64 | */ 65 | public function getBlockCipher($cipher) { 66 | return $this->__call('getBlockCipher', array($cipher)); 67 | } 68 | 69 | /** 70 | * Get an instance of a mode by name 71 | * 72 | * Note that this will return the passed argument if it is an instance of 73 | * the Mode interface. 74 | * 75 | * @param string|Mode $mode The mode name or instance to load 76 | * 77 | * @return Mode The loaded mode instance 78 | * @throws RuntimeException if the mode is not supported 79 | */ 80 | public function getMode( 81 | $mode, 82 | \PasswordLib\Cipher\Block\Cipher $cipher, 83 | $initv, 84 | array $options = array() 85 | ) { 86 | return $this->__call('getMode', array($mode, $cipher, $initv, $options)); 87 | } 88 | 89 | /** 90 | * Register a new cipher implementation class for this factory 91 | * 92 | * This will iterate over each supported cipher for the class and load the 93 | * cipher into the list of supported ciphers 94 | * 95 | * @param string $name The name of the cipher (ignored) 96 | * @param string $class The full class name of the cipher implementation 97 | * 98 | * @return Factory $this The current factory instance 99 | * @throws InvalidArgumentException If the class is not a block cipher 100 | */ 101 | public function registerCipher($name, $class) { 102 | return $this->__call('registerCipher', array($name, $class)); 103 | } 104 | 105 | /** 106 | * Register a new mode implementation class for this factory 107 | * 108 | * @param string $name The name of the mode (ignored) 109 | * @param string $class The full class name of the mode implementation 110 | * 111 | * @return Factory $this The current factory instance 112 | * @throws InvalidArgumentException If the class is not a valid mode 113 | */ 114 | public function registerMode($name, $class) { 115 | return $this->__call('registerMode', array($name, $class)); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /test/Unit/Random/FactoryTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($factory instanceof PasswordLib\Random\Factory); 22 | } 23 | 24 | /** 25 | * @covers PasswordLib\Random\Factory 26 | */ 27 | public function testGetGeneratorFallback() { 28 | $factory = new Factory; 29 | $generator = $factory->getGenerator(new MockStrength(MockStrength::MEDIUMLOW)); 30 | $mixer = call_user_func(array( 31 | get_class($generator->getMixer()), 32 | 'getStrength' 33 | )); 34 | $this->assertTrue($mixer->compare(new Strength(Strength::LOW)) <= 0); 35 | } 36 | 37 | /** 38 | * @covers PasswordLib\Random\Factory 39 | * @expectedException RuntimeException 40 | */ 41 | public function testGetGeneratorFallbackFail() { 42 | $factory = new Factory; 43 | $generator = $factory->getGenerator(new MockStrength(MockStrength::SUPERHIGH)); 44 | } 45 | 46 | /** 47 | * @covers PasswordLib\Random\Factory::registerSource 48 | * @covers PasswordLib\Random\Factory::getSources 49 | */ 50 | public function testRegisterSource() { 51 | $factory = new Factory; 52 | $factory->registerSource('mock', 'PasswordLibTest\Mocks\Random\Source'); 53 | $test = $factory->getSources(); 54 | $this->assertTrue(in_array('PasswordLibTest\Mocks\Random\Source', $test)); 55 | } 56 | 57 | /** 58 | * @covers PasswordLib\Random\Factory::registerSource 59 | * @covers PasswordLib\Random\Factory::getSources 60 | * @expectedException InvalidArgumentException 61 | */ 62 | public function testRegisterSourceFail() { 63 | $factory = new Factory; 64 | $factory->registerSource('mock', 'stdclass'); 65 | } 66 | 67 | 68 | /** 69 | * @covers PasswordLib\Random\Factory::registerMixer 70 | * @covers PasswordLib\Random\Factory::getMixers 71 | */ 72 | public function testRegisterMixer() { 73 | $factory = new Factory; 74 | $factory->registerMixer('mock', 'PasswordLibTest\Mocks\Random\Mixer'); 75 | $test = $factory->getMixers(); 76 | $this->assertTrue(in_array('PasswordLibTest\Mocks\Random\Mixer', $test)); 77 | } 78 | 79 | /** 80 | * @covers PasswordLib\Random\Factory::registerMixer 81 | * @covers PasswordLib\Random\Factory::getMixers 82 | * @expectedException InvalidArgumentException 83 | */ 84 | public function testRegisterMixerFail() { 85 | $factory = new Factory; 86 | $factory->registerMixer('mock', 'stdclass'); 87 | } 88 | 89 | /** 90 | * @covers PasswordLib\Random\Factory::getMediumStrengthGenerator 91 | * @covers PasswordLib\Random\Factory::getGenerator 92 | * @covers PasswordLib\Random\Factory::findMixer 93 | */ 94 | public function testGetMediumStrengthGenerator() { 95 | $factory = new Factory; 96 | $generator = $factory->getMediumStrengthGenerator(); 97 | $this->assertTrue($generator instanceof PasswordLib\Random\Generator); 98 | $mixer = call_user_func(array( 99 | get_class($generator->getMixer()), 100 | 'getStrength' 101 | )); 102 | $this->assertTrue($mixer->compare(new Strength(Strength::MEDIUM)) <= 0); 103 | foreach ($generator->getSources() as $source) { 104 | $strength = call_user_func(array(get_class($source), 'getStrength')); 105 | $this->assertTrue($strength->compare(new Strength(Strength::MEDIUM)) >= 0); 106 | } 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /lib/PasswordLib/Core/BaseConverter.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright 2011 The Authors 13 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 14 | * @version Build @@version@@ 15 | */ 16 | 17 | namespace PasswordLib\Core; 18 | 19 | /** 20 | * A Utility class for converting between raw binary strings and a given 21 | * list of characters 22 | * 23 | * @category PHPPasswordLib 24 | * @package Core 25 | * @author Anthony Ferrara 26 | */ 27 | class BaseConverter { 28 | 29 | /** 30 | * Convert from a raw binary string to a string of characters 31 | * 32 | * @param string $string The string to convert from 33 | * @param string $characters The list of characters to convert to 34 | * 35 | * @return string The converted string 36 | */ 37 | public static function convertFromBinary($string, $characters) { 38 | if ($string === '' || empty($characters)) { 39 | return ''; 40 | } 41 | $string = str_split($string); 42 | $callback = function($str) { 43 | return ord($str); 44 | }; 45 | $string = array_map($callback, $string); 46 | $converted = static::baseConvert($string, 256, strlen($characters)); 47 | $callback = function ($num) use ($characters) { 48 | return $characters[$num]; 49 | }; 50 | $ret = implode('', array_map($callback, $converted)); 51 | return $ret; 52 | } 53 | 54 | /** 55 | * Convert to a raw binary string from a string of characters 56 | * 57 | * @param string $string The string to convert from 58 | * @param string $characters The list of characters to convert to 59 | * 60 | * @return string The converted string 61 | */ 62 | public static function convertToBinary($string, $characters) { 63 | if (empty($string) || empty($characters)) { 64 | return ''; 65 | } 66 | $string = str_split($string); 67 | $callback = function($str) use ($characters) { 68 | return strpos($characters, $str); 69 | }; 70 | $string = array_map($callback, $string); 71 | $converted = static::baseConvert($string, strlen($characters), 256); 72 | $callback = function ($num) { 73 | return chr($num); 74 | }; 75 | return implode('', array_map($callback, $converted)); 76 | } 77 | 78 | /** 79 | * Convert an array of input blocks to another numeric base 80 | * 81 | * This function was modified from an implementation found on StackOverflow. 82 | * Special Thanks to @KeithRandall for supplying the implementation. 83 | * 84 | * @param int[] $source The source number, as an array 85 | * @param int $srcBase The source base as an integer 86 | * @param int $dstBase The destination base as an integer 87 | * 88 | * @see http://codegolf.stackexchange.com/questions/1620/arb/1626#1626 89 | * @return int[] An array of integers in the encoded base 90 | */ 91 | public static function baseConvert(array $source, $srcBase, $dstBase) { 92 | if ($dstBase < 2) { 93 | $message = sprintf('Invalid Destination Base: %d', $dstBase); 94 | throw new \InvalidArgumentException($message); 95 | } 96 | $result = array(); 97 | $count = count($source); 98 | while ($count) { 99 | $itMax = $count; 100 | $remainder = $count = $loop = 0; 101 | while($loop < $itMax) { 102 | $dividend = $source[$loop++] + $remainder * $srcBase; 103 | $remainder = $dividend % $dstBase; 104 | $res = ($dividend - $remainder) / $dstBase; 105 | if ($count || $res) { 106 | $source[$count++] = $res; 107 | } 108 | } 109 | $result[] = $remainder; 110 | } 111 | return array_reverse($result); 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /test/Data/Vectors/hmac.rfc4231.test-vectors: -------------------------------------------------------------------------------- 1 | #Test Vectors taken from RFC 4231 2 | 3 | Set 1 Vector 1 4 | Key=0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 5 | Data=4869205468657265 6 | SHA224=896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22 7 | Len-SHA224=28 8 | SHA256=b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7 9 | Len-SHA256=32 10 | SHA384=afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6 11 | Len-SHA384=48 12 | SHA512=87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854 13 | Len-SHA512=64 14 | 15 | Set 1 Vector 2 16 | Key=4a656665 17 | Data=7768617420646f2079612077616e7420666f72206e6f7468696e673f 18 | SHA224=a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44 19 | Len-SHA224=28 20 | SHA256=5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843 21 | Len-SHA256=32 22 | SHA384=af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649 23 | Len-SHA384=48 24 | SHA512=164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737 25 | Len-SHA512=64 26 | 27 | Set 1 Vector 3 28 | Key=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 29 | Data=dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd 30 | SHA224=7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea 31 | Len-SHA224=28 32 | SHA256=773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe 33 | Len-SHA256=32 34 | SHA384=88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27 35 | Len-SHA384=48 36 | SHA512=fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb 37 | Len-SHA512=64 38 | 39 | Set 1 Vector 4 40 | Key=0102030405060708090a0b0c0d0e0f10111213141516171819 41 | Data=cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd 42 | SHA224=6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a 43 | Len-SHA224=28 44 | SHA256=82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b 45 | Len-SHA256=32 46 | SHA384=3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb 47 | Len-SHA384=48 48 | SHA512=b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd 49 | Len-SHA512=64 50 | 51 | Set 1 Vector 5 52 | Key=0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c 53 | Data=546573742057697468205472756e636174696f6e 54 | SHA224=0e2aea68a90c8d37c988bcdb9fca6fa8 55 | Len-SHA224=16 56 | SHA256=a3b6167473100ee06e0c796c2955552b 57 | Len-SHA256=16 58 | SHA384=3abf34c3503b2a23a46efc619baef897 59 | Len-SHA384=16 60 | SHA512=415fad6271580a531d4179bc891d87a6 61 | Len-SHA512=16 62 | 63 | Set 1 Vector 6 64 | Key=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 65 | Data=54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374 66 | SHA224=95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e 67 | Len-SHA224=28 68 | SHA256=60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54 69 | Len-SHA256=32 70 | SHA384=4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952 71 | Len-SHA384=48 72 | SHA512=80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598 73 | Len-SHA512=64 74 | 75 | Set 1 Vector 7 76 | Key=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 77 | Data=5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e 78 | SHA224=3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1 79 | Len-SHA224=28 80 | SHA256=9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2 81 | Len-SHA256=32 82 | SHA384=6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e 83 | Len-SHA384=48 84 | SHA512=e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58 85 | Len-SHA512=64 86 | 87 | -------------------------------------------------------------------------------- /test/Unit/Password/Implementation/APR1Test.php: -------------------------------------------------------------------------------- 1 | assertEquals('$apr1$', APR1::getPrefix()); 45 | } 46 | 47 | /** 48 | * @covers PasswordLib\Password\Implementation\APR1::detect 49 | * @dataProvider provideTestDetect 50 | */ 51 | public function testDetect($from, $expect) { 52 | $this->assertEquals($expect, APR1::detect($from)); 53 | } 54 | 55 | /** 56 | * @covers PasswordLib\Password\Implementation\APR1::loadFromHash 57 | */ 58 | public function testLoadFromHash() { 59 | $test = APR1::loadFromHash('$apr1$foo'); 60 | $this->assertTrue($test instanceof APR1); 61 | } 62 | 63 | /** 64 | * @covers PasswordLib\Password\Implementation\APR1::loadFromHash 65 | * @expectedException InvalidArgumentException 66 | */ 67 | public function testLoadFromHashFail() { 68 | APR1::loadFromHash('foo'); 69 | } 70 | 71 | /** 72 | * @covers PasswordLib\Password\Implementation\APR1::__construct 73 | */ 74 | public function testConstruct() { 75 | $apr = new APR1(); 76 | $this->assertTrue($apr instanceof APR1); 77 | } 78 | 79 | /** 80 | * @covers PasswordLib\Password\Implementation\APR1::__construct 81 | */ 82 | public function testConstructArgs() { 83 | $gen = $this->getRandomGenerator(function($size) {}); 84 | $apr = new APR1(array(), $gen); 85 | $this->assertTrue($apr instanceof APR1); 86 | } 87 | 88 | /** 89 | * @covers PasswordLib\Password\Implementation\APR1::create 90 | * @covers PasswordLib\Password\Implementation\APR1::to64 91 | * @covers PasswordLib\Password\Implementation\APR1::hash 92 | * @covers PasswordLib\Password\Implementation\APR1::iterate 93 | * @covers PasswordLib\Password\Implementation\APR1::convertToHash 94 | * @dataProvider provideTestCreate 95 | */ 96 | public function testCreate($pass, $expect) { 97 | $apr = $this->getAPR1MockInstance(); 98 | $this->assertEquals($expect, $apr->create($pass)); 99 | } 100 | 101 | /** 102 | * @covers PasswordLib\Password\Implementation\APR1::verify 103 | * @covers PasswordLib\Password\Implementation\APR1::to64 104 | * @covers PasswordLib\Password\Implementation\APR1::hash 105 | * @covers PasswordLib\Password\Implementation\APR1::iterate 106 | * @covers PasswordLib\Password\Implementation\APR1::convertToHash 107 | * @dataProvider provideTestVerify 108 | */ 109 | public function testVerify($pass, $expect) { 110 | $apr = $this->getAPR1MockInstance(); 111 | $this->assertTrue($apr->verify($pass, $expect)); 112 | } 113 | 114 | /** 115 | * @covers PasswordLib\Password\Implementation\APR1::verify 116 | * @dataProvider provideTestVerifyFail 117 | */ 118 | public function testVerifyFail($pass, $expect) { 119 | $apr = $this->getAPR1MockInstance(); 120 | $this->assertFalse($apr->verify($pass, $expect)); 121 | } 122 | 123 | protected function getAPR1MockInstance() { 124 | $gen = $this->getRandomGenerator(function($min, $max) { 125 | return 1914924168; 126 | }); 127 | return new APR1(array(), $gen); 128 | } 129 | 130 | protected function getAPR1Instance($evaluate, $hmac, $generate) { 131 | $generator = $this->getRandomGenerator($generate); 132 | return new APR1(array(), $generator); 133 | } 134 | 135 | protected function getRandomGenerator($generate) { 136 | return new MockGenerator(array( 137 | 'generateInt' => $generate 138 | )); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /test/Unit/Password/Implementation/HashTest.php: -------------------------------------------------------------------------------- 1 | getPassword()->create($password); 56 | } 57 | 58 | /** 59 | * @dataProvider provideCreateTypes 60 | */ 61 | public function testVerifyTypes($password, $valid) { 62 | $hash = md5('test'); 63 | if (!$valid) { 64 | $this->setExpectedException('DomainException'); 65 | } 66 | $this->getPassword()->verify($password, $hash); 67 | } 68 | 69 | /** 70 | * @covers PasswordLib\Password\Implementation\Hash 71 | * @dataProvider provideTestDetect 72 | */ 73 | public function testDetect($from, $expect) { 74 | $this->assertEquals($expect, Hash::detect($from)); 75 | } 76 | 77 | /** 78 | * @covers PasswordLib\Password\Implementation\Hash 79 | * @dataProvider provideTestLoadFromHash 80 | */ 81 | public function testLoadFromHash($algo) { 82 | $test = Hash::loadFromHash(hash($algo, '')); 83 | $this->assertTrue($test instanceof Hash); 84 | } 85 | 86 | /** 87 | * @covers PasswordLib\Password\Implementation\Hash 88 | * @expectedException InvalidArgumentException 89 | */ 90 | public function testLoadFromHashFail() { 91 | Hash::loadFromHash('foo'); 92 | } 93 | 94 | /** 95 | * @covers PasswordLib\Password\Implementation\Hash 96 | */ 97 | public function testConstruct() { 98 | $hash = new Hash(array('hash' => 'sha256')); 99 | $this->assertTrue($hash instanceof Hash); 100 | } 101 | 102 | /** 103 | * @covers PasswordLib\Password\Implementation\Hash 104 | */ 105 | public function testGetPrefix() { 106 | $this->assertFalse(Hash::getPrefix()); 107 | } 108 | 109 | 110 | /** 111 | * @covers PasswordLib\Password\Implementation\Hash 112 | */ 113 | public function testConstructArgs() { 114 | $gen = $this->getRandomGenerator(function($size) {}); 115 | $apr = new Hash(array('hash' => 'md5'), $gen); 116 | $this->assertTrue($apr instanceof Hash); 117 | } 118 | 119 | /** 120 | * @covers PasswordLib\Password\Implementation\Hash 121 | * @expectedException BadMethodCallException 122 | */ 123 | public function testCreate() { 124 | $hash = new Hash(array('hash' => 'md5')); 125 | $hash->create('foo'); 126 | } 127 | 128 | /** 129 | * @covers PasswordLib\Password\Implementation\Hash 130 | * @dataProvider provideTestVerify 131 | */ 132 | public function testVerify($func, $pass, $hash) { 133 | $apr = new Hash(array('hash' => $func)); 134 | $this->assertTrue($apr->verify($pass, $hash)); 135 | } 136 | 137 | /** 138 | * @covers PasswordLib\Password\Implementation\Hash 139 | * @dataProvider provideTestVerifyFail 140 | */ 141 | public function testVerifyFail($func, $pass, $expect) { 142 | $apr = new Hash(array('hash' => $func)); 143 | $this->assertFalse($apr->verify($pass, $expect)); 144 | } 145 | 146 | protected function getRandomGenerator($generate) { 147 | return new MockGenerator(array( 148 | 'generateInt' => $generate 149 | )); 150 | } 151 | 152 | protected function getPassword($func = 'md5') { 153 | return new Hash(array('hash' => $func)); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /lib/PasswordLib/Password/Implementation/Crypt.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright 2011 The Authors 14 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 15 | * @version Build @@version@@ 16 | */ 17 | 18 | namespace PasswordLib\Password\Implementation; 19 | 20 | use PasswordLib\Random\Factory as RandomFactory; 21 | 22 | /** 23 | * The Blowfish password hashing implementation 24 | * 25 | * Use this class to generate and validate Blowfish password hashes. 26 | * 27 | * @category PHPPasswordLib 28 | * @package Password 29 | * @subpackage Implementation 30 | * @author Anthony Ferrara 31 | */ 32 | class Crypt extends \PasswordLib\Password\AbstractPassword { 33 | 34 | /** 35 | * @var Generator The random generator to use for seeds 36 | */ 37 | protected $generator = null; 38 | 39 | protected $saltLen = 2; 40 | 41 | /** 42 | * Determine if the hash was made with this method 43 | * 44 | * @param string $hash The hashed data to check 45 | * 46 | * @return boolean Was the hash created by this method 47 | */ 48 | public static function detect($hash) { 49 | static $regex = '/^[.\/0-9A-Za-z]{13}$/'; 50 | return 1 == preg_match($regex, $hash); 51 | } 52 | 53 | /** 54 | * Load an instance of the class based upon the supplied hash 55 | * 56 | * @param string $hash The hash to load from 57 | * 58 | * @return Password the created instance 59 | * @throws InvalidArgumentException if the hash wasn't created here 60 | */ 61 | public static function loadFromHash($hash) { 62 | if (!static::detect($hash)) { 63 | throw new \InvalidArgumentException('Hash Not Created Here'); 64 | } 65 | return new static(); 66 | } 67 | 68 | /** 69 | * Create a password hash for a given plain text password 70 | * 71 | * @param string $password The password to hash 72 | * 73 | * @return string The formatted password hash 74 | */ 75 | public function create($password) { 76 | $password = $this->checkPassword($password); 77 | $salt = $this->generateSalt(); 78 | $result = crypt($password, $salt); 79 | if ($result[0] == '*') { 80 | //@codeCoverageIgnoreStart 81 | throw new \RuntimeException('Password Could Not Be Created'); 82 | //@codeCoverageIgnoreEnd 83 | } 84 | return $result; 85 | } 86 | 87 | /** 88 | * Verify a password hash against a given plain text password 89 | * 90 | * @param string $password The password to hash 91 | * @param string $hash The supplied ahsh to validate 92 | * 93 | * @return boolean Does the password validate against the hash 94 | */ 95 | public function verify($password, $hash) { 96 | $password = $this->checkPassword($password); 97 | if (!static::detect($hash)) { 98 | throw new \InvalidArgumentException( 99 | 'The hash was not created here, we cannot verify it' 100 | ); 101 | } 102 | $test = crypt($password, $hash); 103 | return $this->compareStrings($test, $hash); 104 | } 105 | 106 | protected function generateSalt() { 107 | $salt = $this->generator->generate($this->saltLen); 108 | $chars = $this->to64($salt); 109 | return substr($chars, 0, $this->saltLen); 110 | } 111 | 112 | /** 113 | * Convert the input number to a base64 number of the specified size 114 | * 115 | * @param int $input The number to convert 116 | * 117 | * @return string The converted representation 118 | */ 119 | protected function to64($input) { 120 | static $itoa = null; 121 | if (empty($itoa)) { 122 | $itoa = './ABCDEFGHIJKLMNOPQRSTUVWXYZ' 123 | . 'abcdefghijklmnopqrstuvwxyz0123456789'; 124 | } 125 | $output = ''; 126 | $size = strlen($input); 127 | $ictr = 0; 128 | do { 129 | $cval1 = ord($input[$ictr++]); 130 | $output .= $itoa[$cval1 >> 2]; 131 | $cval1 = ($cval1 & 0x03) << 4; 132 | if ($ictr >= $size) { 133 | $output .= $itoa[$cval1]; 134 | break; 135 | } 136 | $cval2 = ord($input[$ictr++]); 137 | $cval1 |= $cval2 >> 4; 138 | $output .= $itoa[$cval1]; 139 | $cval1 = ($cval2 & 0x0f) << 2; 140 | if ($ictr >= $size) { 141 | $output .= $itoa[$cval1]; 142 | break; 143 | } 144 | $cval2 = ord($input[$ictr++]); 145 | $cval1 |= $cval2 >> 6; 146 | $output .= $itoa[$cval1]; 147 | $output .= $itoa[$cval2 & 0x3f]; 148 | } while (true); 149 | return $output; 150 | } 151 | } -------------------------------------------------------------------------------- /examples/PasswordLib.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 2011 The Authors 11 | * @license http://opensource.org/licenses/bsd-license.php New BSD License 12 | * @license http://www.gnu.org/licenses/lgpl-2.1.html LGPL v 2.1 13 | */ 14 | 15 | /** 16 | * Note, you do not need to use namespaces in your code to make use of the library. 17 | * Namespaces are used here for separation separation only. 18 | */ 19 | namespace PasswordLibExamples; 20 | 21 | /** 22 | * Since we're using the wrapper class, it will automatically instantiate the 23 | * library without having to manually bootstrap the framework. Either way will 24 | * work just fine. Even if you call both, it's smart enough to not double 25 | * initialize the framework. 26 | */ 27 | require_once dirname(__DIR__) . '/lib/PasswordLib/PasswordLib.php'; 28 | 29 | /** 30 | * There's no parameters to instantiate the class. Just instantiate it. Note the 31 | * namespace prefix. You can import the class using a `use PasswordLib\PasswordLib` 32 | * declaration at the top of the file, but this works just as well. 33 | */ 34 | $PasswordLib = new \PasswordLib\PasswordLib; 35 | 36 | /** 37 | * Now we can do all sorts of things with the library. Let's start off by 38 | * generating a random token. This could be a temporary password, a CSRF token, etc 39 | * 40 | * Note that the number in the input is the number of desired characters in the 41 | * random output. So if you want 16 random characters, pass in 16. If you want 42 | * 300, pass in 300. 43 | * 44 | * Also note that this generates medium strength random numbers. If you are using 45 | * the generated numbers for encryption or for other sensitive needs, use the 46 | * random generator class itself (see the Random/strings.php example). 47 | */ 48 | $token = $PasswordLib->getRandomToken(16); 49 | 50 | printf("\nHere's our token: %s\n", $token); 51 | 52 | /** 53 | * Now, let's generate a random number. This works just like `rand()` in that you 54 | * can provide a min and a max to the function to put boundaries on the generated 55 | * number's range. 56 | */ 57 | $number = $PasswordLib->getRandomNumber(); 58 | 59 | printf("\nHere's a random number from 0 to PHP_INT_MAX: %d\n", $number); 60 | 61 | /** 62 | * Let's bound that to between 10 and 100... 63 | */ 64 | $number = $PasswordLib->getRandomNumber(10, 100); 65 | 66 | printf("\nHere's a random number from 10 to 100: %d\n", $number); 67 | 68 | /** 69 | * And we can also pick a random element from an array 70 | * 71 | * This is similar to array_rand, except that it uses a cryptographic secure RNG 72 | * (which is likely overkill for most applications) 73 | */ 74 | $array = array('ab', 'bc', 'cd', 'de', 'ef', 'fg', 'gh'); 75 | $element = $PasswordLib->getRandomArrayElement($array); 76 | 77 | printf("\nHere's a random array element: %s\n", $element); 78 | 79 | /** 80 | * And we can randomize an array 81 | */ 82 | $array = array('a', 'b', 'c', 'd', 'e', 'f'); 83 | $newArray = $PasswordLib->shuffleArray($array); 84 | 85 | printf("\nHere's a randomized array: \n"); 86 | 87 | print_r($newArray); 88 | 89 | printf("\nAnd here's the same arrays with incremental keys:\n"); 90 | 91 | print_r(array_values($newArray)); 92 | 93 | /** 94 | * And we can randomize a string 95 | */ 96 | 97 | $string = 'abcdef'; 98 | $newString = $PasswordLib->shuffleString($string); 99 | 100 | printf("\nHere's our randomized string: %s\n", $newString); 101 | 102 | /** 103 | * Now, lets do some password hashing. 104 | */ 105 | $password = 'Password'; 106 | 107 | $hash = $PasswordLib->createPasswordHash($password); 108 | 109 | printf("\nHere's a hashed password: %s\n", $hash); 110 | 111 | /** 112 | * Let's verify the password. To show that nothing is saved, let's create a new 113 | * instance of the PasswordLib class. 114 | */ 115 | $PasswordLib2 = new \PasswordLib\PasswordLib; 116 | 117 | $result = $PasswordLib2->verifyPasswordHash($password, $hash); 118 | 119 | printf("\nThe result of the password check was: %s\n", $result ? 'successful' : 'not successful'); 120 | 121 | /** 122 | * Let's use a different format. Let's try using Drupal's password hash 123 | */ 124 | 125 | $hash = $PasswordLib->createPasswordHash($password, '$S$'); 126 | 127 | printf("\nHere's a Drupal hashed password: %s\n", $hash); 128 | 129 | /** 130 | * Let's verify the password. To show that nothing is saved, let's create a new 131 | * instance of the PasswordLib class. 132 | */ 133 | 134 | $result = $PasswordLib2->verifyPasswordHash($password, $hash); 135 | 136 | printf("\nThe result of the Drupal password check was: %s\n", $result ? 'successful' : 'not successful'); 137 | 138 | 139 | /** 140 | * Let's use PBKDF2 141 | */ 142 | 143 | $hash = $PasswordLib->createPasswordHash($password, '$pbkdf$'); 144 | 145 | printf("\nHere's a PBKDF2 hashed password: %s\n", $hash); 146 | 147 | /** 148 | * Let's verify the password. To show that nothing is saved, let's create a new 149 | * instance of the PasswordLib class. 150 | */ 151 | 152 | $result = $PasswordLib2->verifyPasswordHash($password, $hash); 153 | 154 | printf("\nThe result of the PBKDF2 password check was: %s\n", $result ? 'successful' : 'not successful'); 155 | 156 | 157 | /** 158 | * Let's set the cost of bcrypt off its default: 159 | */ 160 | $result = $PasswordLib->createPasswordHash($password, '$2a$', array('cost' => 4)); 161 | 162 | printf("\nThe result of BCrypt with reduced cost was: %s\n", $result); 163 | 164 | /** 165 | * Let's set the cost of bcrypt off its default, again: 166 | */ 167 | $result = $PasswordLib->createPasswordHash($password, '$2a$', array('cost' => 5)); 168 | 169 | printf("\nThe result of BCrypt with reduced cost was: %s\n", $result); -------------------------------------------------------------------------------- /lib/PasswordLib/Core/BigMath/PHPMath.php: -------------------------------------------------------------------------------- 1 | 11 | * @copyright 2011 The Authors 12 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 13 | * @version Build @@version@@ 14 | */ 15 | namespace PasswordLib\Core\BigMath; 16 | 17 | use PasswordLib\Core\BaseConverter; 18 | 19 | /** 20 | * A class for arbitrary precision math functions implemented in PHP 21 | * 22 | * @category PHPPasswordLib 23 | * @package Core 24 | * @subpackage BigMath 25 | */ 26 | class PHPMath extends \PasswordLib\Core\BigMath { 27 | 28 | /** 29 | * Add two numbers together 30 | * 31 | * @param string $left The left argument 32 | * @param string $right The right argument 33 | * 34 | * @return A base-10 string of the sum of the two arguments 35 | */ 36 | public function add($left, $right) { 37 | if (empty($left)) { 38 | return $right; 39 | } elseif (empty($right)) { 40 | return $left; 41 | } 42 | $negative = ''; 43 | if ($left[0] == '-' && $right[0] == '-') { 44 | $negative = '-'; 45 | $left = substr($left, 1); 46 | $right = substr($right, 1); 47 | } elseif ($left[0] == '-') { 48 | return $this->subtract($right, substr($left, 1)); 49 | } elseif ($right[0] == '-') { 50 | return $this->subtract($left, substr($right, 1)); 51 | } 52 | $left = $this->normalize($left); 53 | $right = $this->normalize($right); 54 | $result = BaseConverter::convertFromBinary( 55 | $this->addBinary($left, $right), 56 | '0123456789' 57 | ); 58 | return $negative . $result; 59 | } 60 | 61 | /** 62 | * Subtract two numbers 63 | * 64 | * @param string $left The left argument 65 | * @param string $right The right argument 66 | * 67 | * @return A base-10 string of the difference of the two arguments 68 | */ 69 | public function subtract($left, $right) { 70 | if (empty($left)) { 71 | return $right; 72 | } elseif (empty($right)) { 73 | return $left; 74 | } elseif ($right[0] == '-') { 75 | return $this->add($left, substr($right, 1)); 76 | } elseif ($left[0] == '-') { 77 | return '-' . $this->add(ltrim($left, '-'), $right); 78 | } 79 | $left = $this->normalize($left); 80 | $right = $this->normalize($right); 81 | $results = $this->subtractBinary($left, $right); 82 | $result = BaseConverter::convertFromBinary($results[1], '0123456789'); 83 | return $results[0] . $result; 84 | } 85 | 86 | /** 87 | * Add two binary strings together 88 | * 89 | * @param string $left The left argument 90 | * @param string $right The right argument 91 | * 92 | * @return string The binary result 93 | */ 94 | protected function addBinary($left, $right) { 95 | $len = max(strlen($left), strlen($right)); 96 | $left = str_pad($left, $len, chr(0), STR_PAD_LEFT); 97 | $right = str_pad($right, $len, chr(0), STR_PAD_LEFT); 98 | $result = ''; 99 | $carry = 0; 100 | for ($i = 0; $i < $len; $i++) { 101 | $sum = ord($left[$len - $i - 1]) 102 | + ord($right[$len - $i - 1]) 103 | + $carry; 104 | $result .= chr($sum % 256); 105 | $carry = $sum >> 8; 106 | } 107 | while ($carry) { 108 | $result .= chr($carry % 256); 109 | $carry >>= 8; 110 | } 111 | return strrev($result); 112 | } 113 | 114 | /** 115 | * Subtract two binary strings using 256's compliment 116 | * 117 | * @param string $left The left argument 118 | * @param string $right The right argument 119 | * 120 | * @return string The binary result 121 | */ 122 | protected function subtractBinary($left, $right) { 123 | $len = max(strlen($left), strlen($right)); 124 | $left = str_pad($left, $len, chr(0), STR_PAD_LEFT); 125 | $right = str_pad($right, $len, chr(0), STR_PAD_LEFT); 126 | $right = $this->compliment($right); 127 | $result = $this->addBinary($left, $right); 128 | if (strlen($result) > $len) { 129 | // Positive Result 130 | $carry = substr($result, 0, -1 * $len); 131 | $result = substr($result, strlen($carry)); 132 | return array( 133 | '', 134 | $this->addBinary($result, $carry) 135 | ); 136 | } 137 | return array('-', $this->compliment($result)); 138 | } 139 | 140 | /** 141 | * Take the 256 base compliment 142 | * 143 | * @param string $string The binary string to compliment 144 | * 145 | * @return string The complimented string 146 | */ 147 | protected function compliment($string) { 148 | $result = ''; 149 | $len = strlen($string); 150 | for ($i = 0; $i < $len; $i++) { 151 | $result .= chr(255 - ord($string[$i])); 152 | } 153 | return $result; 154 | } 155 | 156 | /** 157 | * Transform a string number into a binary string using base autodetection 158 | * 159 | * @param string $string The string to transform 160 | * 161 | * @return string The binary transformed number 162 | */ 163 | protected function normalize($string) { 164 | return BaseConverter::convertToBinary( 165 | $string, 166 | '0123456789' 167 | ); 168 | } 169 | 170 | } --------------------------------------------------------------------------------