You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
5.1 KiB

<?php
/**
* Copyright 2005-2008 Matthew Fonda <mfonda@php.net>
* Copyright 2012-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (LGPL). If you
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @author Matthew Fonda <mfonda@php.net>
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Crypt_Blowfish
*/
/**
* Provides blowfish encryption/decryption, with or without a secret key,
* for PHP strings.
*
* @author Matthew Fonda <mfonda@php.net>
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @copyright 2005-2008 Matthew Fonda
* @copyright 2012-2017 Horde LLC
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @package Crypt_Blowfish
*
* @property string $cipher The cipher block mode ('ecb' or 'cbc').
* @property string $key The encryption key in use.
* @property mixed $iv The initialization vector (false if using 'ecb').
*/
class Horde_Crypt_Blowfish
{
// Constants for 'ignore' parameter of constructor.
const IGNORE_OPENSSL = 1;
const IGNORE_MCRYPT = 2;
// Block size for Blowfish
const BLOCKSIZE = 8;
// Maximum key size for Blowfish
const MAXKEYSIZE = 56;
// IV Length for CBC
const IV_LENGTH = 8;
/**
* Blowfish crypt driver.
*
* @var Horde_Crypt_Blowfish_Base
*/
protected $_crypt;
/**
* Constructor.
*
* @param string $key Encryption key.
* @param array $opts Additional options:
* - cipher: (string) Either 'ecb' or 'cbc'.
* - ignore: (integer) A mask of drivers to ignore (IGNORE_* constants).
* - iv: (string) IV to use.
*/
public function __construct($key, array $opts = array())
{
$opts = array_merge(array(
'cipher' => 'ecb',
'ignore' => 0,
'iv' => null
), $opts);
if (!($opts['ignore'] & self::IGNORE_OPENSSL) &&
Horde_Crypt_Blowfish_Openssl::supported()) {
$this->_crypt = new Horde_Crypt_Blowfish_Openssl($opts['cipher']);
} elseif (!($opts['ignore'] & self::IGNORE_MCRYPT) &&
Horde_Crypt_Blowfish_Mcrypt::supported()) {
$this->_crypt = new Horde_Crypt_Blowfish_Mcrypt($opts['cipher']);
} else {
$this->_crypt = new Horde_Crypt_Blowfish_Php($opts['cipher']);
}
$this->setKey($key, $opts['iv']);
}
/**
*/
public function __get($name)
{
switch ($name) {
case 'cipher':
case 'key':
case 'iv':
return $this->_crypt->$name;
}
}
/**
* Encrypts a string.
*
* @param string $text The string to encrypt.
*
* @return string The ciphertext.
* @throws Horde_Crypt_Blowfish_Exception
*/
public function encrypt($text)
{
if (!is_string($text)) {
throw new Horde_Crypt_Blowfish_Exception('Data to encrypt must be a string.');
}
return $this->_crypt->encrypt($text);
}
/**
* Decrypts a string.
*
* @param string $text The string to decrypt.
*
* @return string The plaintext.
* @throws Horde_Crypt_Blowfish_Exception
*/
public function decrypt($text)
{
if (!is_string($text)) {
throw new Horde_Crypt_Blowfish_Exception('Data to decrypt must be a string.');
}
return $this->_crypt->decrypt($text);
}
/**
* Sets the secret key.
*
* The key must be non-zero, and less than or equal to MAXKEYSIZE
* characters (bytes) in length.
*
* @param string $key Key must be non-empty and less than MAXKEYSIZE
* bytes in length.
* @param string $iv The initialization vector to use. Only needed for
* 'cbc' cipher. If null, an IV is automatically
* generated.
*
* @throws Horde_Crypt_Blowfish_Exception
*/
public function setKey($key, $iv = null)
{
if (!is_string($key)) {
throw new Horde_Crypt_Blowfish_Exception('Encryption key must be a string.');
}
$len = strlen($key);
if (($len > self::MAXKEYSIZE) || ($len == 0)) {
throw new Horde_Crypt_Blowfish_Exception(sprintf('Encryption key must be less than %d characters (bytes) and non-zero. Supplied key length: %d', self::MAXKEYSIZE, $len));
}
$this->_crypt->key = $key;
switch ($this->_crypt->cipher) {
case 'cbc':
if (is_null($iv)) {
if (is_null($this->iv)) {
$this->_crypt->setIv();
}
} else {
$iv = substr($iv, 0, self::IV_LENGTH);
if (($len = strlen($iv)) < self::IV_LENGTH) {
$iv .= str_repeat(chr(0), self::IV_LENGTH - $len);
}
$this->_crypt->setIv($iv);
}
break;
case 'ecb':
$this->iv = false;
break;
}
}
}