Come posso crittografare un file con .NET e avere le stesse dimensioni del file del file originale?

10

Sto usando .NET e ho scritto una fantastica routine (xD) che codifica e decrittografa un file usando CBC AES256. Funziona perfettamente, ma ora mi hanno detto che il file crittografato deve essere della stessa dimensione di quello decrittografato. (C'è un problema con alcune altre API, non è colpa mia, lo giuro.)

Quindi, ho provato tutto ciò che posso trovare, ma niente funziona. .NET Framework ha un CipherMode.CTS che assomiglia esattamente a quello di cui ho bisogno, ma sfortunatamente non è attualmente supportato.

Ho provato a impostare il padding su none, ma ovviamente ho errori perché la dimensione del blocco è inferiore a quella che dovrebbe essere.

idee?

Modifica: Sono riuscito a risolvere questo problema in 2 modi:

Con API .NET     SymmetricAlgorithm alg = new RijndaelManaged ();     alg.Mode = CipherMode.CFB;     alg.Padding = PaddingMode.None;     alg.FeedbackSize = 8;

Con le API di BouncyCastle IBufferedCipher cipher = new CtsBlockCipher (new CbcBlockCipher (new AesFastEngine ()));

Spero che questo possa aiutare gli altri con lo stesso problema:)

    
posta Fabio 30.10.2012 - 17:31
fonte

3 risposte

10

Anche se usi CTS, hai ancora bisogno di un vettore di inizializzazione (IV) che DEVE (insisto, MUST ) essere generato di nuovo per ogni file con un generatore di numeri pseudo-casuali crittograficamente strong. Quindi non sarai in grado di adattare tutto senza aumentare le dimensioni. Questo è inevitabile, purché si usi una cifratura a blocchi "normale".

Inoltre, se hai bisogno di crittografia, probabilmente hai bisogno di integrità, cioè un MAC , che, intrinsecamente, richiede un po 'di spazio in più.

Quello che potresti provare è comprimere il file prima di crittarlo ( System.IO.Compression.DeflateStream ); questo potrebbe darti lo spazio di respiro extra di cui hai bisogno (non in un modo garantito , ma funzionerà, specialmente se il file che devi criptare è un file XML o qualcosa del genere, con un sacco di struttura).

    
risposta data 30.10.2012 - 17:49
fonte
5

Come scrisse Thomas, per crittografare in modo sicuro il file è necessario disporre di una IV oltre al file crittografato. Affinché un IV sia sicuro, deve soddisfare due condizioni:

  1. Lo stesso IV e la coppia di chiavi non sono usati per due messaggi diversi.
  2. Un utente malintenzionato non può predire l'IV utilizzato per un messaggio di sua scelta crittografato con la stessa chiave di un messaggio che l'hacker desidera decifrare.

Queste due condizioni sono generalmente soddisfatte utilizzando un IV casuale diverso per messaggio, che nel tuo caso richiederebbe l'aggiunta della IV al file crittografato aumentando così la dimensione del file. Ma se alcune condizioni sono vere puoi usare le proprietà del file (percorso, nome, data e ora) come IV (in modo da non dover aggiungere la IV al file crittografato). Le condizioni sono:

  1. La chiave di crittografia è univoca per macchina. Questo assicura che lo stesso IV non viene mai utilizzato con la stessa chiave di crittografia poiché non è possibile due file sulla stessa macchina con le stesse proprietà del file.
  2. La chiave di crittografia è univoca per utente.Questo assicura che un utente malintenzionato non possa montare un attacco di testo normale selezionato per decodificare i file di altri utenti poiché le chiavi sono diverse.

Se queste due condizioni sono soddisfatte, puoi utilizzare una modalità di esecuzione del codice di flusso (ad esempio CTR, OFB, CFB) e utilizzare le proprietà del file come IV.

    
risposta data 30.10.2012 - 19:46
fonte
2

Ci sono alcune opzioni:

  1. Verifica se TripleDESCryptoServiceProvider supporta CTS.
  2. Trasforma AES in modalità CBC in un codice di streaming.

Per quest'ultimo, crittografate semplicemente i blocchi di zeri e xor il testo in chiaro con il cipherstream risultante:

// work out what the padding length needs to be
int paddingSize = cipher.BlockSize - (message.Length % cipher.BlockSize);
int paddedSize = message.Length + paddingSize;

// build a block of zeros
byte[] zeros = new byte[paddedSize];

// create a keystream from the key and IV, using the zeros as a plaintext
byte[] keystream = EncryptAES(zeros, key, iv);

// produce the ciphertext by xoring the plaintext and the keystream
byte[] ciphertext = new byte[message.Length];
for (int i = 0; i < message.Length; i++)
    ciphertext[i] = message[i] ^ keystream[i];

Funziona sia come algoritmo di crittografia che di decrittografia, basta riportare indietro il testo cifrato con la stessa chiave e IV, e otterrete il testo in chiaro originale. Ma, come sottolinea Thomas Pornin, dovrai comunque inviare una IV univoca con ciascun messaggio.

    
risposta data 30.10.2012 - 17:45
fonte

Leggi altre domande sui tag