/**
* @description: aes各模式加解密
*/
class AesAlgorithm
{
/**
* @description: 秘钥长度
* @var int
*/
protected $keyLength;
/**
* @description: 加密算法
* @var string
*/
protected $algotithm;
/**
* @description: 加密位数-加密秘钥长度映射
* @var array
*/
protected $keyLengths = [
128 => 16,
192 => 24,
256 => 32,
];
/**
* @description: 加密模式对应iv长度
* @var array
*/
protected $ivLength = [
'cbc' => 16,
'ecb' => 0,
'cfb' => 16,
'ofb' => 16,
'ccm' => 12,
'gcm' => 12,
'ocb' => 12,
'ctr' => 16,
'xts' => 16,
];
/**
* @description: 验证算法
* @param {*}
* @return {*}
*/
public function verifyAlgotithm()
{
list($aes, $length, $mode) = explode('-', $this->algotithm, 3);
$this->keyLength = $this->keyLengths[$length] ?? false;
if (!$this->keyLength) {
throw new \Exception('AES加密长度错误');
}
if (!method_exists($this, $mode)) {
throw new \Exception('AES加密模式错误');
}
}
/**
* @description: ecb模式,简单,有利于并行计算,误差不会被传送;
* 但不能隐藏明文的模式,可能对明文进行主动攻击
* @param string $data 需要加解密的数据
* @param int $digits 加密位数
* @param string $key 加密key,注意key长度
* @param int $options 加密填充 0(pkcs7填充返回base64编码内容)其他方式填充返回空字符串;OPENSSL_RAW_DATA (pkcs7填充返回二进制数据)
* @param bool $isDe 解密/加密
* @return {*}
*/
public function ecb(string $data, int $digits, string $key, int $options = 0, bool $isDe = false):string
{
$this->algotithm = 'aes-' . (string)$digits . '-ecb';
$this->verifyAlgotithm();
if ($isDe) {
return trim(openssl_decrypt(base64_decode($data), $this->algotithm, $this->_key($key), $options));
}
echo base64_encode(openssl_encrypt($data, $this->algotithm, $this->_key($key), $options)) . PHP_EOL;
return openssl_encrypt($data, $this->algotithm, $this->_key($key), $options);
}
/**
* @description: cbc模式,不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
* 但不利于并行计算,误差会传递,需要初始化向量IV
* @param string $data 需要加解密的数据
* @param int $digits 加密位数
* @param string $key 加密key,注意key长度
* @param int $options 加密填充 0(pkcs7填充返回base64编码内容)其他方式填充返回空字符串;OPENSSL_RAW_DATA (pkcs7填充返回二进制数据)
* @param string $iv 初始化向量
* @param bool $isDe 解密/加密
* @return {*}
*/
public function cbc(string $data, int $digits, string $key, int $options = 0, string $iv = '', bool $isDe = false):string
{
$this->algotithm = 'aes-' . (string)$digits . '-cbc';
$this->verifyAlgotithm();
if ($isDe) {
return trim(openssl_decrypt(base64_decode($data), $this->algotithm, $this->_key($key), $options, $this->_iv($iv)));
}
return base64_encode(openssl_encrypt($data, $this->algotithm, $this->_key($key), $options, $this->_iv($iv)));
}
/**
* @description: cfb模式,隐藏了明文模式,分组密码转化为流模式,可以及时加密传送小于分组的数据;
* 但是不利于并行计算;误差传送:一个明文单元损坏影响多个单元;唯一的IV;
* @param string $data 需要加解密的数据
* @param int $digits 加密位数
* @param string $key 加密key,注意key长度
* @param int $options 加密填充 0(pkcs7填充返回base64编码内容)其他方式填充返回空字符串;OPENSSL_RAW_DATA (pkcs7填充返回二进制数据)
* @param string $iv 初始化向量
* @param bool $isDe 解密/加密
* @return {*}
*/
public function cfb(string $data, int $digits, string $key, int $options = 0, string $iv = '', bool $isDe = false):string
{
$this->algotithm = 'aes-' . (string)$digits . '-cfb';
$this->verifyAlgotithm();
if ($isDe) {
return trim(openssl_decrypt(base64_decode($data), $this->algotithm, $this->_key($key), $options, $this->_iv($iv)));
}
return base64_encode(openssl_encrypt($data, $this->algotithm, $this->_key($key), $options, $this->_iv($iv)));
}
/**
* @description: ofb模式,隐藏了明文模式;分组密码转化为流模式;可以及时加密传送小于分组的数据;
* 但不利于并行计算;对明文的主动攻击是可能的;误差传送:一个明文单元损坏影响多个单元;
* @param string $data 需要加解密的数据
* @param int $digits 加密位数
* @param string $key 加密key,注意key长度
* @param int $options 加密填充 0(pkcs7填充返回base64编码内容)其他方式填充返回空字符串;OPENSSL_RAW_DATA (pkcs7填充返回二进制数据)
* @param string $iv 初始化向量
* @param bool $isDe 解密/加密
* @return {*}
*/
public function ofb(string $data, int $digits, string $key, int $options = 0, string $iv = '', bool $isDe = false):string
{
$this->algotithm = 'aes-' . (string)$digits . '-ofb';
$this->verifyAlgotithm();
if ($isDe) {
return trim(openssl_decrypt(base64_decode($data), $this->algotithm, $this->_key($key), $options, $this->_iv($iv)));
}
return base64_encode(openssl_encrypt($data, $this->algotithm, $this->_key($key), $options, $this->_iv($iv)));
}
/**
* @description: ctr模式,Counter
* 计算器模式不常见,在CTR模式中, 有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文,相当于一次一密。
* 这种加密方式简单快速,安全可靠,而且可以并行加密,但是在计算器不能维持很长的情况下,密钥只能使用一次
* @param string $data 需要加解密的数据
* @param int $digits 加密位数
* @param string $key 加密key,注意key长度
* @param int $options 加密填充 0(pkcs7填充返回base64编码内容)其他方式填充返回空字符串;OPENSSL_RAW_DATA (pkcs7填充返回二进制数据)
* @param string $iv 初始化向量,ecb模式不需要,其他模式需要,且长度不一
* @param bool $isDe 解密/加密
* @return {*}
*/
public function ctr(string $data, int $digits, string $key, int $options = 0, string $iv = '', bool $isDe = false):string
{
$this->algotithm = 'aes-' . (string)$digits . '-ctr';
$this->verifyAlgotithm();
if ($isDe) {
return trim(openssl_decrypt(base64_decode($data), $this->algotithm, $this->_key($key), $options, $this->_iv($iv)));
}
return base64_encode(openssl_encrypt($data, $this->algotithm, $this->_key($key), $options, $this->_iv($iv)));
}
/**
* @description: ccm模式,在无线通信系统中较为常用的一种加密算法,因其效率和安全性都具有较高的标准,被广泛的应用于802.XX和BLE的协议中;
* 包括CCM算法和AES算法两部分
* 解密时需要加密时引用传递的tag
* @param string $data 需要加解密的数据
* @param int $digits 加密位数
* @param string $key 加密key,注意key长度
* @param int $options 加密填充 0(pkcs7填充返回base64编码内容)其他方式填充返回空字符串;OPENSSL_RAW_DATA (pkcs7填充返回二进制数据)
* @param string $iv 初始化向量
* @param string $tag 使用AEAD密码模式(GCM 或 CCM)时传引用的验证标签。
* @param string $aad 附加的验证数据(GCM 或 CCM)模式
* @param int $tag_length 验证tag的长度。GCM模式时,它的范围是4到16,解密时不需要(GCM 或 CCM)模式
* @param bool $isDe 解密/加密
* @return {*}
*/
public function ccm(string $data, int $digits, string $key, int $options = 0, string $iv = '', string $tag = NULL, string $aad = '', int $tag_length = 16, bool $isDe = false):string
{
$this->algotithm = 'aes-' . (string)$digits . '-ccm';
$this->verifyAlgotithm();
if ($isDe) {
return trim(openssl_decrypt(base64_decode($data), $this->algotithm, $this->_key($key), $options, $this->_iv($iv), $tag, $aad));
}
return base64_encode(openssl_encrypt($data, $this->algotithm, $this->_key($key), $options, $this->_iv($iv), $tag, $aad, $tag_length));
}
/**
* @description: gcm模式,对称加密采用Counter模式,并带有GMAC消息认证码;一种非常快速但可以说是复杂的CTR模式和GHASH的组合
* 解密时需要加密时引用传递的tag
* @param string $data 需要加解密的数据
* @param int $digits 加密位数
* @param string $key 加密key,注意key长度
* @param int $options 加密填充 0(pkcs7填充返回base64编码内容)其他方式填充返回空字符串;OPENSSL_RAW_DATA (pkcs7填充返回二进制数据)
* @param string $iv 初始化向量
* @param string $tag 使用AEAD密码模式(GCM 或 CCM)时传引用的验证标签。
* @param string $aad 附加的验证数据(GCM 或 CCM)模式
* @param int $tag_length 验证tag的长度。GCM模式时,它的范围是4到16,解密时不需要(GCM 或 CCM)模式
* @param bool $isDe 解密/加密
* @return {*}
*/
public function gcm(string $data, int $digits, string $key, int $options = 0, string $iv = '', string $tag = NULL, string $aad = '', int $tag_length = 16, bool $isDe = false):string
{
$this->algotithm = 'aes-' . (string)$digits . '-gcm';
$this->verifyAlgotithm();
if ($isDe) {
return trim(openssl_decrypt(base64_decode($data), $this->algotithm, $this->_key($key), $options, $this->_iv($iv), $tag, $aad));
}
return base64_encode(openssl_encrypt($data, $this->algotithm, $this->_key($key), $options, $this->_iv($iv), $tag, $aad, $tag_length));
}
/**
* @description: ocb模式,它允许一次通过加密和身份验证。 但是在美国有专利;php加密后无法解密
* @return {*}
*/
private function _ocb()
{
}
/**
* @description: xts模式,适用于网络存储的加密模式,无法加解密,192位没有此模式
* @return {*}
*/
private function _xts()
{
}
/**
* @description: key处理,补全/截断指定长度
* @param string $key
* @return {*}
*/
private function _key($key)
{
return substr(str_pad($key, $this->keyLength, 0), 0, $this->keyLength);
}
/**
* @description: iv处理,补全/截断指定长度
* @param string $iv
* @return {*}
*/
private function _iv($iv)
{
$ivLength = openssl_cipher_iv_length($this->algotithm);
return substr(str_pad($iv, $ivLength, 0), 0, $ivLength);
}
/**
* @description: 获取openSSL库的错误,错误消息已被队列化,可以查询到多条错误信息,最后一个是最近的一个错误。
* @param
* @return array
*/
public function errors()
{
$result = [];
while ($data = openssl_error_string() !== false) {
$result[] = $data;
}
return $result;
}
}