Files
pgserver3.0/pgserver/application/lib/SmUtil.php
annnj-company 130c1026c4 first commit
2026-04-17 18:29:53 +08:00

324 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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;
}
}