2017-06-08 49 views
5

Ich arbeite derzeit an einer Klasse, die große Mengen von Text mit einem zufällig generierten Verschlüsselungsschlüssel verschlüsselt mit einem X509-Zertifikat von einer Smartcard, mit einem RSACryptoServiceProvider, um den Hauptschlüssel durchzuführen Verschlüsselungs- und Entschlüsselungsvorgänge. Wenn ich jedoch die fOEAP padding-Option auf "true" gesetzt habe, habe ich immer den Fehler "Fehler beim Decodieren des OAEP-Padding" bei der Entschlüsselung. Ich habe die Schlüsselgröße überprüft und es liegt innerhalb akzeptabler Grenzen. Und ich habe Breakpoints durchlaufen, um sicherzustellen, dass die Base64-Zeichenfolge, die von der Verschlüsselungsfunktion zurückgegeben wird, genau der verschlüsselten Base64-Zeichenfolge entspricht, die beim erneuten Laden der Datei an die Entschlüsselungsfunktion zurückgegeben wird.C#: Fehler bei der Decodierung OAEP Padding seltsames Problem

Das Schlüsselpaar ist definitiv richtig, da es ohne OAEP funktioniert. Und ich habe auch die Textkodierung überprüft.

EDIT: Es stellt sich heraus, dass dies ein Smartcard-spezifisches Problem sein könnte, als ich Entschlüsselung mit einem lokalen X509-Zertifikat versuchte die Entschlüsselung erfolgreich war.

EDIT: Dies ist der Entschlüsselungscode, der fehlschlägt:

string TestString = "Hello World!"; 
X509Certificate2 cert = DRXEncrypter.GetCertificate("Select a test certificate", "Select a certificate to use for this test from the local store."); 
string key = DRXEncrypter.GenerateEncryptionKey(214); 
Console.WriteLine("Encryption Key: " + key); 

string encrypted = DRXEncrypter.EncryptBody(TestString, key); 
Console.WriteLine("Encrypted Body: " + encrypted); 

string cryptokey = DRXEncrypter.EncryptWithCert(cert, key); 
Console.WriteLine("Encrypted Decryption Key: " + cryptokey); 

string decrypted = DRXEncrypter.DecryptBody(encrypted, cryptokey, cert); 
Console.WriteLine("Decrypted Body: " + decrypted); 

Console.WriteLine("Output String: " + decrypted + "."); 

Hier ist der Code aus der Klasse Crypto Provider ich geschrieben habe. Ich stecke seit Stunden in diesem Problem, also wäre es großartig, wenn mir jemand helfen könnte.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Security.Cryptography; 
using System.Security.Cryptography.X509Certificates; 
using System.IO; 

namespace CoreDRXEditor 
{ 
public class DRXEncrypter 
{ 
    private byte[] Salt = Encoding.ASCII.GetBytes("81PO9j8I1a94j"); 
    private string EncryptionKey; 
    private const bool UseOAEP = true; 

    public DRXEncrypter(string EncryptionKey) 
    { 
     this.EncryptionKey = EncryptionKey; 
    } 

    public static string EncryptBody(string body, string encryptionkey) 
    { 
     // Use the plaintext master key to encrypt the body. 
     DRXEncrypter enc = new DRXEncrypter(encryptionkey); 

     // Encrypt the body. 
     return enc.Encrypt(body); 
    } 

    public static int GetMaxKeySize(X509Certificate2 cert) 
    { 
     RSACryptoServiceProvider csp = cert.PublicKey.Key as RSACryptoServiceProvider; 

     return csp.KeySize; 
    } 

    public static string DecryptBody(string body, string encryptionkey, X509Certificate2 cert) 
    { 
     // Decrypt the encrypted encryption key with the certificate. 
     string DecryptedKey = Convert.ToBase64String(DecryptWithCert(cert, encryptionkey)); 

     // Create a new DRXEncrypter using the decrypted encryption key to decrypt the body. 
     DRXEncrypter enc = new DRXEncrypter(DecryptedKey); 

     // Return the decrypted body. 
     return enc.Decrypt(body); 
    } 

    public static string GenerateEncryptionKey(int KeyLength) 
    { 
     using (RandomNumberGenerator rng = new RNGCryptoServiceProvider()) 
     { 
      byte[] CryptoBytes = new byte[KeyLength]; 
      rng.GetBytes(CryptoBytes); 

      return Convert.ToBase64String(CryptoBytes); 
     } 
    } 

    public static X509Certificate2 GetCertificate(string title, string message) 
    { 
     X509Store cstore = new X509Store(StoreLocation.CurrentUser); 
     cstore.Open(OpenFlags.ReadOnly); 

     X509CertificateCollection certs = X509Certificate2UI.SelectFromCollection(cstore.Certificates, title, message, X509SelectionFlag.SingleSelection); 

     if (certs.Count == 1) 
     { 
      X509Certificate2 mcert = certs[0] as X509Certificate2; 
      return mcert; 
     } 
     else 
     { 
      return null; 
     } 
    } 

    public static string EncryptWithCert(X509Certificate2 cert, string PlainText) 
    { 
     RSACryptoServiceProvider csp = cert.PublicKey.Key as RSACryptoServiceProvider; 

     byte[] PlainBytes = Convert.FromBase64String(PlainText); 

     // This converts the plain text into a byte array and then encrypts the raw bytes. 
     byte[] CryptoBytes = csp.Encrypt(PlainBytes, UseOAEP); 

     // This converts the encrypted bytes into a Base64 string. 
     string ReturnString = Convert.ToBase64String(CryptoBytes); 

     return ReturnString; 
    } 

    public static byte[] DecryptWithCert(X509Certificate2 cert, string EncryptedText) 
    { 
     RSACryptoServiceProvider csp = cert.PrivateKey as RSACryptoServiceProvider; 

     //CspParameters csps = new CspParameters(); 

     byte[] EncryptedBytes = Convert.FromBase64String(EncryptedText); 

     // This converts the encrypted, Base64 encoded byte array from EncryptWithCert() to a byte[] and decrypts it. 
     byte[] CryptoBytes = csp.Decrypt(EncryptedBytes, UseOAEP); 

     return CryptoBytes; 
    } 

    public string Encrypt(string PlainText) 
    { 
     RijndaelManaged Algorithm = null; 
     string Output = null; 

     try 
     { 
      Rfc2898DeriveBytes PrivateKey = new Rfc2898DeriveBytes(this.EncryptionKey, this.Salt); 


      Algorithm = new RijndaelManaged(); 
      Algorithm.Key = PrivateKey.GetBytes(Algorithm.KeySize/8); 
      Algorithm.Padding = PaddingMode.PKCS7; 

      ICryptoTransform Encryption = Algorithm.CreateEncryptor(Algorithm.Key, Algorithm.IV); 

      using (MemoryStream msa = new MemoryStream()) 
      { 
       msa.Write(BitConverter.GetBytes(Algorithm.IV.Length), 0, sizeof(int)); 
       msa.Write(Algorithm.IV, 0, Algorithm.IV.Length); 
       using (CryptoStream csa = new CryptoStream(msa, Encryption, CryptoStreamMode.Write)) 
       { 
        using (StreamWriter swa = new StreamWriter(csa)) 
        { 
         swa.Write(PlainText); 
        } 
       } 
       Output = Convert.ToBase64String(msa.ToArray()); 
      } 
     } 
     finally 
     { 
      if (Algorithm != null) 
      { 
       Algorithm.Clear(); 
      } 
     } 

     return Output; 
    } 

    public string Decrypt(string EncryptedText) 
    { 
     RijndaelManaged Algorithm = null; 
     string Output = null; 

     try 
     { 
      Rfc2898DeriveBytes PrivateKey = new Rfc2898DeriveBytes(this.EncryptionKey, this.Salt); 

      byte[] KeyBytes = Convert.FromBase64String(EncryptedText); 
      using (MemoryStream msb = new MemoryStream(KeyBytes)) 
      { 
       Algorithm = new RijndaelManaged(); 
       Algorithm.Key = PrivateKey.GetBytes(Algorithm.KeySize/8); 
       Algorithm.IV = ReadByteArray(msb); 
       Algorithm.Padding = PaddingMode.PKCS7; 
       ICryptoTransform Decryption = Algorithm.CreateDecryptor(Algorithm.Key, Algorithm.IV); 
       using (CryptoStream csb = new CryptoStream(msb, Decryption, CryptoStreamMode.Read)) 
       { 
        using (StreamReader srb = new StreamReader(csb)) 
        { 
         Output = srb.ReadToEnd(); 
        } 
       } 

      } 
     } 
     finally 
     { 
      if (Algorithm != null) 
      { 
       Algorithm.Clear(); 
      } 
     } 

     return Output; 
    } 

    public static string Sha512(string ToHash) 
    { 
     using (SHA512 SHA = new SHA512Managed()) 
     { 
      byte[] HashByte = Encoding.UTF8.GetBytes(ToHash); 
      byte[] HashBytes = SHA.ComputeHash(HashByte); 
      string Hash = System.Text.Encoding.UTF8.GetString(HashBytes, 0, HashBytes.Length); 
      return Hash; 
     } 
    } 

    public static string Base64Encode(string data) 
    { 
     byte[] str = Encoding.UTF8.GetBytes(data); 
     return Convert.ToBase64String(str); 
    } 

    public static string Base64Decode(string data) 
    { 
     byte[] str = Convert.FromBase64String(data); 
     return Encoding.UTF8.GetString(str); 
    } 

    private byte[] ReadByteArray(Stream st) 
    { 
     byte[] Length = new byte[sizeof(int)]; 
     st.Read(Length, 0, Length.Length); 
     byte[] Buffer = new byte[BitConverter.ToInt32(Length, 0)]; 
     st.Read(Buffer, 0, Buffer.Length); 

     return Buffer; 
    } 
} 
} 
+0

Welche Codierung ist Ihre Verschlüsselungszeichenfolge? –

+2

Siehe auch [Ein schlechtes Paar von Jahren für die kryptografische Token-Industrie] (https://blog.cryptographyengineering.com/2012/06/21/bad-couple-of-years-for-cryptographic/). Sind Sie sicher, dass PKCS nicht gepolstert ist? – jww

+1

Dai Bok: Es ist base64. Siehe die Funktion GenerateEncryptionKey(). – CitadelCore

Antwort

0

Stellen Sie sicher, Ihre Schlüsselgröße nicht zu klein oder zu groß ist.

Siehe Kommentare von MSDN

Die RSACryptoServiceProvider Schlüsselgrößen von 384 Bit auf 16384 Bits in Schritten von 8 Bit unterstützt, wenn Sie die Microsoft Verbesserte Cryptographic Provider installiert haben. Es unterstützt Schlüsselgrößen von 384 Bit bis 512 Bit in Schritten von 8 Bit, wenn Sie den Microsoft Base Cryptographic Provider installiert haben.

Sie könnten also mit einigen Bytes kurzen Tasten Strings Pad benötigen die minimale Schlüssellänge

+0

Wenn ich das versuche, bekomme ich "Unhandled Exception: System.Security.Cryptography.CryptographicException: Bad Length." Das Zertifikat der Smartcard unterstützt nur bis zu 2048-Bit-Verschlüsselung. (256 Bytes ist der max.) – CitadelCore

+0

Auch der Provider ist "Microsoft Enhanced RSA und AES Cryptographic Provider". – CitadelCore

0

Ok, ich es geschafft, dies zu überprüfen, und von dem, was ich sehen kann, ich habe Probleme mit einigen Zertifikaten. Ich bin mir nicht sicher, warum einige Zertifikate funktionieren, andere nicht. Es wäre gut zu wissen, warum einige Zertifikate in diesem Fall fehlschlagen?

Wie auch immer, ich habe ein neues selbstsigniertes Zertifikat mit Windows "Verwalten von File Encryption Certificates" erstellt und dieses Zertifikat verwendet, und alles scheint zu funktionieren.

Die Ausgabe aus Ihrem Code.

Encryption Key: aUc/GXWDoh2LktaEGeCJfju1dHP118yD/fzfT0iJLuhOq2QeyGpG6m3aBHaxvdH0ufeXRHbMjmlmPgIL/bhABzkT2C5Oa6ZhY3IFXb5t7JXZ3AtUunvtNAnRyFJ7MzklrSZGgQ 
vF67DSNfIVE17doKt6j6mkCpSco56ooZCrOs2Mp3vSXqNjvjiwMEfQbk41aYUNVNVNlBGhdNQCIZIAKezQCUpWqzn2II27FIDfqDIEW4ieyzpXC05GzUlGXDxFOiFUPk3n0Y94vgeF8AlCD74eyZtz 
WQ== 
Encrypted Body: EAAAANS/W7+GGRbT1q5NCYvZlDZYtxaA8g55HzUqP5qxhenn 
Encrypted Decryption Key: vc/tcsApmY1503BFi7oSu/RDvZivA1Ed58KJuLoEC6eE8q0BIa6ye2JvtXyxkVbzzL0MA51pZ2ZhMIsfCnBsEDjCgy+JLTZTGM1Mv+em9frFUKb0zHbICnPUa/3H 
yd1yOWsdn5ws19QN2dzC6eau+ExhT2T/vyZO4Nf9NdHKnB8n2yB1rrQ/T+N2EYCNH/AVPDAsme6JG7k9Od2XIipBXMyCgXgWYZmQusq+JQjA9d3c4CrQYcg/ERF+K3oZv/gPicBkAR5taxwSxAajGg 
bpkJNsbhTMHTN9bOn333qZ6ojlo5e882baZXuZWPr9qtj1b7ONoOyuSx/OvGKjt93BQg== 
Decrypted Body: Hello World! 
Output String: Hello World!. 

Hoffnung, die

+0

Ja, ich weiß, dass Computerzertifikate funktionieren. Es ist nur das Zertifikat auf meiner Smartcard, das nicht funktioniert. Ich habe mit anderen Zertifikaten auf der gleichen Chipkarte mit verschiedenen EKUs auch versucht. – CitadelCore

+0

Haben Sie den privaten Schlüssel für dieses Zertifikat? –

+0

Ja, wie ich zuvor erwähnte OAEP Padding ist die einzige Sache, die verhindert, dass die Entschlüsselung funktioniert. Die Entschlüsselung funktioniert im PKCS # 1-Modus einwandfrei. – CitadelCore

0

hilft Ich habe mit Smartcards mit dieser heute argumentiert (oder genauer gesagt, ein Yubikey Neo mit dem Smartcard PIV-Applet aktiviert); mit diesem code:

ich habe festgestellt, dass es wichtig ist, was padding algo ich benutze. Wenn ich PKCS1 Padding verwende, funktioniert alles. Wenn ich OaepSHA1 verwende, bekomme ich den Error while decoding [...] Fehler. Wenn ich etwas anderes benutze (z.B., OaepSHA256) Ich bekomme einen Not supported Fehler.

Ich kann nur schließen, dass meine Smartcard OAEP SHA1 nicht richtig unterstützt, aber mit PKCS # 1 Padding alles ist gut.

Auch wenn dies das beantwortet, was Sie bereits wissen, kann es als weiterer Datenpunkt für alle anderen nützlich sein, die mit Smartcards unterwegs sind.