Created
July 12, 2019 04:26
-
-
Save iyaozhen/4cd20a7fa9c7ecd2d2041ec5a831f328 to your computer and use it in GitHub Desktop.
PHP Encrypter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* 加解密类 | |
* | |
* @author iyaozhen | |
* @date: 2016-11-12 | |
*/ | |
class Encrypter | |
{ | |
private $method; | |
private $password; | |
private $padding; | |
private $iv; | |
private $lastErrorMessage; // 最后一次失败的信息 | |
/** | |
* Encrypter constructor | |
* | |
* @param null|string $password 默认使用配置文件中的aes_key | |
* @param string $method 加密的模式 | |
* @param string $padding 填充数据模式, 支持ZERO(默认)、PKCS7(兼容PKCS5) | |
* @param string $iv 初始向量, 默认使用AES-128-ECB初始向量为空 | |
*/ | |
function __construct($password = null, $method = 'AES-128-ECB', $padding = 'ZERO', $iv = '') | |
{ | |
$this->password = $password; | |
$this->method = $method; | |
$this->padding = $padding; | |
$this->iv = $iv; | |
} | |
/** | |
* 加密 | |
* | |
* @param string $data 需要加密的字符串 | |
* | |
* @return false|string 失败时返回false | |
*/ | |
public function encrypt($data) | |
{ | |
/** | |
* openssl_encrypt ZERO_PADDING模式有个小问题 | |
* 当设置为OPENSSL_ZERO_PADDING时其实是禁用padding | |
* EVP_CIPHER_CTX_set_padding(&cipher_ctx, 0); | |
* 因此需要构造合适长度的被加密串, 这样加密过程中就不需要padding了,不然会加密失败 | |
* 不过需要注意的是因为padding了\0字符 解密完成后需要trim。显而易见,若是被加密串两端本身就包含\0等字符就会丢失信息 | |
* | |
* 参考资料: http://php.net/manual/en/function.openssl-encrypt.php#117208 | |
* http://php.net/manual/en/function.openssl-encrypt.php#117499 | |
* http://www.cnblogs.com/solohac/p/4284424.html | |
* http://stackoverflow.com/questions/11838197/php-vs-java-aes-encryption-what-is-the-difference | |
*/ | |
if ($this->padding === 'ZERO') { | |
$options = OPENSSL_ZERO_PADDING; | |
if ($blockSize = $this->getBlockSize($this->method)) { | |
$padLen = $blockSize - (strlen($data) % $blockSize); | |
$data .= str_repeat("\0", $padLen); // zero padding | |
} | |
else { | |
// 不支持的加密方法 | |
$this->lastErrorMessage = 'Unknown cipher method'; | |
return false; | |
} | |
} | |
else { | |
// 默认值, 使用PKCS7(兼容PKCS5) padding方式 | |
$options = 0; | |
} | |
try { | |
$encryptedData = openssl_encrypt($data, $this->method, $this->password, | |
$options, $this->iv); | |
} | |
catch (Exception $e) { | |
$this->lastErrorMessage = $e; | |
return false; | |
} | |
return $encryptedData; | |
} | |
/** | |
* 解密 | |
* | |
* @param string $data 需要解密的字符串 | |
* | |
* @return string|false 失败时返回false | |
*/ | |
public function decrypt($data) | |
{ | |
// 预先 decode | |
// base64 url safe decode | |
$data = base64_decode(str_pad( | |
strtr($data, '-_', '+/'), | |
strlen($data) % 4, | |
'=', | |
STR_PAD_RIGHT | |
)); | |
if ($this->padding === 'ZERO') { | |
$options = OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING; | |
} | |
else { | |
// PKCS7(兼容PKCS5)padding,openssl默认方式 | |
$options = OPENSSL_RAW_DATA; | |
} | |
try { | |
$decryptedData = openssl_decrypt($data, $this->method, $this->password, | |
$options, $this->iv); | |
} | |
catch (Exception $e) { | |
$this->lastErrorMessage = $e; | |
return false; | |
} | |
// 解密后的数据两端可能有padding的空字符, 需要调用方按需trim | |
return $decryptedData; | |
} | |
/** | |
* 获取某个加密方式的块大小 | |
* | |
* @param string $method | |
* | |
* @return bool|int | |
*/ | |
private function getBlockSize($method) | |
{ | |
// 因为openssl没有现成方法获取block size, 只能写死几种常见加密模式 | |
$methodBlockSize = [ | |
'AES-128-CBC' => 16, | |
'AES-128-CFB' => 16, | |
'AES-128-ECB' => 16, | |
'AES-128-OFB' => 16, | |
'AES-192-CBC' => 24, | |
'AES-192-CFB' => 24, | |
'AES-192-ECB' => 24, | |
'AES-192-OFB' => 24, | |
'AES-256-CBC' => 32, | |
'AES-256-CFB' => 32, | |
'AES-256-ECB' => 32, | |
'AES-256-OFB' => 32, | |
]; | |
return isset($methodBlockSize[$method]) ? $methodBlockSize[$method] : false; | |
} | |
/** | |
* 获取最后一次报错的信息 | |
* | |
* @return string | |
*/ | |
public function getLastErrorMessage() | |
{ | |
return sprintf("last error: %s, openssl error: %s", | |
$this->lastErrorMessage, openssl_error_string() | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment