163 lines
6.7 KiB
C#
163 lines
6.7 KiB
C#
|
|
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 ? "未被篡改" : "被篡改")}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|