test(rsa): 重构并增强RSA测试用例

- 简化密钥对生成逻辑并重命名变量
- 新增私钥和公钥内容验证测试
- 新增证书内容验证测试
- 完善密钥格式化测试,增加BEGIN和END标记检查
- 新增证书格式化测试
- 添加无效密钥异常抛出测试
- 改进加密解密测试,使用更真实的消息内容
- 强化签名验证测试,增加篡改检测
- 新增解密失败异常测试
- 添加从证书获取公钥及相关信息的测试
- 创建ApplicationException、DomainException和JltxException异常类
This commit is contained in:
yeyixianyang 2025-12-08 20:52:35 +08:00
parent bc42abeae8
commit 529fb45322
4 changed files with 127 additions and 86 deletions

View File

@ -0,0 +1,5 @@
<?php
namespace Jltx\Support\Exceptions;
class ApplicationException extends JltxException {}

View File

@ -0,0 +1,5 @@
<?php
namespace Jltx\Support\Exceptions;
class DomainException extends JltxException {}

View File

@ -0,0 +1,7 @@
<?php
namespace Jltx\Support\Exceptions;
use Exception;
class JltxException extends Exception {}

View File

@ -6,18 +6,17 @@ use Jltx\Support\Security\RSA;
use RuntimeException;
beforeEach(function () {
// 生成测试用的密钥对
$this->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, '证书加载失败');
});