2011-12-07 60 views
6

Đây là bài đăng đầu tiên của tôi, vì vậy hy vọng tôi không bỏ lỡ bất kỳ điều gì quan trọng. Tôi đang thực hiện một dự án trong C# nơi tôi cần sử dụng mã hóa khóa công khai/riêng tư để mã hóa một tin nhắn và sau đó gửi nó qua kết nối SSL.Mã hóa RSA của dữ liệu lớn trong C#

Tôi đã chọn sử dụng RSACryptoService, như theo tài liệu, đó là lược đồ mã hóa không đối xứng duy nhất được sử dụng để mã hóa dữ liệu. Vấn đề là tôi đang gặp rất nhiều vấn đề với điều này. (Tôi muốn làm mã hóa đối xứng, nhưng đó không phải là điều mà giáo viên của tôi muốn tôi làm, và theo anh ta thì dễ dàng chỉ cần xác định kích thước khối và sau đó nó sẽ làm tất cả công việc cho bạn.) Vâng, cho đến nay không có may mắn và tôi đã thử một số cách tiếp cận khác nhau, nhưng bây giờ tôi trở lại vấn đề cơ bản và cố gắng một lần nữa, đây là mã hiện tại của tôi:

public string[] GenerateKeysToStrings(string uniqueIdentifier) 
    { 
     string[] keys; 
     using (var rsa = new RSACryptoServiceProvider(4096)) 
     { 
      try 
      { 
       string privateKey = rsa.ToXmlString(true); 
       string publicKey = rsa.ToXmlString(false); 

       this.pki.StoreKey(publicKey, uniqueIdentifier); 

       keys = new string[2]; 
       keys[0] = privateKey; 
       keys[1] = publicKey; 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return keys; 
    } 

Như bạn thấy, tôi tạo ra các phím và tôi mimmick một PKI bằng cách gửi khóa công khai đến một lớp đơn giản lưu trữ nó, và sau đó khóa riêng được ghi vào một tệp (Lưu ý rằng tôi cũng có một phương thức khác thực hiện tương tự nhưng lưu trữ nó vào một mảng thay vì chỉ muốn thử nghiệm và đơn giản hóa mọi thứ khi tôi nhận được No such key exceptions và đôi khi ngoại lệ mã hóa khi tôi thực hiện theo cách được hiển thị trong ví dụ phong phú, vì vậy tôi muốn đơn giản hóa nó bằng cách đơn giản giữ chuỗi rsa.ToXmlString, như là một chuỗi trong một mảng, nhưng không có may mắn)

Bây giờ tôi có một mã hóa và giải mã phương pháp như sau:.

public string Encrypt(string keyString, string message) 
    { 
     string encryptedMessage; 
     using (var rsa = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //// Load the key from the specified path 
       var encryptKey = new XmlDocument(); 
       encryptKey.Load(@"C:\Test\PrivateKeyInfo.xml"); 
       rsa.FromXmlString(encryptKey.OuterXml); 


       //// Conver the string message to a byte array for encryption 
       //// var encoder = new UTF8Encoding(); 
       ASCIIEncoding byteConverter = new ASCIIEncoding(); 
       byte[] dataToEncrypt = byteConverter.GetBytes(message); 

       byte[] encryptedData = rsa.Encrypt(dataToEncrypt, false); 

       //// Convert the byte array back to a string message 
       encryptedMessage = byteConverter.GetString(encryptedData); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return encryptedMessage; 
    } 

Decryption :

public string Decrypt(string keyString, string message) 
    { 
     string decryptedText; 
     using (var rsa = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //// Loads the keyinfo into the rsa parameters from the keyfile 
       /* 
       var privateKey = new XmlDocument(); 
       privateKey.Load(keyString); 
       */ 
       rsa.FromXmlString(keyString); 

       //// Convert the text from string to byte array for decryption 
       ASCIIEncoding byteConverter = new ASCIIEncoding(); 
       var encryptedBytes = byteConverter.GetBytes(message); 

       //// Create an aux array to store all the encrypted bytes 
       byte[] decryptedBytes = rsa.Decrypt(encryptedBytes, false); 

       decryptedText = byteConverter.GetString(decryptedBytes); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       rsa.PersistKeyInCsp = false; 
      } 
     } 
     return decryptedText; 
    } 

tôi biết rằng đây là một bức tường của văn bản, nhưng tôi hy vọng bạn có thể giúp tôi ra vì tôi đã đập đầu tôi vào tường quá lâu bây giờ nó không buồn cười :)

Vấn đề là, làm thế nào để đi về các tin nhắn mã hóa với RSA (hoặc bất kỳ công/mã hóa khóa bí mật khác)

Đây là khách hàng kiểm tra:

public static void Main(string[] args) 
    { 
     PublicKeyInfrastructure pki = new PublicKeyInfrastructure(); 
     Cryptograph crypto = new Cryptograph(); 
     string[] keys = crypto.GenerateKeysToStrings("[email protected]"); 


     string plainText = "Hello play with me, please"; 
     string publicKey = crypto.GetPublicKey("[email protected]"); 

     string encryptedText = crypto.Encrypt(keys[0], plainText); 


     string decryptedText = crypto.Decrypt(keys[1], encryptedText); 

    } 

Như tôi đã đề cập, các mảng chuỗi đang có vì tôi muốn loại bỏ lỗi phân tích cú pháp xấu khỏi tài liệu XML ...

Khi tôi chạy ứng dụng khách thử nghiệm, nếu tôi sử dụng khóa riêng để mã hóa và khóa công khai để giải mã, tôi sẽ nhận được "Khóa không tồn tại ngoại lệ" và nếu tôi làm điều đó theo cách khác, tôi nhận được một ngoại lệ dữ liệu xấu.

Hãy giúp tôi, nếu bạn biết bất kỳ hướng dẫn hay nào, hoặc có thể cho tôi biết cách thực hiện phần nào mã hóa khóa công khai/riêng tư trên chuỗi tin nhắn, hãy giúp tôi.

Tôi đánh giá cao bất kỳ trợ giúp nào.

Trả lời

5

Đây không phải là cách thực hiện mã hóa RSA.

RSA là tất cả về toán học. Những gì bạn mã hóa là một số vì vậy nó phải có chiều dài hữu hạn và phù hợp với độ dài cặp khóa RSA bạn đang sử dụng. Các giới hạn chiều dài tiếp theo được áp dụng bởi padding được sử dụng (PKCS # 1 hoặc OAEP).

Nếu bạn muốn mã hóa dữ liệu lớn với RSA, bạn cần phải thực hiện gián tiếp - tức là sử dụng khóa đối xứng để mã hóa dữ liệu lớn và mã hóa khóa này bằng khóa công cộng RSA.

Bạn có thể đọc về việc triển khai điều này trên blog của mình.

+0

Tôi đã nói chuyện với giáo sư của tôi và tại thời điểm đó quan điểm của tôi là tốt hơn nên mã hóa khóa, trao đổi khóa và sau đó sử dụng nó, làm cơ sở cho một thuật toán đối xứng, như rijndael để mã hóa/giải mã thông điệp, tuy nhiên, anh ta không muốn chúng tôi sử dụng mã hóa đối xứng vì vậy bây giờ tôi đang ở vị trí hiện tại đang bị hạn chế. Hiệu năng khôn ngoan, mất bao nhiêu thời gian để mã hóa tin nhắn, 501 byte một lần (sử dụng các khóa RSA 4096bit) khi chúng ta nói về các thông điệp HTTP có chứa tên người dùng và mật khẩu? mã hóa khối theo khối hay không, tôi vẫn có vấn đề thực sự bằng cách sử dụng RSA: ( –

+0

Bạn có thể lặp mã hóa/giải mã RSA để ở dưới giới hạn kích thước (bao gồm đệm) và ghép/chia kết quả. CPU của bạn, nó là một điện thoại thông minh cũ và một máy chủ 8 lõi mới? ;-) nhưng dài hơn rất nhiều so với một giải pháp thay thế chính xác. – poupou

+0

Tôi ước mình có thể có thời gian, nhưng ngay bây giờ tôi thậm chí không thể làm điều này để làm việc cho bất kỳ dữ liệu nào. Tôi lấy một phiên bản đơn giản và sử dụng nó, tuy nhiên, tôi vẫn nhận được lỗi "Key không tồn tại" và tất cả những gì tôi thực sự làm là cấu trúc lại thiết kế, từ một phương thức chính đến các phương thức riêng biệt. Có lẽ tôi đang sử dụng hàm tạo phải không? Phần mà tôi nhập cài đặt khóa? Tôi biết rằng mật mã khối chậm hơn 1000 lần so với thuật toán đối xứng, nhưng ngay bây giờ tôi chỉ muốn nó hoạt động, cho dù tôi có phải mã hóa nó để tôi cắt từng khối dữ liệu thành các phần (keyize/8 - 11 (cho đệm)) byte. –

0

Có thể tôi đang thiếu thứ gì đó, nhưng có vẻ như hàm Encrypt() của bạn không sử dụng tham số keyString hoặc nội dung của encryptKey.

+0

Vâng Tôi rất tiếc về điều đó, nhưng tôi phải quên đặt nó vào đó, nhưng tôi đảm bảo với bạn rằng tôi đã chắc chắn để tải trọng. Tôi đã cập nhật OP ngay bây giờ. Tôi đã thử tải dữ liệu rất nhiều lần, rằng tôi phải có một số phiên bản trộn lẫn và không nhìn thấy nó :) Vấn đề của tôi vẫn còn mặc dù. Vấn đề tôi đang gặp phải, đó là khi tôi sử dụng khóa riêng của mình để mã hóa và công chúng giải mã, tôi nhận được một ngoại lệKhông tồn tại ngoại lệ. Nếu tôi làm điều đó theo cách khác xung quanh tuy nhiên, tôi nhận được một ngoại lệ "dữ liệu xấu". –

1

Được rồi, cuối cùng tôi đã đưa ra giải pháp cho vấn đề tôi đã nêu trong bài đăng gốc của mình. Đây là một cái gì đó tôi đã không kiểm tra kỹ lưỡng hoặc bất cứ điều gì, nhưng một cái gì đó tôi đã tìm ra từ một quá trình thử nghiệm và lỗi nhỏ.

Đây là mã hiện tại tôi có:

public static string Encrypt(string dataToEncrypt, RSAParameters publicKeyInfo) 
    { 
     //// Our bytearray to hold all of our data after the encryption 
     byte[] encryptedBytes = new byte[0]; 
     using (var RSA = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       //Create a new instance of RSACryptoServiceProvider. 
       UTF8Encoding encoder = new UTF8Encoding(); 

       byte[] encryptThis = encoder.GetBytes(dataToEncrypt); 

       //// Importing the public key 
       RSA.ImportParameters(publicKeyInfo); 

       int blockSize = (RSA.KeySize/8) - 32; 

       //// buffer to write byte sequence of the given block_size 
       byte[] buffer = new byte[blockSize]; 

       byte[] encryptedBuffer = new byte[blockSize]; 

       //// Initializing our encryptedBytes array to a suitable size, depending on the size of data to be encrypted 
       encryptedBytes = new byte[encryptThis.Length + blockSize - (encryptThis.Length % blockSize) + 32]; 

       for (int i = 0; i < encryptThis.Length; i += blockSize) 
       { 
        //// If there is extra info to be parsed, but not enough to fill out a complete bytearray, fit array for last bit of data 
        if (2 * i > encryptThis.Length && ((encryptThis.Length - i) % blockSize != 0)) 
        { 
         buffer = new byte[encryptThis.Length - i]; 
         blockSize = encryptThis.Length - i; 
        } 

        //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it 
        if (encryptThis.Length < blockSize) 
        { 
         buffer = new byte[encryptThis.Length]; 
         blockSize = encryptThis.Length; 
        } 

        //// encrypt the specified size of data, then add to final array. 
        Buffer.BlockCopy(encryptThis, i, buffer, 0, blockSize); 
        encryptedBuffer = RSA.Encrypt(buffer, false); 
        encryptedBuffer.CopyTo(encryptedBytes, i); 
       } 
      } 
      catch (CryptographicException e) 
      { 
       Console.Write(e); 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       RSA.PersistKeyInCsp = false; 
      } 
     } 
     //// Convert the byteArray using Base64 and returns as an encrypted string 
     return Convert.ToBase64String(encryptedBytes); 
    } 

    /// <summary> 
    /// Decrypt this message using this key 
    /// </summary> 
    /// <param name="dataToDecrypt"> 
    /// The data To decrypt. 
    /// </param> 
    /// <param name="privateKeyInfo"> 
    /// The private Key Info. 
    /// </param> 
    /// <returns> 
    /// The decrypted data. 
    /// </returns> 
    public static string Decrypt(string dataToDecrypt, RSAParameters privateKeyInfo) 
    { 
     //// The bytearray to hold all of our data after decryption 
     byte[] decryptedBytes; 

     //Create a new instance of RSACryptoServiceProvider. 
     using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider()) 
     { 
      try 
      { 
       byte[] bytesToDecrypt = Convert.FromBase64String(dataToDecrypt); 

       //// Import the private key info 
       RSA.ImportParameters(privateKeyInfo); 

       //// No need to subtract padding size when decrypting (OR do I?) 
       int blockSize = RSA.KeySize/8; 

       //// buffer to write byte sequence of the given block_size 
       byte[] buffer = new byte[blockSize]; 

       //// buffer containing decrypted information 
       byte[] decryptedBuffer = new byte[blockSize]; 

       //// Initializes our array to make sure it can hold at least the amount needed to decrypt. 
       decryptedBytes = new byte[dataToDecrypt.Length]; 

       for (int i = 0; i < bytesToDecrypt.Length; i += blockSize) 
       { 
        if (2 * i > bytesToDecrypt.Length && ((bytesToDecrypt.Length - i) % blockSize != 0)) 
        { 
         buffer = new byte[bytesToDecrypt.Length - i]; 
         blockSize = bytesToDecrypt.Length - i; 
        } 

        //// If the amount of bytes we need to decrypt isn't enough to fill out a block, only decrypt part of it 
        if (bytesToDecrypt.Length < blockSize) 
        { 
         buffer = new byte[bytesToDecrypt.Length]; 
         blockSize = bytesToDecrypt.Length; 
        } 

        Buffer.BlockCopy(bytesToDecrypt, i, buffer, 0, blockSize); 
        decryptedBuffer = RSA.Decrypt(buffer, false); 
        decryptedBuffer.CopyTo(decryptedBytes, i); 
       } 
      } 
      finally 
      { 
       //// Clear the RSA key container, deleting generated keys. 
       RSA.PersistKeyInCsp = false; 
      } 
     } 

     //// We encode each byte with UTF8 and then write to a string while trimming off the extra empty data created by the overhead. 
     var encoder = new UTF8Encoding(); 
     return encoder.GetString(decryptedBytes).TrimEnd(new[] { '\0' }); 

    } 

Như tôi đã nói, tôi đã không kiểm tra nó nhiều, ngoại trừ kích thước dưới đây, tại trở lên khối kích thước, nhưng có vẻ như được làm những gì nó nên. Tôi vẫn còn là một người mới, vì vậy tôi thực sự muốn bạn xem xét mã của tôi :)

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