none
Verschlüsselung mit Datenverlust RRS feed

  • Frage

  • Die NET Verschlüsselung arbeitet seltsam.
    Wenn man mit der u.g. Encrypt() und Decrypt() Methode etwas verschlüsselt und anschließend wieder entschlüsselt, geht am Ende der Daten immer etwas verloren.
    Vielleicht hat das mit der Blockorientierung oder dem Pading zu tun, aber ich verstehe das nicht.
    Wenn ich ein anderes Padding als Zeros nehme, bekomme ich beim Entschlüsseln inner Fehlermeldungen.
    Wie verschlüsselt und entschlüsselt man einen Stream mit Aes und Passwort ?

    Hier mein Ansatz, bei dem immer das Ende verloren geht.

            public MemoryStream Encrypt(MemoryStream stream, string password)
            {
                AesManaged aes = new AesManaged();
    
                Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, new byte[] {101, 23, 87, 65, 45, 98, 10, 45});
    
                aes.Padding = PaddingMode.Zeros;
                aes.Key = rfc.GetBytes(32);
                aes.IV = new byte[] { 100, 210, 21, 33, 76, 87, 97, 23, 87, 65, 54, 09, 43, 28, 67, 89 };
    
                ICryptoTransform transform = aes.CreateEncryptor(aes.Key, aes.IV);
    
                MemoryStream memoryStream = new MemoryStream();
    
                using (CryptoStream encStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
                {
                    stream.CopyTo(encStream);
    
                    memoryStream.Position = 0;
    
                    MemoryStream ms = new MemoryStream();
    
                    memoryStream.CopyTo(ms);
    
                    ms.Position = 0;
    
                    return ms;
                }
            }
    

     

            public MemoryStream Decrypt(Stream stream, string password)
            {
                AesManaged aes = new AesManaged();
    
                Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, new byte[] { 101, 23, 87, 65, 45, 98, 10, 45 });
    
                aes.Padding = PaddingMode.Zeros;
                aes.Key = rfc.GetBytes(32);
                aes.IV = new byte[] { 100, 210, 21, 33, 76, 87, 97, 23, 87, 65, 54, 09, 43, 28, 67, 89 };
    
                ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
    
                MemoryStream memoryStream = new MemoryStream();
    
                using (CryptoStream encStream = new CryptoStream(stream, transform, CryptoStreamMode.Read))
                {
                    encStream.CopyTo(memoryStream);
    
                    memoryStream.Position = 0;
    
                    MemoryStream ms = new MemoryStream();
    
                    memoryStream.CopyTo(ms);
    
                    ms.Position = 0;
    
                    return ms;
                }
            }
    


    MarcAlexanderD

    Montag, 12. März 2012 11:25

Antworten

  • Hallo Marc Alexander,

    damit die letzten  Bytes eines CryptoStreams geschrieben werden, musst Du FlushFinalBlock aufrufen -
    oder den Stream disposen (ruft es implizit auf).

    Eine alternative Implementierung:

        class MemoryEncrypt
        {
            private static readonly byte[] TestSalt = new byte[] { 101, 23, 87, 65, 45, 98, 10, 45 };
            private static readonly byte[] TestIV = new byte[] { 100, 210, 21, 33, 76, 87, 97, 23, 87, 65, 54, 09, 43, 28, 67, 89 };
    
            public MemoryStream Encrypt(MemoryStream stream, string password)
            {
                MemoryStream memoryStream = new MemoryStream();
                using (SymmetricAlgorithm algorithm = Create(password))
                using (ICryptoTransform transform = algorithm.CreateEncryptor(algorithm.Key, algorithm.IV))
                using (CryptoStream encStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
                {
                    stream.CopyTo(encStream);
                    // encStream.FlushFinalBlock(); // hier durch Dispose
                }
                return new MemoryStream(memoryStream.ToArray());
            }
    
            public MemoryStream Decrypt(Stream stream, string password)
            {
                MemoryStream memoryStream = new MemoryStream();
                using (SymmetricAlgorithm algorithm = Create(password))
                using (ICryptoTransform transform = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV))
                using (CryptoStream decStream = new CryptoStream(stream, transform, CryptoStreamMode.Read))
                {
                    decStream.CopyTo(memoryStream);
                } 
                return new MemoryStream(memoryStream.ToArray());
            }
    
            private static SymmetricAlgorithm Create(string password)
            {
                AesManaged aes = new AesManaged();
    
                Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, TestSalt);
                aes.Padding = PaddingMode.Zeros;
                aes.Key = rfc.GetBytes(32);
                aes.IV = TestIV;
                return aes;
            }
    
            internal static void Test()
            {
                const string Password = "Kennwort";
                const string Test = "Alle meine Entchen schwimmen auf dem See...";
    
                MemoryStream inputStream = new MemoryStream();
                StreamWriter writer = new StreamWriter(inputStream);
                writer.WriteLine(Test);
                writer.Flush();
                inputStream.Position = 0;
    
                var encrypt = new MemoryEncrypt();
                var encryptedStream = encrypt.Encrypt(inputStream, Password);
    
                var decrypt = new MemoryEncrypt();
                var decryptStream = encrypt.Decrypt(encryptedStream, Password);
    
                StreamReader reader = new StreamReader(decryptStream);
                var output = reader.ReadLine();
    
                Debug.Assert(Test.Equals(output, StringComparison.Ordinal), "Abweichendes Ergebnis.");
            }
        }

    In der Test-Methode am Ende mit einem (simplen) Testcode.

    Gruß Elmar

    Montag, 12. März 2012 12:47
    Beantworter

Alle Antworten

  • Hallo Marc Alexander,

    damit die letzten  Bytes eines CryptoStreams geschrieben werden, musst Du FlushFinalBlock aufrufen -
    oder den Stream disposen (ruft es implizit auf).

    Eine alternative Implementierung:

        class MemoryEncrypt
        {
            private static readonly byte[] TestSalt = new byte[] { 101, 23, 87, 65, 45, 98, 10, 45 };
            private static readonly byte[] TestIV = new byte[] { 100, 210, 21, 33, 76, 87, 97, 23, 87, 65, 54, 09, 43, 28, 67, 89 };
    
            public MemoryStream Encrypt(MemoryStream stream, string password)
            {
                MemoryStream memoryStream = new MemoryStream();
                using (SymmetricAlgorithm algorithm = Create(password))
                using (ICryptoTransform transform = algorithm.CreateEncryptor(algorithm.Key, algorithm.IV))
                using (CryptoStream encStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
                {
                    stream.CopyTo(encStream);
                    // encStream.FlushFinalBlock(); // hier durch Dispose
                }
                return new MemoryStream(memoryStream.ToArray());
            }
    
            public MemoryStream Decrypt(Stream stream, string password)
            {
                MemoryStream memoryStream = new MemoryStream();
                using (SymmetricAlgorithm algorithm = Create(password))
                using (ICryptoTransform transform = algorithm.CreateDecryptor(algorithm.Key, algorithm.IV))
                using (CryptoStream decStream = new CryptoStream(stream, transform, CryptoStreamMode.Read))
                {
                    decStream.CopyTo(memoryStream);
                } 
                return new MemoryStream(memoryStream.ToArray());
            }
    
            private static SymmetricAlgorithm Create(string password)
            {
                AesManaged aes = new AesManaged();
    
                Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(password, TestSalt);
                aes.Padding = PaddingMode.Zeros;
                aes.Key = rfc.GetBytes(32);
                aes.IV = TestIV;
                return aes;
            }
    
            internal static void Test()
            {
                const string Password = "Kennwort";
                const string Test = "Alle meine Entchen schwimmen auf dem See...";
    
                MemoryStream inputStream = new MemoryStream();
                StreamWriter writer = new StreamWriter(inputStream);
                writer.WriteLine(Test);
                writer.Flush();
                inputStream.Position = 0;
    
                var encrypt = new MemoryEncrypt();
                var encryptedStream = encrypt.Encrypt(inputStream, Password);
    
                var decrypt = new MemoryEncrypt();
                var decryptStream = encrypt.Decrypt(encryptedStream, Password);
    
                StreamReader reader = new StreamReader(decryptStream);
                var output = reader.ReadLine();
    
                Debug.Assert(Test.Equals(output, StringComparison.Ordinal), "Abweichendes Ergebnis.");
            }
        }

    In der Test-Methode am Ende mit einem (simplen) Testcode.

    Gruß Elmar

    Montag, 12. März 2012 12:47
    Beantworter
  • Hallo MarcAlexander,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Montag, 19. März 2012 13:43
    Moderator