using System; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.OpenSsl; public static class FileHashRsaHelper { // 公钥(硬编码) private const string PublicKeyPem = """ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyN+Z04RmVOvzI2Z8Li1t xB9yv80Y4Pd+M0wiuW9BHccmVlm7LVlWDRZgaAykQxIt0UskZbaIQ5eR4mqywVoM BygfWqurVtgC6dO3SSbhZiOuSA3g1xJLgje6TOQIPWDGw1Ap0sbWrCuk+bxPFjSi XANksY3Qfl1e6YETYEEpptTXorM8enM4368/KkvEhFswBqE5/Qf2x7XUpPAfnh3Y cl45bUu87yDeyAnX4HEuA+aZPHEgXFPmhndtqMiUsLEajQNd8zZQHKmjMbubAq9s l10w7smZUck+bozHO0RP31ytI6n/7I0T9PXOb/rwjeXBxXD1K0kvU3DPuq2+a5sa iwIDAQAB -----END PUBLIC KEY----- """; // 私钥(硬编码) private const string PrivateKeyPem = """ -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAyN+Z04RmVOvzI2Z8Li1txB9yv80Y4Pd+M0wiuW9BHccmVlm7 LVlWDRZgaAykQxIt0UskZbaIQ5eR4mqywVoMBygfWqurVtgC6dO3SSbhZiOuSA3g 1xJLgje6TOQIPWDGw1Ap0sbWrCuk+bxPFjSiXANksY3Qfl1e6YETYEEpptTXorM8 enM4368/KkvEhFswBqE5/Qf2x7XUpPAfnh3Ycl45bUu87yDeyAnX4HEuA+aZPHEg XFPmhndtqMiUsLEajQNd8zZQHKmjMbubAq9sl10w7smZUck+bozHO0RP31ytI6n/ 7I0T9PXOb/rwjeXBxXD1K0kvU3DPuq2+a5saiwIDAQABAoIBAACdcETZkedzXBM5 6WofTAof4bWOgovvHJCipBgOiubPKPdG5jNq/bHX2/kSnbl2eWWMQUEuGIiYJccG /6zF6GDQ3FqHZcNbp8M4gbymNZV0TfTB0KOTyDAaojQ381LgyIK1DcWBHdw2wCRZ vo6v1BXez4evaUy5ckXQfAA9POiAH6Im7QQlPamaUJfBCfRqFNvTcL6YQngHg8RW 4xFvN8Lxhgnqftw0dY1YzNkDBz+toQ+211LTAJWYC4vZ2sHoGvR74YxZUWPS4wms QdIq50kRwL45Z9IZcxqp1x27W0pEwBsOO2DhnM6r7mB7Mg9BMEjUFf3oM+vrx67W w6McEXkCgYEA8q+Bb6ldNqWNa5uLmAziEqXCnN/X9o1Cr81YIeWZpx4Ovx2aR3wH 4OtWl9VmYrU7w758nhPH27q8ADxjSbIB3ShPPdfLcKBoW/5eg+K8Bexr5Fb6Lyqo SMhFLptxOdNzYLej99XppzRk4CV3s7IZsfQd6okSdfvlqka5ExFjXDkCgYEA0+TZ IBsc0nCZFTlcDxxMCkmj+c4+c01BGgSeoVSKIgyp5d5DSZoNjxXsrP3Nw3uq2+fh v4DD/V76BpzQ6v7P+Xg9YbW1QO6QdsG4Cf1bnAFYaTwQwdm2To5SXixYpVnON4Xv 4fOWVL0qrn3PK6aUTJCcEOdhx1YtBl+P4gVq9OMCgYEAhtLcDOXBhE96/rI+Xi2i FwwBz1dISo/14WcqNEKzFzXKqYBPqrEMS3dS9y02IVZgKoIUB1oj6T2XnmXuHw4G nQ/83fWZ7ysebyUk6w42uO+8jPGJMlT3gt/IF3mB8Mc5TR0YueIcWajw9dm645jp T4S4bgjSubtEv1FlFmPNmHkCgYAtmq5ka5FrdVJtL/gxRFzVRf4lsI7eT/039VCS 1lgYdfNHBuwidiZ+6jATF1jmvsIKLED472S/LmbPb4bDXO4z+f3z/qCxBedPt+e9 Nqs1y1BU7dmJbyr+g0EVBaRaihaI+qmjTsLHICOEhI1HDsYSKHl+Zd40gcaU/ZJB Cft4EwKBgQDeK/3k6OJTPuzskuqMsQy6yHd7hesxvdsfUH78tZrkRB2B9fciOa2v ulfBss9KKVCQeKaC+91ptLpMOlSJhc9tZUsWvE19vVlNmN0ezQyfSFn+E09Ouqin 0cMfedRgHigwi+T818aFnC8qPzTMqCMQyxRTYxEC43OB9VcPyzo1yA== -----END RSA PRIVATE KEY----- """; private static AsymmetricKeyParameter GetPublicKey() { using var reader = new StringReader(PublicKeyPem); var pemReader = new PemReader(reader); return (AsymmetricKeyParameter)pemReader.ReadObject(); } private static AsymmetricKeyParameter GetPrivateKey() { using var reader = new StringReader(PrivateKeyPem); var pemReader = new PemReader(reader); var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject(); return keyPair.Private; } private static byte[] ComputeFileHash(string filePath) { using var sha256 = SHA256.Create(); using var stream = File.OpenRead(filePath); return sha256.ComputeHash(stream); } private static byte[] EncryptData(byte[] data, AsymmetricKeyParameter publicKey) { var rsaEngine = new Org.BouncyCastle.Crypto.Engines.RsaEngine(); rsaEngine.Init(true, publicKey); return rsaEngine.ProcessBlock(data, 0, data.Length); } private static byte[] DecryptData(byte[] encryptedData, AsymmetricKeyParameter privateKey) { var rsaEngine = new Org.BouncyCastle.Crypto.Engines.RsaEngine(); rsaEngine.Init(false, privateKey); return rsaEngine.ProcessBlock(encryptedData, 0, encryptedData.Length); } public static void GenerateEncFile(string directoryPath) { var publicKey = GetPublicKey(); var files = Directory.GetFiles(directoryPath, "*.rvt", SearchOption.AllDirectories); var encFilePath = Path.Combine(directoryPath, "hashes.enc"); using var fs = new FileStream(encFilePath, FileMode.Create, FileAccess.Write); using var bw = new BinaryWriter(fs); foreach (var file in files) { var fileName = Path.GetFileName(file); var fileHash = ComputeFileHash(file); var nameBytes = Encoding.UTF8.GetBytes(fileName); var combined = nameBytes.Concat(fileHash).ToArray(); var encrypted = EncryptData(combined, publicKey); bw.Write(nameBytes.Length); bw.Write(nameBytes); bw.Write(encrypted.Length); bw.Write(encrypted); } } public static void VerifyEncFile(string directoryPath) { var privateKey = GetPrivateKey(); var encFilePath = Path.Combine(directoryPath, "hashes.enc"); if (!File.Exists(encFilePath)) { Console.WriteLine("enc 文件未找到。"); return; } var allFiles = Directory.GetFiles(directoryPath, "*.rvt", SearchOption.AllDirectories) .ToDictionary(f => Path.GetFileName(f), f => f, StringComparer.OrdinalIgnoreCase); using var fs = new FileStream(encFilePath, FileMode.Open, FileAccess.Read); using var br = new BinaryReader(fs); while (fs.Position < fs.Length) { var nameLen = br.ReadInt32(); //if (nameLen <= 0 || nameLen > 256) // 假设文件名长度不超过256字节 //{ // Console.WriteLine("无效的文件名长度。"); // continue; //} var nameBytes = br.ReadBytes(nameLen); var fileName = Encoding.UTF8.GetString(nameBytes); var encLen = br.ReadInt32(); var encrypted = br.ReadBytes(encLen); if (!allFiles.TryGetValue(fileName, out var actualFilePath)) { Console.WriteLine($"文件 {fileName} 未找到"); continue; } var decrypted = DecryptData(encrypted, privateKey); var expectedName = Encoding.UTF8.GetString(decrypted, 0, nameBytes.Length); var expectedHash = decrypted.Skip(nameBytes.Length).ToArray(); var currentHash = ComputeFileHash(actualFilePath); bool match = expectedName == fileName && currentHash.SequenceEqual(expectedHash); Console.WriteLine($"{fileName}: {(match ? "未被篡改" : "被篡改")}"); } } }