2012-02-20 29 views
39

Tôi đang nhìn chằm chằm vào điều này trong một thời gian và nhờ vào số MSDN documentation Tôi thực sự không thể hiểu được điều gì đang xảy ra. Về cơ bản tôi đang tải một tập tin PFX từ đĩa vào một X509Certificate2 và cố gắng để mã hóa một chuỗi bằng cách sử dụng khóa công khai và giải mã bằng cách sử dụng khóa riêng.CryptographicException "Khóa không hợp lệ để sử dụng ở trạng thái được chỉ định". trong khi cố gắng xuất RSAParameters của khóa riêng X509

Tại sao tôi bối rối: mã hóa/giải mã hoạt động khi tôi vượt qua tham chiếu đến RSACryptoServiceProvider bản thân:

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

Nhưng nếu việc xuất khẩu và vượt qua xung quanh RSAParameter:

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

.. .it ném một "Khóa không hợp lệ để sử dụng trong trạng thái được chỉ định". ngoại lệ trong khi cố gắng xuất khóa cá nhân sang RSAParameter. Xin lưu ý rằng chứng chỉ PFX được tạo ra được đánh dấu là có thể xuất được (tức là tôi đã sử dụng cờ pe trong khi tạo chứng chỉ). Bất kỳ ý tưởng gì gây ra ngoại lệ?

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); 
} 

Chỉ cần làm rõ trong đoạn mã trên phần in đậm là ném: string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);

Trả lời

3

Tôi không phải là chính xác một chuyên gia về những điều này, nhưng tôi đã làm một google nhanh chóng, và thấy điều này:

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

"nếu bạn có nhiều hơn 245 byte trong mảng byte mà bạn vượt qua để RSACryptoServiceProvider.Encrypt của bạn (byte [] rgb, bool fOAEP) phương pháp sau đó nó sẽ ném một ngoại lệ."

+0

Xin lỗi nếu tôi đã không làm rõ bản thân mình rất tốt, tôi có thể phá vỡ dòng này: chuỗi foo = DecryptRSA (ed, (x.PrivateKey như RSACryptoServiceProvider) .ExportParameters (true)); thành: var pvk = (x.PrivateKey là RSACryptoServiceProvider); var pvkParam = pvk.ExportParameters (true); chuỗi foo = DecryptRSA (ed, pvkParam); ... và nếu tôi làm điều đó pvk.ExportParameters (true); sẽ ném. – kalrashi

+0

Lỗi này là một trong những lỗi khó chịu nhất từng được viết. Nó có thể có nghĩa là rất nhiều thứ. Đối với tôi, như Jeroen đã nói: văn bản tin nhắn của tôi quá lớn để được mã hóa bởi khóa (đó là nhược điểm của mã hóa không đồng bộ). – Aejay

1

AFAIK điều này sẽ hoạt động và bạn có thể gặp lỗi/một số hạn chế. Dưới đây là một số câu hỏi có thể giúp bạn tìm ra vấn đề ở đâu.

  • Bạn đã tạo tệp PKCS # 12 (PFX) như thế nào? Tôi đã nhìn thấy một số phím mà CryptoAPI không thích (thông số RSA không phổ biến). Bạn có thể sử dụng một công cụ khác (chỉ để chắc chắn)?

  • Bạn có thể xuất phiên bản PrivateKey thành XML, ví dụ: ToXmlString(true), sau đó tải (nhập) trở lại theo cách này?

  • Phiên bản cũ của khung công tác có một số vấn đề khi nhập khóa có kích thước khác với kích thước hiện tại (mặc định là 1024 bit). Kích thước khóa công khai RSA của bạn trong chứng chỉ của bạn là bao nhiêu?

Cũng lưu ý rằng đây là không làm thế nào bạn nên mã hóa dữ liệu sử dụng RSA. Kích thước của mã hóa thô được giới hạn wrt khóa công khai đang được sử dụng. Lặp lại giới hạn này sẽ chỉ cung cấp cho bạn thực sự hiệu suất kém.

Bí quyết là sử dụng một thuật toán đối xứng (như AES) với khóa ngẫu nhiên hoàn toàn và sau đó mã hóa khóa này (wrap) bằng cách sử dụng khóa công khai RSA. Bạn có thể tìm mã C# để làm như vậy trong số blog entry cũ của mình về chủ đề này.

84

Tôi tin rằng vấn đề có thể là khóa không được đánh dấu là có thể xuất. Có một hàm khởi tạo khác cho X509Certificate2 có một hàm enge X509KeyStorageFlags. Hãy thử thay thế dòng:

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

Với điều này:

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

Cảm ơn! Bạn đã cứu tôi rất nhiều rắc rối! :) – conciliator

8

tôi đã gặp một số vấn đề tương tự, và X509KeyStorageFlags.Exportable giải quyết vấn đề của tôi.

0

Đối với những người khác kết thúc ở đây thông qua Google, nhưng không sử dụng bất kỳ X509Certificate2 nào, nếu bạn gọi ToXmlString trên RSACryptoServiceProvider nhưng bạn chỉ tải khóa công khai, bạn cũng sẽ nhận được thông báo này. Việc sửa chữa này (lưu ý dòng cuối cùng):

var rsaAlg = new RSACryptoServiceProvider(); 

rsaAlg.ImportParameters(rsaParameters); 

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

Đối với vấn đề tôi gặp phải một sự thay đổi mã không phải là một lựa chọn như cùng một thư viện đã được cài đặt và hoạt ở nơi khác.

Câu trả lời của Iridium dẫn tôi xem xét việc tạo khóa có thể xuất và tôi có thể làm điều này như một phần của Trình hướng dẫn nhập chứng chỉ MMC.

Hy vọng điều này sẽ giúp người khác. Cảm ơn đống

Cert import wizard

Các vấn đề liên quan