- <?php
- /**
- * Zend Framework (http://framework.zend.com/)
- *
- * @link http://github.com/zendframework/zf2 for the canonical source repository
- * @copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
- * @license http://framework.zend.com/license/new-bsd New BSD License
- */
-
- namespace Zend\Crypt;
-
- use Zend\Crypt\Key\Derivation\Pbkdf2;
- use Zend\Crypt\Symmetric\SymmetricInterface;
- use Zend\Math\Rand;
-
- /**
- * Encrypt using a symmetric cipher then authenticate using HMAC (SHA-256)
- */
- class BlockCipher
- {
- const KEY_DERIV_HMAC = 'sha256';
-
- /**
- * Symmetric cipher
- *
- * @var SymmetricInterface
- */
- protected $cipher;
-
- /**
- * Symmetric cipher plugin manager
- *
- * @var SymmetricPluginManager
- */
- protected static $symmetricPlugins = null;
-
- /**
- * Hash algorithm fot HMAC
- *
- * @var string
- */
- protected $hash = 'sha256';
-
- /**
- * Check if the salt has been set
- *
- * @var bool
- */
- protected $saltSetted = false;
-
- /**
- * The output is binary?
- *
- * @var bool
- */
- protected $binaryOutput = false;
-
- /**
- * Number of iterations for Pbkdf2
- *
- * @var string
- */
- protected $keyIteration = 5000;
-
- /**
- * Key
- *
- * @var string
- */
- protected $key;
-
- /**
- * Constructor
- *
- * @param SymmetricInterface $cipher
- */
- public function __construct(SymmetricInterface $cipher)
- {
- $this->cipher = $cipher;
- }
-
- /**
- * Factory.
- *
- * @param string $adapter
- * @param array $options
- * @return BlockCipher
- */
- public static function factory($adapter, $options = array())
- {
- $plugins = static::getSymmetricPluginManager();
- $adapter = $plugins->get($adapter, (array) $options);
-
- return new static($adapter);
- }
-
- /**
- * Returns the symmetric cipher plugin manager. If it doesn't exist it's created.
- *
- * @return SymmetricPluginManager
- */
- public static function getSymmetricPluginManager()
- {
- if (static::$symmetricPlugins === null) {
- static::setSymmetricPluginManager(new SymmetricPluginManager());
- }
-
- return static::$symmetricPlugins;
- }
-
- /**
- * Set the symmetric cipher plugin manager
- *
- * @param string|SymmetricPluginManager $plugins
- * @throws Exception\InvalidArgumentException
- */
- public static function setSymmetricPluginManager($plugins)
- {
- if (is_string($plugins)) {
- if (!class_exists($plugins)) {
- throw new Exception\InvalidArgumentException(sprintf(
- 'Unable to locate symmetric cipher plugins using class "%s"; class does not exist',
- $plugins
- ));
- }
- $plugins = new $plugins();
- }
- if (!$plugins instanceof SymmetricPluginManager) {
- throw new Exception\InvalidArgumentException(sprintf(
- 'Expected an instance or extension of %s\SymmetricPluginManager; received "%s"',
- __NAMESPACE__,
- (is_object($plugins) ? get_class($plugins) : gettype($plugins))
- ));
- }
- static::$symmetricPlugins = $plugins;
- }
-
- /**
- * Set the symmetric cipher
- *
- * @param SymmetricInterface $cipher
- * @return BlockCipher
- */
- public function setCipher(SymmetricInterface $cipher)
- {
- $this->cipher = $cipher;
- return $this;
- }
-
- /**
- * Get symmetric cipher
- *
- * @return SymmetricInterface
- */
- public function getCipher()
- {
- return $this->cipher;
- }
-
- /**
- * Set the number of iterations for Pbkdf2
- *
- * @param int $num
- * @return BlockCipher
- */
- public function setKeyIteration($num)
- {
- $this->keyIteration = (int) $num;
-
- return $this;
- }
-
- /**
- * Get the number of iterations for Pbkdf2
- *
- * @return int
- */
- public function getKeyIteration()
- {
- return $this->keyIteration;
- }
-
- /**
- * Set the salt (IV)
- *
- * @param string $salt
- * @return BlockCipher
- * @throws Exception\InvalidArgumentException
- */
- public function setSalt($salt)
- {
- try {
- $this->cipher->setSalt($salt);
- } catch (Symmetric\Exception\InvalidArgumentException $e) {
- throw new Exception\InvalidArgumentException("The salt is not valid: " . $e->getMessage());
- }
- $this->saltSetted = true;
-
- return $this;
- }
-
- /**
- * Get the salt (IV) according to the size requested by the algorithm
- *
- * @return string
- */
- public function getSalt()
- {
- return $this->cipher->getSalt();
- }
-
- /**
- * Get the original salt value
- *
- * @return string
- */
- public function getOriginalSalt()
- {
- return $this->cipher->getOriginalSalt();
- }
-
- /**
- * Enable/disable the binary output
- *
- * @param bool $value
- * @return BlockCipher
- */
- public function setBinaryOutput($value)
- {
- $this->binaryOutput = (bool) $value;
-
- return $this;
- }
-
- /**
- * Get the value of binary output
- *
- * @return bool
- */
- public function getBinaryOutput()
- {
- return $this->binaryOutput;
- }
-
- /**
- * Set the encryption/decryption key
- *
- * @param string $key
- * @return BlockCipher
- * @throws Exception\InvalidArgumentException
- */
- public function setKey($key)
- {
- if (empty($key)) {
- throw new Exception\InvalidArgumentException('The key cannot be empty');
- }
- $this->key = $key;
-
- return $this;
- }
-
- /**
- * Get the key
- *
- * @return string
- */
- public function getKey()
- {
- return $this->key;
- }
-
- /**
- * Set algorithm of the symmetric cipher
- *
- * @param string $algo
- * @return BlockCipher
- * @throws Exception\InvalidArgumentException
- */
- public function setCipherAlgorithm($algo)
- {
- if (empty($this->cipher)) {
- throw new Exception\InvalidArgumentException('No symmetric cipher specified');
- }
- try {
- $this->cipher->setAlgorithm($algo);
- } catch (Symmetric\Exception\InvalidArgumentException $e) {
- throw new Exception\InvalidArgumentException($e->getMessage());
- }
-
- return $this;
- }
-
- /**
- * Get the cipher algorithm
- *
- * @return string|bool
- */
- public function getCipherAlgorithm()
- {
- if (!empty($this->cipher)) {
- return $this->cipher->getAlgorithm();
- }
-
- return false;
- }
-
- /**
- * Get the supported algorithms of the symmetric cipher
- *
- * @return array
- */
- public function getCipherSupportedAlgorithms()
- {
- if (!empty($this->cipher)) {
- return $this->cipher->getSupportedAlgorithms();
- }
-
- return array();
- }
-
- /**
- * Set the hash algorithm for HMAC authentication
- *
- * @param string $hash
- * @return BlockCipher
- * @throws Exception\InvalidArgumentException
- */
- public function setHashAlgorithm($hash)
- {
- if (!Hash::isSupported($hash)) {
- throw new Exception\InvalidArgumentException(
- "The specified hash algorithm '{$hash}' is not supported by Zend\Crypt\Hash"
- );
- }
- $this->hash = $hash;
-
- return $this;
- }
-
- /**
- * Get the hash algorithm for HMAC authentication
- *
- * @return string
- */
- public function getHashAlgorithm()
- {
- return $this->hash;
- }
-
- /**
- * Encrypt then authenticate using HMAC
- *
- * @param string $data
- * @return string
- * @throws Exception\InvalidArgumentException
- */
- public function encrypt($data)
- {
- // 0 (as integer), 0.0 (as float) & '0' (as string) will return false, though these should be allowed
- if (!is_string($data) || $data === '') {
- throw new Exception\InvalidArgumentException('The data to encrypt cannot be empty');
- }
- if (empty($this->cipher)) {
- throw new Exception\InvalidArgumentException('No symmetric cipher specified');
- }
- if (empty($this->key)) {
- throw new Exception\InvalidArgumentException('No key specified for the encryption');
- }
- $keySize = $this->cipher->getKeySize();
- // generate a random salt (IV) if the salt has not been set
- if (!$this->saltSetted) {
- $this->cipher->setSalt(Rand::getBytes($this->cipher->getSaltSize(), true));
- }
- // generate the encryption key and the HMAC key for the authentication
- $hash = Pbkdf2::calc(self::KEY_DERIV_HMAC,
- $this->getKey(),
- $this->getSalt(),
- $this->keyIteration,
- $keySize * 2);
- // set the encryption key
- $this->cipher->setKey(substr($hash, 0, $keySize));
- // set the key for HMAC
- $keyHmac = substr($hash, $keySize);
- // encryption
- $ciphertext = $this->cipher->encrypt($data);
- // HMAC
- $hmac = Hmac::compute($keyHmac,
- $this->hash,
- $this->cipher->getAlgorithm() . $ciphertext);
- if (!$this->binaryOutput) {
- $ciphertext = base64_encode($ciphertext);
- }
-
- return $hmac . $ciphertext;
- }
-
- /**
- * Decrypt
- *
- * @param string $data
- * @return string|bool
- * @throws Exception\InvalidArgumentException
- */
- public function decrypt($data)
- {
- if (!is_string($data)) {
- throw new Exception\InvalidArgumentException('The data to decrypt must be a string');
- }
- if ('' === $data) {
- throw new Exception\InvalidArgumentException('The data to decrypt cannot be empty');
- }
- if (empty($this->key)) {
- throw new Exception\InvalidArgumentException('No key specified for the decryption');
- }
- if (empty($this->cipher)) {
- throw new Exception\InvalidArgumentException('No symmetric cipher specified');
- }
- $hmacSize = Hmac::getOutputSize($this->hash);
- $hmac = substr($data, 0, $hmacSize);
- $ciphertext = substr($data, $hmacSize);
- if (!$this->binaryOutput) {
- $ciphertext = base64_decode($ciphertext);
- }
- $iv = substr($ciphertext, 0, $this->cipher->getSaltSize());
- $keySize = $this->cipher->getKeySize();
- // generate the encryption key and the HMAC key for the authentication
- $hash = Pbkdf2::calc(self::KEY_DERIV_HMAC,
- $this->getKey(),
- $iv,
- $this->keyIteration,
- $keySize * 2);
- // set the decryption key
- $this->cipher->setKey(substr($hash, 0, $keySize));
- // set the key for HMAC
- $keyHmac = substr($hash, $keySize);
- $hmacNew = Hmac::compute($keyHmac,
- $this->hash,
- $this->cipher->getAlgorithm() . $ciphertext);
- if (!Utils::compareStrings($hmacNew, $hmac)) {
- return false;
- }
-
- return $this->cipher->decrypt($ciphertext);
- }
- }
# |
Change |
User |
Description |
Committed |
|
#1
|
18334 |
Liz Lam |
initial add of jambox |
9 years ago
|
|