Skip to content

Commit 44a54bd

Browse files
author
苏青安
committed
refactor(core): 前端自动生成AES密钥,通过RSA加密传输
BREAKING CHANGE: 逻辑变更,增强安全性,不对过去进行兼容,因此版本号提升到2.0.0
1 parent f654b57 commit 44a54bd

File tree

3 files changed

+99
-31
lines changed

3 files changed

+99
-31
lines changed

src/Contracts/DecryptorInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ interface DecryptorInterface
99
*
1010
* @param string $data 加密字符串
1111
*
12-
* @return array 解密后的数组
12+
* @return array|string 解密后的数组或字符串
1313
* @throws \Hejunjie\EncryptedRequest\Exceptions\DecryptionException
1414
*/
15-
public function decrypt(string $data): array;
15+
public function decrypt(string $data): array|string;
1616
}

src/Drivers/RsaDecryptor.php

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
namespace Hejunjie\EncryptedRequest\Drivers;
4+
5+
use Hejunjie\EncryptedRequest\Contracts\DecryptorInterface;
6+
use Hejunjie\EncryptedRequest\Exceptions\DecryptionException;
7+
8+
class RsaDecryptor implements DecryptorInterface
9+
{
10+
private mixed $privateKey;
11+
12+
/**
13+
* 构造方法
14+
*
15+
* @param string $private_key 私钥字符串(包含 -----BEGIN PRIVATE KEY-----)
16+
*/
17+
public function __construct(string $private_key)
18+
{
19+
$this->privateKey = @openssl_pkey_get_private($private_key);
20+
if ($this->privateKey === false) {
21+
$errs = [];
22+
while ($err = openssl_error_string()) {
23+
$errs[] = $err;
24+
}
25+
$msg = 'Failed to load private key';
26+
if (!empty($errs)) {
27+
$msg .= ': ' . implode(' | ', $errs);
28+
}
29+
throw new DecryptionException($msg);
30+
}
31+
}
32+
33+
/**
34+
* 解密方法
35+
*
36+
* @param string $data 加密数据
37+
*
38+
* @return string 解密后的字符串
39+
* @throws DecryptionException
40+
*/
41+
public function decrypt(string $data): string
42+
{
43+
try {
44+
// Base64 解码
45+
$ciphertext = base64_decode($data, true);
46+
if ($ciphertext === false) {
47+
throw new DecryptionException('enc_payload is not valid base64');
48+
}
49+
// 检查 OpenSSL 扩展是否可用
50+
if (!function_exists('openssl_pkey_get_private')) {
51+
throw new DecryptionException('OpenSSL extension is not available in PHP');
52+
}
53+
// 尝试解密
54+
$decrypted = '';
55+
$success = @openssl_private_decrypt($ciphertext, $decrypted, $this->privateKey, OPENSSL_PKCS1_OAEP_PADDING);
56+
if ($success === false) {
57+
$errs = [];
58+
while ($err = openssl_error_string()) {
59+
$errs[] = $err;
60+
}
61+
$msg = 'RSA decryption failed';
62+
if (!empty($errs)) {
63+
$msg .= ': ' . implode(' | ', $errs);
64+
} else {
65+
$msg .= '. No OpenSSL errors captured.';
66+
}
67+
throw new DecryptionException($msg);
68+
}
69+
// 额外校验:解密结果不能为空
70+
if ($decrypted === '' || $decrypted === null) {
71+
throw new DecryptionException('RSA decryption returned empty string');
72+
}
73+
return $decrypted;
74+
} catch (\Throwable $e) {
75+
throw new DecryptionException($e->getMessage(), $e->getCode(), $e);
76+
}
77+
}
78+
}

src/EncryptedRequestHandler.php

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,23 @@
22

33
namespace Hejunjie\EncryptedRequest;
44

5-
use Hejunjie\EncryptedRequest\Contracts\DecryptorInterface;
65
use Hejunjie\EncryptedRequest\Config\EnvConfigLoader;
76
use Hejunjie\EncryptedRequest\Drivers\AesDecryptor;
7+
use Hejunjie\EncryptedRequest\Drivers\RsaDecryptor;
88
use Hejunjie\EncryptedRequest\Exceptions\DecryptionException;
99
use Hejunjie\EncryptedRequest\Exceptions\SignatureException;
1010
use Hejunjie\EncryptedRequest\Exceptions\TimestampException;
1111

1212
class EncryptedRequestHandler
1313
{
1414
private array $config;
15-
private DecryptorInterface $decryptor;
1615

1716
/**
1817
* 构造方法
1918
*
20-
* @param DecryptorInterface $decryptor 解密器
2119
* @param array|string|null $config 配置数组或.env路径
2220
*/
23-
public function __construct(string|DecryptorInterface $decryptorDriver = 'aes', array|string $config = '')
21+
public function __construct(array|string $config = '')
2422
{
2523
if (is_array($config)) {
2624
$loader = new EnvConfigLoader($config);
@@ -30,23 +28,9 @@ public function __construct(string|DecryptorInterface $decryptorDriver = 'aes',
3028
$loader = new EnvConfigLoader();
3129
}
3230
$this->config = [
33-
'key' => $loader->get('APP_KEY'),
34-
'default_timestamp_diff' => $loader->get('DEFAULT_TIMESTAMP_DIFF', 60)
31+
'default_timestamp_diff' => $loader->get('DEFAULT_TIMESTAMP_DIFF', 60),
32+
'rsa_private_key' => $loader->get('RSA_PRIVATE_KEY', '')
3533
];
36-
// 判断是字符串还是实例
37-
if ($decryptorDriver instanceof DecryptorInterface) {
38-
$this->decryptor = $decryptorDriver;
39-
} elseif (is_string($decryptorDriver)) {
40-
switch (strtolower($decryptorDriver)) {
41-
case 'aes':
42-
$this->decryptor = new AesDecryptor($loader->get('AES_KEY'), $loader->get('AES_IV'));
43-
break;
44-
default:
45-
throw new DecryptionException("Unsupported decryptor driver: {$decryptorDriver}");
46-
}
47-
} else {
48-
throw new DecryptionException("Invalid decryptor provided");
49-
}
5034
}
5135

5236
/**
@@ -61,24 +45,30 @@ public function __construct(string|DecryptorInterface $decryptorDriver = 'aes',
6145
* @throws TimestampException 请求时间错误
6246
* @throws DecryptionException 数据解密错误
6347
*/
64-
public function handle(string $en_data, int $timestamp, string $sign): array
48+
public function handle(string $en_data, string $enc_payload, int $timestamp, string $sign): array
6549
{
66-
// 1. 签名验证
6750
if (!isset($timestamp, $sign, $en_data)) {
6851
throw new SignatureException("Missing required parameters");
6952
}
70-
$expectedSign = md5($this->config['key'] . $timestamp);
71-
if ($expectedSign !== $sign) {
72-
throw new SignatureException("Invalid signature");
73-
}
74-
// 2. 时间戳验证
53+
// 1. 时间戳验证
7554
$timestampDiff = $this->config['default_timestamp_diff'];
7655
$now = time();
7756
if (abs($now - $timestamp) > $timestampDiff) {
7857
throw new TimestampException("Timestamp difference too large");
7958
}
80-
// 3. 解密数据
81-
$decrypted = $this->decryptor->decrypt($en_data);
59+
// 2. 获取签名数据
60+
$rsa = new RsaDecryptor($this->config['rsa_private_key']);
61+
$enc_payload = $rsa->decrypt($enc_payload);
62+
// 3. 签名验证
63+
$expectedSign = md5(md5($enc_payload) . $timestamp);
64+
if ($expectedSign !== $sign) {
65+
throw new SignatureException("Invalid signature");
66+
}
67+
// 4. 解密数据
68+
$aesKeyBase64 = substr($enc_payload, 0, 24);
69+
$aesIvBase64 = substr($enc_payload, -24);
70+
$aes = new AesDecryptor(base64_decode($aesKeyBase64), base64_decode($aesIvBase64));
71+
$decrypted = $aes->decrypt($en_data);
8272
return $decrypted;
8373
}
8474
}

0 commit comments

Comments
 (0)