739 lines
21 KiB
C#
739 lines
21 KiB
C#
using System.Security.Cryptography;
|
||
using Common.Utils;
|
||
|
||
namespace Common.Test;
|
||
|
||
/// <summary>
|
||
/// CryptoHelper 加密工具测试
|
||
/// 展示各种加密、哈希、编码功能
|
||
/// </summary>
|
||
[TestClass]
|
||
public class CryptoHelperTests
|
||
{
|
||
#region AES 加密解密测试
|
||
|
||
/// <summary>
|
||
/// 测试:AES 加密和解密
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:相同内容使用相同密码多次加密,结果应该不同(因为 Salt 随机)
|
||
/// </summary>
|
||
[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));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:使用错误密码解密失败
|
||
/// </summary>
|
||
[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<CryptographicException>(() => { CryptoHelper.AesDecrypt(encrypted, wrongPassword); });
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:加密空字符串抛出异常
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void AesEncrypt_EmptyString_ThrowsException()
|
||
{
|
||
Assert.ThrowsException<ArgumentNullException>(() => { CryptoHelper.AesEncrypt("", "password"); });
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region RSA 加密解密测试
|
||
|
||
/// <summary>
|
||
/// 测试:生成 RSA 密钥对
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:RSA 公钥加密,私钥解密
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:RSA 加密相同内容产生不同密文(OAEP 填充)
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:使用错误的私钥解密失败
|
||
/// </summary>
|
||
[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<CryptographicException>(() => { CryptoHelper.RsaDecrypt(encrypted, privateKey2); });
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 哈希函数测试
|
||
|
||
/// <summary>
|
||
/// 测试:MD5 哈希
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:SHA256 哈希
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:SHA512 哈希
|
||
/// </summary>
|
||
[TestMethod]
|
||
public void Sha512Hash_ProducesCorrectHash()
|
||
{
|
||
// Arrange
|
||
var input = "Hello, World!";
|
||
|
||
// Act
|
||
var hash = CryptoHelper.Sha512Hash(input);
|
||
|
||
// Assert
|
||
Assert.AreEqual(128, hash.Length); // SHA512 产生 128 位十六进制字符串
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:相同输入产生相同哈希
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:不同输入产生不同哈希
|
||
/// </summary>
|
||
[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 编解码测试
|
||
|
||
/// <summary>
|
||
/// 测试:Base64 编码和解码
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:URL 安全的 Base64 编码
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:URL Base64 编解码
|
||
/// </summary>
|
||
[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 密码哈希测试
|
||
|
||
/// <summary>
|
||
/// 测试:哈希密码并验证
|
||
/// </summary>
|
||
[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$"));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:验证错误密码返回 false
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:相同密码多次哈希产生不同结果
|
||
/// </summary>
|
||
[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));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:自定义哈希参数
|
||
/// </summary>
|
||
[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 签名测试
|
||
|
||
/// <summary>
|
||
/// 测试:HMAC-SHA256 签名和验证
|
||
/// </summary>
|
||
[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 位十六进制
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:验证错误签名返回 false
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:修改消息后签名无效
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:HMAC-SHA512 签名
|
||
/// </summary>
|
||
[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 位十六进制
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:相同消息和密钥产生相同签名
|
||
/// </summary>
|
||
[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 辅助方法测试
|
||
|
||
/// <summary>
|
||
/// 测试:生成随机字符串
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:生成随机密码
|
||
/// </summary>
|
||
[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");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:生成仅包含字母和数字的密码
|
||
/// </summary>
|
||
[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");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 测试:生成多个随机字符串应该不同
|
||
/// </summary>
|
||
[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 实际应用场景测试
|
||
|
||
/// <summary>
|
||
/// 场景测试:用户密码存储和验证
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 场景测试:API 签名验证
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 场景测试:敏感数据加密存储
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 场景测试:文件完整性验证
|
||
/// </summary>
|
||
[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");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 场景测试:JWT Token 签名(简化版)
|
||
/// </summary>
|
||
[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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 场景测试:安全通信(RSA + AES 混合加密)
|
||
/// </summary>
|
||
[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
|
||
} |