Java Academy · Lezione

Hash crittografico con MessageDigest

Calcoli l'hash delle password con SHA-256, aggiunga un salt per prevenire gli attacchi con rainbow table e confronti i digest in modo sicuro.

Lezione 1 di 413 passaggi

Hash crittografico con MessageDigest è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.

Che cos'è l'hashing crittografico?

Una funzione di hash crittografica associa dati di qualsiasi dimensione a un digest di dimensione fissa. È unidirezionale (non può essere invertita), deterministica e resistente alle collisioni. Viene utilizzata per la memorizzazione delle password, l'integrità dei dati e le firme digitali.

API MessageDigest

MessageDigest.getInstance("SHA-256") restituisce un digestore SHA-256. Chiami digest(bytes) per calcolare l'hash e ottenere un array di byte.

MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest("password123".getBytes(StandardCharsets.UTF_8));
String hex = HexFormat.of().formatHex(hash);
System.out.println(hex); // 64-char hex string

Algoritmi comuni

Il JDK supporta: MD5 (compromesso — non lo utilizzi mai per la sicurezza), SHA-1 (deprecato per la sicurezza), SHA-256 (standard), SHA-512 (più robusto), SHA3-256 (moderno). Per il nuovo codice utilizzi sempre SHA-256 o SHA-512.

MessageDigest.getInstance("SHA-256");  // recommended
MessageDigest.getInstance("SHA-512");  // stronger
MessageDigest.getInstance("SHA3-256"); // SHA-3 family
// Never: MessageDigest.getInstance("MD5"); // cryptographically broken

Conversione dell'hash in una stringa esadecimale

Il risultato sotto forma di array di byte deve essere convertito in una stringa esadecimale per la memorizzazione o il confronto. Utilizzi HexFormat (Java 17+) oppure String.format per le versioni precedenti.

// Java 17+:
String hex = HexFormat.of().formatHex(hash);
// Older Java:
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
String hex = sb.toString();

Il salt: come neutralizzare le rainbow table

Una rainbow table associa le password comuni ai rispettivi hash. L'aggiunta di un salt inserisce un valore casuale in ogni password prima dell'hashing, rendendo inutili le rainbow table. Memorizzi il salt insieme all'hash.

SecureRandom random = new SecureRandom();
byte[] salt = new byte[16];
random.nextBytes(salt);
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt);
byte[] hash = md.digest("password".getBytes(StandardCharsets.UTF_8));
// Store: Base64.encode(salt) + ":" + Base64.encode(hash)

Hashing delle password — utilizzi invece BCrypt

SHA-256 con un salt è migliore di SHA-256 semplice, ma è comunque veloce: un attaccante può provare miliardi di ipotesi al secondo. Per le password utilizzi una KDF lenta: BCryptPasswordEncoder (Spring Security), PBKDF2 o Argon2.

// Spring Security — proper password hashing:
PasswordEncoder encoder = new BCryptPasswordEncoder(12); // cost factor 12
String hash = encoder.encode("password123");
boolean match = encoder.matches("password123", hash); // true

Verifica dell'integrità dei file

Calcoli l'hash di un file per rilevare danneggiamenti o manomissioni. Confronti l'hash calcolato con un riferimento noto e attendibile.

MessageDigest md = MessageDigest.getInstance("SHA-256");
try (InputStream is = Files.newInputStream(Path.of("app.jar"))) {
    byte[] buf = new byte[8192];
    int n;
    while ((n = is.read(buf)) > 0) md.update(buf, 0, n);
}
String hash = HexFormat.of().formatHex(md.digest());
System.out.println("SHA-256: " + hash);

Confronto sicuro degli hash

Utilizzi MessageDigest.isEqual() per un confronto a tempo costante, così da prevenire gli attacchi basati sul tempo. Non utilizzi mai String.equals() per confrontare gli hash.

byte[] expected = computeHash(storedHash);
byte[] actual   = computeHash(inputPassword);
boolean match = MessageDigest.isEqual(expected, actual); // constant-time

Concatenazione degli aggiornamenti

Chiami md.update(bytes) più volte prima di md.digest() per calcolare l'hash di dati che arrivano in blocchi (streaming).

MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update("part1".getBytes());
md.update("part2".getBytes());
byte[] hash = md.digest(); // hash of "part1" + "part2"

Codifica degli hash per la memorizzazione

Memorizzi gli hash binari come stringhe Base64 (più brevi dell'esadecimale) o esadecimali. Base64 usa 43 caratteri per SHA-256 rispetto ai 64 dell'esadecimale. Entrambi sono corretti: sia coerente.

byte[] hash = md.digest(data);
String base64 = Base64.getEncoder().encodeToString(hash); // 44 chars (with padding)
String hex    = HexFormat.of().formatHex(hash);           // 64 chars

DigestInputStream per lo streaming

Avvolga un InputStream con DigestInputStream per calcolare l'hash durante la lettura: evita di caricare l'intero file in memoria.

MessageDigest md = MessageDigest.getInstance("SHA-256");
try (DigestInputStream dis = new DigestInputStream(Files.newInputStream(path), md)) {
    dis.transferTo(OutputStream.nullOutputStream());
}
String hash = HexFormat.of().formatHex(md.digest());

Verifica rapida

Perché SHA-256 con salt non è comunque consigliato per la memorizzazione delle password?

Riepilogo

Utilizzi MessageDigest.getInstance("SHA-256") per i controlli di integrità dei dati. Aggiunga sempre un salt alle password, ma per memorizzarle utilizzi BCrypt/Argon2, non SHA puro. Utilizzi un confronto a tempo costante (MessageDigest.isEqual) per prevenire gli attacchi basati sul tempo.

Gratis per iniziare

Impara Java con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
104
Lezioni
374

Domande Frequenti

La lezione «Hash crittografico con MessageDigest» è gratuita?

Sì — il testo completo di «Hash crittografico con MessageDigest» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.

Cosa imparerò in «Hash crittografico con MessageDigest»?

Calcoli l'hash delle password con SHA-256, aggiunga un salt per prevenire gli attacchi con rainbow table e confronti i digest in modo sicuro. Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Java Academy?

Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Hash crittografico con MessageDigest»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Java Academy?

Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Hash crittografico con MessageDigest
  2. Crittografia simmetrica AES
  3. HMAC-SHA256 per l'integrità dei messaggi
  4. JWT: struttura, creazione e verifica
← Torna a Java Academy