Entwickler-Ecke

Sonstiges (.NET) - ICryptoTransform.TransformBlock() original Länge


Flitzs - Mi 13.01.10 22:34
Titel: ICryptoTransform.TransformBlock() original Länge
Hallo,

vorab, ich benütze .Net 4.0, doch diese Version ist in der Combo Box weiter oben nicht auswählbar.

Ich habe eine Frage zur verschlüsselungen/entschlüsselung mithilfe der AesCryptoServiceProvider Klasse:

Zur besseren Verständnis des Codes der noch folgt, hier eine Klasse die ich benütze, um die Daten für die AES ver-/entschlüsselung zu halten.

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
 public class AESEncryptionSettings : IDisposable
    {        
        public byte[] Key { get; set; }       
        public byte[] IV { get; set; }      
        public ICryptoTransform Encrypter { get; set; }       
        public ICryptoTransform Decrypter { get; set; }
    }

(IDisposable wird weiter unten implementiert, ist hier aber nicht wichtig)

Ich habe mir folgende Funktion geschrieben, um den Schlüssel und co. zu generieren.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
 public const int AESKeyLength = 256;
 public static AESEncryptionSettings GenerateAESSettings(byte[] ivToUse = nullbyte[] keyToUse = null)
        {
            AESEncryptionSettings AESSettings = new AESEncryptionSettings();

            AesCryptoServiceProvider acp = new AesCryptoServiceProvider();
            acp.BlockSize = 128;
            acp.KeySize = AESKeyLength;
            if (ivToUse == null)
                acp.GenerateIV();
            else
                acp.IV = ivToUse;
                            
            if (keyToUse == null)
                acp.GenerateKey();
            else
                acp.Key = keyToUse;

            AESSettings.IV = acp.IV;
            AESSettings.Key = acp.Key;
            AESSettings.Decrypter = acp.CreateDecryptor();
            AESSettings.Encrypter = acp.CreateEncryptor();
            acp.Dispose();                                                

            return AESSettings;
        }


Die Frage ist nun, wie entschlüssle/verschlüssle ich die Daten nun?

Eine Nachricht zu ent-/verschlüsseln ist noch relativ einfach

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
        
        public static byte[] EncryptAES(byte[] plain, AESEncryptionSettings settings)
        {
            return settings.Encrypter.TransformFinalBlock(plain, 0, plain.Length);
        }      
        public static byte[] DecryptAES(byte[] encrypted, AESEncryptionSettings settings)
        {           
            return settings.Decrypter.TransformFinalBlock(encrypted, 0, encrypted.Length);
        }


Doch was nun, wenn ich mehrere Nachrichten hintereiander ver-/entschlüsseln möchte?
Zwar gibt es die ICryptoTransform.TransformBlock Methode die wohl dafür gedacht ist, doch benötige ich hierfür die Länge der Ausgangsnachricht, die ich nicht kenne.
Ist das so dann nicht implementierbar? Bzw ist AES dafür nicht gedacht? Was gibt es für Alternativen?

mfg Flitzs

EDIT: Versuche ich damit, mehrere Nachrichten zu ent-/verschlüsselen, wird beim zweiten entschlüsseln eine System.Security.Cryptography.CryptographicException mit der Meldung: "Padding is invalid and cannot be removed." ausgelöst.


Flitzs - Mi 13.01.10 23:11

Hi,

hier ein paar Änderungen die ich gemacht habe:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
       public static byte[] EncryptAES(byte[] plain, AESEncryptionSettings settings)
        {
            byte[] result;
            using (MemoryStream inputStream = new MemoryStream())
            {
                using (CryptoStream cStream = new CryptoStream(inputStream, settings.Encrypter, CryptoStreamMode.Write))
                    cStream.Write(plain, 0, plain.Length);
                result = inputStream.ToArray();
            }

            return result;          
        }       
        public static byte[] DecryptAES(byte[] encrypted, AESEncryptionSettings settings)
        {
            byte[] result;
            using (MemoryStream inputStream = new MemoryStream())
            {
                using (CryptoStream cStream = new CryptoStream(inputStream, settings.Decrypter, CryptoStreamMode.Write))
                    cStream.Write(encrypted, 0, encrypted.Length);
                result = inputStream.ToArray();
            }
            return result;            
        }


Den Fehler der vorher kahm, konnte ich damit elemieren, indem ich die Nachrichten mindestens 16 Byte (also die Blocklänge) lang gemacht habe.

Doch kommt beim 2ten Entschlüsseln nur noch Müll heraus. Muss ich mir die Instanzen von ICrypoTransform jedes mal neu erzeugen (mithilfe des Keys und IVs)?

mfg Flitzs


Kha - Do 14.01.10 01:00

Kenne mich im Crypto-Bereich nicht aus, aber so, wie es aussieht, musst du wohl wirklich acp.CreateEn/Decryptor jedes Mal neu aufrufen.

PS: Deine Methode GenerateAESSettings nennt man landläufig auch "Konstruktor" :mrgreen: .


Flitzs - Do 14.01.10 11:18

Hi,

ein Konstruktor wäre es doch nur, wenn die Klasse/Methode nicht statisch wäre. Sinn dahinter ist, dass ich mehrer Verschlüsselungsalgorithmen in einer statischen Klasse habe.

mfg Flitzs


Kha - Do 14.01.10 21:36

user profile iconFlitzs hat folgendes geschrieben Zum zitierten Posting springen:
ein Konstruktor wäre es doch nur, wenn die Klasse/Methode nicht statisch wäre.
Ein Konstruktor ist im Grunde eine statische Methode.
Mein "PS" sollte einfach ein Wink mit dem Zaunpfahl sein, dass diese Methode ein Konstruktor sein sollte... ;)


Flitzs - Do 14.01.10 22:18

Hey,

die Funktionen Encrypt/DecryptAES und GenerateAESSettings sind Teil einer statischen Klasse, die mehrer solche Funktionen für verschiedene Verschlüsselungsalgorithmen bereitstellt.

mfg Flitzs