src/Bitpay/Crypto/OpenSSLExtension.php
<?php
/**
* @license Copyright 2011-2014 BitPay Inc., MIT License
* see https://github.com/bitpay/php-bitpay-client/blob/master/LICENSE
*/
namespace Bitpay\Crypto;
/**
* Wrapper around the OpenSSL PHP Extension
*
* @see http://php.net/manual/en/book.openssl.php
*/
class OpenSSLExtension implements CryptoInterface
{
/**
* @inheritdoc
*/
public static function hasSupport()
{
return function_exists('openssl_open');
}
/**
* @inheritdoc
*/
public function getAlgos()
{
return openssl_get_cipher_methods();
}
/**
* Function to generate a new RSA keypair. This is not
* used for point derivation or for generating signatures.
* Only used for assymetric data encryption, as needed.
*
* @param int
* @param string
* @return array|boolean array of keys on success, boolean false on failure
*/
final public function generateKeypair($keybits = 512, $digest_alg = 'sha512')
{
try {
/* see: http://www.php.net/manual/en/function.openssl-pkey-new.php */
if (function_exists('openssl_pkey_new')) {
$keypair = array();
/* openssl keysize can't be smaller than 384 bits */
if ((int) $keybits < 384) {
$keybits = 384;
}
if (!isset($digest_alg) || trim($digest_alg) == '') {
$digest_alg = 'sha512';
}
/*
* RSA is the only supported key type at this time
* http://www.php.net/manual/en/function.openssl-csr-new.php
*/
$config = array(
'digest_alg' => $digest_alg,
'private_key_bits' => (int) $keybits,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
);
$resource = openssl_pkey_new($config);
if (!$resource) {
throw new \Exception('Error in generateOpenSSLKeypair: Could not create new OpenSSL resource.');
/* with the openssl extension, you also have it's own errors returned */
while ($msg = openssl_error_string()) {
throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg);
}
return false;
}
if (openssl_pkey_export($resource, $keypair['pri'])) {
$publickey = openssl_pkey_get_details($resource);
$keypair['pub'] = $publickey['key'];
} else {
throw new \Exception('Error in generateOpenSSLKeypair: Private key could not be determined from OpenSSL key resource.');
while ($msg = openssl_error_string()) {
throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg);
}
return false;
}
openssl_pkey_free($resource);
return $keypair;
} else {
throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL PHP extension missing. Cannot continue.');
return false;
}
} catch (\Exception $e) {
while ($msg = openssl_error_string()) {
throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg);
}
throw $e;
return false;
}
}
/**
* Generates a high-quality random number suitable for
* use in cryptographic functions and returns hex value.
*
* @param int
* @return string|bool
*/
final public function randomNumber($bytes = 32)
{
$random_data = openssl_random_pseudo_bytes($bytes, $cstrong);
if (!$cstrong || !$random_data) {
return false;
} else {
return bin2hex($random_data);
}
}
/**
* Returns the cipher length on success, or FALSE
* on failure. (PHP 5 >= PHP 5.3.3)
*
* @param string
* @return int|bool
*/
final public function cypherIVLength($cypher = '')
{
return openssl_cipher_iv_length($cypher);
}
/**
* Takes the Certificate Signing Request represented
* by $csr and saves it as ascii-armoured text into
* the file named by $outfilename.
* (PHP 4 >= 4.2.0, PHP 5)
*
* @param resource
* @param string
* @param bool
* @return bool
*/
final public function saveCSRtoFile($csr, $outfilename, $notext = true)
{
if (!is_resource($csr)) {
return false;
}
return openssl_csr_export_to_file($csr, $outfilename, $notext);
}
/**
* Takes the Certificate Signing Request represented
* by $csr and stores it as ascii-armoured text into
* $out, which is passed by reference.
* (PHP 4 >= 4.2.0, PHP 5)
*
* @param resource
* @param string
* @param bool
* @return bool
*/
final public function saveCSRtoString($csr, $out, $notext = true)
{
if (!is_resource($csr)) {
return false;
}
return openssl_csr_export($csr, $out, $notext);
}
/**
*
* Encrypts $text based on your $key and $iv. The returned text is
* base-64 encoded to make it easier to work with in various scenarios.
* Default cipher is AES-256-CBC but you can substitute depending
* on your specific encryption needs.
*
* @param string $text
* @param string $key
* @param string $iv
* @param int $bit_check
* @param string $cipher_type
* @return string $text
* @throws Exception $e
*
*/
public function encrypt($text, $key = '', $iv = '', $bit_check = 8, $cipher_type = 'AES-256-CBC')
{
try {
if (function_exists('openssl_pkey_new')) {
/* Ensure the key & IV is the same for both encrypt & decrypt. */
if (!empty($text) && is_string($text)) {
$text_num = str_split($text, $bit_check);
$text_num = $bit_check - strlen($text_num[count($text_num) - 1]);
for ($i = 0; $i < $text_num; $i++) {
$text = $text . chr($text_num);
}
$encrypted = openssl_encrypt($text, $cipher_type, $key, 0, $iv);
return base64_encode($encrypted);
} else {
return $text;
}
} else {
throw new \Exception('Error in OpenSSL encrypt: OpenSSL PHP extension missing. openssl_encrypt function not found.');
return false;
}
} catch (\Exception $e) {
throw $e;
}
}
/**
*
* Decrypts $text based on your $key and $iv. Make sure you use the same key
* and initialization vector that you used when encrypting the $text. Default
* cipher is AES-256-CBC but you can substitute depending on the cipher
* used for encrypting the text - very important.
*
* @param string $encrypted_text
* @param string $key
* @param string $iv
* @param int $bit_check
* @param string $cipher_type
* @return string $text
* @throws Exception $e
*
*/
public function decrypt($encrypted_text, $key = '', $iv = '', $bit_check = 8, $cipher_type = 'AES-256-CBC')
{
try {
/* Ensure the key & IV is the same for both encrypt & decrypt. */
if (!empty($encrypted_text)) {
$decrypted = openssl_decrypt(base64_decode($encrypted_text), $cipher_type, $key, 0, $iv);
$last_char = substr($decrypted, -1);
for ($i = 0; $i < $bit_check; $i++) {
if (chr($i) == $last_char) {
$decrypted = substr($decrypted, 0, strlen($decrypted) - $i);
break;
}
}
return $decrypted;
} else {
return $encrypted_text;
}
} catch (\Exception $e) {
throw $e;
}
}
}