/**
* @description: hash加密、签名字符串和文件,文件支持本地路径(以盘符或/开头)、url(http或https开头)和fopen的资源
*/
class HashAlgorithm
{
public $algorithm;
/**
* @description: 判断是否为文件
* @param {mixed} $data
* @return {*}
*/
private function _isFile(mixed $data):bool
{
// 是字符串且以盘符或/或http开头
if (is_string($data) && ($data[0] == '/' || strpos($data[0], 'http') === 0 || preg_match('/^[a-zA-Z]\:/', $data) > 0)) {
return true;
} elseif (is_resource($data)) {
return true;
}
return false;
}
/**
* @description: hash加密
* @param {string} $algo 算法名称,支持算法:hash_algos()
* @param {mixed} $data 需要加密的字符串或文件
* @param {bool} $isBase64 是否base64编码
* @return {*}
*/
public function hash(string $algo, mixed $data, bool $isBase64 = true):string
{
$func = $this->_isFile($data) ? 'hash_file' : 'hash';
// 第三个参数为false时输出小写16进制字符串,否出输出原始二进制数据
$result = $func($algo, $data, true);
if ($result === false) {
throw new \Exception('加密失败');
}
return $isBase64 ? base64_encode($result) : trim($result);
}
/**
* @description: hash HMAC签名
* @param {string} $algo 签名算法名称,支持算法:hash_hmac_algos()
* @param {mixed} $data 需要加密的字符串或文件
* @param {string} $key 签名需要的key
* @param {bool} $isBase64 是否base64编码
* @return {*}
*/
public function hashSign(string $algo, mixed $data, string $key, bool $isBase64 = true):string
{
$func = $this->_isFile($data) ? 'hash_hmac_file' : 'hash_hmac';
// 第四个参数为false时输出小写16进制字符串,否出输出原始二进制数据
$result = $func($algo, $data, $key, true);
if ($result === false) {
throw new \Exception('加密失败');
}
return $isBase64 ? base64_encode($result) : $result;
}
/**
* @description: hash PBKDF2签名,
* PBKDF2原理:通过一个伪随机函数(例如HMAC函数),把明文和一个盐值作为输入参数,然后重复进行运算,并最终产生密钥
* @param {string} $algo 签名算法名称,支持算法:hash_algos(),不支持非加密哈希函数((adler32,crc32,crc32b,fnv132,fnv1a32,fnv164,fnv1a64,joaat))
* @param {string} $data 需要加密的字符串
* @param {string} $key 签名需要的key
* @param {int} $iterations 签名的迭代次数
* @param {int} $length 签名结果的长度,为0时,结果长度为算法固定长度
* @param {bool} $isBase64 是否base64编码
* @return {*}
*/
public function hashPbkdf2(string $algo, string $data, string $key, int $iterations, int $length = 0, bool $isBase64 = true):string
{
// 第六个参数为false时输出小写16进制字符串,否出输出原始二进制数据
$result = hash_pbkdf2($algo, $data, $key, $iterations, $length, true);
return $isBase64 ? base64_encode($result) : $result;
}
/**
* @description: hash HKDF签名
* HKDF原理:使用原始的密钥材料,派生出一个或更多个能达到密码学强度的密钥(主要是保证随机性)——就是将较短的密钥材料扩展成较长的密钥材料,
* 过程中需要保证随机性。
* HKDF包含两个基本模块:
* 1、提取:使用原始的密钥材料,派生出一个符合密码学强度的伪随机密钥
* 2、扩展:使用第1步骤提取出来的伪随机密钥,扩展出指定长度的密钥(同时保证随机性)
* @param {string} $algo 签名算法名称,支持算法:hash_algos(),不允许使用非加密哈希函数
* @param {string} $data 需要加密的字符串
* @param {string} $key 签名需要的key,提高HKDF的强度
* @param {string} $info 应用程序/上下文特定的信息字符串
* @param {int} $length 签名结果的长度,为0时,结果长度为算法固定长度
* @return {*}
*/
public function hashHkdf(string $algo, string $data, string $key = '', string $info = '', int $length = 0):string
{
return hash_hkdf($algo, $data, $length, $info, $key);
}
/**
* @description: hash字符串对比,可防止时序攻击,对比的两个字符串长度必须相同,否则直接返回false
* @param {string} $hash1 已知hash字符串
* @param {string} $hash2 需要比较的hash字符串
* @return {*}
*/
public function hashContrast(string $hash1, string $hash2):bool
{
return hash_equals($hash1, $hash2);
}
}