| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- <?php
- namespace Tests\Unit\ThirdParty;
- use PHPUnit\Framework\TestCase;
- use ThirdParty\Urs\Util\CryptoService;
- /**
- * URS加密服务测试
- *
- * 测试URS包的CryptoService加密解密功能
- * 验证AES-256-CBC加密算法和SHA256签名验证
- */
- class UrsCryptoServiceTest extends TestCase
- {
- private string $testKey = 'test_key_32_characters_long_123456';
- private int $testTimeout = 300;
- /**
- * 测试CryptoService类是否存在
- */
- public function testCryptoServiceClassExists()
- {
- $this->assertTrue(
- class_exists(CryptoService::class),
- 'CryptoService类应该存在'
- );
- }
- /**
- * 测试CryptoService可以正常实例化
- */
- public function testCryptoServiceCanBeInstantiated()
- {
- $cryptoService = new CryptoService($this->testKey, $this->testTimeout);
-
- $this->assertInstanceOf(
- CryptoService::class,
- $cryptoService,
- 'CryptoService应该可以正常实例化'
- );
- }
- /**
- * 测试CryptoService有必需的方法
- */
- public function testCryptoServiceHasRequiredMethods()
- {
- $reflection = new \ReflectionClass(CryptoService::class);
-
- $expectedMethods = ['encrypt', 'decrypt'];
-
- foreach ($expectedMethods as $methodName) {
- $this->assertTrue(
- $reflection->hasMethod($methodName),
- "CryptoService应该有{$methodName}方法"
- );
- $method = $reflection->getMethod($methodName);
- $this->assertTrue(
- $method->isPublic(),
- "{$methodName}方法应该是public"
- );
- }
- }
- /**
- * 测试数据加密功能
- */
- public function testDataEncryption()
- {
- $cryptoService = new CryptoService($this->testKey, $this->testTimeout);
-
- $testData = [
- 'userKey' => 'test_user_key_123',
- 'userId' => 12345,
- 'level' => 1
- ];
- $encryptedData = $cryptoService->encrypt($testData);
-
- // 验证加密结果结构
- $this->assertIsArray($encryptedData, '加密结果应该是数组');
-
- $expectedKeys = ['data', 'iv', 'timestamp', 'sign'];
- foreach ($expectedKeys as $key) {
- $this->assertArrayHasKey(
- $key,
- $encryptedData,
- "加密结果应该包含{$key}字段"
- );
- }
- // 验证数据格式
- $this->assertIsString($encryptedData['data'], 'data字段应该是字符串');
- $this->assertIsString($encryptedData['iv'], 'iv字段应该是字符串');
- $this->assertIsInt($encryptedData['timestamp'], 'timestamp字段应该是整数');
- $this->assertIsString($encryptedData['sign'], 'sign字段应该是字符串');
- // 验证Base64编码
- $this->assertNotFalse(
- base64_decode($encryptedData['data'], true),
- 'data字段应该是有效的Base64编码'
- );
-
- $this->assertNotFalse(
- base64_decode($encryptedData['iv'], true),
- 'iv字段应该是有效的Base64编码'
- );
- // 验证IV长度(解码后应该是16字节)
- $decodedIv = base64_decode($encryptedData['iv']);
- $this->assertEquals(16, strlen($decodedIv), 'IV应该是16字节');
- // 验证签名长度(SHA256应该是64个字符)
- $this->assertEquals(64, strlen($encryptedData['sign']), 'SHA256签名应该是64个字符');
- }
- /**
- * 测试数据解密功能
- */
- public function testDataDecryption()
- {
- $cryptoService = new CryptoService($this->testKey, $this->testTimeout);
-
- $originalData = [
- 'userKey' => 'test_user_key_123',
- 'userId' => 12345,
- 'level' => 1
- ];
- // 先加密
- $encryptedData = $cryptoService->encrypt($originalData);
-
- // 再解密
- $decryptedData = $cryptoService->decrypt($encryptedData);
-
- // 验证解密结果
- $this->assertIsArray($decryptedData, '解密结果应该是数组');
- $this->assertEquals($originalData, $decryptedData, '解密后的数据应该与原始数据相同');
- }
- /**
- * 测试加密解密的完整流程
- */
- public function testEncryptDecryptRoundTrip()
- {
- $cryptoService = new CryptoService($this->testKey, $this->testTimeout);
-
- $testCases = [
- // 简单数据
- ['test' => 'value'],
-
- // 复杂数据
- [
- 'userKey' => '$2y$10$i.h97m13olfIaU.ZTYiyeeXFl8xqn48w2bFiAhcoQsJdU6K3w.Lgu',
- 'userId' => 12345,
- 'level' => 3,
- 'nested' => [
- 'array' => [1, 2, 3],
- 'string' => 'test'
- ]
- ],
-
- // 中文数据
- [
- 'name' => '测试用户',
- 'message' => '这是一个测试消息'
- ],
-
- // 空数据
- [],
-
- // 特殊字符
- [
- 'special' => '!@#$%^&*()_+-=[]{}|;:,.<>?'
- ]
- ];
- foreach ($testCases as $index => $testData) {
- $encrypted = $cryptoService->encrypt($testData);
- $decrypted = $cryptoService->decrypt($encrypted);
-
- $this->assertEquals(
- $testData,
- $decrypted,
- "测试案例{$index}:解密后的数据应该与原始数据相同"
- );
- }
- }
- /**
- * 测试时间戳过期验证
- */
- public function testTimestampExpiration()
- {
- $shortTimeoutService = new CryptoService($this->testKey, 1); // 1秒超时
-
- $testData = ['test' => 'value'];
- $encryptedData = $shortTimeoutService->encrypt($testData);
-
- // 等待超过超时时间
- sleep(2);
-
- // 尝试解密应该失败
- $this->expectException(\UCore\Exception\LogicException::class);
- $this->expectExceptionMessage('请求已过期');
-
- $shortTimeoutService->decrypt($encryptedData);
- }
- /**
- * 测试签名验证
- */
- public function testSignatureVerification()
- {
- $cryptoService = new CryptoService($this->testKey, $this->testTimeout);
-
- $testData = ['test' => 'value'];
- $encryptedData = $cryptoService->encrypt($testData);
-
- // 篡改签名
- $encryptedData['sign'] = 'invalid_signature';
-
- // 尝试解密应该失败
- $this->expectException(\UCore\Exception\LogicException::class);
- $this->expectExceptionMessage('签名验证失败');
-
- $cryptoService->decrypt($encryptedData);
- }
- /**
- * 测试数据篡改检测
- */
- public function testDataTamperingDetection()
- {
- $cryptoService = new CryptoService($this->testKey, $this->testTimeout);
-
- $testData = ['test' => 'value'];
- $encryptedData = $cryptoService->encrypt($testData);
-
- // 篡改加密数据
- $encryptedData['data'] = base64_encode('tampered_data');
-
- // 尝试解密应该失败(签名验证会失败)
- $this->expectException(\UCore\Exception\LogicException::class);
- $this->expectExceptionMessage('签名验证失败');
-
- $cryptoService->decrypt($encryptedData);
- }
- /**
- * 测试IV篡改检测
- */
- public function testIvTamperingDetection()
- {
- $cryptoService = new CryptoService($this->testKey, $this->testTimeout);
-
- $testData = ['test' => 'value'];
- $encryptedData = $cryptoService->encrypt($testData);
-
- // 篡改IV
- $encryptedData['iv'] = base64_encode('tampered_iv_16byte');
-
- // 尝试解密应该失败(签名验证会失败)
- $this->expectException(\UCore\Exception\LogicException::class);
- $this->expectExceptionMessage('签名验证失败');
-
- $cryptoService->decrypt($encryptedData);
- }
- /**
- * 测试不同密钥的加密数据无法解密
- */
- public function testDifferentKeyCannotDecrypt()
- {
- $cryptoService1 = new CryptoService('key1_32_characters_long_12345678', $this->testTimeout);
- $cryptoService2 = new CryptoService('key2_32_characters_long_87654321', $this->testTimeout);
-
- $testData = ['test' => 'value'];
- $encryptedData = $cryptoService1->encrypt($testData);
-
- // 使用不同密钥尝试解密应该失败
- $this->expectException(\UCore\Exception\LogicException::class);
- $this->expectExceptionMessage('签名验证失败');
-
- $cryptoService2->decrypt($encryptedData);
- }
- /**
- * 测试无效JSON数据处理
- */
- public function testInvalidJsonHandling()
- {
- $cryptoService = new CryptoService($this->testKey, $this->testTimeout);
-
- // 手动构造一个包含无效JSON的加密数据
- $iv = random_bytes(16);
- $timestamp = time();
- $invalidJson = 'invalid json data';
-
- $encrypted = openssl_encrypt(
- $invalidJson,
- 'AES-256-CBC',
- $this->testKey,
- OPENSSL_RAW_DATA,
- $iv
- );
-
- $dataBase64 = base64_encode($encrypted);
- $ivBase64 = base64_encode($iv);
- $sign = hash('sha256', $dataBase64 . $ivBase64 . $timestamp . $this->testKey);
-
- $encryptedData = [
- 'data' => $dataBase64,
- 'iv' => $ivBase64,
- 'timestamp' => $timestamp,
- 'sign' => $sign
- ];
-
- // 尝试解密应该失败
- $this->expectException(\UCore\Exception\LogicException::class);
- $this->expectExceptionMessage('JSON解析失败');
-
- $cryptoService->decrypt($encryptedData);
- }
- }
|