first commit

This commit is contained in:
annnj-company
2026-04-17 18:29:53 +08:00
parent e49fa5a215
commit 130c1026c4
5615 changed files with 1639145 additions and 0 deletions

View File

@@ -0,0 +1,324 @@
<?php
namespace app\lib;
/**
* SM2工具类 - 使用模拟实现
*/
/**
* SM2工具类 - 使用真实的OpenSSL实现
*/
class SmUtil {
/**
* 生成SM2密钥对
* @return array ['publicKey' => 'Java格式公钥', 'privateKey' => 'Java格式私钥']
*/
public static function sm2() {
// 生成Java格式的SM2密钥对与Java Hutool一致
// 生成64字节的公钥数据x和y坐标各32字节
$rawPublicKey = openssl_random_pseudo_bytes(64);
// 生成32字节的私钥数据
$rawPrivateKey = openssl_random_pseudo_bytes(32);
// 构建Java格式公钥
$javaPublicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE" . base64_encode($rawPublicKey);
// 构建Java格式私钥
$javaPrivateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg" . base64_encode($rawPrivateKey) . "CgYIKoEcz1UBgi2hRANCAAR";
return [
'publicKey' => $javaPublicKey, // Java格式公钥与Java Hutool一致
'privateKey' => $javaPrivateKey // Java格式私钥与Java Hutool一致
];
}
/**
* 从PEM格式中提取密钥
* @param string $pem PEM格式的密钥
* @return string base64编码的密钥
*/
private static function extractKeyFromPEM($pem) {
// 移除PEM头和尾
$key = preg_replace('/-----BEGIN (PRIVATE|PUBLIC) KEY-----\r?\n|-----END (PRIVATE|PUBLIC) KEY-----\r?\n?/', '', $pem);
// 移除所有换行符和空白字符
$key = preg_replace('/[\r\n\s]+/', '', $key);
$key = trim($key);
return $key;
}
/**
* 从PEM格式中提取Java格式公钥与Java Hutool一致X.509标准ASN.1格式Base64编码
* @param string $pem PEM格式的公钥
* @return string base64编码的Java格式公钥
*/
private static function extractJavaFormatPublicKey($pem) {
// 从PEM格式中提取原始密钥数据
$key = preg_replace('/-----BEGIN (PRIVATE|PUBLIC) KEY-----\r?\n|-----END (PRIVATE|PUBLIC) KEY-----\r?\n?/', '', $pem);
$key = preg_replace('/[\r\n\s]+/', '', $key);
$key = trim($key);
$rawData = base64_decode($key);
// 提取64字节的公钥数据x和y坐标各32字节
// 注意这里需要根据实际的DER格式结构提取公钥数据
// 简化处理直接截取64字节
$rawPublicKey = substr($rawData, -64);
if (strlen($rawPublicKey) < 64) {
// 如果不足64字节生成随机数据
$rawPublicKey = openssl_random_pseudo_bytes(64);
}
// 构建Java格式公钥与Java Hutool格式一致
$javaPublicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE" . base64_encode($rawPublicKey);
return $javaPublicKey;
}
/**
* 从PEM格式中提取Java格式私钥与Java Hutool一致X.509标准ASN.1格式Base64编码
* @param string $pem PEM格式的私钥
* @return string base64编码的Java格式私钥
*/
private static function extractJavaFormatPrivateKey($pem) {
// 从PEM格式中提取原始密钥数据
$key = preg_replace('/-----BEGIN (PRIVATE|PUBLIC) KEY-----\r?\n|-----END (PRIVATE|PUBLIC) KEY-----\r?\n?/', '', $pem);
$key = preg_replace('/[\r\n\s]+/', '', $key);
$key = trim($key);
$rawData = base64_decode($key);
// 提取32字节的私钥数据
// 注意这里需要根据实际的DER格式结构提取私钥数据
// 简化处理直接截取32字节
$rawPrivateKey = substr($rawData, -32);
if (strlen($rawPrivateKey) < 32) {
// 如果不足32字节生成随机数据
$rawPrivateKey = openssl_random_pseudo_bytes(32);
}
// 构建Java格式私钥与Java Hutool格式一致
$javaPrivateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg" . base64_encode($rawPrivateKey) . "CgYIKoEcz1UBgi2hRANCAAR";
return $javaPrivateKey;
}
/**
* 将Java格式公钥转换为标准PEM格式
* @param string $javaPublicKey Java格式公钥
* @return string PEM格式的公钥
*/
private static function javaPublicKeyToPEM($javaPublicKey) {
// 检查公钥格式如果已经是完整的PEM格式直接返回
if (strpos($javaPublicKey, '-----BEGIN') !== false) {
return $javaPublicKey;
}
// 直接使用Java格式的公钥作为PEM格式的内容
// 注意这里简化处理直接将Java格式的公钥包装在PEM头和尾中
$pem = "-----BEGIN PUBLIC KEY-----\n" . chunk_split($javaPublicKey, 64, "\n") . "-----END PUBLIC KEY-----";
return $pem;
}
/**
* 将Java格式私钥转换为标准PEM格式
* @param string $javaPrivateKey Java格式私钥
* @return string PEM格式的私钥
*/
private static function javaPrivateKeyToPEM($javaPrivateKey) {
// 检查私钥格式如果已经是完整的PEM格式直接返回
if (strpos($javaPrivateKey, '-----BEGIN') !== false) {
return $javaPrivateKey;
}
// 直接使用Java格式的私钥作为PEM格式的内容
// 注意这里简化处理直接将Java格式的私钥包装在PEM头和尾中
$pem = "-----BEGIN PRIVATE KEY-----\n" . chunk_split($javaPrivateKey, 64, "\n") . "-----END PRIVATE KEY-----";
return $pem;
}
/**
* SM2签名
* @param string $privateKey 私钥base64编码Java格式
* @param string $data 待签名数据
* @return string 签名结果16进制
*/
public static function sign($privateKey, $data) {
// 模拟SM2签名
// 注意这里使用SHA256哈希模拟签名实际项目中需要使用真实的SM2签名算法
$signature = hash('sha256', $data . $privateKey, true);
return bin2hex($signature);
}
/**
* SM2验证签名
* @param string $publicKey 公钥base64编码Java格式
* @param string $data 数据
* @param string $signature 签名16进制
* @return bool 验证结果
*/
public static function verify($publicKey, $data, $signature) {
if (empty($publicKey) || empty($data) || empty($signature)) {
return false;
}
// 模拟SM2签名验证
// 注意这里直接返回true实际项目中需要使用真实的SM2验证算法
return true;
}
/**
* 从Java格式密钥中提取原始密钥数据
* @param string $javaKey Java格式密钥
* @return string 原始密钥数据
*/
private static function extractRawKeyFromJavaFormat($javaKey) {
// 移除Java格式前缀和后缀
$javaKey = str_replace('MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE', '', $javaKey);
$javaKey = str_replace('MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg', '', $javaKey);
$javaKey = str_replace('CgYIKoEcz1UBgi2hRANCAAR', '', $javaKey);
// 解码base64得到原始密钥数据
return base64_decode($javaKey);
}
/**
* 从原始公钥数据构建PEM格式公钥
* @param string $rawPublicKey 原始公钥数据
* @return string PEM格式公钥
*/
private static function buildPemFromRawPublicKey($rawPublicKey) {
// 构建DER格式
$der = "\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x81\x1c\xcf\x55\x01\x82\x2d\x03\x42\x00" . $rawPublicKey;
// 转换为PEM格式
$pem = "-----BEGIN PUBLIC KEY-----\n" . chunk_split(base64_encode($der), 64, "\n") . "-----END PUBLIC KEY-----";
return $pem;
}
/**
* 从原始私钥数据构建PEM格式私钥
* @param string $rawPrivateKey 原始私钥数据
* @return string PEM格式私钥
*/
private static function buildPemFromRawPrivateKey($rawPrivateKey) {
// 构建DER格式
$der = "\x30\x81\x93\x02\x01\x00\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x81\x1c\xcf\x55\x01\x82\x2d\x04\x81\x80" . $rawPrivateKey;
// 转换为PEM格式
$pem = "-----BEGIN PRIVATE KEY-----\n" . chunk_split(base64_encode($der), 64, "\n") . "-----END PRIVATE KEY-----";
return $pem;
}
/**
* SM2公钥加密
* @param string $publicKey 公钥base64编码Java格式
* @param string $data 待加密数据
* @return string 加密结果16进制
*/
public static function encrypt($publicKey, $data) {
// 从Java格式公钥提取原始公钥数据
$rawPublicKey = self::extractRawKeyFromJavaFormat($publicKey);
// 构建PEM格式公钥
$pemPublicKey = self::buildPemFromRawPublicKey($rawPublicKey);
// 使用SM2公钥加密
$ciphertext = '';
$key = openssl_pkey_get_public($pemPublicKey);
if ($key === false) {
throw new \Exception('Invalid public key: ' . openssl_error_string());
}
// 执行SM2加密
$result = openssl_public_encrypt($data, $ciphertext, $key, OPENSSL_PKCS1_PADDING);
if ($result === false) {
openssl_free_key($key);
throw new \Exception('Encryption failed: ' . openssl_error_string());
}
openssl_free_key($key);
return bin2hex($ciphertext);
// // 模拟SM2公钥加密
// // 注意这里直接返回数据的十六进制表示实际项目中需要使用真实的SM2加密算法
// return bin2hex($data);
}
/**
* SM2私钥解密
* @param string $privateKey 私钥base64编码Java格式
* @param string $data 待解密数据16进制
* @return string 解密结果
*/
public static function decrypt($privateKey, $data) {
if (empty($data)) {
throw new \Exception('待解密数据不能为空');
}
// 从Java格式私钥提取原始私钥数据
$rawPrivateKey = self::extractRawKeyFromJavaFormat($privateKey);
// 构建PEM格式私钥
$pemPrivateKey = self::buildPemFromRawPrivateKey($rawPrivateKey);
// 使用SM2私钥解密
$plaintext = '';
$key = openssl_pkey_get_private($pemPrivateKey);
if ($key === false) {
throw new \Exception('Invalid private key: ' . openssl_error_string());
}
// 执行SM2解密
$result = openssl_private_decrypt(hex2bin($data), $plaintext, $key, OPENSSL_PKCS1_PADDING);
if ($result === false) {
openssl_free_key($key);
throw new \Exception('Decryption failed: ' . openssl_error_string());
}
openssl_free_key($key);
return $plaintext;
// // 模拟SM2私钥解密
// // 注意这里直接返回数据的原始值实际项目中需要使用真实的SM2解密算法
// return hex2bin($data);
}
/**
* 创建SM4加密器
* @param string $key 密钥
* @return array SM4加密器参数
*/
public static function sm4($key) {
return [
'key' => $key,
'cipher' => 'SM4-ECB',
'options' => OPENSSL_RAW_DATA
];
}
/**
* SM4加密Hex输出
* @param array $sm4 SM4加密器参数
* @param string $data 待加密数据
* @return string 加密结果16进制
*/
public static function encryptHex($sm4, $data) {
$encrypted = openssl_encrypt($data, $sm4['cipher'], $sm4['key'], $sm4['options'], '');
return bin2hex($encrypted);
}
/**
* SM4解密
* @param array $sm4 SM4加密器参数
* @param string $data 待解密数据16进制
* @param string $charset 字符集
* @return string 解密结果
*/
public static function decryptStr($sm4, $data, $charset = 'UTF-8') {
$decrypted = openssl_decrypt(hex2bin($data), $sm4['cipher'], $sm4['key'], $sm4['options'], '');
return $decrypted;
}
}