Newsgroup: it.comp.sicurezza.crittografia
Titolo: Algoritmo di cifratura

Salve, mi sono appassionato da poco alla cifratura dei dati e mi 
intrigano non poco gli algoritmi di cifratura.
Sto realizzando un programma per la de/cifratura dei file sotto Linux 
usando Gambas (simile al VB per capirsi) e stavo cercando di capire 
quale fosse il miglior algoritmo per tale scopo. Ho letto un po' in giro 
ed ho cercato di informarmi per cui, rimanendo nell'ambito dei cifrari 
liberi, ho selezionato i seguenti:
- Rijndael/AES
- Blowfish
- Twofish
- Serpent
Del primo è inutile parlarne perché è uno standard, conseguentemente è 
diffuso per ogni dove. Il Blowfish, soprattutto in ambiente *nix, è 
molto usato ma non ho capito se è perché è freeware o se perché 
effettivamente è valido. Ho letto che non è stato ancora violato per cui 
questo fatto mi pare che sia un ottimo punto a suo vantaggio.
Il Twofish è stato sviluppato da Schneider (Blowfish) e questo dovrebbe 
essere un punto a suo favore ma mi sorge un dubbio: se è valido perché 
non è usato? Quasi tutti conoscono il Blowfish, ma del Twofish, che 
oltretutto è anche più recente, pochi ne sanno qualcosa o lo utilizzano.
Il Serpent è per me il punto più oscuro: arrivato secondo nella 
selezione per il nuovo standard AES, è snobbato incredibilmente. Gli 
autori (e molti sviluppatori) lo definiscono più sicuro del Rijndael ma 
in pratica viene usato veramente pochissimo. Se è solo perché è più 
lento dell'AES, non vedo perché snobbarlo così tanto...
Infine, un paio di domande da profano:
1)
se non ho capito male, tutti questi algoritmi sono a chiave simmetrica, 
cioè la stessa chiave viene usata sia per la cifratura che per la 
decifratura. Rispetto ai sistemi a chiave pubblica/privata è un bene o 
un male? Quale sistema è più sicuro?
2)
non ho capito bene una cosa. Che differenza c'è fra la lunghezza in bit 
della chiave di cifratura e la lunghezza effettiva della chiave usata 
dall'utente? Cioè, se un algoritmo accetta chiavi di 128 bit (esempio), 
la lunghezza della chiave inserita dall'utente si deve limitare ad 8 
caratteri oppure anche per la chiave viene fatta la trasformazione a 
blocchi di 128 bit come per i dati da cifrare?
Grazie a chi avrà la pazienza di illuminarmi :-)
-- 
Ciao.
Leo.
WEB: 
www.leonardomiliani.com
 
E-mail: 
leon...@leonardomiliani.com

 blocchi di 128 bit come per i dati da cifrare?
Il keyfile o la password di solito vengono inviati ad un algoritmo di
derivazione della chiave (v. ad esempio PBKDF2), che a partire da un
valore arbitrario in ingresso (una stringa o un array di larghe
dimensioni) deriva in modo crittograficamente sicuro (=non è possibile
abbreviare il calcolo con una qualche scorciatoia) una chiave di
dimensioni adatte alla cifratura.
Questo fa si che sia possibile imporre un dato tempo computazionale pr
generare una chiave nota la password (o il keyfile), in modo che un
attaccante che provi un attacco a forza bruta o anche solo a dizionario
si trovi rallentato (in modo non bypassabile) nelle operazioni.
Unendo alla password o al keyfile un valore pseudocasuale, che non ha
bisogno di restare segreto (seed), in ingresso alla funzione di
derivazione della password si fa in modo che l'avversario non possa
nemmeno precomputare le chiavi corrispondenti alle password più
provabili, perchè saranno diverse al cambiare del seed, e quindi
diverse per ogni file cifrato.
Il seed è obbligatorio anche nel caso in cui si decida di usare una
stream cypher o una cifra a blocchi in alcune modalità (ad es. CTR) in
modo che la stessa chiave (che l'utente potrebbe voler riutilizzare)
non generi lo stesso output, altrimenti forzare la cifratura
diventerebbe banalmente fare lo xor di due file cifrati con la stessa
chiave.

 chiave.
Anche queste affermazioni sembrano fuorvianti.
Il primo dubbio riguarda l'uso obbligatorio del seed. Se l'utente usa 
propriamente il cifrario (a flusso o a blocchi che sia), cioè usando una 
chiave casuale, il seed è del tutto inutile. Se, invece, si vuole usare 
sempre la stessa chiave (pratica altamente sconsigliabile) hai ragione a 
dire che il seed è obbligatorio, nel senso che è indispensabile se si 
vogliono evitare attacchi da dizionario.
Il secondo dubbio riguarda lo xor. Se usi un block cipher, è proprio 
impossibile forzare la cifratura facendo lo xor di due file cifrati con la 
stessa chiave, proprio perché i bit vengono tutti mischiati tramite funzioni 
altamente non lineari e la chiave usata per la cifratura è (quasi?) sempre 
derivata da quella inserita dall'utente. Ma forse non ho capito cosa intendi 
con "forzare la cifratura".
Cristiano 

 altamente non lineari [...]
Mi stavo riferendo ad alcuni specifici modi d'uso di block cypher, ad
esempio CTR
In questo modo d'uso la funzione crittografica è applicata non al
messaggio ma ad un contatore, del risultante flusso cifrato (contatore
cifrato dalla chiave) viene fatto lo xor con il plain text, originando
il ciphertext.
In questo modo si trasforma la cifra a blocchi in una stream cipher
(ogni bit in entrata è coperto da un bit in uscita dalla funzione
crittografica; il messaggio può avere lunghezza arbitraria e non è
necessario farne il padding ad un multiplo della lunghezza del blocco
della funzione) ed è necessario evitare il riutilizzo della chiave.
Si potrebbe spostare il problema usando un seed unico da cui fare
partire il contatore (cosa in effetti generalmente molto usata) ma
questo non sostituirebbe in toto il seeding della password prima della
key derivation function perchè non renderebbe non pratici gli attacchi
a dizionario precomputati (usando il seed insieme alla password prima
della KDF in teoria sarebbe necessario precomputare 2^n dizionari dove
n è l'ampiezza del seed)

 o non conoscenza del problema tende a riutilizzare il materiale-chiave.
Purtoppo è una prassi molto diffusa e dico "purtroppo" perché molto spesso 
viene attuata senza essere coscenti della sua dannosità.
Cristiano 

Cristiano ha scritto:

Ragazzi siete stati molto gentili a spiegarmi tutte queste cose.
Effettivamente la crittografia è molto affascinante, non credevo davvero.
Il problema è che serve un'ottima base matematico-logico-informatica per
poter capire a fondo ciò che sta alla base di un qualunque algoritmo di
cifratura...
Vi chiedo altre cose, sempre che abbiate la voglia e la pazienza di
rispondere:
1)
prediligendo, per ora, affrontare il discorso della cifratura a chiave
segreta (mi pare che a livello di codice sia più semplice implementarla
su un PC), potrei io cifrare anche la chiave segreta con un qualche
algoritmo che non necessita di un'altra chiave da memorizzare su un
file? Cioè, ad esempio, utilizzando un banale cifrario a sostituzione?
2)
molti degli algoritmi usano blocchi di dati fissi, cioè lavorano ad
esempio su 4 byte per volta (come il Blowfish). In caso la lunghezza del
messaggio non sia un multiplo esatto di 4, si ricorre al passaggio degli
ultimi byte con aggiunti dei byte vuoti. Ma questi byte vuoti devono
essere NULL oppure spazi vuoti?
3)
un altro dubbio che mi resta e che non ho chiarito del tutto dalla prima
risposta di Giorgio è quello relativo alla differenza di lunghezza fra
chiave di cifratura usata dall'algoritmo e chiave inserita dall'utente.
Prendendo sempre il Blowfish la chiave varia da 32 a 448 bit, cioè da 4
a 56 caratteri. Ciò significa che una chiave inserita dall'utente non
può essere più lunga di 56 caratteri oppure che la lunghezza della
chiave inserita non determina la lunghezza della chiave processata
dall'algoritmo?
Blowfish, come molti altri (se non ho capito male), computa una chiave
partendo dalla chiave inserita dall'utente mediante un algoritmo di
calcolo, giusto?
4)
ultima cosa, altrimenti poi mi mandate a quel paese :)
Secondo voi, è più sicuro un cifrario a blocchi (Blowfish) oppure un
cifrario di tipo stream (RC4)? Se implemento un cifrario di tipo stream
con una chiave molto lunga, non ottengo già un buon margine di sicurezza?


 con una chiave molto lunga, non ottengo già un buon margine di sicurezza?
Il problema dei cifrari è che noi sappiamo se hanno alcune
caratteristiche desiderabili o se ne hanno altre non desiderabili, ma
praticamente non si può mai dire di avere finito l'analisi di un
cifrario: possono sempre emergere altre caratteristiche che non si
erano mai notate in precedenza e rimettere in discussione
l'opportunità o meno di usare un certo algoritmo in un dato contesto.
Per questo motivo una buona raccomandazione è di solito di usare gli
algoritmi più diffusi, più studiati ed in poche parole, meglio
compresi. (il che oggi significa AES, comunque come dicevo nel primo
post anche Twofish e Serpent non sono cattive scelte su un PC, hanno
avuto una buona quantità di analisi durante il contest dell'AES e
anche dopo ed ormai sono fuori da parecchio tempo).
Per quanto riguarda algoritmi stream oppure a blocchi, si tratta di due
filosofie diverse ma non inconciliabili, ad es un algoritmo a blocchi
usato in modo CTR assume le proprietà tipiche degli algoritmi della
famiglia stream, IMHO non dovresti fare una scelta di campo verso gli
uni o gli altri, semplicemente hanno caratteristiche diverse, ma
piuttosto, tornando alla prima considerazione, cercare di usare i
cifrari meglio compresi dalla comunità, di cui si conosce il maggior
numero possibile di proprietà, per poter giudicare se in base a tali
proprietà note sono adatti al tuo modello di sicurezza.

 o meno da indovinare).
Serve quindi inserire molti più caratteri di quanti ne contiene la
grandezza della chiave di cifratura, giusto? Pensavo che avendo una
chiave di lunghezza max. di 448 bit (Blowfish) dovessi al massimo
inserire 56 caratteri.
A parte il link che mi hai dato, dove posso trovare altre informazioni?
Ed un sito da cui attingere delle ottime implementazioni in Basic dei
principali algoritmi?


 principali algoritmi?
Non saprei, è un linguaggio che uso veramente poco, ma immagino che se
chiedi sui newsgroup specifici per Basic o VB potrebbero darti qualche
dritta in più.
Comunque essendo un campo dove le prestazioni e l'accesso a bassissimo
livello sono fondamentali trovi soprattutto implementazioni in C, già
io che preferisco il Delphi/Pascal alcune volte faccio un po di fatica
prima di trovare alcune cose più o meno correlate al campo.
(btw se qualcuno conosce una buona libreria che metta a disposizione
funzioni per calcolare Error Correcting Code tipo Hamming, Reed-Solomon
Viterbii code etc in Delphi /Pascal mi farebbe cosa graditissima a
segnalarmela)

Grazie ancora :-)
