Benutzer mit den meisten Antworten
CryptographicEngine mit utf16 encoding

Frage
-
Hallo,
ich möchte gerne einen string mit einer Methode
string Verschluesseln(string _key, string data)
verschlüsseln und den Rückgabewert entsprechend entschlüsseln können, sodass wieder das gleiche Ergebnis herauskommt wie vor der Verschlüsselung. Mit der normalen Funktion
CryptographicBuffer.DecodeFromBase64String()
Funktioniert das auch alles ganz gut, allerdings kann der string data dann keine Sonderzeichen beinhalten, ohne dass eine Exeption geworfen wird "Ungültige Daten";
Deshalb habe ich es mit der Funktion
CryptographicBuffer.ConvertStringToBinary()
versucht. Meine Funktionen sehen wie folgt aus:
public static string Verschluesseln(string _key, string data) { string key = _key; data = strErweitern(data); //Erweitert den string auf ein Vielfaches von 8 mit einem bestimmten Zeichen SymmetricKeyAlgorithmProvider AKYP = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.Rc4); string verschlusseltstr = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf16LE, CryptographicEngine.Encrypt(AKYP.CreateSymmetricKey(CryptographicBuffer.DecodeFromBase64String(key.Replace("-", "1"))), CryptographicBuffer.ConvertStringToBinary(data, BinaryStringEncoding.Utf16LE), null)); return verschlusseltstr; } public static string Entschluesseln(string _key, string data) { string key = _key; SymmetricKeyAlgorithmProvider AKYP = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.Rc4); string encydata = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf16LE, CryptographicEngine.Decrypt(AKYP.CreateSymmetricKey(CryptographicBuffer.DecodeFromBase64String(key.Replace("-", "1"))), CryptographicBuffer.ConvertStringToBinary(data, BinaryStringEncoding.Utf16LE), null)); encydata = strReduzieren(encydata); //Reduziert den string auf das Original, indem das Zeichen (z.B. ß) von hinten entfernt wird return encydata; }
Mein Problem ist: Wenn ich einen string verschlüssle und wieder entschlüssle kommen nur irgendwelche chinesischen Zeichen dabei raus, aber nicht das, was ich ursprünglich wollte.
Ich habe schon alle möglichen Kombinationsweisen zwischen ConvertStringToBinary und DecodeFrom64String ausprobiert. Das hat aber alles nichts gebracht.
Ich habe es auch mit utf8 probiert, dort bekomme ich aber die Fehlermeldung:
Für das Unicode-Zeichen ist kein zugeordnetes Zeichen in der Mehrbytecodepage vorhanden. (Ausnahme von HRESULT: 0x80070459)
Womit ich nicht wirklich was anfangen kann.
Ich hoffe ihr könnt mir helfen.
Wie gesagt, es ist wichtig, das möglichst viele Sonderzeichen unterstützt werden.
Gruß
Hefeteig
Fischertechnik Fan
- Typ geändert Robert BreitenhoferModerator Dienstag, 5. Februar 2013 13:04 Frage
Antworten
-
Hallo Hefeteig,
Obwohl es so aussehen mag, dass man ein Byte-Array problemlos in ein UTF16-String speichern kann, ist dem nicht so. Oder wie Shawn Farkas in seinem Artikel zum Thema schrieb: "just because these encodings use all eight bits of a byte doesn't mean that every arbitrary sequence of bytes represents a valid character in them".
Der Fehler wird leider oft erst beim Roundtripping sichtbar, also wenn man versucht, den Text wieder zu dekodieren. Die Lösung ist ganz einfach: Man verwendet einen base64 kodierten String für die Zwischenspeicherung, da diese Kodierung den verschlüsselten Byte-Puffer verlustlos speichern kann:
public static string Verschluesseln(string base64Key, string base64Data) { // Übergebene Schlüssel- und Klartext-Parameter aus base64 dekodieren IBuffer bufferKey = CryptographicBuffer.DecodeFromBase64String(base64Key); IBuffer bufferData = CryptographicBuffer.DecodeFromBase64String(base64Data); // RC4-Schlüsselalgorithmus-Provider erstellen SymmetricKeyAlgorithmProvider rc4Provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.Rc4); // Symmetrischen Schlüssel erstellen anhand des dekodierten Schlüssel-Puffers erstellen CryptographicKey symmetricKey = rc4Provider.CreateSymmetricKey(bufferKey); // Verschlüsseln IBuffer bufferEncrypted = CryptographicEngine.Encrypt(symmetricKey, bufferData, null); // Verschlüsselten Puffer nach base64 kodieren string base64Encoded = CryptographicBuffer.EncodeToBase64String(bufferEncrypted); return base64Encoded; } public static string Entschluesseln(string base64Key, string base64Data) { // Übergebene Schlüssel- und Klartext-Parameter aus base64 dekodieren IBuffer bufferKey = CryptographicBuffer.DecodeFromBase64String(base64Key); IBuffer bufferData = CryptographicBuffer.DecodeFromBase64String(base64Data); // RC4-Schlüsselalgorithmus-Provider erstellen SymmetricKeyAlgorithmProvider rc4Provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.Rc4); // Symmetrischen Schlüssel erstellen anhand des dekodierten Schlüssel-Puffers erstellen CryptographicKey symmetricKey = rc4Provider.CreateSymmetricKey(bufferKey); // Entschlüsseln IBuffer bufferDecrypted = CryptographicEngine.Decrypt(symmetricKey, bufferData, null); // Entschlüsselter Puffer in ein String konvertieren. string decryptedString = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf16LE, bufferDecrypted); return decryptedString; }
Hier ein Beispiel-Aufruf:
string key = "Secret"; string plaintext = "Attack at dawn"; // Schlüssel zu base64 codieren var keyBuffer = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf16LE); var base64Key = CryptographicBuffer.EncodeToBase64String(keyBuffer); // Klartext zu base64 codieren var plaintextBuffer = CryptographicBuffer.ConvertStringToBinary(plaintext, BinaryStringEncoding.Utf16LE); var base64Buffer = CryptographicBuffer.EncodeToBase64String(plaintextBuffer); // Verschlüsseln var encryptedBase64String = Verschluesseln(base64Key, base64Buffer); var decryptedPlaintext = Entschluesseln(base64Key, encryptedBase64String);
Zum Schluss noch einige Bemerkungen:
Schlüssel und Daten liegen in deinem Code mehrfach im Speicher, was ein Sicherheitsrisiko darstellt. Du solltest darauf achten, möglichst wenige und nur lokale Kopien davon zu behalten und diese sofort nach der Verwendung zu überschreiben. Der GC wird sich um die Bereinigung des Speichers kümmern.In deinem Code werden zwei Hilfsmethoden verwendet (strErweitern() und strReduzieren()). Über deren Sinn kann ich anhand des Kommentars nur mutmaßen. Da RC4 stream- und nicht blockorientiert arbeitet, muss kein Padding (Vielfaches der Blockgröße) angewandt werden.
Über das Speichern von "Sonderzeichen" mußt Du dir keine Sorgen machen, solange Du UTF-16 Strings verwendest.
Dein Problem tritt zwar in einer Windows 8 App auf, hat aber eher wenig damit oder mit WinRT zu tun.Gruß
Marcel- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 5. Februar 2013 13:06
Alle Antworten
-
Hallo Hefeteig,
Obwohl es so aussehen mag, dass man ein Byte-Array problemlos in ein UTF16-String speichern kann, ist dem nicht so. Oder wie Shawn Farkas in seinem Artikel zum Thema schrieb: "just because these encodings use all eight bits of a byte doesn't mean that every arbitrary sequence of bytes represents a valid character in them".
Der Fehler wird leider oft erst beim Roundtripping sichtbar, also wenn man versucht, den Text wieder zu dekodieren. Die Lösung ist ganz einfach: Man verwendet einen base64 kodierten String für die Zwischenspeicherung, da diese Kodierung den verschlüsselten Byte-Puffer verlustlos speichern kann:
public static string Verschluesseln(string base64Key, string base64Data) { // Übergebene Schlüssel- und Klartext-Parameter aus base64 dekodieren IBuffer bufferKey = CryptographicBuffer.DecodeFromBase64String(base64Key); IBuffer bufferData = CryptographicBuffer.DecodeFromBase64String(base64Data); // RC4-Schlüsselalgorithmus-Provider erstellen SymmetricKeyAlgorithmProvider rc4Provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.Rc4); // Symmetrischen Schlüssel erstellen anhand des dekodierten Schlüssel-Puffers erstellen CryptographicKey symmetricKey = rc4Provider.CreateSymmetricKey(bufferKey); // Verschlüsseln IBuffer bufferEncrypted = CryptographicEngine.Encrypt(symmetricKey, bufferData, null); // Verschlüsselten Puffer nach base64 kodieren string base64Encoded = CryptographicBuffer.EncodeToBase64String(bufferEncrypted); return base64Encoded; } public static string Entschluesseln(string base64Key, string base64Data) { // Übergebene Schlüssel- und Klartext-Parameter aus base64 dekodieren IBuffer bufferKey = CryptographicBuffer.DecodeFromBase64String(base64Key); IBuffer bufferData = CryptographicBuffer.DecodeFromBase64String(base64Data); // RC4-Schlüsselalgorithmus-Provider erstellen SymmetricKeyAlgorithmProvider rc4Provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.Rc4); // Symmetrischen Schlüssel erstellen anhand des dekodierten Schlüssel-Puffers erstellen CryptographicKey symmetricKey = rc4Provider.CreateSymmetricKey(bufferKey); // Entschlüsseln IBuffer bufferDecrypted = CryptographicEngine.Decrypt(symmetricKey, bufferData, null); // Entschlüsselter Puffer in ein String konvertieren. string decryptedString = CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf16LE, bufferDecrypted); return decryptedString; }
Hier ein Beispiel-Aufruf:
string key = "Secret"; string plaintext = "Attack at dawn"; // Schlüssel zu base64 codieren var keyBuffer = CryptographicBuffer.ConvertStringToBinary(key, BinaryStringEncoding.Utf16LE); var base64Key = CryptographicBuffer.EncodeToBase64String(keyBuffer); // Klartext zu base64 codieren var plaintextBuffer = CryptographicBuffer.ConvertStringToBinary(plaintext, BinaryStringEncoding.Utf16LE); var base64Buffer = CryptographicBuffer.EncodeToBase64String(plaintextBuffer); // Verschlüsseln var encryptedBase64String = Verschluesseln(base64Key, base64Buffer); var decryptedPlaintext = Entschluesseln(base64Key, encryptedBase64String);
Zum Schluss noch einige Bemerkungen:
Schlüssel und Daten liegen in deinem Code mehrfach im Speicher, was ein Sicherheitsrisiko darstellt. Du solltest darauf achten, möglichst wenige und nur lokale Kopien davon zu behalten und diese sofort nach der Verwendung zu überschreiben. Der GC wird sich um die Bereinigung des Speichers kümmern.In deinem Code werden zwei Hilfsmethoden verwendet (strErweitern() und strReduzieren()). Über deren Sinn kann ich anhand des Kommentars nur mutmaßen. Da RC4 stream- und nicht blockorientiert arbeitet, muss kein Padding (Vielfaches der Blockgröße) angewandt werden.
Über das Speichern von "Sonderzeichen" mußt Du dir keine Sorgen machen, solange Du UTF-16 Strings verwendest.
Dein Problem tritt zwar in einer Windows 8 App auf, hat aber eher wenig damit oder mit WinRT zu tun.Gruß
Marcel- Als Antwort markiert Robert BreitenhoferModerator Dienstag, 5. Februar 2013 13:06
-