2012-02-20 9 views
39

Lo sto fissando da un po 'e grazie allo MSDN documentation non riesco davvero a capire cosa sta succedendo. Fondamentalmente sto caricando un file PFX dal disco in un X509Certificate2 e provando a criptare una stringa usando la chiave pubblica e decifrare usando la chiave privata.CryptographicException "Chiave non valida per l'uso nello stato specificato." mentre provo ad esportare RSAParameters di una chiave privata X509

Perché io sono perplesso: la cifratura/decifratura funziona quando passo il riferimento alla RSACryptoServiceProvider stesso:

byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider); 
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider); 

Ma se l'esportazione e passare tutto il RSAParameter:

byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false)); 
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true)); 

.. .it lancia una "Chiave non valida per l'uso nello stato specificato". eccezione durante il tentativo di esportare la chiave privata a RSAParameter. Si noti che il certificato generato da PFX è contrassegnato come esportabile (ad esempio, ho usato il flag pe durante la creazione del certificato). Qualche idea su cosa sta causando l'eccezione?

static void Main(string[] args) 
    { 
     X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test"); 
     x.FriendlyName = "My test Cert"; 

     X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); 
     store.Open(OpenFlags.ReadWrite); 
     try 
     { 
      store.Add(x); 
     } 
     finally 
     { 
      store.Close(); 
     } 

     byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider); 
     string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider); 

     byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false)); 
     string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true)); 
    } 

private static byte[] EncryptRSA(string data, RSAParameters rsaParameters) 
{ 
    UnicodeEncoding bytConvertor = new UnicodeEncoding(); 
    byte[] plainData = bytConvertor.GetBytes(data); 

    RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider(); 
    publicKey.ImportParameters(rsaParameters); 
    return publicKey.Encrypt(plainData, true); 
} 

private static string DecryptRSA(byte[] data, RSAParameters rsaParameters) 
{ 
    UnicodeEncoding bytConvertor = new UnicodeEncoding(); 

    RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider(); 
    privateKey.ImportParameters(rsaParameters); 

    byte[] deData = privateKey.Decrypt(data, true); 
    return bytConvertor.GetString(deData); 
} 

private static byte[] EncryptRSA(string data, RSACryptoServiceProvider publicKey) 
{ 
    UnicodeEncoding bytConvertor = new UnicodeEncoding(); 
    byte[] plainData = bytConvertor.GetBytes(data); 

    return publicKey.Encrypt(plainData, true); 
} 

private static string DecryptRSA(byte[] data, RSACryptoServiceProvider privateKey) 
{ 
    UnicodeEncoding bytConvertor = new UnicodeEncoding(); 

    byte[] deData = privateKey.Decrypt(data, true); 
    return bytConvertor.GetString(deData); 
} 

Giusto per chiarire nel codice qui sopra la parte in grassetto sta gettando: string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);

risposta

3

Non sono esattamente un esperto di queste cose, ma ho fatto una rapida di Google, e ho trovato questo:

http://social.msdn.microsoft.com/Forums/en/clr/thread/4e3ada0a-bcaf-4c67-bdef-a6b15f5bfdce

"se si dispone di più di 245 byte nella tua matrice di byte che si passa al tuo RSACryptoServiceProvider.Encrypt (byte [] rgb, bool fOAEP) metodo allora sarà un'eccezione."

+0

Scusate se non mi sono chiarito molto bene, posso rompere questa linea: stringa foo = DecryptRSA (a cura di, (x.PrivateKey come RSACryptoServiceProvider) .ExportParameters (veri)); in: var pvk = (x.PrivateKey come RSACryptoServiceProvider); var pvkParam = pvk.ExportParameters (true); string foo = DecryptRSA (ed, pvkParam); ... e se lo faccio pvk.ExportParameters (true); getterà. – kalrashi

+0

Questo errore è uno degli errori più fastidiosi mai scritti. Può significare tante cose. Per me è stato come ha detto Jeroen: il mio messaggio era troppo grande per essere crittografato dalla chiave (è il lato negativo della crittografia asincrona). – Aejay

1

AFAIK questo dovrebbe funzionare e probabilmente si sta verificando un bug/alcune limitazioni. Ecco alcune domande che potrebbero aiutarti a capire dov'è il problema.

  • Come è stato creato il file PKCS # 12 (PFX)? Ho visto alcune chiavi che a CryptoAPI non piacciono (non comuni parametri RSA). Puoi usare un altro strumento (solo per essere sicuro)?

  • È possibile esportare l'istanza PrivateKey in XML, ad es. ToXmlString(true), quindi caricare (importare) in questo modo?

  • Le vecchie versioni del framework presentavano alcuni problemi durante l'importazione di una chiave di dimensioni diverse rispetto all'istanza corrente (predefinita a 1024 bit). Qual è la dimensione della chiave pubblica RSA nel certificato?

Si noti inoltre che questo è non come si dovrebbe crittografare i dati utilizzando RSA. La dimensione della crittografia grezza è limitata dalla chiave pubblica utilizzata. Andare oltre questo limite ti darebbe solo una performance scadente a .

Il trucco è quello di utilizzare un algoritmo simmetrico (come AES) con una chiave casuale totalmente e quindi crittografare questa chiave (involucro) utilizzando la chiave pubblica RSA. È possibile trovare il codice C# per farlo nel mio vecchio blog entry sull'argomento.

84

Credo che il problema potrebbe essere che la chiave non è contrassegnata come esportabile. C'è un altro costruttore per X509Certificate2 che accetta un enum X509KeyStorageFlags. Provare a sostituire la linea:

X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test"); 

Con questo:

X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test", X509KeyStorageFlags.Exportable); 
+6

Grazie! Mi hai salvato un sacco di problemi! :) – conciliator

8

ho incontrato qualche problema simile, e X509KeyStorageFlags.Exportable risolto il mio problema.

0

Per gli altri che finiscono qui attraverso Google, ma non utilizzare alcun X509Certificate2, se si chiama ToXmlString su RSACryptoServiceProvider ma si è caricata solo una chiave pubblica, si riceverà anche questo messaggio. La correzione è questo (notare l'ultima riga):

var rsaAlg = new RSACryptoServiceProvider(); 

rsaAlg.ImportParameters(rsaParameters); 

var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly); 
5

Per il problema che ho incontrato una modifica del codice non era un'opzione come la stessa libreria è stato installato e funzionante altrove.

La risposta di Iridium mi ha portato a cercare di rendere esportabile la chiave e sono stato in grado di farlo come parte dell'Importazione guidata certificati MMC.

Spero che questo aiuti qualcun altro. Grazie cumuli

Cert import wizard

Problemi correlati