3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\Crypt\PublicKey
;
13 use Zend\Crypt\PublicKey\Rsa\Exception
;
14 use Zend\Crypt\PublicKey\RsaOptions
;
15 use Zend\Stdlib\ArrayUtils
;
18 * Implementation of the RSA public key encryption algorithm.
23 const MODE_BASE64
= 2;
29 protected $options = null;
32 * RSA instance factory
34 * @param array|Traversable $options
36 * @throws Rsa\Exception\RuntimeException
37 * @throws Rsa\Exception\InvalidArgumentException
39 public static function factory($options)
41 if (!extension_loaded('openssl')) {
42 throw new Exception\
RuntimeException(
43 'Can not create Zend\Crypt\PublicKey\Rsa; openssl extension to be loaded'
47 if ($options instanceof Traversable
) {
48 $options = ArrayUtils
::iteratorToArray($options);
49 } elseif (!is_array($options)) {
50 throw new Exception\
InvalidArgumentException(
51 'The options parameter must be an array or a Traversable'
56 $passPhrase = isset($options['pass_phrase']) ?
$options['pass_phrase'] : null;
57 if (isset($options['private_key'])) {
58 if (is_file($options['private_key'])) {
59 $privateKey = Rsa\PrivateKey
::fromFile($options['private_key'], $passPhrase);
60 } elseif (is_string($options['private_key'])) {
61 $privateKey = new Rsa\
PrivateKey($options['private_key'], $passPhrase);
63 throw new Exception\
InvalidArgumentException(
64 'Parameter "private_key" must be PEM formatted string or path to key file'
67 unset($options['private_key']);
71 if (isset($options['public_key'])) {
72 if (is_file($options['public_key'])) {
73 $publicKey = Rsa\PublicKey
::fromFile($options['public_key']);
74 } elseif (is_string($options['public_key'])) {
75 $publicKey = new Rsa\
PublicKey($options['public_key']);
77 throw new Exception\
InvalidArgumentException(
78 'Parameter "public_key" must be PEM/certificate string or path to key/certificate file'
81 unset($options['public_key']);
84 $options = new RsaOptions($options);
85 if ($privateKey instanceof Rsa\PrivateKey
) {
86 $options->setPrivateKey($privateKey);
88 if ($publicKey instanceof Rsa\PublicKey
) {
89 $options->setPublicKey($publicKey);
92 return new Rsa($options);
98 * @param RsaOptions $options
99 * @throws Rsa\Exception\RuntimeException
101 public function __construct(RsaOptions
$options = null)
103 if (!extension_loaded('openssl')) {
104 throw new Exception\
RuntimeException(
105 'Zend\Crypt\PublicKey\Rsa requires openssl extension to be loaded'
109 if ($options === null) {
110 $this->options
= new RsaOptions();
112 $this->options
= $options;
119 * @param RsaOptions $options
122 public function setOptions(RsaOptions
$options)
124 $this->options
= $options;
133 public function getOptions()
135 return $this->options
;
139 * Return last openssl error(s)
143 public function getOpensslErrorString()
146 while (false !== ($error = openssl_error_string())) {
147 $message .= $error . "\n";
149 return trim($message);
153 * Sign with private key
155 * @param string $data
156 * @param Rsa\PrivateKey $privateKey
158 * @throws Rsa\Exception\RuntimeException
160 public function sign($data, Rsa\PrivateKey
$privateKey = null)
163 if (null === $privateKey) {
164 $privateKey = $this->options
->getPrivateKey();
167 $result = openssl_sign(
170 $privateKey->getOpensslKeyResource(),
171 $this->options
->getOpensslSignatureAlgorithm()
173 if (false === $result) {
174 throw new Exception\
RuntimeException(
175 'Can not generate signature; openssl ' . $this->getOpensslErrorString()
179 if ($this->options
->getBinaryOutput()) {
183 return base64_encode($signature);
187 * Verify signature with public key
189 * $signature can be encoded in base64 or not. $mode sets how the input must be processed:
190 * - MODE_AUTO: Check if the $signature is encoded in base64. Not recommended for performance.
191 * - MODE_BASE64: Decode $signature using base64 algorithm.
192 * - MODE_RAW: $signature is not encoded.
194 * @param string $data
195 * @param string $signature
196 * @param null|Rsa\PublicKey $publicKey
197 * @param int $mode Input encoding
199 * @throws Rsa\Exception\RuntimeException
200 * @see Rsa::MODE_AUTO
201 * @see Rsa::MODE_BASE64
204 public function verify(
207 Rsa\PublicKey
$publicKey = null,
208 $mode = self
::MODE_AUTO
210 if (null === $publicKey) {
211 $publicKey = $this->options
->getPublicKey();
215 case self
::MODE_AUTO
:
216 // check if data is encoded in Base64
217 $output = base64_decode($signature, true);
218 if ((false !== $output) && ($signature === base64_encode($output))) {
219 $signature = $output;
222 case self
::MODE_BASE64
:
223 $signature = base64_decode($signature);
230 $result = openssl_verify(
233 $publicKey->getOpensslKeyResource(),
234 $this->options
->getOpensslSignatureAlgorithm()
236 if (-1 === $result) {
237 throw new Exception\
RuntimeException(
238 'Can not verify signature; openssl ' . $this->getOpensslErrorString()
242 return ($result === 1);
246 * Encrypt with private/public key
248 * @param string $data
249 * @param Rsa\AbstractKey $key
251 * @throws Rsa\Exception\InvalidArgumentException
253 public function encrypt($data, Rsa\AbstractKey
$key = null)
256 $key = $this->options
->getPublicKey();
260 throw new Exception\
InvalidArgumentException('No key specified for the decryption');
263 $encrypted = $key->encrypt($data);
265 if ($this->options
->getBinaryOutput()) {
269 return base64_encode($encrypted);
273 * Decrypt with private/public key
275 * $data can be encoded in base64 or not. $mode sets how the input must be processed:
276 * - MODE_AUTO: Check if the $signature is encoded in base64. Not recommended for performance.
277 * - MODE_BASE64: Decode $data using base64 algorithm.
278 * - MODE_RAW: $data is not encoded.
280 * @param string $data
281 * @param Rsa\AbstractKey $key
282 * @param int $mode Input encoding
284 * @throws Rsa\Exception\InvalidArgumentException
285 * @see Rsa::MODE_AUTO
286 * @see Rsa::MODE_BASE64
289 public function decrypt(
291 Rsa\AbstractKey
$key = null,
292 $mode = self
::MODE_AUTO
295 $key = $this->options
->getPrivateKey();
299 throw new Exception\
InvalidArgumentException('No key specified for the decryption');
303 case self
::MODE_AUTO
:
304 // check if data is encoded in Base64
305 $output = base64_decode($data, true);
306 if ((false !== $output) && ($data === base64_encode($output))) {
310 case self
::MODE_BASE64
:
311 $data = base64_decode($data);
318 return $key->decrypt($data);
322 * Generate new private/public key pair
323 * @see RsaOptions::generateKeys()
325 * @param array $opensslConfig
327 * @throws Rsa\Exception\RuntimeException
329 public function generateKeys(array $opensslConfig = array())
331 $this->options
->generateKeys($opensslConfig);