2010-06-30 9 views
6

auf Ich versuche, Daten mit RSA in C# zu verschlüsseln und zu entschlüsseln. Ich habe den folgenden MSTest Komponententest:CryptographicException tritt zeitweise beim Verschlüsseln/Entschlüsseln mit RSA

Es schlägt während der Entschlüsselung, aber nur manchmal. Es scheint so, als ob jedes Mal, wenn ich Breakpoints setze und den Test durchlaufe, es passiert. Das brachte mich dazu zu denken, dass vielleicht etwas nicht rechtzeitig fertig wurde, damit die Entschlüsselung erfolgreich durchgeführt werden konnte, und ich verlangsamte das Durchlaufen, während das Debugging ihm genügend Zeit gab, um abgeschlossen zu werden. Wenn es fehlschlägt, scheint die Linie es zum Scheitern verurteilt ist decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); in der folgenden Methode:

public static string Decrypt(string textToDecrypt, string privateKeyXml) 
{ 
    if (string.IsNullOrEmpty(textToDecrypt)) 
    { 
     throw new ArgumentException(
      "Cannot decrypt null or blank string" 
     ); 
    } 
    if (string.IsNullOrEmpty(privateKeyXml)) 
    { 
     throw new ArgumentException("Invalid private key XML given"); 
    } 
    byte[] bytesToDecrypt = ByteConverter.GetBytes(textToDecrypt); 
    byte[] decryptedBytes; 
    using (var rsa = new RSACryptoServiceProvider()) 
    { 
     rsa.FromXmlString(privateKeyXml); 
     decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); // fail here 
    } 
    return ByteConverter.GetString(decryptedBytes); 
} 

Es schlägt fehl, mit dieser Ausnahme:

System.Security.Cryptography.CryptographicException: Bad Daten

Meine Encrypt Methode ist wie folgt:

public static string Encrypt(string textToEncrypt, out string publicKey, 
    out string privateKey) 
{ 
    byte[] bytesToEncrypt = ByteConverter.GetBytes(textToEncrypt); 
    byte[] encryptedBytes; 
    using (var rsa = new RSACryptoServiceProvider()) 
    { 
     encryptedBytes = rsa.Encrypt(bytesToEncrypt, false); 
     publicKey = rsa.ToXmlString(false); 
     privateKey = rsa.ToXmlString(true); 
    } 
    return ByteConverter.GetString(encryptedBytes); 
} 

Die ByteConverter durchgehend verwendet nur die folgenden:

public static readonly UnicodeEncoding ByteConverter = new UnicodeEncoding(); 

Ich habe ein paar Fragen auf Stackoverflow über die RSA-Verschlüsselung und Entschlüsselung mit .NET gesehen. This one war aufgrund der Verschlüsselung mit dem privaten Schlüssel und versuchen, mit dem öffentlichen Schlüssel zu entschlüsseln, aber ich glaube nicht, dass ich das tue. This question hat die selbe Ausnahme wie ich, aber die ausgewählte Antwort war, OpenSSL.NET zu verwenden, was ich lieber nicht machen würde.

Was mache ich falsch?

Antwort

8

Konnten Sie durch Convert.FromBase64String ersetzen und ByteConverter.GetString durch Convert.ToBase64String ersetzen und sehen, ob das hilft. Bad Data Ausnahme bedeutet normalerweise, dass Sie ein ungültiges Zeichen in den Daten haben oder dass die Länge nicht die richtige Länge zum Entschlüsseln hat. Ich denke, dass die Verwendung der Konvertierungsfunktionen Ihre Probleme beheben kann.

public static readonly UnicodeEncoding ByteConverter = new UnicodeEncoding(); 

    public static string Encrypt(string textToEncrypt, out string publicKey, 
    out string privateKey) 
    { 
    byte[] bytesToEncrypt = ByteConverter.GetBytes(textToEncrypt); 
    byte[] encryptedBytes; 
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 
    { 
     encryptedBytes = rsa.Encrypt(bytesToEncrypt, false); 
     publicKey = rsa.ToXmlString(false); 
     privateKey = rsa.ToXmlString(true); 
    } 
    return Convert.ToBase64String(encryptedBytes); 
    } 

    public static string Decrypt(string textToDecrypt, string privateKeyXml) 
    { 
    if (string.IsNullOrEmpty(textToDecrypt)) 
    { 
     throw new ArgumentException(
      "Cannot decrypt null or blank string" 
     ); 
    } 
    if (string.IsNullOrEmpty(privateKeyXml)) 
    { 
     throw new ArgumentException("Invalid private key XML given"); 
    } 
    byte[] bytesToDecrypt = Convert.FromBase64String(textToDecrypt); 
    byte[] decryptedBytes; 
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 
    { 
     rsa.FromXmlString(privateKeyXml); 
     decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); // fail here 
    } 
    return ByteConverter.GetString(decryptedBytes); 
    } 
+1

Hm, versuchen, das gibt mir eine andere Ausnahme: "System.FormatException: Ungültige Länge für eine Base-64 Char-Array". Dies geschah in der ersten Zeile von 'Encrypt':' byte [] bytesToEncrypt = Convert.FromBase64String (textToEncrypt); '. –

+1

@Sarah - Ok, ich habe dein Beispiel aktualisiert. Ich habe es getestet und es sieht gut aus, dass es funktioniert. – SwDevMan81

+0

Das funktioniert! Vielen Dank. Ich hätte nie gedacht, diese Mischung aus 'Convert' /' UnicodeEncoding' zu verwenden. –

1

Ich würde empfehlen die Verwendung dieser Klasse, leider erinnere ich mich allerdings nicht den ursprünglichen Autor ..

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Security.Cryptography; 

namespace Encryption 
{ 

class AsymmetricED 
{ 
    private static RSAParameters param = new RSAParameters(); 
    /// <summary> 
    /// Get Parameters 
    /// </summary> 
    /// <param name="pp">Export private parameters?</param> 
    /// <returns></returns> 
    public static RSAParameters GenerateKeys(bool pp) 
    { 
     RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); 
     if (param.Equals(new RSAParameters())) 
     { 
      param = RSA.ExportParameters(true); 
     } 
     RSA.ImportParameters(param); 
     return RSA.ExportParameters(pp); 
    } 
    static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding) 
    { 
     try 
     { 
      //Create a new instance of RSACryptoServiceProvider. 
      RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); 

      //Import the RSA Key information. This only needs 
      //toinclude the public key information. 
      RSA.ImportParameters(RSAKeyInfo); 

      //Encrypt the passed byte array and specify OAEP padding. 
      //OAEP padding is only available on Microsoft Windows XP or 
      //later. 
      return RSA.Encrypt(DataToEncrypt, DoOAEPPadding); 
     } 
     //Catch and display a CryptographicException 
     //to the console. 
     catch (CryptographicException e) 
     { 
      Console.WriteLine(e.Message); 

      return null; 
     } 

    } 

    static public byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding) 
    { 
     try 
     { 
      //Create a new instance of RSACryptoServiceProvider. 
      RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); 

      //Import the RSA Key information. This needs 
      //to include the private key information. 
      RSA.ImportParameters(RSAKeyInfo); 

      //Decrypt the passed byte array and specify OAEP padding. 
      //OAEP padding is only available on Microsoft Windows XP or 
      //later. 
      return RSA.Decrypt(DataToDecrypt, DoOAEPPadding); 
     } 
     //Catch and display a CryptographicException 
     //to the console. 
     catch (CryptographicException e) 
     { 
      ConsoleColor col = Console.BackgroundColor; 
      Console.BackgroundColor = ConsoleColor.Red; 
      Console.WriteLine(e.ToString()); 
      Console.BackgroundColor = col; 
      return null; 
     } 

    } 
} 
} 

Anwendung:

Encryption.AsymmetricED.RSAEncrypt(Data, GenerateKeys(false), false); 

Encryption.AsymmetricED.RSADecrypt(Data, GenerateKeys(true), false); 

EDIT: Ich empfehle auch, dass Sie verwenden dies nicht für große Datenverschlüsselung. Normalerweise würden Sie die tatsächlichen Daten mit einem symmetrischen Algorithmus (AES, etc) verschlüsseln, dann den symmetrischen Schlüssel (zufällig erzeugt) mit dem RSA-Algorithmus verschlüsseln, dann den RSA-verschlüsselten symmetrischen Schlüssel und die symmetrischen Schlüsseldaten senden. Sie sollten auch Sehen Sie sich die RSA-Signatur an, um sicherzustellen, dass die Daten von der Stelle kommen, an der sie sich befindet.

3

Ihr Problem besteht in der Umwandlung von Bytes in Zeichenfolgen. Nicht alle Bytefolgen sind eine gültige UTF-16-Codierung und Sie verwenden eine UnicodeEncoding, die ungültige Byte automatisch ignoriert.Wenn Sie

verwendet
public static readonly UnicodeEncoding ByteConverter = new UnicodeEncoding(false, false, true); 

stattdessen würde der Code versagt haben, wenn sie versuchen, die Bytes statt still zu konvertieren die ungültigen Byte-Paare mit 0xFFFD ersetzen.

Die Tatsache, dass der Test während des Debugging funktionierte, war ein Zufall. Sie verwenden ein zufälliges RSA-Schlüsselpaar, daher erhalten Sie manchmal eine Verschlüsselung, die eine gültige UTF-16-Codierung ist.

Das Problem ist, wie SwDevMan81 vorschlägt, eine Codierung zu verwenden, die alle möglichen Byte-Arrays konvertieren kann. F.x. Base64-Codierung

Verwandte Themen