Fa un temps vaig fer el hashejador, un software multifil que per cada disc dur calcula el hash dels fitxers que estan en un BBDD i compara el resultat amb el que ja té guardat. Serveix per protegir-se del bit rotting. El cert és que hem va força bé, quan tingui temps el milloraré per fer servir SHA256 enlloc de SHA1 però això serà una altra història. L'inconvenient que li veig al hashejador és que necessita una BBDD, una infraestructura, etc...
El PowerShell disposa d'una comanda Get-FileHash que calcula hashs de fitxers, però no els guarda enlloc, els treu per pantalla. Suposo que es podria escriure alguna utilitat que el guardi en un fitxer de text però aleshores també caldria escriure una altra "cosa" (referint-me al llenguatge del PowerShell) per tal que compari els hashs existents amb el que es calcula en aquell moment. Però jo no sóc de fer coses en PowerShell.
Per això ha sortit el petit hashejador, una utilitat per calcular els hash de fitxers i deixar el resultat en un fitxer XML dins la mateixa carpeta on estan els fitxers. Més endavant el petit hashejador pot fer el procés de verificació per veure que tot està a lloc. El problema que li veig és que permet detectar errors però no corregir-los, es a dir el petit hashejador et dirà que no li encaixa la verificació d'un fitxer però un cop detectat... que fas? Com el recuperes? Això ho fa el seu germà gran que verifica un fitxer en diferents discs durs i llavors saps quina còpia és la bona. Però de moment, el petit hashejador només fa això, detectar sense corregir.
El petit hashejador és una aplicació de línia de comandes (o "aplicación de consola") formada per un programa principal i una classe. El programa principal té la funció de verificar i la de crear el fitxeret amb els hashos, la de guardar i llegir el fitxer XML. No és que sigui gaire complicat. Primer el programa principal:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace Hasher
{
class Program
{
private static string ExecutablePath = "";
private static string CarpetaAProcessar = "";
private static bool Recursiu = false;
static void Main(string[] args)
{
string AppPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
ExecutablePath = Path.GetDirectoryName(AppPath);
try
{
if (args.Length > 0)
{
string Accio = args[0].ToLower();
if (args.Length > 1)
{
if (args[1] != null)
{
CarpetaAProcessar = args[1];
}
}
if (args.Length > 2)
{
if (args[2] != null)
{
if (args[2].ToLower() == "-r")
{
Recursiu = true;
}
}
}
if (CarpetaAProcessar != "")
{
if (!Directory.Exists(CarpetaAProcessar))
{
Console.WriteLine("Carpeta no trobada: " + CarpetaAProcessar);
return;
}
}
else
{
Console.WriteLine("Carpeta a processar no informada");
return;
}
switch (Accio)
{
case "crea":
crea(CarpetaAProcessar);
break;
case "verifica":
if (!File.Exists(CarpetaAProcessar + "\\hasher.xml"))
{
Console.WriteLine("No hi ha fitxer de hashos.");
return;
}
verifica(CarpetaAProcessar);
break;
default:
Console.WriteLine("Possibles parametres:");
Console.WriteLine("\"crea path [-r]\" crea un fitxer XML amb els Hash dels fitxers, -r indica recursiu");
Console.WriteLine("\"verifica path [-r]\" verifica que els fitxers tinguin el Hash -r indica recursiu");
break;
}
}
else
{
Console.WriteLine("Possibles parametres:");
Console.WriteLine("\"crea path [-r]\" crea un fitxer XML amb els Hash dels fitxers -r indica recursiu");
Console.WriteLine("\"verifica path [-r]\" verifica que els fitxers tinguin el Hash -r indica recursiu");
}
}
catch(Exception Err)
{
Console.WriteLine(Err.Message);
}
}
public static string ObtenirData(DateTime data)
{
return data.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
public static string ObtenirData()
{
return DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture);
}
public static void verifica(string pPath)
{
Console.WriteLine(ObtenirData() + " - verificant carpeta: " + pPath);
SHA256 mySHA256 = SHA256.Create();
Dictionary<string, clsFitxer> DicFitxers;
DicFitxers = CarregaHashos(pPath);
foreach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
try
{
if (File.Exists(pPath + "\\ " + objFitxer.Value.Nom))
{
FileInfo fiFitxer = new FileInfo(pPath + "\\ " + objFitxer.Value.Nom);
if (fiFitxer.Length != objFitxer.Value.MidaEnBytes)
{
Console.WriteLine("Fitxer amb mida diferent: " + fiFitxer.Name);
objFitxer.Value.Estat = "MIDA DIFERENT, actual: " + fiFitxer.Length;
}
else
{
FileStream fileStream = fiFitxer.Open(FileMode.Open, FileAccess.Read, FileShare.None);
fileStream.Position = 0;
byte[] hashValue = mySHA256.ComputeHash(fileStream);
string hashValueStr = ConvertByteArrayToHexString(hashValue);
fileStream.Close();
if (hashValueStr == objFitxer.Value.Hash)
{
objFitxer.Value.Estat = "VERIFICAT";
}
else
{
Console.WriteLine("Fitxer amb hash canviat: " + fiFitxer.Name);
objFitxer.Value.Estat = "NO COINCIDEIX";
}
}
}
else
{
objFitxer.Value.Estat = "ESBORRAT";
}
objFitxer.Value.DataVerificacio = DateTime.Now;
}
catch (IOException e)
{
Console.WriteLine($"I/O Exception: {e.Message}");
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine($"Access Exception: {e.Message}");
}
}
Save(pPath, DicFitxers);
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach(string Carpeta in Carpetes)
{
verifica(Carpeta);
}
}
}
public static Dictionary<string, clsFitxer> CarregaHashos(string pPath)
{
XmlDocument Doc = new XmlDocument();
XmlNode Fitxers;
XmlNodeList llistaDeFitxer;
XmlNode Nom;
XmlNode Hash;
XmlNode DataCreacio;
XmlNode DataVerificacio;
XmlNode Estat;
XmlNode MidaEnBytes;
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = new Dictionary<string, clsFitxer>();
Doc.Load(pPath + "\\hasher.xml");
Fitxers = Doc.SelectSingleNode("descendant::fitxers");
llistaDeFitxer = Fitxers.ChildNodes;
foreach (XmlNode Fitxer in llistaDeFitxer)
{
objFitxer = new clsFitxer();
Nom = Fitxer.SelectSingleNode("descendant::nom");
Hash = Fitxer.SelectSingleNode("descendant::hash");
DataCreacio = Fitxer.SelectSingleNode("descendant::datacreacio");
DataVerificacio = Fitxer.SelectSingleNode("descendant::dataverificacio");
Estat = Fitxer.SelectSingleNode("descendant::estat");
MidaEnBytes = Fitxer.SelectSingleNode("descendant::midaenbytes");
objFitxer.Nom = Nom.InnerText;
objFitxer.Hash = Hash.InnerText;
objFitxer.DataCreacio = DateTime.ParseExact(DataCreacio.InnerText, "dd/MM/yyyy HH:mm:ss", null);
objFitxer.DataVerificacio = DateTime.ParseExact(DataVerificacio.InnerText, "dd/MM/yyyy HH:mm:ss", null);
objFitxer.Estat = Estat.InnerText;
objFitxer.MidaEnBytes = long.Parse(MidaEnBytes.InnerText);
DicFitxers.Add(objFitxer.Nom, objFitxer);
}
return DicFitxers;
}
public static void crea(string pPath)
{
Console.WriteLine(ObtenirData() + " - creant fitxer hashos: " + pPath);
if (File.Exists(pPath + "\\hasher.xml"))
{
File.Delete(pPath + "\\hasher.xml");
}
SHA256 mySHA256 = SHA256.Create();
DirectoryInfo dir = new DirectoryInfo(pPath);
FileInfo[] files = dir.GetFiles();
clsFitxer objFitxer = null;
Dictionary<string, clsFitxer> DicFitxers = new Dictionary<string, clsFitxer>();
foreach (FileInfo Fitxer in files)
{
try
{
if (Fitxer.Name.ToLower() != "hasher.exe" && Fitxer.Name.ToLower() != "hasher.xml")
{
FileStream fileStream = Fitxer.Open(FileMode.Open);
fileStream.Position = 0;
byte[] hashValue = mySHA256.ComputeHash(fileStream);
string hashValueStr = ConvertByteArrayToHexString(hashValue);
fileStream.Close();
objFitxer = new clsFitxer(Fitxer.Name, DateTime.Now, DateTime.Now, Fitxer.Length, hashValueStr, "CREAT");
DicFitxers.Add(Fitxer.Name, objFitxer);
}
}
catch (IOException e)
{
Console.WriteLine($"I/O Exception: {e.Message}");
}
catch (UnauthorizedAccessException e)
{
Console.WriteLine($"Access Exception: {e.Message}");
}
}
Save(pPath, DicFitxers);
if (Recursiu)
{
string[] Carpetes = Directory.GetDirectories(pPath);
foreach (string Carpeta in Carpetes)
{
crea(Carpeta);
}
}
}
public static void Save(string pPath, Dictionary<string, clsFitxer> DicFitxers)
{
XmlDocument Doc = new XmlDocument();
XmlNode Fitxers;
XmlNode Fitxer;
XmlNode Nom;
XmlNode Hash;
XmlNode DataCreacio;
XmlNode DataVerificacio;
XmlNode Estat;
XmlNode MidaEnBytes;
Doc.LoadXml("<?xml version=\"1.0\" standalone=\"yes\"?><fitxers></fitxers>");
Fitxers = Doc.SelectSingleNode("descendant::fitxers");
foreach (KeyValuePair<String, clsFitxer> objFitxer in DicFitxers)
{
Fitxer = Doc.CreateNode(XmlNodeType.Element, "fitxer", "");
Nom = Doc.CreateNode(XmlNodeType.Element, "nom", "");
Hash = Doc.CreateNode(XmlNodeType.Element, "hash", "");
DataCreacio = Doc.CreateNode(XmlNodeType.Element, "datacreacio", "");
DataVerificacio = Doc.CreateNode(XmlNodeType.Element, "dataverificacio", "");
Estat = Doc.CreateNode(XmlNodeType.Element, "estat", "");
MidaEnBytes = Doc.CreateNode(XmlNodeType.Element, "midaenbytes", "");
Nom.InnerText = objFitxer.Value.Nom;
Hash.InnerText = objFitxer.Value.Hash;
DataCreacio.InnerText = ObtenirData(objFitxer.Value.DataCreacio);
DataVerificacio.InnerText = ObtenirData(objFitxer.Value.DataVerificacio);
Estat.InnerText = objFitxer.Value.Estat;
MidaEnBytes.InnerText = objFitxer.Value.MidaEnBytes.ToString();
Fitxer.AppendChild(Nom);
Fitxer.AppendChild(Hash);
Fitxer.AppendChild(DataCreacio);
Fitxer.AppendChild(DataVerificacio);
Fitxer.AppendChild(Estat);
Fitxer.AppendChild(MidaEnBytes);
Fitxers.AppendChild(Fitxer);
}
Doc.Save(pPath + "\\hasher.xml");
}
public static string ConvertByteArrayToHexString(byte[] ba)
{
StringBuilder sb = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
sb.AppendFormat("{0:x2}", b);
}
return sb.ToString().ToUpper();
}
}
}
Després la classe:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hasher
{
class clsFitxer
{
public string Nom { get; set; }
public DateTime DataCreacio { get; set; }
public DateTime DataVerificacio { get; set; }
public long MidaEnBytes { get; set; }
public string Hash { get; set; }
public string Estat { get; set; }
public clsFitxer()
{
}
public clsFitxer(string pNom, DateTime pDataCreacio, DateTime pDataVerificacio, long pMidaEnBytes, string pHash, string pEstat)
{
Nom = pNom;
DataCreacio = pDataCreacio;
DataVerificacio = pDataVerificacio;
MidaEnBytes = pMidaEnBytes;
Hash = pHash;
Estat = pEstat;
}
}
}
I fet! |