├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── composer.json └── src ├── AbstractCrypter.php ├── AbstractDecrypter.php ├── AbstractEncrypter.php ├── AbstractRawDecrypter.php ├── AbstractRawEncrypter.php ├── Bound ├── AbstractBoundCrypter.php ├── AbstractBoundDecrypter.php ├── AbstractBoundEncrypter.php ├── BoundCrypter.php ├── BoundCrypterInterface.php ├── BoundDecrypter.php ├── BoundDecrypterInterface.php ├── BoundEncrypter.php └── BoundEncrypterInterface.php ├── Cipher ├── AbstractEncryptCipher.php ├── CipherInterface.php ├── DecryptCipher.php ├── EncryptCipher.php ├── Exception │ ├── CipherFinalizedException.php │ ├── CipherNotInitializedException.php │ ├── CipherStateExceptionInterface.php │ └── UnsupportedCipherParametersException.php ├── Factory │ ├── CipherFactoryInterface.php │ ├── DecryptCipherFactory.php │ └── EncryptCipherFactory.php ├── Parameters │ ├── CipherParametersInterface.php │ ├── EncryptParameters.php │ └── EncryptParametersInterface.php └── Result │ ├── AbstractCipherResult.php │ ├── CipherResult.php │ ├── CipherResultInterface.php │ ├── CipherResultType.php │ └── Factory │ ├── CipherResultFactory.php │ └── CipherResultFactoryInterface.php ├── Comparator └── SlowStringComparator.php ├── Crypter.php ├── CrypterInterface.php ├── Decrypter.php ├── DecrypterInterface.php ├── Encrypter.php ├── EncrypterInterface.php ├── Key ├── Deriver │ ├── KeyDeriver.php │ └── KeyDeriverInterface.php ├── Exception │ ├── InvalidAuthSecretSizeException.php │ ├── InvalidEncryptSecretSizeException.php │ ├── InvalidIterationsException.php │ ├── InvalidKeyParameterExceptionInterface.php │ ├── InvalidSaltException.php │ ├── InvalidSaltSizeException.php │ └── InvalidSecretException.php ├── Factory │ ├── KeyFactory.php │ └── KeyFactoryInterface.php ├── Generator │ ├── KeyGenerator.php │ └── KeyGeneratorInterface.php ├── Key.php ├── KeyInterface.php └── Persistence │ ├── EncryptedKeyReaderInterface.php │ ├── EncryptedKeyWriterInterface.php │ ├── Exception │ ├── KeyReadException.php │ └── KeyWriteException.php │ ├── KeyReader.php │ ├── KeyReaderInterface.php │ ├── KeyWriter.php │ └── KeyWriterInterface.php ├── Lockbox.php ├── Padding ├── Exception │ └── InvalidBlockSizeException.php ├── PadderInterface.php ├── PaddingSchemeInterface.php ├── PkcsPadding.php └── UnpadderInterface.php ├── Password ├── Bound │ ├── BoundPasswordCrypter.php │ ├── BoundPasswordDecrypter.php │ └── BoundPasswordEncrypter.php ├── Cipher │ ├── Factory │ │ ├── PasswordDecryptCipherFactory.php │ │ └── PasswordEncryptCipherFactory.php │ ├── Parameters │ │ ├── PasswordEncryptParameters.php │ │ └── PasswordEncryptParametersInterface.php │ ├── PasswordDecryptCipher.php │ ├── PasswordEncryptCipher.php │ └── Result │ │ ├── Factory │ │ └── PasswordDecryptResultFactory.php │ │ ├── PasswordDecryptResult.php │ │ └── PasswordDecryptResultInterface.php ├── Exception │ └── InvalidPasswordException.php ├── Password.php ├── PasswordCrypter.php ├── PasswordDecrypter.php ├── PasswordEncrypter.php ├── PasswordInterface.php ├── RawPasswordCrypter.php ├── RawPasswordDecrypter.php ├── RawPasswordEncrypter.php └── Stream │ └── Filter │ ├── PasswordDecryptStreamFilter.php │ └── PasswordEncryptStreamFilter.php ├── Random ├── AbstractMcryptRandomSource.php ├── DevRandom.php ├── DevUrandom.php └── RandomSourceInterface.php ├── RawCrypter.php ├── RawDecrypter.php ├── RawEncrypter.php └── Stream ├── CipherStream.php ├── CipherStreamInterface.php ├── CompositePostCipherStream.php ├── CompositePreCipherStream.php ├── Exception └── StreamClosedException.php └── Filter ├── AbstractCipherStreamFilter.php ├── DecryptStreamFilter.php └── EncryptStreamFilter.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Lockbox for PHP changelog 2 | 3 | ## 0.2.0 (2013-09-03) 4 | 5 | - **[NEW]** Added interfaces for bi-directional ciphers. 6 | - **[IMPROVED]** Encryption ciphers now accept any key, rather than only public 7 | keys. 8 | - **[FIXED]** Garbage collection issues with keys are solved. 9 | 10 | ## 0.1.0 (2013-08-25) 11 | 12 | - **[NEW]** Initial implementation. 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | **Lockbox for PHP** is open source software; contributions from the community 4 | are encouraged. Please take a moment to read these guidelines before submitting 5 | changes. 6 | 7 | ## Code style 8 | 9 | All PHP code must adhere to the [PSR-2] standards. 10 | 11 | ## Branching and pull requests 12 | 13 | As a guideline, please follow this process: 14 | 15 | 1. [Fork the repository]. 16 | 2. Create a topic branch for the change: 17 | - New features should branch from **develop**. 18 | - Bug fixes to existing versions should branch from **master**. 19 | - Please ensure the branch is clearly labelled as a feature or fix. 20 | 3. Make the relevant changes. 21 | 4. [Squash] commits if necessary. 22 | 4. Submit a pull request to the **develop** branch. 23 | 24 | Please note this is a general guideline only. For more information on the 25 | branching structure please see the [git-flow cheatsheet]. 26 | 27 | 28 | 29 | [Fork the repository]: https://help.github.com/articles/fork-a-repo 30 | [git-flow cheatsheet]: http://danielkummer.github.com/git-flow-cheatsheet/ 31 | [PSR-2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md 32 | [Squash]: http://git-scm.com/book/en/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright © 2014 Erin Millard 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lockbox for PHP 2 | 3 | *Simple, strong encryption.* 4 | 5 | [![The most recent stable version is 0.2.0][version-image]][Semantic versioning] 6 | [![Current build status image][build-image]][Current build status] 7 | [![Current coverage status image][coverage-image]][Current coverage status] 8 | 9 | ## Installation and documentation 10 | 11 | * Available as [Composer] package [eloquent/lockbox]. 12 | * [API documentation] available. 13 | 14 | ## What is *Lockbox*? 15 | 16 | *Lockbox* is the simplest possible way to implement strong encryption for use in 17 | applications. *Lockbox* uses a combination of well-established technologies to 18 | ensure the safety of data. For more information, see the [Lockbox website]. 19 | 20 | ## Usage 21 | 22 | ### Generating and writing keys 23 | 24 | ```php 25 | use Eloquent\Lockbox\Key\Generator\KeyGenerator; 26 | use Eloquent\Lockbox\Key\Persistence\KeyWriter; 27 | 28 | $keyGenerator = new KeyGenerator; 29 | $key = $keyGenerator->generateKey(); 30 | 31 | $keyPath = '/path/to/lockbox.key'; 32 | $keyWriter = new KeyWriter; 33 | $keyWriter->writeFile($key, $keyPath); 34 | ``` 35 | 36 | Currently there is no way to generate lockbox keys via the command line, but 37 | this feature is planned. 38 | 39 | ### Encrypting data 40 | 41 | ```php 42 | use Eloquent\Lockbox\Encrypter; 43 | use Eloquent\Lockbox\Key\Persistence\KeyReader; 44 | 45 | $keyPath = '/path/to/lockbox.key'; 46 | $keyReader = new KeyReader; 47 | $key = $keyReader->readFile($keyPath); 48 | 49 | $encrypter = new Encrypter; 50 | echo $encrypter->encrypt($key, 'Super secret data.'); 51 | ``` 52 | 53 | ### Encrypting multiple data packets with the same key 54 | 55 | *Lockbox* includes 'bound' encrypters that are locked to a particular key, which 56 | are convenient for encrypting multiple data packets. 57 | 58 | ```php 59 | use Eloquent\Lockbox\Bound\BoundEncrypter; 60 | use Eloquent\Lockbox\Key\Persistence\KeyReader; 61 | 62 | $keyPath = '/path/to/lockbox.key'; 63 | $keyReader = new KeyReader; 64 | $key = $keyReader->readFile($keyPath); 65 | 66 | $encrypter = new BoundEncrypter($key); 67 | 68 | echo $encrypter->encrypt('Super secret data.'); 69 | echo $encrypter->encrypt('Extra secret data.'); 70 | echo $encrypter->encrypt('Mega secret data.'); 71 | ``` 72 | 73 | ### Decrypting data 74 | 75 | ```php 76 | use Eloquent\Lockbox\Decrypter; 77 | use Eloquent\Lockbox\Key\Persistence\KeyReader; 78 | 79 | $keyPath = '/path/to/lockbox.key'; 80 | $keyReader = new KeyReader; 81 | $key = $keyReader->readFile($keyPath); 82 | 83 | $decrypter = new Decrypter; 84 | 85 | $encrypted = 86 | 'AQF_VjJS9sAL75uuUP_HTu9Do_3itIDaHLLXmh_JLOBRqQeZ_hnDwht4WtEkz3io' . 87 | 'iW0WIHb3lANyKqpShyiPcVdj_DbfYiIPEWab8e3vqwEUvoqFFNo'; 88 | 89 | $result = $decrypter->decrypt($key, $encrypted); 90 | if ($result->isSuccessful()) { 91 | echo $result->data(); 92 | } else { 93 | echo 'Decryption failed.'; 94 | } 95 | ``` 96 | 97 | ### Decrypting multiple data packets with the same key 98 | 99 | *Lockbox* includes 'bound' decrypters that are locked to a particular key, which 100 | are convenient for decrypting multiple data packets. 101 | 102 | ```php 103 | use Eloquent\Lockbox\Bound\BoundDecrypter; 104 | use Eloquent\Lockbox\Key\Persistence\KeyReader; 105 | 106 | $keyPath = '/path/to/lockbox.key'; 107 | $keyReader = new KeyReader; 108 | $key = $keyReader->readFile($keyPath); 109 | 110 | $decrypter = new BoundDecrypter($key); 111 | 112 | $encrypted = array( 113 | 'AQF_VjJS9sAL75uuUP_HTu9Do_3itIDaHLLXmh_JLOBRqQeZ_hnDwht4WtEkz3io' . 114 | 'iW0WIHb3lANyKqpShyiPcVdj_DbfYiIPEWab8e3vqwEUvoqFFNo', 115 | 'AQH44yTs7va1cDoBpX0xVLqIRow5fs8Jj5-DYDJ1R3YY9udBCexmvDs9BH1qJDjC' . 116 | 'RSqcGriKi_UkL5per1WHwdxWuPq8QsYiBqeC9e9zypl0Xi1QT3s', 117 | 'AQGg0MsYtH0Rboyqssivssupb_GKlBotCpdFtc6WpnMaji8_ZvmGUTRu2DKkxFhA' . 118 | 'dk_s0FWZ7NYFjSDt1puIrr7MlB7owNuR5KhUIj04Can0zDCYjJY', 119 | ); 120 | 121 | foreach ($encrypted as $string) { 122 | $result = $decrypter->decrypt($string); 123 | if ($result->isSuccessful()) { 124 | echo $result->data(); 125 | } else { 126 | echo 'Decryption failed.'; 127 | } 128 | } 129 | ``` 130 | 131 | 132 | 133 | [Lockbox website]: http://lqnt.co/lockbox 134 | 135 | [API documentation]: http://lqnt.co/lockbox-php/artifacts/documentation/api/ 136 | [Composer]: http://getcomposer.org/ 137 | [build-image]: http://img.shields.io/travis/eloquent/lockbox-php/develop.svg "Current build status for the develop branch" 138 | [Current build status]: https://travis-ci.org/eloquent/lockbox-php 139 | [coverage-image]: http://img.shields.io/coveralls/eloquent/lockbox-php/develop.svg "Current test coverage for the develop branch" 140 | [Current coverage status]: https://coveralls.io/r/eloquent/lockbox-php 141 | [eloquent/lockbox]: https://packagist.org/packages/eloquent/lockbox 142 | [Semantic versioning]: http://semver.org/ 143 | [version-image]: http://img.shields.io/:semver-0.2.0-yellow.svg "This project uses semantic versioning" 144 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eloquent/lockbox", 3 | "description": "Simple, strong encryption.", 4 | "keywords": ["encryption", "mcrypt", "aes", "two", "way", "security", "strong", "simple", "symmetric", "key", "password"], 5 | "homepage": "https://github.com/eloquent/lockbox-php", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Erin Millard", 10 | "email": "ezzatron@gmail.com", 11 | "homepage": "http://ezzatron.com/" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=5.3", 16 | "ext-mcrypt": "*", 17 | "eloquent/endec": "~0.2.1", 18 | "eloquent/enumeration": "~5", 19 | "eloquent/pbkdf2-compat": "~1", 20 | "icecave/isolator": "~2" 21 | }, 22 | "require-dev": { 23 | "eloquent/liberator": "~2", 24 | "icecave/archer": "~1" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Eloquent\\Lockbox\\": "src" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/AbstractCrypter.php: -------------------------------------------------------------------------------- 1 | encrypter = $encrypter; 34 | $this->decrypter = $decrypter; 35 | } 36 | 37 | /** 38 | * Get the encrypter. 39 | * 40 | * @return EncrypterInterface The encrypter. 41 | */ 42 | public function encrypter() 43 | { 44 | return $this->encrypter; 45 | } 46 | 47 | /** 48 | * Get the decrypter. 49 | * 50 | * @return DecrypterInterface The decrypter. 51 | */ 52 | public function decrypter() 53 | { 54 | return $this->decrypter; 55 | } 56 | 57 | /** 58 | * Encrypt a data packet. 59 | * 60 | * @param CipherParametersInterface $parameters The parameters to encrypt with. 61 | * @param string $data The data to encrypt. 62 | * 63 | * @return string The encrypted data. 64 | */ 65 | public function encrypt(CipherParametersInterface $parameters, $data) 66 | { 67 | return $this->encrypter()->encrypt($parameters, $data); 68 | } 69 | 70 | /** 71 | * Decrypt a data packet. 72 | * 73 | * @param CipherParametersInterface $parameters The parameters to decrypt with. 74 | * @param string $data The data to decrypt. 75 | * 76 | * @return CipherResultInterface The decrypt result. 77 | */ 78 | public function decrypt(CipherParametersInterface $parameters, $data) 79 | { 80 | return $this->decrypter()->decrypt($parameters, $data); 81 | } 82 | 83 | /** 84 | * Create a new encrypt stream. 85 | * 86 | * @param CipherParametersInterface $parameters The parameters to encrypt with. 87 | * 88 | * @return CipherStreamInterface The newly created encrypt stream. 89 | */ 90 | public function createEncryptStream(CipherParametersInterface $parameters) 91 | { 92 | return $this->encrypter()->createEncryptStream($parameters); 93 | } 94 | 95 | /** 96 | * Create a new decrypt stream. 97 | * 98 | * @param CipherParametersInterface $parameters The parameters to decrypt with. 99 | * 100 | * @return CipherStreamInterface The newly created decrypt stream. 101 | */ 102 | public function createDecryptStream(CipherParametersInterface $parameters) 103 | { 104 | return $this->decrypter()->createDecryptStream($parameters); 105 | } 106 | 107 | private $encrypter; 108 | private $decrypter; 109 | } 110 | -------------------------------------------------------------------------------- /src/AbstractDecrypter.php: -------------------------------------------------------------------------------- 1 | rawDecrypter = $rawDecrypter; 51 | $this->decoder = $decoder; 52 | $this->resultFactory = $resultFactory; 53 | } 54 | 55 | /** 56 | * Get the raw encrypter. 57 | * 58 | * @return DecrypterInterface The raw encrypter. 59 | */ 60 | public function rawDecrypter() 61 | { 62 | return $this->rawDecrypter; 63 | } 64 | 65 | /** 66 | * Get the decoder. 67 | * 68 | * @return DecoderInterface The decoder. 69 | */ 70 | public function decoder() 71 | { 72 | return $this->decoder; 73 | } 74 | 75 | /** 76 | * Get the result factory. 77 | * 78 | * @return CipherResultFactoryInterface The result factory. 79 | */ 80 | public function resultFactory() 81 | { 82 | return $this->resultFactory; 83 | } 84 | 85 | /** 86 | * Decrypt a data packet. 87 | * 88 | * @param CipherParametersInterface $parameters The parameters to decrypt with. 89 | * @param string $data The data to decrypt. 90 | * 91 | * @return CipherResultInterface The decrypt result. 92 | */ 93 | public function decrypt(CipherParametersInterface $parameters, $data) 94 | { 95 | try { 96 | $data = $this->decoder()->decode($data); 97 | } catch (EncodingExceptionInterface $e) { 98 | return $this->resultFactory() 99 | ->createResult(CipherResultType::INVALID_ENCODING()); 100 | } 101 | 102 | return $this->rawDecrypter()->decrypt($parameters, $data); 103 | } 104 | 105 | /** 106 | * Create a new decrypt stream. 107 | * 108 | * @param CipherParametersInterface $parameters The parameters to decrypt with. 109 | * 110 | * @return CipherStreamInterface The newly created decrypt stream. 111 | */ 112 | public function createDecryptStream(CipherParametersInterface $parameters) 113 | { 114 | $cipherStream = $this->rawDecrypter()->createDecryptStream($parameters); 115 | 116 | $decodeStream = $this->decoder()->createDecodeStream(); 117 | $decodeStream->pipe($cipherStream); 118 | 119 | return new CompositePreCipherStream($cipherStream, $decodeStream); 120 | } 121 | 122 | private $rawDecrypter; 123 | private $decoder; 124 | } 125 | -------------------------------------------------------------------------------- /src/AbstractEncrypter.php: -------------------------------------------------------------------------------- 1 | rawEncrypter = $rawEncrypter; 41 | $this->encoder = $encoder; 42 | } 43 | 44 | /** 45 | * Get the raw encrypter. 46 | * 47 | * @return EncrypterInterface The raw encrypter. 48 | */ 49 | public function rawEncrypter() 50 | { 51 | return $this->rawEncrypter; 52 | } 53 | 54 | /** 55 | * Get the encoder. 56 | * 57 | * @return EncoderInterface The encoder. 58 | */ 59 | public function encoder() 60 | { 61 | return $this->encoder; 62 | } 63 | 64 | /** 65 | * Encrypt a data packet. 66 | * 67 | * @param CipherParametersInterface $parameters The parameters to encrypt with. 68 | * @param string $data The data to encrypt. 69 | * 70 | * @return string The encrypted data. 71 | */ 72 | public function encrypt(CipherParametersInterface $parameters, $data) 73 | { 74 | return $this->encoder() 75 | ->encode($this->rawEncrypter()->encrypt($parameters, $data)); 76 | } 77 | 78 | /** 79 | * Create a new encrypt stream. 80 | * 81 | * @param CipherParametersInterface $parameters The parameters to encrypt with. 82 | * 83 | * @return CipherStreamInterface The newly created encrypt stream. 84 | */ 85 | public function createEncryptStream(CipherParametersInterface $parameters) 86 | { 87 | $encodeStream = $this->encoder()->createEncodeStream(); 88 | 89 | $cipherStream = $this->rawEncrypter()->createEncryptStream($parameters); 90 | $cipherStream->pipe($encodeStream); 91 | 92 | return new CompositePostCipherStream($cipherStream, $encodeStream); 93 | } 94 | 95 | private $rawEncrypter; 96 | private $encoder; 97 | } 98 | -------------------------------------------------------------------------------- /src/AbstractRawDecrypter.php: -------------------------------------------------------------------------------- 1 | cipherFactory = $cipherFactory; 33 | } 34 | 35 | /** 36 | * Get the cipher factory. 37 | * 38 | * @return CipherFactoryInterface The cipher factory. 39 | */ 40 | public function cipherFactory() 41 | { 42 | return $this->cipherFactory; 43 | } 44 | 45 | /** 46 | * Decrypt a data packet. 47 | * 48 | * @param CipherParametersInterface $parameters The parameters to decrypt with. 49 | * @param string $data The data to decrypt. 50 | * 51 | * @return CipherResultInterface The decrypt result. 52 | */ 53 | public function decrypt(CipherParametersInterface $parameters, $data) 54 | { 55 | $cipher = $this->cipherFactory()->createCipher(); 56 | $cipher->initialize($parameters); 57 | 58 | $data = $cipher->finalize($data); 59 | 60 | $result = $cipher->result(); 61 | if ($result->isSuccessful()) { 62 | $result->setData($data); 63 | } 64 | 65 | $cipher->deinitialize(); 66 | 67 | return $result; 68 | } 69 | 70 | /** 71 | * Create a new decrypt stream. 72 | * 73 | * @param CipherParametersInterface $parameters The parameters to decrypt with. 74 | * 75 | * @return CipherStreamInterface The newly created decrypt stream. 76 | */ 77 | public function createDecryptStream(CipherParametersInterface $parameters) 78 | { 79 | $cipher = $this->cipherFactory()->createCipher(); 80 | $cipher->initialize($parameters); 81 | 82 | return new CipherStream($cipher); 83 | } 84 | 85 | private $cipherFactory; 86 | } 87 | -------------------------------------------------------------------------------- /src/AbstractRawEncrypter.php: -------------------------------------------------------------------------------- 1 | cipherFactory = $cipherFactory; 32 | } 33 | 34 | /** 35 | * Get the cipher factory. 36 | * 37 | * @return CipherFactoryInterface The cipher factory. 38 | */ 39 | public function cipherFactory() 40 | { 41 | return $this->cipherFactory; 42 | } 43 | 44 | /** 45 | * Encrypt a data packet. 46 | * 47 | * @param CipherParametersInterface $parameters The parameters to encrypt with. 48 | * @param string $data The data to encrypt. 49 | * 50 | * @return string The encrypted data. 51 | */ 52 | public function encrypt(CipherParametersInterface $parameters, $data) 53 | { 54 | $cipher = $this->cipherFactory()->createCipher(); 55 | $cipher->initialize($parameters); 56 | 57 | $data = $cipher->finalize($data); 58 | $cipher->deinitialize(); 59 | 60 | return $data; 61 | } 62 | 63 | /** 64 | * Create a new encrypt stream. 65 | * 66 | * @param CipherParametersInterface $parameters The parameters to encrypt with. 67 | * 68 | * @return CipherStreamInterface The newly created encrypt stream. 69 | */ 70 | public function createEncryptStream(CipherParametersInterface $parameters) 71 | { 72 | $cipher = $this->cipherFactory()->createCipher(); 73 | $cipher->initialize($parameters); 74 | 75 | return new CipherStream($cipher); 76 | } 77 | 78 | private $cipherFactory; 79 | } 80 | -------------------------------------------------------------------------------- /src/Bound/AbstractBoundCrypter.php: -------------------------------------------------------------------------------- 1 | encryptParameters = $encryptParameters; 37 | $this->decryptParameters = $decryptParameters; 38 | $this->crypter = $crypter; 39 | } 40 | 41 | /** 42 | * Get the encrypt parameters. 43 | * 44 | * @return CipherParametersInterface The encrypt parameters. 45 | */ 46 | public function encryptParameters() 47 | { 48 | return $this->encryptParameters; 49 | } 50 | 51 | /** 52 | * Get the decrypt parameters. 53 | * 54 | * @return CipherParametersInterface The decrypt parameters. 55 | */ 56 | public function decryptParameters() 57 | { 58 | return $this->decryptParameters; 59 | } 60 | 61 | /** 62 | * Get the crypter. 63 | * 64 | * @return CrypterInterface The crypter. 65 | */ 66 | public function crypter() 67 | { 68 | return $this->crypter; 69 | } 70 | 71 | /** 72 | * Encrypt a data packet. 73 | * 74 | * @param string $data The data to encrypt. 75 | * 76 | * @return string The encrypted data. 77 | */ 78 | public function encrypt($data) 79 | { 80 | return $this->crypter()->encrypt($this->encryptParameters(), $data); 81 | } 82 | 83 | /** 84 | * Decrypt a data packet. 85 | * 86 | * @param string $data The data to decrypt. 87 | * 88 | * @return CipherResultInterface The decrypt result. 89 | */ 90 | public function decrypt($data) 91 | { 92 | return $this->crypter()->decrypt($this->decryptParameters(), $data); 93 | } 94 | 95 | /** 96 | * Create a new encrypt stream. 97 | * 98 | * @return CipherStreamInterface The newly created encrypt stream. 99 | */ 100 | public function createEncryptStream() 101 | { 102 | return $this->crypter() 103 | ->createEncryptStream($this->encryptParameters()); 104 | } 105 | 106 | /** 107 | * Create a new decrypt stream. 108 | * 109 | * @return CipherStreamInterface The newly created decrypt stream. 110 | */ 111 | public function createDecryptStream() 112 | { 113 | return $this->crypter() 114 | ->createDecryptStream($this->decryptParameters()); 115 | } 116 | 117 | private $encryptParameters; 118 | private $decryptParameters; 119 | private $crypter; 120 | } 121 | -------------------------------------------------------------------------------- /src/Bound/AbstractBoundDecrypter.php: -------------------------------------------------------------------------------- 1 | parameters = $parameters; 35 | $this->decrypter = $decrypter; 36 | } 37 | 38 | /** 39 | * Get the parameters. 40 | * 41 | * @return CipherParametersInterface The parameters. 42 | */ 43 | public function parameters() 44 | { 45 | return $this->parameters; 46 | } 47 | 48 | /** 49 | * Get the decrypter. 50 | * 51 | * @return DecrypterInterface The decrypter; 52 | */ 53 | public function decrypter() 54 | { 55 | return $this->decrypter; 56 | } 57 | 58 | /** 59 | * Decrypt a data packet. 60 | * 61 | * @param string $data The data to decrypt. 62 | * 63 | * @return CipherResultInterface The decrypt result. 64 | */ 65 | public function decrypt($data) 66 | { 67 | return $this->decrypter()->decrypt($this->parameters(), $data); 68 | } 69 | 70 | /** 71 | * Create a new decrypt stream. 72 | * 73 | * @return CipherStreamInterface The newly created decrypt stream. 74 | */ 75 | public function createDecryptStream() 76 | { 77 | return $this->decrypter()->createDecryptStream($this->parameters()); 78 | } 79 | 80 | private $parameters; 81 | private $decrypter; 82 | } 83 | -------------------------------------------------------------------------------- /src/Bound/AbstractBoundEncrypter.php: -------------------------------------------------------------------------------- 1 | parameters = $parameters; 34 | $this->encrypter = $encrypter; 35 | } 36 | 37 | /** 38 | * Get the parameters. 39 | * 40 | * @return CipherParametersInterface The parameters. 41 | */ 42 | public function parameters() 43 | { 44 | return $this->parameters; 45 | } 46 | 47 | /** 48 | * Get the encrypter. 49 | * 50 | * @return EncrypterInterface The encrypter; 51 | */ 52 | public function encrypter() 53 | { 54 | return $this->encrypter; 55 | } 56 | 57 | /** 58 | * Encrypt a data packet. 59 | * 60 | * @param string $data The data to encrypt. 61 | * 62 | * @return string The encrypted data. 63 | */ 64 | public function encrypt($data) 65 | { 66 | return $this->encrypter()->encrypt($this->parameters(), $data); 67 | } 68 | 69 | /** 70 | * Create a new encrypt stream. 71 | * 72 | * @return CipherStreamInterface The newly created encrypt stream. 73 | */ 74 | public function createEncryptStream() 75 | { 76 | return $this->encrypter()->createEncryptStream($this->parameters()); 77 | } 78 | 79 | private $parameters; 80 | private $encrypter; 81 | } 82 | -------------------------------------------------------------------------------- /src/Bound/BoundCrypter.php: -------------------------------------------------------------------------------- 1 | randomSource = $randomSource; 56 | $this->padder = $padder; 57 | $this->resultFactory = $resultFactory; 58 | 59 | $this->deinitialize(); 60 | } 61 | 62 | /** 63 | * Get the random source. 64 | * 65 | * @return RandomSourceInterface The random source. 66 | */ 67 | public function randomSource() 68 | { 69 | return $this->randomSource; 70 | } 71 | 72 | /** 73 | * Get the padder. 74 | * 75 | * @return PadderInterface The padder. 76 | */ 77 | public function padder() 78 | { 79 | return $this->padder; 80 | } 81 | 82 | /** 83 | * Get the result factory. 84 | * 85 | * @return CipherResultFactoryInterface The result factory. 86 | */ 87 | public function resultFactory() 88 | { 89 | return $this->resultFactory; 90 | } 91 | 92 | /** 93 | * Returns true if this cipher is initialized. 94 | * 95 | * @return boolean True if initialized. 96 | */ 97 | public function isInitialized() 98 | { 99 | return $this->isInitialized; 100 | } 101 | 102 | /** 103 | * Process the supplied input data. 104 | * 105 | * This method may be called repeatedly with additional data. 106 | * 107 | * @param string $input The data to process. 108 | * 109 | * @return string Any output produced. 110 | * @throws CipherStateExceptionInterface If the cipher is in an invalid state. 111 | */ 112 | public function process($input) 113 | { 114 | if (!$this->isInitialized) { 115 | throw new CipherNotInitializedException($this); 116 | } 117 | if ($this->isFinalized) { 118 | throw new CipherFinalizedException($this); 119 | } 120 | 121 | if ($this->isHeaderSent) { 122 | $output = ''; 123 | } else { 124 | $this->isHeaderSent = true; 125 | $output = $this->header; 126 | } 127 | 128 | $this->buffer .= $input; 129 | $size = strlen($this->buffer); 130 | $consume = $size - ($size % 16); 131 | 132 | if (!$consume) { 133 | return $output; 134 | } 135 | 136 | if ($consume === $size) { 137 | $input = $this->buffer; 138 | $this->buffer = ''; 139 | } else { 140 | list($input, $this->buffer) = str_split($this->buffer, $consume); 141 | } 142 | 143 | return $output . 144 | $this->authenticateBlocks( 145 | mcrypt_generic($this->mcryptModule, $input) 146 | ); 147 | } 148 | 149 | /** 150 | * Finalize processing and return any remaining output. 151 | * 152 | * @param string|null $input Any remaining data to process. 153 | * 154 | * @return string Any output produced. 155 | * @throws CipherStateExceptionInterface If the cipher is in an invalid state. 156 | */ 157 | public function finalize($input = null) 158 | { 159 | if (!$this->isInitialized) { 160 | throw new CipherNotInitializedException($this); 161 | } 162 | if ($this->isFinalized) { 163 | throw new CipherFinalizedException($this); 164 | } 165 | 166 | $this->isFinalized = true; 167 | 168 | if ($this->isHeaderSent) { 169 | $output = ''; 170 | } else { 171 | $this->isHeaderSent = true; 172 | $output = $this->header; 173 | } 174 | 175 | if (null !== $input) { 176 | $this->buffer .= $input; 177 | } 178 | $input = null; 179 | 180 | $output .= 181 | $this->authenticateBlocks( 182 | mcrypt_generic( 183 | $this->mcryptModule, 184 | $this->padder->pad($this->buffer) 185 | ) 186 | ) . 187 | hash_final($this->finalHashContext, true); 188 | 189 | $this->result = new CipherResult(CipherResultType::SUCCESS()); 190 | 191 | return $output; 192 | } 193 | 194 | /** 195 | * Returns true if this cipher is finalized. 196 | * 197 | * @return boolean True if finalized. 198 | */ 199 | public function isFinalized() 200 | { 201 | return $this->isFinalized; 202 | } 203 | 204 | /** 205 | * Returns true if this cipher has produced a result. 206 | * 207 | * @return boolean True if a result is available. 208 | */ 209 | public function hasResult() 210 | { 211 | return null !== $this->result; 212 | } 213 | 214 | /** 215 | * Get the result. 216 | * 217 | * @return CipherResultInterface|null The result, if available. 218 | */ 219 | public function result() 220 | { 221 | return $this->result; 222 | } 223 | 224 | /** 225 | * Reset this cipher to the state just after the last initialize() call. 226 | */ 227 | public function reset() 228 | { 229 | $this->isHeaderSent = $this->isFinalized = false; 230 | $this->result = null; 231 | $this->buffer = ''; 232 | 233 | if (null !== $this->mcryptModule) { 234 | if ($this->isMcryptInitialized) { 235 | mcrypt_generic_deinit($this->mcryptModule); 236 | } 237 | 238 | $this->isMcryptInitialized = true; 239 | mcrypt_generic_init( 240 | $this->mcryptModule, 241 | $this->key->encryptSecret(), 242 | $this->iv 243 | ); 244 | } 245 | 246 | if (null !== $this->hashContext) { 247 | $this->finalHashContext = hash_copy($this->hashContext); 248 | hash_update($this->finalHashContext, $this->header); 249 | } 250 | } 251 | 252 | /** 253 | * Reset this cipher to its initial state, and clear any sensitive data. 254 | */ 255 | public function deinitialize() 256 | { 257 | if ($this->isMcryptInitialized) { 258 | mcrypt_generic_deinit($this->mcryptModule); 259 | } 260 | 261 | unset($this->key); 262 | unset($this->iv); 263 | unset($this->header); 264 | unset($this->mcryptModule); 265 | unset($this->hashContext); 266 | unset($this->finalHashContext); 267 | unset($this->buffer); 268 | unset($this->result); 269 | 270 | $this->key = $this->iv = $this->header = $this->mcryptModule = 271 | $this->hashContext = $this->finalHashContext = $this->result = null; 272 | $this->isInitialized = $this->isHeaderSent = $this->isFinalized = 273 | $this->isMcryptInitialized = false; 274 | $this->buffer = ''; 275 | } 276 | 277 | /** 278 | * Initialize this cipher. 279 | * 280 | * @param KeyInterface $key The key to use. 281 | * @param string|null $iv The initialization vector to use, or null to generate one. 282 | */ 283 | protected function doInitialize(KeyInterface $key, $iv = null) 284 | { 285 | if (null === $iv) { 286 | $iv = $this->randomSource()->generate(16); 287 | } 288 | 289 | $this->isInitialized = true; 290 | $this->key = $key; 291 | $this->iv = $iv; 292 | $this->header = $this->header($this->iv); 293 | 294 | $this->mcryptModule = mcrypt_module_open( 295 | MCRYPT_RIJNDAEL_128, 296 | '', 297 | MCRYPT_MODE_CBC, 298 | '' 299 | ); 300 | $this->isMcryptInitialized = false; 301 | 302 | $this->hashContext = hash_init( 303 | 'sha' . $key->authSecretBits(), 304 | HASH_HMAC, 305 | $key->authSecret() 306 | ); 307 | 308 | $this->reset(); 309 | } 310 | 311 | /** 312 | * Get the encryption header. 313 | * 314 | * @param string $iv The initialization vector. 315 | * 316 | * @return string The header. 317 | */ 318 | abstract protected function header($iv); 319 | 320 | private function authenticateBlocks($output) 321 | { 322 | $authenticated = ''; 323 | foreach (str_split($output, 16) as $block) { 324 | $hashContext = hash_copy($this->hashContext); 325 | hash_update($hashContext, $block); 326 | hash_update($this->finalHashContext, $block); 327 | 328 | $authenticated .= $block . 329 | substr(hash_final($hashContext, true), 0, 2); 330 | } 331 | 332 | return $authenticated; 333 | } 334 | 335 | private $randomSource; 336 | private $padder; 337 | private $resultFactory; 338 | private $isInitialized; 339 | private $isHeaderSent; 340 | private $isFinalized; 341 | private $key; 342 | private $iv; 343 | private $header; 344 | private $mcryptModule; 345 | private $isMcryptInitialized; 346 | private $hashContext; 347 | private $finalHashContext; 348 | private $buffer; 349 | private $result; 350 | } 351 | -------------------------------------------------------------------------------- /src/Cipher/CipherInterface.php: -------------------------------------------------------------------------------- 1 | doInitialize($parameters->key(), $parameters->iv()); 35 | } elseif ($parameters instanceof KeyInterface) { 36 | $this->doInitialize($parameters); 37 | } else { 38 | throw new UnsupportedCipherParametersException($this, $parameters); 39 | } 40 | } 41 | 42 | /** 43 | * Get the encryption header. 44 | * 45 | * @param string $iv The initialization vector. 46 | * 47 | * @return string The header. 48 | */ 49 | protected function header($iv) 50 | { 51 | return chr(1) . chr(1) . $iv; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Cipher/Exception/CipherFinalizedException.php: -------------------------------------------------------------------------------- 1 | cipher = $cipher; 34 | 35 | parent::__construct('The cipher is already finalized.', 0, $cause); 36 | } 37 | 38 | /** 39 | * Get the cipher. 40 | * 41 | * @return CipherInterface The cipher. 42 | */ 43 | public function cipher() 44 | { 45 | return $this->cipher; 46 | } 47 | 48 | private $cipher; 49 | } 50 | -------------------------------------------------------------------------------- /src/Cipher/Exception/CipherNotInitializedException.php: -------------------------------------------------------------------------------- 1 | cipher = $cipher; 34 | 35 | parent::__construct('The cipher is not initialized.', 0, $cause); 36 | } 37 | 38 | /** 39 | * Get the cipher. 40 | * 41 | * @return CipherInterface The cipher. 42 | */ 43 | public function cipher() 44 | { 45 | return $this->cipher; 46 | } 47 | 48 | private $cipher; 49 | } 50 | -------------------------------------------------------------------------------- /src/Cipher/Exception/CipherStateExceptionInterface.php: -------------------------------------------------------------------------------- 1 | cipher = $cipher; 36 | $this->parameters = $parameters; 37 | 38 | parent::__construct( 39 | sprintf( 40 | 'Cipher of type %s does not support parameters of type %s.', 41 | var_export(get_class($cipher), true), 42 | var_export(get_class($parameters), true) 43 | ), 44 | 0, 45 | $cause 46 | ); 47 | } 48 | 49 | /** 50 | * Get the cipher. 51 | * 52 | * @return CipherInterface The cipher. 53 | */ 54 | public function cipher() 55 | { 56 | return $this->cipher; 57 | } 58 | 59 | /** 60 | * Get the parameters. 61 | * 62 | * @return CipherParametersInterface The parameters. 63 | */ 64 | public function parameters() 65 | { 66 | return $this->parameters; 67 | } 68 | 69 | private $cipher; 70 | private $parameters; 71 | } 72 | -------------------------------------------------------------------------------- /src/Cipher/Factory/CipherFactoryInterface.php: -------------------------------------------------------------------------------- 1 | unpadder = $unpadder; 58 | $this->resultFactory = $resultFactory; 59 | } 60 | 61 | /** 62 | * Get the unpadder. 63 | * 64 | * @return UnpadderInterface The unpadder. 65 | */ 66 | public function unpadder() 67 | { 68 | return $this->unpadder; 69 | } 70 | 71 | /** 72 | * Get the result factory. 73 | * 74 | * @return CipherResultFactoryInterface The result factory. 75 | */ 76 | public function resultFactory() 77 | { 78 | return $this->resultFactory; 79 | } 80 | 81 | /** 82 | * Create a new cipher. 83 | * 84 | * @return CipherInterface The newly created cipher. 85 | */ 86 | public function createCipher() 87 | { 88 | return new DecryptCipher($this->unpadder(), $this->resultFactory()); 89 | } 90 | 91 | private static $instance; 92 | private $randomSource; 93 | private $unpadder; 94 | private $resultFactory; 95 | } 96 | -------------------------------------------------------------------------------- /src/Cipher/Factory/EncryptCipherFactory.php: -------------------------------------------------------------------------------- 1 | randomSource = $randomSource; 65 | $this->padder = $padder; 66 | $this->resultFactory = $resultFactory; 67 | } 68 | 69 | /** 70 | * Get the random source. 71 | * 72 | * @return RandomSourceInterface The random source. 73 | */ 74 | public function randomSource() 75 | { 76 | return $this->randomSource; 77 | } 78 | 79 | /** 80 | * Get the padder. 81 | * 82 | * @return PadderInterface The padder. 83 | */ 84 | public function padder() 85 | { 86 | return $this->padder; 87 | } 88 | 89 | /** 90 | * Get the result factory. 91 | * 92 | * @return CipherResultFactoryInterface The result factory. 93 | */ 94 | public function resultFactory() 95 | { 96 | return $this->resultFactory; 97 | } 98 | 99 | /** 100 | * Create a new cipher. 101 | * 102 | * @return CipherInterface The newly created cipher. 103 | */ 104 | public function createCipher() 105 | { 106 | return new EncryptCipher( 107 | $this->randomSource(), 108 | $this->padder(), 109 | $this->resultFactory() 110 | ); 111 | } 112 | 113 | private static $instance; 114 | private $randomSource; 115 | private $padder; 116 | private $resultFactory; 117 | } 118 | -------------------------------------------------------------------------------- /src/Cipher/Parameters/CipherParametersInterface.php: -------------------------------------------------------------------------------- 1 | key = $key; 30 | $this->iv = $iv; 31 | } 32 | 33 | /** 34 | * Get the key. 35 | * 36 | * @return KeyInterface The key. 37 | */ 38 | public function key() 39 | { 40 | return $this->key; 41 | } 42 | 43 | /** 44 | * Get the initialization vector. 45 | * 46 | * @return string|null The initialization vector, or null if none was specified. 47 | */ 48 | public function iv() 49 | { 50 | return $this->iv; 51 | } 52 | 53 | /** 54 | * Erase these parameters, removing any sensitive data. 55 | */ 56 | public function erase() 57 | { 58 | $this->key()->erase(); 59 | 60 | unset($this->iv); 61 | $this->iv = null; 62 | } 63 | 64 | private $key; 65 | private $iv; 66 | } 67 | -------------------------------------------------------------------------------- /src/Cipher/Parameters/EncryptParametersInterface.php: -------------------------------------------------------------------------------- 1 | type = $type; 28 | $this->data = $data; 29 | } 30 | 31 | /** 32 | * Get the result type. 33 | * 34 | * @return CipherResultType The result type. 35 | */ 36 | public function type() 37 | { 38 | return $this->type; 39 | } 40 | 41 | /** 42 | * Returns true if this result is successful. 43 | * 44 | * @return boolean True if successful. 45 | */ 46 | public function isSuccessful() 47 | { 48 | return $this->type()->isSuccessful(); 49 | } 50 | 51 | /** 52 | * Set the data. 53 | * 54 | * @param string|null $data The data, or null if unavailable. 55 | */ 56 | public function setData($data) 57 | { 58 | $this->data = $data; 59 | } 60 | 61 | /** 62 | * Get the data. 63 | * 64 | * This method will return null for unsuccessful and/or streaming results. 65 | * 66 | * @return string|null The data, or null if unavailable. 67 | */ 68 | public function data() 69 | { 70 | return $this->data; 71 | } 72 | 73 | private $type; 74 | private $isSuccessful; 75 | private $data; 76 | } 77 | -------------------------------------------------------------------------------- /src/Cipher/Result/CipherResult.php: -------------------------------------------------------------------------------- 1 | isSuccessful; 29 | } 30 | 31 | /** 32 | * Initialize the available cipher result types. 33 | */ 34 | protected static function initializeMembers() 35 | { 36 | new static('SUCCESS', true); // Indicates a successful result. 37 | 38 | new static('INVALID_SIZE', false); // The input data was an invalid size and could not be processed. 39 | new static('INVALID_ENCODING', false); // The input data was not encoded, or the encoding was invalid. 40 | new static('INVALID_MAC', false); // One or more message authentication codes were invalid. 41 | new static('UNSUPPORTED_VERSION', false); // An unsupported version identifier was encountered. 42 | new static('UNSUPPORTED_TYPE', false); // An unsupported type identifier was encountered. 43 | new static('INVALID_PADDING', false); // The input data was not correctly padded. 44 | new static('TOO_MANY_ITERATIONS', false); // The requested number of hash iterations exceeded the configured limit. 45 | } 46 | 47 | /** 48 | * Construct a new cipher result type. 49 | * 50 | * @param string $key The result key. 51 | * @param boolean $isSuccessful True if this result type indicates a successful result. 52 | */ 53 | protected function __construct($key, $isSuccessful) 54 | { 55 | parent::__construct($key); 56 | 57 | $this->isSuccessful = $isSuccessful; 58 | } 59 | 60 | private $isSuccessful; 61 | } 62 | -------------------------------------------------------------------------------- /src/Cipher/Result/Factory/CipherResultFactory.php: -------------------------------------------------------------------------------- 1 | randomSource = $randomSource; 62 | $this->factory = $factory; 63 | } 64 | 65 | /** 66 | * Get the random source. 67 | * 68 | * @return RandomSourceInterface The random source. 69 | */ 70 | public function randomSource() 71 | { 72 | return $this->randomSource; 73 | } 74 | 75 | /** 76 | * Get the factory. 77 | * 78 | * @return KeyFactoryInterface The factory. 79 | */ 80 | public function factory() 81 | { 82 | return $this->factory; 83 | } 84 | 85 | /** 86 | * Derive a key from a password. 87 | * 88 | * @param PasswordInterface $password The password. 89 | * @param integer $iterations The number of hash iterations to use. 90 | * @param string|null $salt The salt to use, or null to generate a random salt. 91 | * @param string|null $name The name. 92 | * @param string|null $description The description. 93 | * 94 | * @return tuple A 2-tuple of the derived key, and the salt used. 95 | * @throws InvalidKeyParameterExceptionInterface If the supplied arguments are invalid. 96 | */ 97 | public function deriveKeyFromPassword( 98 | PasswordInterface $password, 99 | $iterations, 100 | $salt = null, 101 | $name = null, 102 | $description = null 103 | ) { 104 | if (!is_int($iterations) || $iterations < 1) { 105 | throw new InvalidIterationsException($iterations); 106 | } 107 | 108 | if (null === $salt) { 109 | $salt = $this->randomSource()->generate(64); 110 | } else { 111 | if (!is_string($salt)) { 112 | throw new InvalidSaltException($salt); 113 | } 114 | 115 | $saltSize = strlen($salt); 116 | if (64 !== $saltSize) { 117 | throw new InvalidSaltSizeException($saltSize * 8); 118 | } 119 | } 120 | 121 | list($encryptSecret, $authSecret) = str_split( 122 | hash_pbkdf2( 123 | 'sha512', 124 | $password->string(), 125 | $salt, 126 | $iterations, 127 | 64, 128 | true 129 | ), 130 | 32 131 | ); 132 | 133 | return array( 134 | $this->factory() 135 | ->createKey($encryptSecret, $authSecret, $name, $description), 136 | $salt, 137 | ); 138 | } 139 | 140 | private static $instance; 141 | private $randomSource; 142 | private $factory; 143 | } 144 | -------------------------------------------------------------------------------- /src/Key/Deriver/KeyDeriverInterface.php: -------------------------------------------------------------------------------- 1 | A 2-tuple of the derived key, and the salt used. 33 | * @throws InvalidKeyParameterExceptionInterface If the supplied arguments are invalid. 34 | */ 35 | public function deriveKeyFromPassword( 36 | PasswordInterface $password, 37 | $iterations, 38 | $salt = null, 39 | $name = null, 40 | $description = null 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/Key/Exception/InvalidAuthSecretSizeException.php: -------------------------------------------------------------------------------- 1 | size = $size; 31 | 32 | parent::__construct( 33 | sprintf( 34 | 'Invalid auth secret size %d. ' . 35 | 'Auth secret must be 224, 256, 384, or 512 bits.', 36 | $size 37 | ), 38 | 0, 39 | $cause 40 | ); 41 | } 42 | 43 | /** 44 | * Get the invalid secret size. 45 | * 46 | * @return integer The size. 47 | */ 48 | public function size() 49 | { 50 | return $this->size; 51 | } 52 | 53 | private $size; 54 | } 55 | -------------------------------------------------------------------------------- /src/Key/Exception/InvalidEncryptSecretSizeException.php: -------------------------------------------------------------------------------- 1 | size = $size; 31 | 32 | parent::__construct( 33 | sprintf( 34 | 'Invalid encrypt secret size %d. ' . 35 | 'Encrypt secret must be 128, 192, or 256 bits.', 36 | $size 37 | ), 38 | 0, 39 | $cause 40 | ); 41 | } 42 | 43 | /** 44 | * Get the invalid secret size. 45 | * 46 | * @return integer The size. 47 | */ 48 | public function size() 49 | { 50 | return $this->size; 51 | } 52 | 53 | private $size; 54 | } 55 | -------------------------------------------------------------------------------- /src/Key/Exception/InvalidIterationsException.php: -------------------------------------------------------------------------------- 1 | iterations = $iterations; 31 | 32 | parent::__construct( 33 | sprintf('Invalid iterations %s.', var_export($iterations, true)), 34 | 0, 35 | $cause 36 | ); 37 | } 38 | 39 | /** 40 | * Get the invalid iterations. 41 | * 42 | * @return mixed The iterations. 43 | */ 44 | public function iterations() 45 | { 46 | return $this->iterations; 47 | } 48 | 49 | private $iterations; 50 | } 51 | -------------------------------------------------------------------------------- /src/Key/Exception/InvalidKeyParameterExceptionInterface.php: -------------------------------------------------------------------------------- 1 | salt = $salt; 31 | 32 | parent::__construct( 33 | sprintf('Invalid salt %s.', var_export($salt, true)), 34 | 0, 35 | $cause 36 | ); 37 | } 38 | 39 | /** 40 | * Get the invalid salt. 41 | * 42 | * @return mixed The salt. 43 | */ 44 | public function salt() 45 | { 46 | return $this->salt; 47 | } 48 | 49 | private $salt; 50 | } 51 | -------------------------------------------------------------------------------- /src/Key/Exception/InvalidSaltSizeException.php: -------------------------------------------------------------------------------- 1 | size = $size; 31 | 32 | parent::__construct( 33 | sprintf('Invalid salt size %d. Salt must be 512 bits.', $size), 34 | 0, 35 | $cause 36 | ); 37 | } 38 | 39 | /** 40 | * Get the invalid salt size. 41 | * 42 | * @return string The size. 43 | */ 44 | public function size() 45 | { 46 | return $this->size; 47 | } 48 | 49 | private $size; 50 | } 51 | -------------------------------------------------------------------------------- /src/Key/Exception/InvalidSecretException.php: -------------------------------------------------------------------------------- 1 | secret = $secret; 31 | 32 | parent::__construct( 33 | sprintf('Invalid secret %s.', var_export($secret, true)), 34 | 0, 35 | $cause 36 | ); 37 | } 38 | 39 | /** 40 | * Get the invalid secret. 41 | * 42 | * @return mixed The secret. 43 | */ 44 | public function secret() 45 | { 46 | return $this->secret; 47 | } 48 | 49 | private $secret; 50 | } 51 | -------------------------------------------------------------------------------- /src/Key/Factory/KeyFactory.php: -------------------------------------------------------------------------------- 1 | randomSource = $randomSource; 60 | $this->factory = $factory; 61 | } 62 | 63 | /** 64 | * Get the random source. 65 | * 66 | * @return RandomSourceInterface The random source. 67 | */ 68 | public function randomSource() 69 | { 70 | return $this->randomSource; 71 | } 72 | 73 | /** 74 | * Get the factory. 75 | * 76 | * @return KeyFactoryInterface The factory. 77 | */ 78 | public function factory() 79 | { 80 | return $this->factory; 81 | } 82 | 83 | /** 84 | * Generate a new key. 85 | * 86 | * @param string|null $name The name. 87 | * @param string|null $description The description. 88 | * @param integer|null $encryptSecretBits The size of the encrypt secret in bits. 89 | * @param integer|null $authSecretBits The size of the auth secret in bits. 90 | * 91 | * @return KeyInterface The generated key. 92 | * @throws InvalidKeyParameterExceptionInterface If the supplied arguments are invalid. 93 | */ 94 | public function generateKey( 95 | $name = null, 96 | $description = null, 97 | $encryptSecretBits = null, 98 | $authSecretBits = null 99 | ) { 100 | if (null === $encryptSecretBits) { 101 | $encryptSecretBits = 256; 102 | } 103 | if (null === $authSecretBits) { 104 | $authSecretBits = 256; 105 | } 106 | 107 | switch ($encryptSecretBits) { 108 | case 256: 109 | case 192: 110 | case 128: 111 | break; 112 | 113 | default: 114 | throw new InvalidEncryptSecretSizeException($encryptSecretBits); 115 | } 116 | 117 | switch ($authSecretBits) { 118 | case 512: 119 | case 384: 120 | case 256: 121 | case 224: 122 | break; 123 | 124 | default: 125 | throw new InvalidAuthSecretSizeException($authSecretBits); 126 | } 127 | 128 | return $this->factory()->createKey( 129 | $this->randomSource()->generate($encryptSecretBits / 8), 130 | $this->randomSource()->generate($authSecretBits / 8), 131 | $name, 132 | $description 133 | ); 134 | } 135 | 136 | private static $instance; 137 | private $randomSource; 138 | private $factory; 139 | } 140 | -------------------------------------------------------------------------------- /src/Key/Generator/KeyGeneratorInterface.php: -------------------------------------------------------------------------------- 1 | encryptSecret = $encryptSecret; 73 | $this->encryptSecretBytes = $encryptSecretBytes; 74 | $this->encryptSecretBits = $encryptSecretBits; 75 | $this->authSecret = $authSecret; 76 | $this->authSecretBytes = $authSecretBytes; 77 | $this->authSecretBits = $authSecretBits; 78 | $this->name = $name; 79 | $this->description = $description; 80 | } 81 | 82 | /** 83 | * Get the encrypt secret. 84 | * 85 | * @return string The encrypt secret. 86 | */ 87 | public function encryptSecret() 88 | { 89 | return $this->encryptSecret; 90 | } 91 | 92 | /** 93 | * Get the size of the encrypt secret in bytes. 94 | * 95 | * @return integer The size of the encrypt secret in bytes. 96 | */ 97 | public function encryptSecretBytes() 98 | { 99 | return $this->encryptSecretBytes; 100 | } 101 | 102 | /** 103 | * Get the size of the encrypt secret in bits. 104 | * 105 | * @return integer The size of the encrypt secret in bits. 106 | */ 107 | public function encryptSecretBits() 108 | { 109 | return $this->encryptSecretBits; 110 | } 111 | 112 | /** 113 | * Get the auth secret. 114 | * 115 | * @return string The auth secret. 116 | */ 117 | public function authSecret() 118 | { 119 | return $this->authSecret; 120 | } 121 | 122 | /** 123 | * Get the size of the auth secret in bytes. 124 | * 125 | * @return integer The size of the auth secret in bytes. 126 | */ 127 | public function authSecretBytes() 128 | { 129 | return $this->authSecretBytes; 130 | } 131 | 132 | /** 133 | * Get the size of the auth secret in bits. 134 | * 135 | * @return integer The size of the auth secret in bits. 136 | */ 137 | public function authSecretBits() 138 | { 139 | return $this->authSecretBits; 140 | } 141 | 142 | /** 143 | * Get the name. 144 | * 145 | * @return string|null The name, or null if the key has no name. 146 | */ 147 | public function name() 148 | { 149 | return $this->name; 150 | } 151 | 152 | /** 153 | * Get the description. 154 | * 155 | * @return string|null The description, or null if the key has no description. 156 | */ 157 | public function description() 158 | { 159 | return $this->description; 160 | } 161 | 162 | /** 163 | * Erase these parameters, removing any sensitive data. 164 | */ 165 | public function erase() 166 | { 167 | unset($this->encryptSecret); 168 | unset($this->authSecret); 169 | unset($this->name); 170 | unset($this->description); 171 | $this->encryptSecret = str_repeat("\0", $this->encryptSecretBytes); 172 | $this->authSecret = str_repeat("\0", $this->authSecretBytes); 173 | $this->name = $this->description = null; 174 | } 175 | 176 | private $encryptSecret; 177 | private $encryptSecretBytes; 178 | private $encryptSecretBits; 179 | private $authSecret; 180 | private $authSecretBytes; 181 | private $authSecretBits; 182 | private $name; 183 | private $description; 184 | } 185 | -------------------------------------------------------------------------------- /src/Key/KeyInterface.php: -------------------------------------------------------------------------------- 1 | path = $path; 30 | 31 | if (null === $path) { 32 | $message = 'Unable to read key.'; 33 | } else { 34 | $message = sprintf( 35 | 'Unable to read key from %s.', 36 | var_export($path, true) 37 | ); 38 | } 39 | 40 | parent::__construct($message, 0, $cause); 41 | } 42 | 43 | /** 44 | * Get the path. 45 | * 46 | * @return string|null The path, if known. 47 | */ 48 | public function path() 49 | { 50 | return $this->path; 51 | } 52 | 53 | private $path; 54 | } 55 | -------------------------------------------------------------------------------- /src/Key/Persistence/Exception/KeyWriteException.php: -------------------------------------------------------------------------------- 1 | path = $path; 30 | 31 | if (null === $path) { 32 | $message = 'Unable to write key to stream.'; 33 | } else { 34 | $message = sprintf( 35 | 'Unable to write key to %s.', 36 | var_export($path, true) 37 | ); 38 | } 39 | 40 | parent::__construct($message, 0, $cause); 41 | } 42 | 43 | /** 44 | * Get the path. 45 | * 46 | * @return string|null The path, if known. 47 | */ 48 | public function path() 49 | { 50 | return $this->path; 51 | } 52 | 53 | private $path; 54 | } 55 | -------------------------------------------------------------------------------- /src/Key/Persistence/KeyReaderInterface.php: -------------------------------------------------------------------------------- 1 | encrypter = $encrypter; 63 | $this->encoder = $encoder; 64 | $this->isolator = Isolator::get($isolator); 65 | } 66 | 67 | /** 68 | * Get the encrypter. 69 | * 70 | * @return EncrypterInterface The encrypter. 71 | */ 72 | public function encrypter() 73 | { 74 | return $this->encrypter; 75 | } 76 | 77 | /** 78 | * Get the encoder. 79 | * 80 | * @return EncoderInterface The encoder. 81 | */ 82 | public function encoder() 83 | { 84 | return $this->encoder; 85 | } 86 | 87 | /** 88 | * Write a key to the supplied path. 89 | * 90 | * @param KeyInterface $key The key. 91 | * @param string $path The path to write to. 92 | * 93 | * @throws KeyWriteException If the key cannot be written. 94 | */ 95 | public function writeFile(KeyInterface $key, $path) 96 | { 97 | $keyString = $this->writeString($key); 98 | 99 | if (@!$this->isolator()->file_put_contents($path, $keyString)) { 100 | throw new KeyWriteException($path); 101 | } 102 | } 103 | 104 | /** 105 | * Write a key, encrypted with a password, to the supplied path. 106 | * 107 | * @param KeyInterface $key The key. 108 | * @param PasswordEncryptParametersInterface $parameters The encrypt parameters. 109 | * @param string $path The path to write to. 110 | * 111 | * @throws KeyWriteException If the key cannot be written. 112 | */ 113 | public function writeFileWithPassword( 114 | KeyInterface $key, 115 | PasswordEncryptParametersInterface $parameters, 116 | $path 117 | ) { 118 | $keyString = $this->writeStringWithPassword($key, $parameters); 119 | 120 | if (@!$this->isolator()->file_put_contents($path, $keyString)) { 121 | throw new KeyWriteException($path); 122 | } 123 | } 124 | 125 | /** 126 | * Write a key to the supplied stream. 127 | * 128 | * @param KeyInterface $key The key. 129 | * @param stream $stream The stream to write to. 130 | * @param string|null $path The path, if known. 131 | * 132 | * @throws KeyWriteException If the key cannot be written. 133 | */ 134 | public function writeStream(KeyInterface $key, $stream, $path = null) 135 | { 136 | $result = @fwrite($stream, $this->writeString($key)); 137 | if (!$result) { 138 | throw new KeyWriteException($path); 139 | } 140 | } 141 | 142 | /** 143 | * Write a key, encrypted with a password, to the supplied stream. 144 | * 145 | * @param KeyInterface $key The key. 146 | * @param PasswordEncryptParametersInterface $parameters The encrypt parameters. 147 | * @param stream $stream The stream to write to. 148 | * @param string|null $path The path, if known. 149 | * 150 | * @throws KeyWriteException If the key cannot be written. 151 | */ 152 | public function writeStreamWithPassword( 153 | KeyInterface $key, 154 | PasswordEncryptParametersInterface $parameters, 155 | $stream, 156 | $path = null 157 | ) { 158 | $result = 159 | @fwrite($stream, $this->writeStringWithPassword($key, $parameters)); 160 | if (!$result) { 161 | throw new KeyWriteException($path); 162 | } 163 | } 164 | 165 | /** 166 | * Write a key to a string. 167 | * 168 | * @param KeyInterface $key The key. 169 | * 170 | * @return string The key string. 171 | */ 172 | public function writeString(KeyInterface $key) 173 | { 174 | $data = "{\n"; 175 | 176 | if (null !== $key->name()) { 177 | $data .= ' "name": ' . json_encode($key->name()) . ",\n"; 178 | } 179 | if (null !== $key->description()) { 180 | $data .= ' "description": ' . json_encode($key->description()) . 181 | ",\n"; 182 | } 183 | 184 | $data .= " \"type\": \"lockbox-key\",\n \"version\": 1,\n"; 185 | 186 | $data .= ' "encryptSecret": ' . 187 | json_encode($this->encoder()->encode($key->encryptSecret())) . 188 | ",\n"; 189 | $data .= ' "authSecret": ' . 190 | json_encode($this->encoder()->encode($key->authSecret())) . "\n"; 191 | 192 | return $data . "}\n"; 193 | } 194 | 195 | /** 196 | * Write a key, encrypted with a password, to a string. 197 | * 198 | * @param KeyInterface $key The key. 199 | * @param PasswordEncryptParametersInterface $parameters The encrypt parameters. 200 | * 201 | * @return string The key string. 202 | */ 203 | public function writeStringWithPassword( 204 | KeyInterface $key, 205 | PasswordEncryptParametersInterface $parameters 206 | ) { 207 | return chunk_split( 208 | $this->encrypter() 209 | ->encrypt($parameters, $this->writeString($key)), 210 | 64, 211 | "\n" 212 | ); 213 | } 214 | 215 | /** 216 | * Get the isolator. 217 | * 218 | * @return Isolator The isolator. 219 | */ 220 | protected function isolator() 221 | { 222 | return $this->isolator; 223 | } 224 | 225 | private static $instance; 226 | private $encrypter; 227 | private $encoder; 228 | private $isolator; 229 | } 230 | -------------------------------------------------------------------------------- /src/Key/Persistence/KeyWriterInterface.php: -------------------------------------------------------------------------------- 1 | stream_filter_register( 31 | 'lockbox.encrypt', 32 | 'Eloquent\Lockbox\Stream\Filter\EncryptStreamFilter' 33 | ); 34 | $isolator->stream_filter_register( 35 | 'lockbox.decrypt', 36 | 'Eloquent\Lockbox\Stream\Filter\DecryptStreamFilter' 37 | ); 38 | $isolator->stream_filter_register( 39 | 'lockbox.password-encrypt', 40 | 'Eloquent\Lockbox\Password\Stream\Filter' . 41 | '\PasswordEncryptStreamFilter' 42 | ); 43 | $isolator->stream_filter_register( 44 | 'lockbox.password-decrypt', 45 | 'Eloquent\Lockbox\Password\Stream\Filter' . 46 | '\PasswordDecryptStreamFilter' 47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Padding/Exception/InvalidBlockSizeException.php: -------------------------------------------------------------------------------- 1 | blockSize = $blockSize; 30 | 31 | parent::__construct( 32 | sprintf('Invalid block size %s.', var_export($blockSize, true)), 33 | 0, 34 | $cause 35 | ); 36 | } 37 | 38 | /** 39 | * Get the invalid block size. 40 | * 41 | * @return mixed The block size. 42 | */ 43 | public function blockSize() 44 | { 45 | return $this->blockSize; 46 | } 47 | 48 | private $blockSize; 49 | } 50 | -------------------------------------------------------------------------------- /src/Padding/PadderInterface.php: -------------------------------------------------------------------------------- 1 | 255) { 51 | throw new InvalidBlockSizeException($blockSize); 52 | } 53 | 54 | $this->blockSize = $blockSize; 55 | } 56 | 57 | /** 58 | * Get the block size. 59 | * 60 | * @return integer The block size in bytes. 61 | */ 62 | public function blockSize() 63 | { 64 | return $this->blockSize; 65 | } 66 | 67 | /** 68 | * Pad a data packet to a specific block size. 69 | * 70 | * @param string $data The data to pad. 71 | * 72 | * @return string The padded data. 73 | */ 74 | public function pad($data) 75 | { 76 | $blockSize = $this->blockSize(); 77 | $padSize = intval($blockSize - (strlen($data) % $blockSize)); 78 | $padChar = chr($padSize); 79 | 80 | $padded = $dummy = $data; 81 | for ($i = 0; $i < $blockSize; $i ++) { 82 | if ($i < $padSize) { 83 | $padded .= $padChar; 84 | } else { 85 | $dummy .= $padChar; 86 | } 87 | } 88 | 89 | return $padded; 90 | } 91 | 92 | /** 93 | * Remove padding from the supplied data. 94 | * 95 | * @param string $data The padded data. 96 | * 97 | * @return tuple A 2-tuple containing a boolean true if successful, and the data, which will be unpadded if successful. 98 | */ 99 | public function unpad($data) 100 | { 101 | $dataSize = strlen($data); 102 | $blockSize = $this->blockSize(); 103 | 104 | if (0 === $dataSize) { 105 | $padSize = ord(substr("\x10", $dataSize - 0, 1)); 106 | } else { 107 | $padSize = ord(substr($data, $dataSize - 1, 1)); 108 | } 109 | 110 | if ($padSize > $blockSize) { 111 | $padSize = $blockSize + 0; 112 | } else { 113 | $padSize = $padSize + 0; 114 | } 115 | if ($padSize <= 0) { 116 | $padSize = $blockSize + 0; 117 | } else { 118 | $padSize = $padSize + 0; 119 | } 120 | 121 | $padIndex = $dataSize - $padSize; 122 | $padChar = chr($padSize); 123 | 124 | $diff = 0; 125 | $dummyDiff = 0; 126 | $unpadded = ''; 127 | $dummyUnpadded = ''; 128 | $actualPadSize = 0; 129 | $dummyActualPadSize = 0; 130 | for ($i = 0; $i < $dataSize; $i ++) { 131 | if ($i < $padIndex) { 132 | $dummyDiff |= ord($data[$i]) ^ $padSize; 133 | $unpadded .= $data[$i]; 134 | $dummyActualPadSize++; 135 | } else { 136 | $diff |= ord($data[$i]) ^ $padSize; 137 | $dummyUnpadded .= $data[$i]; 138 | $actualPadSize++; 139 | } 140 | } 141 | 142 | $isSuccessful = 0 === $diff; 143 | $dummyIsSuccessful = true; 144 | if ($isSuccessful) { 145 | $isSuccessful = $actualPadSize === $padSize; 146 | } else { 147 | $dummyIsSuccessful = $actualPadSize === $padSize; 148 | } 149 | 150 | if ($isSuccessful) { 151 | $finalData = $unpadded; 152 | } else { 153 | $finalData = $data; 154 | } 155 | 156 | return array($isSuccessful, $finalData); 157 | } 158 | 159 | private static $instance; 160 | private $blockSize; 161 | } 162 | -------------------------------------------------------------------------------- /src/Padding/UnpadderInterface.php: -------------------------------------------------------------------------------- 1 | A 2-tuple containing a boolean true if successful, and the data, which will be unpadded if successful. 25 | */ 26 | public function unpad($data); 27 | } 28 | -------------------------------------------------------------------------------- /src/Password/Bound/BoundPasswordCrypter.php: -------------------------------------------------------------------------------- 1 | maxIterations = $maxIterations; 71 | $this->keyDeriver = $keyDeriver; 72 | $this->unpadder = $unpadder; 73 | $this->resultFactory = $resultFactory; 74 | } 75 | 76 | /** 77 | * Get the maximum number of hash iterations. 78 | * 79 | * @return integer The maximum iterations. 80 | */ 81 | public function maxIterations() 82 | { 83 | return $this->maxIterations; 84 | } 85 | 86 | /** 87 | * Get the key deriver. 88 | * 89 | * @return KeyDeriverInterface The key deriver. 90 | */ 91 | public function keyDeriver() 92 | { 93 | return $this->keyDeriver; 94 | } 95 | 96 | /** 97 | * Get the unpadder. 98 | * 99 | * @return UnpadderInterface The unpadder. 100 | */ 101 | public function unpadder() 102 | { 103 | return $this->unpadder; 104 | } 105 | 106 | /** 107 | * Get the result factory. 108 | * 109 | * @return CipherResultFactoryInterface The result factory. 110 | */ 111 | public function resultFactory() 112 | { 113 | return $this->resultFactory; 114 | } 115 | 116 | /** 117 | * Create a new cipher. 118 | * 119 | * @return CipherInterface The newly created cipher. 120 | */ 121 | public function createCipher() 122 | { 123 | return new PasswordDecryptCipher( 124 | $this->maxIterations(), 125 | $this->keyDeriver(), 126 | $this->unpadder(), 127 | $this->resultFactory() 128 | ); 129 | } 130 | 131 | private static $instance; 132 | private $maxIterations; 133 | private $keyDeriver; 134 | private $unpadder; 135 | private $resultFactory; 136 | } 137 | -------------------------------------------------------------------------------- /src/Password/Cipher/Factory/PasswordEncryptCipherFactory.php: -------------------------------------------------------------------------------- 1 | randomSource = $randomSource; 73 | $this->keyDeriver = $keyDeriver; 74 | $this->padder = $padder; 75 | $this->resultFactory = $resultFactory; 76 | } 77 | 78 | /** 79 | * Get the random source. 80 | * 81 | * @return RandomSourceInterface The random source. 82 | */ 83 | public function randomSource() 84 | { 85 | return $this->randomSource; 86 | } 87 | 88 | /** 89 | * Get the key deriver. 90 | * 91 | * @return KeyDeriverInterface The key deriver. 92 | */ 93 | public function keyDeriver() 94 | { 95 | return $this->keyDeriver; 96 | } 97 | 98 | /** 99 | * Get the padder. 100 | * 101 | * @return PadderInterface The padder. 102 | */ 103 | public function padder() 104 | { 105 | return $this->padder; 106 | } 107 | 108 | /** 109 | * Get the result factory. 110 | * 111 | * @return CipherResultFactoryInterface The result factory. 112 | */ 113 | public function resultFactory() 114 | { 115 | return $this->resultFactory; 116 | } 117 | 118 | /** 119 | * Create a new cipher. 120 | * 121 | * @return CipherInterface The newly created cipher. 122 | */ 123 | public function createCipher() 124 | { 125 | return new PasswordEncryptCipher( 126 | $this->randomSource(), 127 | $this->keyDeriver(), 128 | $this->padder(), 129 | $this->resultFactory() 130 | ); 131 | } 132 | 133 | private static $instance; 134 | private $randomSource; 135 | private $keyDeriver; 136 | private $padder; 137 | private $resultFactory; 138 | } 139 | -------------------------------------------------------------------------------- /src/Password/Cipher/Parameters/PasswordEncryptParameters.php: -------------------------------------------------------------------------------- 1 | password = Password::adapt($password); 37 | $this->iterations = $iterations; 38 | $this->salt = $salt; 39 | $this->iv = $iv; 40 | } 41 | 42 | /** 43 | * Get the password. 44 | * 45 | * @return PasswordInterface The password. 46 | */ 47 | public function password() 48 | { 49 | return $this->password; 50 | } 51 | 52 | /** 53 | * Get the number of hash iterations. 54 | * 55 | * @return integer The number of hash iterations. 56 | */ 57 | public function iterations() 58 | { 59 | return $this->iterations; 60 | } 61 | 62 | /** 63 | * Get the salt to use for key derivation. 64 | * 65 | * @return string|null The salt to use for key derivation, or null if none was specified. 66 | */ 67 | public function salt() 68 | { 69 | return $this->salt; 70 | } 71 | 72 | /** 73 | * Get the initialization vector. 74 | * 75 | * @return string|null The initialization vector, or null if none was specified. 76 | */ 77 | public function iv() 78 | { 79 | return $this->iv; 80 | } 81 | 82 | /** 83 | * Erase these parameters, removing any sensitive data. 84 | */ 85 | public function erase() 86 | { 87 | $this->password()->erase(); 88 | 89 | unset($this->salt); 90 | unset($this->iv); 91 | $this->salt = $this->iv = null; 92 | $this->iterations = 1; 93 | } 94 | 95 | private $password; 96 | private $iterations; 97 | private $salt; 98 | private $iv; 99 | } 100 | -------------------------------------------------------------------------------- /src/Password/Cipher/Parameters/PasswordEncryptParametersInterface.php: -------------------------------------------------------------------------------- 1 | keyDeriver = $keyDeriver; 50 | } 51 | 52 | /** 53 | * Get the key deriver. 54 | * 55 | * @return KeyDeriverInterface The key deriver. 56 | */ 57 | public function keyDeriver() 58 | { 59 | return $this->keyDeriver; 60 | } 61 | 62 | /** 63 | * Initialize this cipher. 64 | * 65 | * @param CipherParametersInterface $parameters The parameters to use. 66 | * 67 | * @throws UnsupportedCipherParametersException If unsupported parameters are supplied. 68 | */ 69 | public function initialize(CipherParametersInterface $parameters) 70 | { 71 | if (!$parameters instanceof PasswordEncryptParametersInterface) { 72 | throw new UnsupportedCipherParametersException($this, $parameters); 73 | } 74 | 75 | $this->iterations = $parameters->iterations(); 76 | 77 | list($key, $this->salt) = $this->keyDeriver()->deriveKeyFromPassword( 78 | $parameters->password(), 79 | $this->iterations, 80 | $parameters->salt() 81 | ); 82 | 83 | $this->doInitialize($key, $parameters->iv()); 84 | } 85 | 86 | /** 87 | * Reset this cipher to its initial state, and clear any sensitive data. 88 | */ 89 | public function deinitialize() 90 | { 91 | parent::deinitialize(); 92 | 93 | unset($this->iterations); 94 | unset($this->salt); 95 | 96 | $this->iterations = $this->salt = null; 97 | } 98 | 99 | /** 100 | * Get the encryption header. 101 | * 102 | * @param string $iv The initialization vector. 103 | * 104 | * @return string The header. 105 | */ 106 | protected function header($iv) 107 | { 108 | return chr(1) . chr(2) . pack('N', $this->iterations) . $this->salt . 109 | $iv; 110 | } 111 | 112 | private $keyDeriver; 113 | private $iterations; 114 | private $salt; 115 | } 116 | -------------------------------------------------------------------------------- /src/Password/Cipher/Result/Factory/PasswordDecryptResultFactory.php: -------------------------------------------------------------------------------- 1 | iterations = $iterations; 38 | } 39 | 40 | /** 41 | * Set the number of hash iterations used. 42 | * 43 | * @param integer|null $iterations The hash iterations, or null if unsuccessful. 44 | */ 45 | public function setIterations($iterations) 46 | { 47 | $this->iterations = $iterations; 48 | } 49 | 50 | /** 51 | * Get the number of hash iterations used. 52 | * 53 | * @return integer|null The hash iterations, or null if unsuccessful. 54 | */ 55 | public function iterations() 56 | { 57 | return $this->iterations; 58 | } 59 | 60 | private $iterations; 61 | } 62 | -------------------------------------------------------------------------------- /src/Password/Cipher/Result/PasswordDecryptResultInterface.php: -------------------------------------------------------------------------------- 1 | password = $password; 30 | 31 | parent::__construct( 32 | sprintf('Invalid password %s.', var_export($password, true)), 33 | 0, 34 | $cause 35 | ); 36 | } 37 | 38 | /** 39 | * Get the invalid password. 40 | * 41 | * @return mixed The password. 42 | */ 43 | public function password() 44 | { 45 | return $this->password; 46 | } 47 | 48 | private $password; 49 | } 50 | -------------------------------------------------------------------------------- /src/Password/Password.php: -------------------------------------------------------------------------------- 1 | password = $password; 50 | } 51 | 52 | /** 53 | * Get the string representation of this password. 54 | * 55 | * @return string The password string. 56 | */ 57 | public function string() 58 | { 59 | return $this->password; 60 | } 61 | 62 | /** 63 | * Get the string representation of this password. 64 | * 65 | * @return string The password string. 66 | */ 67 | public function __toString() 68 | { 69 | return $this->string(); 70 | } 71 | 72 | /** 73 | * Erase these parameters, removing any sensitive data. 74 | */ 75 | public function erase() 76 | { 77 | unset($this->password); 78 | $this->password = ''; 79 | } 80 | 81 | private $password; 82 | } 83 | -------------------------------------------------------------------------------- /src/Password/PasswordCrypter.php: -------------------------------------------------------------------------------- 1 | source = $source; 33 | $this->isolator = Isolator::get($isolator); 34 | } 35 | 36 | /** 37 | * Get the random source. 38 | * 39 | * @return integer The random source. 40 | */ 41 | public function source() 42 | { 43 | return $this->source; 44 | } 45 | 46 | /** 47 | * Generate random data. 48 | * 49 | * @param integer $size The data size in bytes. 50 | * 51 | * @return string The random data. 52 | */ 53 | public function generate($size) 54 | { 55 | return $this->isolator()->mcrypt_create_iv($size, $this->source()); 56 | } 57 | 58 | /** 59 | * Get the isolator. 60 | * 61 | * @return Isolator The isolator. 62 | */ 63 | protected function isolator() 64 | { 65 | return $this->isolator; 66 | } 67 | 68 | private $source; 69 | private $isolator; 70 | } 71 | -------------------------------------------------------------------------------- /src/Random/DevRandom.php: -------------------------------------------------------------------------------- 1 | cipher = $cipher; 33 | 34 | $this->isClosed = $this->isPaused = $this->hasError = false; 35 | $this->buffer = ''; 36 | } 37 | 38 | /** 39 | * Get the cipher. 40 | * 41 | * @return CipherInterface The cipher. 42 | */ 43 | public function cipher() 44 | { 45 | return $this->cipher; 46 | } 47 | 48 | /** 49 | * Returns true if this stream is writable. 50 | * 51 | * @return boolean True if writable. 52 | */ 53 | public function isWritable() 54 | { 55 | return !$this->isClosed; 56 | } 57 | 58 | /** 59 | * Returns true if this stream is readable. 60 | * 61 | * @return boolean True if readable. 62 | */ 63 | public function isReadable() 64 | { 65 | return !$this->isClosed; 66 | } 67 | 68 | /** 69 | * Write some data to be processed. 70 | * 71 | * @param string $data The data to process. 72 | * 73 | * @return boolean True if this stream is ready for more data. 74 | */ 75 | public function write($data) 76 | { 77 | if ($this->isClosed) { 78 | $this->emit( 79 | 'error', 80 | array(new StreamClosedException($this), $this) 81 | ); 82 | 83 | return false; 84 | } 85 | 86 | $this->buffer .= $data; 87 | 88 | if ($this->isPaused) { 89 | return false; 90 | } 91 | 92 | $output = $this->cipher->process($this->buffer); 93 | $this->buffer = ''; 94 | 95 | if ('' !== $output) { 96 | $this->emit('data', array($output, $this)); 97 | } 98 | 99 | if ($result = $this->cipher->result()) { 100 | if (!$result->isSuccessful()) { 101 | $this->hasError = true; 102 | $this->emit('error', array($result, $this)); 103 | 104 | $this->doClose(); 105 | } 106 | } 107 | 108 | return !$this->hasError; 109 | } 110 | 111 | /** 112 | * Process and finalize any remaining buffered data. 113 | * 114 | * @param string|null $data Additional data to process before finalizing. 115 | */ 116 | public function end($data = null) 117 | { 118 | if ($this->isClosed) { 119 | return; 120 | } 121 | 122 | $this->isClosed = true; 123 | 124 | if (null !== $data) { 125 | $this->buffer .= $data; 126 | } 127 | 128 | $output = $this->cipher->finalize($this->buffer); 129 | $this->buffer = ''; 130 | 131 | if ('' !== $output) { 132 | $this->emit('data', array($output, $this)); 133 | } 134 | 135 | if ($result = $this->cipher->result()) { 136 | if (!$result->isSuccessful()) { 137 | $this->hasError = true; 138 | $this->emit('error', array($result, $this)); 139 | } 140 | } 141 | 142 | $this->doClose(); 143 | } 144 | 145 | /** 146 | * Close this stream. 147 | */ 148 | public function close() 149 | { 150 | if ($this->isClosed) { 151 | return; 152 | } 153 | 154 | $this->doClose(); 155 | } 156 | 157 | /** 158 | * Pause this stream. 159 | */ 160 | public function pause() 161 | { 162 | $this->isPaused = true; 163 | } 164 | 165 | /** 166 | * Resume this stream. 167 | */ 168 | public function resume() 169 | { 170 | $this->isPaused = false; 171 | $this->write(''); 172 | } 173 | 174 | /** 175 | * Pipe the output of this stream to another stream. 176 | * 177 | * @param WritableStreamInterface $destination The destination stream. 178 | * @param array $options A set of options for the piping process. 179 | * 180 | * @return WritableStreamInterface The destination stream. 181 | */ 182 | public function pipe( 183 | WritableStreamInterface $destination, 184 | array $options = array() 185 | ) { 186 | Util::pipe($this, $destination, $options); 187 | 188 | return $destination; 189 | } 190 | 191 | /** 192 | * Get the result. 193 | * 194 | * @return CipherResultInterface|null The result, if available. 195 | */ 196 | public function result() 197 | { 198 | return $this->cipher()->result(); 199 | } 200 | 201 | private function doClose() 202 | { 203 | $this->isClosed = true; 204 | $this->isPaused = false; 205 | $this->buffer = ''; 206 | 207 | $this->emit('end', array($this)); 208 | $this->emit('close', array($this)); 209 | 210 | if (!$this->hasError) { 211 | $this->emit('success', array($this)); 212 | } 213 | 214 | $this->cipher->deinitialize(); 215 | } 216 | 217 | private $cipher; 218 | private $isClosed; 219 | private $isPaused; 220 | private $hasError; 221 | private $buffer; 222 | } 223 | -------------------------------------------------------------------------------- /src/Stream/CipherStreamInterface.php: -------------------------------------------------------------------------------- 1 | writable; 50 | } 51 | 52 | /** 53 | * Get the readable stream. 54 | * 55 | * @return ReadableStreamInterface The readable stream. 56 | */ 57 | public function readable() 58 | { 59 | return $this->readable; 60 | } 61 | 62 | /** 63 | * Get the cipher. 64 | * 65 | * @return CipherInterface The cipher. 66 | */ 67 | public function cipher() 68 | { 69 | return $this->cipherStream()->cipher(); 70 | } 71 | 72 | /** 73 | * Get the result. 74 | * 75 | * @return CipherResultInterface|null The result, if available. 76 | */ 77 | public function result() 78 | { 79 | return $this->cipherStream()->result(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Stream/CompositePreCipherStream.php: -------------------------------------------------------------------------------- 1 | readable; 50 | } 51 | 52 | /** 53 | * Get the writable stream. 54 | * 55 | * @return WritableStreamInterface The writable stream. 56 | */ 57 | public function writable() 58 | { 59 | return $this->writable; 60 | } 61 | 62 | /** 63 | * Get the cipher. 64 | * 65 | * @return CipherInterface The cipher. 66 | */ 67 | public function cipher() 68 | { 69 | return $this->cipherStream()->cipher(); 70 | } 71 | 72 | /** 73 | * Get the result. 74 | * 75 | * @return CipherResultInterface|null The result, if available. 76 | */ 77 | public function result() 78 | { 79 | return $this->cipherStream()->result(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Stream/Exception/StreamClosedException.php: -------------------------------------------------------------------------------- 1 | stream = $stream; 32 | 33 | parent::__construct('The stream is closed.', 0, $cause); 34 | } 35 | 36 | /** 37 | * Get the stream. 38 | * 39 | * @return ReadableStreamInterface|WritableStreamInterface The stream. 40 | */ 41 | public function stream() 42 | { 43 | return $this->stream; 44 | } 45 | 46 | private $stream; 47 | } 48 | -------------------------------------------------------------------------------- /src/Stream/Filter/AbstractCipherStreamFilter.php: -------------------------------------------------------------------------------- 1 | cipher = $this->createCipher(); 28 | $this->cipher->initialize($this->params); 29 | 30 | return true; 31 | } 32 | 33 | /** 34 | * Filter the input data through the transform. 35 | * 36 | * @param resource $input The input bucket brigade. 37 | * @param resource $output The output bucket brigade. 38 | * @param integer &$consumed The number of bytes consumed. 39 | * @param boolean $isEnd True if the stream is closing. 40 | * 41 | * @return integer The result code. 42 | */ 43 | public function filter($input, $output, &$consumed, $isEnd) 44 | { 45 | $bucket = stream_bucket_make_writeable($input); 46 | if ($isEnd && !$bucket) { 47 | $bucket = stream_bucket_new(STDIN, ''); 48 | } 49 | 50 | $hasOutput = false; 51 | while ($bucket) { 52 | if ($isEnd) { 53 | $outputBuffer = $this->cipher->finalize($bucket->data); 54 | } else { 55 | $outputBuffer = $this->cipher->process($bucket->data); 56 | } 57 | 58 | if ('' !== $outputBuffer) { 59 | $bucket->data = $outputBuffer; 60 | stream_bucket_append($output, $bucket); 61 | $hasOutput = true; 62 | } 63 | 64 | if ( 65 | $this->cipher->hasResult() && 66 | !$this->cipher->result()->isSuccessful() 67 | ) { 68 | $this->cipher->deinitialize(); 69 | 70 | return PSFS_ERR_FATAL; 71 | } 72 | 73 | $bucket = stream_bucket_make_writeable($input); 74 | } 75 | 76 | if ($isEnd) { 77 | $this->cipher->deinitialize(); 78 | } 79 | 80 | if ($hasOutput || $isEnd) { 81 | return PSFS_PASS_ON; 82 | } 83 | 84 | return PSFS_FEED_ME; 85 | } 86 | 87 | /** 88 | * Create the cipher. 89 | * 90 | * @return CipherInterface The cipher. 91 | */ 92 | abstract protected function createCipher(); 93 | 94 | private $cipher; 95 | } 96 | -------------------------------------------------------------------------------- /src/Stream/Filter/DecryptStreamFilter.php: -------------------------------------------------------------------------------- 1 |