Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

[70-536, #25] Teoria sulle classi Stream di .NET e un caso pratico di TripleDES

Ho visto con infinito piacere l'ultimo post di Alessio Marziali dove ci fa vedere un utilizzo pratico della classe Rijndael per:

  1. leggere un file di input e memorizzarlo in un byte[]
  2. criptare il file in un'area di memoria mantenuta da un MemoryStream
  3. decriptare il contenuto del MemoryStream su un file di output, ottenendo a tutti gli effetti una copia del file di input iniziale

Nel codice, Alessio fa uso di tutta una serie di classi, alcune delle quali derivano direttamente dalla classe astratta Stream. In questo post desidero fare luce - per quanto mi è possibile e cercando di non fare confusione - sui diversi tipi di stream gestiti da .NET. Lo faccio più che altro perchè sono andato in confusione io stesso, specialmente quando ho studiato la classe GZipStream di cui ho già parlato in passato.

La classe astratta Stream
La classe Stream rappresenta il concetto fondamentale sul quale si basa l'elaborazione dei bytes nel framework .NET. La classe Stream è definita come abstract, e come tale non può essere istanziata direttamente: Stream è semplicemente un'astrazione, una sequenza di bytes qualsiasi, indipendentemente dal modo con cui essi vengono letti, scritti, manipolati. Per dirla come dice MSDN: "Provides a generic view of a sequence of bytes". Siccome non ha una rappresentazione fisica, tutto quello che possiamo fare con Stream è assegnarla ad un oggetto derivato di Stream. Stream, fra le altre cose, definisce l'interfaccia che abbiamo a disposizione quando lavoriamo con uno stream.

Detto questo, se non possiamo istanziare uno Stream, cosa possiamo fare? Possiamo creare un oggetto che deriva da Stream, e che ne rappresenta una specializzazione. Ecco quindi che .NET ci mette a disposizione FileStream, MemoryStream, BufferedStream. Queste classi non sono più astratte, ma identificano in modo preciso una sequenza di bytes su files, o in memoria e così via. Indipendentemente dal tipo di stream, avremo a disposizione la stessa interfaccia, semplificando di molto il lavoro.

Il FX suddivide i tipi di stream in due ulteriori categorie: gli stream di back-end e gli stream pass-through. Io per documentarmi meglio ho trovato questo articolo di Billy Hollis un po' vecchiotto (2002), che parla del FX1.1, che però può essere sempre utile.

Gli Stream di back-end
Lo
Stream di back-end è uno stream che legge o scrive bytes. Gli esempi che abbiamo fatto prima sono un esempio di questo tipo di stream: FileStream legge o scrive su un file, MemoryStream legge o scrive in memoria. La classe Stream espone il metodo Read per leggere, ed il metodo Write per scrivere.

Gli Stream di pass-through
Lo Stream pass-through è un tipo particolare di stream (ma va? ): legge i bytes, li elabora/trasforma/manipola, e li scrive in uno stream back-end. La già citata classe GZipStream ne è un esempio: questa classe legge una sequenza di bytes, li comprime e li reindirizza in uno stream di output. Io mi immagino lo stream pass-through come una sorta di "filtro", perchè trasforma i dati, ma di per sè non li memorizza. Un altro esempio di stream pass-through è la CryptoStream, che è uno dei mattoni principali della crittografia.

Perchè usare le classi astratte
Le classi astratte ci permettono di scrivere codice più riutilizzabile, perchè ad esempio possiamo scrivere metodi che possono lavorare su diversi tipi di oggetti, se questi però derivano da una stessa classe base. Mi spiego meglio - spero! - prendendo come esempio il codice di Alessio postato ieri. Nel punto in cui dichiara l'oggetto il tipo di crittografia che vuole applicare, Alessio la classe SymmetricAlgorithm:

SymmetricAlgorithm rijn = Rijndael.Create();

L'algoritmo di Rijndael è un algoritmo di crittografia simmetrico (la stessa chiave viene usata sia per criptare le informazioni, che per decriptarle). Per sua natura, la classe astratta SymmetricAlgorithm non solo può contenere un oggetto di tipo Rinjndael come sopra, ma può contenere qualsiasi altro oggetto derivato da SymmetricAlgorithm: DES, RC2, TripleDES.

Giusto per fare un esempio, ho riscritto brevemente il codice di Alessio per fargli usare il TripleDES, un algoritmo che applica per 3 volte consecutive il DES.

private void btnCripta_Click(object sender, EventArgs e)
{
    FileStream fin = 
new FileStream(this.txtFileInput.Text,
        FileMode.Open, FileAccess.Read);
    
byte[] finData = new byte[fin.Length];

    FileStream fout = 
new FileStream(txtFileOutput.Text, FileMode.Create);

    SymmetricAlgorithm rijn = TripleDES.Create();
    CryptoStream coutenc = 
new CryptoStream(fout, rijn.CreateEncryptor(),
    CryptoStreamMode.Write);
    fin.Read(finData, 0, (
int)fin.Length);
    coutenc.Write(finData, 0, (
int)fin.Length);
    coutenc.FlushFinalBlock();
    
    coutenc.Close();
    fout.Close();
    fin.Close();
}

Al contrario di quanto faceva il codice precedente, questo cripta un file scrivendolo su disco. nonostante abbia cambiato l'algoritmo di criptazione, ho usato la classe SymmetricAlgorithm proprio per i motivi elencati prima.

powered by IMHO 1.2

Print | posted on Friday, March 17, 2006 12:10 PM | Filed Under [ Esame 70-536 ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET