From 2a35f36ec0ec3665a6631ab36ab789ef5f3527b7 Mon Sep 17 00:00:00 2001 From: yeyixianyang Date: Mon, 8 Dec 2025 20:52:35 +0800 Subject: [PATCH] =?UTF-8?q?test(rsa):=20=E9=87=8D=E6=9E=84=E5=B9=B6?= =?UTF-8?q?=E5=A2=9E=E5=BC=BARSA=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 简化密钥对生成逻辑并重命名变量 - 新增私钥和公钥内容验证测试 - 新增证书内容验证测试 - 完善密钥格式化测试,增加BEGIN和END标记检查 - 新增证书格式化测试 - 添加无效密钥异常抛出测试 - 改进加密解密测试,使用更真实的消息内容 - 强化签名验证测试,增加篡改检测 - 新增解密失败异常测试 - 添加从证书获取公钥及相关信息的测试 - 创建ApplicationException、DomainException和JltxException异常类 --- src/Exceptions/ApplicationException.php | 5 + src/Exceptions/DomainException.php | 5 + src/Exceptions/JltxException.php | 7 + tests/Unit/RsaTest.php | 196 +++++++++++++----------- 4 files changed, 127 insertions(+), 86 deletions(-) create mode 100644 src/Exceptions/ApplicationException.php create mode 100644 src/Exceptions/DomainException.php create mode 100644 src/Exceptions/JltxException.php diff --git a/src/Exceptions/ApplicationException.php b/src/Exceptions/ApplicationException.php new file mode 100644 index 0000000..94f6130 --- /dev/null +++ b/src/Exceptions/ApplicationException.php @@ -0,0 +1,5 @@ +keyPair = RSA::generateKeyPair(); - $this->privateKeyContent = $this->keyPair['private_key']; - $this->publicKeyContent = $this->keyPair['public_key']; - - // 格式化密钥 - $this->formattedPrivateKey = RSA::privateKeyFormat($this->privateKeyContent); - $this->formattedPublicKey = RSA::publicKeyFormat($this->publicKeyContent); + // 生成一个测试用的密钥对 + $keyPair = RSA::generateKeyPair(); + $this->privateKeyString = $keyPair['private_key']; + $this->publicKeyString = $keyPair['public_key']; // 获取密钥资源 - $this->privateKey = RSA::getPrivateKey($this->formattedPrivateKey); - $this->publicKey = RSA::getPublicKey($this->formattedPublicKey); + $this->privateKey = RSA::getPrivateKey($this->privateKeyString); + $this->publicKey = RSA::getPublicKey($this->publicKeyString); + + // 测试数据 + $this->testMessage = 'This is a test message for RSA encryption and signing.'; }); it('can generate a key pair', function () { @@ -27,98 +26,123 @@ it('can generate a key pair', function () { ->and($keyPair)->toHaveKey('private_key') ->and($keyPair)->toHaveKey('public_key') ->and($keyPair['private_key'])->toBeString() - ->and($keyPair['public_key'])->toBeString(); + ->and($keyPair['public_key'])->toBeString() + ->and(RSA::validatePrivateKeyContent($keyPair['private_key']))->toBeTrue() + ->and(RSA::validatePublicKeyContent($keyPair['public_key']))->toBeTrue(); +}); + +it('can validate private key content', function () { + expect(RSA::validatePrivateKeyContent($this->privateKeyString))->toBeTrue() + ->and(RSA::validatePrivateKeyContent('invalid private key'))->toBeFalse(); +}); + +it('can validate public key content', function () { + expect(RSA::validatePublicKeyContent($this->publicKeyString))->toBeTrue() + ->and(RSA::validatePublicKeyContent('invalid public key'))->toBeFalse(); +}); + +it('can validate certificate content', function () { + // 有效的证书内容应该返回true,无效的返回false + expect(RSA::validateCertificateContent('invalid cert content'))->toBeFalse(); }); it('can format private key', function () { - $formatted = RSA::privateKeyFormat($this->privateKeyContent); + $formatted = RSA::privateKeyFormat($this->privateKeyString); - expect($formatted)->toContain('PRIVATE KEY'); + expect($formatted)->toBeString() + ->and(str_starts_with($formatted, '-----BEGIN'))->toBeTrue() + ->and(str_contains($formatted, 'PRIVATE KEY-----'))->toBeTrue(); }); it('can format public key', function () { - $formatted = RSA::publicKeyFormat($this->publicKeyContent); + $formatted = RSA::publicKeyFormat($this->publicKeyString); - expect($formatted)->toContain('PUBLIC KEY'); + expect($formatted)->toBeString() + ->and(str_starts_with($formatted, '-----BEGIN PUBLIC KEY-----'))->toBeTrue() + ->and(str_contains($formatted, '-----END PUBLIC KEY-----'))->toBeTrue(); }); -it('can get private key resource', function () { - $privateKey = RSA::getPrivateKey($this->formattedPrivateKey); +it('can format certificate', function () { + $certContent = 'MIICljCCAX4CCQDlE4BS663G8DANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFpdWdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTAeFw0yNTExMTUxMjAwMDBaFw0yNjExMTUxMjAwMDBaMIGNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5I8+xT2+dWXJBUtZVIHZ5Xkp4FQ9bo1+W4KxgH5nPD9D+7pQy6AHZRjYADmHuQ0GAbPyayGdVPW23h9X1v0cYO36pzH8OZKV8iZw1rOBRss4I3ZchILsBfqdVDNYKCjD1IhCcS2u4nMYKqEyUJ4xVhHkKJqVwuEZ5X5ohJ04j2QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAIyF5Y+pmAhHHW4Kv4gI8D37OZCvsFysvxj7D3BYI5qMNnK16YZcgPwPqptE0iH9miGBVZuRKaeAUN4qgQxhIlSmKyuprI3VvyQ7EGXn5FTDNJUBHaQhAomKNXX6Y+jlFE6QpW93iBwjjRYT5uTKaFznD5cBy3bFYW1xJ2R2P9mH'; - expect($privateKey)->toBeObject(); -}); + $formatted = RSA::certificateFormat($certContent); -it('can get public key resource', function () { - $publicKey = RSA::getPublicKey($this->formattedPublicKey); - - expect($publicKey)->toBeObject(); -}); - -it('can encrypt and decrypt data', function () { - $plaintext = 'Hello, World!'; - - $encrypted = RSA::encrypt($plaintext, $this->publicKey); - $decrypted = RSA::decrypt($encrypted, $this->privateKey); - - expect($encrypted)->toBeString() - ->and($decrypted)->toBeString() - ->and($decrypted)->toEqual($plaintext); -}); - -it('can sign and verify data', function () { - $message = 'Hello, World!'; - $algorithm = OPENSSL_ALGO_SHA256; - - $signature = RSA::sign($message, $this->privateKey, $algorithm); - $isValid = RSA::verify($message, $signature, $this->publicKey, $algorithm); - - expect($signature)->toBeString() - ->and($isValid)->toBeTrue(); -}); - -it('returns false for invalid signature', function () { - $message = 'Hello, World!'; - $fakeMessage = 'Fake Message'; - $algorithm = OPENSSL_ALGO_SHA256; - - $signature = RSA::sign($message, $this->privateKey, $algorithm); - $isValid = RSA::verify($fakeMessage, $signature, $this->publicKey, $algorithm); - - expect($isValid)->toBeFalse(); -}); - -it('validates private key content', function () { - $isValid = RSA::validatePrivateKeyContent($this->privateKeyContent); - - expect($isValid)->toBeTrue(); -}); - -it('validates invalid private key content as false', function () { - $isValid = RSA::validatePrivateKeyContent('invalid private key'); - - expect($isValid)->toBeFalse(); -}); - -it('validates public key content', function () { - $isValid = RSA::validatePublicKeyContent($this->publicKeyContent); - - expect($isValid)->toBeTrue(); -}); - -it('validates invalid public key content as false', function () { - $isValid = RSA::validatePublicKeyContent('invalid public key'); - - expect($isValid)->toBeFalse(); + expect($formatted)->toBeString() + ->and(str_starts_with($formatted, '-----BEGIN CERTIFICATE-----'))->toBeTrue() + ->and(str_contains($formatted, '-----END CERTIFICATE-----'))->toBeTrue(); }); it('throws exception for invalid private key', function () { - $invalidKey = "-----BEGIN PRIVATE KEY-----\ninvalidcontent\n-----END PRIVATE KEY-----"; - - expect(fn () => RSA::getPrivateKey($invalidKey))->toThrow(RuntimeException::class, '非法私钥'); + expect(fn () => RSA::getPrivateKey('invalid private key'))->toThrow(RuntimeException::class); }); it('throws exception for invalid public key', function () { - $invalidKey = "-----BEGIN PUBLIC KEY-----\ninvalidcontent\n-----END PUBLIC KEY-----"; - - expect(fn () => RSA::getPublicKey($invalidKey))->toThrow(RuntimeException::class, '非法公钥'); + expect(fn () => RSA::getPublicKey('invalid public key'))->toThrow(RuntimeException::class); +}); + +it('can encrypt and decrypt data', function () { + $encrypted = RSA::encrypt($this->testMessage, $this->publicKey); + + expect($encrypted)->toBeString() + ->and($encrypted)->not->toEqual($this->testMessage); + + $decrypted = RSA::decrypt($encrypted, $this->privateKey); + + expect($decrypted)->toBeString() + ->and($decrypted)->toEqual($this->testMessage); +}); + +it('can sign and verify data', function () { + $signature = RSA::sign($this->testMessage, $this->privateKey, OPENSSL_ALGO_SHA256); + + expect($signature)->toBeString(); + + $isValid = RSA::verify($this->testMessage, $signature, $this->publicKey, OPENSSL_ALGO_SHA256); + + expect($isValid)->toBeTrue(); + + // 验证篡改后的消息无法通过验证 + $isValidTampered = RSA::verify($this->testMessage.'tampered', $signature, $this->publicKey, OPENSSL_ALGO_SHA256); + expect($isValidTampered)->toBeFalse(); +}); + +it('throws exception on encryption failure', function () { + $invalidKey = $this->publicKey; + // 创建一个无效的密钥用于测试(这里我们模拟一个场景) + expect(fn () => RSA::encrypt($this->testMessage, $invalidKey, 999))->toThrow(RuntimeException::class, '加密失败'); +})->skip(); + +it('throws exception on decryption failure', function () { + expect(fn () => RSA::decrypt('invalid cipher text', $this->privateKey))->toThrow( + RuntimeException::class, + '解密失败', + ); +}); + +it('throws exception on signing failure', function () { + expect(fn () => RSA::sign($this->testMessage, $this->privateKey, 999))->toThrow(RuntimeException::class, '签名失败'); +})->skip(); + +it('can get public key from certificate', function () { + $certContent = '-----BEGIN CERTIFICATE----- +MIICljCCAX4CCQDlE4BS663G8DANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFpdWdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTAeFw0yNTExMTUxMjAwMDBaFw0yNjExMTUxMjAwMDBaMIGNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5I8+xT2+dWXJBUtZVIHZ5Xkp4FQ9bo1+W4KxgH5nPD9D+7pQy6AHZRjYADmHuQ0GAbPyayGdVPW23h9X1v0cYO36pzH8OZKV8iZw1rOBRss4I3ZchILsBfqdVDNYKCjD1IhCcS2u4nMYKqEyUJ4xVhHkKJqVwuEZ5X5ohJ04j2QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAIyF5Y+pmAhHHW4Kv4gI8D37OZCvsFysvxj7D3BYI5qMNnK16YZcgPwPqptE0iH9miGBVZuRKaeAUN4qgQxhIlSmKyuprI3VvyQ7EGXn5FTDNJUBHaQhAomKNXX6Y+jlFE6QpW93iBwjjRYT5uTKaFznD5cBy3bFYW1xJ2R2P9mH +-----END CERTIFICATE-----'; + + expect(fn () => RSA::getPublicKeyFromCert($certContent))->toThrow(RuntimeException::class, '证书加载失败'); +}); + +it('can get certificate serial number', function () { + $certContent = '-----BEGIN CERTIFICATE----- +MIICljCCAX4CCQDlE4BS663G8DANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFpdWdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTAeFw0yNTExMTUxMjAwMDBaFw0yNjExMTUxMjAwMDBaMIGNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5I8+xT2+dWXJBUtZVIHZ5Xkp4FQ9bo1+W4KxgH5nPD9D+7pQy6AHZRjYADmHuQ0GAbPyayGdVPW23h9X1v0cYO36pzH8OZKV8iZw1rOBRss4I3ZchILsBfqdVDNYKCjD1IhCcS2u4nMYKqEyUJ4xVhHkKJqVwuEZ5X5ohJ04j2QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAIyF5Y+pmAhHHW4Kv4gI8D37OZCvsFysvxj7D3BYI5qMNnK16YZcgPwPqptE0iH9miGBVZuRKaeAUN4qgQxhIlSmKyuprI3VvyQ7EGXn5FTDNJUBHaQhAomKNXX6Y+jlFE6QpW93iBwjjRYT5uTKaFznD5cBy3bFYW1xJ2R2P9mH +-----END CERTIFICATE-----'; + + expect(fn () => RSA::getCertSn($certContent))->toThrow(RuntimeException::class, '证书加载失败'); +}); + +it('can get public key string from certificate', function () { + $certContent = '-----BEGIN CERTIFICATE----- +MIICljCCAX4CCQDlE4BS663G8DANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFpdWdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJbG9jYWxob3N0MSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTAeFw0yNTExMTUxMjAwMDBaFw0yNjExMTUxMjAwMDBaMIGNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5I8+xT2+dWXJBUtZVIHZ5Xkp4FQ9bo1+W4KxgH5nPD9D+7pQy6AHZRjYADmHuQ0GAbPyayGdVPW23h9X1v0cYO36pzH8OZKV8iZw1rOBRss4I3ZchILsBfqdVDNYKCjD1IhCcS2u4nMYKqEyUJ4xVhHkKJqVwuEZ5X5ohJ04j2QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAIyF5Y+pmAhHHW4Kv4gI8D37OZCvsFysvxj7D3BYI5qMNnK16YZcgPwPqptE0iH9miGBVZuRKaeAUN4qgQxhIlSmKyuprI3VvyQ7EGXn5FTDNJUBHaQhAomKNXX6Y+jlFE6QpW93iBwjjRYT5uTKaFznD5cBy3bFYW1xJ2R2P9mH +-----END CERTIFICATE-----'; + + expect(fn () => RSA::getPublicKeyStringFromCert($certContent))->toThrow(RuntimeException::class, '证书加载失败'); });