Entwickler-Ecke

Sonstiges (.NET) - Verschlüsselung der Daten in einer Datenbank (RSA)


Määx - Mo 06.01.14 16:47
Titel: Verschlüsselung der Daten in einer Datenbank (RSA)
Hallo zusammen,

ich habe ein Projekt, das via EntityFramework auf eine Datenbank zugreift. Nun möchte ich die gesamte Datenbank verschlüsseln. Da -so weit ich das bei google verstanden habe- das EntityFramework selbst keine verschlüsselung unterstützt hab eich mir überlegt die Daten eben vorm/nach dem Schreiben in die DB selbst zu verschlüsseln. Dafür würde ich gerne den AES/Rijndael Algorithmus nutzen. Gleichzeitig möchte ich jedoch sicherstellen, dass man das Programm nicht ienfach auf einen anderen Rechner kopieren köntne und dort auf ide Daten zugreifen kann bzw. das Passwort für die Verschlüsselung zB einmal pro Jahr ändern. Deshalb würde ich gern ein Zertifikat hierfür nutzen.

Jetzt habe ich folgenden Ansatz hierfür gewählt:

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:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
    public static string encrypt(string text)
    {
        X509Certificate2 cert = LoadCert(EnumCipheringTarget.ClientServer);
        RSACryptoServiceProvider publicprovider = (RSACryptoServiceProvider)cert.PublicKey.Key;
        byte[] encrypted = publicprovider.Encrypt(GetBytes(text), false);
        return GetString(encrypted);
    }
    public static string decrypt(string text)
    {
        X509Certificate2 cert = LoadCert(EnumCipheringTarget.ClientServer);
        RSACryptoServiceProvider provider = (RSACryptoServiceProvider)cert.PrivateKey;
        byte[] decryptedBytes = provider.Decrypt(GetBytes(text), false);
        return GetString(decryptedBytes);
    }
    private static X509Certificate2 LoadCert(EnumCipheringTarget cipherTarget)
    {
        X509Store store = new X509Store(StoreLocation.CurrentUser);
        store.Open(OpenFlags.ReadOnly);
        X509Certificate2Collection certCollection = store.Certificates;
        X509Certificate2 cert = null;

        string certSubject = "";
        switch (cipherTarget)
        {
            case EnumCipheringTarget.ServerDB:
                certSubject = "CN=MY_DB_CERTIFICATE";
                break;

            default:
                return null;
        }

        foreach (X509Certificate2 c in certCollection)
        {
            if (c.Subject == certSubject)
            {
                cert = c;
                break;
            }
        }
        store.Close();
        return cert;
    }
    static byte[] GetBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }
    static string GetString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }


Das ganze funktioniert auch soweit, dass ich einen Text ver- und später wieder entschlüsseln kann. Der verschlüsselte Text wird jedoch zum eien extrem lang und besteht zum anderen aus einer art chinesische Zeichen? so dass ich ihn nicht in die Datenbank schreiben kann...

Ich denke, dass ich vll bei getBytes/getString etwas falsch mache? Hat jemand eine Idee?

Vielen Dank
Määx

EDIT:
achso, wenn ich andere GetBytes / GetString Methoden wie z.B. System.Text.Encoding.UTF8.GetBytes(str); nutze, bekomme ich immer den Fehler : "Die zu entschlüsselnden Daten überschreiten das Maximum für das Modul um 256Bytes"


Ralf Jansen - Mo 06.01.14 17:04

Zitat:
Der verschlüsselte Text

(
Du benutzt einen Blockchiffre. Du wirst also minimal immer als Ergebnis einer Verschlüsselung die minimale Blockgröße(bei AES ist die glaube ich immer 128Bit unabhängig von der Schlüssellänge) erhalten.

Etwas verschlüsseltes ist erstmal ein Bytestrom und kein string. Ein string hat immer irgendwelche Einschränkungen was ein gültiges Zeichen ist wie die verglichen werden etc. Je nach Encoding wird es zu also zu Ungültigkeiten oder sogar impliziten Konvertierungen kommen. Gerade dann wenn mehr als ein System (also z.B. eine Programmierumgebung und eine DB) beteiligt ist. Innerhalb von .Net mag das ja noch funktionieren sobald aber eine Datenbank dazu kommt mit ihrer eigenen Vorstellung wie char/varchar Felder zu kodieren sind knallt das. Heist char/varchars sind eher ungeeignet um darin etwas verschlüsseltes abzulegen das logischerweise unverändert (auf Bitebene) bleiben soll.

Wenn du etwas verschlüsselt speichern willst mach das als Blob. Und ich hoffe du willst nur bestimmte Felder verschlüsseln. Die Felder zu verschlüsseln die als Primary/Foreign Key verwendet werden wäre ausgesprochen Kontraproduktiv.


Määx - Mo 06.01.14 17:08

ahhh ok das Sinn! Werde es mit dem Blob direkt mal ausprobieren...
Zitat:
Und ich hoffe du willst nur bestimmte Felder verschlüsseln. Die Felder zu verschlüsseln die als Primary/Foreign Key verwendet werden wäre ausgesprochen Kontraproduktiv

Ja klar, ich verschlüssel in diesem Fall z.B. nur die Stammdaten, nicht die Schlüssel... Danke aber trotzdem für den Hinweis


Ralf Jansen - Mo 06.01.14 17:15

So nebenbei. Dir ist bewußt das Suchen über diese Stammdaten dann kaum noch möglich ist? Nur noch auf absolute Gleichheit wird funktionieren.


Määx - Mo 06.01.14 18:34

Soo, mit dem Blob klappt alles wunderbar! Vielen Dank!

Ja leider, aber die Daten müssen leider zwangsweise in der DB verschlüsselt vorliegen damit auch kein Administrator oä diese direkt auslesen kann :( Und da habe ich ja keine andere Alternative oder?

Achso was ich ja eigentlich noch fragen wollte... ich habe jetzt ja den RSA verwendet, wollte ja aber eigentlich AES da dieser ja deutlich schneller sein sollte. Gibt es eine Möglichkeit aus dem Zertifikat den privateKey auszulesen oder einen einheitlichen AES-Key damit zu erstellen? Denn ich bekomme aus dem X509Certificate2.PrivateKey irgendwie keinen AesCryptoServiceProvider abgeleitet...

Vielen Dank


Ralf Jansen - Mo 06.01.14 19:09

Zitat:
Ja leider, aber die Daten müssen leider zwangsweise in der DB verschlüsselt vorliegen damit auch kein Administrator oä diese direkt auslesen kann :( Und da habe ich ja keine andere Alternative oder?


Wenn man nicht mal dem Admin vertraut ist eh alles verloren. Wird lustig wenn ein User sein Zertifikat zerlegt hat (selbst erstellt nicht gekauft) und es keiner retten kann. Beim 2.ten mal kommt man dann auf die Idee das Zertifikat an zentraler Stelle für den User zu verwalten für den Fall der Fälle. Diese Verwalter wird dann vermutlich der Admin sein und das ganze System ist adabsurdum geführt :roll:

Zitat:
Denn ich bekomme aus dem X509Certificate2.PrivateKey irgendwie keinen AesCryptoServiceProvider abgeleitet


Es ist RSA oder DSA aber niemals AES.


Määx - Di 07.01.14 13:11

Ja, ich gebe dir Recht, dass das nur begrenzt sinnvoll ist. Bin aber leider neu im Team und der Datenschutzbeauftragte hat das als Vorgabe gegeben...

Vielen Dank für deine schnelle&kompetente Hilfe!!