using System.Security.Cryptography; using Common.Utils; namespace Common.Test; /// /// CryptoHelper 加密工具测试 /// 展示各种加密、哈希、编码功能 /// [TestClass] public class CryptoHelperTests { #region AES 加密解密测试 /// /// 测试:AES 加密和解密 /// [TestMethod] public void AesEncrypt_AndDecrypt_ReturnsOriginalText() { // Arrange var plainText = "Hello, World! 你好世界!"; var password = "MySecretPassword123"; // Act var encrypted = CryptoHelper.AesEncrypt(plainText, password); var decrypted = CryptoHelper.AesDecrypt(encrypted, password); // Assert Assert.AreNotEqual(plainText, encrypted); Assert.AreEqual(plainText, decrypted); } /// /// 测试:相同内容使用相同密码多次加密,结果应该不同(因为 Salt 随机) /// [TestMethod] public void AesEncrypt_SameTextSamePassword_ProducesDifferentCiphertext() { // Arrange var plainText = "Test Message"; var password = "password"; // Act var encrypted1 = CryptoHelper.AesEncrypt(plainText, password); var encrypted2 = CryptoHelper.AesEncrypt(plainText, password); // Assert: 密文应该不同(因为使用了随机 Salt) Assert.AreNotEqual(encrypted1, encrypted2); // 但都应该能正确解密 Assert.AreEqual(plainText, CryptoHelper.AesDecrypt(encrypted1, password)); Assert.AreEqual(plainText, CryptoHelper.AesDecrypt(encrypted2, password)); } /// /// 测试:使用错误密码解密失败 /// [TestMethod] public void AesDecrypt_WrongPassword_ThrowsException() { // Arrange var plainText = "Secret Message"; var correctPassword = "correct"; var wrongPassword = "wrong"; var encrypted = CryptoHelper.AesEncrypt(plainText, correctPassword); // Act & Assert Assert.ThrowsException(() => { CryptoHelper.AesDecrypt(encrypted, wrongPassword); }); } /// /// 测试:加密空字符串抛出异常 /// [TestMethod] public void AesEncrypt_EmptyString_ThrowsException() { Assert.ThrowsException(() => { CryptoHelper.AesEncrypt("", "password"); }); } #endregion #region RSA 加密解密测试 /// /// 测试:生成 RSA 密钥对 /// [TestMethod] public void GenerateRsaKeys_ReturnsPublicAndPrivateKeys() { // Act var (publicKey, privateKey) = CryptoHelper.GenerateRsaKeys(); // Assert Assert.IsFalse(string.IsNullOrEmpty(publicKey)); Assert.IsFalse(string.IsNullOrEmpty(privateKey)); Assert.AreNotEqual(publicKey, privateKey); } /// /// 测试:RSA 公钥加密,私钥解密 /// [TestMethod] public void RsaEncrypt_AndDecrypt_ReturnsOriginalText() { // Arrange var plainText = "RSA Test Message"; var (publicKey, privateKey) = CryptoHelper.GenerateRsaKeys(); // Act var encrypted = CryptoHelper.RsaEncrypt(plainText, publicKey); var decrypted = CryptoHelper.RsaDecrypt(encrypted, privateKey); // Assert Assert.AreNotEqual(plainText, encrypted); Assert.AreEqual(plainText, decrypted); } /// /// 测试:RSA 加密相同内容产生不同密文(OAEP 填充) /// [TestMethod] public void RsaEncrypt_SameText_ProducesDifferentCiphertext() { // Arrange var plainText = "Test"; var (publicKey, _) = CryptoHelper.GenerateRsaKeys(); // Act var encrypted1 = CryptoHelper.RsaEncrypt(plainText, publicKey); var encrypted2 = CryptoHelper.RsaEncrypt(plainText, publicKey); // Assert: 由于 OAEP 填充使用随机数,密文应该不同 Assert.AreNotEqual(encrypted1, encrypted2); } /// /// 测试:使用错误的私钥解密失败 /// [TestMethod] public void RsaDecrypt_WrongPrivateKey_ThrowsException() { // Arrange var plainText = "Secret"; var (publicKey1, _) = CryptoHelper.GenerateRsaKeys(); var (_, privateKey2) = CryptoHelper.GenerateRsaKeys(); // 不同的密钥对 var encrypted = CryptoHelper.RsaEncrypt(plainText, publicKey1); // Act & Assert Assert.ThrowsException(() => { CryptoHelper.RsaDecrypt(encrypted, privateKey2); }); } #endregion #region 哈希函数测试 /// /// 测试:MD5 哈希 /// [TestMethod] public void Md5Hash_ProducesCorrectHash() { // Arrange var input = "Hello, World!"; // Act var hash = CryptoHelper.Md5Hash(input); // Assert Assert.AreEqual(32, hash.Length); // MD5 产生 32 位十六进制字符串 Assert.AreEqual("65a8e27d8879283831b664bd8b7f0ad4", hash); } /// /// 测试:SHA256 哈希 /// [TestMethod] public void Sha256Hash_ProducesCorrectHash() { // Arrange var input = "Hello, World!"; // Act var hash = CryptoHelper.Sha256Hash(input); // Assert Assert.AreEqual(64, hash.Length); // SHA256 产生 64 位十六进制字符串 Assert.AreEqual("dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f", hash); } /// /// 测试:SHA512 哈希 /// [TestMethod] public void Sha512Hash_ProducesCorrectHash() { // Arrange var input = "Hello, World!"; // Act var hash = CryptoHelper.Sha512Hash(input); // Assert Assert.AreEqual(128, hash.Length); // SHA512 产生 128 位十六进制字符串 } /// /// 测试:相同输入产生相同哈希 /// [TestMethod] public void Hash_SameInput_ProducesSameHash() { // Arrange var input = "Test Input"; // Act var md5_1 = CryptoHelper.Md5Hash(input); var md5_2 = CryptoHelper.Md5Hash(input); var sha256_1 = CryptoHelper.Sha256Hash(input); var sha256_2 = CryptoHelper.Sha256Hash(input); // Assert Assert.AreEqual(md5_1, md5_2); Assert.AreEqual(sha256_1, sha256_2); } /// /// 测试:不同输入产生不同哈希 /// [TestMethod] public void Hash_DifferentInput_ProducesDifferentHash() { // Arrange var input1 = "Input1"; var input2 = "Input2"; // Act var hash1 = CryptoHelper.Sha256Hash(input1); var hash2 = CryptoHelper.Sha256Hash(input2); // Assert Assert.AreNotEqual(hash1, hash2); } #endregion #region Base64 编解码测试 /// /// 测试:Base64 编码和解码 /// [TestMethod] public void Base64Encode_AndDecode_ReturnsOriginalText() { // Arrange var input = "Hello, World! 你好世界!"; // Act var encoded = CryptoHelper.Base64Encode(input); var decoded = CryptoHelper.Base64Decode(encoded); // Assert Assert.AreNotEqual(input, encoded); Assert.AreEqual(input, decoded); Assert.AreEqual("SGVsbG8sIFdvcmxkISDkvaDlpb3kuJbnlYzvvIE=", encoded); } /// /// 测试:URL 安全的 Base64 编码 /// [TestMethod] public void Base64UrlEncode_ProducesUrlSafeString() { // Arrange var input = "Hello+World/Test="; // Act var encoded = CryptoHelper.Base64UrlEncode(input); var decoded = CryptoHelper.Base64UrlDecode(encoded); // Assert Assert.IsFalse(encoded.Contains('+')); // 不包含 + Assert.IsFalse(encoded.Contains('/')); // 不包含 / Assert.IsFalse(encoded.Contains('=')); // 不包含 = Assert.AreEqual(input, decoded); } /// /// 测试:URL Base64 编解码 /// [TestMethod] public void Base64UrlEncode_AndDecode_ReturnsOriginalText() { // Arrange var testCases = new[] { "test", "test1", "test12", "test123", "Hello, World!", "特殊字符 !@#$%^&*()" }; foreach (var input in testCases) { // Act var encoded = CryptoHelper.Base64UrlEncode(input); var decoded = CryptoHelper.Base64UrlDecode(encoded); // Assert Assert.AreEqual(input, decoded, $"Failed for input: {input}"); } } #endregion #region 密码哈希测试 /// /// 测试:哈希密码并验证 /// [TestMethod] public void HashPassword_AndVerify_ReturnsTrue() { // Arrange var password = "MySecurePassword123!"; // Act var hashed = CryptoHelper.HashPassword(password); var isValid = CryptoHelper.VerifyPassword(password, hashed); // Assert Assert.IsTrue(isValid); Assert.AreNotEqual(password, hashed); Assert.IsTrue(hashed.StartsWith("$pbkdf2-sha256$")); } /// /// 测试:验证错误密码返回 false /// [TestMethod] public void VerifyPassword_WrongPassword_ReturnsFalse() { // Arrange var correctPassword = "correct"; var wrongPassword = "wrong"; var hashed = CryptoHelper.HashPassword(correctPassword); // Act var isValid = CryptoHelper.VerifyPassword(wrongPassword, hashed); // Assert Assert.IsFalse(isValid); } /// /// 测试:相同密码多次哈希产生不同结果 /// [TestMethod] public void HashPassword_SamePassword_ProducesDifferentHashes() { // Arrange var password = "password123"; // Act var hash1 = CryptoHelper.HashPassword(password); var hash2 = CryptoHelper.HashPassword(password); // Assert Assert.AreNotEqual(hash1, hash2); // 不同的 Salt // 但都应该能验证通过 Assert.IsTrue(CryptoHelper.VerifyPassword(password, hash1)); Assert.IsTrue(CryptoHelper.VerifyPassword(password, hash2)); } /// /// 测试:自定义哈希参数 /// [TestMethod] public void HashPassword_CustomParameters_Works() { // Arrange var password = "test"; // Act var hash = CryptoHelper.HashPassword(password, 32, 50000, 64); var isValid = CryptoHelper.VerifyPassword(password, hash); // Assert Assert.IsTrue(isValid); } #endregion #region HMAC 签名测试 /// /// 测试:HMAC-SHA256 签名和验证 /// [TestMethod] public void HmacSha256_AndVerify_ReturnsTrue() { // Arrange var message = "Important message"; var secret = "secret-key"; // Act var signature = CryptoHelper.HmacSha256(message, secret); var isValid = CryptoHelper.VerifyHmacSha256(message, signature, secret); // Assert Assert.IsTrue(isValid); Assert.AreEqual(64, signature.Length); // SHA256 产生 64 位十六进制 } /// /// 测试:验证错误签名返回 false /// [TestMethod] public void VerifyHmacSha256_WrongSignature_ReturnsFalse() { // Arrange var message = "message"; var secret = "secret"; var wrongSignature = "wrong_signature"; // Act var isValid = CryptoHelper.VerifyHmacSha256(message, wrongSignature, secret); // Assert Assert.IsFalse(isValid); } /// /// 测试:修改消息后签名无效 /// [TestMethod] public void VerifyHmacSha256_ModifiedMessage_ReturnsFalse() { // Arrange var originalMessage = "Original message"; var modifiedMessage = "Modified message"; var secret = "secret"; var signature = CryptoHelper.HmacSha256(originalMessage, secret); // Act var isValid = CryptoHelper.VerifyHmacSha256(modifiedMessage, signature, secret); // Assert Assert.IsFalse(isValid); } /// /// 测试:HMAC-SHA512 签名 /// [TestMethod] public void HmacSha512_ProducesCorrectSignature() { // Arrange var message = "Test message"; var secret = "secret"; // Act var signature = CryptoHelper.HmacSha512(message, secret); var isValid = CryptoHelper.VerifyHmacSha512(message, signature, secret); // Assert Assert.IsTrue(isValid); Assert.AreEqual(128, signature.Length); // SHA512 产生 128 位十六进制 } /// /// 测试:相同消息和密钥产生相同签名 /// [TestMethod] public void HmacSha256_SameInputs_ProducesSameSignature() { // Arrange var message = "message"; var secret = "secret"; // Act var signature1 = CryptoHelper.HmacSha256(message, secret); var signature2 = CryptoHelper.HmacSha256(message, secret); // Assert Assert.AreEqual(signature1, signature2); } #endregion #region 辅助方法测试 /// /// 测试:生成随机字符串 /// [TestMethod] public void GenerateRandomString_ProducesCorrectLength() { // Arrange & Act var str10 = CryptoHelper.GenerateRandomString(10); var str20 = CryptoHelper.GenerateRandomString(20); var strWithSpecial = CryptoHelper.GenerateRandomString(15, true); // Assert Assert.AreEqual(10, str10.Length); Assert.AreEqual(20, str20.Length); Assert.AreEqual(15, strWithSpecial.Length); } /// /// 测试:生成随机密码 /// [TestMethod] public void GeneratePassword_MeetsRequirements() { // Act var password = CryptoHelper.GeneratePassword(16); // Assert Assert.AreEqual(16, password.Length); Assert.IsTrue(password.Any(char.IsDigit), "Should contain digit"); Assert.IsTrue(password.Any(char.IsLower), "Should contain lowercase"); Assert.IsTrue(password.Any(char.IsUpper), "Should contain uppercase"); Assert.IsTrue(password.Any(c => !char.IsLetterOrDigit(c)), "Should contain special char"); } /// /// 测试:生成仅包含字母和数字的密码 /// [TestMethod] public void GeneratePassword_OnlyAlphanumeric_NoSpecialChars() { // Act var password = CryptoHelper.GeneratePassword( 12, true, true, true, false ); // Assert Assert.AreEqual(12, password.Length); Assert.IsTrue(password.All(c => char.IsLetterOrDigit(c)), "Should only contain alphanumeric"); } /// /// 测试:生成多个随机字符串应该不同 /// [TestMethod] public void GenerateRandomString_MultipleCalls_ProducesDifferentResults() { // Act var strings = Enumerable.Range(0, 10) .Select(_ => CryptoHelper.GenerateRandomString(20)) .ToList(); // Assert: 所有字符串应该不同 Assert.AreEqual(10, strings.Distinct().Count()); } #endregion #region 实际应用场景测试 /// /// 场景测试:用户密码存储和验证 /// [TestMethod] public void Scenario_UserPasswordStorageAndVerification() { // 模拟用户注册 var userPassword = "SecurePassword123!"; var hashedPassword = CryptoHelper.HashPassword(userPassword); // 存储 hashedPassword 到数据库... // 模拟用户登录 var loginPassword = "SecurePassword123!"; var isAuthenticated = CryptoHelper.VerifyPassword(loginPassword, hashedPassword); Assert.IsTrue(isAuthenticated); // 错误密码 var wrongPassword = "WrongPassword"; var isFailed = CryptoHelper.VerifyPassword(wrongPassword, hashedPassword); Assert.IsFalse(isFailed); } /// /// 场景测试:API 签名验证 /// [TestMethod] public void Scenario_ApiSignatureVerification() { // 客户端准备 API 请求 var apiKey = "client-api-key"; var apiSecret = "client-api-secret"; var requestBody = "{\"userId\":123,\"action\":\"purchase\"}"; var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); // 生成签名 var signatureData = $"{apiKey}{requestBody}{timestamp}"; var signature = CryptoHelper.HmacSha256(signatureData, apiSecret); // 发送请求(包含 signature 和 timestamp)... // 服务器端验证签名 var receivedSignatureData = $"{apiKey}{requestBody}{timestamp}"; var isValidSignature = CryptoHelper.VerifyHmacSha256( receivedSignatureData, signature, apiSecret ); Assert.IsTrue(isValidSignature); } /// /// 场景测试:敏感数据加密存储 /// [TestMethod] public void Scenario_EncryptSensitiveData() { // 加密敏感数据(如信用卡号) var creditCardNumber = "4532-1234-5678-9010"; var encryptionKey = "DataEncryptionKey123!"; var encrypted = CryptoHelper.AesEncrypt(creditCardNumber, encryptionKey); // 存储加密后的数据... Console.WriteLine($"Encrypted: {encrypted}"); // 需要使用时解密 var decrypted = CryptoHelper.AesDecrypt(encrypted, encryptionKey); Assert.AreEqual(creditCardNumber, decrypted); } /// /// 场景测试:文件完整性验证 /// [TestMethod] public void Scenario_FileIntegrityVerification() { // 模拟文件内容 var fileContent = "Important file content that should not be modified"; // 计算文件哈希 var originalHash = CryptoHelper.Sha256Hash(fileContent); // 存储哈希值... // 后续验证文件是否被篡改 var currentHash = CryptoHelper.Sha256Hash(fileContent); Assert.AreEqual(originalHash, currentHash, "File has not been modified"); // 模拟文件被修改 var modifiedContent = fileContent + " (modified)"; var modifiedHash = CryptoHelper.Sha256Hash(modifiedContent); Assert.AreNotEqual(originalHash, modifiedHash, "File has been modified"); } /// /// 场景测试:JWT Token 签名(简化版) /// [TestMethod] public void Scenario_JwtTokenSignature() { // JWT Header 和 Payload var header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; var payload = "{\"userId\":123,\"exp\":1234567890}"; var headerEncoded = CryptoHelper.Base64UrlEncode(header); var payloadEncoded = CryptoHelper.Base64UrlEncode(payload); var tokenWithoutSignature = $"{headerEncoded}.{payloadEncoded}"; // 使用 HMAC 签名 var secret = "jwt-secret-key"; var signature = CryptoHelper.HmacSha256(tokenWithoutSignature, secret); var signatureEncoded = CryptoHelper.Base64UrlEncode(signature); var fullToken = $"{tokenWithoutSignature}.{signatureEncoded}"; Console.WriteLine($"JWT Token: {fullToken}"); // 验证 Token var parts = fullToken.Split('.'); var receivedSignature = CryptoHelper.Base64UrlDecode(parts[2]); var expectedSignature = CryptoHelper.HmacSha256($"{parts[0]}.{parts[1]}", secret); Assert.AreEqual(expectedSignature, receivedSignature); } /// /// 场景测试:安全通信(RSA + AES 混合加密) /// [TestMethod] public void Scenario_HybridEncryption() { // 场景:发送大量数据,使用混合加密(RSA 加密 AES 密钥,AES 加密数据) // 1. 接收方生成 RSA 密钥对 var (publicKey, privateKey) = CryptoHelper.GenerateRsaKeys(); // 2. 发送方生成随机 AES 密钥 var aesKey = CryptoHelper.GenerateRandomString(32); // 3. 使用 RSA 公钥加密 AES 密钥 var encryptedAesKey = CryptoHelper.RsaEncrypt(aesKey, publicKey); // 4. 使用 AES 加密大量数据 var largeData = "This is a large amount of data that would be inefficient to encrypt with RSA directly..."; var encryptedData = CryptoHelper.AesEncrypt(largeData, aesKey); // 5. 发送 encryptedAesKey 和 encryptedData... // 6. 接收方使用 RSA 私钥解密 AES 密钥 var decryptedAesKey = CryptoHelper.RsaDecrypt(encryptedAesKey, privateKey); // 7. 使用解密的 AES 密钥解密数据 var decryptedData = CryptoHelper.AesDecrypt(encryptedData, decryptedAesKey); Assert.AreEqual(aesKey, decryptedAesKey); Assert.AreEqual(largeData, decryptedData); } #endregion }