Ottenere il valore di decrittografia errato usando AesCryptoServiceProvider

Ho il seguente codice che utilizza AesCryptoServiceProvider per la crittografia e la decrittografia. La key iv e utilizzata sono le stesse sia per la crittografia che per la decrittografia. Ancora il valore decrittografato differisce dalla stringa sorgente.

  1. Che cosa è necessario correggere per ottenere il valore originale dopo la decrittografia?
  2. Questo codice funziona quando inputValue = valid128BitString . Ma quando inputString = “Test” sto ottenendo la seguente eccezione Padding is invalid and cannot be removed. . Come possiamo correggerlo?

DOMANDA AGGIORNATA

Quanto segue farà il trucco basato sulla risposta @jbtule.

 encyptedValue.IV = result.IV; 

Il valore IV dal risultato della crittografia cambia. Supponiamo che la crittografia avvenga in un processo separato, come possiamo conoscere l’IV per la decodifica? C’è un modo per renderlo costante o conosciuto?

Risposta: l’altra opzione è passare una IV in Crittografia e assegnarla prima di iniziare la trasformazione crittografica, invece di consentire a aesProvider di generarne uno casuale. – @Scott Chamberlain

  aesProvider.IV = Convert.FromBase64String("4uy34C9sqOC9rbV4GD8jrA=="); 

Aggiornamento: consultare Come applicare il riempimento per Base64 . Possiamo usare UTF8 per codificare l’input sorgente e l’output del risultato. La chiave e IV possono rimanere in Base64 .

L’utilizzo di Base64 per l’input di origine causerà problemi con alcuni valori, ad esempio “MyTest” dove la lunghezza della stringa non è un multiplo di 4

Punti rilevanti:

Per decodificare i dati crittografati utilizzando una delle classi SymmetricAlgorithm, è necessario impostare la proprietà Key e la proprietà IV sugli stessi valori utilizzati per la crittografia.

Proprietà SymmetricAlgorithm.IV: le informazioni del blocco precedente vengono mescolate nel processo di crittografia del blocco successivo. Pertanto, l’output di due blocchi di testo in chiaro identici è diverso. Poiché questa tecnica utilizza il blocco precedente per crittografare il blocco successivo, è necessario un vettore di inizializzazione per crittografare il primo blocco di dati. (Come da articolo MSDN di proprietà SymmetricAlgorithm.IV )

Le dimensioni chiave valide sono: 128, 192, 256 bit (come per Quanti caratteri creare un array di byte per il mio metodo AES? )

Programma principale

 class Program { static void Main(string[] args) { string valid128BitString = "AAECAwQFBgcICQoLDA0ODw=="; string inputValue = valid128BitString; string keyValue = valid128BitString; string iv = valid128BitString; byte[] byteValForString = Convert.FromBase64String(inputValue); EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue); EncryptResult encyptedValue = new EncryptResult(); encyptedValue.IV = iv; encyptedValue.EncryptedMsg = result.EncryptedMsg; string finalResult = Convert.ToBase64String(Aes128Utility.DecryptData(encyptedValue, keyValue)); Console.WriteLine(finalResult); if (String.Equals(inputValue, finalResult)) { Console.WriteLine("Match"); } else { Console.WriteLine("Differ"); } Console.ReadLine(); } } 

Utility AES

 public static class Aes128Utility { private static byte[] key; public static EncryptResult EncryptData(byte[] rawData, string strKey) { EncryptResult result = null; if (key == null) { if (!String.IsNullOrEmpty(strKey)) { key = Convert.FromBase64String((strKey)); result = Encrypt(rawData); } } else { result = Encrypt(rawData); } return result; } public static byte[] DecryptData(EncryptResult encryptResult, string strKey) { byte[] origData = null; if (key == null) { if (!String.IsNullOrEmpty(strKey)) { key = Convert.FromBase64String(strKey); origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV)); } } else { origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV)); } return origData; } private static EncryptResult Encrypt(byte[] rawData) { using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider()) { aesProvider.Key = key; aesProvider.Mode = CipherMode.CBC; aesProvider.Padding = PaddingMode.PKCS7; using (MemoryStream memStream = new MemoryStream()) { CryptoStream encStream = new CryptoStream(memStream, aesProvider.CreateEncryptor(), CryptoStreamMode.Write); encStream.Write(rawData, 0, rawData.Length); encStream.FlushFinalBlock(); EncryptResult encResult = new EncryptResult(); encResult.EncryptedMsg = Convert.ToBase64String(memStream.ToArray()); encResult.IV = Convert.ToBase64String(aesProvider.IV); return encResult; } } } private static byte[] Decrypt(byte[] encryptedMsg, byte[] iv) { using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider()) { aesProvider.Key = key; aesProvider.IV = iv; aesProvider.Mode = CipherMode.CBC; aesProvider.Padding = PaddingMode.PKCS7; using (MemoryStream memStream = new MemoryStream()) { CryptoStream decStream = new CryptoStream(memStream, aesProvider.CreateDecryptor(), CryptoStreamMode.Write); decStream.Write(encryptedMsg, 0, encryptedMsg.Length); decStream.FlushFinalBlock(); return memStream.ToArray(); } } } } 

Classe DTO

 public class EncryptResult { public string EncryptedMsg { get; set; } public string IV { get; set; } } 

Riferimenti

  1. Quanti caratteri creare un array di byte per il mio metodo AES?
  2. La chiave specificata non è una dimensione valida per questo algoritmo
  3. Crittografia con AES-256 e il vettore di inizializzazione
  4. Lunghezza non valida per un array di caratteri Base-64
  5. Qual è la differenza tra UTF8 / UTF16 e Base64 in termini di codifica

È facile fare errori di implementazione con le primitive crittografiche, le persone lo fanno sempre, è meglio usare una libreria di alto livello se ansible.

Ho uno snippet che cerco di tenere aggiornato e aggiornato, che funziona molto vicino a quello che stai facendo. Fa anche l’autenticazione sul testo cifrato, che consiglio se c’è un avversario in grado di inviare un testo cifrato scelto per l’implementazione della decrittografia, ci sono molti attacchi ai canali laterali relativi alla modifica del testo cifrato.

Tuttavia, il problema che stai avendo non ha nulla a che fare con il padding, se il tuo testo cifrato non corrisponde alla tua chiave e iv, e non hai autenticato il tuo iv e ciphertext, di solito ottieni un errore di padding (se questo è ribollito su un client, si chiama oracle di riempimento ). Devi cambiare la tua dichiarazione principale in:

  string valid128BitString = "AAECAwQFBgcICQoLDA0ODw=="; string inputValue = "Test"; string keyValue = valid128BitString; byte[] byteValForString = Encoding.UTF8.GetBytes(inputValue); EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue); EncryptResult encyptedValue = new EncryptResult(); encyptedValue.IV = result.IV; //<--Very Important encyptedValue.EncryptedMsg = result.EncryptedMsg; string finalResult =Encoding.UTF8.GetString(Aes128Utility.DecryptData(encyptedValue, keyValue)); 

Quindi usi lo stesso IV per decodificare come hai fatto per cifrare.