Bei AES (Advanced Encryption Standard) bzw Rijndael (ausgesprochen: Rain-Dahl [rɛindaːl]) handelt es sich um einen Verschlüsselungsalgorithmus, welcher im Oktober 2000 als Standard festgelegt wurde und den Vorgänger DES (Data Encryption Standard) ablöst.
AES setzt auf eine Blockverschlüsselung, d.h. der Schlüssel wird in mehrer Rundenschlüssel eingeteilt, mit welchem pro Runde in jedem Block die Bytes ersetzt (SubBytes), verschoben (ShiftRows) und vermischt (MixColumns) werden. Es gibt je nach Schlüssellänge 10 (128 bit), 12 (192 bit) oder 14 (256 bit) Runden (R) und eine zusätzliche Endrunde, so werden R+1 Rundenschlüssel benötigt.

Für weitere Informationen empfehle ich:

Nun zur Verschlüsselung eines Strings mit AES in C# zum einen nach AES-Spezifikationen (FIPS-197), zum anderen nach Rijndael (welcher ja zum AES Algorithmus gewählt wurde).
Zwischen AES und Rijndael gibt es, trotz der Wahl von Rijndael zum Algorithmus, Unterschiede, welche eine Kompatibilität untereinander unmöglich machen.

  1. Rijndael erlaubt variable Block- und Schlüsselgrößen (128, 160, 192, 224,  256), wohingegen bei AES eine Blockgröße von 128 bit und eine Schlüsselgröße von 128, 192 oder 256 bit vorgeschrieben sind.
  2. Rijndael erlaubt zusätzlich zu Cipher Block Chaining Mode (CBC) die Verwendung von Cipher Feedback Mode (CFB) als Betriebsmodus, wohingegen AES nur Ersteres unterstützt (bzw. CFB nur mit 128 bit Feedback)

Nun aber zum Code:

[tabs active=“1″]
[tab title=“AES (FIPS-197)“]
Ich habe folgenden statische Klasse erstellt, mit der wir sämtliche Vorgänge (also Ver- und Entschlüsseln) durchführen können.
[spoiler title=“Statische AES Klasse“ style=“fancy“]
Benötigt werden folgende Namespaces:

using System; //Für sämtliche Grundfunktionen
using System.IO; //Für Streams
using System.Security.Cryptography; //Für AES
using System.Windows.Forms; //Zum Anzeigen der Fehlermeldungen (MessageBox)

 

static class AesExample
    {
        public static byte[] EncryptStringToBytes(string plainText, byte[] Key,byte[] IV)
        {
            // Überprüfe, ob alle Parameter gefüllt sind
            if ((String.IsNullOrEmpty(plainText) || (Key.Length <= 0 || Key == null) || (IV.Length <= 0 || IV == null)))
                throw new Exception("Keiner der übergebenen Werte darf leer sein");

            byte[] encrypted;

            // Erstelle ein Objekt der Klasse Aes und
            // belege den Schlüssel, sowie den Salt (Initalisierungsvektor) mit den Parametern
            using (Aes aesAlgo = Aes.Create())
            {
                aesAlgo.Key = Key;
                aesAlgo.IV = IV;

                //Verschlüsseler zur Umwandlung erstellen
                ICryptoTransform encryptor = aesAlgo.CreateEncryptor(aesAlgo.Key, aesAlgo.IV);

                // Erstelle Streams, welche für die Verschlüsselung genutzt werden
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            //Schreibe die Daten in den Stream
                            swEncrypt.Write(plainText);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }
            // Gebe die verschlüsselten Bytes aus dem Stream zurück
            return encrypted;
        }

        public static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
        {
            //Überprüfe, ob alle Parameter gefüllt sind
            if (((cipherText.Length <= 0 || cipherText == null) || (Key.Length <= 0 || Key == null) || (IV.Length <= 0 || IV == null)))
                throw new Exception("Keiner der übergebenen Werte darf leer sein");

            //Erstelle eine Variable, in welcher später der entschlüsselte Text gespeichert wird
            string plaintext = null;

            try
            {
                // Erstelle ein Objekt von AES mit begrenzter Gültigkeit und
                // weiße dem Schlüssel (Key) und Salt (IV), die als Parameter übergebenen Werte zu
                using (Aes aesAlgo = Aes.Create())
                {
                    aesAlgo.Key = Key;
                    aesAlgo.IV = IV;

                    // Erstelle einen Entschlüsseler, welcher den Schlüssel und Salt nutzt,
                    // um den ByteArray-Stream zu verändern (entschlüsseln)
                    ICryptoTransform decryptor = aesAlgo.CreateDecryptor(aesAlgo.Key, aesAlgo.IV);

                    // Erstelle Stream, welche zu Entschlüsselung genutzt werden
                    // Ein Stream ist eine Darstellung einer geordneten Abfolge von Bytes
                    using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                    {
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                            {
                                // Lese die entschlüsselten Bytes aus dem entschlüsselten Stream
                                // und füge sie komplett in die Variable, welche den entschlüsselte Text speichert.
                                plaintext = srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + "\r\nMöglichweise passt der aktuelle Schlüssel oder Salt nicht mit jenem überein, welcher die Daten verschlüsselt hat");
                return null;
            }
            return plaintext;
        }

        ///
/// Wandle den String in ein ByteArray mit Base64
        /// Base64 ist ein Verfahren zur Kodierung von Binärdaten
        ///
        public static byte[] AESStringToByteArray(string cipher)
        {
            byte[] encByteArray = Convert.FromBase64String(cipher);
            return encByteArray;
        }

        ///
/// Wandelt das übergebene Bytearray in einen menschenlesbaren String.
        /// Base64 ist ein Verfahren um Binärdaten zu kodieren
        ///
        ///Die Binärdaten
        /// Den gewandelten String
        public static string AESByteArrayToString(byte[] arr)
        {
            string base64 = Convert.ToBase64String(arr);
            return base64;
        }
    }

[/spoiler]

Und so nutzt man die oben erstellte Klasse, in vollem Umfang:
[spoiler title=“Aufruf/Nutzung der AES-Klasse“ style=“fancy“]
Zu allererst erstellen wir ein Objekt, welches uns beim Ausführen des Algorithmus unterstützt. In diesem werden wir unseren Schlüssel, sowie den Salt zwischenspeichern.

Aes aesAlgo = Aes.Create();

Zusätzlich benötigen wir folgende Methode zum Aufruf der Klasse, welche den Schlüssel erstellt und zurückgibt.

        private void AES_CreateOwnSaltedKey()
        {
            CreateOwnSaltedKey eigenerSchluessel = new CreateOwnSaltedKey();
            if (eigenerSchluessel.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                aesAlgo.Key = eigenerSchluessel.Key;
                aesAlgo.IV = eigenerSchluessel.SALT;
            }
        }

Da wir nun einen Schlüssel und den Salt haben, können wir nun den String verschlüsseln.
Dies geschieht über folgende Methode:

        ///
/// Verschlüsselt den eingegebenen String mit dem gewählten Passwort und Salt.
        /// Der Salt wird in die Textbox geschrieben und ist damit öffentlich zugänglich
        ///
        private void AES_EncryptString()
        {
            byte[] encryptedByteArray = AesExample.EncryptStringToBytes(AES_orgString_textBox.Text, aesAlgo.Key, aesAlgo.IV); //Verschlüsselt den eingegeben String (siehe Klasse)
            AES_salt_textBox.Text = AesExample.AESByteArrayToString(aesAlgo.IV); //Der verschlüsseSalt wird in der Regel vor oder nach dem verschlüsselten String angehängt
            //(ist also nicht im Gegensatz zum Schlüssel nicht geheim)
            AES_encryptedString_textBox.Text = AesExample.AESByteArrayToString(encryptedByteArray); //
            aesAlgo.GenerateIV(); //Nach jedem Verschlüsseln, soll ein neuer Salt (IV) generiert werden
        }

Da wir den String nun verschlüsselt haben, möchten wir ihn nun wieder entschlüsseln. Dies geht mit folgender Methode. Die Methode erstellt ein neues Objekt der Klasse InsertOwnKey (Form), zeigt die Form an und bezieht aus den Properties der Klasse den Schlüssel (public byte[] Key). Zusätzlich ruft sie die eigentliche Methode zum Entschlüsseln auf (DecyrptAndShowString)

        private void AES_DecryptWithOwnKey()
        {
            InsertOwnKey insertOwnKey = new InsertOwnKey(AesExample.AESStringToByteArray(AES_salt_textBox.Text)); //Erstelle eine neue Instanz der InsertOwnKey-Klasse, welche von Form abgeleitet ist
            if (insertOwnKey.ShowDialog() == System.Windows.Forms.DialogResult.OK) //Rufe die Methode ShowDialog()-Methode der Instanz auf und prüfe ob der Rückgabetyp (DialogResult) OK ist
            {   //Sollte dies der Fall sein,
                aesAlgo.Key = insertOwnKey.Key; // so greife auf das öffentliche (public) Property 'Key' (Typ: ByteArray)
                //und ersetzte die Eigenschaft (Property) Key durch den Key aus der Instanz der InsertOwnKey-Klasse
                DecyrptAndShowString(); //Rufe die Methode zum Anzeigen des entschlüsselten Textes auf
            }
        }

        ///
/// Entschlüssele den verschlüsselten Text indem man den Text der TextBoxen in ein ByteArray wandelt und dies durch die AES-Klasse
        /// entschlüsseln lässt. Zur Entschlüsselung ist der verschlüsselte Text, der Schlüssel, sowie der Salt (Initialisierungvektor) erforderlich
        ///
        private void DecyrptAndShowString()
        {
            byte[] encryptedString = AesExample.AESStringToByteArray(AES_encryptedString_textBox.Text);  //Rufe eine Methode zur Wandlung eines Strings in ein ByteArray auf und übergibt das ByteArray in eine Variable
            byte[] salt = AesExample.AESStringToByteArray(AES_salt_textBox.Text); //Rufe eine Methode zur Wandlung eines Strings in ein ByteArray auf und übergibt das ByteArray in eine Variable
            string decryptedString = AesExample.DecryptStringFromBytes(encryptedString, aesAlgo.Key, salt); //Entschlüsselt die Daten und speichert sie in einer Variable zwischen
            if (!String.IsNullOrEmpty(decryptedString)) //Prüft ob die Variable zum Zwischenspeichern des entschlüsselten Strings NICHT (!) leer ist
            {
                MessageBox.Show(decryptedString); //Zeigt den entshlüsselten String in einer TextBox an
            }
        }

[/spoiler]
Folgende Klasse (Form) wird zur Erstellung des Schlüssels verwendet und über die Methode AES_CreateOwnSaltedKey aufgerufen.
[spoiler title=“Form zum Erstellen des Schlüssels“ style=“fancy“]
Um selbst ein Passwort zum Verschlüsseln zu verwenden, benötigt man die Rfc2898DeriveBytes-Klasse.

Diese verwende ich meiner eigenen Form, in Verbindung mit Aes-Klasse zum Erstellen eines Salts.

Die Klasse sieht dann wie folgt aus:

    public partial class CreateOwnSaltedKey : Form
    {
        Aes aesAlgo = Aes.Create();
        public byte[] Key { get; set; }
        public byte[] SALT { get; set; }

        public CreateOwnSaltedKey()
        {
            InitializeComponent();
            salt_textBox.Text = AesExample.AESByteArrayToString(aesAlgo.IV);
        }

        #region Random SALT
        private void createRandomSalt_button_Click(object sender, EventArgs e)
        {
            aesAlgo.GenerateIV();
            salt_textBox.Text = AesExample.AESByteArrayToString(aesAlgo.IV);
        }
        #endregion

        public void CreateKey()
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password_textBox.Text, aesAlgo.IV);
            Key = pdb.GetBytes(32);
            SALT = aesAlgo.IV;
        }

        #region Annehmen/Abbrechen
        private void abort_button_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Abort;
            this.Close();
        }

        private void accept_button_Click(object sender, EventArgs e)
        {
            CreateKey();
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
            this.Close();
        }
        #endregion
    }

Für das Abrufen des Schlüssel, sowie des Salts (auch Initialisierungsvektor[IV] genannt) wurde zwei Properties vom Type Byte-Array erstellt. Diese sind public, d.h. es gibt keine Einschränkungen beim Zugriff auf diese Member und sie somit auch von anderen Klassen aus abrufbar.

[/spoiler]

Folgende Klasse (Form) bietet die Möglichkeit der Eingabe des Schlüssels, welcher zu Entschlüsselung benötigt wird. Ein Objekt der Klasse wird in der Methode AES_DecryptWithOwnKey erstellt und angezeigt.

[spoiler title=“Klasse zur Schlüssel-Eingabe zur Entschlüsselung“ style=“fancy“]

    public partial class InsertOwnKey : Form
    {
        public byte[] Key { get; set; }
        public byte[] SALT;

        public InsertOwnKey(byte[] pSALT)
        {
            InitializeComponent();
            SALT = pSALT;
        }

        private void createKey()
        {
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password_textBox.Text, SALT);
            Key = pdb.GetBytes(32);
        }

        private void accept_button_Click(object sender, EventArgs e)
        {
            createKey();
            this.DialogResult = System.Windows.Forms.DialogResult.OK;
            this.Close();
        }

        private void abort_button_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Abort;
            this.Close();
        }
    }

[/spoiler]
[/tab]

[tab title=“Rijndael“]
Inhalt folgt noch. Der Code gleicht jenem der Aes-Klasse jedoch zu 90%
[/tab]
[/tabs]

Zu guter Letzt das Demo-Projekt:

20130811_Verweis-Manager - OleDBTest_000034

AES_Rijndael.zip