<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Integrità on My personal blog</title>
        <link>https://www.matteobianchi.eu/tags/integrit%C3%A0/</link>
        <description>Recent content in Integrità on My personal blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <lastBuildDate>Tue, 18 Aug 2026 09:00:00 +0200</lastBuildDate><atom:link href="https://www.matteobianchi.eu/tags/integrit%C3%A0/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Hashing e integrità</title>
        <link>https://www.matteobianchi.eu/p/hashing-e-integrita/</link>
        <pubDate>Tue, 18 Aug 2026 09:00:00 +0200</pubDate>
        
        <guid>https://www.matteobianchi.eu/p/hashing-e-integrita/</guid>
        <description>&lt;img src="https://www.matteobianchi.eu/p/hashing-e-integrita/cover.png" alt="Featured image of post Hashing e integrità" /&gt;&lt;h2 id=&#34;perché-conta&#34;&gt;Perché conta
&lt;/h2&gt;&lt;p&gt;Il tag AEAD del &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/cifratura-simmetrica-e-aead/&#34; &gt;capitolo precedente&lt;/a&gt; ci ha dato
un primo assaggio di integrità. Ora il mattone fondamentale: la &lt;strong&gt;funzione di hash crittografica&lt;/strong&gt;.
Prende dati di qualsiasi dimensione e produce un&amp;rsquo;impronta di lunghezza fissa — il &lt;em&gt;digest&lt;/em&gt;. È ovunque:
verifica dei download, &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/firma-artefatti-sigstore/&#34; &gt;SBOM e firma del software&lt;/a&gt;,
strutture come i Merkle tree della &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/certificate-transparency/&#34; &gt;Certificate Transparency&lt;/a&gt;,
deduplicazione, blockchain. Sembra banale; le proprietà che la rendono &lt;em&gt;crittografica&lt;/em&gt; non lo sono.&lt;/p&gt;
&lt;h2 id=&#34;le-tre-proprietà&#34;&gt;Le tre proprietà
&lt;/h2&gt;&lt;p&gt;Una funzione di hash è crittografica se soddisfa tre proprietà, in difficoltà crescente:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dato un hash h = H(m):
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  1. Resistenza alla preimmagine   → dato h, infattibile trovare m
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  2. Resistenza alla 2a preimmagine → dato m, infattibile trovare m&amp;#39; ≠ m con H(m&amp;#39;)=H(m)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  3. Resistenza alle collisioni     → infattibile trovare QUALSIASI coppia m≠m&amp;#39; con H(m)=H(m&amp;#39;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;La resistenza alle &lt;strong&gt;collisioni&lt;/strong&gt; è la più forte e la più difficile da garantire: non devi trovare un
secondo messaggio per &lt;em&gt;uno dato&lt;/em&gt;, ma &lt;em&gt;una coppia qualsiasi&lt;/em&gt; che collida — e qui il paradosso del
compleanno gioca contro di te.&lt;/p&gt;
&lt;h2 id=&#34;il-paradosso-del-compleanno&#34;&gt;Il paradosso del compleanno
&lt;/h2&gt;&lt;p&gt;Se l&amp;rsquo;output ha $n$ bit, ci sono $2^n$ valori possibili. Ingenuamente penseresti che servano $2^n$
tentativi per una collisione. In realtà, per il paradosso del compleanno, ne bastano circa:&lt;/p&gt;
&lt;p&gt;$$ 2^{n/2} $$&lt;/p&gt;
&lt;p&gt;Un hash da 256 bit offre quindi circa $2^{128}$ di sicurezza contro le collisioni, non $2^{256}$. È il
motivo per cui gli hash moderni usano output ampi (256+ bit): la resistenza alle collisioni è
&lt;em&gt;metà&lt;/em&gt; della lunghezza in bit. Un hash da 128 bit avrebbe solo $2^{64}$ di margine — oggi aggredibile.&lt;/p&gt;
&lt;h2 id=&#34;leffetto-valanga&#34;&gt;L&amp;rsquo;effetto valanga
&lt;/h2&gt;&lt;p&gt;Una buona funzione di hash ha l&amp;rsquo;&lt;strong&gt;effetto valanga&lt;/strong&gt;: cambiare un solo bit dell&amp;rsquo;input cambia circa
&lt;em&gt;metà&lt;/em&gt; dei bit dell&amp;rsquo;output, in modo imprevedibile.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;H(&amp;#34;crittografia&amp;#34;)  = 1a2b3c... (256 bit)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;H(&amp;#34;Crittografia&amp;#34;)  = f9e8d7... (completamente diverso, pur cambiando 1 bit)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Questo rende impossibile &amp;ldquo;avvicinarsi&amp;rdquo; a un digest per tentativi incrementali: non c&amp;rsquo;è correlazione
tra la distanza degli input e quella degli output. È ciò che rende l&amp;rsquo;hash utile come impronta
infalsificabile.&lt;/p&gt;
&lt;h2 id=&#34;quale-hash-usare&#34;&gt;Quale hash usare
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Scopo generale (integrità, firme, SBOM):
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  SHA-256 / SHA-512   → solido, standard, ovunque
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  SHA-3 (Keccak)      → costruzione diversa (sponge), utile come alternativa indipendente
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;EVITARE per uso crittografico:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  MD5, SHA-1          → collisioni PRATICHE dimostrate. Rotti. Solo per checksum non ostili.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;MD5 e SHA-1 non sono &amp;ldquo;deboli&amp;rdquo;: sono &lt;strong&gt;rotti&lt;/strong&gt;. Esistono collisioni costruite in pratica (due file
diversi con lo stesso hash), quindi non offrono più alcuna garanzia contro un avversario. Vanno
eliminati da ogni contesto di sicurezza.&lt;/p&gt;
&lt;h2 id=&#34;lerrore-da-evitare-lhash-non-autentica&#34;&gt;L&amp;rsquo;errore da evitare: l&amp;rsquo;hash non autentica
&lt;/h2&gt;&lt;p&gt;Un hash dimostra che i dati &lt;em&gt;non sono cambiati per caso&lt;/em&gt; o che corrispondono a un valore noto. &lt;strong&gt;Non&lt;/strong&gt;
dimostra &lt;em&gt;chi&lt;/em&gt; li ha prodotti, né li protegge da un attaccante che può cambiare &lt;em&gt;sia&lt;/em&gt; i dati &lt;em&gt;sia&lt;/em&gt;
l&amp;rsquo;hash. Se pubblichi &lt;code&gt;file + H(file)&lt;/code&gt; e un attaccante controlla il canale, sostituisce entrambi. Per
legare l&amp;rsquo;integrità a un segreto (autenticità) serve altro: l&amp;rsquo;HMAC, prossimo capitolo. E attenzione a
un uso sbagliatissimo che tratteremo dopo — &lt;strong&gt;l&amp;rsquo;hash semplice non va usato per le password&lt;/strong&gt;.&lt;/p&gt;


&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;Domanda:&lt;/strong&gt; se SHA-256 è così solido, perché non usarlo anche per le password invece di algoritmi dedicati come Argon2?&lt;/summary&gt;
&lt;p&gt;Perché per le password la proprietà che vuoi è l&#39;&lt;em&gt;opposto&lt;/em&gt; di quella per cui SHA-256 è
progettato, ed è esattamente questa inversione di obiettivo a rendere l&#39;hash generico pericoloso lì.
SHA-256 è costruito per essere &lt;strong&gt;veloce&lt;/strong&gt;: deve calcolare l&#39;impronta di gigabyte di dati in
un istante, verificare firme e integrità senza rallentare nulla. La velocità è una virtù quando l&#39;hash
serve a fare integrità. Ma quando l&#39;hash protegge una password, la velocità diventa il regalo più grande
che puoi fare all&#39;attaccante. Pensa a cosa succede quando un database di password trapela: l&#39;attaccante ha
gli hash e vuole risalire alle password provando candidati (dizionari, password comuni, brute force su
quelle corte). Il suo collo di bottiglia è quanti tentativi al secondo riesce a fare. Con SHA-256, su
hardware moderno — e peggio su GPU o ASIC costruiti apposta — parliamo di &lt;em&gt;miliardi&lt;/em&gt; di hash al
secondo: un dizionario di tutte le password umane plausibili si esaurisce in minuti o ore. Hai usato un
hash eccellente e hai protetto quasi nulla, perché la sua velocità lavora per chi attacca. Gli algoritmi
di password hashing come Argon2, bcrypt e scrypt fanno la scelta deliberatamente opposta: sono
&lt;em&gt;lenti&lt;/em&gt; e, nel caso di Argon2 e scrypt, deliberatamente &lt;em&gt;costosi in memoria&lt;/em&gt;. Puoi tararli
perché un singolo hash impieghi, diciamo, un decimo di secondo e richieda decine di megabyte di RAM: per
te che verifichi un login è impercettibile, ma per l&#39;attaccante che deve provare miliardi di candidati
diventa proibitivo in tempo e in costo hardware, e il requisito di memoria neutralizza proprio il
vantaggio delle GPU, che hanno molti core ma poca memoria per core. In più questi algoritmi integrano il
&lt;em&gt;salt&lt;/em&gt; per impedire gli attacchi precalcolati (le rainbow table) e il &lt;em&gt;costo regolabile&lt;/em&gt; per
restare al passo con l&#39;hardware che migliora. In breve: SHA-256 risponde alla domanda &#34;questi dati sono
integri?&#34; nel modo più efficiente possibile; le password pongono la domanda opposta, &#34;quanto posso
rendere costoso indovinare?&#34;, e lì la risposta giusta è un algoritmo progettato per essere lento e avido
di memoria. Usare SHA-256 per le password non è un&#39;ottimizzazione, è usare lo strumento costruito per
l&#39;obiettivo sbagliato. Lo vedremo in dettaglio nel capitolo sul password hashing.&lt;/p&gt;
&lt;/details&gt;


&lt;h2 id=&#34;conclusione&#34;&gt;Conclusione
&lt;/h2&gt;&lt;p&gt;Una funzione di hash crittografica dà un&amp;rsquo;impronta fissa con resistenza a preimmagine e collisioni
(ridotta a $2^{n/2}$ dal paradosso del compleanno) ed effetto valanga: usa SHA-256/SHA-3, mai MD5 o
SHA-1. Ma l&amp;rsquo;hash garantisce integrità, non &lt;em&gt;autenticità&lt;/em&gt;: non dice chi ha prodotto i dati. Per legarli
a un segreto condiviso serve aggiungere una chiave all&amp;rsquo;hash — è l&amp;rsquo;HMAC, prossimo capitolo.&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
