En tancar el Mòdul 2 vam deixar tres preguntes a l'aire: com comprovar que un fitxer no ha canviat sense desxifrar-lo, com autenticar un missatge entre dues parts que comparteixen una clau, i com desar les contrasenyes dels usuaris del portal de MediNube. Les tres respostes es construeixen sobre una mateixa primitiva que ja fem servir de contraban des del Mòdul 2 (dins d'HMAC-SHA256 a PBKDF2, dins d'HKDF-SHA256): la funció hash criptogràfica. Aquesta lliçó la treu per fi a primer pla: quines propietats ha de complir, per què la resistència a col·lisions "val la meitat dels bits" (la promesa pendent del Mòdul 1), quins algorismes estan vius i quins estan trencats, i per a què serveix — i per a què no serveix — un hash a seques. És la base sobre la qual a 03-02 construirem HMAC i a 03-03 l'emmagatzematge de contrasenyes: si aquesta peça s'entén bé, les altres dues cauen soles.
Contingut
- Què és una funció hash criptogràfica
- Les tres resistències: preimatge, segona preimatge i col·lisions
- La paradoxa de l'aniversari: per què les col·lisions valen la meitat dels bits
- El zoo d'algorismes: SHA-2, SHA-3, BLAKE2... i els morts (MD5, SHA-1)
- Usos legítims del hash a seques
- Cas pràctic: empremta d'historials exportats a MediNube
- Hashing per streaming de fitxers grans
- Què NO és un hash a seques
Què és una funció hash criptogràfica
Una funció hash criptogràfica agafa una entrada de qualsevol longitud (un byte, un historial mèdic, un disc sencer) i produeix una sortida de longitud fixa anomenada hash, digest o empremta digital. Per a SHA-256, aquesta sortida són sempre 32 bytes (256 bits), pesi el que pesi l'entrada.
import hashlib historial = b"Pacient: Ana Perez. Al·lergies: penicil·lina." empremta = hashlib.sha256(historial).hexdigest() print(empremta) # c0e82a1e1d6b9cec8169bd739a3001b5e05e6f2c7e325a27d692b514e6086700
Desglossament del codi:
hashlibés el mòdul de la biblioteca estàndard de Python per a funcions hash. No necessita instal·lació.hashlib.sha256(...)crea un objecte hash i processa els bytes que li passis. Fixa't que l'entrada són bytes (b"..."), no text: com amb el xifratge al Mòdul 2, si tens unstrprimer l'has de codificar amb.encode("utf-8")..hexdigest()retorna l'empremta com a cadena hexadecimal (64 caràcters = 32 bytes). El seu germà.digest()retorna els 32 bytes crus, que és el que faràs servir quan el hash sigui entrada d'una altra operació.
Propietats que ha de complir per anomenar-se criptogràfica:
- Determinista. La mateixa entrada produeix sempre la mateixa sortida. Avui, demà i en una altra màquina. Sense això no serviria per verificar res.
- Sortida de longitud fixa. 256 bits per a SHA-256, 512 per a SHA-512. La conseqüència immediata: com que hi ha infinites entrades possibles i només 2^256 sortides, les col·lisions existeixen per definició (dues entrades diferents amb el mateix hash). La seguretat no consisteix a fer que no existeixin, sinó que sigui computacionalment inviable trobar-les.
- Ràpida de calcular. Centenars de MB/s en un portàtil normal. Això és una virtut per verificar fitxers... i, com veurem a 03-03, un desastre per a les contrasenyes.
- Efecte allau. Canviar un sol bit de l'entrada canvia, de mitjana, la meitat dels bits de la sortida, de forma imprevisible:
import hashlib a = hashlib.sha256(b"Al·lergies: penicil·lina").hexdigest() b = hashlib.sha256(b"Al·lergies: Penicil·lina").hexdigest() # una majuscula print(a) # 37b1c45d5db36e5a9aa08fd6bac5f203ec22525e6e97aced212102fe8f50c227 print(b) # 11f235776b55df85369676e8829c731e74c9a8277e6c085ce10c09d78e418adb
Les dues empremtes no s'assemblen en res. Això és el que fa útil el hash com a detector de canvis: no hi ha manera de fer una modificació "petita" que passi desapercebuda, ni de deduir de l'empremta quant o on ha canviat l'entrada.
Un model mental útil: una funció hash criptogràfica ideal es comporta com un oracle aleatori — una màquina que, per a cada entrada nova, tria una sortida perfectament aleatòria i la recorda per sempre. Tota la criptografia construïda sobre hashes (HMAC, signatures, KDF) assumeix que el hash real s'assembla prou a aquesta màquina ideal.
Les tres resistències: preimatge, segona preimatge i col·lisions
Que les col·lisions existeixin però no es puguin trobar es formalitza en tres propietats, ordenades de la més forta a la més fàcil de trencar:
| Propietat | L'atacant té... | ...i vol trobar | Exemple d'atac a MediNube |
|---|---|---|---|
| Resistència a preimatge | Un hash h |
Qualsevol m tal que hash(m) = h |
De l'empremta publicada d'un historial, reconstruir-ne el contingut |
| Resistència a segona preimatge | Un missatge m1 |
Un altre m2 ≠ m1 amb hash(m2) = hash(m1) |
Substituir un historial concret ja arxivat per un de fals amb la mateixa empremta |
| Resistència a col·lisions | Res (tria tots dos) | Qualsevol parell m1 ≠ m2 amb el mateix hash |
Preparar dues versions d'un consentiment informat — una innòcua i una abusiva — amb la mateixa empremta, i arxivar-ne una fent-la passar per l'altra |
Detalls que convé interioritzar:
- En la preimatge, l'atacant va "cap enrere": del hash a l'entrada. Per a SHA-256 costa de l'ordre de 2^256 intents — inviable per sempre, a efectes pràctics. Compte: això assumeix que l'entrada és imprevisible. Si l'entrada té poca entropia (un DNI, una contrasenya), l'atacant no inverteix el hash: prova totes les entrades possibles i compara. Aquest matís serà el cor de 03-03.
- En la segona preimatge, el missatge objectiu està fixat per endavant; l'atacant no el pot triar. També costa ~2^256.
- En la col·lisió, l'atacant té la màxima llibertat: li val qualsevol parell. I aquesta llibertat té un preu per al defensor, quantificat per la paradoxa de l'aniversari.
La paradoxa de l'aniversari: per què les col·lisions valen la meitat dels bits
Al Mòdul 1 vam dir que "128 bits és el mínim, 256 l'estàndard" (regla d'or 5) i vam prometre explicar per què en els hashes el compte surt diferent. Aquí està.
La paradoxa: quantes persones calen en una sala perquè sigui probable (>50 %) que dues d'elles comparteixin aniversari? La intuïció diu ~183 (la meitat de 365). La resposta real és 23. La raó: no busquem algú que faci anys un dia concret (això sí que requeriria ~183 persones), sinó qualsevol parella coincident — i amb 23 persones ja hi ha 253 parelles possibles, moltes oportunitats de col·lisió.
Traslladat a hashes: amb sortides de n bits hi ha 2^n empremtes possibles, però un atacant que generi missatges a l'atzar espera trobar una col·lisió qualsevol després de ~2^(n/2) intents, no 2^n. És exactament la diferència entre les files de la taula anterior:
- Atacar la preimatge o la segona preimatge de SHA-256 costa ~2^256: l'objectiu està fixat.
- Atacar les col·lisions de SHA-256 costa ~2^128: l'atacant acumula empremtes i espera que dues xoquin.
Conseqüències pràctiques:
- SHA-256 ofereix 128 bits de resistència a col·lisions — just el mínim acceptable de la regla d'or 5. Per això és avui l'estàndard per defecte i per això per a sistemes de molt llarga vida es considera SHA-384 o SHA-512 (192 i 256 bits de resistència a col·lisions).
- Un hash de 128 bits (com MD5, encara que no estigués trencat) només oferiria 2^64 de resistència a col·lisions: a l'abast d'un atacant ben finançat des de fa anys. Cap hash de 128 bits de sortida és acceptable on importin les col·lisions.
- I et sona el 2^(n/2) d'alguna cosa? És el mateix fenomen que limitava els nonces a 02-03: amb nonces de 96 bits d'AES-GCM esperàvem una repetició cap als 2^48 missatges. Paradoxa de l'aniversari una altra vegada — és una constant en criptografia.
El zoo d'algorismes: SHA-2, SHA-3, BLAKE2... i els morts
La família SHA-2: el cavall de batalla
SHA-2 és una família dissenyada per la NSA i estandarditzada pel NIST el 2001: SHA-224, SHA-256, SHA-384, SHA-512 (el número és la mida de la sortida en bits). Internament funciona amb la construcció Merkle–Damgård: trosseja el missatge en blocs i els va "comprimint" en un estat intern, encadenats com en una picadora. Dos apunts pràctics:
- SHA-256 és l'opció per defecte de l'ecosistema: TLS, Bitcoin, signatures, HMAC... És la que fa servir MediNube a HKDF i la que farem servir a 03-02.
- SHA-512 és, curiosament, més ràpid que SHA-256 en CPU de 64 bits (treballa amb paraules de 64 bits), a més de més resistent. SHA-384 és SHA-512 truncat — i aquest truncament el protegeix d'un defecte estructural de Merkle–Damgård anomenat length extension que veurem a 03-02, perquè és la raó històrica de l'existència d'HMAC tal com és.
SHA-3: el recanvi d'una altra tecnologia
Quan SHA-1 va començar a trontollar (ara hi anem), el NIST va convocar un concurs públic — a l'estil del que va donar lloc a AES — per tenir un substitut a punt per si de cas SHA-2 també queia. El guanyador (2015) va ser Keccak, estandarditzat com a SHA-3. El que t'importa és el panorama, no les tripes:
- SHA-3 fa servir una construcció interna completament diferent, l'esponja (sponge): el missatge s'"absorbeix" en un estat intern gran i després la sortida s'"exprimeix" d'ell. En no ser Merkle–Damgård, és immune per disseny al length extension.
- No és un reemplaçament urgent: SHA-2 continua sa. SHA-3 és el pla B de la criptoagilitat (regla d'or 8) — existeix perquè, si algun dia apareix una esquerda a SHA-2, el món tingui on migrar. Està a
hashlibcomhashlib.sha3_256().
BLAKE2: el ràpid modern
BLAKE2 descendeix d'un finalista del concurs SHA-3 i la seva proposta és simple: seguretat comparable a SHA-3, però més ràpid que SHA-2 en programari. Està a hashlib (blake2b per a 64 bits, blake2s per a 32) i té extres integrats com sortida de mida configurable i mode amb clau. És una elecció excel·lent per a checksums interns d'alt volum; per a tot allò interoperable, SHA-256 continua sent la llengua franca.
import hashlib dades = b"backup complet de Clinica Sol" print(hashlib.sha256(dades).hexdigest()) # 32 bytes de sortida print(hashlib.sha3_256(dades).hexdigest()) # 32 bytes, construccio esponja print(hashlib.blake2b(dades, digest_size=32).hexdigest()) # mida personalitzada
Els morts: MD5 i SHA-1
Aquí és on la teoria de les col·lisions es converteix en història real:
- MD5 (1992, sortida de 128 bits): trencat a la pràctica des del 2004 — generar col·lisions costa segons en un portàtil. No va ser acadèmic: el malware estatal Flame (2012) va fer servir una col·lisió de MD5 per fabricar-se un certificat que semblava signat per Microsoft, i amb ell es feia passar per una actualització legítima de Windows.
- SHA-1 (1995, sortida de 160 bits): l'atac SHAttered (Google/CWI, 2017) va publicar dos PDF diferents amb el mateix SHA-1. Va costar ~2^63 operacions — enorme però pagable. Des del 2020 l'atac és de prefix triat (molt més flexible) i el seu cost ronda les desenes de milers de dòlars. Els navegadors rebutgen certificats SHA-1 des del 2017.
Fixa't en el patró: en tots dos casos va caure primer la resistència a col·lisions (la propietat "barata", 2^(n/2)); les preimatges de MD5 i SHA-1 continuen sense estar trencades. Per això veuràs sistemes antics fent servir MD5 "només com a checksum contra corrupció accidental" — tècnicament encara detecta bits capgirats per un disc, però és una pèssima idea mantenir-lo: convida a confondre usos i que un auditor (amb raó) te'l marqui.
| Algorisme | Sortida | Resist. a col·lisions teòrica | Estat (2026) | Veredicte |
|---|---|---|---|---|
| MD5 | 128 bits | 2^64 | Trencat (col·lisions en segons; Flame) | No fer servir mai |
| SHA-1 | 160 bits | 2^80 | Trencat (SHAttered 2017; prefix triat 2020) | No fer servir; migrar l'heretat |
| SHA-256 | 256 bits | 2^128 | San | Estàndard per defecte |
| SHA-512 / SHA-384 | 512/384 bits | 2^256 / 2^192 | San | Llarga vida; ràpid en CPU 64 bits |
| SHA-3-256 | 256 bits | 2^128 | San | Pla B; immune a length extension |
| BLAKE2b | 1–64 bytes | segons sortida | San | Molt ràpid; ideal per a ús intern |
Usos legítims del hash a seques
Un hash a seques — sense clau, sense sal, sense res més — resol una família concreta de problemes: donar una empremta curta i fiable d'un contingut. Usos canònics:
- Integritat de descàrregues i fitxers (checksums). El proveïdor publica el SHA-256 d'un instal·lador; tu el descarregues, calcules el hash i el compares. Si coincideixen, el fitxer ha arribat intacte. (Matís important a l'apartat final: això només protegeix si vas obtenir l'empremta per un canal fiable.)
- Deduplicació. Si dos fitxers tenen el mateix SHA-256, són el mateix fitxer: un sistema de còpia de seguretat pot desar-ne una sola còpia. La resistència a col·lisions és justament el que fa legítim aquest "si el hash coincideix, el contingut coincideix".
- Identificadors de contingut. git identifica cada commit, fitxer i arbre pel seu hash (SHA-1 històric, en migració a SHA-256 precisament per SHAttered). L'adreça és l'empremta del contingut: si el contingut canvia, l'adreça canvia. Docker fa el mateix amb les capes de les imatges (
sha256:...). - Empremta de documents per detectar canvis — el nostre cas pràctic.
Cas pràctic: empremta d'historials exportats a MediNube
Context: el mòdul medinube.cripto ja exporta còpies de seguretat xifrades (02-04). Però hi ha un altre flux: quan una pacient com Ana Pérez exerceix el seu dret de portabilitat (RGPD), MediNube genera un export en clar (un ZIP amb PDF) que la clínica lliura a la pacient. Mesos després, Ana torna amb "el seu" export i cal respondre: és exactament el fitxer que vam generar, o algú l'ha modificat? — recordatori habitual: dades fictícies; un flux real amb dades sanitàries exigeix revisió de seguretat i compliance (RGPD) abans de desplegar-se.
La solució: en generar l'export, calcular-ne el SHA-256 i desar l'empremta a la base de dades de MediNube, junt amb el registre de l'exportació.
# medinube/integritat.py
import hashlib
def empremta_exportacio(dades_zip: bytes) -> str:
"""Calcula l'empremta SHA-256 d'un export, en hexadecimal."""
return hashlib.sha256(dades_zip).hexdigest()
def verificar_exportacio(dades_zip: bytes, empremta_desada: str) -> bool:
"""Comprova si un export coincideix amb l'empremta registrada."""
return hashlib.sha256(dades_zip).hexdigest() == empremta_desada
# En generar l'export per a ana.perez:
export = b"...contingut del ZIP..." # fictici
registre = {"pacient": "ana.perez", "sha256": empremta_exportacio(export)}
# Mesos despres, quan Ana presenta un fitxer:
fitxer_presentat = b"...contingut del ZIP..."
print(verificar_exportacio(fitxer_presentat, registre["sha256"])) # TruePer què aquí == i no secrets.compare_digest, amb tot el que hem insistit en la regla d'or 6? Perquè l'empremta no és un secret: l'atacant que vol colar un export fals ja sap quin hash necessita igualar (o li és igual); no hi ha informació que es pugui filtrar per timing. La comparació en temps constant és per a secrets (tokens, MAC — a 03-02 tornarà a ser obligatòria). Distingir quan s'aplica cada cosa és senyal que entens la regla, no que només la recites.
I la pregunta incòmoda que prepara la lliçó següent: això funciona perquè l'empremta viu a la nostra base de dades, fora de l'abast de l'atacant. I si haguéssim d'enviar empremta i fitxer junts pel mateix canal? Aguanta la pregunta dos apartats.
Hashing per streaming de fitxers grans
hashlib.sha256(dades) exigeix tenir tots els bytes en memòria. Un export d'imatges mèdiques pot ocupar gigabytes; carregar-lo sencer és inviable. Per a això els objectes hash tenen update(): pots donar-los el contingut a trossos i el resultat és idèntic.
import hashlib
def empremta_fitxer(ruta: str, bloc: int = 1024 * 1024) -> str:
"""SHA-256 d'un fitxer llegit per blocs d'1 MiB."""
h = hashlib.sha256() # 1. estat inicial buit
with open(ruta, "rb") as f: # 2. obrir en binari
while True:
tros = f.read(bloc) # 3. llegir fins a 1 MiB
if not tros: # 4. b"" => final de fitxer
break
h.update(tros) # 5. "absorbir" el tros
return h.hexdigest() # 6. empremta finalPunts clau del codi:
hashlib.sha256()sense arguments crea l'estat inicial; cadah.update(tros)el fa avançar. És la picadora de Merkle–Damgård en acció: l'estat intern resumeix tot el que s'ha vist fins ara fent servir memòria constant (unes desenes de bytes), tant li fa que el fitxer pesi 10 GB.update(a); update(b)equival exactament aupdate(a + b): l'empremta depèn només de la concatenació total, no de com la trossegis."rb"és imprescindible: en mode text Python tocaria els salts de línia i l'empremta no coincidiria entre sistemes.- A Python 3.11+ existeix la drecera
hashlib.file_digest(f, "sha256"), que fa aquest bucle per tu.
Què NO és un hash a seques
Tanquem amb la part que més incidents evita. El hash a seques dona integritat davant d'errors, no davant d'enemics, i no protegeix secrets de baixa entropia. Dos límits concrets:
1. Un hash no autentica. Qualsevol pot calcular el SHA-256 de qualsevol cosa: la funció és pública (Kerckhoffs) i no requereix cap clau. Si MediNube enviés a Clínica Sol un missatge acompanyat del seu hash, un atacant enmig podria substituir el missatge i recalcular el hash del missatge fals; la verificació de la clínica sortiria correcta. El hash diu "aquests bytes són aquests bytes", mai "aquests bytes vénen de MediNube". Per autenticar cal barrejar una clau secreta en el càlcul — això és un MAC, i és exactament la lliçó 03-02.
2. Un hash no serveix per a contrasenyes. Desar sha256(contrasenya) sembla raonable ("és unidireccional, no?") i és un error clàssic. La preimatge és irrompible quan l'entrada és imprevisible, però una contrasenya humana no ho és: l'atacant prova diccionaris sencers a la velocitat del hash — i el hash està dissenyat per ser ràpid, milers de milions d'intents per segon en GPU. La virtut es converteix en vulnerabilitat. Les contrasenyes requereixen funcions deliberadament lentes (les vas conèixer com a KDF a 02-04, i a 03-03 les farem servir com a verificadors amb Argon2id).
| Necessitat | Hash a seques? | Eina correcta |
|---|---|---|
| Detectar corrupció/canvi d'un fitxer (empremta en lloc fiable) | Sí | SHA-256 |
| Deduplicar, identificar contingut | Sí | SHA-256 / BLAKE2 |
| Autenticar un missatge entre dues parts | No | MAC/HMAC (03-02) |
| Desar contrasenyes d'usuaris | No | Argon2id (03-03) |
| Demostrar autoria davant de tercers (no repudi) | No | Signatura digital (04-03) |
Errors Comuns i Consells
- Fer servir MD5 o SHA-1 en codi nou "perquè només és un checksum". Estan trencats en col·lisions i la seva presència contamina auditories. SHA-256 és igual de fàcil d'escriure i no exigeix justificacions.
- Confondre "el hash coincideix" amb "el fitxer és autèntic". Coincidir només prova integritat respecte a l'empremta que tens; si l'empremta ha viatjat pel mateix canal que el fitxer, no prova res. Pregunta't sempre: d'on ha sortit l'empremta i qui l'ha pogut tocar?
- Fer hash d'un
strsense fixar la codificació.hashlibexigeix bytes; fes servir sempre.encode("utf-8")explícit. I si fas hash d'estructures (JSON), serialitza-les de forma canònica (claus ordenades, sense espais variables) o la mateixa informació donarà empremtes diferents. - Comparar-ho tot amb
compare_digest"per si de cas" o, al contrari, no fer-lo servir mai. El criteri: el valor comparat és secret o permet endevinar un secret? Empremta pública de fitxer →==val; token o MAC → temps constant obligatori (03-02). - Truncar hashes alegrement (quedar-se amb els primers 8 hex "per abreujar"). Cada bit que treus redueix la resistència; recorda que les col·lisions ja només valen n/2 bits. Si necessites IDs curts, assumeix i documenta el risc de col·lisió resultant.
- Consell: interioritza la pregunta de la regla d'or 7 (objectiu abans que eina): "qui és l'adversari?". Un disc que corromp bits? Hash. Un atacant actiu? Com a mínim, MAC.
Exercicis
Exercici 1. Sense executar-lo, prediu què imprimeix aquest codi i expliqueu quina(es) propietat(s) de les funcions hash ho justifiquen:
import hashlib h1 = hashlib.sha256(b"medinube").hexdigest() h2 = hashlib.sha256(b"medinube").hexdigest() h3 = hashlib.sha256(b"medinubE").hexdigest() print(h1 == h2, h1[:8] == h3[:8], len(h1) == len(h3))
Exercici 2. Un company proposa identificar els documents adjunts dels historials de MediNube pel seu MD5 "perquè és més curt i les preimatges de MD5 no estan trencades". Una pacient maliciosa pot pujar documents. Explica l'atac concret que això permet i quina propietat (i quin cost, en potències de 2) el fa viable en MD5 però no en SHA-256.
Exercici 3. Escriu verificar_descarrega(ruta, empremta_esperada) que calculi el SHA-256 d'un fitxer per blocs (sense carregar-lo sencer) i retorni True/False comparant-lo amb empremta_esperada (hex, amb possibles majúscules i espais al voltant). Indica raonadament si necessites secrets.compare_digest.
Solucions
Solució 1. Imprimeix True False True (el False amb probabilitat aclaparadora). h1 == h2 és True per determinisme: mateixa entrada, mateixa sortida. h1[:8] == h3[:8] és False per l'efecte allau: un bit diferent a l'entrada canvia ~la meitat dels bits de sortida de forma imprevisible, així que ni tan sols els primers 8 hex coincideixen (la probabilitat que coincidissin per atzar és 16^-8, una entre ~4.300 milions). len(h1) == len(h3) és True per la sortida de longitud fixa: 64 caràcters hex sempre.
Solució 2. La pacient executa un atac de col·lisió (no de preimatge): genera al seu ordinador dos documents diferents amb el mateix MD5 — per exemple, un consentiment innocu i un altre amb clàusules alterades; els atacs de col·lisió de MD5 amb prefix triat permeten exactament això en segons/minuts. Puja l'innocu, que queda registrat per la seva empremta, i més tard presenta el maliciós: el sistema, que identifica per MD5, els considera el mateix document. És viable perquè la resistència a col·lisions val ~2^(n/2) — per a MD5, 2^64 en teoria i gairebé gratis a la pràctica perquè, a més, l'algorisme està trencat estructuralment. En SHA-256 costaria ~2^128, inviable. La clau: quan l'atacant pot triar el contingut que entra al sistema, la propietat que et protegeix és la resistència a col·lisions, no la de preimatge.
Solució 3.
import hashlib
def verificar_descarrega(ruta: str, empremta_esperada: str) -> bool:
h = hashlib.sha256()
with open(ruta, "rb") as f:
while True:
tros = f.read(1024 * 1024)
if not tros:
break
h.update(tros)
return h.hexdigest() == empremta_esperada.strip().lower()strip().lower() normalitza l'empremta enganxada de l'exterior (els hex de hexdigest() van en minúscules). No cal compare_digest: l'empremta d'una descàrrega pública no és un secret — l'atacant ja la coneix —, així que no hi ha res que un timing attack pugui filtrar. (Fer-lo servir tampoc seria un error, només innecessari.)
Conclusió
Ja tens la primitiva despullada: una funció determinista, de sortida fixa, amb efecte allau i resistent a preimatges (~2^n) i a col·lisions (~2^(n/2), per la paradoxa de l'aniversari — promesa del Mòdul 1 saldada). Saps què fer servir (SHA-256 per defecte, SHA-512/BLAKE2 quan el rendiment importi, SHA-3 com a pla B) i què està mort (MD5 per Flame, SHA-1 per SHAttered). I saps el seu territori: empremtes de contingut — checksums, deduplicació, git, els exports de MediNube — sempre que l'empremta visqui en un lloc que l'atacant no controli.
Però deixem una pregunta oberta a propòsit: si empremta i missatge viatgen junts, l'atacant en substitueix tots dos i ningú se n'adona — un hash a seques no autentica, perquè no té cap secret a dins. La solució és barrejar una clau secreta compartida en el càlcul, i fer-ho bé, perquè la drecera intuïtiva hash(clau + missatge) està trencada d'una manera molt instructiva. Això és la lliçó 03-02: Autenticació de Missatges amb HMAC, on a més saldarem dos deutes: signar els webhooks sortints de MediNube i deixar de desar en clar el token de recuperació de 01-03. Ens veiem allà.
Curs de Criptografia Aplicada
Mòdul 1: Fonaments de la Criptografia
- Què és la criptografia i per a què serveix
- Codificació, ofuscació i xifratge
- Aleatorietat i entropia
- El principi de Kerckhoffs i les regles d'or
Mòdul 2: Criptografia Simètrica
- Xifratge simètric: AES i ChaCha20
- Modes d'operació
- Xifratge autenticat (AEAD)
- Derivació de claus (KDF)
Mòdul 3: Hashes, MAC i Contrasenyes
- Funcions hash criptogràfiques
- Autenticació de missatges amb HMAC
- Emmagatzematge segur de contrasenyes
Mòdul 4: Criptografia Asimètrica
- Fonaments de clau pública i RSA
- Criptografia de corba el·líptica
- Signatures digitals
- Intercanvi de claus: Diffie-Hellman
- Xifratge híbrid
Mòdul 5: PKI, Certificats i TLS
- Certificats X.509 i autoritats de certificació
- TLS a la pràctica
- Gestió del cicle de vida dels certificats
