时间:2025-02-04 11:15
人气:
作者:admin
/**
* @function PHP使用AES 256加密字符串数据
* @param $str string 被加密的字符串
* @param $key string 256位自定义key,是加密算法的核心,用于确保只有持有相同密钥的人才能解密数据,推荐随机生成32个随机字符,确保不可预测
* @param $iv string 128位初始化向量,是一个随机或伪随机的值,用于在加密过程中初始化加密算法的状态,确保使用相同密钥加密的相同明文会产生不同的密文
* @return string
*/
function aesEncrypt($str, $key, $iv) {
return base64_encode(openssl_encrypt($str, 'AES-256-CBC', $key, true, $iv));
}
$str = '{"code":0,"msg":"success","data":{"lists":{"k1":"v1","k2":"v2"}}}';
$key = 'abcdabcdabcdabcdabcdabcdabcdabcd';
$iv = 'abcdabcdabcdabcd';
echo aesEncrypt($str, $key, $iv);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script>
function decrypt(str, key, iv) {
return CryptoJS.AES.decrypt(str, CryptoJS.enc.Utf8.parse(key), {iv: CryptoJS.enc.Utf8.parse(iv), padding: CryptoJS.pad.Pkcs7}).toString(CryptoJS.enc.Utf8);
}
console.log(decrypt('naQ3ZnyGetarkvugVeNaroUe9Hrk+KW3sKXSs42QJ6tPER1zcxvS8E2xsCJG0UaJ5WMFhFgLjD6z3wbqPLFgRFIl+BaGqINmdPbm9B+DXMs=', 'abcdabcdabcdabcdabcdabcdabcdabcd', 'abcdabcdabcdabcd'));
</script>
/**
* @function PHP使用AES 256解密字符串数据
* @param $str string 被解密的字符串
* @param $key string 256位自定义key,是加密算法的核心,用于确保只有持有相同密钥的人才能解密数据,推荐随机生成32个随机字符,确保不可预测
* @param $iv string 128位初始化向量,是一个随机或伪随机的值,用于在加密过程中初始化加密算法的状态,确保使用相同密钥加密的相同明文会产生不同的密文
* @return string
*/
function aesDecrypt($str, $key, $iv) {
return base64_decode(base64_encode(openssl_decrypt(base64_decode($str), 'AES-256-CBC', $key, true, $iv)));
}
$str = 'aZlC1imJbcUQblRR0QsMPGF+8Kbja/1fU+tdcTyAUVw=';
$key = 'abcdabcdabcdabcdabcdabcdabcdabcd';
$iv = 'abcdabcdabcdabcd';
echo aesDecrypt($str, $key, $iv);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<script>
function encrypt(str, key, iv) {
return CryptoJS.AES.encrypt(str, CryptoJS.enc.Utf8.parse(key), {iv: CryptoJS.enc.Utf8.parse(iv), mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7}).toString();
}
console.log(encrypt('{"name":"张三", "age": 20}', 'abcdabcdabcdabcdabcdabcdabcdabcd', 'abcdabcdabcdabcd'))
</script>
<?php
class Crypt {
//声明密文前缀
private static $prefix = '$';
/**
* @function 生成ASCII字符随机盐
* @return array
*/
public static function generateRandStr() {
//这里最小设置为1,最大设置为255,大小与密文长度成正比,随机长度用于加强混淆
$length = rand(1, 255);
$salt = '';
for ($i = 0; $i < $length; $i++) {
//按照ASCII,生成随机单字节字符
$salt .= chr(rand(0, 255));
}
return ['salt' => $salt, 'length' => $length];
}
/**
* @function 计算偏移量 加密用
* @param $v int 明文每个字节的ASCII编码值
* @param $s int 自定义算法取余后的值
* @return int
*/
private static function calcOffsetEn($v, $s) {
$r = 255 - $v;
if ($s > $r) {
return $s - $r - 1;
}
return $v + $s;
}
/**
* @function 计算偏移量 解密用
* @param $v int 密文每个字节的ASCII编码值
* @param $s int 自定义算法取余后的值
* @return int
*/
private static function calcOffsetDe($v, $s) {
if ($v >= $s) {
return $v - $s;
}
return 255 - ($s - $v) + 1;
}
/**
* @function 明文和盐混淆成密文
* @param $data string 要被加密的明文
* @param $salt array 盐
* @return string 加密后的数据
*/
private static function encryptWithSalt($data, $salt) {
$result = '';
//获取明文有几个单字节的长度,此处不要用mb_strlen
$data_len = strlen($data);
for ($i = 0; $i < $data_len; $i ++) {
//逐个字节混淆 字符串中每个字节的ASCII值 与
$result .= chr(static::calcOffsetEn(ord($data[$i]), ord($salt['salt'][$i % $salt['length']])));
}
return $result;
}
/**
* @function 密文解密
* @param $data string 要被解密的密文
* @param $salt array 盐
* @return string
*/
private static function decryptWithSalt($data, $salt) {
$result = '';
$data_len = strlen($data);
for ($i = 0; $i < $data_len; $i++) {
// 去盐处理并转换为字符
$result .= chr(static::calcOffsetDe(ord($data[$i]), ord($salt['salt'][$i % $salt['length']])));
}
return $result;
}
/**
* @function 加密数据
* @param $data string 要被加密的字符串
* @return string
*/
public static function encrypt($data) {
if ($data == '') {
return '';
}
// 生成随机盐
$salt = static::generateRandStr();
// 将盐的长度、盐本身、密文
return static::$prefix . bin2hex(chr($salt['length']) . $salt['salt'] . static::encryptWithSalt(mb_convert_encoding($data, 'UTF-8', 'UTF-8'), $salt));
}
/**
* @function 解密数据
* @param $data string 要被加密的字符串
* @return string
*/
public static function decrypt($data) {
if ($data == '') {
return '';
}
// 检查是否是加密字符串,通过标签判断
if ($data[0] != static::$prefix) {
return '';
}
// 去掉标签并从16进制字符串转换回二进制数据
$clear_data = hex2bin(substr($data, strlen(static::$prefix)));
// 获取盐的长度
$salt_len = ord($clear_data[0]);
// 将解密数据转换为UTF-8编码的字符串
return mb_convert_encoding(static::decryptWithSalt(substr($clear_data, 1 + $salt_len), ['salt' => substr($clear_data, 1, $salt_len), 'length' => $salt_len]), 'UTF-8', 'UTF-8');
}
}
class Crypt {
// 声明密文前缀
static prefix = '$';
/**
* 生成ASCII字符随机盐
* @returns {Object} {salt, length}
*/
static generateRandStr() {
const length = Math.floor(Math.random() * 255) + 1; // 随机盐的长度在1到255之间
let salt = '';
for (let i = 0; i < length; i++) {
salt += String.fromCharCode(Math.floor(Math.random() * 256)); // 生成一个随机的ASCII字符
}
return { salt, length };
}
/**
* 计算加密时的偏移量
* @param {number} v 明文字符的ASCII值
* @param {number} s 盐的ASCII值
* @returns {number}
*/
static calcOffsetEn(v, s) {
const r = 255 - v;
if (s > r) {
return s - r - 1;
}
return v + s;
}
/**
* 计算解密时的偏移量
* @param {number} v 密文字符的ASCII值
* @param {number} s 盐的ASCII值
* @returns {number}
*/
static calcOffsetDe(v, s) {
if (v >= s) {
return v - s;
}
return 255 - (s - v) + 1;
}
/**
* 明文与盐混淆加密
* @param {Uint8Array} data 明文的字节数据
* @param {Object} salt 盐
* @returns {Uint8Array} 加密后的密文
*/
static encryptWithSalt(data, salt) {
let result = [];
const data_len = data.length;
for (let i = 0; i < data_len; i++) {
const data_char_code = data[i];
const salt_char_code = salt.salt.charCodeAt(i % salt.length);
result.push(Crypt.calcOffsetEn(data_char_code, salt_char_code));
}
return new Uint8Array(result);
}
/**
* 密文解密
* @param {Uint8Array} data 密文的字节数据
* @param {Object} salt 盐
* @returns {Uint8Array} 解密后的明文
*/
static decryptWithSalt(data, salt) {
let result = [];
const data_len = data.length;
for (let i = 0; i < data_len; i++) {
const data_char_code = data[i];
const salt_char_code = salt.salt.charCodeAt(i % salt.length);
result.push(Crypt.calcOffsetDe(data_char_code, salt_char_code));
}
return new Uint8Array(result);
}
/**
* 将字符串转换为 UTF-8 字节数组
* @param {string} str
* @returns {Uint8Array}
*/
static stringToBytes(str) {
const encoder = new TextEncoder();
return encoder.encode(str);
}
/**
* 将 UTF-8 字节数组转换为字符串
* @param {Uint8Array} bytes
* @returns {string}
*/
static bytesToString(bytes) {
const decoder = new TextDecoder('utf-8');
return decoder.decode(bytes);
}
/**
* 加密数据
* @param {string} data 明文
* @returns {string} 加密后的字符串
*/
static encrypt(data) {
if (data === '') return '';
// 生成随机盐
const salt = Crypt.generateRandStr();
// 将数据转换为字节数组
const byte_data = Crypt.stringToBytes(data);
// 加密数据
const encrypted_data = Crypt.encryptWithSalt(byte_data, salt);
// 生成盐长度字符并将其与盐和密文一起编码为十六进制字符串
const salt_length = String.fromCharCode(salt.length);
// 转换为 UTF-8 字节数组并进行十六进制编码
const all_data = new Uint8Array([salt_length.charCodeAt(0), ...salt.salt.split('').map(c => c.charCodeAt(0)), ...encrypted_data]);
return Crypt.prefix + Crypt.toHex(all_data);
}
/**
* 解密数据
* @param {string} data 加密后的字符串
* @returns {string} 解密后的明文
*/
static decrypt(data) {
if (data === '') return '';
// 检查加密格式
if (data[0] !== Crypt.prefix) return '';
// 去掉前缀并解码16进制数据
const clear_data = Crypt.fromHex(data.slice(1));
// 获取盐的长度
const salt_length = clear_data[0];
// 解密数据并返回结果
const salt = {
salt: String.fromCharCode(...clear_data.slice(1, salt_length + 1)),
length: salt_length
};
const encrypted_data = clear_data.slice(salt_length + 1);
const decrypted_bytes = Crypt.decryptWithSalt(encrypted_data, salt);
return Crypt.bytesToString(decrypted_bytes);
}
/**
* 将字节数组转换为十六进制字符串
* @param {Uint8Array} bytes
* @returns {string}
*/
static toHex(bytes) {
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += bytes[i].toString(16).padStart(2, '0');
}
return hex;
}
/**
* 将十六进制字符串转换为字节数组
* @param {string} hex
* @returns {Uint8Array}
*/
static fromHex(hex) {
let bytes = [];
for (let i = 0; i < hex.length; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return new Uint8Array(bytes);
}
}
echo Crypt::encrypt(json_encode([
'code' => 0,
'msg' => 'success',
'data' => [
'name' => '张三',
'en_name' => 'SanZhang',
'age' => 20,
'mood_emoji' => '????'
]
]));
let json_str = Crypt.decrypt('$19f33b3ae6796c3a9d4e4d37373115791af270a19a201c19d2d06e5d9d55ddd15cd77e7959a4a47c9b5414e316fd83818c45f21f5d9e47edcd5cd7c96fa5989e7a9b5414cc16cf864e492e4527a06a1f9b985c02bcaca5989e7a9b5414c302087a847a403715675c47e0d15cd7807d63599e84e87e51d50e098a853b0cf24fb09e1eacd09612b2b2676b5392f6');
console.log(JSON.parse(json_str))
echo Crypt::decrypt('$3e6811d12601019a4fc061345af6bf305bf16c8071fd4da404e7c49ce861dbe91d44ddc64d44a9311631d84ace9c047c998f55473e1a5da705c65176a26651e3333f876e66bc89e246f0fada77b97d1d8ee5df5cbb05714ce6d60ab43c5777ac3e34b466d55377983d6c08ce34a8bbfcc4b6a279c2147430ba98dc884107a955487e');
let obj = {"name":"张三","en_name":"SanZhang","age":20,"mood_emoji":"????"};
console.log(Crypt.encrypt(JSON.stringify(obj)));
在Linux或Windows git-bash命令行执行以下命令可生成密钥对
openssl genpkey -algorithm RSA -out private.key -pkeyopt rsa_keygen_bits:2048
openssl rsa -in private.key -pubout -out public.key
/**
* @function RSA加密算法,使用公钥加密数据
* @param $str string 被加密的数据
* @param $pub_key string 公钥内容
* @return string
*/
function encryptRsa($str, $pub_key) {
$encrypt_str = '';
if(! openssl_public_encrypt($str, $encrypt_str, $pub_key)) {
return '';
}
return base64_encode($encrypt_str);
}
echo encryptRsa(
json_encode(['code' => 0, 'msg' => 'success', 'data' => ['lists' => [1, 2, 3]]]),
file_get_contents('C:/Users/Administrator/DeskTop/public.key')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js"></script>
<script>
function decryptRsa(str, private_key) {
var encrypt = new JSEncrypt();
encrypt.setPrivateKey(private_key);
return encrypt.decrypt(str);
}
console.log(decryptRsa('接口返回的base64编码过的字符串', '私钥字符串'));
</script>
/**
* @function RSA解密算法,使用私钥解密数据
* @param $str string 要解密的数据
* @param $private_key string 私钥内容
* @return string
*/
function decryptRsa($str, $private_key) {
openssl_private_decrypt(base64_decode($str), $res, $private_key);
return $res;
}
echo decryptRsa(
'被解密的base64字符串',
file_get_contents('C:/Users/Administrator/DeskTop/private.key')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js"></script>
<script>
function encryptRsa(data, public_key) {
var encrypt = new JSEncrypt();
encrypt.setPublicKey(public_key);
return encrypt.encrypt(data);
}
console.log(encryptRsa('要加密的字符串', '公钥字符串'));
</script>
/**
* @function AES加密数据
* @param $data string 要被加密的数据
* @param $key string 256位自定义key,是加密算法的核心,用于确保只有持有相同密钥的人才能解密数据,推荐随机生成32个随机字符,确保不可预测
* @return string
*/
function encrypt($data, $key) {
$cipher = "AES-256-CBC";
$ivlen = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
$encrypted = openssl_encrypt($data, $cipher, $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $encrypted);
}
$key = 'ABCD1234ABCD1234ABCD1234ABCD1234'; //此处可以通过Redis,或数据库共享秘钥,或者通过自定义的算法数据生成
$data = "Hello";
echo encrypt($data, $key);
/**
* @function AES解密数据
* @param $data string 要被解密的数据
* @param $key string 256位自定义key,是加密算法的核心,用于确保只有持有相同密钥的人才能解密数据,推荐随机生成32个随机字符,确保不可预测
* @return string
*/
function decrypt($data, $key) {
$cipher = "AES-256-CBC";
$data = base64_decode($data);
$ivlen = openssl_cipher_iv_length($cipher);
$iv = substr($data, 0, $ivlen);
$encrypted = substr($data, $ivlen);
$decrypted = openssl_decrypt($encrypted, $cipher, $key, OPENSSL_RAW_DATA, $iv);
return $decrypted;
}
$key = 'ABCD1234ABCD1234ABCD1234ABCD1234'; //此处可以通过Redis,或数据库共享秘钥,或者通过自定义的算法数据生成
echo decrypt('TdeyO0y21HGC7MB0sPsLo0DcVmVHYrqjUGXiU6hThHc=', $key);
Crypt 参考上文“服务端与客户端(较为安全的自定义对称加密算法,避免AES算法的 key和vi在客户端存储问题)”,记得用Ctrl + F搜
Crypt::encrypt('要加密的字符串');
Crypt 参考上文“服务端与客户端(较为安全的自定义对称加密算法,避免AES算法的 key和vi在客户端存储问题))”,记得用Ctrl + F搜
Crypt::decrypt('要解密的字符串');
/**
* @function RSA加密算法,使用公钥加密数据
* @param $str string 被加密的数据
* @param $pub_key string 公钥内容
* @return string
*/
function encryptRsa($str, $pub_key) {
$encrypt_str = '';
if(! openssl_public_encrypt($str, $encrypt_str, $pub_key)) {
return '';
}
return base64_encode($encrypt_str);
}
echo encryptRsa(
'要加密的字符串',
file_get_contents('C:/Users/Administrator/DeskTop/public.key')
);
/**
* @function RSA解密算法,使用私钥解密数据
* @param $str string 要解密的数据
* @param $private_key string 私钥内容
* @return string
*/
function decryptRsa($str, $private_key) {
openssl_private_decrypt(base64_decode($str), $res, $private_key);
return $res;
}
echo decryptRsa(
'被解密的base64字符串',
file_get_contents('C:/Users/Administrator/DeskTop/private.key')
);
Base64不是加密与加密,而是编码与解码。它用于将二进制数据转换为文本形式以便在仅支持文本的系统中传输或存储,可保证二进制安全。
//服务端源数据为a
$init_data = 'a';
//拼接自定义的盐
$sign = md5($init_data . '自定义的盐');
//返回给客户端
echo $init_data . '.' . $sign;
假设攻击者将a修改成b,然后给服务端验签,服务端拦截过程如下:
$hacker_data = 'b.af997aac21a6eeaa354fa4d46eed2c58';
$arr = explode('.', $hacker_data);
$init_data = $arr[0];
$sign = $arr[1];
//验签
if(md5($init_data . '自定义的盐') != $sign) {
//验签不通过证明数据被篡改
return '验签不通过,拦截掉本次请求';
}
由于数据的创建和验签都是在服务端执行,所以攻击者并不知道签名算法,篡改数据也就无法通过服务端验签,恶意请求就此被拦截。
哈希碰撞(Hash Collision)是指在密码学和计算机科学中,两个不同的输入数据在经过哈希函数处理后,得到相同的哈希值,这个概率很低,但不代表没有。
告别阻塞!用 PHP TrueAsync 实现 PHP 脚本提
在 PHP 中写真正的异步代码 TrueAsync 0.6.0